mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Added: addEventsListener() and addEventsListeners()
This commit is contained in:
parent
c270f0ad9a
commit
5990addfef
14 changed files with 484 additions and 464 deletions
|
|
@ -19,7 +19,8 @@ import {
|
||||||
$htmlCL,
|
$htmlCL,
|
||||||
Settings,
|
Settings,
|
||||||
SettingsGet,
|
SettingsGet,
|
||||||
leftPanelDisabled
|
leftPanelDisabled,
|
||||||
|
addEventsListener
|
||||||
} from 'Common/Globals';
|
} from 'Common/Globals';
|
||||||
|
|
||||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||||
|
|
@ -89,7 +90,7 @@ class AppUser extends AbstractApp {
|
||||||
}, interval);
|
}, interval);
|
||||||
|
|
||||||
const fn = (ev=>$htmlCL.toggle('rl-ctrl-key-pressed', ev.ctrlKey)).debounce(500);
|
const fn = (ev=>$htmlCL.toggle('rl-ctrl-key-pressed', ev.ctrlKey)).debounce(500);
|
||||||
['keydown','keyup'].forEach(t => doc.addEventListener(t, fn));
|
addEventsListener(doc, ['keydown','keyup'], fn);
|
||||||
|
|
||||||
shortcuts.add('escape,enter', '', Scope.All, () => rl.Dropdowns.detectVisibility());
|
shortcuts.add('escape,enter', '', Scope.All, () => rl.Dropdowns.detectVisibility());
|
||||||
}
|
}
|
||||||
|
|
@ -344,9 +345,7 @@ class AppUser extends AbstractApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add pointermove ?
|
// add pointermove ?
|
||||||
['touchstart','mousemove','keydown'].forEach(
|
addEventsListener(doc, ['touchstart','mousemove','keydown'], SettingsUserStore.delayLogout, {passive:true});
|
||||||
t => doc.addEventListener(t, SettingsUserStore.delayLogout, {passive:true})
|
|
||||||
);
|
|
||||||
SettingsUserStore.delayLogout();
|
SettingsUserStore.delayLogout();
|
||||||
|
|
||||||
// initLeftSideLayoutResizer
|
// initLeftSideLayoutResizer
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import * as Links from 'Common/Links';
|
import * as Links from 'Common/Links';
|
||||||
import { doc, SettingsGet, fireEvent } from 'Common/Globals';
|
import { doc, SettingsGet, fireEvent, addEventsListener } from 'Common/Globals';
|
||||||
|
|
||||||
let notificator = null,
|
let notificator = null,
|
||||||
player = null,
|
player = null,
|
||||||
|
|
@ -73,8 +73,7 @@ export const SMAudio = new class {
|
||||||
this.supportedOgg = canPlay('audio/ogg; codecs="vorbis"');
|
this.supportedOgg = canPlay('audio/ogg; codecs="vorbis"');
|
||||||
if (player) {
|
if (player) {
|
||||||
const stopFn = () => this.pause();
|
const stopFn = () => this.pause();
|
||||||
player.addEventListener('ended', stopFn);
|
addEventsListener(player, ['ended','error'], stopFn);
|
||||||
player.addEventListener('error', stopFn);
|
|
||||||
addEventListener('audio.api.stop', stopFn);
|
addEventListener('audio.api.stop', stopFn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,10 @@ export const Capa = {
|
||||||
export const Scope = {
|
export const Scope = {
|
||||||
All: 'all',
|
All: 'all',
|
||||||
None: 'none',
|
None: 'none',
|
||||||
Contacts: 'Contacts',
|
|
||||||
MessageList: 'MessageList',
|
MessageList: 'MessageList',
|
||||||
FolderList: 'FolderList',
|
FolderList: 'FolderList',
|
||||||
MessageView: 'MessageView',
|
MessageView: 'MessageView',
|
||||||
Compose: 'Compose',
|
Settings: 'Settings'
|
||||||
Settings: 'Settings',
|
|
||||||
Menu: 'Menu',
|
|
||||||
OpenPgpKey: 'OpenPgpKey',
|
|
||||||
KeyboardShortcutsHelp: 'KeyboardShortcutsHelp',
|
|
||||||
Ask: 'Ask'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { Scope } from 'Common/Enums';
|
||||||
let keyScopeFake = Scope.All;
|
let keyScopeFake = Scope.All;
|
||||||
|
|
||||||
export const
|
export const
|
||||||
|
ScopeMenu = 'Menu',
|
||||||
|
|
||||||
doc = document,
|
doc = document,
|
||||||
|
|
||||||
|
|
@ -31,14 +32,20 @@ export const
|
||||||
|
|
||||||
fireEvent = (name, detail) => dispatchEvent(new CustomEvent(name, {detail:detail})),
|
fireEvent = (name, detail) => dispatchEvent(new CustomEvent(name, {detail:detail})),
|
||||||
|
|
||||||
|
addEventsListener = (element, events, fn, options) =>
|
||||||
|
events.forEach(event => element.addEventListener(event, fn, options)),
|
||||||
|
|
||||||
|
addEventsListeners = (element, events) =>
|
||||||
|
Object.entries(events).forEach(([event, fn]) => element.addEventListener(event, fn)),
|
||||||
|
|
||||||
// keys
|
// keys
|
||||||
keyScopeReal = ko.observable(Scope.All),
|
keyScopeReal = ko.observable(Scope.All),
|
||||||
keyScope = value => {
|
keyScope = value => {
|
||||||
if (value) {
|
if (value) {
|
||||||
if (Scope.Menu !== value) {
|
if (ScopeMenu !== value) {
|
||||||
keyScopeFake = value;
|
keyScopeFake = value;
|
||||||
if (dropdownVisibility()) {
|
if (dropdownVisibility()) {
|
||||||
value = Scope.Menu;
|
value = ScopeMenu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyScopeReal(value);
|
keyScopeReal(value);
|
||||||
|
|
@ -50,8 +57,8 @@ export const
|
||||||
|
|
||||||
dropdownVisibility.subscribe(value => {
|
dropdownVisibility.subscribe(value => {
|
||||||
if (value) {
|
if (value) {
|
||||||
keyScope(Scope.Menu);
|
keyScope(ScopeMenu);
|
||||||
} else if (Scope.Menu === shortcuts.getScope()) {
|
} else if (ScopeMenu === shortcuts.getScope()) {
|
||||||
keyScope(keyScopeFake);
|
keyScope(keyScopeFake);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
import { addEventsListeners } from 'Common/Globals';
|
||||||
import { isArray } from 'Common/Utils';
|
import { isArray } from 'Common/Utils';
|
||||||
import { koComputable } from 'External/ko';
|
import { koComputable } from 'External/ko';
|
||||||
|
|
||||||
|
|
@ -239,7 +240,8 @@ export class Selector {
|
||||||
return el ? ko.dataFor(el) : null;
|
return el ? ko.dataFor(el) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
contentScrollable.addEventListener('click', event => {
|
addEventsListeners(contentScrollable, {
|
||||||
|
click: event => {
|
||||||
let el = event.target.closestWithin(this.sItemSelector, contentScrollable);
|
let el = event.target.closestWithin(this.sItemSelector, contentScrollable);
|
||||||
el && this.actionClick(ko.dataFor(el), event);
|
el && this.actionClick(ko.dataFor(el), event);
|
||||||
|
|
||||||
|
|
@ -252,9 +254,8 @@ export class Selector {
|
||||||
item.checked(!item.checked());
|
item.checked(!item.checked());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
auxclick: event => {
|
||||||
contentScrollable.addEventListener('auxclick', event => {
|
|
||||||
if (1 == event.button) {
|
if (1 == event.button) {
|
||||||
const item = getItem(this.sItemSelector);
|
const item = getItem(this.sItemSelector);
|
||||||
if (item) {
|
if (item) {
|
||||||
|
|
@ -262,6 +263,7 @@ export class Selector {
|
||||||
(this.oCallbacks.MiddleClick || (()=>0))(item);
|
(this.oCallbacks.MiddleClick || (()=>0))(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
shortcuts.add('enter,open', '', keyScope, () => {
|
shortcuts.add('enter,open', '', keyScope, () => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { doc, createElement } from 'Common/Globals';
|
import { doc, createElement, addEventsListeners } from 'Common/Globals';
|
||||||
import { EmailModel } from 'Model/Email';
|
import { EmailModel } from 'Model/Email';
|
||||||
|
|
||||||
const contentType = 'snappymail/emailaddress',
|
const contentType = 'snappymail/emailaddress',
|
||||||
|
|
@ -41,28 +41,34 @@ export class EmailAddressesComponent {
|
||||||
// Create the elements
|
// Create the elements
|
||||||
self.ul = createElement('ul',{class:"emailaddresses"});
|
self.ul = createElement('ul',{class:"emailaddresses"});
|
||||||
|
|
||||||
self.ul.addEventListener('click', e => self._focus(e));
|
addEventsListeners(self.ul, {
|
||||||
self.ul.addEventListener('dblclick', e => self._editTag(e));
|
click: e => self._focus(e),
|
||||||
self.ul.addEventListener("dragenter", fnDrag);
|
dblclick: e => self._editTag(e),
|
||||||
self.ul.addEventListener("dragover", fnDrag);
|
dragenter: fnDrag,
|
||||||
self.ul.addEventListener("drop", e => {
|
dragover: fnDrag,
|
||||||
|
drop: e => {
|
||||||
if (validDropzone() && dragAddress.value) {
|
if (validDropzone() && dragAddress.value) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
dragAddress.source._removeDraggedTag(dragAddress.li);
|
dragAddress.source._removeDraggedTag(dragAddress.li);
|
||||||
self._parseValue(dragAddress.value);
|
self._parseValue(dragAddress.value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.input = createElement('input',{type:"text", list:datalist.id,
|
self.input = createElement('input',{type:"text", list:datalist.id,
|
||||||
autocomplete:"off", autocorrect:"off", autocapitalize:"off", spellcheck:"false"});
|
autocomplete:"off", autocorrect:"off", autocapitalize:"off", spellcheck:"false"});
|
||||||
|
|
||||||
self.input.addEventListener('focus', () => self._focusTrigger(true));
|
addEventsListeners(self.input, {
|
||||||
self.input.addEventListener('blur', () => {
|
focus: () => {
|
||||||
|
self._focusTrigger(true);
|
||||||
|
self.input.value || self._resetDatalist();
|
||||||
|
},
|
||||||
|
blur: () => {
|
||||||
// prevent autoComplete menu click from causing a false 'blur'
|
// prevent autoComplete menu click from causing a false 'blur'
|
||||||
self._parseInput(true);
|
self._parseInput(true);
|
||||||
self._focusTrigger(false);
|
self._focusTrigger(false);
|
||||||
});
|
},
|
||||||
self.input.addEventListener('keydown', e => {
|
keydown: e => {
|
||||||
if ('Backspace' === e.key || 'ArrowLeft' === e.key) {
|
if ('Backspace' === e.key || 'ArrowLeft' === e.key) {
|
||||||
// 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
|
||||||
var lastTag = self.inputCont.previousElementSibling,
|
var lastTag = self.inputCont.previousElementSibling,
|
||||||
|
|
@ -78,12 +84,12 @@ export class EmailAddressesComponent {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
self._parseInput(true);
|
self._parseInput(true);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
self.input.addEventListener('input', () => {
|
input: () => {
|
||||||
self._parseInput();
|
self._parseInput();
|
||||||
self._updateDatalist();
|
self._updateDatalist();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.input.addEventListener('focus', () => self.input.value || self._resetDatalist());
|
|
||||||
|
|
||||||
// define starting placeholder
|
// define starting placeholder
|
||||||
if (element.placeholder) {
|
if (element.placeholder) {
|
||||||
|
|
@ -261,10 +267,11 @@ export class EmailAddressesComponent {
|
||||||
|
|
||||||
el = createElement('a',{href:'#', class:'ficon'});
|
el = createElement('a',{href:'#', class:'ficon'});
|
||||||
el.append('✖');
|
el.append('✖');
|
||||||
el.addEventListener('click', e => self._removeTag(e, li));
|
addEventsListeners(el, {
|
||||||
el.addEventListener('focus', () => li.className = 'emailaddresses-selected');
|
click: e => self._removeTag(e, li),
|
||||||
el.addEventListener('blur', () => li.className = null);
|
focus: () => li.className = 'emailaddresses-selected',
|
||||||
el.addEventListener('keydown', e => {
|
blur: () => li.className = null,
|
||||||
|
keydown: e => {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'Delete':
|
case 'Delete':
|
||||||
case 'Backspace':
|
case 'Backspace':
|
||||||
|
|
@ -301,12 +308,14 @@ export class EmailAddressesComponent {
|
||||||
self._focus(e);
|
self._focus(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
li.append(el);
|
li.append(el);
|
||||||
|
|
||||||
li.emailaddress = v;
|
li.emailaddress = v;
|
||||||
|
|
||||||
li.addEventListener("dragstart", e => {
|
addEventsListeners(li, {
|
||||||
|
dragstart: e => {
|
||||||
dragAddress = {
|
dragAddress = {
|
||||||
source: self,
|
source: self,
|
||||||
li: li,
|
li: li,
|
||||||
|
|
@ -317,10 +326,11 @@ export class EmailAddressesComponent {
|
||||||
// e.dataTransfer.setDragImage(li, 0, 0);
|
// e.dataTransfer.setDragImage(li, 0, 0);
|
||||||
e.dataTransfer.effectAllowed = 'move';
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
li.style.opacity = 0.25;
|
li.style.opacity = 0.25;
|
||||||
});
|
},
|
||||||
li.addEventListener("dragend", () => {
|
dragend: () => {
|
||||||
dragAddress = null;
|
dragAddress = null;
|
||||||
li.style.cssText = '';
|
li.style.cssText = '';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.inputCont.before(li);
|
self.inputCont.before(li);
|
||||||
|
|
|
||||||
76
dev/External/User/ko.js
vendored
76
dev/External/User/ko.js
vendored
|
|
@ -2,7 +2,7 @@ import 'External/ko';
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
import { HtmlEditor } from 'Common/Html';
|
import { HtmlEditor } from 'Common/Html';
|
||||||
import { timeToNode } from 'Common/Translator';
|
import { timeToNode } from 'Common/Translator';
|
||||||
import { elementById } from 'Common/Globals';
|
import { elementById, addEventsListeners } from 'Common/Globals';
|
||||||
import { isArray } from 'Common/Utils';
|
import { isArray } from 'Common/Utils';
|
||||||
import { EmailAddressesComponent } from 'Component/EmailAddresses';
|
import { EmailAddressesComponent } from 'Component/EmailAddresses';
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
|
@ -29,12 +29,16 @@ const rlContentType = 'snappymail/action',
|
||||||
id: 0,
|
id: 0,
|
||||||
stop: () => clearTimeout(dragTimer.id),
|
stop: () => clearTimeout(dragTimer.id),
|
||||||
start: fn => dragTimer.id = setTimeout(fn, 500)
|
start: fn => dragTimer.id = setTimeout(fn, 500)
|
||||||
};
|
},
|
||||||
|
|
||||||
|
ttn = (element, fValueAccessor) => timeToNode(element, ko.unwrap(fValueAccessor()));
|
||||||
|
|
||||||
let dragImage,
|
let dragImage,
|
||||||
dragData;
|
dragData;
|
||||||
|
|
||||||
ko.bindingHandlers.editor = {
|
Object.assign(ko.bindingHandlers, {
|
||||||
|
|
||||||
|
editor: {
|
||||||
init: (element, fValueAccessor) => {
|
init: (element, fValueAccessor) => {
|
||||||
let editor = null;
|
let editor = null;
|
||||||
|
|
||||||
|
|
@ -57,15 +61,14 @@ ko.bindingHandlers.editor = {
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
let ttn = (element, fValueAccessor) => timeToNode(element, ko.unwrap(fValueAccessor()));
|
moment: {
|
||||||
ko.bindingHandlers.moment = {
|
|
||||||
init: ttn,
|
init: ttn,
|
||||||
update: ttn
|
update: ttn
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.emailsTags = {
|
emailsTags: {
|
||||||
init: (element, fValueAccessor, fAllBindings) => {
|
init: (element, fValueAccessor, fAllBindings) => {
|
||||||
const fValue = fValueAccessor();
|
const fValue = fValueAccessor();
|
||||||
|
|
||||||
|
|
@ -84,10 +87,10 @@ ko.bindingHandlers.emailsTags = {
|
||||||
update: (element, fValueAccessor) => {
|
update: (element, fValueAccessor) => {
|
||||||
element.addresses.value = ko.unwrap(fValueAccessor());
|
element.addresses.value = ko.unwrap(fValueAccessor());
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
// Start dragging selected messages
|
// Start dragging selected messages
|
||||||
ko.bindingHandlers.dragmessages = {
|
dragmessages: {
|
||||||
init: (element, fValueAccessor) => {
|
init: (element, fValueAccessor) => {
|
||||||
element.addEventListener("dragstart", e => {
|
element.addEventListener("dragstart", e => {
|
||||||
let data = fValueAccessor()(e);
|
let data = fValueAccessor()(e);
|
||||||
|
|
@ -115,10 +118,10 @@ ko.bindingHandlers.dragmessages = {
|
||||||
element.addEventListener("dragend", () => dragData = null);
|
element.addEventListener("dragend", () => dragData = null);
|
||||||
element.setAttribute('draggable', true);
|
element.setAttribute('draggable', true);
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
// Drop selected messages on folder
|
// Drop selected messages on folder
|
||||||
ko.bindingHandlers.dropmessages = {
|
dropmessages: {
|
||||||
init: (element, fValueAccessor) => {
|
init: (element, fValueAccessor) => {
|
||||||
const folder = fValueAccessor(),
|
const folder = fValueAccessor(),
|
||||||
// folder = ko.dataFor(element),
|
// folder = ko.dataFor(element),
|
||||||
|
|
@ -139,10 +142,11 @@ ko.bindingHandlers.dropmessages = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
element.addEventListener("dragenter", fnHover);
|
addEventsListeners(element, {
|
||||||
element.addEventListener("dragover", fnHover);
|
dragenter: fnHover,
|
||||||
element.addEventListener("dragleave", fnStop);
|
dragover: fnHover,
|
||||||
element.addEventListener("drop", e => {
|
dragleave: fnStop,
|
||||||
|
drop: e => {
|
||||||
fnStop(e);
|
fnStop(e);
|
||||||
if ('messages' === getDragAction(e) && ['move','copy'].includes(e.dataTransfer.effectAllowed)) {
|
if ('messages' === getDragAction(e) && ['move','copy'].includes(e.dataTransfer.effectAllowed)) {
|
||||||
let data = dragData.data;
|
let data = dragData.data;
|
||||||
|
|
@ -150,11 +154,12 @@ ko.bindingHandlers.dropmessages = {
|
||||||
moveMessagesToFolder(data.folder, data.uids, folder.fullName, data.copy && e.ctrlKey);
|
moveMessagesToFolder(data.folder, data.uids, folder.fullName, data.copy && e.ctrlKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.sortableItem = {
|
sortableItem: {
|
||||||
init: (element, fValueAccessor) => {
|
init: (element, fValueAccessor) => {
|
||||||
let options = ko.unwrap(fValueAccessor()) || {},
|
let options = ko.unwrap(fValueAccessor()) || {},
|
||||||
parent = element.parentNode,
|
parent = element.parentNode,
|
||||||
|
|
@ -174,15 +179,16 @@ ko.bindingHandlers.sortableItem = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
element.addEventListener("dragstart", e => {
|
addEventsListeners(element, {
|
||||||
|
dragstart: e => {
|
||||||
dragData = {
|
dragData = {
|
||||||
action: 'sortable',
|
action: 'sortable',
|
||||||
element: element
|
element: element
|
||||||
};
|
};
|
||||||
setDragAction(e, 'sortable', 'move', element, element);
|
setDragAction(e, 'sortable', 'move', element, element);
|
||||||
element.style.opacity = 0.25;
|
element.style.opacity = 0.25;
|
||||||
});
|
},
|
||||||
element.addEventListener("dragend", e => {
|
dragend: e => {
|
||||||
element.style.opacity = null;
|
element.style.opacity = null;
|
||||||
if ('sortable' === getDragAction(e)) {
|
if ('sortable' === getDragAction(e)) {
|
||||||
dragData.data.style.cssText = '';
|
dragData.data.style.cssText = '';
|
||||||
|
|
@ -192,12 +198,14 @@ ko.bindingHandlers.sortableItem = {
|
||||||
}
|
}
|
||||||
dragData = null;
|
dragData = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (!parent.sortable) {
|
if (!parent.sortable) {
|
||||||
parent.sortable = true;
|
parent.sortable = true;
|
||||||
parent.addEventListener("dragenter", fnHover);
|
addEventsListeners(parent, {
|
||||||
parent.addEventListener("dragover", fnHover);
|
dragenter: fnHover,
|
||||||
parent.addEventListener("drop", e => {
|
dragover: fnHover,
|
||||||
|
drop: e => {
|
||||||
if ('sortable' === getDragAction(e)) {
|
if ('sortable' === getDragAction(e)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let data = ko.dataFor(dragData.data),
|
let data = ko.dataFor(dragData.data),
|
||||||
|
|
@ -211,16 +219,17 @@ ko.bindingHandlers.sortableItem = {
|
||||||
dragData = null;
|
dragData = null;
|
||||||
options.afterMove && options.afterMove();
|
options.afterMove && options.afterMove();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.initDom = {
|
initDom: {
|
||||||
init: (element, fValueAccessor) => fValueAccessor()(element)
|
init: (element, fValueAccessor) => fValueAccessor()(element)
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.onEsc = {
|
onEsc: {
|
||||||
init: (element, fValueAccessor, fAllBindings, viewModel) => {
|
init: (element, fValueAccessor, fAllBindings, viewModel) => {
|
||||||
let fn = event => {
|
let fn = event => {
|
||||||
if ('Escape' == event.key) {
|
if ('Escape' == event.key) {
|
||||||
|
|
@ -231,16 +240,16 @@ ko.bindingHandlers.onEsc = {
|
||||||
element.addEventListener('keyup', fn);
|
element.addEventListener('keyup', fn);
|
||||||
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeEventListener('keyup', fn));
|
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeEventListener('keyup', fn));
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.registerBootstrapDropdown = {
|
registerBootstrapDropdown: {
|
||||||
init: element => {
|
init: element => {
|
||||||
rl.Dropdowns.register(element);
|
rl.Dropdowns.register(element);
|
||||||
element.ddBtn = new BSN.Dropdown(element.querySelector('.dropdown-toggle'));
|
element.ddBtn = new BSN.Dropdown(element.querySelector('.dropdown-toggle'));
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.openDropdownTrigger = {
|
openDropdownTrigger: {
|
||||||
update: (element, fValueAccessor) => {
|
update: (element, fValueAccessor) => {
|
||||||
if (ko.unwrap(fValueAccessor())) {
|
if (ko.unwrap(fValueAccessor())) {
|
||||||
const el = element.ddBtn;
|
const el = element.ddBtn;
|
||||||
|
|
@ -251,4 +260,5 @@ ko.bindingHandlers.openDropdownTrigger = {
|
||||||
fValueAccessor()(false);
|
fValueAccessor()(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
46
dev/External/ko.js
vendored
46
dev/External/ko.js
vendored
|
|
@ -5,6 +5,10 @@ import { SaveSettingsStep } from 'Common/Enums';
|
||||||
import { arrayLength, isFunction, forEachObjectEntry } from 'Common/Utils';
|
import { arrayLength, isFunction, forEachObjectEntry } from 'Common/Utils';
|
||||||
|
|
||||||
export const
|
export const
|
||||||
|
errorTip = (element, value) => value
|
||||||
|
? setTimeout(() => element.setAttribute('data-rainloopErrorTip', value), 100)
|
||||||
|
: element.removeAttribute('data-rainloopErrorTip'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value of the pureComputed observable shouldn’t vary based on the
|
* The value of the pureComputed observable shouldn’t vary based on the
|
||||||
* number of evaluations or other “hidden” information. Its value should be
|
* number of evaluations or other “hidden” information. Its value should be
|
||||||
|
|
@ -35,26 +39,23 @@ export const
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
ko.bindingHandlers.tooltipErrorTip = {
|
Object.assign(ko.bindingHandlers, {
|
||||||
|
tooltipErrorTip: {
|
||||||
init: (element, fValueAccessor) => {
|
init: (element, fValueAccessor) => {
|
||||||
doc.addEventListener('click', () => {
|
doc.addEventListener('click', () => {
|
||||||
let value = fValueAccessor();
|
let value = fValueAccessor();
|
||||||
ko.isObservable(value) && !ko.isComputed(value) && value('');
|
ko.isObservable(value) && !ko.isComputed(value) && value('');
|
||||||
element.removeAttribute('data-rainloopErrorTip');
|
errorTip(element);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
update: (element, fValueAccessor) => {
|
update: (element, fValueAccessor) => {
|
||||||
let value = ko.unwrap(fValueAccessor());
|
let value = ko.unwrap(fValueAccessor());
|
||||||
value = isFunction(value) ? value() : value;
|
value = isFunction(value) ? value() : value;
|
||||||
if (value) {
|
errorTip(element, value);
|
||||||
setTimeout(() => element.setAttribute('data-rainloopErrorTip', value), 100);
|
|
||||||
} else {
|
|
||||||
element.removeAttribute('data-rainloopErrorTip');
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
|
||||||
|
|
||||||
ko.bindingHandlers.onEnter = {
|
onEnter: {
|
||||||
init: (element, fValueAccessor, fAllBindings, viewModel) => {
|
init: (element, fValueAccessor, fAllBindings, viewModel) => {
|
||||||
let fn = event => {
|
let fn = event => {
|
||||||
if ('Enter' == event.key) {
|
if ('Enter' == event.key) {
|
||||||
|
|
@ -65,9 +66,9 @@ ko.bindingHandlers.onEnter = {
|
||||||
element.addEventListener('keydown', fn);
|
element.addEventListener('keydown', fn);
|
||||||
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeEventListener('keydown', fn));
|
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeEventListener('keydown', fn));
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.onSpace = {
|
onSpace: {
|
||||||
init: (element, fValueAccessor, fAllBindings, viewModel) => {
|
init: (element, fValueAccessor, fAllBindings, viewModel) => {
|
||||||
let fn = event => {
|
let fn = event => {
|
||||||
if (' ' == event.key) {
|
if (' ' == event.key) {
|
||||||
|
|
@ -77,24 +78,24 @@ ko.bindingHandlers.onSpace = {
|
||||||
element.addEventListener('keyup', fn);
|
element.addEventListener('keyup', fn);
|
||||||
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeEventListener('keyup', fn));
|
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeEventListener('keyup', fn));
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.i18nInit = {
|
i18nInit: {
|
||||||
init: element => i18nToNodes(element)
|
init: element => i18nToNodes(element)
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.i18nUpdate = {
|
i18nUpdate: {
|
||||||
update: (element, fValueAccessor) => {
|
update: (element, fValueAccessor) => {
|
||||||
ko.unwrap(fValueAccessor());
|
ko.unwrap(fValueAccessor());
|
||||||
i18nToNodes(element);
|
i18nToNodes(element);
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.title = {
|
title: {
|
||||||
update: (element, fValueAccessor) => element.title = ko.unwrap(fValueAccessor())
|
update: (element, fValueAccessor) => element.title = ko.unwrap(fValueAccessor())
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.command = {
|
command: {
|
||||||
init: (element, fValueAccessor, fAllBindings, viewModel, bindingContext) => {
|
init: (element, fValueAccessor, fAllBindings, viewModel, bindingContext) => {
|
||||||
const command = fValueAccessor();
|
const command = fValueAccessor();
|
||||||
|
|
||||||
|
|
@ -123,9 +124,9 @@ ko.bindingHandlers.command = {
|
||||||
element.disabled = disabled;
|
element.disabled = disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
ko.bindingHandlers.saveTrigger = {
|
saveTrigger: {
|
||||||
init: (element) => {
|
init: (element) => {
|
||||||
let icon = element;
|
let icon = element;
|
||||||
if (element.matches('input,select,textarea')) {
|
if (element.matches('input,select,textarea')) {
|
||||||
|
|
@ -146,7 +147,8 @@ ko.bindingHandlers.saveTrigger = {
|
||||||
cl.toggle('success', value === SaveSettingsStep.TrueResult);
|
cl.toggle('success', value === SaveSettingsStep.TrueResult);
|
||||||
cl.toggle('error', value === SaveSettingsStep.FalseResult);
|
cl.toggle('error', value === SaveSettingsStep.FalseResult);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// extenders
|
// extenders
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Scope } from 'Common/Enums';
|
|
||||||
import { i18n } from 'Common/Translator';
|
import { i18n } from 'Common/Translator';
|
||||||
import { isFunction } from 'Common/Utils';
|
import { isFunction } from 'Common/Utils';
|
||||||
|
|
||||||
|
|
@ -58,8 +57,8 @@ class AskPopupView extends AbstractViewPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
// shortcuts.add('tab', 'shift', Scope.Ask, () => {
|
// shortcuts.add('tab', 'shift', 'Ask', () => {
|
||||||
shortcuts.add('tab,arrowright,arrowleft', '', Scope.Ask, () => {
|
shortcuts.add('tab,arrowright,arrowleft', '', 'Ask', () => {
|
||||||
let btn = this.querySelector('.buttonYes');
|
let btn = this.querySelector('.buttonYes');
|
||||||
if (btn.matches(':focus')) {
|
if (btn.matches(':focus')) {
|
||||||
btn = this.querySelector('.buttonNo');
|
btn = this.querySelector('.buttonNo');
|
||||||
|
|
@ -68,7 +67,7 @@ class AskPopupView extends AbstractViewPopup {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
shortcuts.add('escape', '', Scope.Ask, () => {
|
shortcuts.add('escape', '', 'Ask', () => {
|
||||||
this.noClick();
|
this.noClick();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Scope,
|
|
||||||
Notification,
|
Notification,
|
||||||
UploadErrorCode
|
UploadErrorCode
|
||||||
} from 'Common/Enums';
|
} from 'Common/Enums';
|
||||||
|
|
@ -50,6 +49,8 @@ import { ContactsPopupView } from 'View/Popup/Contacts';
|
||||||
import { ThemeStore } from 'Stores/Theme';
|
import { ThemeStore } from 'Stores/Theme';
|
||||||
|
|
||||||
const
|
const
|
||||||
|
ScopeCompose = 'Compose',
|
||||||
|
|
||||||
base64_encode = text => btoa(text).match(/.{1,76}/g).join('\r\n'),
|
base64_encode = text => btoa(text).match(/.{1,76}/g).join('\r\n'),
|
||||||
|
|
||||||
email = new EmailModel(),
|
email = new EmailModel(),
|
||||||
|
|
@ -1323,42 +1324,42 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
this.addAttachmentEnabled(true);
|
this.addAttachmentEnabled(true);
|
||||||
|
|
||||||
shortcuts.add('q', 'meta', Scope.Compose, ()=>false);
|
shortcuts.add('q', 'meta', ScopeCompose, ()=>false);
|
||||||
shortcuts.add('w', 'meta', Scope.Compose, ()=>false);
|
shortcuts.add('w', 'meta', ScopeCompose, ()=>false);
|
||||||
|
|
||||||
shortcuts.add('contextmenu', '', Scope.Compose, e => this.popupMenu(e));
|
shortcuts.add('contextmenu', '', ScopeCompose, e => this.popupMenu(e));
|
||||||
shortcuts.add('m', 'meta', Scope.Compose, e => this.popupMenu(e));
|
shortcuts.add('m', 'meta', ScopeCompose, e => this.popupMenu(e));
|
||||||
|
|
||||||
shortcuts.add('escape,close', '', Scope.Compose, () => {
|
shortcuts.add('escape,close', '', ScopeCompose, () => {
|
||||||
this.skipCommand();
|
this.skipCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
shortcuts.add('arrowdown', 'meta', Scope.Compose, () => {
|
shortcuts.add('arrowdown', 'meta', ScopeCompose, () => {
|
||||||
this.skipCommand();
|
this.skipCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
shortcuts.add('s', 'meta', Scope.Compose, () => {
|
shortcuts.add('s', 'meta', ScopeCompose, () => {
|
||||||
this.saveCommand();
|
this.saveCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
shortcuts.add('save', '', Scope.Compose, () => {
|
shortcuts.add('save', '', ScopeCompose, () => {
|
||||||
this.saveCommand();
|
this.saveCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Settings.app('allowCtrlEnterOnCompose')) {
|
if (Settings.app('allowCtrlEnterOnCompose')) {
|
||||||
shortcuts.add('enter', 'meta', Scope.Compose, () => {
|
shortcuts.add('enter', 'meta', ScopeCompose, () => {
|
||||||
this.sendCommand();
|
this.sendCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
shortcuts.add('mailsend', '', Scope.Compose, () => {
|
shortcuts.add('mailsend', '', ScopeCompose, () => {
|
||||||
this.sendCommand();
|
this.sendCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
shortcuts.add('escape,close', 'shift', Scope.Compose, () => {
|
shortcuts.add('escape,close', 'shift', ScopeCompose, () => {
|
||||||
this.modalVisibility() && this.tryToClosePopup();
|
this.modalVisibility() && this.tryToClosePopup();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
import { koArrayWithDestroy } from 'External/ko';
|
import { koArrayWithDestroy } from 'External/ko';
|
||||||
|
|
||||||
import {
|
import { SaveSettingsStep } from 'Common/Enums';
|
||||||
SaveSettingsStep,
|
|
||||||
Scope
|
|
||||||
} from 'Common/Enums';
|
|
||||||
|
|
||||||
import { ComposeType } from 'Common/EnumsUser';
|
import { ComposeType } from 'Common/EnumsUser';
|
||||||
|
|
||||||
|
|
@ -26,7 +23,9 @@ import { ContactPropertyModel, ContactPropertyType } from 'Model/ContactProperty
|
||||||
import { decorateKoCommands } from 'Knoin/Knoin';
|
import { decorateKoCommands } from 'Knoin/Knoin';
|
||||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||||
|
|
||||||
const CONTACTS_PER_PAGE = 50,
|
const
|
||||||
|
CONTACTS_PER_PAGE = 50,
|
||||||
|
ScopeContacts = 'Contacts',
|
||||||
propertyIsMail = prop => prop.isType(ContactPropertyType.Email),
|
propertyIsMail = prop => prop.isType(ContactPropertyType.Email),
|
||||||
propertyIsName = prop => prop.isType(ContactPropertyType.FirstName) || prop.isType(ContactPropertyType.LastName);
|
propertyIsName = prop => prop.isType(ContactPropertyType.FirstName) || prop.isType(ContactPropertyType.LastName);
|
||||||
|
|
||||||
|
|
@ -446,14 +445,14 @@ class ContactsPopupView extends AbstractViewPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild(dom) {
|
onBuild(dom) {
|
||||||
this.selector.init(dom.querySelector('.b-list-content'), Scope.Contacts);
|
this.selector.init(dom.querySelector('.b-list-content'), ScopeContacts);
|
||||||
|
|
||||||
shortcuts.add('delete', '', Scope.Contacts, () => {
|
shortcuts.add('delete', '', ScopeContacts, () => {
|
||||||
this.deleteCommand();
|
this.deleteCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
shortcuts.add('c,w', '', Scope.Contacts, () => {
|
shortcuts.add('c,w', '', ScopeContacts, () => {
|
||||||
this.newMessageCommand();
|
this.newMessageCommand();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { Scope } from 'Common/Enums';
|
|
||||||
|
|
||||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||||
|
|
||||||
export class KeyboardShortcutsHelpPopupView extends AbstractViewPopup {
|
export class KeyboardShortcutsHelpPopupView extends AbstractViewPopup {
|
||||||
|
|
@ -14,7 +12,7 @@ export class KeyboardShortcutsHelpPopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
// shortcuts.add('tab', 'shift',
|
// shortcuts.add('tab', 'shift',
|
||||||
shortcuts.add('tab,arrowleft,arrowright', '',
|
shortcuts.add('tab,arrowleft,arrowright', '',
|
||||||
Scope.KeyboardShortcutsHelp,
|
'KeyboardShortcutsHelp',
|
||||||
event => {
|
event => {
|
||||||
let next = 0;
|
let next = 0;
|
||||||
tabs.forEach((node, index) => {
|
tabs.forEach((node, index) => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Scope } from 'Common/Enums';
|
|
||||||
import { doc } from 'Common/Globals';
|
import { doc } from 'Common/Globals';
|
||||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||||
|
|
||||||
|
|
@ -119,7 +118,7 @@ class OpenPgpKeyPopupView extends AbstractViewPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuild() {
|
onBuild() {
|
||||||
shortcuts.add('a', 'meta', Scope.OpenPgpKey, () => {
|
shortcuts.add('a', 'meta', 'OpenPgpKey', () => {
|
||||||
this.selectKey();
|
this.selectKey();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
|
|
||||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||||
|
|
||||||
import { doc, leftPanelDisabled, moveAction, Settings, SettingsCapa, SettingsGet, fireEvent } from 'Common/Globals';
|
import { doc, leftPanelDisabled, moveAction, Settings, SettingsCapa, SettingsGet, fireEvent, addEventsListeners } from 'Common/Globals';
|
||||||
|
|
||||||
import { computedPaginatorHelper, showMessageComposer, populateMessageBody } from 'Common/UtilsUser';
|
import { computedPaginatorHelper, showMessageComposer, populateMessageBody } from 'Common/UtilsUser';
|
||||||
import { FileInfo } from 'Common/File';
|
import { FileInfo } from 'Common/File';
|
||||||
|
|
@ -642,7 +642,8 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
|
|
||||||
this.selector.init(dom.querySelector('.b-content'), Scope.MessageList);
|
this.selector.init(dom.querySelector('.b-content'), Scope.MessageList);
|
||||||
|
|
||||||
dom.addEventListener('click', event => {
|
addEventsListeners(dom, {
|
||||||
|
click: event => {
|
||||||
ThemeStore.isMobile() && !eqs(event, '.toggleLeft') && leftPanelDisabled(true);
|
ThemeStore.isMobile() && !eqs(event, '.toggleLeft') && leftPanelDisabled(true);
|
||||||
|
|
||||||
if (eqs(event, '.messageList') && Scope.MessageView === AppUserStore.focusedState()) {
|
if (eqs(event, '.messageList') && Scope.MessageView === AppUserStore.focusedState()) {
|
||||||
|
|
@ -659,11 +660,11 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
|
|
||||||
el = eqs(event, '.threads-len');
|
el = eqs(event, '.threads-len');
|
||||||
el && this.gotoThread(ko.dataFor(el));
|
el && this.gotoThread(ko.dataFor(el));
|
||||||
});
|
},
|
||||||
|
dblclick: event => {
|
||||||
dom.addEventListener('dblclick', event => {
|
|
||||||
let el = eqs(event, '.actionHandle');
|
let el = eqs(event, '.actionHandle');
|
||||||
el && this.gotoThread(ko.dataFor(el));
|
el && this.gotoThread(ko.dataFor(el));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// initUploaderForAppend
|
// initUploaderForAppend
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue