* Bump version to 0.0.2-alpha: File Base alpha here
* LHA/LZH archive support via external lha command * Nearly complete upload processor * Set default file base filter if none is set * Additional MenuModule common method/helpers * MLTEV property: tabSwitchesView
This commit is contained in:
parent
8d51c7d47c
commit
99036592ae
|
@ -248,9 +248,36 @@ function getDefaultConfig() {
|
||||||
cmd : '7za',
|
cmd : '7za',
|
||||||
args : [ 'e', '-o{extractPath}', '{archivePath}', '{fileList}' ],
|
args : [ 'e', '-o{extractPath}', '{archivePath}', '{fileList}' ],
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Lha : {
|
||||||
|
//
|
||||||
|
// 'lha' command can be obtained from:
|
||||||
|
// * apt-get: lhasa
|
||||||
|
//
|
||||||
|
// (compress not currently supported)
|
||||||
|
//
|
||||||
|
decompress : {
|
||||||
|
cmd : 'lha',
|
||||||
|
args : [ '-ew={extractPath}', '{archivePath}' ],
|
||||||
|
},
|
||||||
|
list : {
|
||||||
|
cmd : 'lha',
|
||||||
|
args : [ '-l', '{archivePath}' ],
|
||||||
|
entryMatch : '^[\\[a-z\\]]+(?:\\s+[0-9]+\\s+[0-9]+|\\s+)([0-9]+)\\s+[0-9]{2}\\.[0-9]\\%\\s+[A-Za-z]{3}\\s+[0-9]{1,2}\\s+[0-9]{4}\\s+([^\\r\\n]+)$',
|
||||||
|
},
|
||||||
|
extract : {
|
||||||
|
cmd : 'lha',
|
||||||
|
args : [ '-ew={extractPath}', '{archivePath}', '{fileList}' ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
formats : {
|
formats : {
|
||||||
|
//
|
||||||
|
// Resources
|
||||||
|
// * http://www.garykessler.net/library/file_sigs.html
|
||||||
|
//
|
||||||
zip : {
|
zip : {
|
||||||
sig : '504b0304',
|
sig : '504b0304',
|
||||||
offset : 0,
|
offset : 0,
|
||||||
|
@ -285,6 +312,20 @@ function getDefaultConfig() {
|
||||||
exts : [ 'gz' ],
|
exts : [ 'gz' ],
|
||||||
handler : '7Zip',
|
handler : '7Zip',
|
||||||
desc : 'Gzip Archive',
|
desc : 'Gzip Archive',
|
||||||
|
},
|
||||||
|
bzip : {
|
||||||
|
sig : '425a68',
|
||||||
|
offset : 0,
|
||||||
|
exts : [ 'bz2' ],
|
||||||
|
handler : '7Zip',
|
||||||
|
desc : 'BZip2 Archive',
|
||||||
|
},
|
||||||
|
lzh : {
|
||||||
|
sig : '2d6c68',
|
||||||
|
offset : 2,
|
||||||
|
exts : [ 'lzh', 'ice' ],
|
||||||
|
handler : 'Lha',
|
||||||
|
desc : 'LHArc Archive',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -399,7 +440,7 @@ function getDefaultConfig() {
|
||||||
'[0-3]?[0-9][\\-\\/\\.][0-3]?[0-9][\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})', // m/d/yyyy, mm-dd-yyyy, etc.
|
'[0-3]?[0-9][\\-\\/\\.][0-3]?[0-9][\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})', // m/d/yyyy, mm-dd-yyyy, etc.
|
||||||
"\\B('[1789][0-9])\\b", // eslint-disable-line quotes
|
"\\B('[1789][0-9])\\b", // eslint-disable-line quotes
|
||||||
'[0-3]?[0-9][\\-\\/\\.](?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)[\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})',
|
'[0-3]?[0-9][\\-\\/\\.](?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december)[\\-\\/\\.]((?:[0-9]{2})?[0-9]{2})',
|
||||||
'(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december),?\\s[0-9]+(?:st|nd|rd|th)\\s((?:[0-9]{2})?[0-9]{2})', // November 29th, 1997
|
'(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|january|february|march|april|may|june|july|august|september|october|november|december),?\\s[0-9]+(?:st|nd|rd|th)?,?\\s((?:[0-9]{2})?[0-9]{2})', // November 29th, 1997
|
||||||
// :TODO: DD/MMM/YY, DD/MMMM/YY, DD/MMM/YYYY, etc.
|
// :TODO: DD/MMM/YY, DD/MMMM/YY, DD/MMM/YYYY, etc.
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,10 @@ function populateFileEntryWithArchive(fileEntry, filePath, stepInfo, iterator, c
|
||||||
extractList.push(longDescFile.fileName);
|
extractList.push(longDescFile.fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(0 === extractList.length) {
|
||||||
|
return callback(null, [] );
|
||||||
|
}
|
||||||
|
|
||||||
temp.mkdir('enigextract-', (err, tempDir) => {
|
temp.mkdir('enigextract-', (err, tempDir) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
@ -423,6 +427,9 @@ function scanFile(filePath, options, iterator, cb) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let lastCalcHashPercent;
|
||||||
|
|
||||||
async.waterfall(
|
async.waterfall(
|
||||||
[
|
[
|
||||||
function startScan(callback) {
|
function startScan(callback) {
|
||||||
|
@ -449,25 +456,39 @@ function scanFile(filePath, options, iterator, cb) {
|
||||||
|
|
||||||
const stream = fs.createReadStream(filePath);
|
const stream = fs.createReadStream(filePath);
|
||||||
|
|
||||||
|
function updateHashes(data) {
|
||||||
|
async.each( HASH_NAMES, (hashName, nextHash) => {
|
||||||
|
hashes[hashName].update(data);
|
||||||
|
return nextHash(null);
|
||||||
|
}, () => {
|
||||||
|
return stream.resume();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
stream.on('data', data => {
|
stream.on('data', data => {
|
||||||
stream.pause(); // until iterator compeltes
|
stream.pause(); // until iterator compeltes
|
||||||
|
|
||||||
stepInfo.bytesProcessed += data.length;
|
stepInfo.bytesProcessed += data.length;
|
||||||
stepInfo.step = 'hash_update';
|
stepInfo.calcHashPercent = Math.round(((stepInfo.bytesProcessed / stepInfo.byteSize) * 100));
|
||||||
|
|
||||||
callIter(err => {
|
//
|
||||||
if(err) {
|
// Only send 'hash_update' step update if we have a noticable percentage change in progress
|
||||||
stream.destroy(); // cancel read
|
//
|
||||||
return callback(err);
|
if(stepInfo.calcHashPercent === lastCalcHashPercent) {
|
||||||
}
|
updateHashes(data);
|
||||||
|
} else {
|
||||||
|
lastCalcHashPercent = stepInfo.calcHashPercent;
|
||||||
|
stepInfo.step = 'hash_update';
|
||||||
|
|
||||||
async.each( HASH_NAMES, (hashName, nextHash) => {
|
callIter(err => {
|
||||||
hashes[hashName].update(data);
|
if(err) {
|
||||||
return nextHash(null);
|
stream.destroy(); // cancel read
|
||||||
}, () => {
|
return callback(err);
|
||||||
return stream.resume();
|
}
|
||||||
|
|
||||||
|
updateHashes(data);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.on('end', () => {
|
stream.on('end', () => {
|
||||||
|
|
|
@ -61,15 +61,29 @@ module.exports = class FileBaseFilters {
|
||||||
delete this.filters[filterUuid];
|
delete this.filters[filterUuid];
|
||||||
}
|
}
|
||||||
|
|
||||||
load(prop) {
|
load() {
|
||||||
prop = prop || this.client.user.properties.file_base_filters;
|
let filtersProperty = this.client.user.properties.file_base_filters;
|
||||||
|
let defaulted;
|
||||||
|
if(!filtersProperty) {
|
||||||
|
filtersProperty = JSON.stringify(FileBaseFilters.getDefaultFilters());
|
||||||
|
defaulted = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.filters = JSON.parse(prop);
|
this.filters = JSON.parse(filtersProperty);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
this.filters = {};
|
this.filters = FileBaseFilters.getDefaultFilters(); // something bad happened; reset everything back to defaults :(
|
||||||
|
defaulted = true;
|
||||||
|
this.client.log.error( { error : e.message, property : filtersProperty }, 'Failed parsing file base filters property' );
|
||||||
|
}
|
||||||
|
|
||||||
this.client.log.error( { error : e.message, property : prop }, 'Failed parsing file base filters property' );
|
if(defaulted) {
|
||||||
|
this.persist( err => {
|
||||||
|
if(!err) {
|
||||||
|
const defaultActiveUuid = this.toArray()[0].uuid;
|
||||||
|
this.setActive(defaultActiveUuid);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +107,23 @@ module.exports = class FileBaseFilters {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getDefaultFilters() {
|
||||||
|
const filters = {};
|
||||||
|
|
||||||
|
const uuid = uuids.v4();
|
||||||
|
filters[uuid] = {
|
||||||
|
name : 'Default',
|
||||||
|
areaTag : '', // all
|
||||||
|
terms : '', // *
|
||||||
|
tags : '', // *
|
||||||
|
order : 'ascending',
|
||||||
|
sort : 'upload_timestamp',
|
||||||
|
uuid : uuid,
|
||||||
|
};
|
||||||
|
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
static getActiveFilter(client) {
|
static getActiveFilter(client) {
|
||||||
return new FileBaseFilters(client).get(client.user.properties.file_base_filter_active_uuid);
|
return new FileBaseFilters(client).get(client.user.properties.file_base_filter_active_uuid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,7 +280,7 @@ module.exports = class FileEntry {
|
||||||
sqlWhere += clause;
|
sqlWhere += clause;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(filter.sort) {
|
if(filter.sort && filter.sort.length > 0) {
|
||||||
if(Object.keys(FILE_WELL_KNOWN_META).indexOf(filter.sort) > -1) { // sorting via a meta value?
|
if(Object.keys(FILE_WELL_KNOWN_META).indexOf(filter.sort) > -1) { // sorting via a meta value?
|
||||||
sql =
|
sql =
|
||||||
`SELECT f.file_id
|
`SELECT f.file_id
|
||||||
|
@ -294,7 +294,7 @@ module.exports = class FileEntry {
|
||||||
`SELECT f.file_id, f.${filter.sort}
|
`SELECT f.file_id, f.${filter.sort}
|
||||||
FROM file f`;
|
FROM file f`;
|
||||||
|
|
||||||
sqlOrderBy = getOrderByWithCast(`f.${filter.sort}`) + sqlOrderDir;
|
sqlOrderBy = getOrderByWithCast(`f.${filter.sort}`) + ' ' + sqlOrderDir;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sql =
|
sql =
|
||||||
|
@ -305,11 +305,11 @@ module.exports = class FileEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(filter.areaTag) {
|
if(filter.areaTag && filter.areaTag.length > 0) {
|
||||||
appendWhereClause(`f.area_tag="${filter.areaTag}"`);
|
appendWhereClause(`f.area_tag="${filter.areaTag}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(filter.terms) {
|
if(filter.terms && filter.terms.length > 0) {
|
||||||
appendWhereClause(
|
appendWhereClause(
|
||||||
`f.file_id IN (
|
`f.file_id IN (
|
||||||
SELECT rowid
|
SELECT rowid
|
||||||
|
@ -319,7 +319,7 @@ module.exports = class FileEntry {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(filter.tags) {
|
if(filter.tags && filter.tags.length > 0) {
|
||||||
// build list of quoted tags; filter.tags comes in as a space separated values
|
// build list of quoted tags; filter.tags comes in as a space separated values
|
||||||
const tags = filter.tags.split(' ').map( tag => `"${tag}"` ).join(',');
|
const tags = filter.tags.split(' ').map( tag => `"${tag}"` ).join(',');
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const PluginModule = require('./plugin_module.js').PluginModule;
|
const PluginModule = require('./plugin_module.js').PluginModule;
|
||||||
const theme = require('./theme.js');
|
const theme = require('./theme.js');
|
||||||
const ansi = require('./ansi_term.js');
|
const ansi = require('./ansi_term.js');
|
||||||
const ViewController = require('./view_controller.js').ViewController;
|
const ViewController = require('./view_controller.js').ViewController;
|
||||||
const menuUtil = require('./menu_util.js');
|
const menuUtil = require('./menu_util.js');
|
||||||
const Config = require('./config.js').config;
|
const Config = require('./config.js').config;
|
||||||
const stringFormat = require('../core/string_format.js');
|
const stringFormat = require('../core/string_format.js');
|
||||||
|
const MultiLineEditTextView = require('../core/multi_line_edit_text_view.js').MultiLineEditTextView;
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
|
@ -183,6 +184,7 @@ MenuModule.prototype.initSequence = function() {
|
||||||
self.client.term.write(ansi.goto(self.afterArtPos[0], 1));
|
self.client.term.write(ansi.goto(self.afterArtPos[0], 1));
|
||||||
|
|
||||||
// :TODO: really need a client.term.pause() that uses the correct art/etc.
|
// :TODO: really need a client.term.pause() that uses the correct art/etc.
|
||||||
|
// :TODO: Use MenuModule.pausePrompt()
|
||||||
theme.displayThemedPause( { client : self.client }, function keyPressed() {
|
theme.displayThemedPause( { client : self.client }, function keyPressed() {
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
|
@ -389,24 +391,54 @@ MenuModule.prototype.prepViewControllerWithArt = function(name, formId, options,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
MenuModule.prototype.setViewText = function(formName, mciId, text) {
|
MenuModule.prototype.pausePrompt = function(position, cb) {
|
||||||
|
if(!cb && _.isFunction(position)) {
|
||||||
|
cb = position;
|
||||||
|
position = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(position) {
|
||||||
|
position.x = position.row || position.x || 1;
|
||||||
|
position.y = position.col || position.y || 1;
|
||||||
|
|
||||||
|
this.client.term.rawWrite(ansi.goto(position.x, position.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
theme.displayThemedPause( { client : this.client }, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuModule.prototype.setViewText = function(formName, mciId, text, appendMultiline) {
|
||||||
const view = this.viewControllers[formName].getView(mciId);
|
const view = this.viewControllers[formName].getView(mciId);
|
||||||
if(view) {
|
if(!view) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(appendMultiline && (view instanceof MultiLineEditTextView)) {
|
||||||
|
view.addText(text);
|
||||||
|
} else {
|
||||||
view.setText(text);
|
view.setText(text);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MenuModule.prototype.updateCustomViewTextsWithFilter = function(formName, startId, fmtObj, filter) {
|
MenuModule.prototype.updateCustomViewTextsWithFilter = function(formName, startId, fmtObj, options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
let textView;
|
let textView;
|
||||||
let customMciId = startId;
|
let customMciId = startId;
|
||||||
const config = this.menuConfig.config;
|
const config = this.menuConfig.config;
|
||||||
|
|
||||||
while( (textView = this.viewControllers[formName].getView(customMciId)) ) {
|
while( (textView = this.viewControllers[formName].getView(customMciId)) ) {
|
||||||
const key = `${formName}InfoFormat${customMciId}`;
|
const key = `${formName}InfoFormat${customMciId}`; // e.g. "mainInfoFormat10"
|
||||||
const format = config[key];
|
const format = config[key];
|
||||||
|
|
||||||
if(format && (!filter || filter.find(f => format.indexOf(f) > - 1))) {
|
if(format && (!options.filter || options.filter.find(f => format.indexOf(f) > - 1))) {
|
||||||
textView.setText(stringFormat(format, fmtObj));
|
const text = stringFormat(format, fmtObj);
|
||||||
|
|
||||||
|
if(options.appendMultiLine && (textView instanceof MultiLineEditTextView)) {
|
||||||
|
textView.addText(text);
|
||||||
|
} else {
|
||||||
|
textView.setText(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++customMciId;
|
++customMciId;
|
||||||
|
|
|
@ -115,8 +115,10 @@ function MultiLineEditTextView(options) {
|
||||||
|
|
||||||
if ('preview' === this.mode) {
|
if ('preview' === this.mode) {
|
||||||
this.autoScroll = options.autoScroll || true;
|
this.autoScroll = options.autoScroll || true;
|
||||||
|
this.tabSwitchesView = true;
|
||||||
} else {
|
} else {
|
||||||
this.autoScroll = options.autoScroll || false;
|
this.autoScroll = options.autoScroll || false;
|
||||||
|
this.tabSwitchesView = options.tabSwitchesView || false;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// cursorPos represents zero-based row, col positions
|
// cursorPos represents zero-based row, col positions
|
||||||
|
@ -261,30 +263,30 @@ function MultiLineEditTextView(options) {
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getTextLines = function(startIndex, endIndex) {
|
this.getTextLines = function(startIndex, endIndex) {
|
||||||
var lines;
|
var lines;
|
||||||
if(startIndex === endIndex) {
|
if(startIndex === endIndex) {
|
||||||
lines = [ self.textLines[startIndex] ];
|
lines = [ self.textLines[startIndex] ];
|
||||||
} else {
|
} else {
|
||||||
lines = self.textLines.slice(startIndex, endIndex + 1); // "slice extracts up to but not including end."
|
lines = self.textLines.slice(startIndex, endIndex + 1); // "slice extracts up to but not including end."
|
||||||
}
|
}
|
||||||
return lines;
|
return lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getOutputText = function(startIndex, endIndex, eolMarker) {
|
this.getOutputText = function(startIndex, endIndex, eolMarker) {
|
||||||
let lines = self.getTextLines(startIndex, endIndex);
|
let lines = self.getTextLines(startIndex, endIndex);
|
||||||
let text = '';
|
let text = '';
|
||||||
var re = new RegExp('\\t{1,' + (self.tabWidth) + '}', 'g');
|
var re = new RegExp('\\t{1,' + (self.tabWidth) + '}', 'g');
|
||||||
|
|
||||||
lines.forEach(line => {
|
lines.forEach(line => {
|
||||||
text += line.text.replace(re, '\t');
|
text += line.text.replace(re, '\t');
|
||||||
if(eolMarker && line.eol) {
|
if(eolMarker && line.eol) {
|
||||||
text += eolMarker;
|
text += eolMarker;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
};
|
||||||
|
|
||||||
this.getContiguousText = function(startIndex, endIndex, includeEol) {
|
this.getContiguousText = function(startIndex, endIndex, includeEol) {
|
||||||
var lines = self.getTextLines(startIndex, endIndex);
|
var lines = self.getTextLines(startIndex, endIndex);
|
||||||
|
@ -532,7 +534,7 @@ function MultiLineEditTextView(options) {
|
||||||
// before and and after column
|
// before and and after column
|
||||||
//
|
//
|
||||||
// :TODO: Need to clean this string (e.g. collapse tabs)
|
// :TODO: Need to clean this string (e.g. collapse tabs)
|
||||||
text = self.textLines
|
text = self.textLines;
|
||||||
|
|
||||||
// :TODO: Remove original line @ index
|
// :TODO: Remove original line @ index
|
||||||
}
|
}
|
||||||
|
@ -544,18 +546,18 @@ function MultiLineEditTextView(options) {
|
||||||
.replace(/\b/g, '')
|
.replace(/\b/g, '')
|
||||||
.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g);
|
.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g);
|
||||||
|
|
||||||
var wrapped;
|
let wrapped;
|
||||||
|
|
||||||
for(var i = 0; i < text.length; ++i) {
|
for(let i = 0; i < text.length; ++i) {
|
||||||
wrapped = self.wordWrapSingleLine(
|
wrapped = self.wordWrapSingleLine(
|
||||||
text[i], // input
|
text[i], // input
|
||||||
'expand', // tabHandling
|
'expand', // tabHandling
|
||||||
self.dimens.width).wrapped;
|
self.dimens.width).wrapped;
|
||||||
|
|
||||||
for(var j = 0; j < wrapped.length - 1; ++j) {
|
for(let j = 0; j < wrapped.length - 1; ++j) {
|
||||||
self.textLines.splice(index++, 0, { text : wrapped[j] } );
|
self.textLines.splice(index++, 0, { text : wrapped[j] } );
|
||||||
}
|
}
|
||||||
self.textLines.splice(index++, 0, { text : wrapped[wrapped.length - 1], eol : true });
|
self.textLines.splice(index++, 0, { text : wrapped[wrapped.length - 1], eol : true } );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1029,13 +1031,20 @@ MultiLineEditTextView.prototype.setPropertyValue = function(propName, value) {
|
||||||
this.specialKeyMap.next = [ 'tab' ];
|
this.specialKeyMap.next = [ 'tab' ];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'autoScroll' : this.autoScroll = value; break;
|
case 'autoScroll' : this.autoScroll = value; break;
|
||||||
|
|
||||||
|
case 'tabSwitchesView' :
|
||||||
|
this.tabSwitchesView = value;
|
||||||
|
this.specialKeyMap.next = this.specialKeyMap.next || [];
|
||||||
|
this.specialKeyMap.next.push('tab');
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiLineEditTextView.super_.prototype.setPropertyValue.call(this, propName, value);
|
MultiLineEditTextView.super_.prototype.setPropertyValue.call(this, propName, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
var HANDLED_SPECIAL_KEYS = [
|
const HANDLED_SPECIAL_KEYS = [
|
||||||
'up', 'down', 'left', 'right',
|
'up', 'down', 'left', 'right',
|
||||||
'home', 'end',
|
'home', 'end',
|
||||||
'page up', 'page down',
|
'page up', 'page down',
|
||||||
|
@ -1046,13 +1055,13 @@ var HANDLED_SPECIAL_KEYS = [
|
||||||
'delete line',
|
'delete line',
|
||||||
];
|
];
|
||||||
|
|
||||||
var PREVIEW_MODE_KEYS = [
|
const PREVIEW_MODE_KEYS = [
|
||||||
'up', 'down', 'page up', 'page down'
|
'up', 'down', 'page up', 'page down'
|
||||||
];
|
];
|
||||||
|
|
||||||
MultiLineEditTextView.prototype.onKeyPress = function(ch, key) {
|
MultiLineEditTextView.prototype.onKeyPress = function(ch, key) {
|
||||||
var self = this;
|
const self = this;
|
||||||
var handled;
|
let handled;
|
||||||
|
|
||||||
if(key) {
|
if(key) {
|
||||||
HANDLED_SPECIAL_KEYS.forEach(function aKey(specialKey) {
|
HANDLED_SPECIAL_KEYS.forEach(function aKey(specialKey) {
|
||||||
|
@ -1062,8 +1071,10 @@ MultiLineEditTextView.prototype.onKeyPress = function(ch, key) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self[_.camelCase('keyPress ' + specialKey)]();
|
if('tab' !== key.name || !self.tabSwitchesView) {
|
||||||
handled = true;
|
self[_.camelCase('keyPress ' + specialKey)]();
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ exports.stylizeString = stylizeString;
|
||||||
exports.pad = pad;
|
exports.pad = pad;
|
||||||
exports.replaceAt = replaceAt;
|
exports.replaceAt = replaceAt;
|
||||||
exports.isPrintable = isPrintable;
|
exports.isPrintable = isPrintable;
|
||||||
|
exports.stripAllLineFeeds = stripAllLineFeeds;
|
||||||
exports.debugEscapedString = debugEscapedString;
|
exports.debugEscapedString = debugEscapedString;
|
||||||
exports.stringFromNullTermBuffer = stringFromNullTermBuffer;
|
exports.stringFromNullTermBuffer = stringFromNullTermBuffer;
|
||||||
exports.renderSubstr = renderSubstr;
|
exports.renderSubstr = renderSubstr;
|
||||||
|
@ -189,6 +190,10 @@ function stringLength(s) {
|
||||||
return s.length;
|
return s.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stripAllLineFeeds(s) {
|
||||||
|
return s.replace(/\r?\n|[\r\u2028\u2029]/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
function debugEscapedString(s) {
|
function debugEscapedString(s) {
|
||||||
return JSON.stringify(s).slice(1, -1);
|
return JSON.stringify(s).slice(1, -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ const stylizeString = require('./string_util.js').stylizeString;
|
||||||
const renderSubstr = require('./string_util.js').renderSubstr;
|
const renderSubstr = require('./string_util.js').renderSubstr;
|
||||||
const renderStringLength = require('./string_util.js').renderStringLength;
|
const renderStringLength = require('./string_util.js').renderStringLength;
|
||||||
const pipeToAnsi = require('./color_codes.js').pipeToAnsi;
|
const pipeToAnsi = require('./color_codes.js').pipeToAnsi;
|
||||||
|
const stripAllLineFeeds = require('./string_util.js').stripAllLineFeeds;
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
@ -183,7 +184,7 @@ TextView.prototype.setText = function(text, redraw) {
|
||||||
text = text.toString();
|
text = text.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
text = pipeToAnsi(text, this.client); // expand MCI/etc.
|
text = pipeToAnsi(stripAllLineFeeds(text), this.client); // expand MCI/etc.
|
||||||
|
|
||||||
var widthDelta = 0;
|
var widthDelta = 0;
|
||||||
if(this.text && this.text !== text) {
|
if(this.text && this.text !== text) {
|
||||||
|
|
|
@ -99,6 +99,7 @@ function AbracadabraModule(options) {
|
||||||
|
|
||||||
if(_.isString(self.config.tooManyArt)) {
|
if(_.isString(self.config.tooManyArt)) {
|
||||||
theme.displayThemeArt( { client : self.client, name : self.config.tooManyArt }, function displayed() {
|
theme.displayThemeArt( { client : self.client, name : self.config.tooManyArt }, function displayed() {
|
||||||
|
// :TODO: Use MenuModule.pausePrompt()
|
||||||
theme.displayThemedPause( { client : self.client }, function keyPressed() {
|
theme.displayThemedPause( { client : self.client }, function keyPressed() {
|
||||||
callback(new Error('Too many active instances'));
|
callback(new Error('Too many active instances'));
|
||||||
});
|
});
|
||||||
|
@ -106,6 +107,7 @@ function AbracadabraModule(options) {
|
||||||
} else {
|
} else {
|
||||||
self.client.term.write('\nToo many active instances. Try again later.\n');
|
self.client.term.write('\nToo many active instances. Try again later.\n');
|
||||||
|
|
||||||
|
// :TODO: Use MenuModule.pausePrompt()
|
||||||
theme.displayThemedPause( { client : self.client }, function keyPressed() {
|
theme.displayThemedPause( { client : self.client }, function keyPressed() {
|
||||||
callback(new Error('Too many active instances'));
|
callback(new Error('Too many active instances'));
|
||||||
});
|
});
|
||||||
|
|
|
@ -227,25 +227,6 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
return this.updateCustomViewTextsWithFilter(category, startId, this.currentFileEntry.entryInfo);
|
return this.updateCustomViewTextsWithFilter(category, startId, this.currentFileEntry.entryInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
updateCustomLabelsWithFilter(category, startId, filter) {
|
|
||||||
let textView;
|
|
||||||
let customMciId = startId;
|
|
||||||
const config = this.menuConfig.config;
|
|
||||||
|
|
||||||
while( (textView = this.viewControllers[category].getView(customMciId)) ) {
|
|
||||||
const key = `${category}InfoFormat${customMciId}`;
|
|
||||||
const format = config[key];
|
|
||||||
|
|
||||||
if(format && (!filter || filter.find(f => format.indexOf(f) > - 1))) {
|
|
||||||
textView.setText(stringFormat(format, this.currentFileEntry.entryInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
++customMciId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
displayArtAndPrepViewController(name, options, cb) {
|
displayArtAndPrepViewController(name, options, cb) {
|
||||||
const self = this;
|
const self = this;
|
||||||
const config = this.menuConfig.config;
|
const config = this.menuConfig.config;
|
||||||
|
@ -447,7 +428,7 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
self.updateCustomViewTextsWithFilter(
|
self.updateCustomViewTextsWithFilter(
|
||||||
'browse',
|
'browse',
|
||||||
MciViewIds.browse.customRangeStart, self.currentFileEntry.entryInfo,
|
MciViewIds.browse.customRangeStart, self.currentFileEntry.entryInfo,
|
||||||
[ '{webDlLink}', '{webDlExpire}' ]
|
{ filter : [ '{webDlLink}', '{webDlExpire}' ] }
|
||||||
);
|
);
|
||||||
return callback(null);
|
return callback(null);
|
||||||
}
|
}
|
||||||
|
@ -472,7 +453,7 @@ exports.getModule = class FileAreaList extends MenuModule {
|
||||||
'browse',
|
'browse',
|
||||||
MciViewIds.browse.customRangeStart,
|
MciViewIds.browse.customRangeStart,
|
||||||
this.currentFileEntry.entryInfo,
|
this.currentFileEntry.entryInfo,
|
||||||
[ '{isQueued}' ]
|
{ filter : [ '{isQueued}' ] }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ function MessageAreaListModule(options) {
|
||||||
if(_.has(area, 'options.pause') && false === area.options.pause) {
|
if(_.has(area, 'options.pause') && false === area.options.pause) {
|
||||||
return self.prevMenuOnTimeout(1000, cb);
|
return self.prevMenuOnTimeout(1000, cb);
|
||||||
} else {
|
} else {
|
||||||
|
// :TODO: Use MenuModule.pausePrompt()
|
||||||
displayThemedPause( { client : self.client }, () => {
|
displayThemedPause( { client : self.client }, () => {
|
||||||
return self.prevMenu(cb);
|
return self.prevMenu(cb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -71,6 +71,7 @@ function MessageConfListModule(options) {
|
||||||
if(_.has(conf, 'options.pause') && false === conf.options.pause) {
|
if(_.has(conf, 'options.pause') && false === conf.options.pause) {
|
||||||
return self.prevMenuOnTimeout(1000, cb);
|
return self.prevMenuOnTimeout(1000, cb);
|
||||||
} else {
|
} else {
|
||||||
|
// :TODO: Use MenuModule.pausePrompt()
|
||||||
displayThemedPause( { client : self.client }, () => {
|
displayThemedPause( { client : self.client }, () => {
|
||||||
return self.prevMenu(cb);
|
return self.prevMenu(cb);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,20 +3,15 @@
|
||||||
|
|
||||||
// enigma-bbs
|
// enigma-bbs
|
||||||
const MenuModule = require('../core/menu_module.js').MenuModule;
|
const MenuModule = require('../core/menu_module.js').MenuModule;
|
||||||
const ViewController = require('../core/view_controller.js').ViewController;
|
|
||||||
const theme = require('../core/theme.js');
|
|
||||||
const ansi = require('../core/ansi_term.js');
|
|
||||||
const Errors = require('../core/enig_error.js').Errors;
|
|
||||||
const stringFormat = require('../core/string_format.js');
|
const stringFormat = require('../core/string_format.js');
|
||||||
const getSortedAvailableFileAreas = require('../core/file_area.js').getSortedAvailableFileAreas;
|
const getSortedAvailableFileAreas = require('../core/file_area.js').getSortedAvailableFileAreas;
|
||||||
const getAreaDefaultStorageDirectory = require('../core/file_area.js').getAreaDefaultStorageDirectory;
|
const getAreaDefaultStorageDirectory = require('../core/file_area.js').getAreaDefaultStorageDirectory;
|
||||||
const scanFile = require('../core/file_area.js').scanFile;
|
const scanFile = require('../core/file_area.js').scanFile;
|
||||||
const getAreaStorageDirectoryByTag = require('../core/file_area.js').getAreaStorageDirectoryByTag;
|
const ansiGoto = require('../core/ansi_term.js').goto;
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const paths = require('path');
|
|
||||||
|
|
||||||
exports.moduleInfo = {
|
exports.moduleInfo = {
|
||||||
name : 'Upload',
|
name : 'Upload',
|
||||||
|
@ -40,8 +35,11 @@ const MciViewIds = {
|
||||||
},
|
},
|
||||||
|
|
||||||
processing : {
|
processing : {
|
||||||
stepIndicator : 1,
|
calcHashIndicator : 1,
|
||||||
customRangeStart : 10, // 10+ = customs
|
archiveListIndicator : 2,
|
||||||
|
descFileIndicator : 3,
|
||||||
|
|
||||||
|
customRangeStart : 10, // 10+ = customs
|
||||||
},
|
},
|
||||||
|
|
||||||
fileDetails : {
|
fileDetails : {
|
||||||
|
@ -160,6 +158,26 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
const fmtObj = Object.assign( {}, stepInfo);
|
const fmtObj = Object.assign( {}, stepInfo);
|
||||||
let stepIndicatorFmt = '';
|
let stepIndicatorFmt = '';
|
||||||
|
|
||||||
|
const indicatorStates = this.menuConfig.config.indicatorStates || [ '|', '/', '-', '\\' ];
|
||||||
|
const indicatorFinished = this.menuConfig.config.indicatorFinished || '√';
|
||||||
|
|
||||||
|
const indicator = { };
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
function updateIndicator(mci, isFinished) {
|
||||||
|
indicator.mci = mci;
|
||||||
|
|
||||||
|
if(isFinished) {
|
||||||
|
indicator.text = indicatorFinished;
|
||||||
|
} else {
|
||||||
|
self.scanStatus.indicatorPos += 1;
|
||||||
|
if(self.scanStatus.indicatorPos >= indicatorStates.length) {
|
||||||
|
self.scanStatus.indicatorPos = 0;
|
||||||
|
}
|
||||||
|
indicator.text = indicatorStates[self.scanStatus.indicatorPos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch(stepInfo.step) {
|
switch(stepInfo.step) {
|
||||||
case 'start' :
|
case 'start' :
|
||||||
stepIndicatorFmt = this.menuConfig.config.scanningStartFormat || 'Scanning {fileName}';
|
stepIndicatorFmt = this.menuConfig.config.scanningStartFormat || 'Scanning {fileName}';
|
||||||
|
@ -167,28 +185,23 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
|
|
||||||
case 'hash_update' :
|
case 'hash_update' :
|
||||||
stepIndicatorFmt = this.menuConfig.calcHashFormat || 'Calculating hash/checksums: {calcHashPercent}%';
|
stepIndicatorFmt = this.menuConfig.calcHashFormat || 'Calculating hash/checksums: {calcHashPercent}%';
|
||||||
|
updateIndicator(MciViewIds.processing.calcHashIndicator);
|
||||||
this.scanStatus.hashUpdateCount += 1;
|
|
||||||
fmtObj.calcHashPercent = Math.round(((stepInfo.bytesProcessed / stepInfo.byteSize) * 100)).toString();
|
|
||||||
|
|
||||||
if(this.scanStatus.hashUpdateCount % 2) {
|
|
||||||
fmtObj.calcHashIndicator = this.menuConfig.config.hashUpdateIndicator1Fmt || '-';
|
|
||||||
} else {
|
|
||||||
fmtObj.calcHashIndicator = this.menuConfig.config.hashUpdateIndicator2Fmt || '*';
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'hash_finish' :
|
case 'hash_finish' :
|
||||||
stepIndicatorFmt = this.menuConfig.calcHashCompleteFormat || 'Finished calculating hash/checksums';
|
stepIndicatorFmt = this.menuConfig.calcHashCompleteFormat || 'Finished calculating hash/checksums';
|
||||||
|
updateIndicator(MciViewIds.processing.calcHashIndicator, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'archive_list_start' :
|
case 'archive_list_start' :
|
||||||
stepIndicatorFmt = this.menuConfig.extractArchiveListFormat || 'Extracting archive list';
|
stepIndicatorFmt = this.menuConfig.extractArchiveListFormat || 'Extracting archive list';
|
||||||
|
updateIndicator(MciViewIds.processing.archiveListIndicator);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'archive_list_finish' :
|
case 'archive_list_finish' :
|
||||||
fmtObj.archivedFileCount = stepInfo.archiveEntries.length;
|
fmtObj.archivedFileCount = stepInfo.archiveEntries.length;
|
||||||
stepIndicatorFmt = this.menuConfig.extractArchiveListFinishFormat || 'Archive list extracted ({archivedFileCount} files)';
|
stepIndicatorFmt = this.menuConfig.extractArchiveListFinishFormat || 'Archive list extracted ({archivedFileCount} files)';
|
||||||
|
updateIndicator(MciViewIds.processing.archiveListIndicator, true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'archive_list_failed' :
|
case 'archive_list_failed' :
|
||||||
|
@ -197,20 +210,25 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
|
|
||||||
case 'desc_files_start' :
|
case 'desc_files_start' :
|
||||||
stepIndicatorFmt = this.menuConfig.processingDescFilesFormat || 'Processing description files';
|
stepIndicatorFmt = this.menuConfig.processingDescFilesFormat || 'Processing description files';
|
||||||
|
updateIndicator(MciViewIds.processing.descFileIndicator);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'desc_files_finish' :
|
case 'desc_files_finish' :
|
||||||
stepIndicatorFmt = this.menuConfig.processingDescFilesFinishFormat || 'Finished processing description files';
|
stepIndicatorFmt = this.menuConfig.processingDescFilesFinishFormat || 'Finished processing description files';
|
||||||
|
updateIndicator(MciViewIds.processing.descFileIndicator, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stepIndicatorText = stringFormat(stepIndicatorFmt, fmtObj);
|
fmtObj.stepIndicatorText = stringFormat(stepIndicatorFmt, fmtObj);
|
||||||
|
|
||||||
if(this.hasProcessingArt) {
|
if(this.hasProcessingArt) {
|
||||||
this.setViewText('processing', MciViewIds.processing.stepIndicator, stepIndicatorText);
|
this.updateCustomViewTextsWithFilter('processing', MciViewIds.processing.customRangeStart, fmtObj, { appendMultiLine : true } );
|
||||||
this.updateCustomViewTextsWithFilter('processing', MciViewIds.processing.customRangeStart, fmtObj);
|
|
||||||
|
if(indicator.mci && indicator.text) {
|
||||||
|
this.setViewText('processing', indicator.mci, indicator.text);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.client.term.pipeWrite(`${stepIndicatorText}\n`);
|
this.client.term.pipeWrite(fmtObj.stepIndicatorText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +244,7 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
// :TODO: virus scanning/etc. should occur around here
|
// :TODO: virus scanning/etc. should occur around here
|
||||||
|
|
||||||
self.scanStatus = {
|
self.scanStatus = {
|
||||||
hashUpdateCount : 0,
|
indicatorPos : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const scanOpts = {
|
const scanOpts = {
|
||||||
|
@ -239,6 +257,8 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
return nextScanStep(null);
|
return nextScanStep(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.client.log.debug('Scanning upload', { filePath : filePath } );
|
||||||
|
|
||||||
scanFile(filePath, scanOpts, handleScanStep, (err, fileEntry, dupeEntries) => {
|
scanFile(filePath, scanOpts, handleScanStep, (err, fileEntry, dupeEntries) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
return nextFilePath(err);
|
return nextFilePath(err);
|
||||||
|
@ -247,6 +267,8 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
// new or dupe?
|
// new or dupe?
|
||||||
if(dupeEntries.length > 0) {
|
if(dupeEntries.length > 0) {
|
||||||
// 1:n dupes found
|
// 1:n dupes found
|
||||||
|
self.client.log.debug('Duplicate(s) of upload found', { dupeEntries : dupeEntries } );
|
||||||
|
|
||||||
results.dupes = results.dupes.concat(dupeEntries);
|
results.dupes = results.dupes.concat(dupeEntries);
|
||||||
} else {
|
} else {
|
||||||
// new one
|
// new one
|
||||||
|
@ -271,6 +293,17 @@ exports.getModule = class UploadModule extends MenuModule {
|
||||||
function scan(callback) {
|
function scan(callback) {
|
||||||
return self.scanFiles(callback);
|
return self.scanFiles(callback);
|
||||||
},
|
},
|
||||||
|
function pause(scanResults, callback) {
|
||||||
|
if(self.hasProcessingArt) {
|
||||||
|
self.client.term.rawWrite(ansiGoto(self.client.term.termHeight, 1));
|
||||||
|
} else {
|
||||||
|
self.client.term.write('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pausePrompt( () => {
|
||||||
|
return callback(null, scanResults);
|
||||||
|
});
|
||||||
|
},
|
||||||
function displayDupes(scanResults, callback) {
|
function displayDupes(scanResults, callback) {
|
||||||
if(0 === scanResults.dupes.length) {
|
if(0 === scanResults.dupes.length) {
|
||||||
return callback(null, scanResults);
|
return callback(null, scanResults);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "enigma-bbs",
|
"name": "enigma-bbs",
|
||||||
"version": "0.0.1-alpha",
|
"version": "0.0.2-alpha",
|
||||||
"description": "ENiGMA½ Bulletin Board System",
|
"description": "ENiGMA½ Bulletin Board System",
|
||||||
"author": "Bryan Ashby <bryan@l33t.codes>",
|
"author": "Bryan Ashby <bryan@l33t.codes>",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
|
|
Loading…
Reference in New Issue