infusion
Version:
Infusion is an application framework for developing flexible stuff with JavaScript
333 lines (316 loc) • 14.4 kB
JavaScript
/*
Copyright The Infusion copyright holders
See the AUTHORS.md file at the top-level directory of this distribution and at
https://github.com/fluid-project/infusion/raw/main/AUTHORS.md.
Licensed under the Educational Community License (ECL), Version 2.0 or the New
BSD license. You may not use this file except in compliance with one these
Licenses.
You may obtain a copy of the ECL 2.0 License and BSD License at
https://github.com/fluid-project/infusion/raw/main/Infusion-LICENSE.txt
*/
"use strict";
fluid.registerNamespace("fluid.dom");
fluid.dom.getDocumentHeight = function (dokkument) {
var body = $("body", dokkument)[0];
return body.offsetHeight;
};
/*******************************************************
* Separated Panel Preferences Editor Top Level Driver *
*******************************************************/
fluid.defaults("fluid.prefs.separatedPanel", {
gradeNames: ["fluid.prefs.prefsEditorLoader", "fluid.contextAware"],
events: {
onReady: null,
onCreateSlidingPanelReady: {
events: {
onPrefsEditorMessagesLoaded: "onPrefsEditorMessagesLoaded"
}
},
templatesAndMessagesReady: {
events: {
templatesLoaded: "onPrefsEditorTemplatesLoaded",
messagesLoaded: "onPrefsEditorMessagesLoaded"
}
}
},
lazyLoad: false,
contextAwareness: {
lazyLoad: {
checks: {
lazyLoad: {
contextValue: "{fluid.prefs.separatedPanel}.options.lazyLoad",
gradeNames: "fluid.prefs.separatedPanel.lazyLoad"
}
}
}
},
selectors: {
reset: ".flc-prefsEditor-reset",
prefsEditor: ".flc-slidingPanel-panel",
containerMarker: ".flc-prefsEditor-main"
},
styles: {
blockingClasses: ["fl-blocking-theme", "fl-blocking-font", "fl-blocking-input-enhanced"]
},
listeners: {
"onReady.bindEvents": {
listener: "fluid.prefs.separatedPanel.bindEvents",
args: ["{separatedPanel}.prefsEditor", "{separatedPanel}.innerEnhancer", "{separatedPanel}"]
},
"onCreate.hideReset": {
listener: "fluid.prefs.separatedPanel.hideReset",
args: ["{separatedPanel}"]
},
"onCreate.applyInitialClasses": {
listener: "fluid.prefs.separatedPanel.applyInitialClasses",
args: ["{separatedPanel}"]
}
},
components: {
slidingPanel: {
type: "fluid.slidingPanel",
container: "{separatedPanel}.container",
createOnEvent: "onCreateSlidingPanelReady",
options: {
gradeNames: ["fluid.prefs.msgLookup"],
strings: {
showText: "{that}.msgLookup.slidingPanelShowText",
hideText: "{that}.msgLookup.slidingPanelHideText",
showTextAriaLabel: "{that}.msgLookup.showTextAriaLabel",
hideTextAriaLabel: "{that}.msgLookup.hideTextAriaLabel",
panelLabel: "{that}.msgLookup.slidingPanelPanelLabel"
},
components: {
msgResolver: {
type: "fluid.messageResolver",
options: {
messageBase: "{messageLoader}.resources.prefsEditor.parsed"
}
}
}
}
},
// innerEnhancer handles preferences applied to the UIO container
innerEnhancer: {
type: "fluid.uiEnhancer",
container: "{separatedPanel}.dom.prefsEditor",
options: {
gradeNames: ["{pageEnhancer}.uiEnhancer.options.userGrades"],
tocTemplate: "{pageEnhancer}.uiEnhancer.options.tocTemplate",
distributeOptions: {
applyInitValue: {
record: true,
target: "{that enactor}.options.applyInitValue"
},
syllabifyHiddenContents: {
record: true,
target: "{that fluid.prefs.enactor.syllabification > parser}.options.parseHidden"
},
// Disable TOC and self voicing enactors from the innerEnhancer
removeTocEnactor: {
record: "fluid.emptySubcomponent",
target: "{that fluid.prefs.enactor.tableOfContents}.type"
},
removeOrator: {
record: "fluid.emptySubcomponent",
target: "{that fluid.orator}.type"
},
removeSelfVoicingEnactor: {
record: "fluid.emptySubcomponent",
target: "{that fluid.prefs.enactor.selfVoicing}.type"
}
}
}
},
prefsEditor: {
createOnEvent: "templatesAndMessagesReady",
container: "{separatedPanel}.dom.prefsEditor",
options: {
gradeNames: ["fluid.prefs.uiEnhancerRelay", "fluid.prefs.arrowScrolling"],
// ensure that model and applier are available to users at top level
model: {
preferences: "{separatedPanel}.model.preferences"
// The `local` model path is used by the `fluid.remoteModelComponent` grade
// for persisting and synchronizing model values with remotely stored data.
// local: {}
},
autoSave: true,
events: {
updateEnhancerModel: "{that}.events.modelChanged"
},
listeners: {
"onCreate.bindReset": {
"this": "{separatedPanel}.dom.reset",
method: "on",
args: ["click", "{that}.reset"]
},
// Refresh the prefs editor with initial preferences
"{separatedPanel}.events.onReady": "{that}.events.onPrefsEditorRefresh.fire",
"afterReset.applyChanges": "{that}.applyChanges"
}
}
}
},
outerEnhancerOptions: "{originalEnhancerOptions}.options.originalUserOptions",
distributeOptions: {
"separatedPanel.slidingPanel": {
source: "{that}.options.slidingPanel",
removeSource: true,
target: "{that > slidingPanel}.options"
},
"separatedPanel.innerEnhancer.outerEnhancerOptions": {
source: "{that}.options.outerEnhancerOptions",
removeSource: true,
target: "{that > innerEnhancer}.options"
},
"separatedPanel.ignoreSelectorForToc": {
source: "{that}.options.selectors.containerMarker",
target: "{fluid.prefs.builder > enhancer fluid.prefs.enactor.tableOfContents}.options.ignoreSelectorForEnactor.forEnactor"
},
"separatedPanel.ignoreSelectorForSelfVoicing": {
source: "{that}.options.selectors.containerMarker",
target: "{fluid.prefs.builder > enhancer fluid.prefs.enactor.selfVoicing}.options.ignoreSelectorForEnactor.forEnactor"
},
"separatedPanel.ignoreSelectorForSyllabification": {
source: "{that}.options.selectors.prefsEditor",
target: "{fluid.prefs.builder > enhancer fluid.prefs.enactor.syllabification}.options.ignoreSelectorForEnactor.forEnactor"
}
}
});
fluid.prefs.separatedPanel.hideReset = function (separatedPanel) {
separatedPanel.locate("reset").hide();
};
fluid.prefs.separatedPanel.applyInitialClasses = function (separatedPanel) {
separatedPanel.container[0].classList.add(separatedPanel.options.selectors.containerMarker.substring(1));
separatedPanel.locate("prefsEditor")[0].classList.add(...separatedPanel.options.styles.blockingClasses);
};
fluid.prefs.separatedPanel.bindEvents = function (prefsEditor, innerEnhancer, separatedPanel) {
// FLUID-5740: This binding should be done declaratively - needs ginger world in order to bind onto slidingPanel
// which is a child of this component
var separatedPanelId = separatedPanel.slidingPanel.panelId;
separatedPanel.locate("reset").attr({
"aria-controls": separatedPanelId,
"role": "button"
});
separatedPanel.slidingPanel.events.afterPanelHide.addListener(function () {
prefsEditor.events.onPrefsEditorRefresh.fire();
}, "updateView");
prefsEditor.events.afterReset.addListener(function (prefsEditor) {
prefsEditor.events.onPrefsEditorRefresh.fire();
}, "updateView");
prefsEditor.events.onPrefsEditorRefresh.addListener(function () {
innerEnhancer.updateModel(prefsEditor.model.preferences);
}, "updateModel");
separatedPanel.slidingPanel.events.afterPanelShow.addListener(function () {
separatedPanel.prefsEditor.container.slideDown(separatedPanel.slidingPanel.options.animationDurations.show);
separatedPanel.locate("reset").show();
}, "openPanel");
separatedPanel.slidingPanel.events.onPanelHide.addListener(function () {
separatedPanel.locate("reset").hide();
}, "hideReset");
};
/**
* FLUID-5926: Some of our users have asked for ways to improve the initial page load
* performance when using the separated panel prefs editor / UI Options. One option,
* provided here, is to implement a scheme for lazy loading the instantiation of the
* prefs editor, only instantiating enough of the workflow to allow display the
* sliding panel tab.
*
* fluid.prefs.separatedPanel.lazyLoad modifies the typical separatedPanel workflow
* by delaying the instantiation and loading of resources for the prefs editor until
* the first time it is opened.
*
* Lazy Load Workflow:
*
* - On instantiation of the prefsEditorLoader only the messageLoader and slidingPanel are instantiated
* - On instantiation, the messageLoader only loads preLoadResources, these are the messages required by
* the slidingPanel. The remaining message bundles will not be loaded until the "onLazyLoad" event is fired.
* - After the preLoadResources have been loaded, the onPrefsEditorMessagesPreloaded event is fired, and triggers the
* sliding panel to instantiate.
* - When a user opens the separated panel prefs editor / UI Options, it checks to see if the prefs editor has been
* instantiated. If it hasn't, a listener is temporarily bound to the onReady event, which gets fired
* after the prefs editor is ready. This is used to continue the process of opening the sliding panel for the first time.
* Additionally the onLazyLoad event is fired, which kicks off the remainder of the instantiation process.
* - onLazyLoad triggers the templateLoader to fetch all of the templates and the messageLoader to fetch the remaining
* message bundles. From here the standard instantiation workflow takes place.
*/
fluid.defaults("fluid.prefs.separatedPanel.lazyLoad", {
events: {
onLazyLoad: null,
onPrefsEditorMessagesPreloaded: null,
onCreateSlidingPanelReady: {
events: {
onPrefsEditorMessagesLoaded: "onPrefsEditorMessagesPreloaded"
}
},
templatesAndMessagesReady: {
events: {
onLazyLoad: "onLazyLoad"
}
}
},
components: {
templateLoader: {
createOnEvent: "onLazyLoad"
},
messageLoader: {
options: {
events: {
onResourcesPreloaded: "{separatedPanel}.events.onPrefsEditorMessagesPreloaded"
},
preloadResources: "prefsEditor",
listeners: {
"onCreate.loadResources": { // Override of framework's definition
listener: "fluid.prefs.separatedPanel.lazyLoad.preloadResources",
args: ["{that}", "{that}.options.preloadResources"]
},
"{separatedPanel}.events.onLazyLoad": {
listener: "{that}.resourceFetcher.fetchAll"
}
}
}
},
slidingPanel: {
options: {
invokers: {
operateShow: {
funcName: "fluid.prefs.separatedPanel.lazyLoad.showPanel",
args: ["{separatedPanel}", "{that}.events.afterPanelShow.fire"]
}
}
}
}
}
});
fluid.prefs.separatedPanel.lazyLoad.showPanel = function (separatedPanel, callback) {
if (separatedPanel.prefsEditor) {
fluid.invokeLater(callback);
} else {
separatedPanel.events.onReady.addListener(function (that) {
that.events.onReady.removeListener("showPanelCallBack");
fluid.invokeLater(callback);
}, "showPanelCallBack");
separatedPanel.events.onLazyLoad.fire();
}
};
/**
* Used to override the standard "onCreate.loadResources" listener for fluid.resourceLoader component,
* allowing for pre-loading of a subset of resources. This is required for the lazyLoading workflow
* for the "fluid.prefs.separatedPanel.lazyLoad".
*
* @param {fluid.resourceLoader} that - the resourceLoader, augmented with the preload workflow
* @param {String|String[]} toPreload - a String or an String[]s corresponding to the names
* of the resources, supplied in the resource argument, that
* should be loaded. Only these resources will be loaded.
*/
fluid.prefs.separatedPanel.lazyLoad.preloadResources = function (that, toPreload) {
toPreload = fluid.makeArray(toPreload);
var resourceFetcher = that.resourceFetcher;
var preloadPromises = toPreload.map(function (onePreload) {
return fluid.fetchResources.fetchOneResource(resourceFetcher.resourceSpecs[onePreload], resourceFetcher);
});
var preloadAllPromise = fluid.promise.sequence(preloadPromises);
preloadAllPromise.then(function () {
that.events.onResourcesPreloaded.fire(that.resources);
});
};