diff --git a/README.md b/README.md
index 1a1ad0a0d..5ee2fb1c5 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@ This fork has the following changes:
* Embed boot.js and boot.css into index.html
* Ongoing removal of old JavaScript code (things are native these days)
* Added modified [Squire](https://github.com/neilj/Squire) HTML editor as replacement for CKEditor
+* Split Admin specific JavaScript code from User code
### Removal of old JavaScript
@@ -89,23 +90,23 @@ Things might work in Edge 18, Firefox 50-62 and Chrome 54-68 due to one polyfill
|js/* |1.14.0 |native |
|----------- |--------: |--------: |
-|admin.js |2.130.942 | 935.611 |
-|app.js |4.184.455 |2.517.449 |
+|admin.js |2.130.942 | 857.772 |
+|app.js |4.184.455 |2.507.407 |
|boot.js | 671.522 | 5.777 |
|libs.js | 647.614 | 327.257 |
|polyfills.js | 325.834 | 0 |
-|TOTAL |7.960.367 |3.786.094 |
+|TOTAL |7.960.367 |3.698.213 |
|js/min/* |1.14.0 |native |gzip 1.14 |gzip |brotli |
|--------------- |--------: |--------: |--------: |--------: |--------: |
-|admin.min.js | 252.147 | 128.146 | 73.657 | 37.448 | 32.137 |
-|app.min.js | 511.202 | 344.299 |140.462 | 90.265 | 73.006 |
+|admin.min.js | 252.147 | 117.678 | 73.657 | 33.668 | 29.096 |
+|app.min.js | 511.202 | 342.012 |140.462 | 89.893 | 72.807 |
|boot.min.js | 66.007 | 3.101 | 22.567 | 1.576 | 1.346 |
|libs.min.js | 572.545 | 304.000 |176.720 | 94.870 | 83.524 |
|polyfills.min.js | 32.452 | 0 | 11.312 | 0 | 0 |
-|TOTAL |1.434.353 | 779.546 |424.718 |224.159 |190.013 |
+|TOTAL |1.434.353 | 766.791 |424.718 |220.007 |186.773 |
-654.807 bytes (200.559 gzip) is not much, but it feels faster.
+667.562 bytes (204.711 gzip) is not much, but it feels faster.
### CSS changes
@@ -130,8 +131,8 @@ Things might work in Edge 18, Firefox 50-62 and Chrome 54-68 due to one polyfill
|css/* |1.14.0 |native |gzip 1.14 |gzip |brotli |
|-------------- |-------: |-------: |------: |------: |------: |
-|app.css | 340.334 | 253.691 | 46,959 | 36.574 | 30.777 |
-|app.min.css | 274.791 | 207.298 | 39.618 | 32.001 | 27.155 |
+|app.css | 340.334 | 254.033 | 46,959 | 36.648 | 30.815 |
+|app.min.css | 274.791 | 207.558 | 39.618 | 32.050 | 27.234 |
|boot.css | | 2.538 | | 837 | 668 |
|boot.min.css | | 2.055 | | 732 | 560 |
diff --git a/dev/App/Admin.js b/dev/App/Admin.js
index e3e185e68..5ae00477b 100644
--- a/dev/App/Admin.js
+++ b/dev/App/Admin.js
@@ -1,4 +1,4 @@
-import ko from 'ko';
+import ko from 'External/Admin/ko';
import { StorageResultType } from 'Common/Enums';
diff --git a/dev/App/User.js b/dev/App/User.js
index 3f0ff3471..16f240bff 100644
--- a/dev/App/User.js
+++ b/dev/App/User.js
@@ -72,7 +72,10 @@ import { startScreens, showScreenPopup } from 'Knoin/Knoin';
import { AbstractApp } from 'App/Abstract';
-const doc = document, Settings = rl.settings;
+require('External/User/ko');
+
+const doc = document,
+ Settings = rl.settings;
class AppUser extends AbstractApp {
constructor() {
diff --git a/dev/External/Admin/ko.js b/dev/External/Admin/ko.js
new file mode 100644
index 000000000..b2ba46881
--- /dev/null
+++ b/dev/External/Admin/ko.js
@@ -0,0 +1,68 @@
+import { SaveSettingsStep } from 'Common/Enums';
+
+const ko = window.ko;
+
+ko.bindingHandlers.saveTrigger = {
+ init: (element) => {
+ element.saveTriggerType = element.matches('input[type=text],input[type=email],input[type=password],select,textarea')
+ ? 'input' : 'custom';
+
+ if ('custom' === element.saveTriggerType) {
+ element.append(
+ ' ',
+ Element.fromHTML(''),
+ Element.fromHTML(''),
+ Element.fromHTML('')
+ );
+ element.classList.add('settings-saved-trigger');
+ } else {
+ element.classList.add('settings-saved-trigger-input');
+ }
+ },
+ update: (element, fValueAccessor) => {
+ const value = parseInt(ko.unwrap(fValueAccessor()),10);
+ if ('custom' === element.saveTriggerType) {
+ element.querySelector('.animated').hidden = value !== SaveSettingsStep.Animate;
+ element.querySelector('.success').hidden = value !== SaveSettingsStep.TrueResult;
+ element.querySelector('.error').hidden = value !== SaveSettingsStep.FalseResult;
+ } else if (value !== SaveSettingsStep.Animate) {
+ element.classList.toggle('success', value === SaveSettingsStep.TrueResult);
+ element.classList.toggle('error', value === SaveSettingsStep.FalseResult);
+ }
+ }
+};
+
+ko.extenders.idleTrigger = (target) => {
+ target.trigger = ko.observable(SaveSettingsStep.Idle);
+ return target;
+};
+
+ko.extenders.posInterer = (target, defaultVal) => {
+ const Utils = require('Common/Utils'),
+ result = ko.computed({
+ read: target,
+ write: (newValue) => {
+ let val = Utils.pInt(newValue.toString(), defaultVal);
+ if (0 >= val) {
+ val = defaultVal;
+ }
+
+ if (val === target() && '' + val !== '' + newValue) {
+ target(val + 1);
+ }
+
+ target(val);
+ }
+ });
+
+ result(target());
+ return result;
+};
+
+// functions
+
+ko.observable.fn.idleTrigger = function() {
+ return this.extend({ 'idleTrigger': true });
+};
+
+export default ko;
diff --git a/dev/External/User/ko.js b/dev/External/User/ko.js
new file mode 100644
index 000000000..6da8566f8
--- /dev/null
+++ b/dev/External/User/ko.js
@@ -0,0 +1,263 @@
+import { bMobileDevice } from 'Common/Globals';
+
+const ko = window.ko,
+ $ = jQuery;
+
+ko.bindingHandlers.editor = {
+ init: (element, fValueAccessor) => {
+ let editor = null;
+
+ const fValue = fValueAccessor(),
+ HtmlEditor = require('Common/HtmlEditor').default,
+ fUpdateEditorValue = () => fValue && fValue.__editor && fValue.__editor.setHtmlOrPlain(fValue()),
+ fUpdateKoValue = () => fValue && fValue.__editor && fValue(fValue.__editor.getDataWithHtmlMark()),
+ fOnReady = () => {
+ fValue.__editor = editor;
+ fUpdateEditorValue();
+ };
+
+ if (ko.isObservable(fValue) && HtmlEditor) {
+ editor = new HtmlEditor(element, fUpdateKoValue, fOnReady, fUpdateKoValue);
+
+ fValue.__fetchEditorValue = fUpdateKoValue;
+
+ fValue.subscribe(fUpdateEditorValue);
+
+ // ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
+ // });
+ }
+ }
+};
+
+let ttn = (element, fValueAccessor) => require('Common/Momentor').timeToNode(element, ko.unwrap(fValueAccessor()));
+ko.bindingHandlers.moment = {
+ init: ttn,
+ update: ttn
+};
+
+ko.bindingHandlers.emailsTags = {
+ init: (element, fValueAccessor, fAllBindingsAccessor) => {
+ const EmailModel = require('Model/Email').default,
+ $el = $(element),
+ fValue = fValueAccessor(),
+ fAllBindings = fAllBindingsAccessor(),
+ inputDelimiters = [',', ';', '\n'];
+
+ $el.inputosaurus({
+ parseOnBlur: true,
+ allowDragAndDrop: true,
+ focusCallback: value => {
+ if (fValue && fValue.focused) {
+ fValue.focused(!!value);
+ }
+ },
+ inputDelimiters: inputDelimiters,
+ 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 =>
+ 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 => {
+ element.EmailsTagsValue = event.target.value;
+ fValue(event.target.value);
+ }
+ });
+
+ if (fValue && fValue.focused && fValue.focused.subscribe) {
+ fValue.focused.subscribe((value) => {
+ $el.inputosaurus(value ? 'focus' : 'blur');
+ });
+ }
+ },
+ update: (element, fValueAccessor) => {
+ const value = ko.unwrap(fValueAccessor());
+
+ if (element.EmailsTagsValue !== value) {
+ element.value = value;
+ element.EmailsTagsValue = value;
+ $(element).inputosaurus('refresh');
+ }
+ }
+};
+
+ko.bindingHandlers.draggable = {
+ init: (element, fValueAccessor, fAllBindingsAccessor) => {
+ const Utils = require('Common/Utils');
+
+ if (!bMobileDevice) {
+ const triggerZone = 50,
+ scrollSpeed = 3,
+ fAllValueFunc = fAllBindingsAccessor(),
+ selector = fAllValueFunc ? fAllValueFunc.droppableSelector : '',
+ droppable = selector ? document.querySelector(selector) : null,
+ conf = {
+ distance: 20,
+ handle: '.dragHandle',
+ cursorAt: { top: 22, left: 3 },
+ refreshPositions: true,
+ scroll: true,
+ drag: null,
+ stop: null,
+ helper: null
+ };
+ let bcr;
+
+ if (droppable) {
+ conf.drag = event => {
+ if (droppable.scrollTopMax) {
+ clearInterval(droppable.timerScroll);
+ if (droppable.scrollTop
+ && bcr.top < event.clientY
+ && bcr.top + triggerZone > event.clientY)
+ {
+ droppable.timerScroll = setInterval(() => droppable.scrollTop -= scrollSpeed, 10);
+ }
+ else if (droppable.scrollTop < droppable.scrollTopMax
+ && bcr.bottom > event.clientY
+ && bcr.bottom - triggerZone < event.clientY)
+ {
+ droppable.timerScroll = setInterval(() => droppable.scrollTop += scrollSpeed, 10);
+ }
+ else {
+ clearInterval(droppable.timerScroll);
+ }
+ }
+ };
+
+ conf.stop = () => clearInterval(droppable.timerScroll);
+ }
+
+ conf.helper = event => fValueAccessor()(event && event.target ? ko.dataFor(event.target) : null);
+
+ $(element)
+ .draggable(conf)
+ .on('mousedown.koDraggable', () => {
+ Utils.removeInFocus();
+ bcr = droppable ? droppable.getBoundingClientRect() : null;
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(element, () =>
+ $(element)
+ .off('mousedown.koDraggable')
+ .draggable('destroy')
+ );
+ }
+ }
+};
+
+ko.bindingHandlers.droppable = {
+ init: (element, fValueAccessor, fAllBindingsAccessor) => {
+ if (!bMobileDevice) {
+ const fValueFunc = fValueAccessor(),
+ fAllValueFunc = fAllBindingsAccessor(),
+ fOverCallback = fAllValueFunc && fAllValueFunc.droppableOver ? fAllValueFunc.droppableOver : null,
+ fOutCallback = fAllValueFunc && fAllValueFunc.droppableOut ? fAllValueFunc.droppableOut : null,
+ conf = {
+ tolerance: 'pointer',
+ hoverClass: 'droppableHover',
+ drop: null,
+ over: null,
+ out: null
+ };
+
+ if (fValueFunc) {
+ conf.drop = (event, ui) => {
+ fValueFunc(event, ui);
+ };
+
+ if (fOverCallback) {
+ conf.over = (event, ui) => {
+ fOverCallback(event, ui);
+ };
+ }
+
+ if (fOutCallback) {
+ conf.out = (event, ui) => {
+ fOutCallback(event, ui);
+ };
+ }
+
+ $(element).droppable(conf);
+
+ ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
+ $(element).droppable('destroy');
+ });
+ }
+ }
+ }
+};
+
+ko.bindingHandlers.link = {
+ update: (element, fValueAccessor) => element.href = ko.unwrap(fValueAccessor())
+};
+
+ko.bindingHandlers.initDom = {
+ init: (element, fValueAccessor) => fValueAccessor()(element)
+};
+
+ko.bindingHandlers.onEsc = {
+ init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
+ $(element).on('keyup.koOnEsc', (event) => {
+ if (event && 27 === parseInt(event.keyCode, 10)) {
+ $(element).trigger('change');
+ fValueAccessor().call(viewModel);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
+ $(element).off('keyup.koOnEsc');
+ });
+ }
+};
+
+// extenders
+
+ko.extenders.specialThrottle = (target, option) => {
+ target.iSpecialThrottleTimeoutValue = require('Common/Utils').pInt(option);
+ if (0 < target.iSpecialThrottleTimeoutValue) {
+ target.iSpecialThrottleTimeout = 0;
+ target.valueForRead = ko.observable(!!target()).extend({ throttle: 10 });
+
+ return ko.computed({
+ read: target.valueForRead,
+ write: (bValue) => {
+ if (bValue) {
+ target.valueForRead(bValue);
+ } else if (target.valueForRead()) {
+ clearTimeout(target.iSpecialThrottleTimeout);
+ target.iSpecialThrottleTimeout = setTimeout(() => {
+ target.valueForRead(false);
+ target.iSpecialThrottleTimeout = 0;
+ }, target.iSpecialThrottleTimeoutValue);
+ } else {
+ target.valueForRead(bValue);
+ }
+ }
+ });
+ }
+
+ return target;
+};
+
+// functions
+
+ko.observable.fn.validateEmail = function() {
+ this.hasError = ko.observable(false);
+
+ this.subscribe(value => this.hasError(value && !/^[^@\s]+@[^@\s]+$/.test(value)));
+
+ this.valueHasMutated();
+ return this;
+};
+
+export default ko;
diff --git a/dev/External/ko.js b/dev/External/ko.js
index 0758a7a7d..a10c905b1 100644
--- a/dev/External/ko.js
+++ b/dev/External/ko.js
@@ -1,44 +1,17 @@
-import { SaveSettingsStep } from 'Common/Enums';
-
const
$ = jQuery,
doc = document,
ko = window.ko,
Translator = () => require('Common/Translator'),
+ Globals = () => require('Common/Globals'),
isFunction = v => typeof v === 'function';
-ko.bindingHandlers.editor = {
- init: (element, fValueAccessor) => {
- let editor = null;
-
- const fValue = fValueAccessor(),
- HtmlEditor = require('Common/HtmlEditor').default,
- fUpdateEditorValue = () => fValue && fValue.__editor && fValue.__editor.setHtmlOrPlain(fValue()),
- fUpdateKoValue = () => fValue && fValue.__editor && fValue(fValue.__editor.getDataWithHtmlMark()),
- fOnReady = () => {
- fValue.__editor = editor;
- fUpdateEditorValue();
- };
-
- if (ko.isObservable(fValue) && HtmlEditor) {
- editor = new HtmlEditor(element, fUpdateKoValue, fOnReady, fUpdateKoValue);
-
- fValue.__fetchEditorValue = fUpdateKoValue;
-
- fValue.subscribe(fUpdateEditorValue);
-
- // ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
- // });
- }
- }
-};
-
ko.bindingHandlers.tooltip = {
init: (element, fValueAccessor) => {
const fValue = fValueAccessor(),
- Globals = require('Common/Globals');
+ Global = Globals();
- if (!Globals.bMobileDevice || 'on' === element.dataset.tooltipMobile) {
+ if (!Global.bMobileDevice || 'on' === element.dataset.tooltipMobile) {
const sValue = !ko.isObservable(fValue) && isFunction(fValue) ? fValue() : ko.unwrap(fValue);
if ('off' === element.dataset.tooltipI18n) {
@@ -48,17 +21,16 @@ ko.bindingHandlers.tooltip = {
Translator().trigger.subscribe(() =>
element.title = Translator().i18n(sValue)
);
- Globals.dropdownVisibility.subscribe(() =>
+ Global.dropdownVisibility.subscribe(() =>
element.title = Translator().i18n(sValue)
);
}
}
},
update: (element, fValueAccessor) => {
- const fValue = fValueAccessor(),
- Globals = require('Common/Globals');
+ const fValue = fValueAccessor();
- if (!Globals.bMobileDevice || 'on' === element.dataset.tooltipMobile) {
+ if (!Globals().bMobileDevice || 'on' === element.dataset.tooltipMobile) {
const sValue = !ko.isObservable(fValue) && isFunction(fValue) ? fValue() : ko.unwrap(fValue);
if (sValue) {
element.title = 'off' === element.dataset.tooltipI18n ? sValue : Translator().i18n(sValue);
@@ -148,26 +120,9 @@ ko.bindingHandlers.onSpace = {
}
};
-ko.bindingHandlers.onEsc = {
- init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
- $(element).on('keyup.koOnEsc', (event) => {
- if (event && 27 === parseInt(event.keyCode, 10)) {
- $(element).trigger('change');
- fValueAccessor().call(viewModel);
- }
- });
-
- ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
- $(element).off('keyup.koOnEsc');
- });
- }
-};
-
ko.bindingHandlers.modal = {
init: (element, fValueAccessor) => {
- const Globals = require('Common/Globals');
-
- element.classList.toggle('fade', !Globals.bMobileDevice);
+ element.classList.toggle('fade', !Globals().bMobileDevice);
const close = element.querySelector('.close'), click = () => fValueAccessor()(false);
close && close.addEventListener('click.koModal', click);
@@ -178,12 +133,6 @@ ko.bindingHandlers.modal = {
}
};
-let ttn = (element, fValueAccessor) => require('Common/Momentor').timeToNode(element, ko.unwrap(fValueAccessor()));
-ko.bindingHandlers.moment = {
- init: ttn,
- update: ttn
-};
-
ko.bindingHandlers.i18nInit = {
init: element => Translator().i18nToNodes(element)
};
@@ -195,212 +144,10 @@ ko.bindingHandlers.i18nUpdate = {
}
};
-ko.bindingHandlers.link = {
- update: (element, fValueAccessor) => element.href = ko.unwrap(fValueAccessor())
-};
-
ko.bindingHandlers.title = {
update: (element, fValueAccessor) => element.title = ko.unwrap(fValueAccessor())
};
-ko.bindingHandlers.initDom = {
- init: (element, fValueAccessor) => fValueAccessor()(element)
-};
-
-ko.bindingHandlers.draggable = {
- init: (element, fValueAccessor, fAllBindingsAccessor) => {
- const Globals = require('Common/Globals'),
- Utils = require('Common/Utils');
-
- if (!Globals.bMobileDevice) {
- const triggerZone = 50,
- scrollSpeed = 3,
- fAllValueFunc = fAllBindingsAccessor(),
- selector = fAllValueFunc ? fAllValueFunc.droppableSelector : '',
- droppable = selector ? doc.querySelector(selector) : null,
- conf = {
- distance: 20,
- handle: '.dragHandle',
- cursorAt: { top: 22, left: 3 },
- refreshPositions: true,
- scroll: true,
- drag: null,
- stop: null,
- helper: null
- };
- let bcr;
-
- if (droppable) {
- conf.drag = event => {
- if (droppable.scrollTopMax) {
- clearInterval(droppable.timerScroll);
- if (droppable.scrollTop
- && bcr.top < event.clientY
- && bcr.top + triggerZone > event.clientY)
- {
- droppable.timerScroll = setInterval(() => droppable.scrollTop -= scrollSpeed, 10);
- }
- else if (droppable.scrollTop < droppable.scrollTopMax
- && bcr.bottom > event.clientY
- && bcr.bottom - triggerZone < event.clientY)
- {
- droppable.timerScroll = setInterval(() => droppable.scrollTop += scrollSpeed, 10);
- }
- else {
- clearInterval(droppable.timerScroll);
- }
- }
- };
-
- conf.stop = () => clearInterval(droppable.timerScroll);
- }
-
- conf.helper = event => fValueAccessor()(event && event.target ? ko.dataFor(event.target) : null);
-
- $(element)
- .draggable(conf)
- .on('mousedown.koDraggable', () => {
- Utils.removeInFocus();
- bcr = droppable ? droppable.getBoundingClientRect() : null;
- });
-
- ko.utils.domNodeDisposal.addDisposeCallback(element, () =>
- $(element)
- .off('mousedown.koDraggable')
- .draggable('destroy')
- );
- }
- }
-};
-
-ko.bindingHandlers.droppable = {
- init: (element, fValueAccessor, fAllBindingsAccessor) => {
- const Globals = require('Common/Globals');
- if (!Globals.bMobileDevice) {
- const fValueFunc = fValueAccessor(),
- fAllValueFunc = fAllBindingsAccessor(),
- fOverCallback = fAllValueFunc && fAllValueFunc.droppableOver ? fAllValueFunc.droppableOver : null,
- fOutCallback = fAllValueFunc && fAllValueFunc.droppableOut ? fAllValueFunc.droppableOut : null,
- conf = {
- tolerance: 'pointer',
- hoverClass: 'droppableHover',
- drop: null,
- over: null,
- out: null
- };
-
- if (fValueFunc) {
- conf.drop = (event, ui) => {
- fValueFunc(event, ui);
- };
-
- if (fOverCallback) {
- conf.over = (event, ui) => {
- fOverCallback(event, ui);
- };
- }
-
- if (fOutCallback) {
- conf.out = (event, ui) => {
- fOutCallback(event, ui);
- };
- }
-
- $(element).droppable(conf);
-
- ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
- $(element).droppable('destroy');
- });
- }
- }
- }
-};
-
-ko.bindingHandlers.saveTrigger = {
- init: (element) => {
- element.saveTriggerType = element.matches('input[type=text],input[type=email],input[type=password],select,textarea')
- ? 'input' : 'custom';
-
- if ('custom' === element.saveTriggerType) {
- element.append(
- ' ',
- Element.fromHTML(''),
- Element.fromHTML(''),
- Element.fromHTML('')
- );
- element.classList.add('settings-saved-trigger');
- } else {
- element.classList.add('settings-saved-trigger-input');
- }
- },
- update: (element, fValueAccessor) => {
- const value = parseInt(ko.unwrap(fValueAccessor()),10);
- if ('custom' === element.saveTriggerType) {
- element.querySelector('.animated').hidden = value !== SaveSettingsStep.Animate;
- element.querySelector('.success').hidden = value !== SaveSettingsStep.TrueResult;
- element.querySelector('.error').hidden = value !== SaveSettingsStep.FalseResult;
- } else if (value !== SaveSettingsStep.Animate) {
- element.classList.toggle('success', value === SaveSettingsStep.TrueResult);
- element.classList.toggle('error', value === SaveSettingsStep.FalseResult);
- }
- }
-};
-
-ko.bindingHandlers.emailsTags = {
- init: (element, fValueAccessor, fAllBindingsAccessor) => {
- const EmailModel = require('Model/Email').default,
- $el = $(element),
- fValue = fValueAccessor(),
- fAllBindings = fAllBindingsAccessor(),
- inputDelimiters = [',', ';', '\n'];
-
- $el.inputosaurus({
- parseOnBlur: true,
- allowDragAndDrop: true,
- focusCallback: value => {
- if (fValue && fValue.focused) {
- fValue.focused(!!value);
- }
- },
- inputDelimiters: inputDelimiters,
- 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 =>
- 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 => {
- element.EmailsTagsValue = event.target.value;
- fValue(event.target.value);
- }
- });
-
- if (fValue && fValue.focused && fValue.focused.subscribe) {
- fValue.focused.subscribe((value) => {
- $el.inputosaurus(value ? 'focus' : 'blur');
- });
- }
- },
- update: (element, fValueAccessor) => {
- const value = ko.unwrap(fValueAccessor());
-
- if (element.EmailsTagsValue !== value) {
- element.value = value;
- element.EmailsTagsValue = value;
- $(element).inputosaurus('refresh');
- }
- }
-};
-
ko.bindingHandlers.command = {
init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => {
const command = fValueAccessor();
@@ -455,28 +202,6 @@ ko.bindingHandlers.command = {
// extenders
-ko.extenders.posInterer = (target, defaultVal) => {
- const Utils = require('Common/Utils'),
- result = ko.computed({
- read: target,
- write: (newValue) => {
- let val = Utils.pInt(newValue.toString(), defaultVal);
- if (0 >= val) {
- val = defaultVal;
- }
-
- if (val === target() && '' + val !== '' + newValue) {
- target(val + 1);
- }
-
- target(val);
- }
- });
-
- result(target());
- return result;
-};
-
ko.extenders.limitedList = (target, limitedList) => {
const result = ko
.computed({
@@ -522,12 +247,6 @@ ko.extenders.reversible = (target) => {
return target;
};
-ko.extenders.toggleSubscribe = (target, options) => {
- target.subscribe(options[1], options[0], 'beforeChange');
- target.subscribe(options[2], options[0]);
- return target;
-};
-
ko.extenders.toggleSubscribeProperty = (target, options) => {
const prop = options[1];
if (prop) {
@@ -558,53 +277,8 @@ ko.extenders.falseTimeout = (target, option) => {
return target;
};
-ko.extenders.specialThrottle = (target, option) => {
- target.iSpecialThrottleTimeoutValue = require('Common/Utils').pInt(option);
- if (0 < target.iSpecialThrottleTimeoutValue) {
- target.iSpecialThrottleTimeout = 0;
- target.valueForRead = ko.observable(!!target()).extend({ throttle: 10 });
-
- return ko.computed({
- read: target.valueForRead,
- write: (bValue) => {
- if (bValue) {
- target.valueForRead(bValue);
- } else if (target.valueForRead()) {
- clearTimeout(target.iSpecialThrottleTimeout);
- target.iSpecialThrottleTimeout = setTimeout(() => {
- target.valueForRead(false);
- target.iSpecialThrottleTimeout = 0;
- }, target.iSpecialThrottleTimeoutValue);
- } else {
- target.valueForRead(bValue);
- }
- }
- });
- }
-
- return target;
-};
-
-ko.extenders.idleTrigger = (target) => {
- target.trigger = ko.observable(SaveSettingsStep.Idle);
- return target;
-};
-
// functions
-ko.observable.fn.idleTrigger = function() {
- return this.extend({ 'idleTrigger': true });
-};
-
-ko.observable.fn.validateEmail = function() {
- this.hasError = ko.observable(false);
-
- this.subscribe(value => this.hasError(value && !/^[^@\s]+@[^@\s]+$/.test(value)));
-
- this.valueHasMutated();
- return this;
-};
-
ko.observable.fn.deleteAccessHelper = function() {
this.extend({ falseTimeout: 3000 }).extend({ toggleSubscribeProperty: [this, 'deleteAccess'] });
return this;
diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js
index 9b98f4111..b916f0d7f 100644
--- a/dev/View/Popup/Compose.js
+++ b/dev/View/Popup/Compose.js
@@ -45,6 +45,12 @@ import { AbstractViewNext } from 'Knoin/AbstractViewNext';
const Settings = rl.settings;
+ko.extenders.toggleSubscribe = (target, options) => {
+ target.subscribe(options[1], options[0], 'beforeChange');
+ target.subscribe(options[2], options[0]);
+ return target;
+};
+
@popup({
name: 'View/Popup/Compose',
templateID: 'PopupsCompose'
diff --git a/dev/View/Popup/Identity.js b/dev/View/Popup/Identity.js
index a2bfb3963..a4bc0921b 100644
--- a/dev/View/Popup/Identity.js
+++ b/dev/View/Popup/Identity.js
@@ -10,6 +10,15 @@ import Remote from 'Remote/User/Fetch';
import { popup, command } from 'Knoin/Knoin';
import { AbstractViewNext } from 'Knoin/AbstractViewNext';
+ko.observable.fn.validateEmail = function() {
+ this.hasError = ko.observable(false);
+
+ this.subscribe(value => this.hasError(value && !/^[^@\s]+@[^@\s]+$/.test(value)));
+
+ this.valueHasMutated();
+ return this;
+};
+
@popup({
name: 'View/Popup/Identity',
templateID: 'PopupsIdentity'