mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-24 03:42:32 +01:00
Replaced el.components mapping with component service weakmap
Old system was hard to track in terms of usage and it's application of 'components' properties directly to elements was shoddy. This routes usage via the components service, with element-specific component usage tracked via a local weakmap. Updated existing found usages to use the new system.
This commit is contained in:
parent
25c23a2e5f
commit
be736b3939
@ -43,7 +43,9 @@ export class Attachments extends Component {
|
||||
|
||||
reloadList() {
|
||||
this.stopEdit();
|
||||
this.mainTabs.components.tabs.show('items');
|
||||
/** @var {Tabs} */
|
||||
const tabs = window.$components.firstOnElement(this.mainTabs, 'tabs');
|
||||
tabs.show('items');
|
||||
window.$http.get(`/attachments/get/page/${this.pageId}`).then(resp => {
|
||||
this.list.innerHTML = resp.data;
|
||||
window.$components.init(this.list);
|
||||
|
@ -126,7 +126,7 @@ export class CodeEditor extends Component {
|
||||
}
|
||||
|
||||
this.loadHistory();
|
||||
this.popup.components.popup.show(() => {
|
||||
this.getPopup().show(() => {
|
||||
Code.updateLayout(this.editor);
|
||||
this.editor.focus();
|
||||
}, () => {
|
||||
@ -135,10 +135,17 @@ export class CodeEditor extends Component {
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.popup.components.popup.hide();
|
||||
this.getPopup().hide();
|
||||
this.addHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Popup}
|
||||
*/
|
||||
getPopup() {
|
||||
return window.$components.firstOnElement(this.popup, 'popup');
|
||||
}
|
||||
|
||||
async updateEditorMode(language) {
|
||||
const Code = await window.importVersioned('code');
|
||||
Code.setMode(this.editor, language, this.editor.getValue());
|
||||
|
@ -34,7 +34,7 @@ export class ConfirmDialog extends Component {
|
||||
* @returns {Popup}
|
||||
*/
|
||||
getPopup() {
|
||||
return this.container.components.popup;
|
||||
return window.$components.firstOnElement(this.container, 'popup');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,16 +17,26 @@ export class EntitySelectorPopup extends Component {
|
||||
|
||||
show(callback) {
|
||||
this.callback = callback;
|
||||
this.container.components.popup.show();
|
||||
this.getPopup().show();
|
||||
this.getSelector().focusSearch();
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.container.components.popup.hide();
|
||||
this.getPopup().hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Popup}
|
||||
*/
|
||||
getPopup() {
|
||||
return window.$components.firstOnElement(this.container, 'popup');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {EntitySelector}
|
||||
*/
|
||||
getSelector() {
|
||||
return this.selectorEl.components['entity-selector'];
|
||||
return window.$components.firstOnElement(this.selectorEl, 'entity-selector');
|
||||
}
|
||||
|
||||
onSelectButtonClick() {
|
||||
|
@ -94,7 +94,7 @@ export class ImageManager extends Component {
|
||||
|
||||
this.callback = callback;
|
||||
this.type = type;
|
||||
this.popupEl.components.popup.show();
|
||||
this.getPopup().show();
|
||||
this.dropzoneContainer.classList.toggle('hidden', type !== 'gallery');
|
||||
|
||||
if (!this.hasData) {
|
||||
@ -104,7 +104,14 @@ export class ImageManager extends Component {
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.popupEl.components.popup.hide();
|
||||
this.getPopup().hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Popup}
|
||||
*/
|
||||
getPopup() {
|
||||
return window.$components.firstOnElement(this.popupEl, 'popup');
|
||||
}
|
||||
|
||||
async loadGallery() {
|
||||
|
@ -196,7 +196,8 @@ export class PageEditor extends Component {
|
||||
event.preventDefault();
|
||||
|
||||
const link = event.target.closest('a').href;
|
||||
const dialog = this.switchDialogContainer.components['confirm-dialog'];
|
||||
/** @var {ConfirmDialog} **/
|
||||
const dialog = window.$components.firstOnElement(this.switchDialogContainer, 'confirm-dialog');
|
||||
const [saved, confirmed] = await Promise.all([this.saveDraft(), dialog.show()]);
|
||||
|
||||
if (saved && confirmed) {
|
||||
|
@ -11,7 +11,8 @@ export class TagManager extends Component {
|
||||
|
||||
setupListeners() {
|
||||
this.container.addEventListener('change', event => {
|
||||
const addRemoveComponent = this.addRemoveComponentEl.components['add-remove-rows'];
|
||||
/** @var {AddRemoveRows} **/
|
||||
const addRemoveComponent = window.$components.firstOnElement(this.addRemoveComponentEl, 'add-remove-rows');
|
||||
if (!this.hasEmptyRows()) {
|
||||
addRemoveComponent.add();
|
||||
}
|
||||
|
@ -4,12 +4,11 @@ import {Component} from "./component";
|
||||
export class UserSelect extends Component {
|
||||
|
||||
setup() {
|
||||
this.container = this.$el;
|
||||
this.input = this.$refs.input;
|
||||
this.userInfoContainer = this.$refs.userInfo;
|
||||
|
||||
this.hide = this.$el.components.dropdown.hide;
|
||||
|
||||
onChildEvent(this.$el, 'a.dropdown-search-item', 'click', this.selectUser.bind(this));
|
||||
onChildEvent(this.container, 'a.dropdown-search-item', 'click', this.selectUser.bind(this));
|
||||
}
|
||||
|
||||
selectUser(event, userEl) {
|
||||
@ -20,4 +19,10 @@ export class UserSelect extends Component {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
hide() {
|
||||
/** @var {Dropdown} **/
|
||||
const dropdown = window.$components.firstOnElement(this.container, 'dropdown');
|
||||
dropdown.hide();
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,21 @@
|
||||
/**
|
||||
* A mapping of active components keyed by name, with values being arrays of component
|
||||
* instances since there can be multiple components of the same type.
|
||||
* @type {Object<String, Component[]>}
|
||||
*/
|
||||
const components = {};
|
||||
const componentMap = {};
|
||||
|
||||
/**
|
||||
* A mapping of component class models, keyed by name.
|
||||
* @type {Object<String, Constructor<Component>>}
|
||||
*/
|
||||
const componentModelMap = {};
|
||||
|
||||
/**
|
||||
* A mapping of active component maps, keyed by the element components are assigned to.
|
||||
* @type {WeakMap<Element, Object<String, Component>>}
|
||||
*/
|
||||
const elementComponentMap = new WeakMap();
|
||||
|
||||
/**
|
||||
* Initialize a component instance on the given dom element.
|
||||
@ -8,7 +24,7 @@ const componentMap = {};
|
||||
*/
|
||||
function initComponent(name, element) {
|
||||
/** @type {Function<Component>|undefined} **/
|
||||
const componentModel = componentMap[name];
|
||||
const componentModel = componentModelMap[name];
|
||||
if (componentModel === undefined) return;
|
||||
|
||||
// Create our component instance
|
||||
@ -33,11 +49,10 @@ function initComponent(name, element) {
|
||||
}
|
||||
components[name].push(instance);
|
||||
|
||||
// Add to element listing
|
||||
if (typeof element.components === 'undefined') {
|
||||
element.components = {};
|
||||
}
|
||||
element.components[name] = instance;
|
||||
// Add to element mapping
|
||||
const elComponents = elementComponentMap.get(element) || {};
|
||||
elComponents[name] = instance;
|
||||
elementComponentMap.set(element, elComponents);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,7 +140,7 @@ export function init(parentElement = document) {
|
||||
export function register(mapping) {
|
||||
const keys = Object.keys(mapping);
|
||||
for (const key of keys) {
|
||||
componentMap[camelToKebab(key)] = mapping[key];
|
||||
componentModelMap[camelToKebab(key)] = mapping[key];
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,6 +162,17 @@ export function get(name = '') {
|
||||
return components[name] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first component, of the given name, that's assigned to the given element.
|
||||
* @param {Element} element
|
||||
* @param {String} name
|
||||
* @returns {Component|null}
|
||||
*/
|
||||
export function firstOnElement(element, name) {
|
||||
const elComponents = elementComponentMap.get(element) || {};
|
||||
return elComponents[name] || null;
|
||||
}
|
||||
|
||||
function camelToKebab(camelStr) {
|
||||
return camelStr.replace(/[A-Z]/g, (str, offset) => (offset > 0 ? '-' : '') + str.toLowerCase());
|
||||
}
|
Loading…
Reference in New Issue
Block a user