mirror of https://github.com/requarks/wiki
parent
6ea243e8d4
commit
91d524eb06
File diff suppressed because one or more lines are too long
@ -1,88 +1,84 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
jQuery( document ).ready(function( $ ) {
|
if($('#search-input').length) {
|
||||||
|
|
||||||
if($('#search-input').length) {
|
$('#search-input').focus();
|
||||||
|
|
||||||
$('#search-input').focus();
|
$('.searchresults').css('display', 'block');
|
||||||
|
|
||||||
$('.searchresults').css('display', 'block');
|
var vueHeader = new Vue({
|
||||||
|
el: '#header-container',
|
||||||
var vueHeader = new Vue({
|
data: {
|
||||||
el: '#header-container',
|
searchq: '',
|
||||||
data: {
|
searchres: [],
|
||||||
searchq: '',
|
searchsuggest: [],
|
||||||
searchres: [],
|
searchload: 0,
|
||||||
searchsuggest: [],
|
searchactive: false,
|
||||||
searchload: 0,
|
searchmoveidx: 0,
|
||||||
searchactive: false,
|
searchmovekey: '',
|
||||||
searchmoveidx: 0,
|
searchmovearr: []
|
||||||
searchmovekey: '',
|
},
|
||||||
searchmovearr: []
|
watch: {
|
||||||
|
searchq: (val, oldVal) => {
|
||||||
|
vueHeader.searchmoveidx = 0;
|
||||||
|
if(val.length >= 3) {
|
||||||
|
vueHeader.searchactive = true;
|
||||||
|
vueHeader.searchload++;
|
||||||
|
socket.emit('search', { terms: val }, (data) => {
|
||||||
|
vueHeader.searchres = data.match;
|
||||||
|
vueHeader.searchsuggest = data.suggest;
|
||||||
|
vueHeader.searchmovearr = _.concat([], vueHeader.searchres, vueHeader.searchsuggest);
|
||||||
|
if(vueHeader.searchload > 0) { vueHeader.searchload--; }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
vueHeader.searchactive = false;
|
||||||
|
vueHeader.searchres = [];
|
||||||
|
vueHeader.searchsuggest = [];
|
||||||
|
vueHeader.searchmovearr = [];
|
||||||
|
vueHeader.searchload = 0;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
searchmoveidx: (val, oldVal) => {
|
||||||
searchq: (val, oldVal) => {
|
if(val > 0) {
|
||||||
vueHeader.searchmoveidx = 0;
|
vueHeader.searchmovekey = (vueHeader.searchmovearr[val - 1]) ?
|
||||||
if(val.length >= 3) {
|
'res.' + vueHeader.searchmovearr[val - 1]._id :
|
||||||
vueHeader.searchactive = true;
|
'sug.' + vueHeader.searchmovearr[val - 1];
|
||||||
vueHeader.searchload++;
|
} else {
|
||||||
socket.emit('search', { terms: val }, (data) => {
|
vueHeader.searchmovekey = '';
|
||||||
vueHeader.searchres = data.match;
|
|
||||||
vueHeader.searchsuggest = data.suggest;
|
|
||||||
vueHeader.searchmovearr = _.concat([], vueHeader.searchres, vueHeader.searchsuggest);
|
|
||||||
if(vueHeader.searchload > 0) { vueHeader.searchload--; }
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
vueHeader.searchactive = false;
|
|
||||||
vueHeader.searchres = [];
|
|
||||||
vueHeader.searchsuggest = [];
|
|
||||||
vueHeader.searchmovearr = [];
|
|
||||||
vueHeader.searchload = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
searchmoveidx: (val, oldVal) => {
|
|
||||||
if(val > 0) {
|
|
||||||
vueHeader.searchmovekey = (vueHeader.searchmovearr[val - 1]) ?
|
|
||||||
'res.' + vueHeader.searchmovearr[val - 1]._id :
|
|
||||||
'sug.' + vueHeader.searchmovearr[val - 1];
|
|
||||||
} else {
|
|
||||||
vueHeader.searchmovekey = '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
useSuggestion: (sug) => {
|
||||||
|
vueHeader.searchq = sug;
|
||||||
},
|
},
|
||||||
methods: {
|
closeSearch: () => {
|
||||||
useSuggestion: (sug) => {
|
vueHeader.searchq = '';
|
||||||
vueHeader.searchq = sug;
|
},
|
||||||
},
|
moveSelectSearch: () => {
|
||||||
closeSearch: () => {
|
if(vueHeader.searchmoveidx < 1) { return; }
|
||||||
vueHeader.searchq = '';
|
let i = vueHeader.searchmoveidx - 1;
|
||||||
},
|
|
||||||
moveSelectSearch: () => {
|
|
||||||
if(vueHeader.searchmoveidx < 1) { return; }
|
|
||||||
let i = vueHeader.searchmoveidx - 1;
|
|
||||||
|
|
||||||
if(vueHeader.searchmovearr[i]) {
|
if(vueHeader.searchmovearr[i]) {
|
||||||
window.location.assign('/' + vueHeader.searchmovearr[i]._id);
|
window.location.assign('/' + vueHeader.searchmovearr[i]._id);
|
||||||
} else {
|
} else {
|
||||||
vueHeader.searchq = vueHeader.searchmovearr[i];
|
vueHeader.searchq = vueHeader.searchmovearr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
moveDownSearch: () => {
|
moveDownSearch: () => {
|
||||||
if(vueHeader.searchmoveidx < vueHeader.searchmovearr.length) {
|
if(vueHeader.searchmoveidx < vueHeader.searchmovearr.length) {
|
||||||
vueHeader.searchmoveidx++;
|
vueHeader.searchmoveidx++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
moveUpSearch: () => {
|
moveUpSearch: () => {
|
||||||
if(vueHeader.searchmoveidx > 0) {
|
if(vueHeader.searchmoveidx > 0) {
|
||||||
vueHeader.searchmoveidx--;
|
vueHeader.searchmoveidx--;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
$('main').on('click', vueHeader.closeSearch);
|
|
||||||
|
|
||||||
}
|
$('main').on('click', vueHeader.closeSearch);
|
||||||
|
|
||||||
});
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = (socket) => {
|
||||||
|
|
||||||
|
//-----------------------------------------
|
||||||
|
// SEARCH
|
||||||
|
//-----------------------------------------
|
||||||
|
|
||||||
|
socket.on('search', (data, cb) => {
|
||||||
|
cb = cb || _.noop;
|
||||||
|
entries.search(data.terms).then((results) => {
|
||||||
|
cb(results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//-----------------------------------------
|
||||||
|
// UPLOADS
|
||||||
|
//-----------------------------------------
|
||||||
|
|
||||||
|
socket.on('uploadsGetFolders', (data, cb) => {
|
||||||
|
cb = cb || _.noop;
|
||||||
|
upl.getUploadsFolders().then((f) => {
|
||||||
|
cb(f);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('uploadsCreateFolder', (data, cb) => {
|
||||||
|
cb = cb || _.noop;
|
||||||
|
upl.createUploadsFolder(data.foldername).then((f) => {
|
||||||
|
cb(f);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('uploadsGetImages', (data, cb) => {
|
||||||
|
cb = cb || _.noop;
|
||||||
|
upl.getUploadsFiles('image', data.folder).then((f) => {
|
||||||
|
cb(f);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('uploadsDeleteFile', (data, cb) => {
|
||||||
|
cb = cb || _.noop;
|
||||||
|
upl.deleteUploadsFile(data.uid).then((f) => {
|
||||||
|
cb(f);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
@ -1,133 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const Promise = require('bluebird'),
|
|
||||||
_ = require('lodash'),
|
|
||||||
path = require('path');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search Model
|
|
||||||
*/
|
|
||||||
module.exports = {
|
|
||||||
|
|
||||||
_si: null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize Search model
|
|
||||||
*
|
|
||||||
* @param {Object} appconfig The application config
|
|
||||||
* @return {Object} Search model instance
|
|
||||||
*/
|
|
||||||
init(appconfig) {
|
|
||||||
|
|
||||||
let self = this;
|
|
||||||
|
|
||||||
return self;
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
find(terms) {
|
|
||||||
|
|
||||||
let self = this;
|
|
||||||
terms = _.chain(terms)
|
|
||||||
.deburr()
|
|
||||||
.toLower()
|
|
||||||
.trim()
|
|
||||||
.replace(/[^a-z0-9 ]/g, '')
|
|
||||||
.split(' ')
|
|
||||||
.filter((f) => { return !_.isEmpty(f); })
|
|
||||||
.join(' ')
|
|
||||||
.value();
|
|
||||||
|
|
||||||
return db.Entry.find(
|
|
||||||
{ $text: { $search: terms } },
|
|
||||||
{ score: { $meta: "textScore" }, title: 1 }
|
|
||||||
)
|
|
||||||
.sort({ score: { $meta: "textScore" } })
|
|
||||||
.limit(10)
|
|
||||||
.exec()
|
|
||||||
.then((hits) => {
|
|
||||||
|
|
||||||
/*if(hits.length < 5) {
|
|
||||||
return self._si.matchAsync({
|
|
||||||
beginsWith: terms,
|
|
||||||
threshold: 3,
|
|
||||||
limit: 5,
|
|
||||||
type: 'simple'
|
|
||||||
}).then((matches) => {
|
|
||||||
|
|
||||||
return {
|
|
||||||
match: hits,
|
|
||||||
suggest: matches
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
||||||
} else {*/
|
|
||||||
return {
|
|
||||||
match: hits,
|
|
||||||
suggest: []
|
|
||||||
};
|
|
||||||
//}
|
|
||||||
|
|
||||||
}).catch((err) => {
|
|
||||||
|
|
||||||
if(err.type === 'NotFoundError') {
|
|
||||||
return {
|
|
||||||
match: [],
|
|
||||||
suggest: []
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
winston.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete an entry from the index
|
|
||||||
*
|
|
||||||
* @param {String} The entry path
|
|
||||||
* @return {Promise} Promise of the operation
|
|
||||||
*/
|
|
||||||
delete(entryPath) {
|
|
||||||
|
|
||||||
let self = this;
|
|
||||||
/*let hasResults = false;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
self._si.search({
|
|
||||||
query: {
|
|
||||||
AND: { 'entryPath': [entryPath] }
|
|
||||||
}
|
|
||||||
}).on('data', (results) => {
|
|
||||||
|
|
||||||
hasResults = true;
|
|
||||||
|
|
||||||
if(results.totalHits > 0) {
|
|
||||||
let delIds = _.map(results.hits, 'id');
|
|
||||||
self._si.del(delIds).on('end', () => { return resolve(true); });
|
|
||||||
} else {
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}).on('error', (err) => {
|
|
||||||
|
|
||||||
if(err.type === 'NotFoundError') {
|
|
||||||
resolve(true);
|
|
||||||
} else {
|
|
||||||
winston.error(err);
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
}).on('end', () => {
|
|
||||||
if(!hasResults) {
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
@ -1,184 +0,0 @@
|
|||||||
// ===========================================
|
|
||||||
// REQUARKS WIKI - WebSocket Server
|
|
||||||
// 1.0.0
|
|
||||||
// Licensed under AGPLv3
|
|
||||||
// ===========================================
|
|
||||||
|
|
||||||
global.ROOTPATH = __dirname;
|
|
||||||
global.PROCNAME = 'WS';
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Load Winston
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
var _isDebug = process.env.NODE_ENV === 'development';
|
|
||||||
global.winston = require('./lib/winston')(_isDebug);
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Fetch internal handshake key
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
if(!process.argv[2] || process.argv[2].length !== 40) {
|
|
||||||
winston.error('[WS] Illegal process start. Missing handshake key.');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
global.internalAuth = require('./lib/internalAuth').init(process.argv[2]);;
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Load global modules
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
winston.info('[WS] WS Server is initializing...');
|
|
||||||
|
|
||||||
var appconfig = require('./models/config')('./config.yml');
|
|
||||||
global.db = require('./models/mongo').init(appconfig);
|
|
||||||
global.upl = require('./models/ws/uploads').init(appconfig);
|
|
||||||
global.entries = require('./models/entries').init(appconfig);
|
|
||||||
global.mark = require('./models/markdown');
|
|
||||||
global.search = require('./models/ws/search').init(appconfig);
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Load local modules
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
var _ = require('lodash');
|
|
||||||
var express = require('express');
|
|
||||||
var path = require('path');
|
|
||||||
var http = require('http');
|
|
||||||
var socketio = require('socket.io');
|
|
||||||
var moment = require('moment');
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Define Express App
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
global.app = express();
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Controllers
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
app.get('/', function(req, res){
|
|
||||||
res.send('Requarks Wiki WebSocket server');
|
|
||||||
});
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Start WebSocket server
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
winston.info('[SERVER] Starting WebSocket server on port ' + appconfig.wsPort + '...');
|
|
||||||
|
|
||||||
app.set('port', appconfig.wsPort);
|
|
||||||
var server = http.Server(app);
|
|
||||||
var io = socketio(server);
|
|
||||||
|
|
||||||
server.on('error', (error) => {
|
|
||||||
if (error.syscall !== 'listen') {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (error.code) {
|
|
||||||
case 'EACCES':
|
|
||||||
console.error('Listening on port ' + appconfig.port + ' requires elevated privileges!');
|
|
||||||
process.exit(1);
|
|
||||||
break;
|
|
||||||
case 'EADDRINUSE':
|
|
||||||
console.error('Port ' + appconfig.port + ' is already in use!');
|
|
||||||
process.exit(1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.listen(appconfig.wsPort, () => {
|
|
||||||
winston.info('[WS] WebSocket server started successfully! [RUNNING]');
|
|
||||||
});
|
|
||||||
|
|
||||||
io.on('connection', (socket) => {
|
|
||||||
|
|
||||||
//-----------------------------------------
|
|
||||||
// SEARCH
|
|
||||||
//-----------------------------------------
|
|
||||||
|
|
||||||
socket.on('searchAdd', (data) => {
|
|
||||||
if(internalAuth.validateKey(data.auth)) {
|
|
||||||
search.add(data.content);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('searchDel', (data, cb) => {
|
|
||||||
cb = cb || _.noop;
|
|
||||||
if(internalAuth.validateKey(data.auth)) {
|
|
||||||
search.delete(data.entryPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('search', (data, cb) => {
|
|
||||||
cb = cb || _.noop;
|
|
||||||
search.find(data.terms).then((results) => {
|
|
||||||
cb(results);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
//-----------------------------------------
|
|
||||||
// UPLOADS
|
|
||||||
//-----------------------------------------
|
|
||||||
|
|
||||||
socket.on('uploadsSetFolders', (data) => {
|
|
||||||
if(internalAuth.validateKey(data.auth)) {
|
|
||||||
upl.setUploadsFolders(data.content);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('uploadsGetFolders', (data, cb) => {
|
|
||||||
cb = cb || _.noop;
|
|
||||||
cb(upl.getUploadsFolders());
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('uploadsValidateFolder', (data, cb) => {
|
|
||||||
cb = cb || _.noop;
|
|
||||||
if(internalAuth.validateKey(data.auth)) {
|
|
||||||
cb(upl.validateUploadsFolder(data.content));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('uploadsCreateFolder', (data, cb) => {
|
|
||||||
cb = cb || _.noop;
|
|
||||||
upl.createUploadsFolder(data.foldername).then((fldList) => {
|
|
||||||
cb(fldList);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('uploadsSetFiles', (data) => {
|
|
||||||
if(internalAuth.validateKey(data.auth)) {
|
|
||||||
upl.setUploadsFiles(data.content);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('uploadsAddFiles', (data) => {
|
|
||||||
if(internalAuth.validateKey(data.auth)) {
|
|
||||||
upl.addUploadsFiles(data.content);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('uploadsGetImages', (data, cb) => {
|
|
||||||
cb = cb || _.noop;
|
|
||||||
cb(upl.getUploadsFiles('image', data.folder));
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// ----------------------------------------
|
|
||||||
// Shutdown gracefully
|
|
||||||
// ----------------------------------------
|
|
||||||
|
|
||||||
process.on('disconnect', () => {
|
|
||||||
winston.warn('[WS] Lost connection to main server. Exiting... [' + moment().toISOString() + ']');
|
|
||||||
server.close();
|
|
||||||
process.exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('exit', () => {
|
|
||||||
server.stop();
|
|
||||||
});
|
|
Loading…
Reference in new issue