diff --git a/nodes/config/locales/en-US/ui_page.json b/nodes/config/locales/en-US/ui_page.json index fed5b28f..c17a21ec 100644 --- a/nodes/config/locales/en-US/ui_page.json +++ b/nodes/config/locales/en-US/ui_page.json @@ -7,6 +7,7 @@ "icon": "Icon", "theme": "Theme", "layout": "Layout", + "editLayout": "Edit Layout", "grid": "Grid", "fixed": "Fixed", "tabs": "Tabs", diff --git a/nodes/config/ui_base.html b/nodes/config/ui_base.html index 21d9d45a..e47bc26c 100644 --- a/nodes/config/ui_base.html +++ b/nodes/config/ui_base.html @@ -287,6 +287,56 @@ /** @typedef {Object>} DashboardItemLookup */ // #endregion +// Custom global sidebar function used in other nodes +async function showDashboardWysiwygEditor (pageId, baseId) { + // call to httpadmin endpoint requesting layout editor mode for this group + const windowUrl = new URL(window.location.href) + const base = RED.nodes.node(baseId) + const dashboardBasePath = (base.path || 'dashboard').replace(/\/$/, '').replace(/^\/+/, '') + const authTokens = RED.settings.get('auth-tokens') || {} + const headers = {} + if (authTokens.access_token) { + headers.Authorization = `${authTokens.token_type || 'Bearer'} ${authTokens.access_token}` + } + + // promisify the ajax call so we can await it & return false after opening the popup + const ajax = () => { + return new Promise((resolve, reject) => { + $.ajax({ + url: `${dashboardBasePath}/api/v1/${baseId}/edit/${pageId}`, // e.g. /dashboard/api/v1/123/edit/456 + type: 'PATCH', + headers, + data: { + mode: 'edit', + dashboard: baseId, + page: pageId + }, + success: function (data) { + // construct the url to open the layout editor + const _url = new URL(`${dashboardBasePath}/${data.path}`.replace(/\/\//g, '/'), windowUrl.origin) + _url.searchParams.set('edit-key', data.editKey) + const editorPath = windowUrl.pathname?.replace(/\/$/, '').replace(/^\/+/, '') || '' + if (editorPath) { + _url.searchParams.set('editor-path', editorPath) + } + resolve(_url) + }, + error: function (err) { + reject(err) + } + }) + }) + } + try { + const url = await ajax() + const target = `ff-dashboard-${baseId}` // try to reuse the same window per base + window.open(url, target) + } catch (err) { + console.error('layout mode error', err) + RED.notify('Unable to begin layout editor', 'error') + } +} + (function () { const supportedEditableLayouts = ['grid', 'flex'] const sidebarContainer = '
' @@ -373,13 +423,12 @@ // backward compatibility for including header content // The headerContent replaces the old (boolean) showPageTitle if (this.headerContent === undefined) { - let showPageTitle = (this.showPageTitle === undefined) ? true : this.showPageTitle + const showPageTitle = (this.showPageTitle === undefined) ? true : this.showPageTitle if (showPageTitle) { this.headerContent = 'page' $('#node-config-input-headerContent').val('page') - } - else { + } else { this.headerContent = 'none' $('#node-config-input-headerContent').val('none') } @@ -1150,71 +1199,29 @@ evt.preventDefault() }) - if (item.type === 'ui-page' && supportedEditableLayouts.includes(item.node.layout)) { - // button to edit group in wysiwyg layout editor - const layoutButton = $(``).appendTo(btnGroup) - layoutButton.on('click', async function (evt) { + if (item.type === 'ui-page') { + // add the "+ group" button + const groupEditButton = $(``).appendTo(btnGroup) + groupEditButton.on('click', function (evt) { + list.editableList('addItem') evt.preventDefault() - evt.stopPropagation() + }) - // call to httpadmin endpoint requesting layout editor mode for this group - const windowUrl = new URL(window.location.href) - const pageId = item.id - const baseId = item.node.ui - const base = RED.nodes.node(item.node.ui) - const dashboardBasePath = (base.path || 'dashboard').replace(/\/$/, '').replace(/^\/+/, '') - const authTokens = RED.settings.get('auth-tokens') || {} - const headers = {} - if (authTokens.access_token) { - headers.Authorization = `${authTokens.token_type || 'Bearer'} ${authTokens.access_token}` - } + if (supportedEditableLayouts.includes(item.node.layout)) { + // button to edit group in wysiwyg layout editor + const layoutButton = $(``).appendTo(btnGroup) + layoutButton.on('click', function (evt) { + evt.preventDefault() + evt.stopPropagation() - // promisify the ajax call so we can await it & return false after opening the popup - const ajax = () => { - return new Promise((resolve, reject) => { - $.ajax({ - url: `${dashboardBasePath}/api/v1/${baseId}/edit/${pageId}`, // e.g. /dashboard/api/v1/123/edit/456 - type: 'PATCH', - headers, - data: { - mode: 'edit', - dashboard: baseId, - page: pageId - }, - success: function (data) { - // construct the url to open the layout editor - const _url = new URL(`${dashboardBasePath}/${data.path}`.replace(/\/\//g, '/'), windowUrl.origin) - _url.searchParams.set('edit-key', data.editKey) - const editorPath = windowUrl.pathname?.replace(/\/$/, '').replace(/^\/+/, '') || '' - if (editorPath) { - _url.searchParams.set('editor-path', editorPath) - } - resolve(_url) - }, - error: function (err) { - reject(err) - } - }) - }) - } - try { - const url = await ajax() - const target = `ff-dashboard-${baseId}` // try to reuse the same window per base - window.open(url, target) - } catch (err) { - console.error('layout mode error', err) - RED.notify('Unable to begin layout editor', 'error') - } - return false // return false to click event to prevent default - }) - } + const pageId = item.id + const baseId = item.node.ui + showDashboardWysiwygEditor(pageId, baseId) - // add the "+ group" button - const groupEditButton = $(``).appendTo(btnGroup) - groupEditButton.on('click', function (evt) { - list.editableList('addItem') - evt.preventDefault() - }) + return false // return false to click event to prevent default + }) + } + } // if this is a group & it is not an unattached group, add the "_ spacer" button if (item.type === 'ui-group' && !!item.page) { diff --git a/nodes/config/ui_page.html b/nodes/config/ui_page.html index 8d8fbbfb..b6f423d1 100644 --- a/nodes/config/ui_page.html +++ b/nodes/config/ui_page.html @@ -82,6 +82,8 @@ disabled: { value: 'false' } }, oneditprepare: function () { + const node = this + if (this.path === -1) { // we have no path set yet let pageCount = 0 @@ -115,6 +117,19 @@ } }) + // button to edit page layout in wysiwyg layout editor + $('#node-config-layout-edit').on('click', function (evt) { + evt.preventDefault() + evt.stopPropagation() + + const pageId = node.id + const baseNode = RED.nodes.node(node.ui) + // eslint-disable-next-line no-undef + showDashboardWysiwygEditor(pageId, baseNode.id) // defined in UI Base as a Global + + return false // return false to click event to prevent default + }) + // Breakpoints Editable List const breakpointsList = $('#node-config-list-breakpoints').editableList({ header: $('
').addClass('node-config-list-breakpoints-header') @@ -276,8 +291,16 @@
- - +
+
+ + +
+ +