mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-10-01 01:14:20 +08:00
Bugfix: Email addressparser
Cleanup vendor scripts
This commit is contained in:
parent
aaf4933b0a
commit
a8ef5ec75b
11 changed files with 651 additions and 968 deletions
18
README.md
18
README.md
|
@ -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 |
|
||||
|----------- |--------: |--------: |--------: |--------: |
|
||||
|admin.js |2.130.942 |1.133.275 | 485.481 | 274.632 |
|
||||
|app.js |4.184.455 |2.844.189 | 932.725 | 664.075 |
|
||||
|admin.js |2.130.942 |1.130.247 | 485.481 | 273.277 |
|
||||
|app.js |4.184.455 |2.840.968 | 932.725 | 662.061 |
|
||||
|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 |
|
||||
|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 |
|
||||
|--------------- |--------: |--------: |--------: |--------: |
|
||||
|admin.min.js | 252.147 | 153.095 | 73.657 | 43.734 |
|
||||
|app.min.js | 511.202 | 378.695 |140.462 | 99.511 |
|
||||
|admin.min.js | 252.147 | 152.759 | 73.657 | 43.564 |
|
||||
|app.min.js | 511.202 | 378.335 |140.462 | 99.341 |
|
||||
|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 |
|
||||
|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 |
|
||||
|
|
|
@ -7,19 +7,15 @@ import { Mime } from 'Common/Mime';
|
|||
const
|
||||
$ = jQuery,
|
||||
$div = $('<div></div>'),
|
||||
isArray = Array.isArray;
|
||||
|
||||
var htmlspecialchars = ((de,se,gt,lt,sq,dq,bt) => {
|
||||
return (str, quote_style = 3, double_encode = true) => {
|
||||
str = (''+str)
|
||||
.replace(double_encode?de:se,'&')
|
||||
.replace(gt,'<')
|
||||
.replace(lt,'>')
|
||||
.replace(bt,'`');
|
||||
if (quote_style & 1) { str = str.replace(sq,'''); }
|
||||
return (quote_style & 2) ? str.replace(dq,'"') : str;
|
||||
};
|
||||
})(/&/g,/&(?![\w#]+;)/gi,/</g,/>/g,/'/g,/"/g,/`/g);
|
||||
isArray = Array.isArray,
|
||||
htmlmap = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
},
|
||||
htmlspecialchars = str => (''+str).replace(/[&<>"']/g, m => htmlmap[m]);
|
||||
|
||||
/**
|
||||
* @param {*} value
|
||||
|
@ -89,15 +85,13 @@ export function simpleQueryParser(queryString) {
|
|||
* @returns {string}
|
||||
*/
|
||||
export function fakeMd5(len = 32) {
|
||||
const line = '0123456789abcdefghijklmnopqrstuvwxyz',
|
||||
lineLen = line.length;
|
||||
const line = '0123456789abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
len = pInt(len);
|
||||
|
||||
let result = '';
|
||||
while (result.length < len) {
|
||||
result += line.substr(Math.round(Math.random() * lineLen), 1);
|
||||
}
|
||||
while (len--)
|
||||
result += line.substr(Math.round(Math.random() * 36), 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
22
dev/External/ko.js
vendored
22
dev/External/ko.js
vendored
|
@ -747,35 +747,33 @@ ko.bindingHandlers.emailsTags = {
|
|||
$el = $(element),
|
||||
fValue = fValueAccessor(),
|
||||
fAllBindings = fAllBindingsAccessor(),
|
||||
fAutoCompleteSource = fAllBindings.autoCompleteSource || null,
|
||||
inputDelimiters = [',', ';', '\n'],
|
||||
fFocusCallback = (value) => {
|
||||
if (fValue && fValue.focused) {
|
||||
fValue.focused(!!value);
|
||||
}
|
||||
};
|
||||
inputDelimiters = [',', ';', '\n'];
|
||||
|
||||
$el.inputosaurus({
|
||||
parseOnBlur: true,
|
||||
allowDragAndDrop: true,
|
||||
focusCallback: fFocusCallback,
|
||||
focusCallback: value => {
|
||||
if (fValue && fValue.focused) {
|
||||
fValue.focused(!!value);
|
||||
}
|
||||
},
|
||||
inputDelimiters: inputDelimiters,
|
||||
autoCompleteSource: fAutoCompleteSource,
|
||||
splitHook: (value) => {
|
||||
autoCompleteSource: fAllBindings.autoCompleteSource || null,
|
||||
splitHook: value => {
|
||||
const v = value.trim();
|
||||
if (v && inputDelimiters.includes(v.substr(-1))) {
|
||||
return EmailModel.splitEmailLine(value);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
parseHook: (input) =>
|
||||
parseHook: input =>
|
||||
input.map(inputValue => {
|
||||
const values = EmailModel.parseEmailLine(inputValue);
|
||||
return values.length ? values : inputValue;
|
||||
}).flat(Infinity).map(
|
||||
item => (item.toLine ? [item.toLine(false), item] : [item, null])
|
||||
),
|
||||
change: (event) => {
|
||||
change: event => {
|
||||
$el.data('EmailsTagsValue', event.target.value);
|
||||
fValue(event.target.value);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { encodeHtml, isNonEmptyArray } from 'Common/Utils';
|
||||
import { encodeHtml } from 'Common/Utils';
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -64,12 +64,10 @@ function _handleAddress(tokens) {
|
|||
comment: [],
|
||||
group: [],
|
||||
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') {
|
||||
switch (token.value) {
|
||||
case '<':
|
||||
|
@ -85,12 +83,10 @@ function _handleAddress(tokens) {
|
|||
default:
|
||||
state = 'text';
|
||||
}
|
||||
} else {
|
||||
if (token.value) {
|
||||
data[state].push(token.value);
|
||||
}
|
||||
} else if (token.value) {
|
||||
data[state].push(token.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// If there is no text but a comment, replace the two
|
||||
if (!data.text.length && data.comment.length) {
|
||||
|
@ -108,25 +104,25 @@ function _handleAddress(tokens) {
|
|||
} else {
|
||||
// If no address was found, try to detect one from regular text
|
||||
if (!data.address.length && data.text.length) {
|
||||
for (var _i = data.text.length - 1; _i >= 0; _i--) {
|
||||
if (data.text[_i].match(/^[^@\s]+@[^@\s]+$/)) {
|
||||
data.address = data.text.splice(_i, 1);
|
||||
var i = data.text.length;
|
||||
while (i--) {
|
||||
if (data.text[i].match(/^[^@\s]+@[^@\s]+$/)) {
|
||||
data.address = data.text.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var _regexHandler = function _regexHandler(address) {
|
||||
if (!data.address.length) {
|
||||
data.address = [address.trim()];
|
||||
return ' ';
|
||||
}
|
||||
return address;
|
||||
};
|
||||
|
||||
// still no address
|
||||
if (!data.address.length) {
|
||||
for (var _i2 = data.text.length - 1; _i2 >= 0; _i2--) {
|
||||
data.text[_i2] = data.text[_i2].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/, _regexHandler).trim();
|
||||
i = data.text.length;
|
||||
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) {
|
||||
break;
|
||||
}
|
||||
|
@ -202,8 +198,8 @@ class Tokenizer
|
|||
}
|
||||
|
||||
tokenize() {
|
||||
var list = [], i = this.str.length;
|
||||
while (i--) this.checkChar(this.str[i]);
|
||||
var list = [];
|
||||
[...this.str].forEach(c => this.checkChar(c));
|
||||
|
||||
this.list.forEach(node => {
|
||||
node.value = (node.value || '').toString().trim();
|
||||
|
@ -420,7 +416,7 @@ class EmailModel {
|
|||
|
||||
static splitEmailLine(line) {
|
||||
const parsedResult = addressparser(line);
|
||||
if (isNonEmptyArray(parsedResult)) {
|
||||
if (parsedResult.length) {
|
||||
const result = [];
|
||||
let exists = false;
|
||||
parsedResult.forEach((item) => {
|
||||
|
@ -443,7 +439,7 @@ class EmailModel {
|
|||
|
||||
static parseEmailLine(line) {
|
||||
const parsedResult = addressparser(line);
|
||||
if (isNonEmptyArray(parsedResult)) {
|
||||
if (parsedResult.length) {
|
||||
return parsedResult.map(item =>
|
||||
item.address ? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '') : null
|
||||
).filter(value => !!value);
|
||||
|
@ -463,7 +459,7 @@ class EmailModel {
|
|||
}
|
||||
|
||||
const result = addressparser(emailAddress);
|
||||
if (isNonEmptyArray(result) && result[0]) {
|
||||
if (result.length) {
|
||||
this.name = result[0].name || '';
|
||||
this.email = result[0].address || '';
|
||||
this.clearDuplicateName();
|
||||
|
|
|
@ -1401,7 +1401,7 @@ class ComposePopupView extends AbstractViewNext {
|
|||
}
|
||||
});
|
||||
|
||||
this.addAttachmentEnabled(true).dragAndDropEnabled(oJua.isDragAndDropSupported());
|
||||
this.addAttachmentEnabled(true).dragAndDropEnabled(true);
|
||||
} else {
|
||||
this.addAttachmentEnabled(false).dragAndDropEnabled(false);
|
||||
}
|
||||
|
|
127
vendors/inputosaurus/inputosaurus.js
vendored
127
vendors/inputosaurus/inputosaurus.js
vendored
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
|
||||
(function($) {
|
||||
($ => {
|
||||
|
||||
var inputosaurustext = {
|
||||
|
||||
|
@ -39,22 +39,12 @@
|
|||
// the value tags are created on the fly when an inputDelimiter is detected
|
||||
inputDelimiters : [',', ';'],
|
||||
|
||||
// this separator is used to rejoin all input items back to the value of the original <input>
|
||||
outputDelimiter : ',',
|
||||
|
||||
allowDuplicates : false,
|
||||
|
||||
allowDragAndDrop : true,
|
||||
|
||||
focusCallback : null,
|
||||
|
||||
parseOnBlur : false,
|
||||
|
||||
// optional wrapper for widget
|
||||
wrapperElement : null,
|
||||
|
||||
width : null,
|
||||
|
||||
// simply passing an autoComplete source (array, string or function) will instantiate autocomplete functionality
|
||||
autoCompleteSource : '',
|
||||
|
||||
|
@ -65,17 +55,14 @@
|
|||
// the array of tag names is passed and expected to be returned as an array after manipulation
|
||||
parseHook : null,
|
||||
|
||||
elementHook : null,
|
||||
|
||||
// define a placeholder to display when the input is empty
|
||||
placeholder: null
|
||||
splitHook : null
|
||||
},
|
||||
|
||||
_create: function() {
|
||||
var widget = this,
|
||||
els = {},
|
||||
o = widget.options,
|
||||
placeholder = o.placeholder || this.element.attr('placeholder') || null;
|
||||
placeholder = this.element.attr('placeholder') || null;
|
||||
|
||||
this._chosenValues = [];
|
||||
|
||||
|
@ -85,7 +72,7 @@
|
|||
if (this.options.allowDragAndDrop)
|
||||
{
|
||||
els.ul.droppable({
|
||||
'drop': function(event, ui) {
|
||||
'drop': (event, ui) => {
|
||||
|
||||
ui.draggable.addClass('inputosaurus-dropped');
|
||||
els.input.val(ui.draggable.data('inputosaurus-value'));
|
||||
|
@ -106,9 +93,9 @@
|
|||
els.origInputCont = $('<li class="inputosaurus-input-hidden inputosaurus-required"></li>');
|
||||
els.lastEdit = '';
|
||||
|
||||
els.input.on('focus', function () {
|
||||
els.input.on('focus', () => {
|
||||
widget._focusTrigger(true);
|
||||
}).on('blur', function () {
|
||||
}).on('blur', () => {
|
||||
widget._focusTrigger(false);
|
||||
});
|
||||
|
||||
|
@ -116,21 +103,15 @@
|
|||
if (placeholder) {
|
||||
o.placeholder = 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(o.wrapperElement || els.ul);
|
||||
this.element.replaceWith(els.ul);
|
||||
els.origInputCont.append(this.element).hide();
|
||||
|
||||
els.inputCont.append(els.input);
|
||||
els.ul.append(els.inputCont);
|
||||
els.ul.append(els.origInputCont);
|
||||
|
||||
o.width && els.ul.css('width', o.width);
|
||||
|
||||
this.elements = els;
|
||||
|
||||
widget._attachEvents();
|
||||
|
@ -148,13 +129,10 @@
|
|||
|
||||
_focusTrigger : function (bValue) {
|
||||
var widget = this;
|
||||
window.clearTimeout(this._focusTriggerTimer);
|
||||
this._focusTriggerTimer = window.setTimeout(function () {
|
||||
clearTimeout(this._focusTriggerTimer);
|
||||
this._focusTriggerTimer = setTimeout(() => {
|
||||
widget.elements.ul[!bValue ? 'removeClass' : 'addClass']('inputosaurus-focused');
|
||||
if (widget.options.focusCallback)
|
||||
{
|
||||
widget.options.focusCallback(bValue);
|
||||
}
|
||||
widget.options.focusCallback(bValue);
|
||||
}, 10);
|
||||
},
|
||||
|
||||
|
@ -169,7 +147,7 @@
|
|||
source : this.options.autoCompleteSource,
|
||||
minLength : 1,
|
||||
autoFocus : true,
|
||||
select : function(ev, ui){
|
||||
select : (ev, ui) => {
|
||||
ev.preventDefault();
|
||||
widget.elements.input.val(ui.item.value);
|
||||
widget.parseInput();
|
||||
|
@ -190,9 +168,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
focus: function () {
|
||||
return false;
|
||||
}
|
||||
focus: () => false
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -210,12 +186,6 @@
|
|||
}
|
||||
},
|
||||
|
||||
/*_closeAutoCompleteMenu : function() {
|
||||
if(this.options.autoCompleteSource){
|
||||
this.elements.input.autocomplete('close');
|
||||
}
|
||||
},*/
|
||||
|
||||
parseInput : function(ev) {
|
||||
var widget = (ev && ev.data.widget) || this,
|
||||
val,
|
||||
|
@ -226,11 +196,7 @@
|
|||
val = widget.elements.input.val();
|
||||
|
||||
if (val) {
|
||||
if ($.isFunction(widget.options.splitHook)) {
|
||||
hook = widget.options.splitHook(val);
|
||||
} else {
|
||||
delimiterFound = widget._containsDelimiter(val);
|
||||
}
|
||||
hook = widget.options.splitHook(val);
|
||||
}
|
||||
|
||||
if (hook) {
|
||||
|
@ -246,15 +212,13 @@
|
|||
values.push(val);
|
||||
}
|
||||
|
||||
$.isFunction(widget.options.parseHook) && (values = widget.options.parseHook(values));
|
||||
values = widget.options.parseHook(values);
|
||||
|
||||
if(values.length){
|
||||
widget._setChosen(values);
|
||||
widget.elements.input.val('');
|
||||
widget._resizeInput();
|
||||
}
|
||||
|
||||
widget._resetPlaceholder();
|
||||
},
|
||||
|
||||
_inputFocus : function(ev) {
|
||||
|
@ -284,7 +248,7 @@
|
|||
|
||||
// reposition autoComplete menu as <ul> grows and shrinks vertically
|
||||
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;
|
||||
inputosaurustext.fakeSpan.text(widget.elements.input.val());
|
||||
|
||||
// window.setTimeout(function () {
|
||||
// setTimeout(function () {
|
||||
var txtWidth = 25 + inputosaurustext.fakeSpan.width();
|
||||
txtWidth = txtWidth > 50 ? txtWidth : 50;
|
||||
txtWidth = txtWidth < 500 ? txtWidth : 500;
|
||||
|
@ -305,18 +269,6 @@
|
|||
// }, 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
|
||||
_inputBackspace : function(ev) {
|
||||
var widget = (ev && ev.data.widget) || this,
|
||||
|
@ -349,7 +301,7 @@
|
|||
next = false
|
||||
;
|
||||
|
||||
$.each(widget._chosenValues, function(i,v) {
|
||||
$.each(widget._chosenValues, (i,v) => {
|
||||
if (v.key === tagKey)
|
||||
{
|
||||
tagName = v.value;
|
||||
|
@ -369,15 +321,13 @@
|
|||
$li.after(widget.elements.inputCont);
|
||||
|
||||
widget.elements.input.val(tagName);
|
||||
window.setTimeout(function () {
|
||||
widget.elements.input.select();
|
||||
}, 100);
|
||||
setTimeout(() => widget.elements.input.select(), 100);
|
||||
|
||||
widget._removeTag(ev);
|
||||
widget._resizeInput(ev);
|
||||
},
|
||||
|
||||
_tagKeypress : function(ev) {
|
||||
_tagKeypress : ev => {
|
||||
var widget = ev.data.widget;
|
||||
switch(ev.which){
|
||||
|
||||
|
@ -439,7 +389,7 @@
|
|||
|
||||
var found = false;
|
||||
|
||||
$.each(this.options.inputDelimiters, function(k,v) {
|
||||
$.each(this.options.inputDelimiters, (k,v) => {
|
||||
if(tagStr.indexOf(v) !== -1){
|
||||
found = v;
|
||||
}
|
||||
|
@ -455,7 +405,7 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
$.each(valArr, function(k,a) {
|
||||
$.each(valArr, (k,a) => {
|
||||
var v = '', exists = false,
|
||||
lastIndex = -1,
|
||||
obj = {
|
||||
|
@ -466,7 +416,7 @@
|
|||
|
||||
v = $.trim(a[0]);
|
||||
|
||||
$.each(self._chosenValues, function(kk, vv) {
|
||||
$.each(self._chosenValues, (kk, vv) => {
|
||||
if (vv.value === self.elements.lastEdit)
|
||||
{
|
||||
lastIndex = kk;
|
||||
|
@ -475,7 +425,7 @@
|
|||
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.value = v;
|
||||
|
@ -505,11 +455,10 @@
|
|||
},
|
||||
|
||||
_buildValue : function() {
|
||||
var widget = this,
|
||||
value = '';
|
||||
var value = '';
|
||||
|
||||
$.each(this._chosenValues, function(k,v) {
|
||||
value += value.length ? widget.options.outputDelimiter + v.value : v.value;
|
||||
$.each(this._chosenValues, (k,v) => {
|
||||
value += value.length ? ',' + v.value : v.value;
|
||||
});
|
||||
|
||||
return value;
|
||||
|
@ -542,14 +491,10 @@
|
|||
$li.draggable({
|
||||
'revert': 'invalid',
|
||||
'revertDuration': 200,
|
||||
'start': function(event, ui) {
|
||||
ui.helper.__widget = widget;
|
||||
}
|
||||
'start': (event, ui) => ui.helper.__widget = widget
|
||||
});
|
||||
}
|
||||
|
||||
$.isFunction(this.options.elementHook) && (this.options.elementHook($li, obj));
|
||||
|
||||
return $li;
|
||||
}
|
||||
},
|
||||
|
@ -559,7 +504,7 @@
|
|||
|
||||
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);
|
||||
if (el) {
|
||||
self.elements.ul.find('li.inputosaurus-input').before(el);
|
||||
|
@ -573,7 +518,7 @@
|
|||
widget = (ev && ev.data.widget) || this;
|
||||
|
||||
|
||||
$.each(widget._chosenValues, function(k,v) {
|
||||
$.each(widget._chosenValues, (k,v) => {
|
||||
if(key === v.key){
|
||||
indexFound = k;
|
||||
}
|
||||
|
@ -584,9 +529,7 @@
|
|||
widget._setValue(widget._buildValue());
|
||||
|
||||
$(ev.currentTarget).closest('li').remove();
|
||||
window.setTimeout(function () {
|
||||
widget.elements.input.focus();
|
||||
}, 100);
|
||||
setTimeout(() => widget.elements.input.focus(), 100);
|
||||
},
|
||||
|
||||
_removeDraggedTag : function ($li) {
|
||||
|
@ -596,7 +539,7 @@
|
|||
indexFound = false
|
||||
;
|
||||
|
||||
$.each(widget._chosenValues, function(k,v) {
|
||||
$.each(widget._chosenValues, (k,v) => {
|
||||
if (key === v.key) {
|
||||
|
||||
indexFound = k;
|
||||
|
@ -634,12 +577,10 @@
|
|||
}
|
||||
},
|
||||
|
||||
_tagFocus : function(ev) {
|
||||
$(ev.currentTarget).parent()[ev.type === 'focusout' ? 'removeClass' : 'addClass']('inputosaurus-selected');
|
||||
},
|
||||
_tagFocus : ev => $(ev.currentTarget).parent()[ev.type === 'focusout' ? 'removeClass' : 'addClass']('inputosaurus-selected'),
|
||||
|
||||
refresh : function() {
|
||||
var delim = this.options.outputDelimiter,
|
||||
var delim = ',',
|
||||
val = this.element.val(),
|
||||
values = [];
|
||||
|
||||
|
@ -659,7 +600,7 @@
|
|||
if (values.length) {
|
||||
this._chosenValues = [];
|
||||
|
||||
$.isFunction(this.options.parseHook) && (values = this.options.parseHook(values));
|
||||
values = this.options.parseHook(values);
|
||||
|
||||
this._setChosen(values);
|
||||
this._renderTags();
|
||||
|
|
1067
vendors/jua/jua.js
vendored
1067
vendors/jua/jua.js
vendored
File diff suppressed because it is too large
Load diff
2
vendors/jua/jua.min.js
vendored
2
vendors/jua/jua.min.js
vendored
File diff suppressed because one or more lines are too long
34
vendors/keymaster/keymaster.js
vendored
34
vendors/keymaster/keymaster.js
vendored
|
@ -44,7 +44,11 @@
|
|||
|
||||
// parse and assign shortcut
|
||||
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) {
|
||||
method = scope;
|
||||
scope = 'all';
|
||||
|
@ -56,12 +60,12 @@
|
|||
mods = [];
|
||||
key = keys[i].split('+');
|
||||
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]];
|
||||
}
|
||||
// convert to keycode and...
|
||||
key = key[0];
|
||||
key = code(key);
|
||||
key = code(key[0]);
|
||||
// ...store handler
|
||||
if (!(key in _handlers)) _handlers[key] = [];
|
||||
|
||||
|
@ -78,25 +82,7 @@
|
|||
// initialize key.<modifier> to false
|
||||
for(k in _MODIFIERS) assignKey[k] = false;
|
||||
|
||||
// set current scope (default '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;
|
||||
};
|
||||
const getScope = () => _scope || 'all';
|
||||
|
||||
// set the handlers globally on document
|
||||
document.addEventListener('keydown', event => {
|
||||
|
@ -170,7 +156,7 @@
|
|||
|
||||
// set window.key and window.key.set/get, and the default filter
|
||||
global.key = assignKey;
|
||||
global.key.setScope = setScope;
|
||||
global.key.setScope = scope => { _scope = scope || 'all' };
|
||||
global.key.getScope = getScope;
|
||||
global.key.filter = event => {
|
||||
var tagName = event.target.tagName;
|
||||
|
|
263
vendors/qr.js/qr.js
vendored
263
vendors/qr.js/qr.js
vendored
|
@ -20,10 +20,6 @@
|
|||
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
|
||||
];
|
||||
// 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
|
||||
// data width, and finally the ECC width.
|
||||
var ECC_BLOCKS = [
|
||||
|
@ -131,8 +127,6 @@
|
|||
0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5,
|
||||
0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69
|
||||
];
|
||||
// Mode for node.js file system file writes.
|
||||
var WRITE_MODE = parseInt('0666', 8);
|
||||
|
||||
// Private variables
|
||||
// -----------------
|
||||
|
@ -153,16 +147,10 @@
|
|||
var frameBuffer = [];
|
||||
// Fixed part of the image.
|
||||
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.
|
||||
var inNode = false;
|
||||
// Generator polynomial.
|
||||
var polynomial = [];
|
||||
// Save the previous value of the `qr` variable.
|
||||
var previousQr = root.qr;
|
||||
// Data input buffer.
|
||||
var stringBuffer = [];
|
||||
// Version for the data.
|
||||
|
@ -173,92 +161,14 @@
|
|||
// 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.
|
||||
function normalizeData(data) {
|
||||
const normalizeData = data => {
|
||||
if (typeof data === 'string') data = { value: 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).
|
||||
function setMask(x, y) {
|
||||
setMask = (x, y) => {
|
||||
var bit;
|
||||
|
||||
if (x > y) {
|
||||
|
@ -274,11 +184,11 @@
|
|||
bit += x;
|
||||
|
||||
frameMask[bit] = 1;
|
||||
}
|
||||
},
|
||||
|
||||
// Enter alignment pattern. Foreground colour to frame, background to mask. Frame will be merged
|
||||
// with mask later.
|
||||
function addAlignment(x, y) {
|
||||
addAlignment = (x, y) => {
|
||||
var i;
|
||||
|
||||
frameBuffer[x + width * y] = 1;
|
||||
|
@ -296,21 +206,21 @@
|
|||
setMask(x - i, y - 1);
|
||||
setMask(x + i, y + 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Exponentiation mod N.
|
||||
function modN(x) {
|
||||
modN = x => {
|
||||
while (x >= 255) {
|
||||
x -= 255;
|
||||
x = (x >> 8) + (x & 255);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
},
|
||||
|
||||
// Calculate and append `ecc` data to the `data` block. If block is in the string buffer the
|
||||
// indices to buffers are used.
|
||||
function appendData(data, dataLength, ecc, eccLength) {
|
||||
appendData = (data, dataLength, ecc, eccLength) => {
|
||||
var bit, i, j;
|
||||
|
||||
for (i = 0; i < eccLength; i++) {
|
||||
|
@ -334,10 +244,10 @@
|
|||
stringBuffer[ecc + eccLength - 1] = bit === 255 ? 0 :
|
||||
GALOIS_EXPONENT[modN(bit + polynomial[0])];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Check mask since symmetricals use half.
|
||||
function isMasked(x, y) {
|
||||
isMasked = (x, y) => {
|
||||
var bit;
|
||||
|
||||
if (x > y) {
|
||||
|
@ -352,10 +262,10 @@
|
|||
bit += x;
|
||||
|
||||
return frameMask[bit] === 1;
|
||||
}
|
||||
},
|
||||
|
||||
// Apply the selected mask out of the 8 options.
|
||||
function applyMask(mask) {
|
||||
applyMask = mask => {
|
||||
var x, y, r3x, r3y;
|
||||
|
||||
switch (mask) {
|
||||
|
@ -463,11 +373,11 @@
|
|||
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 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.
|
||||
function getBadRuns(length) {
|
||||
getBadRuns = length => {
|
||||
var badRuns = 0;
|
||||
var i;
|
||||
|
||||
|
@ -492,10 +402,10 @@
|
|||
}
|
||||
|
||||
return badRuns;
|
||||
}
|
||||
},
|
||||
|
||||
// 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;
|
||||
bad = bw = count = 0;
|
||||
|
||||
|
@ -566,10 +476,10 @@
|
|||
}
|
||||
|
||||
return bad;
|
||||
}
|
||||
},
|
||||
|
||||
// Generate the encoded QR image for the string provided.
|
||||
function generateFrame(str) {
|
||||
generateFrame = str => {
|
||||
var i, j, k, m, t, v, x, y;
|
||||
|
||||
// Find the smallest version that fits the string.
|
||||
|
@ -975,13 +885,13 @@
|
|||
|
||||
// Finally, return the image data.
|
||||
return frameBuffer;
|
||||
}
|
||||
};
|
||||
|
||||
// qr.js setup
|
||||
// -----------
|
||||
|
||||
// Build the publicly exposed API.
|
||||
var qr = {
|
||||
root.qr = {
|
||||
|
||||
// Constants
|
||||
// ---------
|
||||
|
@ -992,12 +902,13 @@
|
|||
// 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
|
||||
// used.
|
||||
// ECC (error correction capacity) determines how many intential errors are contained in the QR
|
||||
// code.
|
||||
canvas: function(data) {
|
||||
toDataURL: data => {
|
||||
data = normalizeData(data);
|
||||
|
||||
// Module size of the generated QR code (i.e. 1-10).
|
||||
|
@ -1006,7 +917,7 @@
|
|||
size *= 25;
|
||||
|
||||
// `<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.
|
||||
var c2d = cvs.getContext('2d');
|
||||
// Ensure the canvas has the correct dimensions.
|
||||
|
@ -1047,131 +958,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
return cvs;
|
||||
},
|
||||
|
||||
// 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;
|
||||
return cvs.toDataURL('image/png');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Support
|
||||
// -------
|
||||
|
||||
root.qr = qr;
|
||||
|
||||
})(this);
|
||||
|
|
2
vendors/qr.js/qr.min.js
vendored
2
vendors/qr.js/qr.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue