mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 07:35:55 +08:00
More jQuery to native (including bootstrap.js)
This commit is contained in:
parent
bdb36ec128
commit
69fcc240e9
|
@ -39,7 +39,9 @@ module.exports = {
|
|||
// vendors/jua
|
||||
'Jua': "readonly",
|
||||
// vendors/qr.js
|
||||
'qr': "readonly"
|
||||
'qr': "readonly",
|
||||
// vendors/bootstrap/bootstrap.native.js
|
||||
'BSN': "readonly"
|
||||
},
|
||||
// http://eslint.org/docs/rules/
|
||||
rules: {
|
||||
|
|
23
README.md
23
README.md
|
@ -78,32 +78,33 @@ Things might work in Edge 18, Firefox 50-62 and Chrome 54-68 due to one polyfill
|
|||
* Replaced momentToNode with proper HTML5 <time>
|
||||
* Replaced resize listeners with ResizeObserver
|
||||
* Removed non-community (aka Prem/Premium/License) code
|
||||
* Replaced bootstrap.js with native drop-in replacement
|
||||
|
||||
|js/* |1.14.0 |native |
|
||||
|----------- |--------: |--------: |
|
||||
|admin.js |2.130.942 | 973.239 |
|
||||
|app.js |4.184.455 |2.640.205 |
|
||||
|admin.js |2.130.942 | 971.538 |
|
||||
|app.js |4.184.455 |2.635.592 |
|
||||
|boot.js | 671.522 | 43.824 |
|
||||
|libs.js | 647.614 | 316.970 |
|
||||
|libs.js | 647.614 | 315.749 |
|
||||
|polyfills.js | 325.834 | 0 |
|
||||
|TOTAL |7.960.367 |3.974.238 |
|
||||
|TOTAL |7.960.367 |3.966.789 |
|
||||
|
||||
|js/min/* |1.14.0 |native |gzip 1.14 |gzip |brotli |
|
||||
|--------------- |--------: |--------: |--------: |--------: |--------: |
|
||||
|admin.min.js | 252.147 | 132.156 | 73.657 | 38.184 | 32.740 |
|
||||
|app.min.js | 511.202 | 356.109 |140.462 | 93.738 | 75.150 |
|
||||
|admin.min.js | 252.147 | 132.110 | 73.657 | 38.198 | 32.764 |
|
||||
|app.min.js | 511.202 | 355.996 |140.462 | 93.741 | 75.209 |
|
||||
|boot.min.js | 66.007 | 5.560 | 22.567 | 2.341 | 2.004 |
|
||||
|libs.min.js | 572.545 | 300.691 |176.720 | 92.925 | 82.046 |
|
||||
|libs.min.js | 572.545 | 299.213 |176.720 | 92.512 | 81.723 |
|
||||
|polyfills.min.js | 32.452 | 0 | 11.312 | 0 | 0 |
|
||||
|TOTAL |1.434.353 | 794.516 |424.718 |227.188 |191.940 |
|
||||
|TOTAL |1.434.353 | 792.879 |424.718 |226.792 |191.700 |
|
||||
|
||||
639.837 bytes (197.530 gzip) is not much, but it feels faster.
|
||||
641.474 bytes (197.926 gzip) is not much, but it feels faster.
|
||||
|
||||
|
||||
|css/* |1.14.0 |native |
|
||||
|-------------- |--------: |--------: |
|
||||
|app.css | 340.334 | 266.739 |
|
||||
|app.min.css | 274.791 | 211.574 |
|
||||
|app.css | 340.334 | 266.793 |
|
||||
|app.min.css | 274.791 | 211.620 |
|
||||
|
||||
|
||||
### PHP73 branch
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
50
dev/External/ko.js
vendored
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>');
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -152,7 +152,7 @@ html.no-mobile {
|
|||
/*transform: scale(0.95);*/
|
||||
transform: translateY(-20px);
|
||||
|
||||
&.in {
|
||||
&.show {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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')));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> ' +
|
||||
'<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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
12
dev/bootstrap.js
vendored
|
@ -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
13
dev/prototype-element.js
vendored
Normal 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;
|
||||
};
|
||||
})();
|
|
@ -79,8 +79,9 @@ config.paths.js = {
|
|||
'vendors/jua/jua.min.js', // custom
|
||||
'vendors/keymaster/keymaster.js', // custom (modified)
|
||||
'vendors/qr.js/qr.min.js', // fixed (license)
|
||||
'vendors/bootstrap/js/bootstrap.min.js', // fixed
|
||||
'vendors/bootstrap/js/bootstrap.native.min.js', // fixed
|
||||
'dev/prototype-date.js',
|
||||
'dev/prototype-element.js',
|
||||
'dev/prototype-function.js',
|
||||
'node_modules/knockout/build/output/knockout-latest.js',
|
||||
'node_modules/knockout-sortable/build/knockout-sortable.min.js ',
|
||||
|
|
221
vendors/bootstrap/js/bootstrap.native.js
vendored
Normal file
221
vendors/bootstrap/js/bootstrap.native.js
vendored
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*!
|
||||
* Native JavaScript for Bootstrap v3.0.10 (https://thednp.github.io/bootstrap.native/)
|
||||
* Copyright 2015-2020 © dnp_theme
|
||||
* Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
window.BSN = (() => {
|
||||
'use strict';
|
||||
|
||||
const transitionEndEvent = 'transitionend',
|
||||
doc = document,
|
||||
body = doc.body;
|
||||
|
||||
function getElementTransitionDuration(element) {
|
||||
var duration = parseFloat(getComputedStyle(element).transitionDuration);
|
||||
duration = typeof duration === 'number' && !isNaN(duration) ? duration * 1000 : 0;
|
||||
return duration;
|
||||
}
|
||||
|
||||
function emulateTransitionEnd(element,handler){
|
||||
var called = 0, duration = getElementTransitionDuration(element);
|
||||
duration ? element.addEventListener( transitionEndEvent, function transitionEndWrapper(e){
|
||||
!called && handler(e), called = 1;
|
||||
element.removeEventListener( transitionEndEvent, transitionEndWrapper);
|
||||
})
|
||||
: setTimeout(() => { !called && handler(), called = 1; }, 17);
|
||||
}
|
||||
|
||||
function queryElement(selector, parent) {
|
||||
var lookUp = parent && parent instanceof Element ? parent : doc;
|
||||
return selector instanceof Element ? selector : lookUp.querySelector(selector);
|
||||
}
|
||||
|
||||
function setFocus (element){
|
||||
element.focus ? element.focus() : element.setActive();
|
||||
}
|
||||
|
||||
function Dropdown(element) {
|
||||
var self = this,
|
||||
parent, menu, menuItems = [];
|
||||
function preventEmptyAnchor(anchor) {
|
||||
(anchor.href && anchor.href.slice(-1) === '#' || anchor.parentNode && anchor.parentNode.href
|
||||
&& anchor.parentNode.href.slice(-1) === '#') && this.preventDefault();
|
||||
}
|
||||
function toggleDismiss() {
|
||||
var action = element.open ? 'addEventListener' : 'removeEventListener';
|
||||
doc[action]('click',dismissHandler,false);
|
||||
doc[action]('keydown',preventScroll,false);
|
||||
doc[action]('keyup',keyHandler,false);
|
||||
doc[action]('focus',dismissHandler,false);
|
||||
}
|
||||
function dismissHandler(e) {
|
||||
var eventTarget = e.target,
|
||||
hasData = eventTarget && (eventTarget.getAttribute('data-toggle')
|
||||
|| eventTarget.parentNode && eventTarget.parentNode.getAttribute
|
||||
&& eventTarget.parentNode.getAttribute('data-toggle'));
|
||||
if ( e.type === 'focus' && (eventTarget === element || eventTarget === menu || menu.contains(eventTarget) ) ) {
|
||||
return;
|
||||
}
|
||||
if ( hasData && (eventTarget === menu || menu.contains(eventTarget)) ) { return; }
|
||||
self.hide();
|
||||
preventEmptyAnchor.call(e,eventTarget);
|
||||
}
|
||||
function clickHandler(e) {
|
||||
self.show();
|
||||
preventEmptyAnchor.call(e,e.target);
|
||||
}
|
||||
function preventScroll(e) {
|
||||
var key = e.which || e.keyCode;
|
||||
if( key === 38 || key === 40 ) { e.preventDefault(); }
|
||||
}
|
||||
function keyHandler(e) {
|
||||
var key = e.which || e.keyCode,
|
||||
activeItem = doc.activeElement,
|
||||
isSameElement = activeItem === element,
|
||||
isInsideMenu = menu.contains(activeItem),
|
||||
isMenuItem = activeItem.parentNode === menu || activeItem.parentNode.parentNode === menu,
|
||||
idx = menuItems.indexOf(activeItem);
|
||||
if ( isMenuItem ) {
|
||||
idx = isSameElement ? 0
|
||||
: key === 38 ? (idx>1?idx-1:0)
|
||||
: key === 40 ? (idx<menuItems.length-1?idx+1:idx) : idx;
|
||||
menuItems[idx] && setFocus(menuItems[idx]);
|
||||
}
|
||||
if ( (menuItems.length && isMenuItem
|
||||
|| !menuItems.length && (isInsideMenu || isSameElement)
|
||||
|| !isInsideMenu )
|
||||
&& element.open && key === 27
|
||||
) {
|
||||
self.toggle();
|
||||
}
|
||||
}
|
||||
self.show = () => {
|
||||
menu.classList.add('show');
|
||||
parent.classList.add('show');
|
||||
element.setAttribute('aria-expanded',true);
|
||||
element.open = true;
|
||||
element.removeEventListener('click',clickHandler,false);
|
||||
setTimeout(() => {
|
||||
setFocus( menu.getElementsByTagName('INPUT')[0] || element );
|
||||
toggleDismiss();
|
||||
},1);
|
||||
};
|
||||
self.hide = () => {
|
||||
menu.classList.remove('show');
|
||||
parent.classList.remove('show');
|
||||
element.setAttribute('aria-expanded',false);
|
||||
element.open = false;
|
||||
toggleDismiss();
|
||||
setFocus(element);
|
||||
setTimeout(() => element.Dropdown && element.addEventListener('click',clickHandler,false), 1);
|
||||
};
|
||||
self.toggle = () => (parent.classList.contains('show') && element.open) ? self.hide() : self.show();
|
||||
parent = element.parentNode;
|
||||
menu = queryElement('.dropdown-menu', parent);
|
||||
Array.from(menu.children).forEach(child => {
|
||||
child.children.length && (child.children[0].tagName === 'A' && menuItems.push(child.children[0]));
|
||||
child.tagName === 'A' && menuItems.push(child);
|
||||
});
|
||||
if ( !element.Dropdown ) {
|
||||
!('tabindex' in menu) && menu.setAttribute('tabindex', '0');
|
||||
element.addEventListener('click',clickHandler,false);
|
||||
}
|
||||
element.open = false;
|
||||
element.Dropdown = self;
|
||||
}
|
||||
|
||||
function Modal(modal) {
|
||||
var scrollBarWidth;
|
||||
function setScrollbar() {
|
||||
var openModal = body.classList.contains('modal-open'),
|
||||
bodyPad = parseInt(getComputedStyle(body).paddingRight),
|
||||
bodyOverflow = doc.documentElement.clientHeight !== doc.documentElement.scrollHeight
|
||||
|| body.clientHeight !== body.scrollHeight,
|
||||
modalOverflow = modal.clientHeight !== modal.scrollHeight;
|
||||
scrollBarWidth = measureScrollbar();
|
||||
modal.style.paddingRight = !modalOverflow && scrollBarWidth ? scrollBarWidth + "px" : '';
|
||||
body.style.paddingRight = modalOverflow || bodyOverflow
|
||||
? (bodyPad + (openModal ? 0:scrollBarWidth)) + "px"
|
||||
: '';
|
||||
}
|
||||
function resetScrollbar() {
|
||||
body.style.paddingRight = '';
|
||||
modal.style.paddingRight = '';
|
||||
}
|
||||
function measureScrollbar() {
|
||||
var scrollDiv = doc.createElement('div'), widthValue;
|
||||
scrollDiv.className = 'modal-scrollbar-measure';
|
||||
body.appendChild(scrollDiv);
|
||||
widthValue = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
||||
body.removeChild(scrollDiv);
|
||||
return widthValue;
|
||||
}
|
||||
function toggleEvents(action) {
|
||||
action = action ? 'addEventListener' : 'removeEventListener';
|
||||
window[action]( 'resize', () => modal.classList.contains('show') && setScrollbar(), { passive: true });
|
||||
}
|
||||
function beforeShow() {
|
||||
modal.style.display = 'block';
|
||||
setScrollbar();
|
||||
!doc.getElementsByClassName('modal show')[0] && body.classList.add('modal-open');
|
||||
modal.classList.add('show');
|
||||
modal.setAttribute('aria-hidden', false);
|
||||
modal.classList.contains('fade') ? emulateTransitionEnd(modal, triggerShow) : triggerShow();
|
||||
}
|
||||
function triggerShow() {
|
||||
setFocus(modal);
|
||||
modal.isAnimating = false;
|
||||
toggleEvents(1);
|
||||
}
|
||||
function triggerHide() {
|
||||
modal.style.display = '';
|
||||
body.classList.remove('modal-open');
|
||||
resetScrollbar();
|
||||
toggleEvents();
|
||||
modal.isAnimating = false;
|
||||
}
|
||||
this.show = () => {
|
||||
if (!modal.classList.contains('show') || !modal.isAnimating) {
|
||||
modal.isAnimating = true;
|
||||
doc.getElementsByClassName('modal show')[0] ? beforeShow() : setTimeout( beforeShow, 0 );
|
||||
}
|
||||
};
|
||||
this.hide = () => {
|
||||
if (modal.classList.contains('show') ) {
|
||||
modal.isAnimating = true;
|
||||
modal.classList.remove('show');
|
||||
modal.setAttribute('aria-hidden', true);
|
||||
modal.classList.contains('fade') ? emulateTransitionEnd(modal, triggerHide) : triggerHide();
|
||||
}
|
||||
};
|
||||
modal.isAnimating = false;
|
||||
modal.Modal = this;
|
||||
}
|
||||
|
||||
class Tab {
|
||||
constructor(element) {
|
||||
this.element = element
|
||||
element.Tab = this;
|
||||
element.addEventListener('click', e => {e.preventDefault();this.show();});
|
||||
}
|
||||
|
||||
show() {
|
||||
const el = this.element, li = el.closest('li');
|
||||
if (!li.classList.contains('active')) {
|
||||
const previous = el.closest('ul').querySelector('.active a');
|
||||
previous.closest('li').classList.remove('active');
|
||||
queryElement(previous.getAttribute('href')).classList.remove('active');
|
||||
li.classList.add('active');
|
||||
queryElement(el.getAttribute('href')).classList.add('active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
Dropdown: Dropdown,
|
||||
Modal: Modal,
|
||||
Tab: Tab
|
||||
};
|
||||
|
||||
})();
|
7
vendors/bootstrap/js/bootstrap.native.min.js
vendored
Normal file
7
vendors/bootstrap/js/bootstrap.native.min.js
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*!
|
||||
* Native JavaScript for Bootstrap v3.0.10 (https://thednp.github.io/bootstrap.native/)
|
||||
* Copyright 2015-2020 © dnp_theme
|
||||
* Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
window.BSN=(()=>{"use strict";const e="transitionend",t=document,n=t.body;function s(t,n){var s=0;(function(e){var t=parseFloat(getComputedStyle(e).transitionDuration);return t="number"!=typeof t||isNaN(t)?0:1e3*t})(t)?t.addEventListener(e,function i(a){!s&&n(a),s=1,t.removeEventListener(e,i)}):setTimeout(()=>{!s&&n(),s=1},17)}function i(e,n){var s=n&&n instanceof Element?n:t;return e instanceof Element?e:s.querySelector(e)}function a(e){e.focus?e.focus():e.setActive()}return{Dropdown:function(e){var n,s,o=this,c=[];function r(e){(e.href&&"#"===e.href.slice(-1)||e.parentNode&&e.parentNode.href&&"#"===e.parentNode.href.slice(-1))&&this.preventDefault()}function l(){var n=e.open?"addEventListener":"removeEventListener";t[n]("click",d,!1),t[n]("keydown",u,!1),t[n]("keyup",m,!1),t[n]("focus",d,!1)}function d(t){var n=t.target,i=n&&(n.getAttribute("data-toggle")||n.parentNode&&n.parentNode.getAttribute&&n.parentNode.getAttribute("data-toggle"));("focus"!==t.type||n!==e&&n!==s&&!s.contains(n))&&(i&&(n===s||s.contains(n))||(o.hide(),r.call(t,n)))}function h(e){o.show(),r.call(e,e.target)}function u(e){var t=e.which||e.keyCode;38!==t&&40!==t||e.preventDefault()}function m(n){var i=n.which||n.keyCode,r=t.activeElement,l=r===e,d=s.contains(r),h=r.parentNode===s||r.parentNode.parentNode===s,u=c.indexOf(r);h&&(u=l?0:38===i?u>1?u-1:0:40===i&&u<c.length-1?u+1:u,c[u]&&a(c[u])),(c.length&&h||!c.length&&(d||l)||!d)&&e.open&&27===i&&o.toggle()}o.show=(()=>{s.classList.add("show"),n.classList.add("show"),e.setAttribute("aria-expanded",!0),e.open=!0,e.removeEventListener("click",h,!1),setTimeout(()=>{a(s.getElementsByTagName("INPUT")[0]||e),l()},1)}),o.hide=(()=>{s.classList.remove("show"),n.classList.remove("show"),e.setAttribute("aria-expanded",!1),e.open=!1,l(),a(e),setTimeout(()=>e.Dropdown&&e.addEventListener("click",h,!1),1)}),o.toggle=(()=>n.classList.contains("show")&&e.open?o.hide():o.show()),n=e.parentNode,s=i(".dropdown-menu",n),Array.from(s.children).forEach(e=>{e.children.length&&"A"===e.children[0].tagName&&c.push(e.children[0]),"A"===e.tagName&&c.push(e)}),e.Dropdown||(!("tabindex"in s)&&s.setAttribute("tabindex","0"),e.addEventListener("click",h,!1)),e.open=!1,e.Dropdown=o},Modal:function(e){var i;function o(){var s,a,o=n.classList.contains("modal-open"),c=parseInt(getComputedStyle(n).paddingRight),r=t.documentElement.clientHeight!==t.documentElement.scrollHeight||n.clientHeight!==n.scrollHeight,l=e.clientHeight!==e.scrollHeight;(a=t.createElement("div")).className="modal-scrollbar-measure",n.appendChild(a),s=a.offsetWidth-a.clientWidth,n.removeChild(a),i=s,e.style.paddingRight=!l&&i?i+"px":"",n.style.paddingRight=l||r?c+(o?0:i)+"px":""}function c(t){t=t?"addEventListener":"removeEventListener",window[t]("resize",()=>e.classList.contains("show")&&o(),{passive:!0})}function r(){e.style.display="block",o(),!t.getElementsByClassName("modal show")[0]&&n.classList.add("modal-open"),e.classList.add("show"),e.setAttribute("aria-hidden",!1),e.classList.contains("fade")?s(e,l):l()}function l(){a(e),e.isAnimating=!1,c(1)}function d(){e.style.display="",n.classList.remove("modal-open"),n.style.paddingRight="",e.style.paddingRight="",c(),e.isAnimating=!1}this.show=(()=>{e.classList.contains("show")&&e.isAnimating||(e.isAnimating=!0,t.getElementsByClassName("modal show")[0]?r():setTimeout(r,0))}),this.hide=(()=>{e.classList.contains("show")&&(e.isAnimating=!0,e.classList.remove("show"),e.setAttribute("aria-hidden",!0),e.classList.contains("fade")?s(e,d):d())}),e.isAnimating=!1,e.Modal=this},Tab:class{constructor(e){this.element=e,e.Tab=this,e.addEventListener("click",e=>{e.preventDefault(),this.show()})}show(){const e=this.element,t=e.closest("li");if(!t.classList.contains("active")){const n=e.closest("ul").querySelector(".active a");n.closest("li").classList.remove("active"),i(n.getAttribute("href")).classList.remove("active"),t.classList.add("active"),i(e.getAttribute("href")).classList.add("active")}}}}})();
|
|
@ -6,7 +6,7 @@
|
|||
.fade {
|
||||
opacity: 0;
|
||||
.transition(opacity .15s linear);
|
||||
&.in {
|
||||
&.show {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
|
4
vendors/bootstrap/less/modals.less
vendored
4
vendors/bootstrap/less/modals.less
vendored
|
@ -25,7 +25,7 @@
|
|||
}
|
||||
|
||||
.modal-backdrop,
|
||||
.modal-backdrop.fade.in {
|
||||
.modal-backdrop.fade.show {
|
||||
.opacity(80);
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
.transition(e('opacity .3s linear, top .3s ease-out'));
|
||||
top: -25%;
|
||||
}
|
||||
&.fade.in { top: 50%; }
|
||||
&.fade.show { top: 50%; }
|
||||
}
|
||||
.modal-header {
|
||||
padding: 9px 15px;
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
right: 20px;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
&.fade.in { top: auto; }
|
||||
&.fade.show { top: auto; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue