Removing keywords from server and client
This commit is contained in:
parent
eece4dd876
commit
4f4713ec46
@ -18,10 +18,6 @@
|
|||||||
<div class="col-md-7">
|
<div class="col-md-7">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="pull-right">
|
|
||||||
<button class="btn btn-xs btn-danger" id="forget">Forget</button>
|
|
||||||
<button class="btn btn-xs btn-default" id="learn">Learn</button>
|
|
||||||
</div>
|
|
||||||
<big>Visualizer</big>
|
<big>Visualizer</big>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
@ -37,10 +33,6 @@
|
|||||||
<big>Query</big>
|
<big>Query</big>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="form-group">
|
|
||||||
<label for="searchKeyword">Keyword <span class="label label-warning" id="customized" style="display: none;">Cutomized</span></label>
|
|
||||||
<select id="searchKeyword" class="form-control"></select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="walkingDist">Walking distance (km)</label>
|
<label for="walkingDist">Walking distance (km)</label>
|
||||||
<input class="form-control" type="number" step="0.1" min="0.1" value="1.0" id="walkingDist">
|
<input class="form-control" type="number" step="0.1" min="0.1" value="1.0" id="walkingDist">
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2015 Alex Yatskov <alex@foosoft.net>
|
||||||
The MIT License (MIT)
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
Copyright (c) 2014 Alex Yatskov
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
in the Software without restriction, including without limitation the rights
|
* subject to the following conditions:
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
*
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
furnished to do so, subject to the following conditions:
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
The above copyright notice and this permission notice shall be included in
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
all copies or substantial portions of the Software.
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
*/
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function(hscd) {
|
(function(hscd) {
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -34,7 +29,6 @@
|
|||||||
$.getJSON('/search', _ctx.query, function(results) {
|
$.getJSON('/search', _ctx.query, function(results) {
|
||||||
saveSnapshot(results);
|
saveSnapshot(results);
|
||||||
outputSnapshot(results, true);
|
outputSnapshot(results, true);
|
||||||
setCustomized(true);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,84 +54,17 @@
|
|||||||
|
|
||||||
$.getJSON('/get_parameters', function(parameters) {
|
$.getJSON('/get_parameters', function(parameters) {
|
||||||
_ctx.parameters = parameters;
|
_ctx.parameters = parameters;
|
||||||
for (var keyword in parameters.keywords) {
|
|
||||||
$('#searchKeyword').append($('<option></option>', { value: keyword, text: keyword }));
|
|
||||||
}
|
|
||||||
|
|
||||||
onSearch();
|
onSearch();
|
||||||
|
|
||||||
$('#searchKeyword').change(function() { onSearch(); });
|
|
||||||
$('#minScore,#hintSteps,#walkingDist,#maxResults').change(function() { onSearch(getFeaturesGrapher); });
|
$('#minScore,#hintSteps,#walkingDist,#maxResults').change(function() { onSearch(getFeaturesGrapher); });
|
||||||
$('#historyIndex').on('slideStop', onSelectSnapshot);
|
$('#historyIndex').on('slideStop', onSelectSnapshot);
|
||||||
$('#learn').click(onLearn);
|
|
||||||
$('#forget').click(onForget);
|
|
||||||
$('#customized').click(onReset);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReset() {
|
|
||||||
if (confirm('Reset customizations?')) {
|
|
||||||
onSearch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLearn() {
|
|
||||||
var keyword = prompt('Learn keyword as');
|
|
||||||
if (keyword === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var query = {
|
|
||||||
keyword: keyword,
|
|
||||||
features: _ctx.query.features
|
|
||||||
};
|
|
||||||
|
|
||||||
$.getJSON('/add_keyword', query, function(results) {
|
|
||||||
if (results.success) {
|
|
||||||
_ctx.parameters.keywords[keyword] = _.clone(query.features);
|
|
||||||
$('#searchKeyword').append($('<option></option>', { value: keyword, text: keyword }));
|
|
||||||
$('#searchKeyword').val(keyword);
|
|
||||||
setCustomized(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
alert('Failed to learn keyword');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onForget() {
|
|
||||||
var keyword = $('#searchKeyword').val();
|
|
||||||
if (!confirm('Are you sure you want to delete keyword "' + keyword + '"?')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var query = {
|
|
||||||
keyword: keyword
|
|
||||||
};
|
|
||||||
|
|
||||||
$.getJSON('/remove_keyword', query, function(results) {
|
|
||||||
if (results.success) {
|
|
||||||
$('#searchKeyword option:selected').remove();
|
|
||||||
onSearch();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
alert('Failed to forget keyword');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFeaturesKeyword() {
|
|
||||||
var keyword = $('#searchKeyword').val();
|
|
||||||
return _.clone(_ctx.parameters.keywords[keyword]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFeaturesGrapher() {
|
|
||||||
return _.clone(_ctx.query.features);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSearch(provider) {
|
function onSearch(provider) {
|
||||||
_ctx.query = {
|
_ctx.query = {
|
||||||
features: (provider || getFeaturesKeyword)(),
|
features: _clone(_ctx.query.features),
|
||||||
range: { min: -1.0, max: 1.0 },
|
range: { min: -1.0, max: 1.0 },
|
||||||
walkingDist: parseFloat($('#walkingDist').val()),
|
walkingDist: parseFloat($('#walkingDist').val()),
|
||||||
minScore: parseFloat($('#minScore').val()),
|
minScore: parseFloat($('#minScore').val()),
|
||||||
@ -185,14 +112,12 @@
|
|||||||
$.getJSON('/search', _ctx.query, function(results) {
|
$.getJSON('/search', _ctx.query, function(results) {
|
||||||
saveSnapshot(results);
|
saveSnapshot(results);
|
||||||
outputSnapshot(results, false);
|
outputSnapshot(results, false);
|
||||||
setCustomized(false);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelectSnapshot() {
|
function onSelectSnapshot() {
|
||||||
var index = $('#historyIndex').slider('getValue');
|
var index = $('#historyIndex').slider('getValue');
|
||||||
outputSnapshot(_ctx.log[index], false);
|
outputSnapshot(_ctx.log[index], false);
|
||||||
setCustomized(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSnapshot(results) {
|
function saveSnapshot(results) {
|
||||||
@ -208,17 +133,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCustomized(customized) {
|
|
||||||
if (customized) {
|
|
||||||
$('#customized').show();
|
|
||||||
$('#forget').hide();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#customized').hide();
|
|
||||||
$('#forget').show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function outputSnapshot(results, omitValues) {
|
function outputSnapshot(results, omitValues) {
|
||||||
var columns = {};
|
var columns = {};
|
||||||
for (var name in results.columns) {
|
for (var name in results.columns) {
|
||||||
|
@ -1,28 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (c) 2015 Alex Yatskov <alex@foosoft.net>
|
||||||
The MIT License (MIT)
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
Copyright (c) 2014 Alex Yatskov
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
in the Software without restriction, including without limitation the rights
|
* subject to the following conditions:
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
*
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
furnished to do so, subject to the following conditions:
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
The above copyright notice and this permission notice shall be included in
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
all copies or substantial portions of the Software.
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
*/
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function(grapher) {
|
(function(grapher) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
@ -133,67 +133,6 @@ function loadDb(params) {
|
|||||||
pool = mysql.createPool(params);
|
pool = mysql.createPool(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addKeyword(query, callback) {
|
|
||||||
if (!/^[a-zA-Z0-9\s\-]+$/.test(query.keyword)) {
|
|
||||||
callback({
|
|
||||||
keyword: query.keyword,
|
|
||||||
success: false
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
getKeywords(function(keywords) {
|
|
||||||
var values = [
|
|
||||||
query.keyword,
|
|
||||||
query.features.delicious,
|
|
||||||
query.features.accomodating,
|
|
||||||
query.features.affordable,
|
|
||||||
query.features.atmospheric,
|
|
||||||
query.features.nearby,
|
|
||||||
query.features.accessible
|
|
||||||
];
|
|
||||||
|
|
||||||
pool.query('INSERT INTO keywords VALUES(?, ?, ?, ?, ?, ?, ?)', values, function(err) {
|
|
||||||
callback({
|
|
||||||
keyword: query.keyword,
|
|
||||||
success: err === null
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeKeyword(query, callback) {
|
|
||||||
pool.query('DELETE FROM keywords WHERE name=? AND name NOT IN (SELECT name FROM presets)', [query.keyword], function(err, fields) {
|
|
||||||
callback({
|
|
||||||
keyword: query.keyword,
|
|
||||||
success: err === null && fields.affectedRows > 0
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getKeywords(callback) {
|
|
||||||
pool.query('SELECT * FROM keywords', function(err, rows) {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
var keywords = {};
|
|
||||||
for (var i = 0, count = rows.length; i < count; ++i) {
|
|
||||||
var row = rows[i];
|
|
||||||
keywords[row.name] = {
|
|
||||||
delicious: row.delicious,
|
|
||||||
accomodating: row.accomodating,
|
|
||||||
affordable: row.affordable,
|
|
||||||
atmospheric: row.atmospheric,
|
|
||||||
nearby: row.nearby,
|
|
||||||
accessible: row.access
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(keywords);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRecords(context, callback) {
|
function getRecords(context, callback) {
|
||||||
pool.query('SELECT * FROM reviews', function(err, rows) {
|
pool.query('SELECT * FROM reviews', function(err, rows) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -250,30 +189,13 @@ function computeRecordGeo(records, context) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getData(context, callback) {
|
|
||||||
getKeywords(function(keywords) {
|
|
||||||
getRecords(context, function(records) {
|
|
||||||
callback({
|
|
||||||
keywords: keywords,
|
|
||||||
records: records
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParameters(callback) {
|
|
||||||
getKeywords(function(keywords) {
|
|
||||||
callback({keywords: keywords});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function execQuery(query, callback) {
|
function execQuery(query, callback) {
|
||||||
var context = {
|
var context = {
|
||||||
geo: query.geo,
|
geo: query.geo,
|
||||||
walkingDist: query.walkingDist * 1000.0
|
walkingDist: query.walkingDist * 1000.0
|
||||||
};
|
};
|
||||||
|
|
||||||
getData(context, function(data) {
|
getRecords(context, function(data) {
|
||||||
var searchResults = findRecords(
|
var searchResults = findRecords(
|
||||||
data,
|
data,
|
||||||
query.features,
|
query.features,
|
||||||
@ -308,8 +230,5 @@ function execQuery(query, callback) {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
loadDb: loadDb,
|
loadDb: loadDb,
|
||||||
addKeyword: addKeyword,
|
|
||||||
removeKeyword: removeKeyword,
|
|
||||||
getParameters: getParameters,
|
|
||||||
execQuery: execQuery
|
execQuery: execQuery
|
||||||
};
|
};
|
||||||
|
@ -39,24 +39,6 @@ function main(staticFiles, port) {
|
|||||||
user: 'hscd'
|
user: 'hscd'
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use('/get_parameters', function(req, res) {
|
|
||||||
search.getParameters(function(parameters) {
|
|
||||||
res.json(parameters);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/add_keyword', function(req, res) {
|
|
||||||
search.addKeyword(req.query, function(results) {
|
|
||||||
res.json(results);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/remove_keyword', function(req, res) {
|
|
||||||
search.removeKeyword(req.query, function(results) {
|
|
||||||
res.json(results);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/search', function(req, res) {
|
app.use('/search', function(req, res) {
|
||||||
search.execQuery(req.query, function(results) {
|
search.execQuery(req.query, function(results) {
|
||||||
res.json(results);
|
res.json(results);
|
||||||
|
Loading…
Reference in New Issue
Block a user