mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-01-09 00:08:18 +08:00
264 lines
6.8 KiB
JavaScript
264 lines
6.8 KiB
JavaScript
|
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;
|