mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-01-05 22:42:25 +08:00
17669b7be0
Signature plugin fixes Add view decorator A large number of fixes
518 lines
11 KiB
JavaScript
518 lines
11 KiB
JavaScript
|
|
import _ from '_';
|
|
import $ from '$';
|
|
import ko from 'ko';
|
|
import hasher from 'hasher';
|
|
import crossroads from 'crossroads';
|
|
|
|
import {runHook} from 'Common/Plugins';
|
|
import {$html, aViewModels as VIEW_MODELS, popupVisibilityNames} from 'Common/Globals';
|
|
|
|
import {
|
|
isArray, isUnd, pString, log,
|
|
createCommand, delegateRun, isNonEmptyArray
|
|
} from 'Common/Utils';
|
|
|
|
let
|
|
currentScreen = null,
|
|
defaultScreenName = '';
|
|
|
|
const SCREENS = {};
|
|
|
|
export const ViewType = {
|
|
Popup: 'Popups',
|
|
Left: 'Left',
|
|
Right: 'Right',
|
|
Center: 'Center'
|
|
};
|
|
|
|
/**
|
|
* @returns {void}
|
|
*/
|
|
export function hideLoading()
|
|
{
|
|
$('#rl-content').addClass('rl-content-show');
|
|
$('#rl-loading').hide().remove();
|
|
}
|
|
|
|
/**
|
|
* @param {Function} SettingsViewModelClass
|
|
* @param {string} template
|
|
* @param {string} labelName
|
|
* @param {string} route
|
|
* @param {boolean=} isDefault = false
|
|
* @returns {void}
|
|
*/
|
|
export function addSettingsViewModel(SettingsViewModelClass, template, labelName, route, isDefault = false)
|
|
{
|
|
SettingsViewModelClass.__rlSettingsData = {
|
|
Label: labelName,
|
|
Template: template,
|
|
Route: route,
|
|
IsDefault: !!isDefault
|
|
};
|
|
|
|
VIEW_MODELS.settings.push(SettingsViewModelClass);
|
|
}
|
|
|
|
/**
|
|
* @param {Function} SettingsViewModelClass
|
|
* @returns {void}
|
|
*/
|
|
export function removeSettingsViewModel(SettingsViewModelClass)
|
|
{
|
|
VIEW_MODELS['settings-removed'].push(SettingsViewModelClass);
|
|
}
|
|
|
|
/**
|
|
* @param {Function} SettingsViewModelClass
|
|
* @returns {void}
|
|
*/
|
|
export function disableSettingsViewModel(SettingsViewModelClass)
|
|
{
|
|
VIEW_MODELS['settings-disabled'].push(SettingsViewModelClass);
|
|
}
|
|
|
|
/**
|
|
* @returns {void}
|
|
*/
|
|
export function routeOff()
|
|
{
|
|
hasher.changed.active = false;
|
|
}
|
|
|
|
/**
|
|
* @returns {void}
|
|
*/
|
|
export function routeOn()
|
|
{
|
|
hasher.changed.active = true;
|
|
}
|
|
|
|
/**
|
|
* @param {string} screenName
|
|
* @returns {?Object}
|
|
*/
|
|
export function screen(screenName)
|
|
{
|
|
return ('' !== screenName && !isUnd(SCREENS[screenName])) ? SCREENS[screenName] : null;
|
|
}
|
|
|
|
/**
|
|
* @param {Function} ViewModelClassToHide
|
|
* @returns {void}
|
|
*/
|
|
export function hideScreenPopup(ViewModelClassToHide)
|
|
{
|
|
if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom)
|
|
{
|
|
ViewModelClassToHide.__vm.modalVisibility(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} hookName
|
|
* @param {Function} ViewModelClass
|
|
* @param {mixed=} params = null
|
|
*/
|
|
export function vmRunHook(hookName, ViewModelClass, params = null)
|
|
{
|
|
_.each(ViewModelClass.__names, (name) => {
|
|
runHook(hookName, [name, ViewModelClass.__vm, params]);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {Function} ViewModelClass
|
|
* @param {Object=} vmScreen
|
|
* @returns {*}
|
|
*/
|
|
export function buildViewModel(ViewModelClass, vmScreen)
|
|
{
|
|
if (ViewModelClass && !ViewModelClass.__builded)
|
|
{
|
|
let vmDom = null;
|
|
const
|
|
vm = new ViewModelClass(vmScreen),
|
|
position = ViewModelClass.__type || '',
|
|
vmPlace = position ? $('#rl-content #rl-' + position.toLowerCase()) : null;
|
|
|
|
ViewModelClass.__builded = true;
|
|
ViewModelClass.__vm = vm;
|
|
|
|
vm.onShowTrigger = ko.observable(false);
|
|
vm.onHideTrigger = ko.observable(false);
|
|
|
|
vm.viewModelName = ViewModelClass.__name;
|
|
vm.viewModelNames = ViewModelClass.__names;
|
|
vm.viewModelTemplateID = ViewModelClass.__templateID;
|
|
vm.viewModelPosition = ViewModelClass.__type;
|
|
|
|
if (vmPlace && 1 === vmPlace.length)
|
|
{
|
|
vmDom = $('<div></div>').addClass('rl-view-model').addClass('RL-' + vm.viewModelTemplateID).hide();
|
|
vmDom.appendTo(vmPlace);
|
|
|
|
vm.viewModelDom = vmDom;
|
|
ViewModelClass.__dom = vmDom;
|
|
|
|
if (ViewType.Popup === position)
|
|
{
|
|
vm.cancelCommand = vm.closeCommand = createCommand(() => {
|
|
hideScreenPopup(ViewModelClass);
|
|
});
|
|
|
|
vm.modalVisibility.subscribe((value) => {
|
|
if (value)
|
|
{
|
|
vm.viewModelDom.show();
|
|
vm.storeAndSetKeyScope();
|
|
|
|
popupVisibilityNames.push(vm.viewModelName);
|
|
vm.viewModelDom.css('z-index', 3000 + popupVisibilityNames().length + 10);
|
|
|
|
if (vm.onShowTrigger)
|
|
{
|
|
vm.onShowTrigger(!vm.onShowTrigger());
|
|
}
|
|
|
|
delegateRun(vm, 'onShowWithDelay', [], 500);
|
|
}
|
|
else
|
|
{
|
|
delegateRun(vm, 'onHide');
|
|
delegateRun(vm, 'onHideWithDelay', [], 500);
|
|
|
|
if (vm.onHideTrigger)
|
|
{
|
|
vm.onHideTrigger(!vm.onHideTrigger());
|
|
}
|
|
|
|
vm.restoreKeyScope();
|
|
|
|
vmRunHook('view-model-on-hide', ViewModelClass);
|
|
|
|
popupVisibilityNames.remove(vm.viewModelName);
|
|
vm.viewModelDom.css('z-index', 2000);
|
|
|
|
_.delay(() => vm.viewModelDom.hide(), 300);
|
|
}
|
|
});
|
|
}
|
|
|
|
vmRunHook('view-model-pre-build', ViewModelClass, vmDom);
|
|
|
|
ko.applyBindingAccessorsToNode(vmDom[0], {
|
|
translatorInit: true,
|
|
template: () => ({name: vm.viewModelTemplateID})
|
|
}, vm);
|
|
|
|
delegateRun(vm, 'onBuild', [vmDom]);
|
|
if (vm && ViewType.Popup === position)
|
|
{
|
|
vm.registerPopupKeyDown();
|
|
}
|
|
|
|
vmRunHook('view-model-post-build', ViewModelClass, vmDom);
|
|
}
|
|
else
|
|
{
|
|
log('Cannot find view model position: ' + position);
|
|
}
|
|
}
|
|
|
|
return ViewModelClass ? ViewModelClass.__vm : null;
|
|
}
|
|
|
|
/**
|
|
* @param {Function} ViewModelClassToShow
|
|
* @param {Array=} params
|
|
* @returns {void}
|
|
*/
|
|
export function showScreenPopup(ViewModelClassToShow, params = [])
|
|
{
|
|
if (ViewModelClassToShow)
|
|
{
|
|
buildViewModel(ViewModelClassToShow);
|
|
|
|
if (ViewModelClassToShow.__vm && ViewModelClassToShow.__dom)
|
|
{
|
|
delegateRun(ViewModelClassToShow.__vm, 'onBeforeShow', params || []);
|
|
|
|
ViewModelClassToShow.__vm.modalVisibility(true);
|
|
|
|
delegateRun(ViewModelClassToShow.__vm, 'onShow', params || []);
|
|
|
|
vmRunHook('view-model-on-show', ViewModelClassToShow, params || []);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Function} ViewModelClassToShow
|
|
* @returns {void}
|
|
*/
|
|
export function warmUpScreenPopup(ViewModelClassToShow)
|
|
{
|
|
if (ViewModelClassToShow)
|
|
{
|
|
buildViewModel(ViewModelClassToShow);
|
|
|
|
if (ViewModelClassToShow.__vm && ViewModelClassToShow.__dom)
|
|
{
|
|
delegateRun(ViewModelClassToShow.__vm, 'onWarmUp');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Function} ViewModelClassToShow
|
|
* @returns {boolean}
|
|
*/
|
|
export function isPopupVisible(ViewModelClassToShow)
|
|
{
|
|
return ViewModelClassToShow && ViewModelClassToShow.__vm ? ViewModelClassToShow.__vm.modalVisibility() : false;
|
|
}
|
|
|
|
/**
|
|
* @param {string} screenName
|
|
* @param {string} subPart
|
|
* @returns {void}
|
|
*/
|
|
export function screenOnRoute(screenName, subPart)
|
|
{
|
|
let
|
|
vmScreen = null,
|
|
isSameScreen = false,
|
|
cross = null;
|
|
|
|
if ('' === pString(screenName))
|
|
{
|
|
screenName = defaultScreenName;
|
|
}
|
|
|
|
if ('' !== screenName)
|
|
{
|
|
vmScreen = screen(screenName);
|
|
if (!vmScreen)
|
|
{
|
|
vmScreen = screen(defaultScreenName);
|
|
if (vmScreen)
|
|
{
|
|
subPart = screenName + '/' + subPart;
|
|
screenName = defaultScreenName;
|
|
}
|
|
}
|
|
|
|
if (vmScreen && vmScreen.__started)
|
|
{
|
|
isSameScreen = currentScreen && vmScreen === currentScreen;
|
|
|
|
if (!vmScreen.__builded)
|
|
{
|
|
vmScreen.__builded = true;
|
|
|
|
if (isNonEmptyArray(vmScreen.viewModels()))
|
|
{
|
|
_.each(vmScreen.viewModels(), (ViewModelClass) => {
|
|
buildViewModel(ViewModelClass, vmScreen);
|
|
});
|
|
}
|
|
|
|
delegateRun(vmScreen, 'onBuild');
|
|
}
|
|
|
|
_.defer(() => {
|
|
// hide screen
|
|
if (currentScreen && !isSameScreen)
|
|
{
|
|
delegateRun(currentScreen, 'onHide');
|
|
delegateRun(currentScreen, 'onHideWithDelay', [], 500);
|
|
|
|
if (currentScreen.onHideTrigger)
|
|
{
|
|
currentScreen.onHideTrigger(!currentScreen.onHideTrigger());
|
|
}
|
|
|
|
if (isNonEmptyArray(currentScreen.viewModels()))
|
|
{
|
|
_.each(currentScreen.viewModels(), (ViewModelClass) => {
|
|
if (ViewModelClass.__vm && ViewModelClass.__dom && ViewType.Popup !== ViewModelClass.__vm.viewModelPosition)
|
|
{
|
|
ViewModelClass.__dom.hide();
|
|
ViewModelClass.__vm.viewModelVisibility(false);
|
|
|
|
delegateRun(ViewModelClass.__vm, 'onHide');
|
|
delegateRun(ViewModelClass.__vm, 'onHideWithDelay', [], 500);
|
|
|
|
if (ViewModelClass.__vm.onHideTrigger)
|
|
{
|
|
ViewModelClass.__vm.onHideTrigger(!ViewModelClass.__vm.onHideTrigger());
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
// --
|
|
|
|
currentScreen = vmScreen;
|
|
|
|
// show screen
|
|
if (currentScreen && !isSameScreen)
|
|
{
|
|
delegateRun(currentScreen, 'onShow');
|
|
if (currentScreen.onShowTrigger)
|
|
{
|
|
currentScreen.onShowTrigger(!currentScreen.onShowTrigger());
|
|
}
|
|
|
|
runHook('screen-on-show', [currentScreen.screenName(), currentScreen]);
|
|
|
|
if (isNonEmptyArray(currentScreen.viewModels()))
|
|
{
|
|
_.each(currentScreen.viewModels(), (ViewModelClass) => {
|
|
|
|
if (ViewModelClass.__vm && ViewModelClass.__dom && ViewType.Popup !== ViewModelClass.__vm.viewModelPosition)
|
|
{
|
|
delegateRun(ViewModelClass.__vm, 'onBeforeShow');
|
|
|
|
ViewModelClass.__dom.show();
|
|
ViewModelClass.__vm.viewModelVisibility(true);
|
|
|
|
delegateRun(ViewModelClass.__vm, 'onShow');
|
|
if (ViewModelClass.__vm.onShowTrigger)
|
|
{
|
|
ViewModelClass.__vm.onShowTrigger(!ViewModelClass.__vm.onShowTrigger());
|
|
}
|
|
|
|
delegateRun(ViewModelClass.__vm, 'onShowWithDelay', [], 200);
|
|
vmRunHook('view-model-on-show', ViewModelClass);
|
|
}
|
|
|
|
});
|
|
}
|
|
}
|
|
// --
|
|
|
|
cross = vmScreen.__cross ? vmScreen.__cross() : null;
|
|
if (cross)
|
|
{
|
|
cross.parse(subPart);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Array} screensClasses
|
|
* @returns {void}
|
|
*/
|
|
export function startScreens(screensClasses)
|
|
{
|
|
_.each(screensClasses, (CScreen) => {
|
|
if (CScreen)
|
|
{
|
|
const
|
|
vmScreen = new CScreen(),
|
|
screenName = vmScreen ? vmScreen.screenName() : '';
|
|
|
|
if (vmScreen && '' !== screenName)
|
|
{
|
|
if ('' === defaultScreenName)
|
|
{
|
|
defaultScreenName = screenName;
|
|
}
|
|
|
|
SCREENS[screenName] = vmScreen;
|
|
}
|
|
}
|
|
});
|
|
|
|
_.each(SCREENS, (vmScreen) => {
|
|
if (vmScreen && !vmScreen.__started && vmScreen.__start)
|
|
{
|
|
vmScreen.__started = true;
|
|
vmScreen.__start();
|
|
|
|
runHook('screen-pre-start', [vmScreen.screenName(), vmScreen]);
|
|
delegateRun(vmScreen, 'onStart');
|
|
runHook('screen-post-start', [vmScreen.screenName(), vmScreen]);
|
|
}
|
|
});
|
|
|
|
const cross = crossroads.create();
|
|
cross.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/, screenOnRoute);
|
|
|
|
hasher.initialized.add(cross.parse, cross);
|
|
hasher.changed.add(cross.parse, cross);
|
|
hasher.init();
|
|
|
|
_.delay(() => $html.removeClass('rl-started-trigger').addClass('rl-started'), 100);
|
|
_.delay(() => $html.addClass('rl-started-delay'), 200);
|
|
}
|
|
|
|
/**
|
|
* @param {string} sHash
|
|
* @param {boolean=} silence = false
|
|
* @param {boolean=} replace = false
|
|
* @returns {void}
|
|
*/
|
|
export function setHash(hash, silence = false, replace = false)
|
|
{
|
|
hash = '#' === hash.substr(0, 1) ? hash.substr(1) : hash;
|
|
hash = '/' === hash.substr(0, 1) ? hash.substr(1) : hash;
|
|
|
|
const cmd = replace ? 'replaceHash' : 'setHash';
|
|
|
|
if (silence)
|
|
{
|
|
hasher.changed.active = false;
|
|
hasher[cmd](hash);
|
|
hasher.changed.active = true;
|
|
}
|
|
else
|
|
{
|
|
hasher.changed.active = true;
|
|
hasher[cmd](hash);
|
|
hasher.setHash(hash);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Object} params
|
|
* @returns {void}
|
|
*/
|
|
function viewDecorator({name, type, templateID})
|
|
{
|
|
return (target) => {
|
|
if (target)
|
|
{
|
|
if (name)
|
|
{
|
|
if (isArray(name))
|
|
{
|
|
target.__names = name;
|
|
}
|
|
else
|
|
{
|
|
target.__names = [name];
|
|
}
|
|
|
|
target.__name = target.__names[0];
|
|
}
|
|
|
|
if (type)
|
|
{
|
|
target.__type = type;
|
|
}
|
|
|
|
if (templateID)
|
|
{
|
|
target.__templateID = templateID;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
export {viewDecorator, viewDecorator as view, viewDecorator as viewModel};
|