@flowfuse/nr-launcher 2.31.3 → 2.31.4-5ccdf52-202606300926.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/admin.js +2 -0
- package/lib/runtimeSettings.js +18 -6
- package/lib/theme/common/flowfuse-common.js +8 -0
- package/lib/theme/common/forge-branding.js +69 -0
- package/lib/theme/common/forge-platform.js +59 -0
- package/lib/theme/forge/forge.js +0 -3
- package/lib/theme/forge-dark/forge-dark.js +0 -4
- package/lib/theme/forge-light/forge-light.js +0 -4
- package/package.json +7 -6
- package/lib/theme/common/forge-common.js +0 -125
- package/lib/theme/forge/forge-common.js +0 -125
package/lib/admin.js
CHANGED
|
@@ -148,6 +148,7 @@ class AdminInterface {
|
|
|
148
148
|
await launcher.start(request.body.safe ? States.SAFE : States.RUNNING)
|
|
149
149
|
} catch (error) {
|
|
150
150
|
await launcher.logAuditEvent('start-failed', { error })
|
|
151
|
+
return response.status(500).send({ error: error.message })
|
|
151
152
|
}
|
|
152
153
|
response.send({})
|
|
153
154
|
}, 2000)
|
|
@@ -157,6 +158,7 @@ class AdminInterface {
|
|
|
157
158
|
await launcher.start(request.body.safe ? States.SAFE : States.RUNNING)
|
|
158
159
|
} catch (error) {
|
|
159
160
|
await launcher.logAuditEvent('start-failed', { error })
|
|
161
|
+
return response.status(500).send({ error: error.message })
|
|
160
162
|
}
|
|
161
163
|
response.send({})
|
|
162
164
|
} else {
|
package/lib/runtimeSettings.js
CHANGED
|
@@ -265,6 +265,21 @@ function getSettingsFile (settings) {
|
|
|
265
265
|
},`
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
|
+
// Load via page.scripts so they run regardless of active theme; branding is dropped for non-FlowFuse themes.
|
|
269
|
+
const requestedTheme = projectSettings.theme
|
|
270
|
+
const themeCommonDir = path.join(__dirname, 'theme', 'common')
|
|
271
|
+
const pageScripts = [path.join(themeCommonDir, 'forge-platform.js')]
|
|
272
|
+
if (!requestedTheme || ['forge', 'forge-light', 'forge-dark'].includes(requestedTheme)) {
|
|
273
|
+
pageScripts.push(path.join(themeCommonDir, 'forge-branding.js'))
|
|
274
|
+
}
|
|
275
|
+
projectSettings.page_scripts = `scripts: ${JSON.stringify(pageScripts)},`
|
|
276
|
+
// launcher values shared by the flowfuse-common plugin settings and the legacy theme settings
|
|
277
|
+
const ffSettings = {
|
|
278
|
+
launcherVersion: settings.launcherVersion,
|
|
279
|
+
projectURL: `${settings.forgeURL}/instance/${settings.projectID}`
|
|
280
|
+
}
|
|
281
|
+
projectSettings.flowfuseCommonSettings = `"flowfuse-common": ${JSON.stringify(ffSettings)},`
|
|
282
|
+
|
|
268
283
|
if (projectSettings.theme) {
|
|
269
284
|
const nrMajor = parseInt((settings.nodeRedVersion || '0.0.0').split('.')[0], 10) || 0
|
|
270
285
|
let activeTheme = projectSettings.theme
|
|
@@ -279,12 +294,7 @@ function getSettingsFile (settings) {
|
|
|
279
294
|
activeTheme = 'forge-light'
|
|
280
295
|
}
|
|
281
296
|
|
|
282
|
-
|
|
283
|
-
launcherVersion: settings.launcherVersion,
|
|
284
|
-
forgeURL: settings.forgeURL,
|
|
285
|
-
projectURL: `${settings.forgeURL}/instance/${settings.projectID}`
|
|
286
|
-
}
|
|
287
|
-
projectSettings.themeSettings = `"${activeTheme}": ${JSON.stringify(themeSettings)},`
|
|
297
|
+
projectSettings.themeSettings = `"${activeTheme}": ${JSON.stringify(ffSettings)},`
|
|
288
298
|
projectSettings.theme = `theme: '${activeTheme}',`
|
|
289
299
|
}
|
|
290
300
|
|
|
@@ -419,10 +429,12 @@ module.exports = {
|
|
|
419
429
|
},
|
|
420
430
|
${nodesDir}
|
|
421
431
|
${projectSettings.themeSettings || ''}
|
|
432
|
+
${projectSettings.flowfuseCommonSettings || ''}
|
|
422
433
|
editorTheme: {
|
|
423
434
|
${projectSettings.theme}
|
|
424
435
|
page: {
|
|
425
436
|
title: '${projectSettings.page_title}',
|
|
437
|
+
${projectSettings.page_scripts || ''}
|
|
426
438
|
${projectSettings.page_favicon}
|
|
427
439
|
},
|
|
428
440
|
header: {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
/* global RED, $ */
|
|
3
|
+
// Favicon and menu items; runtimeSettings.js omits this script for non-FlowFuse (OEM) themes. Uses helpers from forge-platform.js.
|
|
4
|
+
function changeFavicon (src) {
|
|
5
|
+
const link = document.createElement('link')
|
|
6
|
+
const oldLink = $('link[href="favicon.ico"]')[0] || $('#dynamic-favicon')[0]
|
|
7
|
+
link.id = 'dynamic-favicon'
|
|
8
|
+
link.rel = 'shortcut icon'
|
|
9
|
+
link.href = src
|
|
10
|
+
if (oldLink) {
|
|
11
|
+
document.head.removeChild(oldLink)
|
|
12
|
+
}
|
|
13
|
+
document.head.appendChild(link)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
window.addEventListener('load', (_event) => {
|
|
17
|
+
const favicon32 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADzUlEQVR4AcXB206UVxzG4d+71jcbBmYGpjJIg2iHiNYEJaSKrQe4QeMNcOaR11BP2wuwV2JvQSMkxFAiGk1Q8UCjAoJsAkgRZuZb/wJtk6YtuEN4Ht3o7f0B+AXoBhy7w4Bh4FoEXAe+Z3cJ6AauO+Ake+c7B0TsHe/YY44495thjjj0WsdvMMNaZsSHiC7MQwAwkXBSZT6eJ0ml8MmlyziK+ADODEPDJpNU0N1t9qUT94cPkWlvJNDaSzGbxqZTkHBE7yOIYeU/d/v2h2NVFc3c3De3tShcKOO/Ffynic5lhIRDV1FjhyBFr6emh+dQpMk1NTs7xPhGfyEJgQyqft6auLjt48SL7OjqUyGTER4j4CBYCmOGiyOpaWqz59GlrPXdO9W1tcomEeB8z4nLZqqurhEoFC4HI4pgtSWyQc/h02moKBWtob2f/yZNW7OxUTWOjl8R24nLZlicnbe7RI+bHxmx5fFxri4vE5bIsBKJvr1wxzLAQYlsnkLx38t58MkmUTiuZy1Hb1ERtc7PSDQ3Ie8d2zHg3N2dTd++GicFBzY+NaW1hQRbHbJLYJBF1XL3q+FPEZ7I4tsUXL+xVf79NDA7q7fi4s2pVcg4k5D3/FrEDQqVibx48CC9v3tTUyIhW5+cd6+Qc8p7tOHZAqFRs8flz5p8+ZW1hQZghiQ8RsQOiTMYd6evj4IUL9np4OLy8dYu5x49VXVkRziGJrUTjAwO2KYQYEOvknJP35hMJ+XSaVD5PuqFByWwWeS+2kC4U9M3lyzrQ02Ozo6M2PjAQpu/d08rMjKxaFRKS2CSxQb9euhTMTJgZGyQEQjIknPf4VIp0Q4PlDh2i8cQJKx4/rrqWFrkoEtuwEOz36WmbffjQ3ty/r4Vnz1hbWFB1dZVQrWIhoBu9vQEQ2zHDzMAMOUe6ULB9HR124OxZip2dSmaz4j0sBKssL7O2tGSVt2+prKwQl8tEfAgJSfzt3fy8Xt2+rck7d6y+rc1az5+3r8+cobZYdEj8HzmnZC5HMpcT/+D7SqWfAPERJCHnsBC0MjOj6ZERvR4asnczMyFRV0cqn0feiw/g+0qlnwHxiSSxYW1xUbOjo25icJD5J08slMuWqKsjUVODnBNbiNghco4N5aUlTQwOanJoyGqLRQpHj9pXx46FfKmkTLFIMpuVT6Vw3oNzROw0CXkPZlqemmJ5clIv+/uJUilLZrOk8nlL5nJEmQw+kSACYsDxBUgC79kQl8tamZ1lZWZGmPGX2AHD7BJJyDnkPfIeeX/XAdeAO0Bg9wTgN+DHPwAIHJAeMJ00fgAAAABJRU5ErkJggg=='
|
|
18
|
+
changeFavicon(favicon32)
|
|
19
|
+
|
|
20
|
+
const ff = window.FlowFuse || {}
|
|
21
|
+
|
|
22
|
+
const addMenuItems = function () {
|
|
23
|
+
if (!RED || document.querySelector('#usermenu-item-ffsite')) { return }
|
|
24
|
+
const settings = (RED.settings && RED.settings['flowfuse-common']) || {}
|
|
25
|
+
|
|
26
|
+
RED.menu.addItem('red-ui-header-button-sidemenu', null) // menu seperator
|
|
27
|
+
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
28
|
+
id: 'usermenu-item-ffsite',
|
|
29
|
+
label: 'About FlowFuse',
|
|
30
|
+
onselect: function () {
|
|
31
|
+
ff.navigateTo('https://flowfuse.com/')
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
const projectURL = ff.getProjectURL ? ff.getProjectURL() : ''
|
|
35
|
+
if (projectURL) {
|
|
36
|
+
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
37
|
+
id: 'usermenu-item-ffmain',
|
|
38
|
+
label: 'FlowFuse Application',
|
|
39
|
+
onselect: function () {
|
|
40
|
+
ff.navigateTo(projectURL)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
if (settings.launcherVersion) {
|
|
45
|
+
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
46
|
+
id: 'usermenu-item-fflv',
|
|
47
|
+
label: 'FlowFuse Launcher v' + settings.launcherVersion,
|
|
48
|
+
onselect: function () {
|
|
49
|
+
// do nothing
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Add now if the menu button already exists; otherwise add it once Node-RED inserts it.
|
|
56
|
+
if (document.querySelector('#red-ui-header-button-sidemenu')) {
|
|
57
|
+
addMenuItems()
|
|
58
|
+
} else {
|
|
59
|
+
const observer = new MutationObserver(function () {
|
|
60
|
+
if (document.querySelector('#red-ui-header-button-sidemenu')) {
|
|
61
|
+
observer.disconnect()
|
|
62
|
+
addMenuItems()
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
observer.observe(document.querySelector('#red-ui-header') || document.body, { childList: true, subtree: true })
|
|
66
|
+
setTimeout(function () { observer.disconnect() }, 30000)
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
})()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
/* global RED, $ */
|
|
3
|
+
// Navigation interception and iframe messaging; loaded via editorTheme.page.scripts so it runs regardless of active theme.
|
|
4
|
+
const context = {
|
|
5
|
+
isEmbedded: window.parent !== window.self,
|
|
6
|
+
shouldEmitInsteadOfRedirect: false
|
|
7
|
+
}
|
|
8
|
+
const navigateTo = (url) => {
|
|
9
|
+
if (context.shouldEmitInsteadOfRedirect) {
|
|
10
|
+
window.parent.postMessage({
|
|
11
|
+
type: 'navigate',
|
|
12
|
+
payload: url
|
|
13
|
+
}, '*')
|
|
14
|
+
} else {
|
|
15
|
+
window.location = url
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// falls back to the project link in the header when flowfuse-common settings are absent
|
|
19
|
+
const getProjectURL = () => {
|
|
20
|
+
const settings = (typeof RED !== 'undefined' && RED.settings && RED.settings['flowfuse-common']) || {}
|
|
21
|
+
if (settings.projectURL) {
|
|
22
|
+
return settings.projectURL
|
|
23
|
+
}
|
|
24
|
+
const img = $('#red-ui-header > span > a > img')
|
|
25
|
+
const ownerHref = img.parent().prop('href')
|
|
26
|
+
if (ownerHref && /http[s]*:\/\/.*\/project\/\w+-\w+-\w+-\w+-\w+.*/.test(ownerHref)) {
|
|
27
|
+
return ownerHref
|
|
28
|
+
}
|
|
29
|
+
return ''
|
|
30
|
+
}
|
|
31
|
+
document.addEventListener('click', (e) => {
|
|
32
|
+
if (e.target.closest('#usermenu-item-logout')) {
|
|
33
|
+
e.preventDefault()
|
|
34
|
+
e.stopPropagation()
|
|
35
|
+
if (context.shouldEmitInsteadOfRedirect) {
|
|
36
|
+
window.parent.postMessage({ type: 'logout' }, '*')
|
|
37
|
+
}
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
if (e.target.closest('.red-ui-header-logo a')) {
|
|
41
|
+
e.preventDefault()
|
|
42
|
+
navigateTo(getProjectURL())
|
|
43
|
+
}
|
|
44
|
+
}, true)
|
|
45
|
+
|
|
46
|
+
function handleMessage (event) {
|
|
47
|
+
if (event.data && event.data.type === 'prevent-redirect') {
|
|
48
|
+
context.shouldEmitInsteadOfRedirect = event.data.payload
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (context.isEmbedded) {
|
|
53
|
+
window.parent.postMessage({ type: 'load', payload: true }, '*')
|
|
54
|
+
window.addEventListener('message', handleMessage)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// shared with forge-branding.js
|
|
58
|
+
window.FlowFuse = Object.assign(window.FlowFuse || {}, { navigateTo, getProjectURL })
|
|
59
|
+
})()
|
package/lib/theme/forge/forge.js
CHANGED
|
@@ -12,10 +12,6 @@ module.exports = function (RED) {
|
|
|
12
12
|
|
|
13
13
|
RED.plugins.registerPlugin('forge-dark', {
|
|
14
14
|
type: 'node-red-theme',
|
|
15
|
-
scripts: [
|
|
16
|
-
'lib/theme/common/forge-common.js'
|
|
17
|
-
// /* optional */ 'lib/theme/forge-dark/forge-dark-custom.js'
|
|
18
|
-
],
|
|
19
15
|
css: [
|
|
20
16
|
'lib/theme/common/forge-common.css',
|
|
21
17
|
'lib/theme/forge-dark/forge-dark-theme.css'
|
|
@@ -12,10 +12,6 @@ module.exports = function (RED) {
|
|
|
12
12
|
|
|
13
13
|
RED.plugins.registerPlugin('forge-light', {
|
|
14
14
|
type: 'node-red-theme',
|
|
15
|
-
scripts: [
|
|
16
|
-
'lib/theme/common/forge-common.js'
|
|
17
|
-
// /* optional */ 'lib/theme/forge-light/forge-light-custom.js'
|
|
18
|
-
],
|
|
19
15
|
css: [
|
|
20
16
|
'lib/theme/common/forge-common.css',
|
|
21
17
|
'lib/theme/forge-light/forge-light-theme.css'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowfuse/nr-launcher",
|
|
3
|
-
"version": "2.31.
|
|
3
|
+
"version": "2.31.4-5ccdf52-202606300926.0",
|
|
4
4
|
"description": "FlowFuse Launcher for running Node-RED",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./auditLogger": "./lib/auditLogger/index.js",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"node-red": {
|
|
14
14
|
"plugins": {
|
|
15
15
|
"flowfuse-auth": "lib/auth/httpAuthPlugin.js",
|
|
16
|
+
"flowfuse-common": "lib/theme/common/flowfuse-common.js",
|
|
16
17
|
"flowfuse-library": "lib/storage/libraryPlugin.js",
|
|
17
18
|
"flowfuse-blueprint-library": "lib/storage/blueprintPlugin.js",
|
|
18
19
|
"forge-light": "lib/theme/forge-light/forge-light.js",
|
|
@@ -47,12 +48,12 @@
|
|
|
47
48
|
},
|
|
48
49
|
"homepage": "https://github.com/FlowFuse/nr-launcher#readme",
|
|
49
50
|
"dependencies": {
|
|
50
|
-
"@flowfuse/nr-assistant": "
|
|
51
|
-
"@flowfuse/nr-file-nodes": "
|
|
52
|
-
"@flowfuse/nr-mqtt-nodes": "
|
|
53
|
-
"@flowfuse/nr-project-nodes": "
|
|
51
|
+
"@flowfuse/nr-assistant": "0.16.1-4db3964-202606261214.0",
|
|
52
|
+
"@flowfuse/nr-file-nodes": "0.0.11-cc0b339-202606241506.0",
|
|
53
|
+
"@flowfuse/nr-mqtt-nodes": "0.3.1-69e7b9c-202606220918.0",
|
|
54
|
+
"@flowfuse/nr-project-nodes": "0.7.9-783c2eb-202606241244.0",
|
|
54
55
|
"@flowfuse/nr-subflow-export": "^1.0.2",
|
|
55
|
-
"@flowfuse/nr-tables-nodes": "
|
|
56
|
+
"@flowfuse/nr-tables-nodes": "0.2.3-fe7d48f-202606220919.0",
|
|
56
57
|
"@node-red/util": "^3.1.0",
|
|
57
58
|
"body-parser": "^1.20.2",
|
|
58
59
|
"bytes": "^3.1.2",
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
(function () {
|
|
2
|
-
/* global RED, $ */
|
|
3
|
-
// monitorInsertion: derived from https://github.com/naugtur/insertionQuery/blob/master/insQ.min.js (MIT License Copyright (c) 2014-present Zbyszek Tenerowicz <naugtur@gmail.com>)
|
|
4
|
-
// eslint-disable-next-line
|
|
5
|
-
document.head = (document.head || document.getElementsByTagName('head')[0]);
|
|
6
|
-
// eslint-disable-next-line
|
|
7
|
-
const monitorInsertion = (function () { 'use strict'; let m = 100; let t = !1; let u = 'animationName'; let d = ''; const n = 'Webkit Moz O ms Khtml'.split(' '); let e = ''; const i = document.createElement('div'); const s = { strictlyNew: !0, timeout: 20, addImportant: !1 }; if (i.style.animationName && (t = !0), !1 === t) for (let o = 0; o < n.length; o++) if (void 0 !== i.style[n[o] + 'AnimationName']) { e = n[o], u = e + 'AnimationName', d = '-' + e.toLowerCase() + '-', t = !0; break } function c (t) { return s.strictlyNew && !0 === t.QinsQ } function r (t, n) { function e (t) { t.animationName !== o && t[u] !== o || c(t.target) || n(t.target) } let i; var o = 'insQ_' + m++; const r = s.addImportant ? ' !important' : ''; (i = document.createElement('style')).innerHTML = '@' + d + 'keyframes ' + o + ' { from { outline: 1px solid transparent } to { outline: 0px solid transparent } }\n' + t + ' { animation-duration: 0.001s' + r + '; animation-name: ' + o + r + '; ' + d + 'animation-duration: 0.001s' + r + '; ' + d + 'animation-name: ' + o + r + '; } ', document.head.appendChild(i); const a = setTimeout(function () { document.addEventListener('animationstart', e, !1), document.addEventListener('MSAnimationStart', e, !1), document.addEventListener('webkitAnimationStart', e, !1) }, s.timeout); return { destroy: function () { clearTimeout(a), i && (document.head.removeChild(i), i = null), document.removeEventListener('animationstart', e), document.removeEventListener('MSAnimationStart', e), document.removeEventListener('webkitAnimationStart', e) } } } function a (t) { t.QinsQ = !0 } function f (t) { if (t) for (a(t), t = t.firstChild; t; t = t.nextSibling) void 0 !== t && t.nodeType === 1 && f(t) } function l (t, n) { let e; let i = []; const o = function () { clearTimeout(e), e = setTimeout(function () { i.forEach(f), n(i), i = [] }, 10) }; return r(t, function (t) { if (!c(t)) { a(t); const n = (function t (n) { return c(n.parentNode) || n.nodeName === 'BODY' ? n : t(n.parentNode) }(t)); i.indexOf(n) < 0 && i.push(n), o() } }) } function v (n) { return !(!t || !n.match(/[^{}]/)) && (s.strictlyNew && f(document.body), { every: function (t) { return r(n, t) }, summary: function (t) { return l(n, t) } }) } return v.config = function (t) { for (const n in t)t.hasOwnProperty(n) && (s[n] = t[n]) }, v }()); typeof module !== 'undefined' && void 0 !== module.exports && (module.exports = monitorInsertion)
|
|
8
|
-
const context = {
|
|
9
|
-
isEmbedded: window.parent !== window.self,
|
|
10
|
-
shouldEmitInsteadOfRedirect: false
|
|
11
|
-
}
|
|
12
|
-
const navigateTo = (url) => {
|
|
13
|
-
if (context.shouldEmitInsteadOfRedirect) {
|
|
14
|
-
window.parent.postMessage({
|
|
15
|
-
type: 'navigate',
|
|
16
|
-
payload: url
|
|
17
|
-
}, '*')
|
|
18
|
-
} else {
|
|
19
|
-
window.location = url
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const interceptLogoClick = (url) => {
|
|
23
|
-
const logoAnchor = document.querySelector('#red-ui-header > .red-ui-header-logo > a')
|
|
24
|
-
|
|
25
|
-
if (logoAnchor) {
|
|
26
|
-
logoAnchor.addEventListener(
|
|
27
|
-
'click',
|
|
28
|
-
(e) => {
|
|
29
|
-
e.preventDefault()
|
|
30
|
-
navigateTo(url)
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
const interceptLogOutClick = (url) => {
|
|
35
|
-
document.querySelector('#usermenu-item-logout')
|
|
36
|
-
.addEventListener('click', (e) => {
|
|
37
|
-
e.preventDefault()
|
|
38
|
-
e.stopPropagation()
|
|
39
|
-
if (context.shouldEmitInsteadOfRedirect) {
|
|
40
|
-
window.parent.postMessage({
|
|
41
|
-
type: 'logout'
|
|
42
|
-
}, '*')
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function changeFavicon (src) {
|
|
48
|
-
const link = document.createElement('link')
|
|
49
|
-
const oldLink = $('link[href="favicon.ico"]')[0] || $('#dynamic-favicon"]')[0]
|
|
50
|
-
link.id = 'dynamic-favicon'
|
|
51
|
-
link.rel = 'shortcut icon'
|
|
52
|
-
link.href = src
|
|
53
|
-
if (oldLink) {
|
|
54
|
-
document.head.removeChild(oldLink)
|
|
55
|
-
}
|
|
56
|
-
document.head.appendChild(link)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function handleMessage (event) {
|
|
60
|
-
if (event.data.type === 'prevent-redirect') {
|
|
61
|
-
context.shouldEmitInsteadOfRedirect = event.data.payload
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (context.isEmbedded) {
|
|
66
|
-
window.parent.postMessage({ type: 'load', payload: true }, '*')
|
|
67
|
-
window.addEventListener('message', handleMessage)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
window.addEventListener('load', (_event) => {
|
|
71
|
-
// set favicon
|
|
72
|
-
const favicon32 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADzUlEQVR4AcXB206UVxzG4d+71jcbBmYGpjJIg2iHiNYEJaSKrQe4QeMNcOaR11BP2wuwV2JvQSMkxFAiGk1Q8UCjAoJsAkgRZuZb/wJtk6YtuEN4Ht3o7f0B+AXoBhy7w4Bh4FoEXAe+Z3cJ6AauO+Ake+c7B0TsHe/YY4495thjjj0WsdvMMNaZsSHiC7MQwAwkXBSZT6eJ0ml8MmlyziK+ADODEPDJpNU0N1t9qUT94cPkWlvJNDaSzGbxqZTkHBE7yOIYeU/d/v2h2NVFc3c3De3tShcKOO/Ffynic5lhIRDV1FjhyBFr6emh+dQpMk1NTs7xPhGfyEJgQyqft6auLjt48SL7OjqUyGTER4j4CBYCmOGiyOpaWqz59GlrPXdO9W1tcomEeB8z4nLZqqurhEoFC4HI4pgtSWyQc/h02moKBWtob2f/yZNW7OxUTWOjl8R24nLZlicnbe7RI+bHxmx5fFxri4vE5bIsBKJvr1wxzLAQYlsnkLx38t58MkmUTiuZy1Hb1ERtc7PSDQ3Ie8d2zHg3N2dTd++GicFBzY+NaW1hQRbHbJLYJBF1XL3q+FPEZ7I4tsUXL+xVf79NDA7q7fi4s2pVcg4k5D3/FrEDQqVibx48CC9v3tTUyIhW5+cd6+Qc8p7tOHZAqFRs8flz5p8+ZW1hQZghiQ8RsQOiTMYd6evj4IUL9np4OLy8dYu5x49VXVkRziGJrUTjAwO2KYQYEOvknJP35hMJ+XSaVD5PuqFByWwWeS+2kC4U9M3lyzrQ02Ozo6M2PjAQpu/d08rMjKxaFRKS2CSxQb9euhTMTJgZGyQEQjIknPf4VIp0Q4PlDh2i8cQJKx4/rrqWFrkoEtuwEOz36WmbffjQ3ty/r4Vnz1hbWFB1dZVQrWIhoBu9vQEQ2zHDzMAMOUe6ULB9HR124OxZip2dSmaz4j0sBKssL7O2tGSVt2+prKwQl8tEfAgJSfzt3fy8Xt2+rck7d6y+rc1az5+3r8+cobZYdEj8HzmnZC5HMpcT/+D7SqWfAPERJCHnsBC0MjOj6ZERvR4asnczMyFRV0cqn0feiw/g+0qlnwHxiSSxYW1xUbOjo25icJD5J08slMuWqKsjUVODnBNbiNghco4N5aUlTQwOanJoyGqLRQpHj9pXx46FfKmkTLFIMpuVT6Vw3oNzROw0CXkPZlqemmJ5clIv+/uJUilLZrOk8nlL5nJEmQw+kSACYsDxBUgC79kQl8tamZ1lZWZGmPGX2AHD7BJJyDnkPfIeeX/XAdeAO0Bg9wTgN+DHPwAIHJAeMJ00fgAAAABJRU5ErkJggg=='
|
|
73
|
-
changeFavicon(favicon32)
|
|
74
|
-
|
|
75
|
-
// monitor #red-ui-header-button-sidemenu & add main menu entries
|
|
76
|
-
monitorInsertion('#red-ui-header-button-sidemenu').summary(function (_arrayOfInsertedNodes) {
|
|
77
|
-
if (!RED) { return }
|
|
78
|
-
|
|
79
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', null) // menu seperator
|
|
80
|
-
// add main menu item "About FlowFuse"
|
|
81
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
82
|
-
id: 'usermenu-item-ffsite',
|
|
83
|
-
label: 'About FlowFuse',
|
|
84
|
-
onselect: function () {
|
|
85
|
-
navigateTo('https://flowfuse.com/')
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
// gather info from settings and page - prep for next 2 menu items
|
|
89
|
-
const ffThemeSettings = RED.settings['forge-light'] || RED.settings['forge-dark']
|
|
90
|
-
let projectURL = ''
|
|
91
|
-
if (ffThemeSettings && ffThemeSettings.projectURL) {
|
|
92
|
-
projectURL = ffThemeSettings.projectURL
|
|
93
|
-
} else {
|
|
94
|
-
const img = $('#red-ui-header > span > a > img')
|
|
95
|
-
const ownerHref = img.parent().prop('href')
|
|
96
|
-
// Test the URL is FlowFuse Project alike
|
|
97
|
-
if (ownerHref && /http[s]*:\/\/.*\/project\/\w+-\w+-\w+-\w+-\w+.*/.test(ownerHref)) {
|
|
98
|
-
projectURL = ownerHref
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// if projectURL is present, show link to project in main menu
|
|
102
|
-
if (projectURL) {
|
|
103
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
104
|
-
id: 'usermenu-item-ffmain',
|
|
105
|
-
label: 'FlowFuse Application',
|
|
106
|
-
onselect: function () {
|
|
107
|
-
navigateTo(projectURL)
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
// if theme settings are present, add launcher version entry in main menu
|
|
112
|
-
if (ffThemeSettings && ffThemeSettings.launcherVersion) {
|
|
113
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
114
|
-
id: 'usermenu-item-fflv',
|
|
115
|
-
label: 'FlowFuse Launcher v' + ffThemeSettings.launcherVersion,
|
|
116
|
-
onselect: function () {
|
|
117
|
-
// do nothing
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
interceptLogOutClick()
|
|
122
|
-
interceptLogoClick(projectURL)
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
})()
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
(function () {
|
|
2
|
-
/* global RED, $ */
|
|
3
|
-
// monitorInsertion: derived from https://github.com/naugtur/insertionQuery/blob/master/insQ.min.js (MIT License Copyright (c) 2014-present Zbyszek Tenerowicz <naugtur@gmail.com>)
|
|
4
|
-
// eslint-disable-next-line
|
|
5
|
-
document.head = (document.head || document.getElementsByTagName('head')[0]);
|
|
6
|
-
// eslint-disable-next-line
|
|
7
|
-
const monitorInsertion = (function () { 'use strict'; let m = 100; let t = !1; let u = 'animationName'; let d = ''; const n = 'Webkit Moz O ms Khtml'.split(' '); let e = ''; const i = document.createElement('div'); const s = { strictlyNew: !0, timeout: 20, addImportant: !1 }; if (i.style.animationName && (t = !0), !1 === t) for (let o = 0; o < n.length; o++) if (void 0 !== i.style[n[o] + 'AnimationName']) { e = n[o], u = e + 'AnimationName', d = '-' + e.toLowerCase() + '-', t = !0; break } function c (t) { return s.strictlyNew && !0 === t.QinsQ } function r (t, n) { function e (t) { t.animationName !== o && t[u] !== o || c(t.target) || n(t.target) } let i; var o = 'insQ_' + m++; const r = s.addImportant ? ' !important' : ''; (i = document.createElement('style')).innerHTML = '@' + d + 'keyframes ' + o + ' { from { outline: 1px solid transparent } to { outline: 0px solid transparent } }\n' + t + ' { animation-duration: 0.001s' + r + '; animation-name: ' + o + r + '; ' + d + 'animation-duration: 0.001s' + r + '; ' + d + 'animation-name: ' + o + r + '; } ', document.head.appendChild(i); const a = setTimeout(function () { document.addEventListener('animationstart', e, !1), document.addEventListener('MSAnimationStart', e, !1), document.addEventListener('webkitAnimationStart', e, !1) }, s.timeout); return { destroy: function () { clearTimeout(a), i && (document.head.removeChild(i), i = null), document.removeEventListener('animationstart', e), document.removeEventListener('MSAnimationStart', e), document.removeEventListener('webkitAnimationStart', e) } } } function a (t) { t.QinsQ = !0 } function f (t) { if (t) for (a(t), t = t.firstChild; t; t = t.nextSibling) void 0 !== t && t.nodeType === 1 && f(t) } function l (t, n) { let e; let i = []; const o = function () { clearTimeout(e), e = setTimeout(function () { i.forEach(f), n(i), i = [] }, 10) }; return r(t, function (t) { if (!c(t)) { a(t); const n = (function t (n) { return c(n.parentNode) || n.nodeName === 'BODY' ? n : t(n.parentNode) }(t)); i.indexOf(n) < 0 && i.push(n), o() } }) } function v (n) { return !(!t || !n.match(/[^{}]/)) && (s.strictlyNew && f(document.body), { every: function (t) { return r(n, t) }, summary: function (t) { return l(n, t) } }) } return v.config = function (t) { for (const n in t)t.hasOwnProperty(n) && (s[n] = t[n]) }, v }()); typeof module !== 'undefined' && void 0 !== module.exports && (module.exports = monitorInsertion)
|
|
8
|
-
const context = {
|
|
9
|
-
isEmbedded: window.parent !== window.self,
|
|
10
|
-
shouldEmitInsteadOfRedirect: false
|
|
11
|
-
}
|
|
12
|
-
const navigateTo = (url) => {
|
|
13
|
-
if (context.isEmbedded) {
|
|
14
|
-
window.parent.postMessage({
|
|
15
|
-
type: 'navigate',
|
|
16
|
-
payload: url
|
|
17
|
-
}, '*')
|
|
18
|
-
} else {
|
|
19
|
-
window.location = url
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const interceptLogoClick = (url) => {
|
|
23
|
-
const logoAnchor = document.querySelector('.red-ui-header-logo a')
|
|
24
|
-
|
|
25
|
-
if (logoAnchor) {
|
|
26
|
-
logoAnchor.addEventListener(
|
|
27
|
-
'click',
|
|
28
|
-
(e) => {
|
|
29
|
-
e.preventDefault()
|
|
30
|
-
navigateTo(url)
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
const interceptLogOutClick = (url) => {
|
|
35
|
-
document.querySelector('#usermenu-item-logout')
|
|
36
|
-
.addEventListener('click', (e) => {
|
|
37
|
-
e.preventDefault()
|
|
38
|
-
e.stopPropagation()
|
|
39
|
-
if (context.shouldEmitInsteadOfRedirect) {
|
|
40
|
-
window.parent.postMessage({
|
|
41
|
-
type: 'logout'
|
|
42
|
-
}, '*')
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function changeFavicon (src) {
|
|
48
|
-
const link = document.createElement('link')
|
|
49
|
-
const oldLink = $('link[href="favicon.ico"]')[0] || $('#dynamic-favicon"]')[0]
|
|
50
|
-
link.id = 'dynamic-favicon'
|
|
51
|
-
link.rel = 'shortcut icon'
|
|
52
|
-
link.href = src
|
|
53
|
-
if (oldLink) {
|
|
54
|
-
document.head.removeChild(oldLink)
|
|
55
|
-
}
|
|
56
|
-
document.head.appendChild(link)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function handleMessage (event) {
|
|
60
|
-
if (event.data.type === 'prevent-redirect') {
|
|
61
|
-
context.shouldEmitInsteadOfRedirect = event.data.payload
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (context.isEmbedded) {
|
|
66
|
-
window.parent.postMessage({ type: 'load', payload: true }, '*')
|
|
67
|
-
window.addEventListener('message', handleMessage)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
window.addEventListener('load', (_event) => {
|
|
71
|
-
// set favicon
|
|
72
|
-
const favicon32 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADzUlEQVR4AcXB206UVxzG4d+71jcbBmYGpjJIg2iHiNYEJaSKrQe4QeMNcOaR11BP2wuwV2JvQSMkxFAiGk1Q8UCjAoJsAkgRZuZb/wJtk6YtuEN4Ht3o7f0B+AXoBhy7w4Bh4FoEXAe+Z3cJ6AauO+Ake+c7B0TsHe/YY4495thjjj0WsdvMMNaZsSHiC7MQwAwkXBSZT6eJ0ml8MmlyziK+ADODEPDJpNU0N1t9qUT94cPkWlvJNDaSzGbxqZTkHBE7yOIYeU/d/v2h2NVFc3c3De3tShcKOO/Ffynic5lhIRDV1FjhyBFr6emh+dQpMk1NTs7xPhGfyEJgQyqft6auLjt48SL7OjqUyGTER4j4CBYCmOGiyOpaWqz59GlrPXdO9W1tcomEeB8z4nLZqqurhEoFC4HI4pgtSWyQc/h02moKBWtob2f/yZNW7OxUTWOjl8R24nLZlicnbe7RI+bHxmx5fFxri4vE5bIsBKJvr1wxzLAQYlsnkLx38t58MkmUTiuZy1Hb1ERtc7PSDQ3Ie8d2zHg3N2dTd++GicFBzY+NaW1hQRbHbJLYJBF1XL3q+FPEZ7I4tsUXL+xVf79NDA7q7fi4s2pVcg4k5D3/FrEDQqVibx48CC9v3tTUyIhW5+cd6+Qc8p7tOHZAqFRs8flz5p8+ZW1hQZghiQ8RsQOiTMYd6evj4IUL9np4OLy8dYu5x49VXVkRziGJrUTjAwO2KYQYEOvknJP35hMJ+XSaVD5PuqFByWwWeS+2kC4U9M3lyzrQ02Ozo6M2PjAQpu/d08rMjKxaFRKS2CSxQb9euhTMTJgZGyQEQjIknPf4VIp0Q4PlDh2i8cQJKx4/rrqWFrkoEtuwEOz36WmbffjQ3ty/r4Vnz1hbWFB1dZVQrWIhoBu9vQEQ2zHDzMAMOUe6ULB9HR124OxZip2dSmaz4j0sBKssL7O2tGSVt2+prKwQl8tEfAgJSfzt3fy8Xt2+rck7d6y+rc1az5+3r8+cobZYdEj8HzmnZC5HMpcT/+D7SqWfAPERJCHnsBC0MjOj6ZERvR4asnczMyFRV0cqn0feiw/g+0qlnwHxiSSxYW1xUbOjo25icJD5J08slMuWqKsjUVODnBNbiNghco4N5aUlTQwOanJoyGqLRQpHj9pXx46FfKmkTLFIMpuVT6Vw3oNzROw0CXkPZlqemmJ5clIv+/uJUilLZrOk8nlL5nJEmQw+kSACYsDxBUgC79kQl8tamZ1lZWZGmPGX2AHD7BJJyDnkPfIeeX/XAdeAO0Bg9wTgN+DHPwAIHJAeMJ00fgAAAABJRU5ErkJggg=='
|
|
73
|
-
changeFavicon(favicon32)
|
|
74
|
-
|
|
75
|
-
// monitor #red-ui-header-button-sidemenu & add main menu entries
|
|
76
|
-
monitorInsertion('#red-ui-header-button-sidemenu').summary(function (_arrayOfInsertedNodes) {
|
|
77
|
-
if (!RED) { return }
|
|
78
|
-
|
|
79
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', null) // menu seperator
|
|
80
|
-
// add main menu item "About FlowFuse"
|
|
81
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
82
|
-
id: 'usermenu-item-ffsite',
|
|
83
|
-
label: 'About FlowFuse',
|
|
84
|
-
onselect: function () {
|
|
85
|
-
navigateTo('https://flowfuse.com/')
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
// gather info from settings and page - prep for next 2 menu items
|
|
89
|
-
const ffThemeSettings = RED.settings['forge']
|
|
90
|
-
let projectURL = ''
|
|
91
|
-
if (ffThemeSettings && ffThemeSettings.projectURL) {
|
|
92
|
-
projectURL = ffThemeSettings.projectURL
|
|
93
|
-
} else {
|
|
94
|
-
const img = $('#red-ui-header > span > a > img')
|
|
95
|
-
const ownerHref = img.parent().prop('href')
|
|
96
|
-
// Test the URL is FlowFuse Project alike
|
|
97
|
-
if (ownerHref && /http[s]*:\/\/.*\/project\/\w+-\w+-\w+-\w+-\w+.*/.test(ownerHref)) {
|
|
98
|
-
projectURL = ownerHref
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// if projectURL is present, show link to project in main menu
|
|
102
|
-
if (projectURL) {
|
|
103
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
104
|
-
id: 'usermenu-item-ffmain',
|
|
105
|
-
label: 'FlowFuse Application',
|
|
106
|
-
onselect: function () {
|
|
107
|
-
navigateTo(projectURL)
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
|
-
}
|
|
111
|
-
// if theme settings are present, add launcher version entry in main menu
|
|
112
|
-
if (ffThemeSettings && ffThemeSettings.launcherVersion) {
|
|
113
|
-
RED.menu.addItem('red-ui-header-button-sidemenu', {
|
|
114
|
-
id: 'usermenu-item-fflv',
|
|
115
|
-
label: 'FlowFuse Launcher v' + ffThemeSettings.launcherVersion,
|
|
116
|
-
onselect: function () {
|
|
117
|
-
// do nothing
|
|
118
|
-
}
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
interceptLogOutClick()
|
|
122
|
-
interceptLogoClick(projectURL)
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
})()
|