diff --git a/bundles/org.openhab.ui/web/src/assets/sitemap-lexer.nearley b/bundles/org.openhab.ui/web/src/assets/sitemap-lexer.nearley index b413cd31f3..e8fd9ef8e4 100644 --- a/bundles/org.openhab.ui/web/src/assets/sitemap-lexer.nearley +++ b/bundles/org.openhab.ui/web/src/assets/sitemap-lexer.nearley @@ -2,32 +2,40 @@ const moo = require('moo') let lexer = moo.compile({ - WS: /[ \t]+/, - comment: /\/\/.*?$/, - number: /\-?[0-9]+(?:\.[0-9]*)?/, - string: { match: /"(?:\\["\\]|[^\n"\\])*"/, value: x => x.slice(1, -1) }, - sitemap: 'sitemap ', - name: 'name=', - label: 'label=', - item: 'item=', - icon: 'icon=', - widgetattr: ['url=', 'refresh=', 'service=', 'refresh=', 'period=', 'legend=', 'height=', 'frequency=', 'sendFrequency=', - 'switchEnabled=', 'mappings=', 'minValue=', 'maxValue=', 'step=', 'separator=', 'encoding='], - nlwidget: ['Switch ', 'Selection ', 'Slider ', 'List ', 'Setpoint ', 'Video ', 'Chart ', 'Webview ', 'Colorpicker ', 'Mapview ', 'Default '], - lwidget: ['Text', 'Group', 'Image', 'Frame'], - identifier: /[A-Za-z0-9_]+/, - lparen: '(', - rparen: ')', - colon: ':', - lbrace: '{', - rbrace: '}', - lbracket: '[', - rbracket: ']', - lt: '<', - gt: '>', - equals: '=', - comma: ',', - NL: { match: /\n/, lineBreaks: true }, + WS: /[ \t]+/, + comment: /\/\/.*?$/, + number: /\-?[0-9]+(?:\.[0-9]*)?/, + string: { match: /"(?:\\["\\]|[^\n"\\])*"/, value: x => x.slice(1, -1) }, + sitemap: 'sitemap ', + name: 'name=', + label: 'label=', + item: 'item=', + icon: 'icon=', + widgetattr: ['url=', 'refresh=', 'service=', 'period=', 'legend=', 'height=', 'mappings=', 'minValue=', 'maxValue=', 'step=', 'separator=', 'encoding=', 'yAxisDecimalPattern='], + widgetfreqattr: 'sendFrequency=', + widgetfrcitmattr: 'forceasitem=', + widgetvisiattr: 'visibility=', + widgetcolorattr: ['labelcolor=', 'valuecolor=', 'iconcolor='], + widgetswitchattr: 'switchSupport', + nlwidget: ['Switch ', 'Selection ', 'Slider ', 'List ', 'Setpoint ', 'Video ', 'Chart ', 'Webview ', 'Colorpicker ', 'Mapview ', 'Default '], + lwidget: ['Text ', 'Group ', 'Image ', 'Frame '], + identifier: /[A-Za-z][A-Za-z0-9_]*/, + lparen: '(', + rparen: ')', + colon: ':', + lbrace: '{', + rbrace: '}', + lbracket: '[', + rbracket: ']', + eq: '==', + noteq: '!=', + lteq: '<=', + gteq: '>=', + lt: '<', + gt: '>', + equals: '=', + comma: ',', + NL: { match: /\n/, lineBreaks: true }, }) function getSitemap(d) { @@ -64,7 +72,6 @@ @lexer lexer - Main -> _ Sitemap _ {% (d) => d[1] %} Sitemap -> %sitemap _ SitemapName __ SitemapLabel __ %lbrace _ Widgets _ %rbrace {% getSitemap %} @@ -77,23 +84,49 @@ Widgets -> Widget Widget -> %nlwidget _ WidgetAttrs:* {% getWidget %} | %lwidget _ WidgetAttrs:* {% getWidget %} - | %lwidget _ WidgetAttrs:* __ %lbrace __ Widgets __ %rbrace {% getWidget %} + | %lwidget _ WidgetAttrs:* _ %lbrace _ Widgets _ %rbrace {% getWidget %} WidgetAttrs -> WidgetAttr {% (d) => [d[0]] %} | WidgetAttrs _ WidgetAttr {% (d) => d[0].concat([d[2]]) %} -WidgetAttr -> WidgetAttrName WidgetAttrValue {% (d) => [d[0][0].value, d[1]] %} +WidgetAttr -> %widgetswitchattr {% (d) => ['switchEnabled', true] %} + | %widgetfreqattr {% (d) => ['frequency', d[1]] %} + | %widgetfrcitmattr {% (d) => ['forceAsItem', d[1]] %} + | WidgetAttrName WidgetAttrValue {% (d) => [d[0][0].value, d[1]] %} + | WidgetVisibilityAttrName WidgetVisibilityAttrValue {% (d) => [d[0][0].value, d[1]] %} + | WidgetColorAttrName WidgetColorAttrValue {% (d) => [d[0][0].value, d[1]] %} WidgetAttrName -> %item | %label | %icon | %widgetattr WidgetAttrValue -> %string {% (d) => d[0].value %} | %identifier {% (d) => d[0].value %} | %number {% (d) => { return parseFloat(d[0].value) } %} | %lbracket _ Mappings _ %rbracket {% (d) => d[2] %} +WidgetVisibilityAttrName -> %widgetvisiattr +WidgetVisibilityAttrValue -> %lbracket _ Visibilities _ %rbracket {% (d) => d[2] %} +WidgetColorAttrName -> %widgetcolorattr +WidgetColorAttrValue -> %lbracket _ Colors _ %rbracket {% (d) => d[2] %} Mappings -> Mapping {% (d) => [d[0]] %} | Mappings _ %comma _ Mapping {% (d) => d[0].concat([d[4]]) %} -Mapping -> MappingCommand %equals MappingLabel {% (d) => d[0][0].value.toString() + '=' + d[2][0].value.toString() %} +Mapping -> MappingCommand _ %equals _ MappingLabel {% (d) => d[0][0].value.toString() + '=' + d[4][0].value.toString() %} MappingCommand -> %number | %identifier | %string MappingLabel -> %number | %identifier | %string +Visibilities -> Visibility {% (d) => [d[0]] %} + | Visibilities _ %comma _ Visibility {% (d) => d[0].concat([d[4]]) %} +Visibility -> VisibilityCommand _ VisibilityComparator _ VisibilityValue {% (d) => d[0][0].value.toString() + d[2][0].value.toString() + d[4][0].value.toString() %} +VisibilityCommand -> %identifier | %string +VisibilityComparator -> %eq | %noteq | %lteq | %gteq | %lt | %gt +VisibilityValue -> %number | %identifier | %string + +Colors -> Color {% (d) => [d[0]] %} + | Colors _ %comma _ Color {% (d) => d[0].concat([d[4]]) %} +Color -> ColorCommand _ ColorComparator _ ColorValue _ %equals _ ColorName {% (d) => d[0][0].value.toString() + d[2][0].value.toString() + d[4][0].value.toString() + '=' + d[8][0].value.toString() %} + | ColorComparator _ ColorValue _ %equals _ ColorName {% (d) => d[0][0].value.toString() + d[2][0].value.toString() + '=' + d[6][0].value.toString() %} + | ColorValue _ %equals _ ColorName {% (d) => "==" + d[0][0].value.toString() + '=' + d[4][0].value.toString() %} + | ColorName {% (d) => d[0][0].value.toString() %} +ColorCommand -> %identifier | %string +ColorComparator -> %eq | %noteq | %lteq | %gteq | %lt | %gt +ColorValue -> %number | %identifier | %string +ColorName -> %identifier | %string _ -> null {% () => null %} | _ %WS {% () => null %} diff --git a/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/attribute-details.vue b/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/attribute-details.vue new file mode 100644 index 0000000000..fb25f00512 --- /dev/null +++ b/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/attribute-details.vue @@ -0,0 +1,51 @@ + + + diff --git a/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/dslUtil.js b/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/dslUtil.js index 8c15d4ef86..08a3fce2b4 100644 --- a/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/dslUtil.js +++ b/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/dslUtil.js @@ -4,18 +4,31 @@ function writeWidget (widget, indent) { if (widget.config) { for (let key in widget.config) { if (!widget.config[key]) continue - dsl += ` ${key}=` - if (key === 'item' || Number.isFinite(widget.config[key])) { - dsl += widget.config[key] - } else if (key === 'mappings') { - dsl += '[' - const mappingsDsl = widget.config.mappings.map((m) => - `${m.split('=')[0]}="${m.substring(m.indexOf('=') + 1)}"` - ) - dsl += mappingsDsl.join(',') - dsl += ']' + if ((Array.isArray(widget.config[key]) && widget.config[key].filter(Boolean).length <= 0)) continue + if (key === 'switchEnabled') { + dsl += ' switchSupport' + } else if (key === 'frequency') { + dsl += ' sendFrequency=' + widget.config[key] + } else if (key === 'forceAsItem') { + dsl += ' forceasitem=' + widget.config[key] } else { - dsl += '"' + widget.config[key] + '"' + dsl += ` ${key}=` + if (key === 'item' || Number.isFinite(widget.config[key])) { + dsl += widget.config[key] + } else if (['mappings', 'visibility', 'valuecolor', 'labelcolor', 'iconcolor'].includes(key)) { + dsl += '[' + const arrayDsl = widget.config[key].map((v) => { + // Anything after the first comparator that is a string should be in quotes. + // Also quote string if no comparator (i.e. fixed labelcolor or valuecolor). + let value = v.substring(0, v.search(/[=<>]/)) + value += v.substring(v.search(/[=<>]/)).replace(/"/g, '').replace(/[A-Za-z][A-Za-z0-9 _-]*/g, function (x) { return '"' + x.trim() + '"' }) + return value.trim() + }) + dsl += arrayDsl.filter(Boolean).join(',') + dsl += ']' + } else { + dsl += '"' + widget.config[key] + '"' + } } } } diff --git a/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/mapping-details.vue b/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/mapping-details.vue deleted file mode 100644 index f2367dc28e..0000000000 --- a/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/mapping-details.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - diff --git a/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/widget-details.vue b/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/widget-details.vue index 46e81f614c..a4d2657dde 100644 --- a/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/widget-details.vue +++ b/bundles/org.openhab.ui/web/src/components/pagedesigner/sitemap/widget-details.vue @@ -5,7 +5,7 @@ - +
    @@ -23,14 +23,17 @@ - + + + +
@@ -67,13 +70,13 @@ export default { additionalControls: { Image: ['url', 'refresh'], Video: ['url', 'encoding'], - Chart: ['service', 'period', 'refresh', 'legend'], + Chart: ['service', 'period', 'refresh', 'legend', 'forceAsItem', 'yAxisDecimalPattern'], Webview: ['url', 'height'], Mapview: ['height'], Slider: ['sendFrequency', 'switchEnabled', 'minValue', 'maxValue', 'step'], List: ['separator'], Setpoint: ['minValue', 'maxValue', 'step'], - Colorpicker: ['frequency'], + Colorpicker: ['sendFrequency'], Default: ['height'] } } diff --git a/bundles/org.openhab.ui/web/src/pages/settings/pages/sitemap/sitemap-edit.vue b/bundles/org.openhab.ui/web/src/pages/settings/pages/sitemap/sitemap-edit.vue index d20e4db32c..8fb19b3a35 100644 --- a/bundles/org.openhab.ui/web/src/pages/settings/pages/sitemap/sitemap-edit.vue +++ b/bundles/org.openhab.ui/web/src/pages/settings/pages/sitemap/sitemap-edit.vue @@ -46,9 +46,25 @@ Nothing selected + +
Visibility
+ +
+ +
Label Color
+ +
+ +
Value Color
+ +
+ +
Icon Color
+ +
Mappings
- +
Add Child Widget
@@ -101,8 +117,20 @@ + + + + + + + + + + + + - + @@ -176,7 +204,7 @@