VulpesOS/assets/webapps/costcontrol.gaiamobile.org/js/view_manager.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

255 lines
7.7 KiB
JavaScript

/* global AccessibilityHelper, LazyLoader */
/* exported ViewManager */
/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
var ViewManager = (function() {
// The ViewManager is in charge of simply manage the different views of the
// applications. ViewManager.changeViewTo() valid values are listed above
// these lines.
function ViewManager(tabs) {
tabs = tabs || [];
this._tabs = {};
tabs.forEach(function _registerTab(tabItem) {
if (typeof tabItem !== 'object') {
tabItem = { id: tabItem };
}
this._tabs[tabItem.id] = tabItem.tab || 'left';
}, this);
this._currentView = null;
this._currentTab = null;
}
// Return true if the passed view is a tab
ViewManager.prototype._isTab = function _isTab(view) {
return this._tabs.hasOwnProperty(view);
};
// Make target enter screen's main area and call callback after, passing as
// arguments if the new view is a tab, the new view id and a third parameter
// depending on if the view was a tab or not:
// If it is a tab: it returns the current overlay view id or null
// If it is not a tab: it returns the previous ovrlay view or null
ViewManager.prototype.changeViewTo = function _changeViewTo(viewHash,
obstructed,
callback) {
var hashParts = viewHash.split('?');
var viewId = hashParts[0];
if (this.isCurrentView(viewId)) {
return;
}
// Note here how we set the same value with different semantincs.
// This is used at the end of the function and the names are the correct
// because, depending on if the view is a tab or not, semantics may change.
var previousViewId, currentViewId;
previousViewId = currentViewId = this._currentView ?
this._currentView.id : null;
var view = document.getElementById(viewId);
var params = parseQueryParams(hashParts[1]);
var self = this;
// lazy load HTML of the panel
this.loadPanel(view, function() {
// Tabs are treated in a different way than overlay views
var isTab = self._isTab(viewId);
if (isTab) {
// Disposing the current view
var disposingTab = null;
if (self._currentTab) {
disposingTab = document.getElementById(self._currentTab);
}
if (disposingTab) {
disposingTab.dataset.viewport = self._tabs[disposingTab.id];
document.getElementById(disposingTab.id + '-filter').classList.remove(
'.selected');
}
// Showing the new one
view.dataset.viewport = '';
document.getElementById(view.id + '-filter').classList.add('.selected');
AccessibilityHelper.setAriaSelected(
document.getElementById(view.id + '-control'),
document.querySelectorAll('[role="tab"]'));
self._currentTab = viewId;
// Overlay view
} else {
self.closeCurrentView();
previousViewId = self._currentView ? self._currentView.id : '';
self._currentView = {
id: viewId,
defaultViewport: view.dataset.viewport,
obstructed: obstructed
};
// With a combination of CSS, we actually animate and display the view
delete view.dataset.viewport;
if (obstructed) {
document.querySelector(obstructed).classList.add('behind');
}
}
if (typeof callback === 'function') {
callback(isTab, viewId, isTab ? currentViewId : previousViewId);
}
notifyViewChange(isTab, viewId, params);
});
};
function notifyViewChange(isTab, current, params) {
var type = isTab ? 'tabchanged' : 'viewchanged';
var event = new CustomEvent(type, {
detail: {
id: current,
params: params
}
});
window.dispatchEvent(event);
}
ViewManager.prototype.loadPanel = function _loadPanel(panel, callback) {
if (!panel || panel.hidden === false) {
if (typeof callback === 'function') {
callback();
}
return;
}
LazyLoader.load(panel, function() {
var resourceRemaining = 0;
function loadResource(node) {
node.onload = onResourceLoaded;
document.head.appendChild(node);
resourceRemaining++;
}
// activate all styles
Array.from(panel.querySelectorAll('link')).forEach((node) => {
if (!document.querySelector('head > link[href="' + node.href + '"]')) {
var styleLink = document.createElement('link');
styleLink.href = node.href;
styleLink.media = node.media;
styleLink.rel = node.rel;
styleLink.type = node.type;
loadResource(styleLink);
}
node.remove();
});
// activate all scripts
Array.from(panel.querySelectorAll('script')).forEach((node) => {
if (!document.querySelector('head > script[src="' + node.src + '"]')) {
var scriptLink = document.createElement('script');
scriptLink.src = node.src;
scriptLink.type = node.type;
loadResource(scriptLink);
}
node.remove();
});
// add listeners
var headers = Array.from(
panel.querySelectorAll('gaia-header[action="close"]')
);
headers.forEach((headerWithClose) => {
headerWithClose.addEventListener('action', function() {
window.parent.location.hash = '#';
});
});
panel.hidden = false;
checkCallback();
function checkCallback() {
if (resourceRemaining === 0 && typeof callback === 'function') {
callback();
}
}
function onResourceLoaded() {
resourceRemaining--;
checkCallback();
}
});
};
// Close the current view returning to the previous one
ViewManager.prototype.closeCurrentView = function _closeCurrentView() {
if (!this._currentView) {
return;
}
var view = document.getElementById(this._currentView.id);
// With a combination of CSS, Restoring the last viewport we actually
// animate and hide the current view
view.dataset.viewport = this._currentView.defaultViewport;
if (this._currentView.obstructed) {
var obstructed = document.querySelector(this._currentView.obstructed);
obstructed.classList.remove('behind');
}
this._currentView = null;
};
// Test if the current view is the one passed as parameter
ViewManager.prototype.isCurrentView = function _isCurrentView(view) {
return this._currentView && this._currentView.id === view;
};
// Return the current view id or null if not current view
ViewManager.prototype.getCurrentView = function _getCurrentView() {
return this._currentView ? this._currentView.id : null;
};
// Return true if the tab id passed is the current tab
ViewManager.prototype.isCurrentTab = function _isCurrentTab(tab) {
return this._currentTab && this._currentTab === tab;
};
// Return the current tab
ViewManager.prototype.getCurrentTab = function _getCurrentTab() {
return this._currentTab;
};
function parseQueryParams(queryParams) {
var params = {};
queryParams = (queryParams || '').split('&');
queryParams.forEach(function(param) {
if (!param) { return; }
var pair = param.split('=');
var key = pair[0];
var value = pair[1];
if (params[key]) {
if (!Array.isArray(params[key])) {
params[key] = [params[key]];
}
params[key].push(value);
return;
}
params[key] = value;
});
return params;
}
return ViewManager;
}());