api work. search added. browse upgrade. some html5 improvements.

This commit is contained in:
Nick Earwood 2016-03-20 18:26:27 -04:00
parent 834dbc5439
commit 7de3e8a1bb
20 changed files with 448 additions and 217 deletions

View File

@ -16,18 +16,29 @@ Parses MSQ "XML" in tandem with an associated INI (config) file and displays it
#### Needed software ####
* AMP Stack
* AMP Stack: Apache, MySQL (MariaDB), PHP
* MySQL PDO extension for PHP:
`/etc/php/php.ini`:
`extension=pdo_mysql.so`
Arch Linux:
# pacman -S apache mysql php php-apache
#### Recommended software ####
* phpMyAdmin
* phpMyAdmin - For managing the DB
* rsync - For the deployment script
#### Process ####
#### Development Setup ####
* Create database user and database itself.
* Upload & deploy files.
* Setup script.config with details.
* Run db scripts.
# Clone repo to dev directory
# Copy script.config.dist to script.config
# Copy src/config.php.dist to src/config.php
# Create database for msqur, and assign it a user
# Setup parameters in each config file
# Update DB with update scripts in sequential order
# Run deploy script
# Test
#### hgrc ####
To display a fancy version string, modify your .hgrc to have this hook:

View File

@ -1 +0,0 @@
CREATE USER 'msqur'@'%' IDENTIFIED BY '';GRANT USAGE ON *.* TO 'msqur'@'%' IDENTIFIED BY '' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;CREATE DATABASE IF NOT EXISTS `msqur`;GRANT ALL PRIVILEGES ON `msqur`.* TO 'msqur'@'%';

View File

@ -1,110 +0,0 @@
-- phpMyAdmin SQL Dump
-- version 4.3.3
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Dec 22, 2014 at 02:49 PM
-- Server version: 10.0.15-MariaDB-log
-- PHP Version: 5.6.3
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET NAMES utf8 */;
--
-- Database: `msqur`
--
CREATE DATABASE IF NOT EXISTS `msqur` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
USE `msqur`;
-- --------------------------------------------------------
--
-- Table structure for table `engines`
--
DROP TABLE IF EXISTS `engines`;
CREATE TABLE IF NOT EXISTS `engines` (
`id` int(11) NOT NULL,
`displacement` decimal(4,2) NOT NULL,
`numCylinders` tinyint(2) NOT NULL,
`compression` decimal(4,2) NOT NULL,
`induction` int(11) NOT NULL,
`injectorSize` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `metadata`
--
DROP TABLE IF EXISTS `metadata`;
CREATE TABLE IF NOT EXISTS `metadata` (
`id` int(11) NOT NULL,
`msq` int(11) NOT NULL,
`engine` int(11) DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`fileFormat` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`signature` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`firmware` varchar(255) NOT NULL,
`author` varchar(255) NOT NULL,
`writeDate` datetime NOT NULL,
`uploadDate` datetime NOT NULL,
`tuneComment` text NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `msqs`
--
DROP TABLE IF EXISTS `msqs`;
CREATE TABLE IF NOT EXISTS `msqs` (
`id` int(11) NOT NULL,
`xml` mediumtext CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `engines`
--
ALTER TABLE `engines`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `metadata`
--
ALTER TABLE `metadata`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `msqs`
--
ALTER TABLE `msqs`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `engines`
--
ALTER TABLE `engines`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=3;
--
-- AUTO_INCREMENT for table `metadata`
--
ALTER TABLE `metadata`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=3;
--
-- AUTO_INCREMENT for table `msqs`
--
ALTER TABLE `msqs`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=3;

2
db/procs/create-user.sql Normal file
View File

@ -0,0 +1,2 @@
CREATE USER 'msqur'@'%' IDENTIFIED BY '';
GRANT USAGE ON *.* TO 'msqur'@'%' IDENTIFIED BY '' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;CREATE DATABASE IF NOT EXISTS `msqur`;GRANT ALL PRIVILEGES ON `msqur`.* TO 'msqur'@'%';

View File

@ -1,4 +1,4 @@
. script.config
rsync -av --exclude='config.php' --exclude='*/.hg*' src/ $DEPLOY_DIR/
cp -v VERSION $DEPLOY_DIR/
rsync -av --delete --exclude='*/.hg*' src/ $DEPLOY_DIR/
cp -v VERSION $DEPLOY_DIR/ > /dev/null 2>&1

14
setup.sh Normal file
View File

@ -0,0 +1,14 @@
# test for script.config, or cp from script.config.dist
. script.config
# test each script var, ask for nulls
#setup DB
#mysql --user=root -p --host=$DB_HOST < $1
# look for/generate config.php from config.php.dist
# copy to deploy dir if not exist there

41
src/about.php Normal file
View File

@ -0,0 +1,41 @@
<?php
/* msqur - MegaSquirt .msq file viewer web application
Copyright (C) 2015 Nicholas Earwood nearwood@gmail.com http://nearwood.net
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
require "msqur.php";
$msqur->header();
?>
<div>
<h2>About</h2>
<p>Created out of a need to share .MSQ files.
I was tired of downloading files and having to open them in <strike>MegaTune</strike> Tuner Studio.
So, I created this site. It's open source, so <a href="https://bitbucket.org/nearwood/msqur">feel free to contribute</a>.
Since going "live" I only add things here and there whenever I have time or the urge to work in PHP (ha!).</p>
</div>
<div>
<h2>FAQ</h2>
<ul id="faq">
<li class="q">Why is this site so ugly?</li>
<li class="a">My Ballmer peak doesn't last all day.</li>
<li class="q">Can you add X feature?</li>
<li class="a">File a request for it <a href="https://bitbucket.org/nearwood/msqur/issues">here</a>.</li>
</ul>
</div>
<?php
$msqur->footer();
?>

View File

@ -15,8 +15,28 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
//So as to not garble up the JSON response
ini_set('display_errors', API_DEBUG ? 'On' : 'Off');
require "msqur.php";
function parseQueryString($s)
{
$ret = null;
if (isset($_GET[$s]))
{
$ret = htmlspecialchars($_GET[$s]);
if (strlen($ret) == 0) $ret = null;
}
return $ret;
}
$method = parseQueryString('method');
$auth = parseQueryString('token') || parseQueryString('auth');
$api = new API($msqur, $auth);
echo $api->call($method);
/*
* @brief Public API
*
@ -24,17 +44,75 @@ require "msqur.php";
* get firmware versions (for ajax calls)
* get tune files?
* get individual tables?
*
* @see http://www.aljtmedia.com/blog/creating-a-php-rest-routing-class-for-your-application/
*/
class API
{
$fwList = $msqur->getFirmwareVersionList('MS2Extra');
var_export($msqur->getFirmwareVersionList('MS2Extra'));
foreach ($fwList as $fw)
const VERSION = 1;
private $isAuthenticated = false;
private $result = "";
private $msqur = null;
public function __construct($msqur, $authToken)
{
echo $fw;
$this->msqur = $msqur;
$this->authenticate($authToken);
}
public function authenticate($authToken)
{//TODO Proper auth steps
$this->isAuthenticated = true;
return $this->isAuthenticated;
}
public function call($method)
{
$result = array("version" => API::VERSION);
if (!$this->isAuthenticated)
{
$result["error"] = "Invalid authentication";
return json_encode($result);
}
//I'm sorry
switch ($method)
{
case 'firmwareList':
$result = array($method => $this->msqur->getFirmwareList());
break;
case 'firmwareVersions':
$fw = parseQueryString('firmware');
$result = array($method => $this->msqur->getFirmwareVersionList($fw));
break;
case 'engineMakes':
//$a = parseQueryString('firmware'); //TODO inverse code->make is probably not frequent enough to bother
$result = array($method => $this->msqur->getEngineMakeList());
//SELECT DISTINCT make FROM `engines` WHERE 1
break;
case 'engineCodes':
$make = parseQueryString('make'); //optional
$result = array($method => $this->msqur->getEngineCodeList($make));
//SELECT DISTINCT code FROM `engines` WHERE 1
break;
case 'cylinders':
//SELECT DISTINCT cylinders FROM `engines` WHERE 1
break;
case 'displacements':
//SELECT DISTINCT make FROM `engines` WHERE 1 //TODO Will need to make this into ranges...
break;
case 'compressionratios':
//SELECT DISTINCT make FROM `engines` WHERE 1
break;
case 'aspirations':
//SELECT DISTINCT make FROM `engines` WHERE 1
break;
//TODO upload date range?
default:
$result["error"] = "Invalid API call";
break;
}
return json_encode($result);
}
}
?>

View File

@ -18,21 +18,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
require "msqur.php";
if (isset($_GET['p'])) {
$page = $_GET['p']; //TODO processing
$page = htmlspecialchars($_GET['p']);
} else $page = 0;
$results = $msqur->browse($page);
$numResults = count($results);
//echo '<div class="debug">'; var_export($results); echo '</div>';
$msqur->header();
require "view/filter.php";
//require "view/browse.php";
?>
<div class="browse" id="categories">
<div>Makes: <div class="browse" id="makes"></div></div>
<div>Models: <div class="browse" id="models"></div></div>
<div>Firmware: <div class="browse" id="firmware"></div></div>
<div>Versions: <div class="browse" id="versions"></div></div>
</div>
<script src="view/browse.js"></script>
<?php
echo '<div id="content"><div class="info">' . $numResults . ' results.</div>';
echo '<table>';
echo '<tr><th>ID</th><th>Engine Make</th><th>Engine Code</th><th>Cylinders</th><th>Liters</th><th>Compression</th><th>Aspiration</th><th>Firmware/Version</th><th>Upload Date</th><th>Views</th></th>';
echo '<table ng-controller="BrowseController">';
echo '<tr><th>ID</th><th>Engine Make</th><th>Engine Code</th><th>Cylinders</th><th>Liters</th><th>Compression</th><th>Aspiration</th><th>Firmware/Version</th><th>Upload Date</th><th>Views</th></tr>';
for ($c = 0; $c < $numResults; $c++)
{
$aspiration = $results[$c]['induction'] == 1 ? "Turbo" : "NA";

View File

@ -1,11 +1,12 @@
<?php
define('CONFIG_VERSION', "4");
define('CONFIG_VERSION', "5");
define('DB_HOST', "localhost");
define('DB_USERNAME', "msqur");
define('DB_PASSWORD', "");
define('DB_NAME', "msqur");
define('DEBUG', FALSE);
define('API_DEBUG', FALSE);
define('DISABLE_MSQ_CACHE', FALSE);
error_reporting(E_ALL);

View File

@ -299,6 +299,35 @@ class MsqurDB
return null;
}
/**
* @brief Search metadata for any hits against a search query
* @param $query The string to search against
* @returns A list of matching metadata, or null if unsuccessful
*/
public function search($query)
{
if (!$this->connect()) return null;
//tuneComment, uploadDate writeDate author firmware signature e.make e.code e.displacement e.compression e.numCylinders
//firmware signature e.make e.code e.displacement e.compression e.numCylinders
try
{
$st = $this->db->prepare("SELECT m.id as mid, make, code, numCylinders, displacement, compression, induction, firmware, signature, uploadDate, views FROM metadata m INNER JOIN engines e ON m.engine = e.id WHERE firmware LIKE :query");
$this->tryBind($st, ":query", "%" . $query . "%"); //TODO exact/wildcard option
if ($st->execute())
{
$result = $st->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
else echo '<div class="error">There was a problem constructing the search query.</div>';
}
catch (PDOException $e)
{
$this->dbError($e);
}
return null;
}
/**
* @brief Get all unique firmware names listed in DB
* @returns List of strings
@ -322,18 +351,26 @@ class MsqurDB
}
/**
* @brief Get all unique firmware versions listed in DB
* @brief Get unique firmware versions listed in DB
* @param $firmware name of firmware to limit versions to
* @returns List of strings
*/
public function getFirmwareVersionList($firmware)
{
if (!$this->connect()) return null;
try
{
if (DEBUG) echo "<div class=\"debug\">Getting firmware list...</div>";
$st = $this->db->prepare("SELECT DISTINCT signature FROM `metadata` WHERE firmware = :fw");
$this->tryBind($st, ":fw", $firmware);
if (DEBUG) echo "<div class=\"debug\">Getting firmware version list...</div>";
if ($firmware == null)
{
$st = $this->db->prepare("SELECT DISTINCT signature FROM `metadata`");
}
else
{
$st = $this->db->prepare("SELECT DISTINCT signature FROM `metadata` WHERE firmware = :fw");
$this->tryBind($st, ":fw", $firmware);
}
if ($st->execute()) return $st->fetchAll(PDO::FETCH_ASSOC);
else echo "<div class=\"error\">Error getting firmware version list for: $firmware</div>";
@ -344,6 +381,24 @@ class MsqurDB
}
}
public function getEngineMakeList()
{
if (!$this->connect()) return null;
try
{
if (DEBUG) echo "<div class=\"debug\">Getting engine make list...</div>";
$st = $this->db->prepare("SELECT DISTINCT make FROM `engines`");
if ($st->execute()) return $st->fetchAll(PDO::FETCH_ASSOC);
else echo "<div class=\"error\">Error getting engine make list</div>";
}
catch (PDOException $e)
{
$this->dbError($e);
}
}
/**
* @brief Update HTML cache of MSQ by metadata id
* @param $id integer The ID of the metadata.

View File

@ -72,6 +72,11 @@ class Msqur
return $this->db->browse($page);
}
public function search($query = "")
{
return $this->db->search($query);
}
/*
* @brief Clean out empty strings and fix PDO::fetch() array
* @param $a an array of arrays or whatever the hell PDO:fetch(PDO:ASSOC) returns
@ -88,30 +93,33 @@ class Msqur
return $ret;
}*/
public function getFirmwareList()
{//TODO Cache
$list = $this->db->getFirmwareList();
private static function parseArray($dbResult, $key)
{
$ret = array();
foreach ($list as $l)
foreach ($dbResult as $l)
{
$fw = $l['firmware'];
if (strlen(trim($fw)) != 0) $ret[] = $fw;
$a = $l[$key];
if (strlen(trim($a)) != 0) $ret[] = $a;
}
return $ret;
}
public function getFirmwareList()
{//TODO Cache
return MSQUR::parseArray($this->db->getFirmwareList(), 'firmware');
}
public function getFirmwareVersionList($fw)
{//TODO Cache
$list = $this->db->getFirmwareVersionList($fw);
$ret = array();
foreach ($list as $l)
{
$fw = $l['signature'];
if (strlen(trim($fw)) != 0) $ret[] = $fw;
}
return $ret;
return MSQUR::parseArray($this->db->getFirmwareVersionList($fw), 'signature');
}
public function getEngineMakeList()
{
return MSQUR::parseArray($this->db->getEngineMakeList(), 'make');
}
/**
* get html from md id
* if msq xml not cached,

46
src/search.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/* msqur - MegaSquirt .msq file viewer web application
Copyright (C) 2015 Nicholas Earwood nearwood@gmail.com http://nearwood.net
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
require "msqur.php";
$msqur->header();
require "view/search.php";
if (isset($_GET['query']))
{
$query = htmlspecialchars($_GET['query']);
$results = $msqur->search($query);
$numResults = count($results);
echo '<div id="content"><div class="info">' . $numResults . ' results.</div>';
echo '<table ng-controller="SearchController">';
echo '<tr><th>ID</th><th>Engine Make</th><th>Engine Code</th><th>Cylinders</th><th>Liters</th><th>Compression</th><th>Aspiration</th><th>Firmware/Version</th><th>Upload Date</th><th>Views</th></tr>';
for ($c = 0; $c < $numResults; $c++)
{
$aspiration = $results[$c]['induction'] == 1 ? "Turbo" : "NA";
echo '<tr><td><a href="view.php?msq=' . $results[$c]['mid'] . '">' . $results[$c]['mid'] . '</a></td><td>' . $results[$c]['make'] . '</td><td>' . $results[$c]['code'] . '</td><td>' . $results[$c]['numCylinders'] . '</td><td>' . $results[$c]['displacement'] . '</td><td>' . $results[$c]['compression'] . ':1</td><td>' . $aspiration . '</td><td>' . $results[$c]['firmware'] . '/' . $results[$c]['signature'] . '</td><td>' . $results[$c]['uploadDate'] . '</td><td>' . $results[$c]['views'] . '</td></tr>';
}
echo '</table></div>';
}
else
{
$query = "";
}
$msqur->footer();
?>

24
src/view/browse.js Normal file
View File

@ -0,0 +1,24 @@
"use strict"
$(function() {
var $makes = $('.browse#makes');
var $models = $('.browse#models');
var $firmware = $('.browse#firmware');
var $versions = $('.browse#versions');
apiGet('engineMakes', $makes);
apiGet('engineModels', $models);
apiGet('firmwareList', $firmware);
apiGet('firmwareVersions', $versions);
function apiGet(method, $target)
{
$.get("api.php?method=" + method, function(data) {
if (method in data) {
data[method].forEach(function(a) {
$target.append('<span>' + a + '</span>');
});
}
}, "json");
}
});

View File

@ -1,38 +0,0 @@
<div>
<form id="filter" action="browse.php" method="get">
<fieldset>
<legend>Browse Filter</legend>
<div>Make: <input name="make" type="text" placeholder="Nissan" maxlength="32" style="width:3em;"/></div>
<div>Engine Code: <input name="ecode" type="text" placeholder="VG30" maxlength="32" style="width:3em;"/></div>
<div>Cylinders: <input name="cylinders" type="number" min="0" value="6" max="99" style="width:3em;"/></div>
<div>Displacement (liters): <input name="liters" type="number" min="0" step="0.01" value="3.0" style="width:4em;"/> +/- <span><input name="literTol="number" min="0" max="50" step="5" value="10">%</span></div>
<div>Compression (X:1) <input name="compression" type="number" min="0" step="0.1" value="9.0" style="width:4em;"/> +/- <span><input name="compressionTol" type="number" min="0" max="50" step="5" value="10">%</span></div>
<div>Aspiration:
<select>
<option value="na" title="AKA: Slow">Naturally Aspirated</option>
<option value="fi" title="The way God intended">Forced Induction</option>
</select>
</div>
<div>Firmware
<select name="firmware">
<option value="any" selected>-- Any --</option>
<?php
$fwList = $msqur->getFirmwareList();
foreach ($fwList as $fw)
{
echo "<option value=\"$fw\">$fw</option>";
}
?>
</select>
</div>
<div>Firmware Version:
<select name="version">
<option value="any" selected>-- Any --</option>
<option value="comms333e2">comms333e2</option>
</select>
</div>
<div><button>Apply</button></div>
</fieldset>
</form>
</div>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" ng-app="msqur">
<head>
<title>MSQur</title>
<meta name="description" content="Megasquirt tune file sharing site">
@ -8,16 +8,17 @@
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/smoothness/jquery-ui.css" />
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.2/angular.min.js"></script>
<script src="view/lib/tablesorter/jquery.tablesorter.min.js"></script>
<script src="view/lib/Chart.js/Chart.min.js"></script>
<script src="view/msqur.js"></script>
</head>
<body>
<div id="navigation"><span><button id="btnUpload">Upload</button></span><span><a href="browse.php">Browse</a></span><span><a>Search</a></span><span><a>Stats</a></span><span id="aboutLink">About</span></div>
<div id="navigation"><span><button id="btnUpload">Upload</button></span><span><a href="browse.php">Browse</a></span><span><a href="search.php">Search</a></span><span><a>Stats</a></span><span><a href="about.php">About</a></span></div>
<div id="upload" style="display:none;">
<form id="engineForm" action="upload.php" method="post" enctype="multipart/form-data">
<div id="fileDropZone"><label for="fileSelect">Drop files here</label>
<input type="file" id="fileSelect" accept=".msq" name="files[]" multiple />
<input required type="file" id="fileSelect" accept=".msq" name="files[]" multiple />
</div>
<output id="fileList"></output>
<div>
@ -25,29 +26,28 @@
<legend>Engine Information</legend>
<div><span>All fields are required. Please enter accurate information to help other users.</span></div>
<div class="formDiv">
<label for="make">Engine Make:</label>
<input name="make" type="text" placeholder="e.g. GM" maxlength="32" style="width:4em;"/>
<label for="make">Engine Make:</label>
<input required name="make" type="text" placeholder="e.g. GM" maxlength="32" style="width:4em;"/>
</div>
<div class="formDiv">
<label for="code">Engine Code:</label>
<input name="code" type="text" placeholder="LS3" maxlength="32" style="width:4em;"/>
<label for="code">Engine Code:</label>
<input required name="code" type="text" placeholder="LS3" maxlength="32" style="width:4em;"/>
</div>
<div class="formDiv">
<label for="displacement">Displacement (liters):</label>
<input name="displacement" type="number" min="0" step="0.01" value="3.0" style="width:4em;"/>
<label for="displacement">Displacement (liters):</label>
<input required name="displacement" type="number" min="0" step="0.1" value="3.0" style="width:4em;"/>
</div>
<div class="formDiv">
<label for="compression">Compression (X:1)</label>
<input name="compression" type="number" min="0" step="0.1" value="9.0" style="width:4em;"/>
<label for="compression">Compression (X:1)</label>
<input required name="compression" type="number" min="0" step="0.1" value="9.0" style="width:4em;"/>
</div>
<div class="formDiv">
<label for="aspiration">Aspiration:</label>
<select name="aspiration">
<option value="na" title="Slow">Naturally Aspirated</option>
<option value="fi" title="Fast">Forced Induction</option>
</select>
<label for="aspiration">Aspiration:</label>
<select required name="aspiration">
<option value="na" title="Slow">Naturally Aspirated</option>
<option value="fi" title="Fast">Forced Induction</option>
</select>
</div>
<input type="hidden" name="upload" value="upload" style="display:none;">
</fieldset>
</div>
</form>

View File

@ -123,6 +123,7 @@ table th, table td {
border: 1px dotted #333;
font-size: smaller;
text-align: center;
white-space: nowrap;
}
/* eh, need to switch top/bottom border dep. on where the header is */
@ -176,14 +177,34 @@ div.chart > canvas.table {
font-size: small;
}
form#filter {
/* display: none; */
form#search #btnSearch {
float: right;
}
input:invalid {
outline: 2px solid red;
}
input:focus:invalid {
color: red;
}
span#literMargin input {
/* display: none; */
}
form#search {
display: none;
#faq .q {
font-weight: bold;
}
#faq li.q:before {
content: "Q: ";
}
#faq li.a:before {
content: "A: ";
}
#faq li.a {
margin-bottom: 1em;
}

View File

@ -16,6 +16,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
"use strict";
var msqur = angular.module('msqur', []);
msqur.controller('BrowseController', function ($scope) {
return true;
});
msqur.controller('SearchController', function ($scope) {
});
$(function() {
$('div#upload').dialog({
modal: true,
@ -23,7 +33,7 @@ $(function() {
title: "Upload Tune Files",
width: "512px",
buttons: {
Upload: upload,
Upload: uploadClick,
Cancel: function() { $(this).dialog('close'); }
}
});
@ -243,10 +253,36 @@ $(function() {
e.dataTransfer.dropEffect = 'copy';
}
function upload()
function simpleValidation(s)
{
//TODO Check files
$('div#upload form').submit();
if (typeof s === 'string' && s.length > 0)
return true;
else
return false;
}
function uploadClick()
{
//var files = $('input#fileSelect').val();
var make = $('input[name="make"]').val();
var model = $('input[name="code"]').val();
var disp = $('input[name="displacement"]').val();
var comp = $('input[name="compression"]').val();
//put in array and map/reduce?
if (simpleValidation(make) && simpleValidation(model) && simpleValidation(disp) && simpleValidation(comp))
{
$('div#upload form').submit();
}
else
{
//TODO some error msg
}
}
function searchClick()
{
$('form#search').submit();
}
$('input#fileSelect').change(uploadAdd);

37
src/view/search.php Normal file
View File

@ -0,0 +1,37 @@
<div ng-controller="SearchController">
<form id="search" action="search.php" method="get">
<fieldset>
<legend>Search Options</legend>
<table>
<tr>
<th><label for="make">Engine Make</label></th>
<th><label for="ecode">Engine Code</label></th>
<th><label for="cylinders">Cylinders</label></th>
<th><label for="liters">Displacement (liters)</label></th>
<th><label for="compression">Compression (X:1)</label></th>
<th><label for="aspiration">Aspiration</label></th>
<th><label for="firmware">Firmware/Version (signature)</label></th>
<!-- th><label for="uploadDate">Upload Date</label></th -->
</tr>
<tr>
<td><input name="make" type="text" placeholder="Nissan" maxlength="32" style="width:5em;"/></td>
<td><input name="ecode" type="text" placeholder="VG30" maxlength="32" style="width:5em;"/></td>
<td><input name="cylinders" type="number" min="0" max="99" style="width:4em;"/></td>
<td><input name="liters" type="number" min="0" step="0.01" style="width:4em;"/> +/- <input name="literTol" type="number" min="0" max="50" step="5" value="10" style="width:4em;">%</td>
<td><input name="compression" type="number" min="0" step="0.1" style="width:4em;"/> +/- <input name="compressionTol" type="number" min="0" max="50" step="5" value="10" style="width:4em;">%</td>
<td>
<select>
<option value="any" title="Any">-- Any --</option>
<option value="na" title="AKA: Slow">Naturally Aspirated</option>
<option value="fi" title="The way God intended">Forced Induction</option>
</select>
</td>
<td><input name="firmware" type="text" placeholder="MS2Extra" maxlength="32" style="width:5em;"/>/<input name="version" type="text" placeholder="" maxlength="32" style="width:5em;"/></td>
<!-- td><input name="uploadDate" type="date" /></td -->
</tr>
</table>
<div><label for="query">Text: <input name="query" type="search" placeholder="Search for any text..."/></div>
<div><button id="btnSearch">Search</button></div>
</fieldset>
</form>
</div>