More jQuery to native (including bootstrap.js)

This commit is contained in:
djmaze 2020-08-30 10:30:50 +02:00
parent bdb36ec128
commit 69fcc240e9
39 changed files with 496 additions and 344 deletions

View file

@ -265,26 +265,23 @@ class Selector {
this.oContentScrollable = contentScrollable;
if (contentScrollable) {
jQuery(contentScrollable)
.on('selectstart', (event) => {
if (event && event.preventDefault) {
event.preventDefault();
}
})
.on('click', this.sItemSelector, (event) => {
this.actionClick(ko.dataFor(event.currentTarget), event);
})
.on('click', this.sItemCheckedSelector, (event) => {
const item = ko.dataFor(event.currentTarget);
contentScrollable.addEventListener('click', event => {
let el = event.target.closestWithin(this.sItemSelector, contentScrollable);
el && this.actionClick(ko.dataFor(el), event);
el = event.target.closestWithin(this.sItemCheckedSelector, contentScrollable);
if (el) {
const item = ko.dataFor(el);
if (item) {
if (event && event.shiftKey) {
if (event.shiftKey) {
this.actionClick(item, event);
} else {
this.focusedItem(item);
item.checked(!item.checked());
}
}
});
}
});
key('enter', keyScope, () => {
const focused = this.focusedItem();

View file

@ -14,13 +14,6 @@ const
},
htmlspecialchars = str => (''+str).replace(/[&<>"']/g, m => htmlmap[m]);
export function htmlToElement(html) {
var template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.firstChild;
}
/**
* @param {(string|number)} value
* @param {boolean=} includeZero = true

View file

@ -28,12 +28,12 @@ const componentExportHelper = (ClassObject, templateID = '') => ({
if (componentInfo && componentInfo.element) {
params.component = componentInfo;
params.element = jQuery(componentInfo.element);
params.element = componentInfo.element;
i18nToNodes(componentInfo.element);
if (undefined !== params.inline && ko.unwrap(params.inline)) {
params.element.css('display', 'inline-block');
params.element.style.display = 'inline-block';
}
}

View file

@ -31,7 +31,7 @@ class AbstractInput extends AbstractComponent {
});
if (undefined !== params.width && params.element) {
params.element.find('input,select,textarea').css('width', params.width);
params.element.querySelectorAll('input,select,textarea').forEach(node => node.style.width = params.width);
}
this.disposable.push(this.className);

View file

@ -9,7 +9,7 @@ class SaveTriggerComponent extends AbstractComponent {
constructor(params) {
super();
this.element = params.element || null;
this.element = jQuery(params.element) || null;
this.value = params.value && params.value.subscribe ? params.value : null;
if (this.element) {

50
dev/External/ko.js vendored
View file

@ -92,18 +92,18 @@ ko.bindingHandlers.tooltipErrorTip = {
};
ko.bindingHandlers.registrateBootstrapDropdown = {
init: element => rl.Dropdowns.registrate(element)
init: element => {
rl.Dropdowns.registrate(element);
element.ddBtn = new BSN.Dropdown(element.querySelector('[data-toggle="dropdown"]'));
}
};
ko.bindingHandlers.openDropdownTrigger = {
update: (element, fValueAccessor) => {
if (ko.unwrap(fValueAccessor())) {
const $el = $(element), t = $el.find('.dropdown-toggle');
if (!$el.hasClass('open')) {
t.dropdown('toggle');
}
t.focus();
const el = element.ddBtn;
el.open || el.Dropdown.toggle();
// el.focus();
rl.Dropdowns.detectVisibility();
fValueAccessor()(false);
@ -112,11 +112,9 @@ ko.bindingHandlers.openDropdownTrigger = {
};
ko.bindingHandlers.dropdownCloser = {
init: element => $(element)
.closest('.dropdown')
.on('click', '.e-item', () => {
$(element).dropdown('toggle');
})
init: element => element.closest('.dropdown').addEventListener('click', event =>
event.target.closestWithin('.e-item', element) && element.ddBtn.Dropdown.toggle()
)
};
ko.bindingHandlers.popover = {
@ -179,28 +177,22 @@ ko.bindingHandlers.modal = {
init: (element, fValueAccessor) => {
const Globals = require('Common/Globals');
$(element)
.toggleClass('fade', !Globals.bMobileDevice)
.modal({
'keyboard': false,
'show': ko.unwrap(fValueAccessor())
})
.find('.close')
.on('click.koModal', () => {
fValueAccessor()(false);
});
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
$(element)
.off('shown.koModal')
.find('.close')
.off('click.koModal');
element.classList.toggle('fade', !Globals.bMobileDevice);
new BSN.Modal(element, {
'keyboard': false,
'show': ko.unwrap(fValueAccessor())
});
const close = element.querySelector('.close'), click = () => fValueAccessor()(false);
close && close.addEventListener('click.koModal', click);
ko.utils.domNodeDisposal.addDisposeCallback(element, () =>
close.removeEventListener('click.koModal', click)
);
},
update: (element, fValueAccessor) => {
const htmlCL = doc.documentElement.classList;
$(element).modal(ko.unwrap(fValueAccessor()) ? 'show' : 'hide');
element.Modal[ko.unwrap(fValueAccessor()) ? 'show' : 'hide']();
if (htmlCL.contains('no-mobile')) {
htmlCL.add('rl-modal-animation');

View file

@ -166,13 +166,11 @@ export function buildViewModel(ViewModelClass, vmScreen) {
vm.viewModelPosition = ViewModelClass.__type;
if (vmPlace) {
vmDom = jQuery('<div></div>');
vmDom[0].classList.add('rl-view-model', 'RL-' + vm.viewModelTemplateID);
vmDom[0].hidden = true;
vmPlace.append(vmDom[0]);
vmDom = Element.fromHTML('<div class="rl-view-model RL-' + vm.viewModelTemplateID + '" hidden=""></div>');
vmPlace.append(vmDom);
vm.viewModelDom = vmDom[0];
ViewModelClass.__dom = vmDom[0];
vm.viewModelDom = vmDom;
ViewModelClass.__dom = vmDom;
if (ViewType.Popup === position) {
vm.cancelCommand = vm.closeCommand = createCommand(() => {
@ -203,7 +201,7 @@ export function buildViewModel(ViewModelClass, vmScreen) {
}
ko.applyBindingAccessorsToNode(
vmDom[0],
vmDom,
{
i18nInit: true,
template: () => ({ name: vm.viewModelTemplateID })
@ -509,19 +507,18 @@ function commandDecorator(canExecute = true) {
* @param {miced} $items
* @returns {Function}
*/
function settingsMenuKeysHandler($items) {
function settingsMenuKeysHandler(items) {
return ((event, handler)=>{
const up = handler && 'up' === handler.shortcut;
if (event && $items.length) {
let index = $items.index($items.filter('.selected'));
if (up && 0 < index) {
index -= 1;
} else if (!up && index < $items.length - 1) {
index += 1;
let index = items.length;
if (event && index) {
while (index-- && !items[index].matches('.selected'));
if (handler && 'up' === handler.shortcut) {
index && --index;
} else if (index < items.length - 1) {
++index;
}
const resultHash = $items.eq(index).attr('href');
const resultHash = items[index].href;
if (resultHash) {
setHash(resultHash, false, true);
}

View file

@ -17,7 +17,6 @@ class AbstractSettingsScreen extends AbstractScreen {
this.menu = ko.observableArray([]);
this.oCurrentSubScreen = null;
this.oViewModelPlace = null;
this.setupSettings();
}
@ -66,25 +65,24 @@ class AbstractSettingsScreen extends AbstractScreen {
if (RoutedSettingsViewModel.__builded && RoutedSettingsViewModel.__vm) {
settingsScreen = RoutedSettingsViewModel.__vm;
} else {
if (this.oViewModelPlace) {
const vmPlace = document.getElementById('rl-settings-subscreen');
if (vmPlace) {
settingsScreen = new RoutedSettingsViewModel();
viewModelDom = jQuery('<div></div>');
viewModelDom[0].classList.add('rl-settings-view-model');
viewModelDom[0].hidden = true;
this.oViewModelPlace.append(viewModelDom[0]);
viewModelDom = Element.fromHTML('<div class="rl-settings-view-model" hidden=""></div>');
vmPlace.append(viewModelDom);
settingsScreen.viewModelDom = viewModelDom[0];
settingsScreen.viewModelDom = viewModelDom;
settingsScreen.__rlSettingsData = RoutedSettingsViewModel.__rlSettingsData;
RoutedSettingsViewModel.__dom = viewModelDom[0];
RoutedSettingsViewModel.__dom = viewModelDom;
RoutedSettingsViewModel.__builded = true;
RoutedSettingsViewModel.__vm = settingsScreen;
const tmpl = { name: RoutedSettingsViewModel.__rlSettingsData.Template };
ko.applyBindingAccessorsToNode(
viewModelDom[0],
viewModelDom,
{
i18nInit: true,
template: () => tmpl
@ -161,8 +159,6 @@ class AbstractSettingsScreen extends AbstractScreen {
});
}
});
this.oViewModelPlace = document.getElementById('rl-settings-subscreen');
}
routes() {

View file

@ -1,5 +1,5 @@
import { Focused, Capa, ClientSideKeyName } from 'Common/Enums';
import { $html, leftPanelDisabled, leftPanelType, moveAction, bMobileDevice } from 'Common/Globals';
import { leftPanelDisabled, leftPanelType, moveAction, bMobileDevice } from 'Common/Globals';
import { pString, pInt } from 'Common/Utils';
import { getFolderFromCacheList, getFolderFullNameRaw, getFolderInboxName } from 'Common/Cache';
import { i18n } from 'Common/Translator';
@ -128,9 +128,9 @@ class MailBoxUserScreen extends AbstractScreen {
, 1);
}
jQuery($html).on('click', '#rl-right', () => {
moveAction(false);
});
document.addEventListener('click', event =>
event.target.closest('#rl-right') && moveAction(false)
);
}
/**

View file

@ -39,13 +39,9 @@ class DomainsAdminSettings {
}
onBuild(oDom) {
const self = this;
oDom.on('click', '.b-admin-domains-list-table .e-item .e-action', function() {
// eslint-disable-line prefer-arrow-callback
const domainItem = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (domainItem) {
Remote.domain(self.onDomainLoadRequest, domainItem.name);
}
oDom.addEventListener('click', event => {
let el = event.target.closestWithin('.b-admin-domains-list-table .e-item .e-action', oDom);
el && ko.dataFor(el) && Remote.domain(this.onDomainLoadRequest, ko.dataFor(el).name);
});
getApp().reloadDomainList();

View file

@ -35,23 +35,13 @@ class PluginsAdminSettings {
}
onBuild(oDom) {
const self = this;
oDom.addEventListener('click', event => {
let el = event.target.closestWithin('.e-item .configure-plugin-action', oDom);
el && ko.dataFor(el) && this.configurePlugin(ko.dataFor(el));
oDom
.on('click', '.e-item .configure-plugin-action', function() {
// eslint-disable-line prefer-arrow-callback
const plugin = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (plugin) {
self.configurePlugin(plugin);
}
})
.on('click', '.e-item .disabled-plugin', function() {
// eslint-disable-line prefer-arrow-callback
const plugin = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (plugin) {
self.disablePlugin(plugin);
}
});
el = event.target.closestWithin('.e-item .disabled-plugin', oDom);
el && ko.dataFor(el) && this.disablePlugin(ko.dataFor(el));
});
this.enabledPlugins.subscribe((value) => {
Remote.saveAdminConfig(null, {

View file

@ -99,23 +99,13 @@ class AccountsUserSettings {
}
onBuild(oDom) {
const self = this;
oDom.addEventListener('click', event => {
let el = event.target.closestWithin('.accounts-list .account-item .e-action', oDom);
el && ko.dataFor(el) && this.editAccount(ko.dataFor(el));
oDom
.on('click', '.accounts-list .account-item .e-action', function() {
// eslint-disable-line prefer-arrow-callback
const account = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (account) {
self.editAccount(account);
}
})
.on('click', '.identities-list .identity-item .e-action', function() {
// eslint-disable-line prefer-arrow-callback
const identity = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (identity) {
self.editIdentity(identity);
}
});
el = event.target.closestWithin('.identities-list .identity-item .e-action', oDom);
el && ko.dataFor(el) && this.editIdentity(ko.dataFor(el));
});
}
}

View file

@ -180,14 +180,9 @@ class FiltersUserSettings {
}
onBuild(oDom) {
const self = this;
oDom.on('click', '.filter-item .e-action', function() {
// eslint-disable-line prefer-arrow-callback
const filter = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (filter) {
self.editFilter(filter);
}
oDom.addEventListener('click', event => {
const el = event.target.closestWithin('.filter-item .e-action', oDom);
el && ko.dataFor(el) && this.editFilter(ko.dataFor(el));
});
}

View file

@ -70,19 +70,13 @@ class FoldersUserSettings {
}
onBuild(oDom) {
oDom
.on('mouseover', '.delete-folder-parent', () => {
this.folderListHelp(i18n('SETTINGS_FOLDERS/HELP_DELETE_FOLDER'));
})
.on('mouseover', '.subscribe-folder-parent', () => {
this.folderListHelp(i18n('SETTINGS_FOLDERS/HELP_SHOW_HIDE_FOLDER'));
})
.on('mouseover', '.check-folder-parent', () => {
this.folderListHelp(i18n('SETTINGS_FOLDERS/HELP_CHECK_FOR_NEW_MESSAGES'));
})
.on('mouseout', '.subscribe-folder-parent, .check-folder-parent, .delete-folder-parent', () => {
this.folderListHelp('');
});
oDom.addEventListener('mouseover', event => {
const eqs = s => event.target.closestWithin(s, oDom);
eqs('.delete-folder-parent') && this.folderListHelp(i18n('SETTINGS_FOLDERS/HELP_DELETE_FOLDER'));
eqs('.subscribe-folder-parent') && this.folderListHelp(i18n('SETTINGS_FOLDERS/HELP_SHOW_HIDE_FOLDER'));
eqs('.check-folder-parent') && this.folderListHelp(i18n('SETTINGS_FOLDERS/HELP_CHECK_FOR_NEW_MESSAGES'));
});
oDom.addEventListener('mouseout', () => this.folderListHelp(''));
}
createFolder() {

View file

@ -58,14 +58,9 @@ class TemplatesUserSettings {
}
onBuild(oDom) {
const self = this;
oDom.on('click', '.templates-list .template-item .e-action', function() {
// eslint-disable-line prefer-arrow-callback
const template = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (template) {
self.editTemplate(template);
}
oDom.addEventListener('click', event => {
const el = event.target.closestWithin('.templates-list .template-item .e-action', oDom);
el && ko.dataFor(el) && this.editTemplate(ko.dataFor(el));
});
this.reloadTemplates();

View file

@ -6,8 +6,7 @@ import {
pInt,
pString,
plainToHtml,
findEmailAndLinks,
htmlToElement
findEmailAndLinks
} from 'Common/Utils';
import {
@ -45,7 +44,7 @@ import { getApp } from 'Helper/Apps/User';
import Remote from 'Remote/User/Ajax';
const
hcont = htmlToElement('<div area="hidden" style="position:absolute;left:-5000px"></div>'),
hcont = Element.fromHTML('<div area="hidden" style="position:absolute;left:-5000px"></div>'),
getRealHeight = el => {
hcont.innerHTML = el.outerHTML;
const result = hcont.clientHeight;
@ -428,7 +427,7 @@ class MessageUserStore {
if (node.textContent.trim() && !node.parentNode.closest('blockquote')) {
let h = node.clientHeight || getRealHeight(node);
if (0 === h || 100 < h) {
const el = htmlToElement('<span class="rlBlockquoteSwitcher">•••</span>');
const el = Element.fromHTML('<span class="rlBlockquoteSwitcher">•••</span>');
node.classList.add('rl-bq-switcher','hidden-bq');
node.before(el);
el.addEventListener('click', () => node.classList.toggle('hidden-bq'));
@ -539,7 +538,7 @@ class MessageUserStore {
iMessageBodyCacheCount += 1;
body = htmlToElement('<div id="' + id + '" hidden="" class="rl-cache-class b-text-part '
body = Element.fromHTML('<div id="' + id + '" hidden="" class="rl-cache-class b-text-part '
+ (isHtml ? 'html' : 'plain') + '">'
+ findEmailAndLinks(resultHtml)
+ '</div>');

View file

@ -1,7 +1,7 @@
import ko from 'ko';
import { i18n } from 'Common/Translator';
import { isNonEmptyArray, pString, htmlToElement } from 'Common/Utils';
import { isNonEmptyArray, pString } from 'Common/Utils';
import AccountStore from 'Stores/User/Account';
@ -349,7 +349,7 @@ class PgpUserStore {
if (encrypted || signed) {
const domText = dom.textContent;
verControl = htmlToElement('<div class="b-openpgp-control"><i class="icon-lock"></i></div>'); // 🔒
verControl = Element.fromHTML('<div class="b-openpgp-control"><i class="icon-lock"></i></div>'); // 🔒
if (encrypted) {
verControl.title = i18n('MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC');
verControl.addEventHandler('click', domControlEncryptedClickHelper(this, dom, domText, recipients));

View file

@ -152,7 +152,7 @@ html.no-mobile {
/*transform: scale(0.95);*/
transform: translateY(-20px);
&.in {
&.show {
transform: none;
}
}

View file

@ -204,7 +204,7 @@ select {
overflow: hidden;
text-overflow: ellipsis;
&.in {
&.show {
opacity: 1;
}
@ -330,7 +330,7 @@ html.no-rgba .modal {
border-width: 0px !important;
}
.modal-backdrop, .modal-backdrop.fade.in {
.modal-backdrop, .modal-backdrop.fade.show {
.opacity(20);
transform: none;
}
@ -344,6 +344,7 @@ html.no-rgba .modal {
right: 0;
z-index: 1100;
overflow: auto;
background-color: rgba(0,0,0,0.3);
// -webkit-overflow-scrolling: touch;
.modal {
@ -367,7 +368,7 @@ html.no-rgba .modal {
top: 0;
}
.modal.fade.in {
.modal.fade.show {
top: 0;
}

View file

@ -26,7 +26,7 @@ class MenuSettingsAdminView extends AbstractViewNext {
}
onBuild(dom) {
key('up, down', KeyState.Settings, settingsMenuKeysHandler(jQuery('.b-admin-menu .e-item', dom)));
key('up, down', KeyState.Settings, settingsMenuKeysHandler(dom.querySelectoAll('.b-admin-menu .e-item')));
}
}

View file

@ -99,7 +99,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
this.defautOptionsAfterRender(domOption, item);
if (item && undefined !== item.class && domOption) {
jQuery(domOption).addClass(item.class);
domOption.classList.add(item.class);
}
};

View file

@ -610,7 +610,7 @@ class ContactsPopupView extends AbstractViewNext {
}
onBuild(dom) {
this.selector.init(dom[0].querySelector('.b-list-content'), KeyState.ContactList);
this.selector.init(dom.querySelector('.b-list-content'), KeyState.ContactList);
key('delete', KeyState.ContactList, () => {
this.deleteCommand();
@ -624,11 +624,10 @@ class ContactsPopupView extends AbstractViewNext {
const self = this;
dom.on('click', '.e-pagenator .e-page', function() {
// eslint-disable-line prefer-arrow-callback
const page = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (page) {
self.contactsPage(pInt(page.value));
dom.addEventListener('click', event => {
let el = event.target.closestWithin('.e-pagenator .e-page', dom);
if (el && ko.dataFor(el)) {
self.contactsPage(pInt(ko.dataFor(el).value));
self.reloadContactList();
}
});

View file

@ -14,27 +14,27 @@ class KeyboardShortcutsHelpPopupView extends AbstractViewNext {
}
onBuild(dom) {
dom.querySelectorAll('a[data-toggle="tab"]').forEach(node => node.Tab || new BSN.Tab(node));
key(
'tab, shift+tab, left, right',
KeyState.PopupKeyboardShortcutsHelp,
((event, handler)=>{
if (event && handler) {
const $tabs = dom.find('.nav.nav-tabs > li'),
isNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut);
const tabs = dom.querySelectorAll('.nav.nav-tabs > li'),
last = tabs.length - 1;
let next = 0;
tabs.forEach((node, index) => {
if (node.matches('.active')) {
if (['tab','right'].includes(handler.shortcut)) {
next = index < last ? index+1 : 0;
} else {
next = index ? index-1 : last;
}
}
});
let index = $tabs.index($tabs.filter('.active'));
if (!isNext && 0 < index) {
index -= 1;
} else if (isNext && index < $tabs.length - 1) {
index += 1;
} else {
index = isNext ? 0 : $tabs.length - 1;
}
$tabs
.eq(index)
.find('a[data-toggle="tab"]')
.tab('show');
tabs[next].querySelector('a[data-toggle="tab"]').Tab.show();
}
}).throttle(100)
);

View file

@ -90,22 +90,18 @@ class MessageOpenPgpPopupView extends AbstractViewNext {
const self = this;
oDom.on('click', '.key-list__item', function() {
// eslint-disable-line prefer-arrow-callback
oDom.addEventListener('click', event => {
const el = event.target.closestWithin('.key-list__item', oDom);
if (el) {
oDom.querySelectorAll('.key-list__item .key-list__item__radio').forEach(node => {
node.classList.toggle('icon-radio-unchecked', el !== node);
node.classList.toggle('icon-radio-checked', el === node);
});
oDom
.find('.key-list__item .key-list__item__radio')
.addClass('icon-radio-unchecked')
.removeClass('icon-radio-checked');
self.selectedKey(ko.dataFor(el)); // eslint-disable-line no-invalid-this
jQuery(this)
.find('.key-list__item__radio') // eslint-disable-line no-invalid-this
.removeClass('icon-radio-unchecked')
.addClass('icon-radio-checked');
self.selectedKey(ko.dataFor(this)); // eslint-disable-line no-invalid-this
// this.querySelector('.inputPassword').focus();
// this.querySelector('.inputPassword').focus();
}
});
}

View file

@ -1,6 +1,6 @@
import ko from 'ko';
import { Capa, Focused, Layout, KeyState, EventKeyCode } from 'Common/Enums';
import { Capa, Focused, Layout, KeyState } from 'Common/Enums';
import { $htmlCL, leftPanelDisabled, moveAction } from 'Common/Globals';
import { mailBox, settings } from 'Common/Links';
import { setFolderHash } from 'Common/Cache';
@ -58,8 +58,8 @@ class FolderListMailBoxUserView extends AbstractViewNext {
}
onBuild(dom) {
const self = this,
qs = s => dom[0].querySelector(s),
const qs = s => dom.querySelector(s),
eqs = (ev, s) => ev.target.closestWithin(s, dom),
isMobile = Settings.appSettingsGet('mobile'),
fSelectFolder = (el, event, starred) => {
const isMove = moveAction();
@ -105,11 +105,11 @@ class FolderListMailBoxUserView extends AbstractViewNext {
this.oContentScrollable = qs('.b-content');
dom
.on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function(event) {
// eslint-disable-line prefer-arrow-callback
const folder = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (folder && event) {
dom.addEventListener('click', event => {
let el = eqs(event, '.b-folders .e-item .e-link .e-collapsed-sign');
if (el) {
const folder = ko.dataFor(el);
if (folder) {
const collapsed = folder.collapsed();
getApp().setExpandedFolder(folder.fullNameHash, collapsed);
@ -117,35 +117,34 @@ class FolderListMailBoxUserView extends AbstractViewNext {
event.preventDefault();
event.stopPropagation();
}
})
.on('click', '.b-folders .e-item .e-link.selectable .inbox-star-icon', function(event) {
// eslint-disable-line prefer-arrow-callback
fSelectFolder(this, event, !self.isInboxStarred()); // eslint-disable-line no-invalid-this
})
.on('click', '.b-folders .e-item .e-link.selectable', function(event) {
// eslint-disable-line prefer-arrow-callback
fSelectFolder(this, event, false); // eslint-disable-line no-invalid-this
});
}
el = eqs(event, '.b-folders .e-item .e-link.selectable .inbox-star-icon');
el && fSelectFolder(el, event, !this.isInboxStarred());
el = eqs(event, '.b-folders .e-item .e-link.selectable');
el && fSelectFolder(el, event, false);
});
key('up, down', KeyState.FolderList, (event, handler) => {
const keyCode = handler && 'up' === handler.shortcut ? EventKeyCode.Up : EventKeyCode.Down,
$items = jQuery('.b-folders .e-item .e-link:not(.hidden):visible', dom);
let index = $items.length;
if (event && index) {
while (index--) {
if ($items[index].matches('.focused')) {
$items[index].classList.remove('focused');
break;
let items = [], index = 0;
dom.querySelectorAll('.b-folders .e-item .e-link:not(.hidden)').forEach(node => {
if (node.offsetHeight || node.getClientRects().length) {
items.push(node);
if (node.matches('.focused')) {
node.classList.remove('focused');
index = items.length - 1;
}
}
if (EventKeyCode.Up === keyCode && 0 < index) {
--index;
} else if (EventKeyCode.Down === keyCode && index < $items.length - 1) {
});
if (items.length) {
if (handler && 'up' === handler.shortcut) {
index && --index;
} else if (index < items.length - 1) {
++index;
}
$items[index].classList.add('focused');
self.scrollToFocused();
items[index].classList.add('focused');
this.scrollToFocused();
}
return false;

View file

@ -15,7 +15,7 @@ import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { bMobileDevice, leftPanelDisabled, moveAction } from 'Common/Globals';
import { computedPagenatorHelper, friendlySize, htmlToElement } from 'Common/Utils';
import { computedPagenatorHelper, friendlySize } from 'Common/Utils';
import { mailBox, append } from 'Common/Links';
import { Selector } from 'Common/Selector';
@ -502,7 +502,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
oMessageListItem.checked(true);
}
const el = htmlToElement('<div class="draggablePlace">' +
const el = Element.fromHTML('<div class="draggablePlace">' +
'<span class="text"></span>&nbsp;' +
'<i class="icon-copy icon-white visible-on-ctrl"></i>' +
'<i class="icon-mail icon-white hidden-on-ctrl"></i>' +
@ -739,41 +739,33 @@ class MessageListMailBoxUserView extends AbstractViewNext {
}
onBuild(dom) {
const self = this;
const eqs = (ev, s) => ev.target.closestWithin(s, dom);
this.selector.init(dom[0].querySelector('.b-content'), KeyState.MessageList);
this.selector.init(dom.querySelector('.b-content'), KeyState.MessageList);
if (this.mobile) {
dom.on('click', () => {
leftPanelDisabled(true);
});
}
dom.addEventListener('click', event => {
this.mobile && leftPanelDisabled(true);
dom
.on('click', '.messageList .b-message-list-wrapper', () => {
if (Focused.MessageView === AppStore.focusedState()) {
AppStore.focusedState(Focused.MessageList);
}
})
.on('click', '.e-pagenator .e-page', function() {
// eslint-disable-line prefer-arrow-callback
self.gotoPage(ko.dataFor(this)); // eslint-disable-line no-invalid-this
})
.on('click', '.messageList .checkboxCkeckAll', () => {
this.checkAll(!this.checkAll());
})
.on('click', '.messageList .messageListItem .flagParent', function() {
// eslint-disable-line prefer-arrow-callback
self.flagMessages(ko.dataFor(this)); // eslint-disable-line no-invalid-this
})
.on('click', '.messageList .messageListItem .threads-len', function() {
// eslint-disable-line prefer-arrow-callback
self.gotoThread(ko.dataFor(this)); // eslint-disable-line no-invalid-this
})
.on('dblclick', '.messageList .messageListItem .actionHandle', function() {
// eslint-disable-line prefer-arrow-callback
self.gotoThread(ko.dataFor(this)); // eslint-disable-line no-invalid-this
});
if (eqs(event, '.messageList .b-message-list-wrapper') && Focused.MessageView === AppStore.focusedState()) {
AppStore.focusedState(Focused.MessageList);
}
let el = eqs(event, '.e-pagenator .e-page');
el && this.gotoPage(ko.dataFor(el));
eqs(event, '.messageList .checkboxCkeckAll') && this.checkAll(!this.checkAll());
el = eqs(event, '.messageList .messageListItem .flagParent');
el && this.flagMessages(ko.dataFor(el));
el = eqs(event, '.messageList .messageListItem .threads-len');
el && this.gotoThread(ko.dataFor(el));
});
dom.addEventListener('dblclick', event => {
let el = eqs(event, '.messageList .messageListItem .actionHandle');
el && this.gotoThread(ko.dataFor(el));
});
this.initUploaderForAppend();
this.initShortcuts();

View file

@ -74,7 +74,6 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
}
}, this.messageVisibility);
this.oDom = null;
this.oHeaderDom = null;
this.oMessageScrollerDom = null;
@ -488,10 +487,6 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
}
onBuild(dom) {
const self = this;
this.oDom = dom;
this.fullScreenMode.subscribe((value) => {
if (value && this.message()) {
AppStore.focusedState(Focused.MessageView);
@ -502,7 +497,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
Local.set(ClientSideKeyName.MessageHeaderFullInfo, value ? '1' : '0');
});
this.oHeaderDom = dom[0].querySelector('.messageItemHeader');
this.oHeaderDom = dom.querySelector('.messageItemHeader');
if (this.oHeaderDom) {
if (!this.resizeObserver) {
this.resizeObserver = new ResizeObserver(this.checkHeaderHeight.throttle(50).bind(this));
@ -512,37 +507,30 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
this.resizeObserver.disconnect();
}
if (this.mobile) {
dom.on('click', () => {
leftPanelDisabled(true);
});
}
const eqs = (ev, s) => ev.target.closestWithin(s, dom);
dom.addEventListener('click', event => {
this.mobile && leftPanelDisabled(true);
dom
.on('click', 'a', function(event) {
// eslint-disable-line prefer-arrow-callback
// setup maito protocol
let el = eqs(event, 'a');
if (el) {
return !(
!!event &&
3 !== event.which &&
mailToHelper(
this.href,
Settings.capa(Capa.Composer) ? require('View/Popup/Compose') : null // eslint-disable-line no-invalid-this
el.href,
Settings.capa(Capa.Composer) ? require('View/Popup/Compose') : null
)
);
})
.on('click', '.attachmentsPlace .attachmentIconParent', (event) => {
if (event && event.stopPropagation) {
event.stopPropagation();
}
})
.on('click', '.attachmentsPlace .showPreplay', function(event) {
// eslint-disable-line prefer-arrow-callback
if (event && event.stopPropagation) {
event.stopPropagation();
}
}
const attachment = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (eqs(event, '.attachmentsPlace .attachmentIconParent')) {
event.stopPropagation();
}
el = eqs(event, '.attachmentsPlace .showPreplay');
if (el) {
event.stopPropagation();
const attachment = ko.dataFor(el); // eslint-disable-line no-invalid-this
if (attachment && Audio.supported) {
switch (true) {
case Audio.supportedMp3 && attachment.isMp3():
@ -557,17 +545,17 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
// no default
}
}
})
.on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function() {
}
el = eqs(event, '.attachmentsPlace .attachmentItem .attachmentNameParent');
if (el) {
const attachment = ko.dataFor(el);
attachment && attachment.download && getApp().download(attachment.linkDownload());
}
if (eqs(event, '.messageItemHeader .subjectParent .flagParent')) {
// eslint-disable-line prefer-arrow-callback
const attachment = ko.dataFor(this); // eslint-disable-line no-invalid-this
if (attachment && attachment.download) {
getApp().download(attachment.linkDownload());
}
})
.on('click', '.messageItemHeader .subjectParent .flagParent', function() {
// eslint-disable-line prefer-arrow-callback
const message = self.message();
const message = this.message();
if (message) {
getApp().messageListAction(
message.folderFullNameRaw,
@ -575,10 +563,12 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
[message]
);
}
})
.on('click', '.thread-list .flagParent', function() {
}
el = eqs(event, '.thread-list .flagParent');
if (el) {
// eslint-disable-line prefer-arrow-callback
const message = ko.dataFor(this); // eslint-disable-line no-invalid-this
const message = ko.dataFor(el); // eslint-disable-line no-invalid-this
if (message && message.folder && message.uid) {
getApp().messageListAction(
message.folder,
@ -587,10 +577,11 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
);
}
self.threadsDropdownTrigger(true);
this.threadsDropdownTrigger(true);
return false;
});
}
});
AppStore.focusedState.subscribe((value) => {
if (Focused.MessageView !== value) {
@ -603,8 +594,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
this.messageDomFocused(KeyState.MessageView === value && !inFocus());
});
const node = dom.find('.messageItem');
this.oMessageScrollerDom = node && node[0] ? node[0] : null;
this.oMessageScrollerDom = dom.querySelector('.messageItem');
this.initShortcuts();
}

View file

@ -29,12 +29,12 @@ class MenuSettingsUserView extends AbstractViewNext {
onBuild(dom) {
if (this.mobile) {
dom.on('click', '.b-settings-menu .e-item.selectable', () => {
leftPanelDisabled(true);
});
dom.addEventListener('click', event =>
event.target.closestWithin('.b-settings-menu .e-item.selectable', dom) && leftPanelDisabled(true)
);
}
key('up, down', KeyState.Settings, settingsMenuKeysHandler(jQuery('.b-settings-menu .e-item', dom)));
key('up, down', KeyState.Settings, settingsMenuKeysHandler(dom.querySelectoAll('.b-settings-menu .e-item')));
}
link(route) {

View file

@ -42,11 +42,7 @@ class PaneSettingsUserView extends AbstractViewNext {
}
onBuild(dom) {
if (this.mobile) {
dom.on('click', () => {
leftPanelDisabled(true);
});
}
this.mobile && dom.addEventListener('click', () => leftPanelDisabled(true));
}
backToMailBoxClick() {

12
dev/bootstrap.js vendored
View file

@ -1,4 +1,4 @@
import { $html, $htmlCL, data as GlobalsData, bMobileDevice, dropdownVisibility } from 'Common/Globals';
import { $htmlCL, data as GlobalsData, bMobileDevice, dropdownVisibility } from 'Common/Globals';
import * as Enums from 'Common/Enums';
import * as Plugins from 'Common/Plugins';
import { i18n } from 'Common/Translator';
@ -32,7 +32,7 @@ export default (App) => {
addEventListener('unload', () => GlobalsData.bUnload = true);
$htmlCL.add(bMobileDevice ? 'mobile' : 'no-mobile');
jQuery($html).on('click.dropdown.data-api', ()=>rl.Dropdowns.detectVisibility());
addEventListener('click', ()=>rl.Dropdowns.detectVisibility());
const rl = window.rl || {};
@ -60,10 +60,10 @@ export default (App) => {
window.rl = rl;
window.__APP_BOOT = fErrorCallback => {
jQuery(() => {
setTimeout(() => {
const doc = document,
cb = () => setTimeout(() => {
if (window.rainloopTEMPLATES && rainloopTEMPLATES[0]) {
document.getElementById('rl-templates').innerHTML = rainloopTEMPLATES[0];
doc.getElementById('rl-templates').innerHTML = rainloopTEMPLATES[0];
setTimeout(() => {
$htmlCL.remove('no-js', 'rl-booted-trigger');
$htmlCL.add('rl-booted');
@ -76,6 +76,6 @@ export default (App) => {
window.__APP_BOOT = null;
}, 10);
});
('loading' !== doc.readyState) ? cb() : doc.addEventListener('DOMContentLoaded', cb);
};
};

13
dev/prototype-element.js vendored Normal file
View file

@ -0,0 +1,13 @@
(()=>{
Element.prototype.closestWithin = function(selector, parent) {
const el = this.closest(selector);
return (el && el !== parent && parent.contains(el)) ? el : null;
};
Element.fromHTML = string => {
const template = document.createElement('template');
template.innerHTML = string.trim();
return template.content.firstChild;
};
})();