diff --git a/index.js b/index.js index b9ec7472..24f8fdb2 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,7 @@ import definitions from "./src/definitions.js"; import ApplicationFactory from "./src/application.js"; import Labels from "./src/labels/labels.js"; +import LocalPlugins from "./src/plugins/index.js"; // pull in our css we defined for our plugin // eslint-disable-next-line no-unused-vars @@ -40,6 +41,9 @@ window.__AB_Plugins.push({ AB.scriptLoadAll(this.scripts()); AB.cssLoadAll(this.stylesheets()); + // load any included plugins + LocalPlugins.load(AB); + // At this point, the Plugin should already have loaded all it's definitions // into the AB Factory AB.pluginLoad(ApplicationFactory(AB)); diff --git a/src/plugins/index.js b/src/plugins/index.js new file mode 100644 index 00000000..a8b0b552 --- /dev/null +++ b/src/plugins/index.js @@ -0,0 +1,13 @@ +import viewListProperties from "./web_view_list/FNAbviewlist.js"; +import TabProperties from "./web_view_tab/FNAbviewtab.js"; +import TabEditor from "./web_view_tab/FNAbviewtabEditor.js"; + +const AllPlugins = [TabProperties, TabEditor, viewListProperties]; + +export default { + load: (AB) => { + AllPlugins.forEach((plugin) => { + AB.pluginRegister(plugin); + }); + }, +}; diff --git a/src/rootPages/Designer/properties/views/ABViewList.js b/src/plugins/web_view_list/FNAbviewlist.js similarity index 88% rename from src/rootPages/Designer/properties/views/ABViewList.js rename to src/plugins/web_view_list/FNAbviewlist.js index f031cbb8..aa2cf13f 100644 --- a/src/rootPages/Designer/properties/views/ABViewList.js +++ b/src/plugins/web_view_list/FNAbviewlist.js @@ -1,24 +1,33 @@ -/* - * ABViewList - * A Property manager for our ABViewList definitions - */ - -import FABView from "./ABView"; - -export default function (AB) { +// FNAbviewlist Properties +// A properties side import for an ABView. +// +export default function FNAbviewlistProperties({ + AB, + ABViewPropertiesPlugin, + // ABUIPlugin, +}) { const BASE_ID = "properties_abview_list"; - const ABView = FABView(AB); - const L = ABView.L(); const uiConfig = AB.UISettings.config(); + const L = AB.Label(); + + return class ABAbviewlistProperties extends ABViewPropertiesPlugin { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + // properties-view : will display in the properties panel of the ABDesigner + } - class ABViewListProperty extends ABView { constructor() { super(BASE_ID, { datacollection: "", field: "", height: "", }); + this.AB = AB; } static get key() { @@ -168,7 +177,5 @@ export default function (AB) { ViewClass() { return super._ViewClass("list"); } - } - - return ABViewListProperty; + }; } diff --git a/src/rootPages/Designer/properties/views/ABViewTab.js b/src/plugins/web_view_tab/FNAbviewtab.js similarity index 90% rename from src/rootPages/Designer/properties/views/ABViewTab.js rename to src/plugins/web_view_tab/FNAbviewtab.js index 6dd9bd2f..1f614b1e 100644 --- a/src/rootPages/Designer/properties/views/ABViewTab.js +++ b/src/plugins/web_view_tab/FNAbviewtab.js @@ -1,21 +1,30 @@ -/* - * ABViewTab - * A Property manager for our ABViewTab definitions - */ - -import FABView from "./ABView"; -import FTabPopup from "../../interface_common/ui_tab_form_popup"; - -export default function (AB) { +// FNAbviewtab Properties +// A properties side import for an ABView. +// +import FTabPopup from "../../rootPages/Designer/interface_common/ui_tab_form_popup"; + +export default function FNAbviewtabProperties({ + AB, + ABViewPropertiesPlugin, + // ABUIPlugin, +}) { const BASE_ID = "properties_abview_tab"; - const ABView = FABView(AB); const uiConfig = AB.Config.uiSettings(); - const L = ABView.L(); + const L = AB.Label(); const TabPopup = FTabPopup(AB); - class ABViewTabProperty extends ABView { + return class ABAbviewtabProperties extends ABViewPropertiesPlugin { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + // properties-view : will display in the properties panel of the ABDesigner + } + constructor() { super(BASE_ID, { sidebarWidth: "", @@ -26,6 +35,7 @@ export default function (AB) { stackTabs: "", darkTheme: "", }); + this.AB = AB; } static get key() { @@ -209,7 +219,5 @@ export default function (AB) { ViewClass() { return super._ViewClass("tab"); } - } - - return ABViewTabProperty; + }; } diff --git a/src/plugins/web_view_tab/FNAbviewtabEditor.js b/src/plugins/web_view_tab/FNAbviewtabEditor.js new file mode 100644 index 00000000..47858f6a --- /dev/null +++ b/src/plugins/web_view_tab/FNAbviewtabEditor.js @@ -0,0 +1,357 @@ +// FNAbviewtab Editor +// An Editor wrapper for the ABView Component. +// The Editor is displayed in the ABDesigner as a view is worked on. +// The Editor allows a widget to be moved and placed on the canvas. +// + +import FTabPopup from "../../rootPages/Designer/interface_common/ui_tab_form_popup"; + +export default function FNAbviewtabEditor({ AB, ABViewEditorPlugin }) { + const BASE_ID = "interface_editor_viewtab"; + + const L = AB.Label(); + + const TabPopup = FTabPopup(AB); + + return class ABAbviewtabEditor extends ABViewEditorPlugin { + /** + * @method getPluginKey + * return the plugin key for this editor. + * @return {string} plugin key + */ + static getPluginKey() { + return this.key; + } + + /** + * @method getPluginType + * return the plugin type for this editor. + * plugin types are how our ClassManager knows how to store + * the plugin. + * @return {string} plugin type + */ + static getPluginType() { + return "editor-view"; + // editor-view : will display in the editor panel of the ABDesigner + } + + static get key() { + return "tab"; + } + + constructor(view, base = BASE_ID) { + // base: {string} unique base id reference + super(base, { + view: "", + }); + + this.AB = AB; + this.view = view; + this.component = this.view.component(); + } + + ui() { + const ids = this.ids; + const baseView = this.view; + const component = this.component; + const componentUI = this.component.ui()?.rows[0]; + + if (componentUI.rows) { + componentUI.rows[0].id = ids.component; + componentUI.rows[0].tabbar = { + height: 60, + type: "bottom", + css: baseView.settings.darkTheme ? "webix_dark" : "", + on: { + onItemClick: (id, e) => { + const tabID = $$(ids.component).getValue(); + const tab = baseView.views((view) => view.id === tabID)[0]; + const currIndex = baseView._views.findIndex( + (view) => view.id === tabID + ); + + // Rename + if (e.target.classList.contains("rename")) { + baseView.tabPopup.show(tab); + } + // Reorder back + else if (e.target.classList.contains("move-back")) { + baseView.viewReorder(tabID, currIndex - 1); + + // refresh editor view + baseView.emit("properties.updated", baseView); + } + // Reorder next + else if (e.target.classList.contains("move-next")) { + baseView.viewReorder(tabID, currIndex + 1); + + // refresh editor view + baseView.emit("properties.updated", baseView); + } + }, + }, + }; + + // Add action buttons + for ( + let i = 0; + i < (componentUI.rows[0]?.cells ?? []).length; + i++ + ) { + let _cell = componentUI.rows[0].cells[i]; + // Add 'move back' icon + _cell.header = `${componentUI.rows[0]?.cells[i].header}`; + + let currView = baseView.views((v) => v.id == _cell.body.id)[0]; + if (!currView || (currView.warningsAll() || []).length > 0) { + // Add warnings icon + _cell.header += this.WARNING_ICON; + } + + // Add 'edit' icon + _cell.header += + ' '; + + // Add 'move next' icon + _cell.header += + ' '; + } + } else if (componentUI.cols) { + // if we detect colums we are using sidebar and need to format the onItemClick event differently + let viewIndex = 1; + let tabIndex = 0; + + if (baseView.settings.sidebarPos === "right") { + // the sidebar is in the second column now so we need to reference it properly + viewIndex = 0; + tabIndex = 1; + } + + componentUI.cols[viewIndex].id = ids.component; + componentUI.cols[tabIndex].on = { + onItemClick: (id, e) => { + const tabID = id.replace("_menu", ""); + const tab = baseView.views((view) => view.id == tabID)[0]; + const currIndex = baseView._views.findIndex( + (view) => view.id === tabID + ); + + component.onShow(tabID); + + // Rename + if (e.target.classList.contains("rename")) + baseView.tabPopup.show(tab); + // Reorder back + else if (e.target.classList.contains("move-back")) { + baseView.viewReorder(tabID, currIndex - 1); + + // refresh editor view + baseView.emit("properties.updated", baseView); + } + // Reorder next + else if (e.target.classList.contains("move-next")) { + baseView.viewReorder(tabID, currIndex + 1); + + // refresh editor view + baseView.emit("properties.updated", baseView); + } + }, + }; + + // Add action buttons + for ( + let i = 0; + i < (componentUI.cols[tabIndex].data ?? []).length; + i++ + ) { + // Add 'edit' icon + componentUI.cols[tabIndex].data[i].value = + componentUI.cols[tabIndex].data[i].value + + ' '; + // Add 'move up' icon + componentUI.cols[tabIndex].data[i].value += + ''; + // Add 'move down' icon + componentUI.cols[tabIndex].data[i].value += + ' '; + } + } + + return { + _dashboardID: ids.component, + rows: [componentUI], + }; + } + + async init(AB) { + this.AB = AB; + + const ids = this.ids; + + await this.component.init(this.AB); + + const $component = $$(ids.component); + + if ($component) { + const tabID = $component.getValue(); + const tab = this.view.views((v) => v.id === tabID)[0]; + + let warnText = ""; + if (!tab || (tab.warningsAll() || []).length > 0) { + warnText = this.WARNING_ICON; + } + + // Add actions buttons - Edit , Delete + if ($component.config.view === "tabview") { + webix.ui({ + container: $component.getMultiview().$view, + view: "template", + autoheight: false, + height: 1, + width: 0, + template: [ + '
', + '', + '', + warnText, + "
", + ].join(""), + onClick: { + "ab-component-edit": (e, id, trg) => { + this.tabEdit(e, id, trg); + }, + "ab-component-remove": (e, id, trg) => { + this.tabRemove(e, id, trg); + }, + }, + }); + } else if ($component.config.view === "multiview") { + webix.ui({ + container: $component.$view, + view: "template", + autoheight: false, + height: 1, + width: 0, + template: [ + '
', + warnText, + '', + '', + "
", + ].join(""), + onClick: { + "ab-component-edit": (e) => { + this.tabEdit(e); + }, + "ab-component-remove": (e) => { + this.tabRemove(e); + }, + }, + }); + } + } + + const baseView = this.view; + + if (!baseView.tabPopup) { + baseView.tabPopup = new TabPopup(baseView); + baseView.tabPopup.init(AB); + } + + // this.component.onShow(); + // in our editor, we provide accessLv = 2 + } + + // templateBlock(tab) { + // const _template = [ + // '
', + // '
', + // '', + // ' #label#', + // '
', + // '
' + // ].join(''); + + // return _template + // .replace('#objID#', tab.id) + // .replace('#icon#', tab.icon) + // .replace('#label#', tab.label); + // } + + tabEdit(element) { + const tabID = $$(this.ids.component).getValue(); + const view = this.view.views((view) => view.id == tabID)[0]; + + if (!view) return false; + + // NOTE: let webix finish this onClick event, before + // calling .populateInterfaceWorkspace() which will replace + // the interface elements with the edited view. (apparently + // that causes errors.) + setTimeout(() => { + try { + this.emit("view.edit", view); + } catch (err) { + console.error(err); + } + }, 50); + + element.preventDefault(); + + return false; + } + + tabRemove(element) { + const ids = this.ids; + + const $component = $$(ids.component); + + const tabID = $component.getValue(); + const deletedView = this.view.views((view) => view.id == tabID)[0]; + + if (deletedView) { + webix.confirm({ + title: L("Delete tab"), + text: L("Do you want to delete {0}?", [ + deletedView.label, + ]), + callback: (result) => { + if (result) { + // this.viewDestroy(deletedView); + deletedView.destroy(); + + const componentUI = this.component.ui(); + + // remove tab option + if (componentUI.rows) $component.removeView(tabID); + else { + let $sidebar = null; + + for (let i = 0; i < componentUI.cols.length; i++) + if (componentUI.cols[i].view === "sidebar") { + $sidebar = $$(componentUI.cols[i].id); + + break; + } + + $sidebar.remove(`${tabID}_menu`); + } + } + }, + }); + } + + element.preventDefault(); + + return false; + } + + detatch() { + this.component.detatch?.(); + } + + onShow() { + this.component.onShow(); + } + }; +} diff --git a/src/rootPages/Designer/properties/PropertyManager.js b/src/rootPages/Designer/properties/PropertyManager.js index 3e4c86d4..3e97a0c2 100644 --- a/src/rootPages/Designer/properties/PropertyManager.js +++ b/src/rootPages/Designer/properties/PropertyManager.js @@ -111,14 +111,14 @@ export default function (AB) { require("./views/ABViewKanban"), require("./views/ABViewLabel"), require("./views/ABViewLayout"), - require("./views/ABViewList"), + // require("./views/ABViewList"), require("./views/ABViewMenu"), require("./views/ABViewPage"), require("./views/ABViewPDFImporter"), require("./views/ABViewPivot"), require("./views/ABViewReportsManager"), require("./views/ABViewScheduler"), - require("./views/ABViewTab"), + // require("./views/ABViewTab"), require("./views/ABViewText"), ].forEach((V) => { Views.push(V.default(AB));