Bugfix: Email addressparser

Cleanup vendor scripts
This commit is contained in:
djmaze 2020-08-12 11:49:40 +02:00
parent aaf4933b0a
commit a8ef5ec75b
11 changed files with 651 additions and 968 deletions

View file

@ -75,23 +75,23 @@ Things might work in Edge 15-18, Firefox 47-62 and Chrome 54-68 due to one polyf
|js/* |1.14.0 |native |gzip 1.14 |gzip | |js/* |1.14.0 |native |gzip 1.14 |gzip |
|----------- |--------: |--------: |--------: |--------: | |----------- |--------: |--------: |--------: |--------: |
|admin.js |2.130.942 |1.133.275 | 485.481 | 274.632 | |admin.js |2.130.942 |1.130.247 | 485.481 | 273.277 |
|app.js |4.184.455 |2.844.189 | 932.725 | 664.075 | |app.js |4.184.455 |2.840.968 | 932.725 | 662.061 |
|boot.js | 671.522 | 44.029 | 169.502 | 15.460 | |boot.js | 671.522 | 44.029 | 169.502 | 15.460 |
|libs.js | 647.614 | 431.049 | 194.728 | 132.315 | |libs.js | 647.614 | 426.949 | 194.728 | 131.409 |
|polyfills.js | 325.834 | 0 | 71.825 | 0 | |polyfills.js | 325.834 | 0 | 71.825 | 0 |
|TOTAL js |7.960.367 |4.452.542 |1.854.261 |1.086.482 | |TOTAL js |7.960.367 |4.442.193 |1.854.261 |1.082.207 |
|js/min/* |1.14.0 |native |gzip 1.14 |gzip | |js/min/* |1.14.0 |native |gzip 1.14 |gzip |
|--------------- |--------: |--------: |--------: |--------: | |--------------- |--------: |--------: |--------: |--------: |
|admin.min.js | 252.147 | 153.095 | 73.657 | 43.734 | |admin.min.js | 252.147 | 152.759 | 73.657 | 43.564 |
|app.min.js | 511.202 | 378.695 |140.462 | 99.511 | |app.min.js | 511.202 | 378.335 |140.462 | 99.341 |
|boot.min.js | 66.007 | 5.589 | 22.567 | 2.333 | |boot.min.js | 66.007 | 5.589 | 22.567 | 2.333 |
|libs.min.js | 572.545 | 387.636 |176.720 |122.519 | |libs.min.js | 572.545 | 385.139 |176.720 |121.907 |
|polyfills.min.js | 32.452 | 0 | 11.312 | 0 | |polyfills.min.js | 32.452 | 0 | 11.312 | 0 |
|TOTAL js/min |1.434.353 | 925.015 |424.718 |268.097 | |TOTAL js/min |1.434.353 | 921.822 |424.718 |267.145 |
509.338 bytes (156.621 gzip) is not much, but it feels faster. 512.531 bytes (157.573 gzip) is not much, but it feels faster.
|css/* |1.14.0 |native | |css/* |1.14.0 |native |

View file

@ -7,19 +7,15 @@ import { Mime } from 'Common/Mime';
const const
$ = jQuery, $ = jQuery,
$div = $('<div></div>'), $div = $('<div></div>'),
isArray = Array.isArray; isArray = Array.isArray,
htmlmap = {
var htmlspecialchars = ((de,se,gt,lt,sq,dq,bt) => { '&': '&amp;',
return (str, quote_style = 3, double_encode = true) => { '<': '&lt;',
str = (''+str) '>': '&gt;',
.replace(double_encode?de:se,'&amp;') '"': '&quot;',
.replace(gt,'&lt;') "'": '&#x27;'
.replace(lt,'&gt;') },
.replace(bt,'&#x60;'); htmlspecialchars = str => (''+str).replace(/[&<>"']/g, m => htmlmap[m]);
if (quote_style & 1) { str = str.replace(sq,'&#x27;'); }
return (quote_style & 2) ? str.replace(dq,'&quot;') : str;
};
})(/&/g,/&(?![\w#]+;)/gi,/</g,/>/g,/'/g,/"/g,/`/g);
/** /**
* @param {*} value * @param {*} value
@ -89,15 +85,13 @@ export function simpleQueryParser(queryString) {
* @returns {string} * @returns {string}
*/ */
export function fakeMd5(len = 32) { export function fakeMd5(len = 32) {
const line = '0123456789abcdefghijklmnopqrstuvwxyz', const line = '0123456789abcdefghijklmnopqrstuvwxyz';
lineLen = line.length;
len = pInt(len); len = pInt(len);
let result = ''; let result = '';
while (result.length < len) { while (len--)
result += line.substr(Math.round(Math.random() * lineLen), 1); result += line.substr(Math.round(Math.random() * 36), 1);
}
return result; return result;
} }

22
dev/External/ko.js vendored
View file

@ -747,35 +747,33 @@ ko.bindingHandlers.emailsTags = {
$el = $(element), $el = $(element),
fValue = fValueAccessor(), fValue = fValueAccessor(),
fAllBindings = fAllBindingsAccessor(), fAllBindings = fAllBindingsAccessor(),
fAutoCompleteSource = fAllBindings.autoCompleteSource || null, inputDelimiters = [',', ';', '\n'];
inputDelimiters = [',', ';', '\n'],
fFocusCallback = (value) => {
if (fValue && fValue.focused) {
fValue.focused(!!value);
}
};
$el.inputosaurus({ $el.inputosaurus({
parseOnBlur: true, parseOnBlur: true,
allowDragAndDrop: true, allowDragAndDrop: true,
focusCallback: fFocusCallback, focusCallback: value => {
if (fValue && fValue.focused) {
fValue.focused(!!value);
}
},
inputDelimiters: inputDelimiters, inputDelimiters: inputDelimiters,
autoCompleteSource: fAutoCompleteSource, autoCompleteSource: fAllBindings.autoCompleteSource || null,
splitHook: (value) => { splitHook: value => {
const v = value.trim(); const v = value.trim();
if (v && inputDelimiters.includes(v.substr(-1))) { if (v && inputDelimiters.includes(v.substr(-1))) {
return EmailModel.splitEmailLine(value); return EmailModel.splitEmailLine(value);
} }
return null; return null;
}, },
parseHook: (input) => parseHook: input =>
input.map(inputValue => { input.map(inputValue => {
const values = EmailModel.parseEmailLine(inputValue); const values = EmailModel.parseEmailLine(inputValue);
return values.length ? values : inputValue; return values.length ? values : inputValue;
}).flat(Infinity).map( }).flat(Infinity).map(
item => (item.toLine ? [item.toLine(false), item] : [item, null]) item => (item.toLine ? [item.toLine(false), item] : [item, null])
), ),
change: (event) => { change: event => {
$el.data('EmailsTagsValue', event.target.value); $el.data('EmailsTagsValue', event.target.value);
fValue(event.target.value); fValue(event.target.value);
} }

View file

@ -1,4 +1,4 @@
import { encodeHtml, isNonEmptyArray } from 'Common/Utils'; import { encodeHtml } from 'Common/Utils';
'use strict'; 'use strict';
@ -64,12 +64,10 @@ function _handleAddress(tokens) {
comment: [], comment: [],
group: [], group: [],
text: [] text: []
// Filter out <addresses>, (comments) and regular text
}; };
for (var i = 0, len = tokens.length; i < len; i++) {
var token = tokens[i];
// Filter out <addresses>, (comments) and regular text
tokens.forEach(token => {
if (token.type === 'operator') { if (token.type === 'operator') {
switch (token.value) { switch (token.value) {
case '<': case '<':
@ -85,12 +83,10 @@ function _handleAddress(tokens) {
default: default:
state = 'text'; state = 'text';
} }
} else { } else if (token.value) {
if (token.value) { data[state].push(token.value);
data[state].push(token.value);
}
} }
} });
// If there is no text but a comment, replace the two // If there is no text but a comment, replace the two
if (!data.text.length && data.comment.length) { if (!data.text.length && data.comment.length) {
@ -108,25 +104,25 @@ function _handleAddress(tokens) {
} else { } else {
// If no address was found, try to detect one from regular text // If no address was found, try to detect one from regular text
if (!data.address.length && data.text.length) { if (!data.address.length && data.text.length) {
for (var _i = data.text.length - 1; _i >= 0; _i--) { var i = data.text.length;
if (data.text[_i].match(/^[^@\s]+@[^@\s]+$/)) { while (i--) {
data.address = data.text.splice(_i, 1); if (data.text[i].match(/^[^@\s]+@[^@\s]+$/)) {
data.address = data.text.splice(i, 1);
break; break;
} }
} }
var _regexHandler = function _regexHandler(address) {
if (!data.address.length) {
data.address = [address.trim()];
return ' ';
}
return address;
};
// still no address // still no address
if (!data.address.length) { if (!data.address.length) {
for (var _i2 = data.text.length - 1; _i2 >= 0; _i2--) { i = data.text.length;
data.text[_i2] = data.text[_i2].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/, _regexHandler).trim(); while (i--) {
data.text[i] = data.text[i].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/, address => {
if (!data.address.length) {
data.address = [address.trim()];
return '';
}
return address.trim();
});
if (data.address.length) { if (data.address.length) {
break; break;
} }
@ -202,8 +198,8 @@ class Tokenizer
} }
tokenize() { tokenize() {
var list = [], i = this.str.length; var list = [];
while (i--) this.checkChar(this.str[i]); [...this.str].forEach(c => this.checkChar(c));
this.list.forEach(node => { this.list.forEach(node => {
node.value = (node.value || '').toString().trim(); node.value = (node.value || '').toString().trim();
@ -420,7 +416,7 @@ class EmailModel {
static splitEmailLine(line) { static splitEmailLine(line) {
const parsedResult = addressparser(line); const parsedResult = addressparser(line);
if (isNonEmptyArray(parsedResult)) { if (parsedResult.length) {
const result = []; const result = [];
let exists = false; let exists = false;
parsedResult.forEach((item) => { parsedResult.forEach((item) => {
@ -443,7 +439,7 @@ class EmailModel {
static parseEmailLine(line) { static parseEmailLine(line) {
const parsedResult = addressparser(line); const parsedResult = addressparser(line);
if (isNonEmptyArray(parsedResult)) { if (parsedResult.length) {
return parsedResult.map(item => return parsedResult.map(item =>
item.address ? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '') : null item.address ? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '') : null
).filter(value => !!value); ).filter(value => !!value);
@ -463,7 +459,7 @@ class EmailModel {
} }
const result = addressparser(emailAddress); const result = addressparser(emailAddress);
if (isNonEmptyArray(result) && result[0]) { if (result.length) {
this.name = result[0].name || ''; this.name = result[0].name || '';
this.email = result[0].address || ''; this.email = result[0].address || '';
this.clearDuplicateName(); this.clearDuplicateName();

View file

@ -1401,7 +1401,7 @@ class ComposePopupView extends AbstractViewNext {
} }
}); });
this.addAttachmentEnabled(true).dragAndDropEnabled(oJua.isDragAndDropSupported()); this.addAttachmentEnabled(true).dragAndDropEnabled(true);
} else { } else {
this.addAttachmentEnabled(false).dragAndDropEnabled(false); this.addAttachmentEnabled(false).dragAndDropEnabled(false);
} }

View file

@ -18,7 +18,7 @@
*/ */
(function($) { ($ => {
var inputosaurustext = { var inputosaurustext = {
@ -39,22 +39,12 @@
// the value tags are created on the fly when an inputDelimiter is detected // the value tags are created on the fly when an inputDelimiter is detected
inputDelimiters : [',', ';'], inputDelimiters : [',', ';'],
// this separator is used to rejoin all input items back to the value of the original <input>
outputDelimiter : ',',
allowDuplicates : false,
allowDragAndDrop : true, allowDragAndDrop : true,
focusCallback : null, focusCallback : null,
parseOnBlur : false, parseOnBlur : false,
// optional wrapper for widget
wrapperElement : null,
width : null,
// simply passing an autoComplete source (array, string or function) will instantiate autocomplete functionality // simply passing an autoComplete source (array, string or function) will instantiate autocomplete functionality
autoCompleteSource : '', autoCompleteSource : '',
@ -65,17 +55,14 @@
// the array of tag names is passed and expected to be returned as an array after manipulation // the array of tag names is passed and expected to be returned as an array after manipulation
parseHook : null, parseHook : null,
elementHook : null, splitHook : null
// define a placeholder to display when the input is empty
placeholder: null
}, },
_create: function() { _create: function() {
var widget = this, var widget = this,
els = {}, els = {},
o = widget.options, o = widget.options,
placeholder = o.placeholder || this.element.attr('placeholder') || null; placeholder = this.element.attr('placeholder') || null;
this._chosenValues = []; this._chosenValues = [];
@ -85,7 +72,7 @@
if (this.options.allowDragAndDrop) if (this.options.allowDragAndDrop)
{ {
els.ul.droppable({ els.ul.droppable({
'drop': function(event, ui) { 'drop': (event, ui) => {
ui.draggable.addClass('inputosaurus-dropped'); ui.draggable.addClass('inputosaurus-dropped');
els.input.val(ui.draggable.data('inputosaurus-value')); els.input.val(ui.draggable.data('inputosaurus-value'));
@ -106,9 +93,9 @@
els.origInputCont = $('<li class="inputosaurus-input-hidden inputosaurus-required"></li>'); els.origInputCont = $('<li class="inputosaurus-input-hidden inputosaurus-required"></li>');
els.lastEdit = ''; els.lastEdit = '';
els.input.on('focus', function () { els.input.on('focus', () => {
widget._focusTrigger(true); widget._focusTrigger(true);
}).on('blur', function () { }).on('blur', () => {
widget._focusTrigger(false); widget._focusTrigger(false);
}); });
@ -116,21 +103,15 @@
if (placeholder) { if (placeholder) {
o.placeholder = placeholder; o.placeholder = placeholder;
els.input.attr('placeholder', o.placeholder); els.input.attr('placeholder', o.placeholder);
if (o.width) {
els.input.css('min-width', o.width - 50);
}
} }
o.wrapperElement && o.wrapperElement.append(els.ul); this.element.replaceWith(els.ul);
this.element.replaceWith(o.wrapperElement || els.ul);
els.origInputCont.append(this.element).hide(); els.origInputCont.append(this.element).hide();
els.inputCont.append(els.input); els.inputCont.append(els.input);
els.ul.append(els.inputCont); els.ul.append(els.inputCont);
els.ul.append(els.origInputCont); els.ul.append(els.origInputCont);
o.width && els.ul.css('width', o.width);
this.elements = els; this.elements = els;
widget._attachEvents(); widget._attachEvents();
@ -148,13 +129,10 @@
_focusTrigger : function (bValue) { _focusTrigger : function (bValue) {
var widget = this; var widget = this;
window.clearTimeout(this._focusTriggerTimer); clearTimeout(this._focusTriggerTimer);
this._focusTriggerTimer = window.setTimeout(function () { this._focusTriggerTimer = setTimeout(() => {
widget.elements.ul[!bValue ? 'removeClass' : 'addClass']('inputosaurus-focused'); widget.elements.ul[!bValue ? 'removeClass' : 'addClass']('inputosaurus-focused');
if (widget.options.focusCallback) widget.options.focusCallback(bValue);
{
widget.options.focusCallback(bValue);
}
}, 10); }, 10);
}, },
@ -169,7 +147,7 @@
source : this.options.autoCompleteSource, source : this.options.autoCompleteSource,
minLength : 1, minLength : 1,
autoFocus : true, autoFocus : true,
select : function(ev, ui){ select : (ev, ui) => {
ev.preventDefault(); ev.preventDefault();
widget.elements.input.val(ui.item.value); widget.elements.input.val(ui.item.value);
widget.parseInput(); widget.parseInput();
@ -190,9 +168,7 @@
} }
} }
}, },
focus: function () { focus: () => false
return false;
}
}); });
} }
}, },
@ -210,12 +186,6 @@
} }
}, },
/*_closeAutoCompleteMenu : function() {
if(this.options.autoCompleteSource){
this.elements.input.autocomplete('close');
}
},*/
parseInput : function(ev) { parseInput : function(ev) {
var widget = (ev && ev.data.widget) || this, var widget = (ev && ev.data.widget) || this,
val, val,
@ -226,11 +196,7 @@
val = widget.elements.input.val(); val = widget.elements.input.val();
if (val) { if (val) {
if ($.isFunction(widget.options.splitHook)) { hook = widget.options.splitHook(val);
hook = widget.options.splitHook(val);
} else {
delimiterFound = widget._containsDelimiter(val);
}
} }
if (hook) { if (hook) {
@ -246,15 +212,13 @@
values.push(val); values.push(val);
} }
$.isFunction(widget.options.parseHook) && (values = widget.options.parseHook(values)); values = widget.options.parseHook(values);
if(values.length){ if(values.length){
widget._setChosen(values); widget._setChosen(values);
widget.elements.input.val(''); widget.elements.input.val('');
widget._resizeInput(); widget._resizeInput();
} }
widget._resetPlaceholder();
}, },
_inputFocus : function(ev) { _inputFocus : function(ev) {
@ -284,7 +248,7 @@
// reposition autoComplete menu as <ul> grows and shrinks vertically // reposition autoComplete menu as <ul> grows and shrinks vertically
if(widget.options.autoCompleteSource){ if(widget.options.autoCompleteSource){
setTimeout(function(){widget._autoCompleteMenuPosition.call(widget);}, 200); setTimeout(()=>widget._autoCompleteMenuPosition.call(widget), 200);
} }
}, },
@ -297,7 +261,7 @@
var widget = (ev && ev.data.widget) || this; var widget = (ev && ev.data.widget) || this;
inputosaurustext.fakeSpan.text(widget.elements.input.val()); inputosaurustext.fakeSpan.text(widget.elements.input.val());
// window.setTimeout(function () { // setTimeout(function () {
var txtWidth = 25 + inputosaurustext.fakeSpan.width(); var txtWidth = 25 + inputosaurustext.fakeSpan.width();
txtWidth = txtWidth > 50 ? txtWidth : 50; txtWidth = txtWidth > 50 ? txtWidth : 50;
txtWidth = txtWidth < 500 ? txtWidth : 500; txtWidth = txtWidth < 500 ? txtWidth : 500;
@ -305,18 +269,6 @@
// }, 1); // }, 1);
}, },
// resets placeholder on representative input
_resetPlaceholder: function () {
var placeholder = this.options.placeholder,
input = this.elements.input,
width = this.options.width || 'inherit';
if (placeholder && this.element.val().length === 0) {
input.attr('placeholder', placeholder).css('min-width', width - 50)
}else {
input.attr('placeholder', '').css('min-width', 'inherit')
}
},
// if our input contains no value and backspace has been pressed, select the last tag // if our input contains no value and backspace has been pressed, select the last tag
_inputBackspace : function(ev) { _inputBackspace : function(ev) {
var widget = (ev && ev.data.widget) || this, var widget = (ev && ev.data.widget) || this,
@ -349,7 +301,7 @@
next = false next = false
; ;
$.each(widget._chosenValues, function(i,v) { $.each(widget._chosenValues, (i,v) => {
if (v.key === tagKey) if (v.key === tagKey)
{ {
tagName = v.value; tagName = v.value;
@ -369,15 +321,13 @@
$li.after(widget.elements.inputCont); $li.after(widget.elements.inputCont);
widget.elements.input.val(tagName); widget.elements.input.val(tagName);
window.setTimeout(function () { setTimeout(() => widget.elements.input.select(), 100);
widget.elements.input.select();
}, 100);
widget._removeTag(ev); widget._removeTag(ev);
widget._resizeInput(ev); widget._resizeInput(ev);
}, },
_tagKeypress : function(ev) { _tagKeypress : ev => {
var widget = ev.data.widget; var widget = ev.data.widget;
switch(ev.which){ switch(ev.which){
@ -439,7 +389,7 @@
var found = false; var found = false;
$.each(this.options.inputDelimiters, function(k,v) { $.each(this.options.inputDelimiters, (k,v) => {
if(tagStr.indexOf(v) !== -1){ if(tagStr.indexOf(v) !== -1){
found = v; found = v;
} }
@ -455,7 +405,7 @@
return false; return false;
} }
$.each(valArr, function(k,a) { $.each(valArr, (k,a) => {
var v = '', exists = false, var v = '', exists = false,
lastIndex = -1, lastIndex = -1,
obj = { obj = {
@ -466,7 +416,7 @@
v = $.trim(a[0]); v = $.trim(a[0]);
$.each(self._chosenValues, function(kk, vv) { $.each(self._chosenValues, (kk, vv) => {
if (vv.value === self.elements.lastEdit) if (vv.value === self.elements.lastEdit)
{ {
lastIndex = kk; lastIndex = kk;
@ -475,7 +425,7 @@
vv.value === v && (exists = true); vv.value === v && (exists = true);
}); });
if(v !== '' && a && a[1] && (!exists || self.options.allowDuplicates)){ if(v !== '' && a && a[1] && !exists){
obj.key = 'mi_' + Math.random().toString( 16 ).slice( 2, 10 ); obj.key = 'mi_' + Math.random().toString( 16 ).slice( 2, 10 );
obj.value = v; obj.value = v;
@ -505,11 +455,10 @@
}, },
_buildValue : function() { _buildValue : function() {
var widget = this, var value = '';
value = '';
$.each(this._chosenValues, function(k,v) { $.each(this._chosenValues, (k,v) => {
value += value.length ? widget.options.outputDelimiter + v.value : v.value; value += value.length ? ',' + v.value : v.value;
}); });
return value; return value;
@ -542,14 +491,10 @@
$li.draggable({ $li.draggable({
'revert': 'invalid', 'revert': 'invalid',
'revertDuration': 200, 'revertDuration': 200,
'start': function(event, ui) { 'start': (event, ui) => ui.helper.__widget = widget
ui.helper.__widget = widget;
}
}); });
} }
$.isFunction(this.options.elementHook) && (this.options.elementHook($li, obj));
return $li; return $li;
} }
}, },
@ -559,7 +504,7 @@
this.elements.ul.find('li:not(.inputosaurus-required)').remove(); this.elements.ul.find('li:not(.inputosaurus-required)').remove();
$.each(this._chosenValues, function(k, v) { $.each(this._chosenValues, (k, v) => {
var el = self._createTag(v.value, v.key, v.obj); var el = self._createTag(v.value, v.key, v.obj);
if (el) { if (el) {
self.elements.ul.find('li.inputosaurus-input').before(el); self.elements.ul.find('li.inputosaurus-input').before(el);
@ -573,7 +518,7 @@
widget = (ev && ev.data.widget) || this; widget = (ev && ev.data.widget) || this;
$.each(widget._chosenValues, function(k,v) { $.each(widget._chosenValues, (k,v) => {
if(key === v.key){ if(key === v.key){
indexFound = k; indexFound = k;
} }
@ -584,9 +529,7 @@
widget._setValue(widget._buildValue()); widget._setValue(widget._buildValue());
$(ev.currentTarget).closest('li').remove(); $(ev.currentTarget).closest('li').remove();
window.setTimeout(function () { setTimeout(() => widget.elements.input.focus(), 100);
widget.elements.input.focus();
}, 100);
}, },
_removeDraggedTag : function ($li) { _removeDraggedTag : function ($li) {
@ -596,7 +539,7 @@
indexFound = false indexFound = false
; ;
$.each(widget._chosenValues, function(k,v) { $.each(widget._chosenValues, (k,v) => {
if (key === v.key) { if (key === v.key) {
indexFound = k; indexFound = k;
@ -634,12 +577,10 @@
} }
}, },
_tagFocus : function(ev) { _tagFocus : ev => $(ev.currentTarget).parent()[ev.type === 'focusout' ? 'removeClass' : 'addClass']('inputosaurus-selected'),
$(ev.currentTarget).parent()[ev.type === 'focusout' ? 'removeClass' : 'addClass']('inputosaurus-selected');
},
refresh : function() { refresh : function() {
var delim = this.options.outputDelimiter, var delim = ',',
val = this.element.val(), val = this.element.val(),
values = []; values = [];
@ -659,7 +600,7 @@
if (values.length) { if (values.length) {
this._chosenValues = []; this._chosenValues = [];
$.isFunction(this.options.parseHook) && (values = this.options.parseHook(values)); values = this.options.parseHook(values);
this._setChosen(values); this._setChosen(values);
this._renderTags(); this._renderTags();

1067
vendors/jua/jua.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -44,7 +44,11 @@
// parse and assign shortcut // parse and assign shortcut
function assignKey(key, scope, method){ function assignKey(key, scope, method){
var keys = getKeys(key), mods; key = key.replace(/\s/g, '');
var keys = key.split(','), mods;
if ((keys[keys.length - 1]) == '') {
keys[keys.length - 2] += ',';
}
if (method === undefined) { if (method === undefined) {
method = scope; method = scope;
scope = 'all'; scope = 'all';
@ -56,12 +60,12 @@
mods = []; mods = [];
key = keys[i].split('+'); key = keys[i].split('+');
if (key.length > 1){ if (key.length > 1){
mods = getMods(key); mods = key.slice(0, key.length - 1);
mods.forEach((mod, mi) => mods[mi] = _MODIFIERS[mod]);
key = [key[key.length-1]]; key = [key[key.length-1]];
} }
// convert to keycode and... // convert to keycode and...
key = key[0]; key = code(key[0]);
key = code(key);
// ...store handler // ...store handler
if (!(key in _handlers)) _handlers[key] = []; if (!(key in _handlers)) _handlers[key] = [];
@ -78,25 +82,7 @@
// initialize key.<modifier> to false // initialize key.<modifier> to false
for(k in _MODIFIERS) assignKey[k] = false; for(k in _MODIFIERS) assignKey[k] = false;
// set current scope (default 'all') const getScope = () => _scope || 'all';
const
setScope = scope => { _scope = scope || 'all' },
getScope = () => _scope || 'all',
// abstract key logic for assign and unassign
getKeys = key => {
key = key.replace(/\s/g, '');
var keys = key.split(',');
if ((keys[keys.length - 1]) == '') {
keys[keys.length - 2] += ',';
}
return keys;
},
// abstract mods logic for assign and unassign
getMods = key => {
var mods = key.slice(0, key.length - 1);
mods.forEach((mod, mi) => mods[mi] = _MODIFIERS[mod]);
return mods;
};
// set the handlers globally on document // set the handlers globally on document
document.addEventListener('keydown', event => { document.addEventListener('keydown', event => {
@ -170,7 +156,7 @@
// set window.key and window.key.set/get, and the default filter // set window.key and window.key.set/get, and the default filter
global.key = assignKey; global.key = assignKey;
global.key.setScope = setScope; global.key.setScope = scope => { _scope = scope || 'all' };
global.key.getScope = getScope; global.key.getScope = getScope;
global.key.filter = event => { global.key.filter = event => {
var tagName = event.target.tagName; var tagName = event.target.tagName;

263
vendors/qr.js/qr.js vendored
View file

@ -20,10 +20,6 @@
16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24, 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28
]; ];
// Default MIME type.
var DEFAULT_MIME = 'image/png';
// MIME used to initiate a browser download prompt when `qr.save` is called.
var DOWNLOAD_MIME = 'image/octet-stream';
// There are four elements per version. The first two indicate the number of blocks, then the // There are four elements per version. The first two indicate the number of blocks, then the
// data width, and finally the ECC width. // data width, and finally the ECC width.
var ECC_BLOCKS = [ var ECC_BLOCKS = [
@ -131,8 +127,6 @@
0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5, 0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5,
0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69
]; ];
// Mode for node.js file system file writes.
var WRITE_MODE = parseInt('0666', 8);
// Private variables // Private variables
// ----------------- // -----------------
@ -153,16 +147,10 @@
var frameBuffer = []; var frameBuffer = [];
// Fixed part of the image. // Fixed part of the image.
var frameMask = []; var frameMask = [];
// File system within the node.js environment.
var fs;
// Constructor for `img` elements in the node.js environment.
var Image;
// Indicates whether or not this script is running in node.js. // Indicates whether or not this script is running in node.js.
var inNode = false; var inNode = false;
// Generator polynomial. // Generator polynomial.
var polynomial = []; var polynomial = [];
// Save the previous value of the `qr` variable.
var previousQr = root.qr;
// Data input buffer. // Data input buffer.
var stringBuffer = []; var stringBuffer = [];
// Version for the data. // Version for the data.
@ -173,92 +161,14 @@
// Private functions // Private functions
// ----------------- // -----------------
// Create a new canvas using `document.createElement` unless script is running in node.js, in
// which case the `canvas` module is used.
function createCanvas() {
return inNode ? new Canvas() : root.document.createElement('canvas');
}
// Create a new image using `document.createElement` unless script is running in node.js, in
// which case the `canvas` module is used.
function createImage() {
return inNode ? new Image() : root.document.createElement('img');
}
// Force the canvas image to be downloaded in the browser.
// Optionally, a `callback` function can be specified which will be called upon completed. Since
// this is not an asynchronous operation, this is merely convenient and helps simplify the
// calling code.
function download(cvs, data, callback) {
var mime = data.mime || DEFAULT_MIME;
root.location.href = cvs.toDataURL(mime).replace(mime, DOWNLOAD_MIME);
if (typeof callback === 'function') callback();
}
// Normalize the `data` that is provided to the main API. // Normalize the `data` that is provided to the main API.
function normalizeData(data) { const normalizeData = data => {
if (typeof data === 'string') data = { value: data }; if (typeof data === 'string') data = { value: data };
return data || {}; return data || {};
} },
// Asynchronously write the data of the rendered canvas to a given file path.
function writeFile(cvs, data, callback) {
if (typeof data.path !== 'string') {
return callback(new TypeError('Invalid path type: ' + typeof data.path));
}
var fd, buff;
// Write the buffer to the open file stream once both prerequisites are met.
function writeBuffer() {
fs.write(fd, buff, 0, buff.length, 0, function (error) {
fs.close(fd);
callback(error);
});
}
// Create a buffer of the canvas' data.
cvs.toBuffer(function (error, _buff) {
if (error) return callback(error);
buff = _buff;
if (fd) {
writeBuffer();
}
});
// Open a stream for the file to be written.
fs.open(data.path, 'w', WRITE_MODE, function (error, _fd) {
if (error) return callback(error);
fd = _fd;
if (buff) {
writeBuffer();
}
});
}
// Write the data of the rendered canvas to a given file path.
function writeFileSync(cvs, data) {
if (typeof data.path !== 'string') {
throw new TypeError('Invalid path type: ' + typeof data.path);
}
var buff = cvs.toBuffer();
var fd = fs.openSync(data.path, 'w', WRITE_MODE);
try {
fs.writeSync(fd, buff, 0, buff.length, 0);
} finally {
fs.closeSync(fd);
}
}
// Set bit to indicate cell in frame is immutable (symmetric around diagonal). // Set bit to indicate cell in frame is immutable (symmetric around diagonal).
function setMask(x, y) { setMask = (x, y) => {
var bit; var bit;
if (x > y) { if (x > y) {
@ -274,11 +184,11 @@
bit += x; bit += x;
frameMask[bit] = 1; frameMask[bit] = 1;
} },
// Enter alignment pattern. Foreground colour to frame, background to mask. Frame will be merged // Enter alignment pattern. Foreground colour to frame, background to mask. Frame will be merged
// with mask later. // with mask later.
function addAlignment(x, y) { addAlignment = (x, y) => {
var i; var i;
frameBuffer[x + width * y] = 1; frameBuffer[x + width * y] = 1;
@ -296,21 +206,21 @@
setMask(x - i, y - 1); setMask(x - i, y - 1);
setMask(x + i, y + 1); setMask(x + i, y + 1);
} }
} },
// Exponentiation mod N. // Exponentiation mod N.
function modN(x) { modN = x => {
while (x >= 255) { while (x >= 255) {
x -= 255; x -= 255;
x = (x >> 8) + (x & 255); x = (x >> 8) + (x & 255);
} }
return x; return x;
} },
// Calculate and append `ecc` data to the `data` block. If block is in the string buffer the // Calculate and append `ecc` data to the `data` block. If block is in the string buffer the
// indices to buffers are used. // indices to buffers are used.
function appendData(data, dataLength, ecc, eccLength) { appendData = (data, dataLength, ecc, eccLength) => {
var bit, i, j; var bit, i, j;
for (i = 0; i < eccLength; i++) { for (i = 0; i < eccLength; i++) {
@ -334,10 +244,10 @@
stringBuffer[ecc + eccLength - 1] = bit === 255 ? 0 : stringBuffer[ecc + eccLength - 1] = bit === 255 ? 0 :
GALOIS_EXPONENT[modN(bit + polynomial[0])]; GALOIS_EXPONENT[modN(bit + polynomial[0])];
} }
} },
// Check mask since symmetricals use half. // Check mask since symmetricals use half.
function isMasked(x, y) { isMasked = (x, y) => {
var bit; var bit;
if (x > y) { if (x > y) {
@ -352,10 +262,10 @@
bit += x; bit += x;
return frameMask[bit] === 1; return frameMask[bit] === 1;
} },
// Apply the selected mask out of the 8 options. // Apply the selected mask out of the 8 options.
function applyMask(mask) { applyMask = mask => {
var x, y, r3x, r3y; var x, y, r3x, r3y;
switch (mask) { switch (mask) {
@ -463,11 +373,11 @@
break; break;
} }
} },
// Using the table for the length of each run, calculate the amount of bad image. Long runs or // Using the table for the length of each run, calculate the amount of bad image. Long runs or
// those that look like finders are called twice; once for X and Y. // those that look like finders are called twice; once for X and Y.
function getBadRuns(length) { getBadRuns = length => {
var badRuns = 0; var badRuns = 0;
var i; var i;
@ -492,10 +402,10 @@
} }
return badRuns; return badRuns;
} },
// Calculate how bad the masked image is (e.g. blocks, imbalance, runs, or finders). // Calculate how bad the masked image is (e.g. blocks, imbalance, runs, or finders).
function checkBadness() { checkBadness = () => {
var b, b1, bad, big, bw, count, h, x, y; var b, b1, bad, big, bw, count, h, x, y;
bad = bw = count = 0; bad = bw = count = 0;
@ -566,10 +476,10 @@
} }
return bad; return bad;
} },
// Generate the encoded QR image for the string provided. // Generate the encoded QR image for the string provided.
function generateFrame(str) { generateFrame = str => {
var i, j, k, m, t, v, x, y; var i, j, k, m, t, v, x, y;
// Find the smallest version that fits the string. // Find the smallest version that fits the string.
@ -975,13 +885,13 @@
// Finally, return the image data. // Finally, return the image data.
return frameBuffer; return frameBuffer;
} };
// qr.js setup // qr.js setup
// ----------- // -----------
// Build the publicly exposed API. // Build the publicly exposed API.
var qr = { root.qr = {
// Constants // Constants
// --------- // ---------
@ -992,12 +902,13 @@
// QR functions // QR functions
// ------------ // ------------
// Generate the QR code using the data provided and render it on to a `<canvas>` element. // Generate the QR code using the data provided and render it on to a `<canvas>` element before
// returning its data URI.
// If no `<canvas>` element is specified in the argument provided a new one will be created and // If no `<canvas>` element is specified in the argument provided a new one will be created and
// used. // used.
// ECC (error correction capacity) determines how many intential errors are contained in the QR // ECC (error correction capacity) determines how many intential errors are contained in the QR
// code. // code.
canvas: function(data) { toDataURL: data => {
data = normalizeData(data); data = normalizeData(data);
// Module size of the generated QR code (i.e. 1-10). // Module size of the generated QR code (i.e. 1-10).
@ -1006,7 +917,7 @@
size *= 25; size *= 25;
// `<canvas>` element used to render the QR code. // `<canvas>` element used to render the QR code.
var cvs = data.canvas || createCanvas(); var cvs = inNode ? new Canvas() : document.createElement('canvas');
// Retreive the 2D context of the canvas. // Retreive the 2D context of the canvas.
var c2d = cvs.getContext('2d'); var c2d = cvs.getContext('2d');
// Ensure the canvas has the correct dimensions. // Ensure the canvas has the correct dimensions.
@ -1047,131 +958,9 @@
} }
} }
return cvs; return cvs.toDataURL('image/png');
},
// Generate the QR code using the data provided and render it on to a `<img>` element.
// If no `<img>` element is specified in the argument provided a new one will be created and
// used.
// ECC (error correction capacity) determines how many intential errors are contained in the QR
// code.
image: function(data) {
data = normalizeData(data);
// `<canvas>` element only which the QR code is rendered.
var cvs = this.canvas(data);
// `<img>` element used to display the QR code.
var img = data.image || createImage();
// Apply the QR code to `img`.
img.src = cvs.toDataURL(data.mime || DEFAULT_MIME);
img.height = cvs.height;
img.width = cvs.width;
return img;
},
// Generate the QR code using the data provided and render it on to a `<canvas>` element and
// save it as an image file.
// If no `<canvas>` element is specified in the argument provided a new one will be created and
// used.
// ECC (error correction capacity) determines how many intential errors are contained in the QR
// code.
// If called in a browser the `path` property/argument is ignored and will simply prompt the
// user to choose a location and file name. However, if called within node.js the file will be
// saved to specified path.
// A `callback` function must be provided which will be called once the saving process has
// started. If an error occurs it will be passed as the first argument to this function,
// otherwise this argument will be `null`.
save: function(data, path, callback) {
data = normalizeData(data);
switch (typeof path) {
case 'function':
callback = path;
path = null;
break;
case 'string':
data.path = path;
break;
}
// Callback function is required.
if (typeof callback !== 'function') {
throw new TypeError('Invalid callback type: ' + typeof callback);
}
var completed = false;
// `<canvas>` element only which the QR code is rendered.
var cvs = this.canvas(data);
// Simple function to try and ensure that the `callback` function is only called once.
function done(error) {
if (!completed) {
completed = true;
callback(error);
}
}
if (inNode) {
writeFile(cvs, data, done);
} else {
download(cvs, data, done);
}
},
// Generate the QR code using the data provided and render it on to a `<canvas>` element and
// save it as an image file.
// If no `<canvas>` element is specified in the argument provided a new one will be created and
// used.
// ECC (error correction capacity) determines how many intential errors are contained in the QR
// code.
// If called in a browser the `path` property/argument is ignored and will simply prompt the
// user to choose a location and file name. However, if called within node.js the file will be
// saved to specified path.
saveSync: function(data, path) {
data = normalizeData(data);
if (typeof path === 'string') data.path = path;
// `<canvas>` element only which the QR code is rendered.
var cvs = this.canvas(data);
if (inNode) {
writeFileSync(cvs, data);
} else {
download(cvs, data);
}
},
// Generate the QR code using the data provided and render it on to a `<canvas>` element before
// returning its data URI.
// If no `<canvas>` element is specified in the argument provided a new one will be created and
// used.
// ECC (error correction capacity) determines how many intential errors are contained in the QR
// code.
toDataURL: function(data) {
data = normalizeData(data);
return this.canvas(data).toDataURL(data.mime || DEFAULT_MIME);
},
// Utility functions
// -----------------
// Run qr.js in *noConflict* mode, returning the `qr` variable to its previous owner.
// Returns a reference to `qr`.
noConflict: function() {
root.qr = previousQr;
return this;
} }
}; };
// Support
// -------
root.qr = qr;
})(this); })(this);

File diff suppressed because one or more lines are too long