Intial Commit
2
nodered/rootfs/data/node_modules/node-red-dashboard/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
24
nodered/rootfs/data/node_modules/node-red-dashboard/.jscsrc
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"fileExtensions": [ ".js", "jscs" ],
|
||||
"excludeFiles": [ "node_modules/**" ],
|
||||
"validateIndentation": 4,
|
||||
"disallowKeywordsOnNewLine": [],
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowMultipleSpaces": {"allowEOLComments": true},
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
"disallowTabs": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"requireCurlyBraces": true,
|
||||
//"requireKeywordsOnNewLine": ["else", "catch"],
|
||||
//"requireSemicolons": true,
|
||||
//"requireSpaceAfterBinaryOperators": true,
|
||||
//"requireSpaceAfterComma": {"allExcept": ["trailing"]},
|
||||
"requireSpaceAfterKeywords": ["do","for","if","else","switch","case","try","while"],
|
||||
"requireSpaceBeforeBlockStatements": 1,
|
||||
"requireSpaceBeforeObjectValues": false,
|
||||
"requireSpacesInForStatement": true,
|
||||
"requireSpacesInFunction": { "beforeOpeningCurlyBrace": true },
|
||||
//"validateParameterSeparator": ", ",
|
||||
//"validateQuoteMarks": false,
|
||||
"maximumLineLength": 300
|
||||
}
|
||||
2
nodered/rootfs/data/node_modules/node-red-dashboard/.jshintignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules/
|
||||
dist/
|
||||
16
nodered/rootfs/data/node_modules/node-red-dashboard/.jshintrc
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
//"undef": true, // require all non-globals to be declared
|
||||
"asi": true, // allow missing semicolons
|
||||
"curly": true, // require braces
|
||||
"eqnull": true, // ignore ==null
|
||||
"forin": true, // require property filtering in "for in" loops
|
||||
"immed": true, // require immediate functions to be wrapped in ( )
|
||||
"nonbsp": true, // warn on unexpected whitespace breaking chars
|
||||
//"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
|
||||
//"unused": true, // Check for unused functions and variables
|
||||
"loopfunc": true, // allow functions to be defined in loops
|
||||
//"expr": true, // allow ternery operator syntax...
|
||||
"sub": true, // don't warn that foo['bar'] should be written as foo.bar
|
||||
"proto": true, // allow setting of __proto__ in node < v0.12
|
||||
"esversion": 6 // allow es6
|
||||
}
|
||||
853
nodered/rootfs/data/node_modules/node-red-dashboard/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,853 @@
|
||||
### 2.19.3: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let dropdown status show selected label rather than value.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix notification to send cancel instead of OK when dismissed by blank message.
|
||||
- Fix Angular theme reverting to light in menu. Issue #554
|
||||
|
||||
### 2.19.2: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Revert dropping of angular material icons with animation. Issue #552
|
||||
|
||||
### 2.19.1: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Self host Material Icons Font - PR #550
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Adjust Gauge title spacing.
|
||||
|
||||
### 2.19.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let ui_form node accept input to prefill, and add multiline text
|
||||
- Let dialog be removed by blank message.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix undocumented change to justgage custom sectors api. Issue #547
|
||||
|
||||
### 2.18.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Update justgauge to latest (now maintained) version and drop monkeypatch. Issue #535.
|
||||
- Add engines node8 to package.json
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Stop propagation of swipe when using color picker - Issue #539
|
||||
- Handle tab names with multiple spaces in for hide/show - Issue #541
|
||||
- Update gulpfile.js to gulp 4 - Issue #542
|
||||
- Fix numeric step rounding when changed by ui_control
|
||||
|
||||
### 2.17.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Add warning re missing order property in custom widget nodes
|
||||
- Fix notifications. Issue #537.
|
||||
|
||||
### 2.17.0: Milestone Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Better vertical align larger button icons if supplied via label text
|
||||
- Fix ui_notification node to not accept raw HTML by default, add option to allow.
|
||||
|
||||
### 2.16.3: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- If template has height -1 then set it to 0 height (test).
|
||||
- Add wrap value feature to numeric node.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Ensure widgets handle undefined msg parts for labels etc.
|
||||
- Fix scrollbar theming inside template.
|
||||
- Ensure msg.topic really doesn't exist if not specified, for all ui nodes. Was PR #531
|
||||
- Backlevel less package to fix IE11 loading, Issue #530
|
||||
|
||||
### 2.16.2: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Ui-control can be set to only report connect events, or change tab events.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Stop slider sending twice (after fixing endstop issue below). Issue #527
|
||||
- Fix Theme colour swatch size.
|
||||
|
||||
### 2.16.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix toast to show border correctly and better timing. Issue #525
|
||||
- Stop colour picker sending on page refresh. Issue #514
|
||||
- Fix layout tool group locations. PR #526
|
||||
- Fix slider not sending if past end of widget.
|
||||
|
||||
### 2.16.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add Dashboard Layout tool - Major contribution - Thanks @KazuhiroItoh - PR #482
|
||||
- Add ui.isDark() returns true/false if overall theme is dark or light, so the widget could switch appropriately. (can already use getTheme() to get actual colors if needs be.)
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Make spacer transparent so background is really the background.
|
||||
- Fix text_input to only send duplicates if enter key hit multiple times and not on loss of focus. Issue #513
|
||||
- Fix color-picker to not emit on tab change, and fix background overlay. Issue #514
|
||||
- Fix IE11 loading issue #515 (reversion)
|
||||
- Improve embedded node-red dashboard full path resolve - Issue #517
|
||||
- Let ui-form input be full width on IE11 - Issue #524
|
||||
|
||||
### 2.15.5: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add compression middleware by default to speed up loading. Thanks @zyrorl
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix legend to keep items hidden when new data arrives. Issue #507
|
||||
- Re-re-fix switch to not show correct icon despite passthru, and toggle output correctly. Issue #506
|
||||
- Make Dialog and Toast be more consistent
|
||||
- Fix odd gauge behaviour when in donut mode
|
||||
- Fix UI redraw (not redrawing when changing tabs). PR #508
|
||||
- Fix vertical slider in only on release mode
|
||||
- Let webfont loader be async to not delay page load when offline, and fail silently
|
||||
- Fix Datepicker to honour Site date format
|
||||
- Tweak passthrough option wording to try to match what actually happens
|
||||
- Fix text-input to only send one message when using tab key to move fields
|
||||
|
||||
### 2.15.4: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add CSS variable names for main theme colours to make user customisations easier
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Re-fix switch to not visibly switch when set to show input not output. Issue #506
|
||||
- Fix colour swatch widths in ui_chart and ui_gauge.
|
||||
|
||||
### 2.15.3: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let ui_template use full screen editor (when used with NR 1.0)
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix slider css so numbers stay visible when in "on release only" mode
|
||||
- Fix switch to show correct state for late connecting clients. Issue #497
|
||||
- Fix button to show correct state for late connecting clients. Issue #499
|
||||
- Fix sidenav to ensure colour picker is behind it. Part of issue #492
|
||||
- Better contrast for sidebar menu buttons to work across themes. Issue #500
|
||||
- Revert colour picker to its default design with colour + lightness, add square option, and fix cursor. Issue #502
|
||||
- Fix slider discrete mode to align better, blend theme better and not hide thumb. Issue #503
|
||||
- Fix button to return to original colour on loss of focus. Issue #504
|
||||
|
||||
### 2.15.2: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix legend being visible when it should not be. Issue #494
|
||||
- Fix ui_text_input time mode to accept and passthrough input correctly. Issue #495
|
||||
- Fix theme to better handle new ui_list node switch styles.
|
||||
|
||||
### 2.15.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix built in fa-icons font paths
|
||||
|
||||
### 2.15.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Allow ui_chart to have many more options set by control message, see [config-fields.md](config-fields.md)
|
||||
- Allow `ui.middleware` in settings.js to specify middleware for use with dashboard endpoint. See [PR #209](https://github.com/node-red/node-red-dashboard/pull/209/) for example usage.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Ensure `msg.enabled` applies to all themes. Issue #481
|
||||
- Ensure theme applies to popup dialog alerts also.
|
||||
- Ensure slider only sends on mouse up when in that mode. Issue #490
|
||||
|
||||
### 2.14.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Allow Tabs to be hidden or disabled dynamically from a ui_control msg.
|
||||
- Finally remove deprecated second output from ui_chart node.
|
||||
- Allow ui_form to be submitted with empty fields (if they are not required)
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Don't try to close non-existent menu at start (logging issue only) - Issue #470
|
||||
- Add startsWith polyfill for IE11
|
||||
- Ensure active sidebar menu item is highlighted - Issue #472
|
||||
- Sanitise display of html input - Issue #473
|
||||
- Respect msg.socketid to return msg back to selected session when using ui_template
|
||||
- Allow dropdown to have 0 pre-configured values, by removing validation.
|
||||
|
||||
### 2.13.2: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Revert change that broke gauge pointer colours
|
||||
|
||||
### 2.13.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix ui_template to return correct sessionid to each browser.
|
||||
- Fix line chart xAxis hover to use same time format as main axis
|
||||
- Fix chart colours to have more than 9 colours just in case - Issue #465
|
||||
- Remove circular ref in menu that caused problems with 0.20 beta
|
||||
- Let ui_text node send data onBlur when in wait for key mode
|
||||
- Update Angular dependency to 1.7.6 - Issue #462
|
||||
- Add X-UA-Compatible tag to help to get IE-11 to behave
|
||||
- Fix css to use numerics not incorrect name - Issue #469
|
||||
|
||||
### 2.13.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add ability to hide and/or disable tabs manually - PR #456
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix up ui_text toString mishandling error - Issue #459
|
||||
- Add some undo capability to ordering of widgets - Issue #461
|
||||
|
||||
### 2.12.2: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Revert change to button and switch typed inputs - Issue #455
|
||||
- Fix handling of {{msg.property}} handling for labels
|
||||
|
||||
### 2.12.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Ensure spacer actually gets created with no users
|
||||
|
||||
### 2.12.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Introduce concept of spacer nodes in groups to allow more widget layout options
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Set order value correctly for newly added ui nodes
|
||||
- Let ui_text node handle buffers without mangling to utf8
|
||||
- Fix ui_template info odd/even example to work again (after theme changes)
|
||||
- Ensure colour picker retains old value on multiple reloads when in dynamic mode - Issue #452
|
||||
- Fix missing page titles (mea culpa) - Issue #453
|
||||
|
||||
### 2.11.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let side menu be locked open via site config tab - Issue #446
|
||||
- Let audio playback node show status in editor for debug
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix button background CSS so it can be over-ridden - Issue #444
|
||||
|
||||
### 2.10.1: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let slider only send on mouse release (discrete mode)
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Stop background path css escape for gauge
|
||||
- Fix radar chart so it picks up theme - Issue #443
|
||||
|
||||
### 2.10.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add PR to allow pluggable widgets. PR #427
|
||||
- see https://github.com/node-red/node-red-dashboard/wiki/Creating-New-Dashboard-Widgets
|
||||
- Let users use 100% Angular theme if desired.
|
||||
- Add footer div with id nr-dashboard-footer to make targeting easier.
|
||||
- Add Japanese translations for ui_control node. PR #439
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Add polyfill for IE11 Object.assign. Issue #402
|
||||
- Tweak colour picker to default to solid colours
|
||||
- Fix up ng-click colours in list. Issue #433
|
||||
|
||||
### 2.9.8: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Tidy up dashboard widget list if widget moved then renamed. Issue #426
|
||||
- Let numeric widget handle angular filters again for value. Issue #428
|
||||
|
||||
### 2.9.7: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let link specify existing tab. Issue #420
|
||||
- Let bar charts specify legend if required. Issue #423
|
||||
- Add more links to lists of icons available.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Ensure old forms Submit/Cancel buttons still display a value.
|
||||
- Let internal form elements scale more appropriately with grid size. Issue #416
|
||||
- Adjust slider timing to try to better smooth output
|
||||
|
||||
### 2.9.6: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Update socket.io to remove audit vulnerability. Issue #411
|
||||
|
||||
### 2.9.5: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Remove colour from button when in template in no style mode. Issue #400
|
||||
- Fix format support for numeric widget. Issue #401
|
||||
- Fix min-width of dropdown label field. Issue #405
|
||||
- Let blank value field in gauge NOT display the value text (default to payload). Issue #406
|
||||
- Let form buttons have changeable text. Issue #408
|
||||
|
||||
### 2.9.4: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Let text input node handle floating point input when in numeric mode. Issue #391
|
||||
- Fix incorrect scoping of colour palettes in charts. Issue #396
|
||||
- Docs updates re some of the ui_control to make groups show/hide.
|
||||
|
||||
### 2.9.3: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Revert change to sessionStorage - better fix for Issue #386, unfix Issue #384
|
||||
|
||||
### 2.9.2: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Let dropdown edit config, scale more sensibly on slide out.
|
||||
- Change to sessionStorage to mitigate httpAuth issue. Issue #384
|
||||
- Ensure groups are restored rather than completely disappeared on refresh. Issue #386
|
||||
- Let bar charts also auto scale negative values. Issue #387
|
||||
- Use rounded line joins on charts to reduce spiky-ness.
|
||||
- Ensure numeric input matches theme (now that it is editable)
|
||||
- Fix Gauge so {{ format }} works again.
|
||||
|
||||
### 2.9.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Let dashboard work if localstorage not available. PR #383
|
||||
- Let numeric field also be editable
|
||||
- Clean up gauge value (to be more as previously). Issue #385
|
||||
|
||||
### 2.9.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Allow groups to be hidden and made visible via ui_control {group:{hide:["tab_name_group_name_with_underscores"],show:["another_group"],focus:true}}
|
||||
- Allow `readOnly:true` in settings.js `ui` section to disable all input to dashboard.
|
||||
You can still click/type but nothing gets sent to backend.
|
||||
- Add "No theme in ui_template" option to site options to allow regular angular theme through. Issue #379
|
||||
- Add option to remove hue slider from color-picker
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Monkeypatch fix for Justgage negative numbers. Issue #113
|
||||
- Ensure toast is a string.
|
||||
- Clean up require of tinycolor2. Issue #367
|
||||
- Allow numeric input in form to accept floating point numbers. Issue #368
|
||||
- Fix small wrinkle in reset of head elements on reload
|
||||
- Fix Use of object assign for IE11. Issue #372
|
||||
- Fix button background colour for IE11. Issue #373
|
||||
- Let Gauge display invalid value as text, and set pointer to minimum value rather than 0
|
||||
- Fix date picker width to stop css overrides. Issue #378
|
||||
- Try to resolve blurred charts. Issues #302 and #380
|
||||
|
||||
### 2.8.2: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let Gauge units be specified by msg {{property}}
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Better fix for numeric field widths. Issue #344
|
||||
- Fix some theme <-> library consistency issues
|
||||
- Clean up old line chart data from other topics after 60s. Issue #342 and #360
|
||||
|
||||
### 2.8.1: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let Gauge widget accept {{payload.foo.bar}} style property input
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix references to FontAwesome to pin to version 4.7.0 icons
|
||||
- Give numeric field a width so buttons don't wobble (so much). Issue #344
|
||||
- Let gauge change labels more dynamically
|
||||
- ensure dateFormat defaults to something valid
|
||||
|
||||
### 2.8.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Allow groups to be collapsed (extra option in group config) - PR #333 Issue #73 and #177
|
||||
- Add a bit more status to switch, slider, numeric and dropdown - Issue #335
|
||||
- Add vertical slider capability if height > width
|
||||
- Add scope.theme to ui_template scope to allow users to pick up default colours
|
||||
- Add scope watch example to ui_template info panel
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix text time input format to report in milliseconds from local midnight
|
||||
- Fix change tab event to report correctly when switching to tab 0
|
||||
- Fix template editor minimum height so always visible
|
||||
- Fix sanitise notification html input, but allow basic markup.
|
||||
|
||||
### 2.7.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add initial manifest.json capability for Android add to home screen
|
||||
- Add weather-icons-lite font - may finally close #165
|
||||
- Let boolean false values also create gaps in charts (as well as null)
|
||||
- Add status to switch widget (and slider, numeric and dropdown) - Issue #314
|
||||
- Add "welcome" page to blank dashboard - Issue #318
|
||||
- Add i18n for base pages (thanks Nishiyama-san)- PR #315
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix tab to send data from text entry field - Issue #307
|
||||
- Fix colour picker hex output/passthrough - Issue #308
|
||||
- Ensure there is a base tab to switch to at start - Issue #310
|
||||
- Constrain changetab event when starting up with blank dashboard
|
||||
- Update ui-masonry to fix layouts - PR #312
|
||||
- Fix path join for icon link to dashboard - Issue #319
|
||||
|
||||
### 2.6.2: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix problem with partial deploy - Issue #279
|
||||
- Remove `msg.` option from Button as makes no sense without node context - Issue #301
|
||||
- Better handling of empty data series in chart data
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add time option to text input widget.
|
||||
- Let colour picker optionally send outputs as they change - Issue #299
|
||||
|
||||
### 2.6.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix "connection lost" on initial load - Issue #298
|
||||
|
||||
### 2.6.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let widgets have properties set by `msg.ui_control` object - see config-fields.md - Issue #235
|
||||
- Let charts lines have gaps by sending null as payload.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix TTS to pick correct voice at start - Issue #291
|
||||
- Fix TTS to try to select similar voice across different browsers - Issue #292
|
||||
- Fix chart colours to re-initialise correctly on refresh - Issue #296
|
||||
|
||||
### 2.5.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix chart reference to 0.2.5 to the correct 2.5.0 - Issue #281
|
||||
- Fix line chart legend back to top and shrink colour swatch size - Issue #283
|
||||
- Fix bar chart colours to be like previous style
|
||||
- Fix blank array to clear out old and new style charts
|
||||
- Slight chart positioning adjustment
|
||||
|
||||
### 2.5.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let ui_chart use chart.js style data array - faster, better data import/export, allow insert of data with `msg.timestamp`, bar chart supports multiple series using `msg.series` - Issues #261, #224, #144
|
||||
- Let chart accept non-timeseries array of data (just y values)
|
||||
- Let chart set x-axis labelling to automatic to try to best guess time units
|
||||
- Let widget size be specified by typed input as well as drag PR #270
|
||||
- Allow button to set colour and background colour via msg properties #275
|
||||
- Add browser side locale support for charts and datepicker number and date formatting.
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix ui_template msg.template lost on reload - Issue #266
|
||||
- Fix notification popup displays incorrect topic - Issue #269
|
||||
- Let switch label be set my message even if payload same as previously -Issue #274
|
||||
- Clean up any extra ui_base nodes that get imported - Issue #273
|
||||
- Make sure dropdown doesn't pass through when set not to pass-through - Issue #276
|
||||
|
||||
### 2.4.3: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add links to web pages of icons to Tab info
|
||||
- Let alerts contain html content - Issue #253
|
||||
- Let bar charts use same colour for all bars
|
||||
|
||||
**Fixes**s
|
||||
|
||||
- Set y-Axis scale if max and min set to stop overlapping labels
|
||||
- Make input field and justgage font match theme font choice
|
||||
- Fix icon position for min fab buttons - PR #255
|
||||
- Redo update logic on tab change - Issue #256
|
||||
|
||||
### 2.4.2: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Let ui_chart enlarge points so they are visible dots
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Revert version of socket.io to keep working on node.js v0.10....
|
||||
|
||||
### 2.4.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix location for fa-icons
|
||||
- Make Tabs/Links window correctly expandable on Firefox
|
||||
|
||||
### 2.4.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add ability to specify basefont style. (NOTE the Cross Platform font uses a
|
||||
system font stack approach that should look good across as many platforms as possible)
|
||||
- Merge tabs and links so all can be re-ordered - PR #234
|
||||
- Let labels handle multiple properties (like payload and colour)
|
||||
- Add possibility to use a template node to add or replace content inside <head> tag. PR #239
|
||||
- Adjust Form widget spacing to line up with other widgets
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Simpler, better date injection to preset date-picker
|
||||
- Let switch resize after being set to 1x1
|
||||
|
||||
### 2.3.11: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add name of tab to ui_control node tab change msg
|
||||
- Let dropdown use value as label if not otherwise specified
|
||||
- Add label field to date-picker
|
||||
- Adjust labels spacing on gauges to look better at small sizes
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Make sure chart display is fully refreshed on tab change - Issue #226
|
||||
- Catch another possible missing theme escape path.
|
||||
- Fix msg. label regression for ui_text node - Issue #230
|
||||
- Retain enable/disable state of widgets (broken in 2.3.10)
|
||||
- Fix name-spacing of base node inputs
|
||||
- Fix custom theme to default back to previous setting
|
||||
|
||||
### 2.3.10: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Make fixup of Font Awesome fonts easier for developers
|
||||
- Let the Wave gauge display units if you wish
|
||||
- Add *change* tab event to ui_control output and also accept +1 and -1 to move to next/prev tab - Issue #194
|
||||
- Let label field be set by a {{msg.property}} (for all widgets with label field) - Issue #220
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Unbreak change made in 2.3.9 that dropped all msg with no payload.
|
||||
- add passthru flag to button (as per other nodes) - Issue #211
|
||||
- fix bad number conversion for slider (and other nodes), if payload not set - Issue #212
|
||||
- now returns undefined which leaves UI unchanged, but passes through msg
|
||||
- Fix bar charts not being cleared properly by [] - Issue #217
|
||||
- Fix Node-RED crashing on chart bad data input conversion - Issue #218
|
||||
|
||||
### 2.3.9: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Dashboard Tab - still occasionally empty (for old dashboard migrations)
|
||||
- Add CSS to try to help fix scroll of Edge Mobile devices - Issue #207
|
||||
- Fix Apple Touch Icon - Issue #208
|
||||
- Fix widget sy height (was picking up sx by mistake) - Issue #210
|
||||
- Don't let widget bother handle msg with no payload (only handle enabled) - Issue #211, #212
|
||||
|
||||
### 2.3.8: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add keyboard shortcut to menu of shortcuts (ctrl-shift-d - Show Dashboard)
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Critical Fix : for Dashboard tab not populating on initial empty flow
|
||||
|
||||
### 2.3.7: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Stop rendering datapoints out of range on line charts - Issue #198
|
||||
- Let dropdown placeholder text be editable - Issue #202
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Let date-picker survive changes of tabs - Issue #189
|
||||
- Change text input box to detect tab to send data (rather than loss of focus) - Issue #196
|
||||
- Update Site properties in UI when theme loaded from library - Issue #197
|
||||
- Fix audiocontext to reuse existing - Issue #199
|
||||
- Better align text input and dropdown text inputs - Issue #201
|
||||
- Let ui be hosted at / if required - Issue204
|
||||
- Let bar and pie charts be reloaded correctly from saved data - Issue #205
|
||||
- Let base colour theme edits work again (rather than resetting all the time)
|
||||
|
||||
### 2.3.6: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- let ui_gauge sector sizes be specified
|
||||
- sending tab change of "" to ui_control refreshes current page
|
||||
- let button widget pass messages (or be triggered by input)
|
||||
- enhance gulp, jshint and jscs checks
|
||||
- Hide page *title* tag until actually set
|
||||
- add optional i18n.js file to dist
|
||||
- optionally let switch status be set by input/feedback rather than press - PR #188
|
||||
|
||||
**Fixes**
|
||||
|
||||
- stop numeric widget emitting on accidental mouseover
|
||||
- text input will now send it's payload on losing focus as well as enter (if in enter mode)
|
||||
- fix form colours to be more dynamic to match theme, Issue #186
|
||||
|
||||
### 2.3.5: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- let numeric (and slider) widget accept floating point presets if step set appropriately Issue #185
|
||||
- initialises OK if absolutely no theme present from old flow
|
||||
- knock the corners off homescreen icon
|
||||
|
||||
### 2.3.4: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add IOS homescreen icon link - PR #176
|
||||
- Let datepicker accept timestamp input to preset date.
|
||||
- Don't react to swipe in charts, or slider
|
||||
|
||||
**Fixes**
|
||||
|
||||
- move to ngTouch rather than mdTouch to fix swipe/scroll Issue #164
|
||||
- correct data output format from bar chart type chart - fixes Issue #181
|
||||
- prevent button forwarding input messages as it makes no sense. - PR #170
|
||||
- correct select box example - PR #182
|
||||
- fix compass colour to be set by custom widget colour
|
||||
- centre icon in button widget
|
||||
|
||||
### 2.3.3: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix saving of named custom themes
|
||||
- Fix dashboard link icon not appearing for FF and Safari
|
||||
- Default old text colours so they are visible
|
||||
|
||||
### 2.3.2: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Stop light and dark colour reset icon repeating on tab changes
|
||||
- Let colour helper library load from editor side
|
||||
- Better height detection (or lack of) for template nodes
|
||||
- Catch ui_gauge initialisation errors
|
||||
|
||||
### 2.3.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fix gauge initialisation for upgrading dashboard version
|
||||
|
||||
### 2.3.0: Milestone Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add Themes to Dashboard Tab - includes colour and sizes and other options - Issue #137
|
||||
- Colour-picker - add configurable lightness slider - PR #123
|
||||
- Configurable colour for Notification toasts - Issue #145
|
||||
- Remove whitespace from above gauge with no label - Issue #159
|
||||
- Let gauge widgets scall larger when basic unit size increased - Issue #162
|
||||
- Let most labels show icons if required (via html <i syntax)
|
||||
- Add date-picker widget - Issue #14
|
||||
- Give audio node option to play when not in focus - Issue #167
|
||||
|
||||
**Fixes**
|
||||
|
||||
- also check template for existence of sole <link tag : if so set height to 0
|
||||
- ensure ui_base node has a user to prevent node appearing in "unused" config nodes tab - Issue #110 - actually fixed in core for 0.16.1
|
||||
- chart no longer emits a blank array on start (which was wiping out file storage of data)
|
||||
- link tabs were stuck at light theme - now follow overall theme correctly - Issue #149
|
||||
- fixed numeric widget to not have rounding error, and also occasional stall/hang - Issue #150
|
||||
- fixed numeric widget not starting at min value - Issue #163
|
||||
- dashboard root path re-write from UI now working
|
||||
- remove .res and .req properties of msg in case they have circular refs - Issue #153
|
||||
- make dropdown widget arrow, chart gridlines, match theme
|
||||
- remove .req and .res properties to remove problems with circular references
|
||||
|
||||
### 2.2.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Gauges now scale properly on IE9/10/11 and Edge
|
||||
- Increase chart size to better fill available space
|
||||
- Fix colour-picker touch support (temporary patch while awaiting upstream fix)
|
||||
- Fix slight transparency issue on select dropdown
|
||||
- Small changes to colour-picker styling
|
||||
- Allow use of wi and icofont icon families (only if loaded externally via ui_template)
|
||||
- Fix for overlapping last X-axis label (temporary while fixed upstream)
|
||||
|
||||
### 2.2.0: Milestone Release
|
||||
|
||||
**License change**
|
||||
|
||||
- Change of license copyright to Javascript Foundation
|
||||
|
||||
**Deprecated**
|
||||
|
||||
- Second output from chart node - use the `ui_control node` instead. This will emit both *connect* and *lost* messages for each client that connects or loses connection. The 2nd output from the chart node will eventually be removed in a future release.
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Replace nvd3 charts with **charts.js** charts - to fix various issues
|
||||
- Add pie chart and horizontal bar chart options to new charts.js based widget
|
||||
- Add ui_colour_picker widget to palette
|
||||
- Add ui_audio out widget for wav, mp3 and TTS to Dashboard
|
||||
- Add step option to ui_numeric input widget
|
||||
- Add background colour setting to ui_button widget
|
||||
- ui_control emits "connect" and "lost" messages for client id and ip.
|
||||
- Add OK/Cancel Dialog mode to ui_notification widget, if msg.socketid is present the notification will only go to that client.
|
||||
- All ui elements now also emit `msg.socketid`
|
||||
- bumped fa-icons version to 4.7.0
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Replace nvd3 charts with charts.js charts - to fix various issues
|
||||
- change link `_new` refs to `_blank` to be standards compliant
|
||||
- fix fa icons default size so fixed width matches material icons width (24px)
|
||||
- bump sockets.io version
|
||||
- fixed dropdown generating messages when opening tab
|
||||
|
||||
|
||||
### 2.1.0: Milestone Release
|
||||
|
||||
**License change**
|
||||
|
||||
- Change of license from MIT to Apache-2.0 to be in line with other Node-RED projects
|
||||
(approved by all contributors)
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Complete re-write of group layout code to stop overlapping issues
|
||||
- Add ui_form widget to submit complete form in one go
|
||||
- Add swipe left/right between tabs
|
||||
- Add "comms lost" toast when connection lost to server
|
||||
- Add allow formatting of chart x-axis date formatting
|
||||
- Let ui_numeric, ui_textinput and ui_dropdown also control passthru of incoming values
|
||||
- Add step size option to ui_slider widget to allow floating point numbers more easily
|
||||
- Allow switch label to be dynamically set by msg input
|
||||
- Add Dashboard version number to console.log on start
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Fill dark background more completely
|
||||
- Fix CSS sizing for Safari 10
|
||||
- Let ui_dropdown pass through payload values
|
||||
- Let dashboard open iframes again (if allowed by remote site)
|
||||
- Stop double scrollbars appearing on internal frames
|
||||
- Stop ui_control causing missing group prompt
|
||||
- Fix missing sidenav "left" item on initial page load
|
||||
- Fix enter key to work for ui_textinput on FF
|
||||
- Fix groups sizes to display border correctly on FF
|
||||
- Fix dropdown select types
|
||||
- Fix switch to only switch if input value matches on and off values
|
||||
|
||||
|
||||
### 2.0.2: Maintenance Release
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- Add password entry option to text input
|
||||
- Add basic colour names to themes
|
||||
- Let slider and switch optionally not pass through messages
|
||||
- Add time formatter to chart x-Axis
|
||||
- Add ui_control widget to allow dynamic tab switch
|
||||
- Chart will warn every 1000 points (not a fix for too much data but just a hint :-)
|
||||
- Allow dropdown to be configured by passed in options
|
||||
- Allow text widget to optionally wait for enter key
|
||||
- Allow msg.enabled=false to disable any widget
|
||||
- Change dark theme so groups look flat (no widget borders)
|
||||
- Add bar chart mode to graph widget
|
||||
- Change template widget so default is to accept passed in html
|
||||
- Allow Gauge 3 colour ranges to be set
|
||||
- Allow Toast notification position to be set
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Relax auto-creation of ui_base
|
||||
- Handle imported flows properly when updating sidebar tree
|
||||
- Maintain expand/collapse states of sidebar tree on refresh
|
||||
- Make sure gauge colours default even if theme broken
|
||||
- Fix template editor auto height sizing to fill window
|
||||
- Template node better height auto detection (but only if in auto size mode)
|
||||
- Better layout alignment for groups on wide and narrow screens
|
||||
- Allow msg with no payload to be handled
|
||||
|
||||
|
||||
### 2.0.1: Maintenance Release
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Sorting groups/tabs in sidebar not sticking
|
||||
- Tidy up auto-generation of ui_base node
|
||||
|
||||
|
||||
### 2.0.0: Milestone Release
|
||||
|
||||
- First release published to npm
|
||||
60
nodered/rootfs/data/node_modules/node-red-dashboard/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
# Contributing to Node-RED-Dashboard
|
||||
|
||||
We welcome contributions, but request you follow these guidelines.
|
||||
|
||||
- [Raising issues](#raising-issues)
|
||||
- [Feature requests](#feature-requests)
|
||||
- [Pull-Requests](#pull-requests)
|
||||
- [Contributor License Agreement](#contributor-license-agreement)
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable
|
||||
behaviour to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
|
||||
|
||||
## Raising issues
|
||||
|
||||
Please raise any bug reports on the relevant project's issue tracker. Be sure to
|
||||
search the list to see if your issue has already been raised.
|
||||
|
||||
A good bug report is one that make it easy for us to understand what you were
|
||||
trying to do and what went wrong.
|
||||
|
||||
Provide as much context as possible so we can try to recreate the issue.
|
||||
If possible, include the relevant part of your flow. To do this, select the
|
||||
relevant nodes, press Ctrl-E and copy the flow data from the Export dialog.
|
||||
|
||||
At a minimum, please include:
|
||||
|
||||
- Version of Node-RED-Dashboard - either release number if you downloaded a zip, or the first few lines of `git log` if you are cloning the repository directly.
|
||||
- Version of Node-RED - either release number if you downloaded a zip, or the first few lines of `git log` if you are cloning the repository directly.
|
||||
- Version of node.js - what does `node -v` say?
|
||||
|
||||
## Feature requests
|
||||
|
||||
For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red).
|
||||
|
||||
## Pull-Requests
|
||||
|
||||
If you want to raise a pull-request with a new feature, or a refactoring
|
||||
of existing code, it may well get rejected if you haven't discussed it on
|
||||
the [mailing list](https://groups.google.com/forum/#!forum/node-red) first.
|
||||
|
||||
### Contributor License Agreement
|
||||
|
||||
All contributors need to sign the JS Foundation's Contributor License Agreement.
|
||||
It is an online process and quick to do. You can read the details of the agreement
|
||||
here: https://cla.js.foundation/node-red/node-red.
|
||||
|
||||
If you raise a pull-request without having signed the CLA, you will be prompted
|
||||
to do so automatically.
|
||||
|
||||
### Coding standards
|
||||
|
||||
Please ensure you follow the coding standards used through-out the existing
|
||||
code base. Some basic rules include:
|
||||
|
||||
- indent with 4-spaces, no tabs. No arguments.
|
||||
- opening brace on same line as `if`/`for`/`function` and so on, closing brace
|
||||
on its own line.
|
||||
- There are **.jshintrc** and **.jscsrc** files included in the project which
|
||||
should be used to help formatting.
|
||||
106
nodered/rootfs/data/node_modules/node-red-dashboard/Charts.md
generated
vendored
Normal file
34
nodered/rootfs/data/node_modules/node-red-dashboard/ISSUE_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<!--
|
||||
## Before you hit that Submit button....
|
||||
|
||||
This issue tracker is for problems with the Node-RED-Dashboard only.
|
||||
|
||||
If your issue is:
|
||||
- a general 'how-to' type question,
|
||||
- a feature request or suggestion for a change
|
||||
|
||||
please use the Dashboard category in the [Node-RED Forum](https://discourse.nodered.org) or [slack team](https://nodered.org/slack).
|
||||
|
||||
You could also consider asking a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/node-red) and tag it `node-red`.
|
||||
|
||||
That way the whole Node-RED user community can help, rather than rely on the core development team.
|
||||
|
||||
## So you have a real issue to raise...
|
||||
|
||||
To help us understand the issue, please fill-in as much of the following information as you can:
|
||||
-->
|
||||
|
||||
### What are the steps to reproduce?
|
||||
|
||||
### What happens?
|
||||
|
||||
### What do you expect to happen?
|
||||
|
||||
### Please tell us about your environment:
|
||||
|
||||
- [ ] Node-RED-Dashboard version:
|
||||
- [ ] Node-RED version:
|
||||
- [ ] node.js version:
|
||||
- [ ] npm version:
|
||||
- [ ] Platform/OS:
|
||||
- [ ] Browser:
|
||||
15
nodered/rootfs/data/node_modules/node-red-dashboard/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
Copyright 2016,2019 JS Foundation and other contributors, https://js.foundation/
|
||||
Copyright 2016 IBM Corp.
|
||||
Copyright 2015 Andrei Tatar
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
202
nodered/rootfs/data/node_modules/node-red-dashboard/README.md
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
# node-red-dashboard
|
||||
|
||||

|
||||
[](https://badge.fury.io/gh/node-red%2Fnode-red-dashboard)
|
||||
[](https://img.shields.io/github/license/node-red/node-red-dashboard.svg)
|
||||
|
||||
This module provides a set of nodes in Node-RED to quickly create a live data dashboard.
|
||||
|
||||
These nodes require node.js version 8. The last version to support node v6 was 2.9.5.
|
||||
|
||||
From version 2.10.0 you can create and install widget nodes like other Node-RED nodes.
|
||||
See the [Wiki](https://github.com/node-red/node-red-dashboard/wiki/Creating-New-Dashboard-Widgets) for more information.
|
||||
|
||||
For the latest updates see the [CHANGELOG.md](https://github.com/node-red/node-red-dashboard/blob/master/CHANGELOG.md)
|
||||
|
||||

|
||||
|
||||
## Pre-requisites
|
||||
|
||||
The Node-RED-Dashboard requires [Node-RED](https://nodered.org) to be installed.
|
||||
|
||||
## Install
|
||||
|
||||
To install the stable version use the `Menu - Manage palette` option and search for `node-red-dashboard`, or run the following command in your Node-RED user directory (typically `~/.node-red`):
|
||||
|
||||
npm i node-red-dashboard
|
||||
|
||||
Restart your Node-RED instance and you should have UI nodes available in the palette and a new `dashboard` tab in the
|
||||
right side panel. The UI interface is available at <http://localhost:1880/ui> (if the default settings are used).
|
||||
|
||||
If you want to try the latest version from github, you can install it by
|
||||
|
||||
npm i node-red/node-red-dashboard
|
||||
|
||||
## Settings
|
||||
|
||||
The default url for the dashboard is based off your existing Node-RED httpRoot path with /ui added. This can be changed in your Node-RED settings.js file - `ui: { path: "ui" },`
|
||||
|
||||
You can also add your own express middleware to handle requests by using the `ui: { middleware: your_function }` property in settings.js. For example
|
||||
|
||||
```
|
||||
ui: { path: 'ui', middleware: function (req, res, next) {
|
||||
// Do something more interesting here.
|
||||
console.log('LOGGED')
|
||||
next()
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
You can also set the dashboard to be read only by `ui: { readOnly: true }`. This does not stop the user interacting with the dashboard but does ignore all updates coming from the dashboard.
|
||||
|
||||
## Layout
|
||||
|
||||
The dashboard layout should be considered as a grid.
|
||||
|
||||
Each **group** element has a width - by default 6 'units' (a unit is 48px wide by default with a 6px gap).
|
||||
|
||||
Each **widget** in the group also has a width - by default, 'auto' which means it will fill the width of the group it is in, but you can set it to a fixed number of units.
|
||||
|
||||
The layout algorithm of the dashboard always tries to place items as high and to the left as they can within their container - this applies to how groups are positioned on the page, as well as how widgets are positioned in a group.
|
||||
|
||||
Given a group with width 6, if you add six widgets, each with a width of 2, then they will be laid out in two rows - three widgets in each.
|
||||
|
||||
If you add two groups of width 6, as long as your browser window is wide enough, they will sit alongside each other. If you shrink the browser, at some point the second group will shift to be below the first, in a column.
|
||||
|
||||
It is advisable to use multiple groups if possible, rather than one big group, so that the page can dynamically resize on smaller screens.
|
||||
|
||||
## Features
|
||||
|
||||
#### Dashboard sidebar
|
||||
|
||||
The widget layout is managed by a `dashboard` tab in the sidebar of the Node-RED editor.
|
||||
|
||||
##### Layout
|
||||
|
||||
- **Tabs** - From here you can re-order the tabs, groups and widgets, and add and edit their properties.
|
||||
|
||||
- **Links** - to other web pages can also be added to the menu. They can optionally be opened in an iframe - if allowed by the target page.
|
||||
|
||||
##### Site
|
||||
|
||||
- **Title** - the `title` of the UI page can be set.
|
||||
|
||||
- **Options** - optionally hide the title bar, and allow swiping sideways between tabs on a touch screen. You can also set whether the template uses the selected theme or uses the underlying Angular Material theme. You can also choose to use the Angular Material theme everywhere.
|
||||
|
||||
- **Date Format** - sets the default date format for chart and other labels.
|
||||
|
||||
- **Sizes** - sets the basic geometry of the grid layout in pixels. The **width** and **height** of widgets can be set, as can the width of *groups*. These are the basic definitions of the "units' used elsewhere within the dashboard.
|
||||
|
||||
##### Theme
|
||||
|
||||
- **Style** - the theme and font of the UI is set in the dashboard sidebar. You can select a default Light, Dark or Custom Theme. You cannot have different themes for each tab.
|
||||
|
||||
You can also choose to use the basic Angular Material themes instead if you like, either just within any ui_templates or for the whole Dashboard. This will only affect angular components so some of the charts and so on may need extra work.
|
||||
|
||||
**Note**: For users creating their own templates the following CSS variable names are available
|
||||
to help pick up the theme colours.
|
||||
|
||||
- --nr-dashboard-pageBackgroundColor
|
||||
- --nr-dashboard-pageTitlebarBackgroundColor
|
||||
- --nr-dashboard-groupBackgroundColor
|
||||
- --nr-dashboard-groupTextColor
|
||||
- --nr-dashboard-groupBorderColor
|
||||
- --nr-dashboard-widgetColor
|
||||
- --nr-dashboard-widgetTextColor
|
||||
- --nr-dashboard-widgetBgndColor
|
||||
|
||||
#### Widgets
|
||||
|
||||
Group labels are optional.
|
||||
|
||||
Most widgets can have a label and value - both of these can be specified by properties of the incoming msg if required, and modified by angular filters. For example the label can be set to `{{msg.topic}}`, or the value could be set to `{{value | number:1}}%` to round the value to one decimal place and append a % sign.
|
||||
|
||||
Each node may parse the `msg.payload` to make it suitable for display. This converted version is exposed as the variable called `value`, (see example above).
|
||||
|
||||
Any widget can be disabled by passing in a `msg.enabled` property set to `false;`. *Note:* this doesn't stop the widget receiving messages but does stop inputs being active and does re-style the widget.
|
||||
|
||||
Most ui widgets can also be configured by using a `msg.ui_control` message - see **[config-fields.md](https://github.com/node-red/node-red-dashboard/blob/master/config-fields.md)**
|
||||
for futher details.
|
||||
|
||||
- **Audio out** - a widget that will let you play audio (wav or mp3) or send Text to Speech (TTS) to the client.
|
||||
- **Button** - the icon can be set using either Material or fa-icons - the colour and background colour may also be set. If the widget is sized to 1 wide the icon has precedence.
|
||||
- **Chart** - has both line, bar and pie chart modes. Also the X-Axis labels can be customised using a date formatter string. See **[this document](https://github.com/node-red/node-red-dashboard/blob/master/Charts.md)** for more information on the chart data formats accepted.
|
||||
- **Colour Picker** - a colour picker widget.
|
||||
- **Date Picker** - a date picker widget. The displayed Date format can be specified in the Site tab using moment.js formatting.
|
||||
- **Dropdown** - a dropdown select widget has been added. Multiple label, value pairs can be specified. The choices can also be set via `msg.options` containing an array of objects. If just text then the value will be the same as the label, otherwise you can specify both by using an object of "label":"value" pairs :
|
||||
|
||||
[ "Choice 1", "Choice 2", {"Choice 3": 3} ]
|
||||
|
||||
Setting `msg.payload` will pre-select the value in the dropdown.
|
||||
- **Form** - a widget that can be composed of several sub-widgets. When submitted all values are submitted as a single message.
|
||||
- **Gauge** - has 4 modes - *standard* (simple gauge), *donut* (complete 360°), *compass*, and *wave*. You can also specify the colour range of the standard and donut gauges.
|
||||
- **Notification** - creates alerts to the user - can either be a toast popup, or a dismissable alert box. The alert may be targeted to a single user.
|
||||
- **Numeric** - a Numeric input widget with up/down buttons.
|
||||
- **Slider** - a simple horizontal slider, with variable step size.
|
||||
- **Switch** - can also set two icons and/or colours depending on state.
|
||||
- **Template** - the template node allows the user to specify and create their own widgets within the framework using HTML, Javascript. This is an Angular.js widget. You may also use this to override the built in CSS styles.
|
||||
- **Text** - A read only widget, the layout of the `label`, and `value` can be configured.
|
||||
- **Text input** - text input box, with optional label, can also support password, email and colour modes.
|
||||
- **UI-Control** - allows some dynamic control of the dashboard. Sending a `msg.payload` of the tab number (from 0) or tab_name will switch to that tab. Tabs can be enabled/disabled/hide/show via msg like `{"tabs":{"hide":["tab_name_with_underscores"],"show":["another_tab_name"],"disable":["unused_tab_name"]}}`.
|
||||
Groups can be hidden and made visible via a msg like `{"group":{"hide":["tab_name_group_name_with_underscores"],"show":["tab_name_another_group"],"focus":true}}`. Outputs a `msg.payload` for every browser *connect* and *loss*, and every tab *change*. This can be used to trigger other actions like resetting the visibility of tabs and groups.
|
||||
|
||||
**Tip:** The *Text* widget will accept html - so you can use it together with the *fa-icons* we
|
||||
already use to create indicator type widgets.
|
||||
|
||||
## Securing the Dashboard
|
||||
|
||||
You can use the `httpNodeAuth` property in your Node-RED settings.js file to secure the Dashboard as it is
|
||||
created the same way as other HTTP nodes are. The details can be found at the bottom of this page in the
|
||||
docs <http://nodered.org/docs/security>
|
||||
|
||||
## Multiple Users
|
||||
|
||||
This Dashboard does NOT support multiple individual users. It is a view of the status of the underlying
|
||||
Node-RED flow, which itself is single user. If the state of the flow changes then all clients will get
|
||||
notified of that change.
|
||||
|
||||
Messages coming from the dashboard **do** have a `msg.socketid`, and updates like change of tab,
|
||||
notifications, and audio alerts will be directed only to that session. Delete the `msg.sessionid` to send
|
||||
to all sessions.
|
||||
|
||||
## Discussions and suggestions
|
||||
|
||||
Use the Node-RED Discourse Forum: https://discourse.nodered.org/c/dashboard
|
||||
or the Dashboard-ui channel in <a href="http://nodered.org/slack/">Slack</a> to ask
|
||||
questions or to discuss new features.
|
||||
|
||||
The current work in progress list is shown in the
|
||||
<a href="https://github.com/node-red/node-red-dashboard/projects/1" target="_blank"> Github Project</a>.
|
||||
|
||||
## Contributing
|
||||
|
||||
Before raising a pull-request, please read our
|
||||
[contributing guide](https://github.com/node-red/node-red-dashboard/blob/master/CONTRIBUTING.md).
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.4](http://contributor-covenant.org/version/1/4/).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable
|
||||
behavior to any of the [project's core team](https://github.com/orgs/node-red/teams/core).
|
||||
|
||||
## Developers
|
||||
|
||||
```
|
||||
cd ~\.node-red\node_modules
|
||||
git clone https://github.com/node-red/node-red-dashboard.git
|
||||
cd node-red-dashboard
|
||||
npm install
|
||||
```
|
||||
The plugin uses the ```dist``` folder if it exists. Make sure it has been deleted if you want to use the non-minified version while developing.
|
||||
After finishing changes to the front-end code in the src folder, you can use ```gulp``` to update and rebuild the minified files and update the *appcache* manifest.
|
||||
|
||||
gulp
|
||||
|
||||
We also have suggested *lint* and *js* styles that can be checked with:
|
||||
|
||||
gulp lint
|
||||
gulp jscs
|
||||
|
||||
If submitting a Pull Request (PR) please do NOT include the minified `/dist` files.
|
||||
|
||||
Thank you.
|
||||
|
||||
<img src="http://nodered.org/images/dashboardl.png"/>
|
||||
77
nodered/rootfs/data/node_modules/node-red-dashboard/config-fields.md
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
## UI Widget configuration via msg.ui_control
|
||||
|
||||
The following configuration properties of ui widget nodes can be set by using a `msg.ui_control` property on a msg.
|
||||
Multiple properties of the node can be set at the same time. For example you can use a change
|
||||
node to set msg.ui_control to JSON `{ "min":10, "max":50 }`
|
||||
|
||||
**Note**: It is still recommended that nodes are configured via the editor in order to preset the default values.
|
||||
|
||||
|widget |property |type | notes / example
|
||||
|--- |--- |--- |---
|
||||
|ui_button |color |string | not needed
|
||||
| |bgcolor |string | not needed
|
||||
| |icon |string | on refresh
|
||||
| |format |string | not needed
|
||||
| |tooltip |string | on refresh
|
||||
|ui_chart |look |string |"line","bar","horizontalBar","pie","polar-area","radar"
|
||||
| |legend |boolean |
|
||||
| |interpolate |string |"linear","step","bezier"
|
||||
| |nodata |string |
|
||||
| |ymin |number |
|
||||
| |ymax |number |
|
||||
| |dot |boolean |
|
||||
| |xformat |string |"HH:mm:ss"
|
||||
| |cutout |number |
|
||||
| |colors |object | n/a
|
||||
| |useOneColor |boolean | n/a
|
||||
| |spanGaps |boolean | n/a
|
||||
| |animation |string | (Note 1), {duration:1000, easing:"easeInOutSine"}
|
||||
| |options |object | (Note 2), {scales: {yAxes: [{ticks: {fontSize: 20}}]}}
|
||||
|ui_colour_picker |format |string | on refresh
|
||||
| |showPicker |boolean | on refresh
|
||||
| |showSwatch |boolean | on refresh
|
||||
| |showValue |boolean | on refresh
|
||||
| |showAlpha |boolean | on refresh
|
||||
| |showLightness |boolean | on refresh
|
||||
|ui_dropdown |place |string |"placeholder text"
|
||||
| |options |array |[{"label":"foo","value":"0","type":"str"}]
|
||||
|ui_gauge |gtype |string |"gage", "donut", "compass", "wave"
|
||||
| |min |number |
|
||||
| |seg1 |number |segment 1 limit
|
||||
| |seg2 |number |segment 2 limit
|
||||
| |max |number |
|
||||
| |colors |array |["blue","#00ff00","#f00"]
|
||||
| |options |object |(see Note 3 below)
|
||||
|ui_numeric |min |number |
|
||||
| |max |number |
|
||||
| |step |number |
|
||||
| |format |string |"{{value}}"
|
||||
|ui_slider |min |number |
|
||||
| |max |number |
|
||||
| |step |number |
|
||||
|ui_switch |onicon |string | all or nothing
|
||||
| |officon |string | all or nothing
|
||||
| |oncolor |string | all or nothing
|
||||
| |offcolor |string | all or nothing
|
||||
|ui_template |format |string | the script
|
||||
| |templateScope |string | "local" or "global"
|
||||
|ui_text |format |string |"{{value}}"
|
||||
| |layout |string | "row-left", "row-right", etc
|
||||
|ui_text_input |mode |string | "text", "email", "password", "color"
|
||||
| |delay |number |
|
||||
|
||||
**Notes**:
|
||||
|
||||
1. See http://easings.net/ for examples of easings for chart animation.
|
||||
|
||||
2. The chart can take many of the angular-chartjs options for changing axes label, scales etc
|
||||
|
||||
3. The gauge options can accept any of the [Justgage parameters](https://github.com/toorshia/justgage/blob/master/justgage.js#L42) for example:
|
||||
|
||||
{"options":{"pointer":false,"gaugeWidthScale":1.5}}
|
||||
{"options":{"pointer":true,"gaugeWidthScale":0.4,"reverse":true}}
|
||||
|
||||
Likewise the Wave type gauge can accept [liquidfillgauge config](http://bl.ocks.org/brattonc/5e5ce9beee483220e2f6) options for example:
|
||||
|
||||
{options:{circleColor:"#FF7777", textColor:"#FF4444", waveTextColor:"#FFAAAA", waveColor:"#FFDDDD", circleThickness:0.3, textVertPosition:0.2, waveHeight:0.05, waveCount:8}}
|
||||
29697
nodered/rootfs/data/node_modules/node-red-dashboard/dist/css/app.min.css
generated
vendored
Normal file
813
nodered/rootfs/data/node_modules/node-red-dashboard/dist/css/app.min.less
generated
vendored
Normal file
@@ -0,0 +1,813 @@
|
||||
/* */
|
||||
/* Copyright 2016,2019 JS Foundation and other contributors, https://js.foundation/ */
|
||||
/* Copyright 2016 IBM Corp. */
|
||||
/* Copyright 2015 Andrei Tatar */
|
||||
/* */
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License"); */
|
||||
/* you may not use this file except in compliance with the License. */
|
||||
/* You may obtain a copy of the License at */
|
||||
/* */
|
||||
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
||||
/* */
|
||||
/* Unless required by applicable law or agreed to in writing, software */
|
||||
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
||||
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* */
|
||||
|
||||
@media(max-width: 959px) {
|
||||
.md-sidenav-left, md-sidenav {
|
||||
top: 48px !important;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
@media (max-width: 959px) and (min-width: 0) and (orientation: portrait) {
|
||||
md-toolbar {
|
||||
min-height: 48px;
|
||||
height: 48px;
|
||||
max-height: 48px;
|
||||
}
|
||||
}
|
||||
@media(min-width: 960px) {
|
||||
.md-sidenav-left, md-sidenav {
|
||||
top: 64px;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
@media(max-width: 660px) {
|
||||
md-sidenav,
|
||||
md-sidenav.md-locked-open,
|
||||
md-sidenav.md-closed.md-locked-open-add-active {
|
||||
min-width: 160px !important;
|
||||
width: auto;
|
||||
max-width: 200px !important;
|
||||
}
|
||||
}
|
||||
@media(min-width: 661px) {
|
||||
md-sidenav,
|
||||
md-sidenav.md-locked-open,
|
||||
md-sidenav.md-closed.md-locked-open-add-active {
|
||||
min-width: 200px !important;
|
||||
width: auto;
|
||||
max-width: 320px !important;
|
||||
}
|
||||
}
|
||||
md-sidenav ng-md-icon {
|
||||
padding-right: 4px;
|
||||
}
|
||||
md-sidenav i {
|
||||
padding-right: 4px;
|
||||
}
|
||||
md-sidenav md-list-item .md-list-item-inner>p {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
md-toast .md-toast-content {
|
||||
height: auto;
|
||||
}
|
||||
md-toast .md-toast-error {
|
||||
color: rgba(255, 64, 41, 0.84);
|
||||
font-weight: 500;
|
||||
font-size: large;
|
||||
}
|
||||
md-backdrop.md-sidenav-backdrop {
|
||||
z-index: 80;
|
||||
}
|
||||
|
||||
md-card {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.md-tooltip {
|
||||
background-color: #888 !important;
|
||||
color: #fff !important;
|
||||
border-radius: 3px;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.md-tooltip.md-origin-bottom {
|
||||
margin-top: -6px;
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
.node-red-ui--notabs {
|
||||
color: #888;
|
||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 1;
|
||||
animation-name: fadeInOpacity;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: ease-in;
|
||||
animation-duration: 2.5s;
|
||||
}
|
||||
|
||||
.node-red-ui--inline-link {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
.node-red-ui--inline-link iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ie9 img[src$=".svg"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
img[src$=".svg"] {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInOpacity {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
30% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (-ms-overflow-style: none) {
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
/*
|
||||
ALL COMPONENTS/CONTENT
|
||||
*/
|
||||
@baseFont: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
|
||||
@baseColor: #fff;
|
||||
@pageBackgroundColor: #eee;
|
||||
@pageTitlebarBackgroundColor: #0094CE;
|
||||
@groupBackgroundColor: #fff;
|
||||
@groupTextColor: #00A4DE;
|
||||
@groupBorderColor: #fff;
|
||||
@widgetTextColor: #000;
|
||||
@widgetBackgroundColor: #4FBAE4;
|
||||
@widgetBorderColor: #fff;
|
||||
@nrTheme: true;
|
||||
@nrTemplateTheme: true;
|
||||
@nrUnitHeight: 24px;
|
||||
|
||||
// define some CSS variables for user usage
|
||||
:root {
|
||||
--nr-dashboard-pageBackgroundColor: @pageBackgroundColor;
|
||||
--nr-dashboard-pageTitlebarBackgroundColor: @pageTitlebarBackgroundColor;
|
||||
--nr-dashboard-groupTextColor: @groupTextColor;
|
||||
--nr-dashboard-groupBackgroundColor: @groupBackgroundColor;
|
||||
--nr-dashboard-groupBorderColor: @groupBorderColor;
|
||||
--nr-dashboard-widgetTextColor: @widgetTextColor;
|
||||
--nr-dashboard-widgetBackgroundColor: @widgetBackgroundColor; // deprecated - will be removed at some point
|
||||
--nr-dashboard-widgetBorderColor: @widgetBorderColor; // deprecated - will be removed at some point
|
||||
--nr-dashboard-widgetColor: @widgetBackgroundColor;
|
||||
--nr-dashboard-widgetBgndColor: @widgetBorderColor;
|
||||
}
|
||||
|
||||
.nr-dashboard-disabled {
|
||||
opacity: 0.4 !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
& when (@nrTheme = false) {
|
||||
.nr-menu-item-active div button {
|
||||
border-right: 4px solid #888;
|
||||
}
|
||||
}
|
||||
|
||||
& when (@nrTheme = true) {
|
||||
|
||||
body.nr-dashboard-theme {
|
||||
background-color: @pageBackgroundColor;
|
||||
font-family: @baseFont;
|
||||
}
|
||||
|
||||
body.nr-dashboard-theme md-content {
|
||||
background: transparent;
|
||||
height: 100%;
|
||||
& when (@nrTemplateTheme = true) {
|
||||
color: @groupTextColor;
|
||||
}
|
||||
}
|
||||
|
||||
body.nr-dashboard-theme md-select-menu md-content {
|
||||
height: initial;
|
||||
}
|
||||
|
||||
body.nr-dashboard-theme md-input-container.md-input-focused:not([md-no-float]) .md-select-placeholder span:first-child {
|
||||
-webkit-transform: translateY(-28px) scale(.75);
|
||||
transform: translateY(-28px) scale(.75);
|
||||
}
|
||||
body.nr-dashboard-theme md-input-container.md-input-focused:not(.md-input-has-value) md-select .md-select-value.md-select-placeholder {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
|
||||
body.nr-dashboard-theme md-content md-card {
|
||||
background-color: @widgetBorderColor;
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
|
||||
/* Some colour classes */
|
||||
body.nr-dashboard-theme .nr-dashboard-color { color: @groupTextColor; }
|
||||
body.nr-dashboard-theme .nr-dashboard-error { color: #ff2929; }
|
||||
body.nr-dashboard-theme .nr-dashboard-warning { color: #eaf42f; }
|
||||
body.nr-dashboard-theme .nr-dashboard-ok { color: #49db3c; }
|
||||
body.nr-dashboard-theme .nr-dashboard-dim { opacity: 0.5 !important; }
|
||||
|
||||
|
||||
/*
|
||||
DASHBOARD HEADER
|
||||
*/
|
||||
body.nr-dashboard-theme md-toolbar {
|
||||
background-color: @pageTitlebarBackgroundColor;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/*
|
||||
DASHBOARD SIDEBAR
|
||||
*/
|
||||
body.nr-dashboard-theme md-sidenav {
|
||||
color: @groupTextColor;
|
||||
background-color: @groupBackgroundColor;
|
||||
}
|
||||
a.md-no-style, button.md-no-style {
|
||||
background-color: transparent;
|
||||
}
|
||||
.nr-menu-item-active div button {
|
||||
border-right: 4px solid @groupTextColor;
|
||||
}
|
||||
|
||||
/*
|
||||
GROUP SPECIFIC
|
||||
*/
|
||||
.nr-dashboard-theme ui-card-panel {
|
||||
background-color: @groupBackgroundColor;
|
||||
border: 1px solid @groupBorderColor;
|
||||
& p.nr-dashboard-cardtitle {
|
||||
color: @groupTextColor;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
COMPONENT-SPECIFIC
|
||||
*/
|
||||
|
||||
.nr-dashboard-theme .nr-dashboard-spacer {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.md-button.md-default-theme.md-primary, .md-button.md-primary {
|
||||
background-color: @widgetBackgroundColor !important;
|
||||
color: white;
|
||||
}
|
||||
// .md-button.md-default-theme:not([disabled]):hover, .md-button:not([disabled]):hover {
|
||||
// filter: grayscale(75%);
|
||||
// }
|
||||
// .nr-dashboard-theme .md-button.md-primary {
|
||||
// color: lighten(@widgetBackgroundColor, 8);
|
||||
// }
|
||||
.nr-dashboard-theme .md-button[disabled] {
|
||||
color: rgba(0,0,0,0.38);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Button */
|
||||
.nr-dashboard-theme .nr-dashboard-button .md-button {
|
||||
background-color: @widgetBackgroundColor;
|
||||
color: white;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-button .md-button:hover {
|
||||
background-color: lighten(@widgetBackgroundColor, 6);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button[disabled] {
|
||||
color: #888;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-button .md-button.md-primary {
|
||||
color: white;
|
||||
background-color: lighten(@widgetBackgroundColor, 4);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-button .md-button.md-raised:not([disabled]).md-focused {
|
||||
background-color: @widgetBackgroundColor;
|
||||
}
|
||||
|
||||
/* Date picker */
|
||||
.nr-dashboard-theme .nr-dashboard-date-picker md-input-container .md-input {
|
||||
color: @widgetTextColor;
|
||||
border-bottom-color: @widgetBackgroundColor;
|
||||
font-family: inherit;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-date-picker md-input-container .md-input::-webkit-input-placeholder {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-date-picker .md-button.md-icon-button {
|
||||
/* background-color: @widgetBackgroundColor; */
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-date-picker .md-button.md-icon-button md-icon {
|
||||
color: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-date-picker .md-datepicker-triangle-button .md-datepicker-expand-triangle {
|
||||
border-top-color: @widgetTextColor;
|
||||
}
|
||||
|
||||
.md-default-theme .md-calendar-day-header, .md-calendar-day-header {
|
||||
color: contrast(@pageTitlebarBackgroundColor);
|
||||
background-color: @pageTitlebarBackgroundColor;
|
||||
}
|
||||
.md-default-theme .md-calendar-date.md-calendar-selected-date .md-calendar-date-selection-indicator, .md-calendar-date.md-calendar-selected-date .md-calendar-date-selection-indicator, .md-default-theme .md-calendar-date.md-focus.md-calendar-selected-date .md-calendar-date-selection-indicator, .md-calendar-date.md-focus.md-calendar-selected-date .md-calendar-date-selection-indicator {
|
||||
background: @widgetBackgroundColor;
|
||||
color: contrast(@widgetBackgroundColor);
|
||||
border-color: transparent;
|
||||
}
|
||||
.md-default-theme .md-calendar-date.md-calendar-date-today .md-calendar-date-selection-indicator, .md-calendar-date.md-calendar-date-today .md-calendar-date-selection-indicator {
|
||||
border: 1px solid @widgetBackgroundColor;
|
||||
}
|
||||
.md-datepicker-calendar-pane.md-pane-open {
|
||||
width: 345px;
|
||||
background-color: @groupBackgroundColor;
|
||||
}
|
||||
|
||||
/* Chart */
|
||||
.nr-dashboard-theme .nr-dashboard-chart-title {
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-chart-titlel {
|
||||
font-size: larger;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
/* Colour Picker */
|
||||
.nr-dashboard-theme .color-picker-panel {
|
||||
background-color: @groupBackgroundColor;
|
||||
border-color: @groupBorderColor;
|
||||
box-shadow: 0 0 1px rgba(255,255,255,.5);
|
||||
}
|
||||
.nr-dashboard-theme .color-picker-input-wrapper > input {
|
||||
color: @widgetTextColor;
|
||||
background-color: @widgetBorderColor;
|
||||
font-family: inherit;
|
||||
}
|
||||
.nr-dashboard-theme .color-picker-wrapper .color-picker-panel.color-picker-panel-round .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-grid-inner {
|
||||
background-color: @widgetBorderColor;
|
||||
}
|
||||
.nr-dashboard-theme .color-picker-wrapper.color-picker-open {
|
||||
border-width:0;
|
||||
}
|
||||
// .nr-dashboard-theme .color-picker-wrapper .color-picker-panel.color-picker-panel-round .color-picker-grid-wrapper .color-picker-row .color-picker-grid .color-picker-overlay {
|
||||
// background-image: url("./wheel.png");
|
||||
// border-radius: 50%;
|
||||
// }
|
||||
|
||||
/* Dropdown */
|
||||
.nr-dashboard-theme .nr-dashboard-dropdown p.label {
|
||||
margin-left: 3px;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-dropdown md-select .md-select-value,
|
||||
.nr-dashboard-theme .nr-dashboard-dropdown md-select .md-select-value.md-select-placeholder {
|
||||
color: @widgetTextColor;
|
||||
border-color: @widgetTextColor;
|
||||
border-bottom-width: 1px;
|
||||
padding: 0px 2px;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-dropdown .md-select-icon {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
.nr-dashboard-theme md-select-menu {
|
||||
margin-left: -2px;
|
||||
}
|
||||
.nr-dashboard-theme md-select-menu md-content {
|
||||
border: 1px solid #4F4F4F;
|
||||
padding: 0px;
|
||||
}
|
||||
.nr-dashboard-theme md-select-menu, .nr-dashboard-theme md-select-menu md-option {
|
||||
background-color: @groupBackgroundColor;
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
.nr-dashboard-theme md-select-menu md-option[selected] {
|
||||
color: @groupTextColor !important;
|
||||
background-color: @groupBackgroundColor !important;
|
||||
}
|
||||
.nr-dashboard-theme md-select-menu.md-default-theme md-option:focus:not([disabled]):not([selected]),
|
||||
md-select-menu md-option:focus:not([disabled]):not([selected]) {
|
||||
background-color: @groupBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme md-select-menu md-option:hover {
|
||||
background-color: lighten(@widgetBackgroundColor, 4) !important;
|
||||
}
|
||||
|
||||
/* Gauge */
|
||||
.nr-dashboard-theme .nr-dashboard-gauge {}
|
||||
.nr-dashboard-theme .nr-dashboard-gauge text {
|
||||
fill: @widgetTextColor;
|
||||
margin: 8px;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-gauge-title {
|
||||
margin: 6px 0px 20px 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-gauge-titlel {
|
||||
font-size: larger;
|
||||
font-weight: 500 !important;
|
||||
z-index: 1;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-gauge-titlem {
|
||||
font-weight: 500 !important;
|
||||
margin: 2px 0px 14px 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-gauge-titles {
|
||||
font-size: x-small;
|
||||
margin-top: 2px;
|
||||
height: 10px;
|
||||
padding-bottom: 14px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Numeric */
|
||||
.nr-dashboard-theme .nr-dashboard-numeric .value {
|
||||
background-color: @widgetBorderColor;
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
|
||||
/* Slider */
|
||||
.nr-dashboard-theme .nr-dashboard-slider {}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-track {
|
||||
background-color: rgba(111, 111, 111, 0.5);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-track-fill {
|
||||
background-color: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-thumb:after {
|
||||
background-color: @widgetBackgroundColor;
|
||||
border-color: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-focus-ring {
|
||||
background-color: @widgetBackgroundColor;
|
||||
transform: scale(.4);
|
||||
opacity: 1;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-sign {
|
||||
background-color: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-sign:after {
|
||||
border-top-color: @widgetBackgroundColor !important;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-min[md-discrete] .md-sign {
|
||||
background-color: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider md-slider[md-discrete] .md-sign,
|
||||
.nr-dashboard-theme .nr-dashboard-slider md-slider[md-discrete] .md-sign:after {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 0, 0) scale(1);
|
||||
transform: translate3d(0, 0, 0) scale(1);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider .md-sign:after {
|
||||
border-top-color: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme md-slider.md-default-theme[md-vertical] .md-sign:after, .nr-dashboard-theme md-slider[md-vertical] .md-sign:after {
|
||||
content: none;;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider md-slider.md-default-theme.md-min[md-discrete] .md-thumb:after, md-slider.md-min[md-discrete] .md-thumb:after {
|
||||
background-color: @widgetBackgroundColor;
|
||||
border-color: transparent;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider md-slider .md-track-ticks {
|
||||
color: transparent;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-slider md-slider[md-discrete]:not([disabled]) .md-slider-wrapper.md-focused .md-focus-ring {
|
||||
transform: scale(0.4);
|
||||
animation: unset;
|
||||
}
|
||||
|
||||
/* Switch */
|
||||
.nr-dashboard-theme .nr-dashboard-switch {}
|
||||
.nr-dashboard-theme .nr-dashboard-switch md-switch .md-bar {
|
||||
background-color: rgba(111, 111, 111, 0.5);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-switch md-switch.md-checked .md-bar {
|
||||
background-color: rgba(red(@widgetBackgroundColor), green(@widgetBackgroundColor), blue(@widgetBackgroundColor), 0.5);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-switch md-switch .md-thumb {
|
||||
background-color: rgb(148, 148, 148);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-switch md-switch.md-checked .md-thumb {
|
||||
background-color: rgba(red(@widgetBackgroundColor), green(@widgetBackgroundColor), blue(@widgetBackgroundColor), 1);
|
||||
}
|
||||
|
||||
/* Template */
|
||||
& when (@nrTemplateTheme = true) {
|
||||
md-list {
|
||||
padding: unset;
|
||||
}
|
||||
md-list-item[disabled] {
|
||||
color: #888;
|
||||
// text-decoration: line-through;
|
||||
}
|
||||
md-list-item {
|
||||
min-height: @nrUnitHeight * 2;
|
||||
height: @nrUnitHeight * 2;
|
||||
}
|
||||
md-list-item._md-button-wrap>div.md-button:first-child {
|
||||
background-color: @widgetBorderColor;
|
||||
height: inherit;
|
||||
padding: 0 6px;
|
||||
}
|
||||
md-list-item.md-2-line {
|
||||
height: @nrUnitHeight * 2;
|
||||
min-height: @nrUnitHeight * 2;
|
||||
}
|
||||
md-list-item.md-3-line {
|
||||
height: @nrUnitHeight * 3;
|
||||
min-height: @nrUnitHeight * 3;
|
||||
}
|
||||
md-list-item .md-list-item-inner {
|
||||
background: @widgetBorderColor;
|
||||
//color: @widgetTextColor;
|
||||
padding-left: 8px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
md-progress-linear {
|
||||
padding-top: 4px !important;
|
||||
}
|
||||
md-progress-linear .md-container {
|
||||
margin-top: @nrUnitHeight / 2;
|
||||
background-color: @pageBackgroundColor;
|
||||
}
|
||||
md-progress-linear .md-container .md-bar {
|
||||
background-color: lighten(@widgetBackgroundColor, 5);
|
||||
}
|
||||
|
||||
md-checkbox {
|
||||
min-height: @nrUnitHeight * 2;
|
||||
margin-left: 6px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
md-checkbox .md-icon {
|
||||
border-color: @widgetBackgroundColor !important;
|
||||
}
|
||||
md-checkbox[disabled] .md-icon {
|
||||
border-color: #888 !important;
|
||||
}
|
||||
md-checkbox.md-checked .md-icon {
|
||||
background-color: lighten(@widgetBackgroundColor, 5);
|
||||
border-color: transparent !important;
|
||||
}
|
||||
md-checkbox .md-label {
|
||||
position: absolute;
|
||||
top: 32%;
|
||||
}
|
||||
md-checkbox[disabled] .md-label {
|
||||
color: #888;
|
||||
}
|
||||
md-checkbox:last-of-type {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.nr-dashboard-theme .nr-dashboard-template md-switch .md-thumb {
|
||||
background-color: rgb(148, 148, 148);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template md-switch .md-bar {
|
||||
background-color: rgba(111, 111, 111, 0.5);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template md-switch.md-checked:not([disabled]) .md-thumb {
|
||||
background-color: lighten(@widgetBackgroundColor, 5);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template md-switch.md-checked:not([disabled]) .md-bar {
|
||||
background-color: rgba(red(@widgetBackgroundColor), green(@widgetBackgroundColor), blue(@widgetBackgroundColor), 0.5);
|
||||
}
|
||||
|
||||
md-radio-button {
|
||||
min-height: @nrUnitHeight * 2;
|
||||
margin-left: 6px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
md-radio-button .md-off, md-radio-button .md-on {
|
||||
border-color: @widgetBackgroundColor !important;
|
||||
}
|
||||
md-radio-button[disabled] .md-off, md-radio-button[disabled] .md-on {
|
||||
border-color: #888 !important;
|
||||
}
|
||||
md-radio-button.md-checked .md-on {
|
||||
background-color: @widgetBackgroundColor !important;
|
||||
}
|
||||
md-radio-button .md-label {
|
||||
position: absolute;
|
||||
top: 32%;
|
||||
}
|
||||
md-radio-button[disabled] .md-label {
|
||||
color: #888;
|
||||
}
|
||||
md-divider {
|
||||
border-color: @widgetBackgroundColor !important;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template path {
|
||||
fill: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-template {
|
||||
padding: (@nrUnitHeight / 8) 6px;
|
||||
p, h1, h2, h3, h4 {
|
||||
color: @widgetTextColor !important;
|
||||
background-color : @widgetBorderColor !important;
|
||||
}
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button .md-no-style {
|
||||
background: initial !important;
|
||||
color: initial !important;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button[disabled] {
|
||||
color: #ccc;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button.md-primary:not([disabled]) {
|
||||
color: @widgetTextColor;
|
||||
background-color: lighten(@widgetBackgroundColor, 5);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button .ng-scope {
|
||||
color: unset;
|
||||
}
|
||||
.nr-dashboard-template .md-button {
|
||||
color: white;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button:not(:first-of-type) {
|
||||
margin-top: @nrUnitHeight * 3 / 4;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button {
|
||||
margin: 0;
|
||||
//padding: 0px 12px;
|
||||
min-height: @nrUnitHeight * 3 / 2;
|
||||
min-width: unset;
|
||||
line-height: unset;
|
||||
background-color: @widgetBackgroundColor;
|
||||
|
||||
&.md-fab.md-mini {
|
||||
padding: unset;
|
||||
}
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button:not([disabled]):hover {
|
||||
background-color: lighten(@widgetBackgroundColor, 4);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button.md-primary:not([disabled]):hover {
|
||||
background-color: lighten(@widgetBackgroundColor, 4);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button.md-primary.md-raised:not([disabled]) {
|
||||
background-color: lighten(@widgetBackgroundColor, 2);
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-template .md-button.md-primary.md-raised:not([disabled]):hover {
|
||||
background-color: lighten(@widgetBackgroundColor, 4);
|
||||
}
|
||||
|
||||
// .md-button:disabled {
|
||||
// background-color: @widgetBackgroundColor;
|
||||
// }
|
||||
|
||||
.nr-dashboard-theme .nr-dashboard-template {
|
||||
::-webkit-scrollbar {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: @baseColor;
|
||||
-webkit-border-radius: 1ex;
|
||||
-webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: @pageBackgroundColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Text-Input */
|
||||
.nr-dashboard-theme .nr-dashboard-textinput {}
|
||||
.nr-dashboard-theme .nr-dashboard-textinput label {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-textinput md-input-container.md-input-has-value label {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-textinput md-input-container.md-input-focused label {
|
||||
color: @groupTextColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-textinput md-input-container.md-input-focused input {
|
||||
border-color: @groupTextColor;
|
||||
font-family: inherit;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-textinput md-input-container .md-input:invalid {
|
||||
color: #DA5252;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-textinput input {
|
||||
border-color: @widgetTextColor;
|
||||
color: @widgetTextColor;
|
||||
border-bottom-width: 1px;
|
||||
font-family: inherit;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
/* Text */
|
||||
.nr-dashboard-theme .nr-dashboard-text {}
|
||||
.nr-dashboard-theme .nr-dashboard-text p {
|
||||
margin-left:0;
|
||||
}
|
||||
|
||||
/* Dialog */
|
||||
.nr-dashboard-theme md-dialog {
|
||||
color: @widgetTextColor;
|
||||
background-color: @groupBackgroundColor;
|
||||
border: 3px solid @groupBorderColor;
|
||||
}
|
||||
.nr-dashboard-theme .md-dialog-content {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
|
||||
/* Form */
|
||||
.nr-dashboard-theme .nr-dashboard-form md-input-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nr-dashboard-theme .nr-dashboard-form-button {
|
||||
background-color: @widgetBackgroundColor;
|
||||
color: white;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form-button:hover {
|
||||
background-color: lighten(@widgetBackgroundColor, 10) !important;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form-button:focus {
|
||||
background-color: lighten(@widgetBackgroundColor, 10) !important;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form form md-input-container input {
|
||||
border-color: @widgetTextColor;
|
||||
color: @widgetTextColor;
|
||||
font-family: inherit;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form form md-input-container label {
|
||||
color: @widgetTextColor;;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form form md-input-container.md-input-has-value:not(.md-input-invalid) label {
|
||||
color: @widgetTextColor;;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form form md-input-container:not(.md-input-invalid).md-input-focused input {
|
||||
border-color: @groupTextColor ;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form form md-input-container:not(.md-input-invalid).md-input-focused label {
|
||||
color: @groupTextColor ;
|
||||
}
|
||||
.nr-dashboard-theme .nr-dashboard-form form .md-input-invalid input {
|
||||
border-color: #d00 !important;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form .md-input-invalid label {
|
||||
color: #d00 !important;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-input-container md-checkbox.md-checked .md-icon {
|
||||
background-color: lighten(@widgetBackgroundColor, 10);
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-input-container md-checkbox .md-icon{
|
||||
border-color: @widgetTextColor;;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-input-container md-switch .md-bar{
|
||||
background-color: rgba(111, 111, 111, 0.5);
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-input-container md-switch .md-thumb {
|
||||
background-color: rgb(148, 148, 148);
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-input-container md-switch.md-checked .md-bar{
|
||||
background-color: lighten(@widgetBackgroundColor, 10);
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-input-container md-switch.md-checked .md-thumb {
|
||||
background-color: @widgetBackgroundColor;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-datepicker {
|
||||
background-color: inherit;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form .md-datepicker-calendar-icon {
|
||||
fill: @groupTextColor;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form .md-datepicker-open .md-datepicker-calendar-icon {
|
||||
fill: @widgetBackgroundColor ;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form .md-datepicker-input {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form .md-datepicker-input-container {
|
||||
border-color: @widgetTextColor;;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form .md-datepicker-expand-triangle{
|
||||
border-top-color: @widgetBackgroundColor ;
|
||||
}
|
||||
.nr-dashboard-theme md-content .nr-dashboard-form form md-input-container .md-input {
|
||||
color: @widgetTextColor;
|
||||
}
|
||||
}
|
||||
1
nodered/rootfs/data/node_modules/node-red-dashboard/dist/css/gridstack-extra.min.css
generated
vendored
Normal file
1
nodered/rootfs/data/node_modules/node-red-dashboard/dist/css/gridstack.min.css
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
:root .grid-stack-item>.ui-resizable-handle{filter:none}.grid-stack{position:relative}.grid-stack.grid-stack-rtl{direction:ltr}.grid-stack.grid-stack-rtl>.grid-stack-item{direction:rtl}.grid-stack .grid-stack-placeholder>.placeholder-content{border:1px dashed #d3d3d3;margin:0;position:absolute;top:0;left:10px;right:10px;bottom:0;width:auto;z-index:0!important;text-align:center}.grid-stack>.grid-stack-item{min-width:8.3333333333%;position:absolute;padding:0}.grid-stack>.grid-stack-item>.grid-stack-item-content{margin:0;position:absolute;top:0;left:10px;right:10px;bottom:0;width:auto;z-index:0;overflow-x:hidden;overflow-y:auto}.grid-stack>.grid-stack-item>.ui-resizable-handle{position:absolute;font-size:.1px;display:block;-ms-touch-action:none;touch-action:none}.grid-stack>.grid-stack-item.ui-resizable-autohide>.ui-resizable-handle,.grid-stack>.grid-stack-item.ui-resizable-disabled>.ui-resizable-handle{display:none}.grid-stack>.grid-stack-item.ui-draggable-dragging,.grid-stack>.grid-stack-item.ui-resizable-resizing{z-index:100}.grid-stack>.grid-stack-item.ui-draggable-dragging>.grid-stack-item-content,.grid-stack>.grid-stack-item.ui-resizable-resizing>.grid-stack-item-content{box-shadow:1px 4px 6px rgba(0,0,0,.2);opacity:.8}.grid-stack>.grid-stack-item>.ui-resizable-se,.grid-stack>.grid-stack-item>.ui-resizable-sw{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjE2cHgiIGhlaWdodD0iMTZweCIgdmlld0JveD0iMCAwIDUxMS42MjYgNTExLjYyNyIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTExLjYyNiA1MTEuNjI3OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTMyOC45MDYsNDAxLjk5NGgtMzYuNTUzVjEwOS42MzZoMzYuNTUzYzQuOTQ4LDAsOS4yMzYtMS44MDksMTIuODQ3LTUuNDI2YzMuNjEzLTMuNjE1LDUuNDIxLTcuODk4LDUuNDIxLTEyLjg0NSAgIGMwLTQuOTQ5LTEuODAxLTkuMjMxLTUuNDI4LTEyLjg1MWwtNzMuMDg3LTczLjA5QzI2NS4wNDQsMS44MDksMjYwLjc2LDAsMjU1LjgxMywwYy00Ljk0OCwwLTkuMjI5LDEuODA5LTEyLjg0Nyw1LjQyNCAgIGwtNzMuMDg4LDczLjA5Yy0zLjYxOCwzLjYxOS01LjQyNCw3LjkwMi01LjQyNCwxMi44NTFjMCw0Ljk0NiwxLjgwNyw5LjIyOSw1LjQyNCwxMi44NDVjMy42MTksMy42MTcsNy45MDEsNS40MjYsMTIuODUsNS40MjYgICBoMzYuNTQ1djI5Mi4zNThoLTM2LjU0MmMtNC45NTIsMC05LjIzNSwxLjgwOC0xMi44NSw1LjQyMWMtMy42MTcsMy42MjEtNS40MjQsNy45MDUtNS40MjQsMTIuODU0ICAgYzAsNC45NDUsMS44MDcsOS4yMjcsNS40MjQsMTIuODQ3bDczLjA4OSw3My4wODhjMy42MTcsMy42MTcsNy44OTgsNS40MjQsMTIuODQ3LDUuNDI0YzQuOTUsMCw5LjIzNC0xLjgwNywxMi44NDktNS40MjQgICBsNzMuMDg3LTczLjA4OGMzLjYxMy0zLjYyLDUuNDIxLTcuOTAxLDUuNDIxLTEyLjg0N2MwLTQuOTQ4LTEuODA4LTkuMjMyLTUuNDIxLTEyLjg1NCAgIEMzMzguMTQyLDQwMy44MDIsMzMzLjg1Nyw0MDEuOTk0LDMyOC45MDYsNDAxLjk5NHoiIGZpbGw9IiM2NjY2NjYiLz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K);background-repeat:no-repeat;background-position:center;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.grid-stack>.grid-stack-item>.ui-resizable-se{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}.grid-stack>.grid-stack-item>.ui-resizable-nw{cursor:nw-resize;width:20px;height:20px;left:10px;top:0}.grid-stack>.grid-stack-item>.ui-resizable-n{cursor:n-resize;height:10px;top:0;left:25px;right:25px}.grid-stack>.grid-stack-item>.ui-resizable-ne{cursor:ne-resize;width:20px;height:20px;right:10px;top:0}.grid-stack>.grid-stack-item>.ui-resizable-e{cursor:e-resize;width:10px;right:10px;top:15px;bottom:15px}.grid-stack>.grid-stack-item>.ui-resizable-se{cursor:se-resize;width:20px;height:20px;right:10px;bottom:0}.grid-stack>.grid-stack-item>.ui-resizable-s{cursor:s-resize;height:10px;left:25px;bottom:0;right:25px}.grid-stack>.grid-stack-item>.ui-resizable-sw{cursor:sw-resize;width:20px;height:20px;left:10px;bottom:0}.grid-stack>.grid-stack-item>.ui-resizable-w{cursor:w-resize;width:10px;left:10px;top:15px;bottom:15px}.grid-stack>.grid-stack-item.ui-draggable-dragging>.ui-resizable-handle{display:none!important}.grid-stack>.grid-stack-item[data-gs-width='1']{width:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='1']{left:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='1']{min-width:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='1']{max-width:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='2']{width:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='2']{left:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='2']{min-width:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='2']{max-width:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='3']{width:25%}.grid-stack>.grid-stack-item[data-gs-x='3']{left:25%}.grid-stack>.grid-stack-item[data-gs-min-width='3']{min-width:25%}.grid-stack>.grid-stack-item[data-gs-max-width='3']{max-width:25%}.grid-stack>.grid-stack-item[data-gs-width='4']{width:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='4']{left:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='4']{min-width:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='4']{max-width:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='5']{width:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='5']{left:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='5']{min-width:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='5']{max-width:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='6']{width:50%}.grid-stack>.grid-stack-item[data-gs-x='6']{left:50%}.grid-stack>.grid-stack-item[data-gs-min-width='6']{min-width:50%}.grid-stack>.grid-stack-item[data-gs-max-width='6']{max-width:50%}.grid-stack>.grid-stack-item[data-gs-width='7']{width:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='7']{left:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='7']{min-width:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='7']{max-width:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='8']{width:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='8']{left:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='8']{min-width:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='8']{max-width:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='9']{width:75%}.grid-stack>.grid-stack-item[data-gs-x='9']{left:75%}.grid-stack>.grid-stack-item[data-gs-min-width='9']{min-width:75%}.grid-stack>.grid-stack-item[data-gs-max-width='9']{max-width:75%}.grid-stack>.grid-stack-item[data-gs-width='10']{width:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='10']{left:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='10']{min-width:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='10']{max-width:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='11']{width:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='11']{left:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='11']{min-width:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='11']{max-width:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='12']{width:100%}.grid-stack>.grid-stack-item[data-gs-x='12']{left:100%}.grid-stack>.grid-stack-item[data-gs-min-width='12']{min-width:100%}.grid-stack>.grid-stack-item[data-gs-max-width='12']{max-width:100%}.grid-stack.grid-stack-animate,.grid-stack.grid-stack-animate .grid-stack-item{-webkit-transition:left .3s,top .3s,height .3s,width .3s;-moz-transition:left .3s,top .3s,height .3s,width .3s;-ms-transition:left .3s,top .3s,height .3s,width .3s;-o-transition:left .3s,top .3s,height .3s,width .3s;transition:left .3s,top .3s,height .3s,width .3s}.grid-stack.grid-stack-animate .grid-stack-item.grid-stack-placeholder,.grid-stack.grid-stack-animate .grid-stack-item.ui-draggable-dragging,.grid-stack.grid-stack-animate .grid-stack-item.ui-resizable-resizing{-webkit-transition:left 0s,top 0s,height 0s,width 0s;-moz-transition:left 0s,top 0s,height 0s,width 0s;-ms-transition:left 0s,top 0s,height 0s,width 0s;-o-transition:left 0s,top 0s,height 0s,width 0s;transition:left 0s,top 0s,height 0s,width 0s}.grid-stack.grid-stack-one-column-mode{height:auto!important}.grid-stack.grid-stack-one-column-mode>.grid-stack-item{position:relative!important;width:auto!important;left:0!important;top:auto!important;margin-bottom:20px;max-width:none!important}.grid-stack.grid-stack-one-column-mode>.grid-stack-item>.ui-resizable-handle{display:none}
|
||||
29
nodered/rootfs/data/node_modules/node-red-dashboard/dist/dashboard.appcache
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
CACHE MANIFEST
|
||||
# Time: Thu Dec 19 2019 22:41:21 GMT+0000 (Greenwich Mean Time)
|
||||
|
||||
CACHE:
|
||||
i18n.js
|
||||
icon120x120.png
|
||||
icon192x192.png
|
||||
icon64x64.png
|
||||
css/app.min.css
|
||||
css/app.min.less
|
||||
css/gridstack-extra.min.css
|
||||
css/gridstack.min.css
|
||||
js/app.min.js
|
||||
js/gridstack.jQueryUI.min.js
|
||||
js/gridstack.min.js
|
||||
js/lodash.min.js
|
||||
js/tinycolor-min.js
|
||||
socket.io/socket.io.js
|
||||
fonts/MaterialIcons-Regular.woff
|
||||
fonts/MaterialIcons-Regular.woff2
|
||||
fonts/fontawesome-webfont.woff
|
||||
fonts/fontawesome-webfont.woff2
|
||||
fonts/weather-icons-lite.woff
|
||||
fonts/weather-icons-lite.woff2
|
||||
|
||||
NETWORK:
|
||||
*
|
||||
|
||||
# hash: a1fd0572ad1d13a28e64add455b494edc186ce3facbfa48d145cbb10c0b8c892
|
||||
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/fonts/MaterialIcons-Regular.woff
generated
vendored
Normal file
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/fonts/MaterialIcons-Regular.woff2
generated
vendored
Normal file
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/fonts/fontawesome-webfont.woff
generated
vendored
Normal file
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/fonts/fontawesome-webfont.woff2
generated
vendored
Normal file
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/fonts/weather-icons-lite.woff
generated
vendored
Normal file
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/fonts/weather-icons-lite.woff2
generated
vendored
Normal file
4
nodered/rootfs/data/node_modules/node-red-dashboard/dist/i18n.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// Placeholder only - This is NOT a sustainable solution to i18n localisation
|
||||
// Replace/overwrite this file with an angular-locale_... file of your choice from the npm angular-i18n project
|
||||
// Then edit dashboard.appcache - (for example add a digit to the hash)
|
||||
// Stop, start Node-RED and refresh the browser page twice to flush the cache.
|
||||
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/icon120x120.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/icon192x192.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/dist/icon64x64.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
17
nodered/rootfs/data/node_modules/node-red-dashboard/dist/index.html
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html> <!--
|
||||
Copyright 2016,2019 JS Foundation and other contributors, https://js.foundation/
|
||||
Copyright 2016 IBM Corp.
|
||||
Copyright 2015 Andrei Tatar
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
--> <!-- <html> --> <html lang="en" manifest="dashboard.appcache"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-title" content="Node-RED"> <meta name="mobile-web-app-capable" content="yes"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <link rel="manifest" href="manifest.json"> <link rel="icon" sizes="192x192" href="icon192x192.png"> <link rel="shortcut icon" type="image/png" href="icon64x64.png"> <link rel="apple-touch-icon" href="icon120x120.png"> <link rel="stylesheet" href="css/app.min.css"> <link rel="stylesheet/less" href="css/app.min.less"> <title></title> </head> <body id="nr-dashboard" ng-app="ui" ng-controller="MainController as main" ng-cloak layout="column" style="background: {{main.backgroundColor}}" class="nr-dashboard-theme" ng-swipe-right="onSwipeRight();" ng-swipe-left="onSwipeLeft();"> <md-content ng-if="main.loaded" ng-include="'partials/main.html'" layout="column" flex></md-content> <div ng-if="main.nothing" class="node-red-ui--notabs"> <table><tr><td><center><img src="icon120x120.png"></center></td></tr> <tr><td><center><h2>Welcome to the Node-RED Dashboard</h2></center></td></tr> <tr><td><center>Please add some UI nodes to your flow and redeploy.</center></td></tr></table> </div> <!-- <i class="fa fa-spinner fa-spin fa-4x fa-fw"></i> --> <script src="socket.io/socket.io.js"></script> <script src="js/app.min.js"></script> <script src="i18n.js"></script> </body> </html>
|
||||
612
nodered/rootfs/data/node_modules/node-red-dashboard/dist/js/app.min.js
generated
vendored
Normal file
2
nodered/rootfs/data/node_modules/node-red-dashboard/dist/js/gridstack.jQueryUI.min.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
!function(e){if("function"==typeof define&&define.amd)define(["jquery","lodash","gridstack","jquery-ui/data","jquery-ui/disable-selection","jquery-ui/focusable","jquery-ui/form","jquery-ui/ie","jquery-ui/keycode","jquery-ui/labels","jquery-ui/jquery-1-7","jquery-ui/plugin","jquery-ui/safe-active-element","jquery-ui/safe-blur","jquery-ui/scroll-parent","jquery-ui/tabbable","jquery-ui/unique-id","jquery-ui/version","jquery-ui/widget","jquery-ui/widgets/mouse","jquery-ui/widgets/draggable","jquery-ui/widgets/droppable","jquery-ui/widgets/resizable"],e);else if("undefined"!=typeof exports){try{jQuery=require("jquery")}catch(e){}try{_=require("lodash")}catch(e){}try{GridStackUI=require("gridstack")}catch(e){}e(jQuery,_,GridStackUI)}else e(jQuery,_,GridStackUI)}(function(a,n,r){window;function e(e){r.GridStackDragDropPlugin.call(this,e)}return r.GridStackDragDropPlugin.registerPlugin(e),((e.prototype=Object.create(r.GridStackDragDropPlugin.prototype)).constructor=e).prototype.resizable=function(e,r){if(e=a(e),"disable"===r||"enable"===r)e.resizable(r);else if("option"===r){var i=arguments[2],t=arguments[3];e.resizable(r,i,t)}else{var u=e.data("gs-resize-handles")?e.data("gs-resize-handles"):this.grid.opts.resizable.handles;e.resizable(n.extend({},this.grid.opts.resizable,{handles:u},{start:r.start||function(){},stop:r.stop||function(){},resize:r.resize||function(){}}))}return this},e.prototype.draggable=function(e,r){return e=a(e),"disable"===r||"enable"===r?e.draggable(r):e.draggable(n.extend({},this.grid.opts.draggable,{containment:this.grid.opts.isNested?this.grid.container.parent():null,start:r.start||function(){},stop:r.stop||function(){},drag:r.drag||function(){}})),this},e.prototype.droppable=function(e,r){return(e=a(e)).droppable(r),this},e.prototype.isDroppable=function(e,r){return e=a(e),Boolean(e.data("droppable"))},e.prototype.on=function(e,r,i){return a(e).on(r,i),this},e});
|
||||
//# sourceMappingURL=gridstack.min.map
|
||||
2
nodered/rootfs/data/node_modules/node-red-dashboard/dist/js/gridstack.min.js
generated
vendored
Normal file
137
nodered/rootfs/data/node_modules/node-red-dashboard/dist/js/lodash.min.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @license
|
||||
* Lodash lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
|
||||
*/
|
||||
;(function(){function n(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function t(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u<i;){var o=n[u];t(e,o,r(o),n)}return e}function r(n,t){for(var r=-1,e=null==n?0:n.length;++r<e&&false!==t(n[r],r,n););return n}function e(n,t){for(var r=null==n?0:n.length;r--&&false!==t(n[r],r,n););return n}function u(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(!t(n[r],r,n))return false;
|
||||
return true}function i(n,t){for(var r=-1,e=null==n?0:n.length,u=0,i=[];++r<e;){var o=n[r];t(o,r,n)&&(i[u++]=o)}return i}function o(n,t){return!(null==n||!n.length)&&-1<v(n,t,0)}function f(n,t,r){for(var e=-1,u=null==n?0:n.length;++e<u;)if(r(t,n[e]))return true;return false}function c(n,t){for(var r=-1,e=null==n?0:n.length,u=Array(e);++r<e;)u[r]=t(n[r],r,n);return u}function a(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];return n}function l(n,t,r,e){var u=-1,i=null==n?0:n.length;for(e&&i&&(r=n[++u]);++u<i;)r=t(r,n[u],u,n);
|
||||
return r}function s(n,t,r,e){var u=null==n?0:n.length;for(e&&u&&(r=n[--u]);u--;)r=t(r,n[u],u,n);return r}function h(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(t(n[r],r,n))return true;return false}function p(n,t,r){var e;return r(n,function(n,r,u){if(t(n,r,u))return e=r,false}),e}function _(n,t,r,e){var u=n.length;for(r+=e?1:-1;e?r--:++r<u;)if(t(n[r],r,n))return r;return-1}function v(n,t,r){if(t===t)n:{--r;for(var e=n.length;++r<e;)if(n[r]===t){n=r;break n}n=-1}else n=_(n,d,r);return n}function g(n,t,r,e){
|
||||
--r;for(var u=n.length;++r<u;)if(e(n[r],t))return r;return-1}function d(n){return n!==n}function y(n,t){var r=null==n?0:n.length;return r?m(n,t)/r:F}function b(n){return function(t){return null==t?T:t[n]}}function x(n){return function(t){return null==n?T:n[t]}}function j(n,t,r,e,u){return u(n,function(n,u,i){r=e?(e=false,n):t(r,n,u,i)}),r}function w(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].c;return n}function m(n,t){for(var r,e=-1,u=n.length;++e<u;){var i=t(n[e]);i!==T&&(r=r===T?i:r+i)}return r;
|
||||
}function A(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function E(n,t){return c(t,function(t){return[t,n[t]]})}function k(n){return function(t){return n(t)}}function S(n,t){return c(t,function(t){return n[t]})}function O(n,t){return n.has(t)}function I(n,t){for(var r=-1,e=n.length;++r<e&&-1<v(t,n[r],0););return r}function R(n,t){for(var r=n.length;r--&&-1<v(t,n[r],0););return r}function z(n){return"\\"+Un[n]}function W(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n];
|
||||
}),r}function B(n,t){return function(r){return n(t(r))}}function L(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){var o=n[r];o!==t&&"__lodash_placeholder__"!==o||(n[r]="__lodash_placeholder__",i[u++]=r)}return i}function U(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function C(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=[n,n]}),r}function D(n){if(Rn.test(n)){for(var t=On.lastIndex=0;On.test(n);)++t;n=t}else n=Qn(n);return n}function M(n){return Rn.test(n)?n.match(On)||[]:n.split("");
|
||||
}var T,$=1/0,F=NaN,N=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],P=/\b__p\+='';/g,Z=/\b(__p\+=)''\+/g,q=/(__e\(.*?\)|\b__t\))\+'';/g,V=/&(?:amp|lt|gt|quot|#39);/g,K=/[&<>"']/g,G=RegExp(V.source),H=RegExp(K.source),J=/<%-([\s\S]+?)%>/g,Y=/<%([\s\S]+?)%>/g,Q=/<%=([\s\S]+?)%>/g,X=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,nn=/^\w*$/,tn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,rn=/[\\^$.*+?()[\]{}|]/g,en=RegExp(rn.source),un=/^\s+|\s+$/g,on=/^\s+/,fn=/\s+$/,cn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,an=/\{\n\/\* \[wrapped with (.+)\] \*/,ln=/,? & /,sn=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,hn=/\\(\\)?/g,pn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,_n=/\w*$/,vn=/^[-+]0x[0-9a-f]+$/i,gn=/^0b[01]+$/i,dn=/^\[object .+?Constructor\]$/,yn=/^0o[0-7]+$/i,bn=/^(?:0|[1-9]\d*)$/,xn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,jn=/($^)/,wn=/['\n\r\u2028\u2029\\]/g,mn="[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?(?:\\u200d(?:[^\\ud800-\\udfff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?)*",An="(?:[\\u2700-\\u27bf]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])"+mn,En="(?:[^\\ud800-\\udfff][\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]?|[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\ud800-\\udfff])",kn=RegExp("['\u2019]","g"),Sn=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g"),On=RegExp("\\ud83c[\\udffb-\\udfff](?=\\ud83c[\\udffb-\\udfff])|"+En+mn,"g"),In=RegExp(["[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde]|$)|(?:[A-Z\\xc0-\\xd6\\xd8-\\xde]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde](?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])|$)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:d|ll|m|re|s|t|ve))?|[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?|\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])|\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])|\\d+",An].join("|"),"g"),Rn=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]"),zn=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Wn="Array Buffer DataView Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Map Math Object Promise RegExp Set String Symbol TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap _ clearTimeout isFinite parseInt setTimeout".split(" "),Bn={};
|
||||
Bn["[object Float32Array]"]=Bn["[object Float64Array]"]=Bn["[object Int8Array]"]=Bn["[object Int16Array]"]=Bn["[object Int32Array]"]=Bn["[object Uint8Array]"]=Bn["[object Uint8ClampedArray]"]=Bn["[object Uint16Array]"]=Bn["[object Uint32Array]"]=true,Bn["[object Arguments]"]=Bn["[object Array]"]=Bn["[object ArrayBuffer]"]=Bn["[object Boolean]"]=Bn["[object DataView]"]=Bn["[object Date]"]=Bn["[object Error]"]=Bn["[object Function]"]=Bn["[object Map]"]=Bn["[object Number]"]=Bn["[object Object]"]=Bn["[object RegExp]"]=Bn["[object Set]"]=Bn["[object String]"]=Bn["[object WeakMap]"]=false;
|
||||
var Ln={};Ln["[object Arguments]"]=Ln["[object Array]"]=Ln["[object ArrayBuffer]"]=Ln["[object DataView]"]=Ln["[object Boolean]"]=Ln["[object Date]"]=Ln["[object Float32Array]"]=Ln["[object Float64Array]"]=Ln["[object Int8Array]"]=Ln["[object Int16Array]"]=Ln["[object Int32Array]"]=Ln["[object Map]"]=Ln["[object Number]"]=Ln["[object Object]"]=Ln["[object RegExp]"]=Ln["[object Set]"]=Ln["[object String]"]=Ln["[object Symbol]"]=Ln["[object Uint8Array]"]=Ln["[object Uint8ClampedArray]"]=Ln["[object Uint16Array]"]=Ln["[object Uint32Array]"]=true,
|
||||
Ln["[object Error]"]=Ln["[object Function]"]=Ln["[object WeakMap]"]=false;var Un={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Cn=parseFloat,Dn=parseInt,Mn=typeof global=="object"&&global&&global.Object===Object&&global,Tn=typeof self=="object"&&self&&self.Object===Object&&self,$n=Mn||Tn||Function("return this")(),Fn=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Nn=Fn&&typeof module=="object"&&module&&!module.nodeType&&module,Pn=Nn&&Nn.exports===Fn,Zn=Pn&&Mn.process,qn=function(){
|
||||
try{var n=Nn&&Nn.f&&Nn.f("util").types;return n?n:Zn&&Zn.binding&&Zn.binding("util")}catch(n){}}(),Vn=qn&&qn.isArrayBuffer,Kn=qn&&qn.isDate,Gn=qn&&qn.isMap,Hn=qn&&qn.isRegExp,Jn=qn&&qn.isSet,Yn=qn&&qn.isTypedArray,Qn=b("length"),Xn=x({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I",
|
||||
"\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C",
|
||||
"\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i",
|
||||
"\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r",
|
||||
"\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij",
|
||||
"\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),nt=x({"&":"&","<":"<",">":">",'"':""","'":"'"}),tt=x({"&":"&","<":"<",">":">",""":'"',"'":"'"}),rt=function x(mn){function An(n){if(yu(n)&&!ff(n)&&!(n instanceof Un)){if(n instanceof On)return n;if(oi.call(n,"__wrapped__"))return Fe(n)}return new On(n)}function En(){}function On(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=T}function Un(n){this.__wrapped__=n,
|
||||
this.__actions__=[],this.__dir__=1,this.__filtered__=false,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Mn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Tn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Fn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Nn(n){var t=-1,r=null==n?0:n.length;for(this.__data__=new Fn;++t<r;)this.add(n[t]);
|
||||
}function Zn(n){this.size=(this.__data__=new Tn(n)).size}function qn(n,t){var r,e=ff(n),u=!e&&of(n),i=!e&&!u&&af(n),o=!e&&!u&&!i&&_f(n),u=(e=e||u||i||o)?A(n.length,ni):[],f=u.length;for(r in n)!t&&!oi.call(n,r)||e&&("length"==r||i&&("offset"==r||"parent"==r)||o&&("buffer"==r||"byteLength"==r||"byteOffset"==r)||Se(r,f))||u.push(r);return u}function Qn(n){var t=n.length;return t?n[ir(0,t-1)]:T}function et(n,t){return De(Ur(n),pt(t,0,n.length))}function ut(n){return De(Ur(n))}function it(n,t,r){(r===T||lu(n[t],r))&&(r!==T||t in n)||st(n,t,r);
|
||||
}function ot(n,t,r){var e=n[t];oi.call(n,t)&&lu(e,r)&&(r!==T||t in n)||st(n,t,r)}function ft(n,t){for(var r=n.length;r--;)if(lu(n[r][0],t))return r;return-1}function ct(n,t,r,e){return uo(n,function(n,u,i){t(e,n,r(n),i)}),e}function at(n,t){return n&&Cr(t,Wu(t),n)}function lt(n,t){return n&&Cr(t,Bu(t),n)}function st(n,t,r){"__proto__"==t&&Ai?Ai(n,t,{configurable:true,enumerable:true,value:r,writable:true}):n[t]=r}function ht(n,t){for(var r=-1,e=t.length,u=Ku(e),i=null==n;++r<e;)u[r]=i?T:Ru(n,t[r]);return u;
|
||||
}function pt(n,t,r){return n===n&&(r!==T&&(n=n<=r?n:r),t!==T&&(n=n>=t?n:t)),n}function _t(n,t,e,u,i,o){var f,c=1&t,a=2&t,l=4&t;if(e&&(f=i?e(n,u,i,o):e(n)),f!==T)return f;if(!du(n))return n;if(u=ff(n)){if(f=me(n),!c)return Ur(n,f)}else{var s=vo(n),h="[object Function]"==s||"[object GeneratorFunction]"==s;if(af(n))return Ir(n,c);if("[object Object]"==s||"[object Arguments]"==s||h&&!i){if(f=a||h?{}:Ae(n),!c)return a?Mr(n,lt(f,n)):Dr(n,at(f,n))}else{if(!Ln[s])return i?n:{};f=Ee(n,s,c)}}if(o||(o=new Zn),
|
||||
i=o.get(n))return i;o.set(n,f),pf(n)?n.forEach(function(r){f.add(_t(r,t,e,r,n,o))}):sf(n)&&n.forEach(function(r,u){f.set(u,_t(r,t,e,u,n,o))});var a=l?a?ve:_e:a?Bu:Wu,p=u?T:a(n);return r(p||n,function(r,u){p&&(u=r,r=n[u]),ot(f,u,_t(r,t,e,u,n,o))}),f}function vt(n){var t=Wu(n);return function(r){return gt(r,n,t)}}function gt(n,t,r){var e=r.length;if(null==n)return!e;for(n=Qu(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===T&&!(u in n)||!i(o))return false}return true}function dt(n,t,r){if(typeof n!="function")throw new ti("Expected a function");
|
||||
return bo(function(){n.apply(T,r)},t)}function yt(n,t,r,e){var u=-1,i=o,a=true,l=n.length,s=[],h=t.length;if(!l)return s;r&&(t=c(t,k(r))),e?(i=f,a=false):200<=t.length&&(i=O,a=false,t=new Nn(t));n:for(;++u<l;){var p=n[u],_=null==r?p:r(p),p=e||0!==p?p:0;if(a&&_===_){for(var v=h;v--;)if(t[v]===_)continue n;s.push(p)}else i(t,_,e)||s.push(p)}return s}function bt(n,t){var r=true;return uo(n,function(n,e,u){return r=!!t(n,e,u)}),r}function xt(n,t,r){for(var e=-1,u=n.length;++e<u;){var i=n[e],o=t(i);if(null!=o&&(f===T?o===o&&!wu(o):r(o,f)))var f=o,c=i;
|
||||
}return c}function jt(n,t){var r=[];return uo(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function wt(n,t,r,e,u){var i=-1,o=n.length;for(r||(r=ke),u||(u=[]);++i<o;){var f=n[i];0<t&&r(f)?1<t?wt(f,t-1,r,e,u):a(u,f):e||(u[u.length]=f)}return u}function mt(n,t){return n&&oo(n,t,Wu)}function At(n,t){return n&&fo(n,t,Wu)}function Et(n,t){return i(t,function(t){return _u(n[t])})}function kt(n,t){t=Sr(t,n);for(var r=0,e=t.length;null!=n&&r<e;)n=n[Me(t[r++])];return r&&r==e?n:T}function St(n,t,r){return t=t(n),
|
||||
ff(n)?t:a(t,r(n))}function Ot(n){if(null==n)n=n===T?"[object Undefined]":"[object Null]";else if(mi&&mi in Qu(n)){var t=oi.call(n,mi),r=n[mi];try{n[mi]=T;var e=true}catch(n){}var u=ai.call(n);e&&(t?n[mi]=r:delete n[mi]),n=u}else n=ai.call(n);return n}function It(n,t){return n>t}function Rt(n,t){return null!=n&&oi.call(n,t)}function zt(n,t){return null!=n&&t in Qu(n)}function Wt(n,t,r){for(var e=r?f:o,u=n[0].length,i=n.length,a=i,l=Ku(i),s=1/0,h=[];a--;){var p=n[a];a&&t&&(p=c(p,k(t))),s=Ci(p.length,s),
|
||||
l[a]=!r&&(t||120<=u&&120<=p.length)?new Nn(a&&p):T}var p=n[0],_=-1,v=l[0];n:for(;++_<u&&h.length<s;){var g=p[_],d=t?t(g):g,g=r||0!==g?g:0;if(v?!O(v,d):!e(h,d,r)){for(a=i;--a;){var y=l[a];if(y?!O(y,d):!e(n[a],d,r))continue n}v&&v.push(d),h.push(g)}}return h}function Bt(n,t,r){var e={};return mt(n,function(n,u,i){t(e,r(n),u,i)}),e}function Lt(t,r,e){return r=Sr(r,t),t=2>r.length?t:kt(t,hr(r,0,-1)),r=null==t?t:t[Me(Ve(r))],null==r?T:n(r,t,e)}function Ut(n){return yu(n)&&"[object Arguments]"==Ot(n)}function Ct(n){
|
||||
return yu(n)&&"[object ArrayBuffer]"==Ot(n)}function Dt(n){return yu(n)&&"[object Date]"==Ot(n)}function Mt(n,t,r,e,u){if(n===t)t=true;else if(null==n||null==t||!yu(n)&&!yu(t))t=n!==n&&t!==t;else n:{var i=ff(n),o=ff(t),f=i?"[object Array]":vo(n),c=o?"[object Array]":vo(t),f="[object Arguments]"==f?"[object Object]":f,c="[object Arguments]"==c?"[object Object]":c,a="[object Object]"==f,o="[object Object]"==c;if((c=f==c)&&af(n)){if(!af(t)){t=false;break n}i=true,a=false}if(c&&!a)u||(u=new Zn),t=i||_f(n)?se(n,t,r,e,Mt,u):he(n,t,f,r,e,Mt,u);else{
|
||||
if(!(1&r)&&(i=a&&oi.call(n,"__wrapped__"),f=o&&oi.call(t,"__wrapped__"),i||f)){n=i?n.value():n,t=f?t.value():t,u||(u=new Zn),t=Mt(n,t,r,e,u);break n}if(c)t:if(u||(u=new Zn),i=1&r,f=_e(n),o=f.length,c=_e(t).length,o==c||i){for(a=o;a--;){var l=f[a];if(!(i?l in t:oi.call(t,l))){t=false;break t}}if((c=u.get(n))&&u.get(t))t=c==t;else{c=true,u.set(n,t),u.set(t,n);for(var s=i;++a<o;){var l=f[a],h=n[l],p=t[l];if(e)var _=i?e(p,h,l,t,n,u):e(h,p,l,n,t,u);if(_===T?h!==p&&!Mt(h,p,r,e,u):!_){c=false;break}s||(s="constructor"==l);
|
||||
}c&&!s&&(r=n.constructor,e=t.constructor,r!=e&&"constructor"in n&&"constructor"in t&&!(typeof r=="function"&&r instanceof r&&typeof e=="function"&&e instanceof e)&&(c=false)),u.delete(n),u.delete(t),t=c}}else t=false;else t=false}}return t}function Tt(n){return yu(n)&&"[object Map]"==vo(n)}function $t(n,t,r,e){var u=r.length,i=u,o=!e;if(null==n)return!i;for(n=Qu(n);u--;){var f=r[u];if(o&&f[2]?f[1]!==n[f[0]]:!(f[0]in n))return false}for(;++u<i;){var f=r[u],c=f[0],a=n[c],l=f[1];if(o&&f[2]){if(a===T&&!(c in n))return false;
|
||||
}else{if(f=new Zn,e)var s=e(a,l,c,n,t,f);if(s===T?!Mt(l,a,3,e,f):!s)return false}}return true}function Ft(n){return!(!du(n)||ci&&ci in n)&&(_u(n)?hi:dn).test(Te(n))}function Nt(n){return yu(n)&&"[object RegExp]"==Ot(n)}function Pt(n){return yu(n)&&"[object Set]"==vo(n)}function Zt(n){return yu(n)&&gu(n.length)&&!!Bn[Ot(n)]}function qt(n){return typeof n=="function"?n:null==n?$u:typeof n=="object"?ff(n)?Jt(n[0],n[1]):Ht(n):Zu(n)}function Vt(n){if(!ze(n))return Li(n);var t,r=[];for(t in Qu(n))oi.call(n,t)&&"constructor"!=t&&r.push(t);
|
||||
return r}function Kt(n,t){return n<t}function Gt(n,t){var r=-1,e=su(n)?Ku(n.length):[];return uo(n,function(n,u,i){e[++r]=t(n,u,i)}),e}function Ht(n){var t=xe(n);return 1==t.length&&t[0][2]?We(t[0][0],t[0][1]):function(r){return r===n||$t(r,n,t)}}function Jt(n,t){return Ie(n)&&t===t&&!du(t)?We(Me(n),t):function(r){var e=Ru(r,n);return e===T&&e===t?zu(r,n):Mt(t,e,3)}}function Yt(n,t,r,e,u){n!==t&&oo(t,function(i,o){if(u||(u=new Zn),du(i)){var f=u,c=Le(n,o),a=Le(t,o),l=f.get(a);if(l)it(n,o,l);else{
|
||||
var l=e?e(c,a,o+"",n,t,f):T,s=l===T;if(s){var h=ff(a),p=!h&&af(a),_=!h&&!p&&_f(a),l=a;h||p||_?ff(c)?l=c:hu(c)?l=Ur(c):p?(s=false,l=Ir(a,true)):_?(s=false,l=zr(a,true)):l=[]:xu(a)||of(a)?(l=c,of(c)?l=Ou(c):du(c)&&!_u(c)||(l=Ae(a))):s=false}s&&(f.set(a,l),Yt(l,a,r,e,f),f.delete(a)),it(n,o,l)}}else f=e?e(Le(n,o),i,o+"",n,t,u):T,f===T&&(f=i),it(n,o,f)},Bu)}function Qt(n,t){var r=n.length;if(r)return t+=0>t?r:0,Se(t,r)?n[t]:T}function Xt(n,t,r){var e=-1;return t=c(t.length?t:[$u],k(ye())),n=Gt(n,function(n){return{
|
||||
a:c(t,function(t){return t(n)}),b:++e,c:n}}),w(n,function(n,t){var e;n:{e=-1;for(var u=n.a,i=t.a,o=u.length,f=r.length;++e<o;){var c=Wr(u[e],i[e]);if(c){e=e>=f?c:c*("desc"==r[e]?-1:1);break n}}e=n.b-t.b}return e})}function nr(n,t){return tr(n,t,function(t,r){return zu(n,r)})}function tr(n,t,r){for(var e=-1,u=t.length,i={};++e<u;){var o=t[e],f=kt(n,o);r(f,o)&&lr(i,Sr(o,n),f)}return i}function rr(n){return function(t){return kt(t,n)}}function er(n,t,r,e){var u=e?g:v,i=-1,o=t.length,f=n;for(n===t&&(t=Ur(t)),
|
||||
r&&(f=c(n,k(r)));++i<o;)for(var a=0,l=t[i],l=r?r(l):l;-1<(a=u(f,l,a,e));)f!==n&&xi.call(f,a,1),xi.call(n,a,1);return n}function ur(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];if(r==e||u!==i){var i=u;Se(u)?xi.call(n,u,1):xr(n,u)}}}function ir(n,t){return n+Ii(Ti()*(t-n+1))}function or(n,t){var r="";if(!n||1>t||9007199254740991<t)return r;do t%2&&(r+=n),(t=Ii(t/2))&&(n+=n);while(t);return r}function fr(n,t){return xo(Be(n,t,$u),n+"")}function cr(n){return Qn(Uu(n))}function ar(n,t){var r=Uu(n);
|
||||
return De(r,pt(t,0,r.length))}function lr(n,t,r,e){if(!du(n))return n;t=Sr(t,n);for(var u=-1,i=t.length,o=i-1,f=n;null!=f&&++u<i;){var c=Me(t[u]),a=r;if(u!=o){var l=f[c],a=e?e(l,c,f):T;a===T&&(a=du(l)?l:Se(t[u+1])?[]:{})}ot(f,c,a),f=f[c]}return n}function sr(n){return De(Uu(n))}function hr(n,t,r){var e=-1,u=n.length;for(0>t&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Ku(u);++e<u;)r[e]=n[e+t];return r}function pr(n,t){var r;return uo(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}
|
||||
function _r(n,t,r){var e=0,u=null==n?e:n.length;if(typeof t=="number"&&t===t&&2147483647>=u){for(;e<u;){var i=e+u>>>1,o=n[i];null!==o&&!wu(o)&&(r?o<=t:o<t)?e=i+1:u=i}return u}return vr(n,t,$u,r)}function vr(n,t,r,e){t=r(t);for(var u=0,i=null==n?0:n.length,o=t!==t,f=null===t,c=wu(t),a=t===T;u<i;){var l=Ii((u+i)/2),s=r(n[l]),h=s!==T,p=null===s,_=s===s,v=wu(s);(o?e||_:a?_&&(e||h):f?_&&h&&(e||!p):c?_&&h&&!p&&(e||!v):p||v?0:e?s<=t:s<t)?u=l+1:i=l}return Ci(i,4294967294)}function gr(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){
|
||||
var o=n[r],f=t?t(o):o;if(!r||!lu(f,c)){var c=f;i[u++]=0===o?0:o}}return i}function dr(n){return typeof n=="number"?n:wu(n)?F:+n}function yr(n){if(typeof n=="string")return n;if(ff(n))return c(n,yr)+"";if(wu(n))return ro?ro.call(n):"";var t=n+"";return"0"==t&&1/n==-$?"-0":t}function br(n,t,r){var e=-1,u=o,i=n.length,c=true,a=[],l=a;if(r)c=false,u=f;else if(200<=i){if(u=t?null:so(n))return U(u);c=false,u=O,l=new Nn}else l=t?[]:a;n:for(;++e<i;){var s=n[e],h=t?t(s):s,s=r||0!==s?s:0;if(c&&h===h){for(var p=l.length;p--;)if(l[p]===h)continue n;
|
||||
t&&l.push(h),a.push(s)}else u(l,h,r)||(l!==a&&l.push(h),a.push(s))}return a}function xr(n,t){return t=Sr(t,n),n=2>t.length?n:kt(n,hr(t,0,-1)),null==n||delete n[Me(Ve(t))]}function jr(n,t,r,e){for(var u=n.length,i=e?u:-1;(e?i--:++i<u)&&t(n[i],i,n););return r?hr(n,e?0:i,e?i+1:u):hr(n,e?i+1:0,e?u:i)}function wr(n,t){var r=n;return r instanceof Un&&(r=r.value()),l(t,function(n,t){return t.func.apply(t.thisArg,a([n],t.args))},r)}function mr(n,t,r){var e=n.length;if(2>e)return e?br(n[0]):[];for(var u=-1,i=Ku(e);++u<e;)for(var o=n[u],f=-1;++f<e;)f!=u&&(i[u]=yt(i[u]||o,n[f],t,r));
|
||||
return br(wt(i,1),t,r)}function Ar(n,t,r){for(var e=-1,u=n.length,i=t.length,o={};++e<u;)r(o,n[e],e<i?t[e]:T);return o}function Er(n){return hu(n)?n:[]}function kr(n){return typeof n=="function"?n:$u}function Sr(n,t){return ff(n)?n:Ie(n,t)?[n]:jo(Iu(n))}function Or(n,t,r){var e=n.length;return r=r===T?e:r,!t&&r>=e?n:hr(n,t,r)}function Ir(n,t){if(t)return n.slice();var r=n.length,r=gi?gi(r):new n.constructor(r);return n.copy(r),r}function Rr(n){var t=new n.constructor(n.byteLength);return new vi(t).set(new vi(n)),
|
||||
t}function zr(n,t){return new n.constructor(t?Rr(n.buffer):n.buffer,n.byteOffset,n.length)}function Wr(n,t){if(n!==t){var r=n!==T,e=null===n,u=n===n,i=wu(n),o=t!==T,f=null===t,c=t===t,a=wu(t);if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&n<t||a&&r&&u&&!e&&!i||f&&r&&u||!o&&u||!c)return-1}return 0}function Br(n,t,r,e){var u=-1,i=n.length,o=r.length,f=-1,c=t.length,a=Ui(i-o,0),l=Ku(c+a);for(e=!e;++f<c;)l[f]=t[f];for(;++u<o;)(e||u<i)&&(l[r[u]]=n[u]);for(;a--;)l[f++]=n[u++];
|
||||
return l}function Lr(n,t,r,e){var u=-1,i=n.length,o=-1,f=r.length,c=-1,a=t.length,l=Ui(i-f,0),s=Ku(l+a);for(e=!e;++u<l;)s[u]=n[u];for(l=u;++c<a;)s[l+c]=t[c];for(;++o<f;)(e||u<i)&&(s[l+r[o]]=n[u++]);return s}function Ur(n,t){var r=-1,e=n.length;for(t||(t=Ku(e));++r<e;)t[r]=n[r];return t}function Cr(n,t,r,e){var u=!r;r||(r={});for(var i=-1,o=t.length;++i<o;){var f=t[i],c=e?e(r[f],n[f],f,r,n):T;c===T&&(c=n[f]),u?st(r,f,c):ot(r,f,c)}return r}function Dr(n,t){return Cr(n,po(n),t)}function Mr(n,t){return Cr(n,_o(n),t);
|
||||
}function Tr(n,r){return function(e,u){var i=ff(e)?t:ct,o=r?r():{};return i(e,n,ye(u,2),o)}}function $r(n){return fr(function(t,r){var e=-1,u=r.length,i=1<u?r[u-1]:T,o=2<u?r[2]:T,i=3<n.length&&typeof i=="function"?(u--,i):T;for(o&&Oe(r[0],r[1],o)&&(i=3>u?T:i,u=1),t=Qu(t);++e<u;)(o=r[e])&&n(t,o,e,i);return t})}function Fr(n,t){return function(r,e){if(null==r)return r;if(!su(r))return n(r,e);for(var u=r.length,i=t?u:-1,o=Qu(r);(t?i--:++i<u)&&false!==e(o[i],i,o););return r}}function Nr(n){return function(t,r,e){
|
||||
var u=-1,i=Qu(t);e=e(t);for(var o=e.length;o--;){var f=e[n?o:++u];if(false===r(i[f],f,i))break}return t}}function Pr(n,t,r){function e(){return(this&&this!==$n&&this instanceof e?i:n).apply(u?r:this,arguments)}var u=1&t,i=Vr(n);return e}function Zr(n){return function(t){t=Iu(t);var r=Rn.test(t)?M(t):T,e=r?r[0]:t.charAt(0);return t=r?Or(r,1).join(""):t.slice(1),e[n]()+t}}function qr(n){return function(t){return l(Mu(Du(t).replace(kn,"")),n,"")}}function Vr(n){return function(){var t=arguments;switch(t.length){
|
||||
case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=eo(n.prototype),t=n.apply(r,t);return du(t)?t:r}}function Kr(t,r,e){function u(){for(var o=arguments.length,f=Ku(o),c=o,a=de(u);c--;)f[c]=arguments[c];return c=3>o&&f[0]!==a&&f[o-1]!==a?[]:L(f,a),
|
||||
o-=c.length,o<e?ue(t,r,Jr,u.placeholder,T,f,c,T,T,e-o):n(this&&this!==$n&&this instanceof u?i:t,this,f)}var i=Vr(t);return u}function Gr(n){return function(t,r,e){var u=Qu(t);if(!su(t)){var i=ye(r,3);t=Wu(t),r=function(n){return i(u[n],n,u)}}return r=n(t,r,e),-1<r?u[i?t[r]:r]:T}}function Hr(n){return pe(function(t){var r=t.length,e=r,u=On.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if(typeof i!="function")throw new ti("Expected a function");if(u&&!o&&"wrapper"==ge(i))var o=new On([],true)}for(e=o?e:r;++e<r;)var i=t[e],u=ge(i),f="wrapper"==u?ho(i):T,o=f&&Re(f[0])&&424==f[1]&&!f[4].length&&1==f[9]?o[ge(f[0])].apply(o,f[3]):1==i.length&&Re(i)?o[u]():o.thru(i);
|
||||
return function(){var n=arguments,e=n[0];if(o&&1==n.length&&ff(e))return o.plant(e).value();for(var u=0,n=r?t[u].apply(this,n):e;++u<r;)n=t[u].call(this,n);return n}})}function Jr(n,t,r,e,u,i,o,f,c,a){function l(){for(var d=arguments.length,y=Ku(d),b=d;b--;)y[b]=arguments[b];if(_){var x,j=de(l),b=y.length;for(x=0;b--;)y[b]===j&&++x}if(e&&(y=Br(y,e,u,_)),i&&(y=Lr(y,i,o,_)),d-=x,_&&d<a)return j=L(y,j),ue(n,t,Jr,l.placeholder,r,y,j,f,c,a-d);if(j=h?r:this,b=p?j[n]:n,d=y.length,f){x=y.length;for(var w=Ci(f.length,x),m=Ur(y);w--;){
|
||||
var A=f[w];y[w]=Se(A,x)?m[A]:T}}else v&&1<d&&y.reverse();return s&&c<d&&(y.length=c),this&&this!==$n&&this instanceof l&&(b=g||Vr(b)),b.apply(j,y)}var s=128&t,h=1&t,p=2&t,_=24&t,v=512&t,g=p?T:Vr(n);return l}function Yr(n,t){return function(r,e){return Bt(r,n,t(e))}}function Qr(n,t){return function(r,e){var u;if(r===T&&e===T)return t;if(r!==T&&(u=r),e!==T){if(u===T)return e;typeof r=="string"||typeof e=="string"?(r=yr(r),e=yr(e)):(r=dr(r),e=dr(e)),u=n(r,e)}return u}}function Xr(t){return pe(function(r){
|
||||
return r=c(r,k(ye())),fr(function(e){var u=this;return t(r,function(t){return n(t,u,e)})})})}function ne(n,t){t=t===T?" ":yr(t);var r=t.length;return 2>r?r?or(t,n):t:(r=or(t,Oi(n/D(t))),Rn.test(t)?Or(M(r),0,n).join(""):r.slice(0,n))}function te(t,r,e,u){function i(){for(var r=-1,c=arguments.length,a=-1,l=u.length,s=Ku(l+c),h=this&&this!==$n&&this instanceof i?f:t;++a<l;)s[a]=u[a];for(;c--;)s[a++]=arguments[++r];return n(h,o?e:this,s)}var o=1&r,f=Vr(t);return i}function re(n){return function(t,r,e){
|
||||
e&&typeof e!="number"&&Oe(t,r,e)&&(r=e=T),t=Au(t),r===T?(r=t,t=0):r=Au(r),e=e===T?t<r?1:-1:Au(e);var u=-1;r=Ui(Oi((r-t)/(e||1)),0);for(var i=Ku(r);r--;)i[n?r:++u]=t,t+=e;return i}}function ee(n){return function(t,r){return typeof t=="string"&&typeof r=="string"||(t=Su(t),r=Su(r)),n(t,r)}}function ue(n,t,r,e,u,i,o,f,c,a){var l=8&t,s=l?o:T;o=l?T:o;var h=l?i:T;return i=l?T:i,t=(t|(l?32:64))&~(l?64:32),4&t||(t&=-4),u=[n,t,u,h,s,i,o,f,c,a],r=r.apply(T,u),Re(n)&&yo(r,u),r.placeholder=e,Ue(r,n,t)}function ie(n){
|
||||
var t=Yu[n];return function(n,r){if(n=Su(n),(r=null==r?0:Ci(Eu(r),292))&&Wi(n)){var e=(Iu(n)+"e").split("e"),e=t(e[0]+"e"+(+e[1]+r)),e=(Iu(e)+"e").split("e");return+(e[0]+"e"+(+e[1]-r))}return t(n)}}function oe(n){return function(t){var r=vo(t);return"[object Map]"==r?W(t):"[object Set]"==r?C(t):E(t,n(t))}}function fe(n,t,r,e,u,i,o,f){var c=2&t;if(!c&&typeof n!="function")throw new ti("Expected a function");var a=e?e.length:0;if(a||(t&=-97,e=u=T),o=o===T?o:Ui(Eu(o),0),f=f===T?f:Eu(f),a-=u?u.length:0,
|
||||
64&t){var l=e,s=u;e=u=T}var h=c?T:ho(n);return i=[n,t,r,e,u,l,s,i,o,f],h&&(r=i[1],n=h[1],t=r|n,e=128==n&&8==r||128==n&&256==r&&i[7].length<=h[8]||384==n&&h[7].length<=h[8]&&8==r,131>t||e)&&(1&n&&(i[2]=h[2],t|=1&r?0:4),(r=h[3])&&(e=i[3],i[3]=e?Br(e,r,h[4]):r,i[4]=e?L(i[3],"__lodash_placeholder__"):h[4]),(r=h[5])&&(e=i[5],i[5]=e?Lr(e,r,h[6]):r,i[6]=e?L(i[5],"__lodash_placeholder__"):h[6]),(r=h[7])&&(i[7]=r),128&n&&(i[8]=null==i[8]?h[8]:Ci(i[8],h[8])),null==i[9]&&(i[9]=h[9]),i[0]=h[0],i[1]=t),n=i[0],
|
||||
t=i[1],r=i[2],e=i[3],u=i[4],f=i[9]=i[9]===T?c?0:n.length:Ui(i[9]-a,0),!f&&24&t&&(t&=-25),Ue((h?co:yo)(t&&1!=t?8==t||16==t?Kr(n,t,f):32!=t&&33!=t||u.length?Jr.apply(T,i):te(n,t,r,e):Pr(n,t,r),i),n,t)}function ce(n,t,r,e){return n===T||lu(n,ei[r])&&!oi.call(e,r)?t:n}function ae(n,t,r,e,u,i){return du(n)&&du(t)&&(i.set(t,n),Yt(n,t,T,ae,i),i.delete(t)),n}function le(n){return xu(n)?T:n}function se(n,t,r,e,u,i){var o=1&r,f=n.length,c=t.length;if(f!=c&&!(o&&c>f))return false;if((c=i.get(n))&&i.get(t))return c==t;
|
||||
var c=-1,a=true,l=2&r?new Nn:T;for(i.set(n,t),i.set(t,n);++c<f;){var s=n[c],p=t[c];if(e)var _=o?e(p,s,c,t,n,i):e(s,p,c,n,t,i);if(_!==T){if(_)continue;a=false;break}if(l){if(!h(t,function(n,t){if(!O(l,t)&&(s===n||u(s,n,r,e,i)))return l.push(t)})){a=false;break}}else if(s!==p&&!u(s,p,r,e,i)){a=false;break}}return i.delete(n),i.delete(t),a}function he(n,t,r,e,u,i,o){switch(r){case"[object DataView]":if(n.byteLength!=t.byteLength||n.byteOffset!=t.byteOffset)break;n=n.buffer,t=t.buffer;case"[object ArrayBuffer]":
|
||||
if(n.byteLength!=t.byteLength||!i(new vi(n),new vi(t)))break;return true;case"[object Boolean]":case"[object Date]":case"[object Number]":return lu(+n,+t);case"[object Error]":return n.name==t.name&&n.message==t.message;case"[object RegExp]":case"[object String]":return n==t+"";case"[object Map]":var f=W;case"[object Set]":if(f||(f=U),n.size!=t.size&&!(1&e))break;return(r=o.get(n))?r==t:(e|=2,o.set(n,t),t=se(f(n),f(t),e,u,i,o),o.delete(n),t);case"[object Symbol]":if(to)return to.call(n)==to.call(t)}
|
||||
return false}function pe(n){return xo(Be(n,T,Ze),n+"")}function _e(n){return St(n,Wu,po)}function ve(n){return St(n,Bu,_o)}function ge(n){for(var t=n.name+"",r=Gi[t],e=oi.call(Gi,t)?r.length:0;e--;){var u=r[e],i=u.func;if(null==i||i==n)return u.name}return t}function de(n){return(oi.call(An,"placeholder")?An:n).placeholder}function ye(){var n=An.iteratee||Fu,n=n===Fu?qt:n;return arguments.length?n(arguments[0],arguments[1]):n}function be(n,t){var r=n.__data__,e=typeof t;return("string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t)?r[typeof t=="string"?"string":"hash"]:r.map;
|
||||
}function xe(n){for(var t=Wu(n),r=t.length;r--;){var e=t[r],u=n[e];t[r]=[e,u,u===u&&!du(u)]}return t}function je(n,t){var r=null==n?T:n[t];return Ft(r)?r:T}function we(n,t,r){t=Sr(t,n);for(var e=-1,u=t.length,i=false;++e<u;){var o=Me(t[e]);if(!(i=null!=n&&r(n,o)))break;n=n[o]}return i||++e!=u?i:(u=null==n?0:n.length,!!u&&gu(u)&&Se(o,u)&&(ff(n)||of(n)))}function me(n){var t=n.length,r=new n.constructor(t);return t&&"string"==typeof n[0]&&oi.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function Ae(n){
|
||||
return typeof n.constructor!="function"||ze(n)?{}:eo(di(n))}function Ee(n,t,r){var e=n.constructor;switch(t){case"[object ArrayBuffer]":return Rr(n);case"[object Boolean]":case"[object Date]":return new e(+n);case"[object DataView]":return t=r?Rr(n.buffer):n.buffer,new n.constructor(t,n.byteOffset,n.byteLength);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":
|
||||
case"[object Uint16Array]":case"[object Uint32Array]":return zr(n,r);case"[object Map]":return new e;case"[object Number]":case"[object String]":return new e(n);case"[object RegExp]":return t=new n.constructor(n.source,_n.exec(n)),t.lastIndex=n.lastIndex,t;case"[object Set]":return new e;case"[object Symbol]":return to?Qu(to.call(n)):{}}}function ke(n){return ff(n)||of(n)||!!(ji&&n&&n[ji])}function Se(n,t){var r=typeof n;return t=null==t?9007199254740991:t,!!t&&("number"==r||"symbol"!=r&&bn.test(n))&&-1<n&&0==n%1&&n<t;
|
||||
}function Oe(n,t,r){if(!du(r))return false;var e=typeof t;return!!("number"==e?su(r)&&Se(t,r.length):"string"==e&&t in r)&&lu(r[t],n)}function Ie(n,t){if(ff(n))return false;var r=typeof n;return!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=n&&!wu(n))||(nn.test(n)||!X.test(n)||null!=t&&n in Qu(t))}function Re(n){var t=ge(n),r=An[t];return typeof r=="function"&&t in Un.prototype&&(n===r||(t=ho(r),!!t&&n===t[0]))}function ze(n){var t=n&&n.constructor;return n===(typeof t=="function"&&t.prototype||ei)}function We(n,t){
|
||||
return function(r){return null!=r&&(r[n]===t&&(t!==T||n in Qu(r)))}}function Be(t,r,e){return r=Ui(r===T?t.length-1:r,0),function(){for(var u=arguments,i=-1,o=Ui(u.length-r,0),f=Ku(o);++i<o;)f[i]=u[r+i];for(i=-1,o=Ku(r+1);++i<r;)o[i]=u[i];return o[r]=e(f),n(t,this,o)}}function Le(n,t){if(("constructor"!==t||"function"!=typeof n[t])&&"__proto__"!=t)return n[t]}function Ue(n,t,r){var e=t+"";t=xo;var u,i=$e;return u=(u=e.match(an))?u[1].split(ln):[],r=i(u,r),(i=r.length)&&(u=i-1,r[u]=(1<i?"& ":"")+r[u],
|
||||
r=r.join(2<i?", ":" "),e=e.replace(cn,"{\n/* [wrapped with "+r+"] */\n")),t(n,e)}function Ce(n){var t=0,r=0;return function(){var e=Di(),u=16-(e-r);if(r=e,0<u){if(800<=++t)return arguments[0]}else t=0;return n.apply(T,arguments)}}function De(n,t){var r=-1,e=n.length,u=e-1;for(t=t===T?e:t;++r<t;){var e=ir(r,u),i=n[e];n[e]=n[r],n[r]=i}return n.length=t,n}function Me(n){if(typeof n=="string"||wu(n))return n;var t=n+"";return"0"==t&&1/n==-$?"-0":t}function Te(n){if(null!=n){try{return ii.call(n)}catch(n){}
|
||||
return n+""}return""}function $e(n,t){return r(N,function(r){var e="_."+r[0];t&r[1]&&!o(n,e)&&n.push(e)}),n.sort()}function Fe(n){if(n instanceof Un)return n.clone();var t=new On(n.__wrapped__,n.__chain__);return t.__actions__=Ur(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function Ne(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Eu(r),0>r&&(r=Ui(e+r,0)),_(n,ye(t,3),r)):-1}function Pe(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e-1;return r!==T&&(u=Eu(r),u=0>r?Ui(e+u,0):Ci(u,e-1)),
|
||||
_(n,ye(t,3),u,true)}function Ze(n){return(null==n?0:n.length)?wt(n,1):[]}function qe(n){return n&&n.length?n[0]:T}function Ve(n){var t=null==n?0:n.length;return t?n[t-1]:T}function Ke(n,t){return n&&n.length&&t&&t.length?er(n,t):n}function Ge(n){return null==n?n:$i.call(n)}function He(n){if(!n||!n.length)return[];var t=0;return n=i(n,function(n){if(hu(n))return t=Ui(n.length,t),true}),A(t,function(t){return c(n,b(t))})}function Je(t,r){if(!t||!t.length)return[];var e=He(t);return null==r?e:c(e,function(t){
|
||||
return n(r,T,t)})}function Ye(n){return n=An(n),n.__chain__=true,n}function Qe(n,t){return t(n)}function Xe(){return this}function nu(n,t){return(ff(n)?r:uo)(n,ye(t,3))}function tu(n,t){return(ff(n)?e:io)(n,ye(t,3))}function ru(n,t){return(ff(n)?c:Gt)(n,ye(t,3))}function eu(n,t,r){return t=r?T:t,t=n&&null==t?n.length:t,fe(n,128,T,T,T,T,t)}function uu(n,t){var r;if(typeof t!="function")throw new ti("Expected a function");return n=Eu(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=T),
|
||||
r}}function iu(n,t,r){return t=r?T:t,n=fe(n,8,T,T,T,T,T,t),n.placeholder=iu.placeholder,n}function ou(n,t,r){return t=r?T:t,n=fe(n,16,T,T,T,T,T,t),n.placeholder=ou.placeholder,n}function fu(n,t,r){function e(t){var r=c,e=a;return c=a=T,_=t,s=n.apply(e,r)}function u(n){var r=n-p;return n-=_,p===T||r>=t||0>r||g&&n>=l}function i(){var n=Go();if(u(n))return o(n);var r,e=bo;r=n-_,n=t-(n-p),r=g?Ci(n,l-r):n,h=e(i,r)}function o(n){return h=T,d&&c?e(n):(c=a=T,s)}function f(){var n=Go(),r=u(n);if(c=arguments,
|
||||
a=this,p=n,r){if(h===T)return _=n=p,h=bo(i,t),v?e(n):s;if(g)return lo(h),h=bo(i,t),e(p)}return h===T&&(h=bo(i,t)),s}var c,a,l,s,h,p,_=0,v=false,g=false,d=true;if(typeof n!="function")throw new ti("Expected a function");return t=Su(t)||0,du(r)&&(v=!!r.leading,l=(g="maxWait"in r)?Ui(Su(r.maxWait)||0,t):l,d="trailing"in r?!!r.trailing:d),f.cancel=function(){h!==T&&lo(h),_=0,c=p=a=h=T},f.flush=function(){return h===T?s:o(Go())},f}function cu(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;
|
||||
return i.has(u)?i.get(u):(e=n.apply(this,e),r.cache=i.set(u,e)||i,e)}if(typeof n!="function"||null!=t&&typeof t!="function")throw new ti("Expected a function");return r.cache=new(cu.Cache||Fn),r}function au(n){if(typeof n!="function")throw new ti("Expected a function");return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function lu(n,t){return n===t||n!==n&&t!==t;
|
||||
}function su(n){return null!=n&&gu(n.length)&&!_u(n)}function hu(n){return yu(n)&&su(n)}function pu(n){if(!yu(n))return false;var t=Ot(n);return"[object Error]"==t||"[object DOMException]"==t||typeof n.message=="string"&&typeof n.name=="string"&&!xu(n)}function _u(n){return!!du(n)&&(n=Ot(n),"[object Function]"==n||"[object GeneratorFunction]"==n||"[object AsyncFunction]"==n||"[object Proxy]"==n)}function vu(n){return typeof n=="number"&&n==Eu(n)}function gu(n){return typeof n=="number"&&-1<n&&0==n%1&&9007199254740991>=n;
|
||||
}function du(n){var t=typeof n;return null!=n&&("object"==t||"function"==t)}function yu(n){return null!=n&&typeof n=="object"}function bu(n){return typeof n=="number"||yu(n)&&"[object Number]"==Ot(n)}function xu(n){return!(!yu(n)||"[object Object]"!=Ot(n))&&(n=di(n),null===n||(n=oi.call(n,"constructor")&&n.constructor,typeof n=="function"&&n instanceof n&&ii.call(n)==li))}function ju(n){return typeof n=="string"||!ff(n)&&yu(n)&&"[object String]"==Ot(n)}function wu(n){return typeof n=="symbol"||yu(n)&&"[object Symbol]"==Ot(n);
|
||||
}function mu(n){if(!n)return[];if(su(n))return ju(n)?M(n):Ur(n);if(wi&&n[wi]){n=n[wi]();for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}return t=vo(n),("[object Map]"==t?W:"[object Set]"==t?U:Uu)(n)}function Au(n){return n?(n=Su(n),n===$||n===-$?1.7976931348623157e308*(0>n?-1:1):n===n?n:0):0===n?n:0}function Eu(n){n=Au(n);var t=n%1;return n===n?t?n-t:n:0}function ku(n){return n?pt(Eu(n),0,4294967295):0}function Su(n){if(typeof n=="number")return n;if(wu(n))return F;if(du(n)&&(n=typeof n.valueOf=="function"?n.valueOf():n,
|
||||
n=du(n)?n+"":n),typeof n!="string")return 0===n?n:+n;n=n.replace(un,"");var t=gn.test(n);return t||yn.test(n)?Dn(n.slice(2),t?2:8):vn.test(n)?F:+n}function Ou(n){return Cr(n,Bu(n))}function Iu(n){return null==n?"":yr(n)}function Ru(n,t,r){return n=null==n?T:kt(n,t),n===T?r:n}function zu(n,t){return null!=n&&we(n,t,zt)}function Wu(n){return su(n)?qn(n):Vt(n)}function Bu(n){if(su(n))n=qn(n,true);else if(du(n)){var t,r=ze(n),e=[];for(t in n)("constructor"!=t||!r&&oi.call(n,t))&&e.push(t);n=e}else{if(t=[],
|
||||
null!=n)for(r in Qu(n))t.push(r);n=t}return n}function Lu(n,t){if(null==n)return{};var r=c(ve(n),function(n){return[n]});return t=ye(t),tr(n,r,function(n,r){return t(n,r[0])})}function Uu(n){return null==n?[]:S(n,Wu(n))}function Cu(n){return $f(Iu(n).toLowerCase())}function Du(n){return(n=Iu(n))&&n.replace(xn,Xn).replace(Sn,"")}function Mu(n,t,r){return n=Iu(n),t=r?T:t,t===T?zn.test(n)?n.match(In)||[]:n.match(sn)||[]:n.match(t)||[]}function Tu(n){return function(){return n}}function $u(n){return n;
|
||||
}function Fu(n){return qt(typeof n=="function"?n:_t(n,1))}function Nu(n,t,e){var u=Wu(t),i=Et(t,u);null!=e||du(t)&&(i.length||!u.length)||(e=t,t=n,n=this,i=Et(t,Wu(t)));var o=!(du(e)&&"chain"in e&&!e.chain),f=_u(n);return r(i,function(r){var e=t[r];n[r]=e,f&&(n.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=n(this.__wrapped__);return(r.__actions__=Ur(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,a([this.value()],arguments))})}),n}function Pu(){}
|
||||
function Zu(n){return Ie(n)?b(Me(n)):rr(n)}function qu(){return[]}function Vu(){return false}mn=null==mn?$n:rt.defaults($n.Object(),mn,rt.pick($n,Wn));var Ku=mn.Array,Gu=mn.Date,Hu=mn.Error,Ju=mn.Function,Yu=mn.Math,Qu=mn.Object,Xu=mn.RegExp,ni=mn.String,ti=mn.TypeError,ri=Ku.prototype,ei=Qu.prototype,ui=mn["__core-js_shared__"],ii=Ju.prototype.toString,oi=ei.hasOwnProperty,fi=0,ci=function(){var n=/[^.]+$/.exec(ui&&ui.keys&&ui.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),ai=ei.toString,li=ii.call(Qu),si=$n._,hi=Xu("^"+ii.call(oi).replace(rn,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),pi=Pn?mn.Buffer:T,_i=mn.Symbol,vi=mn.Uint8Array,gi=pi?pi.g:T,di=B(Qu.getPrototypeOf,Qu),yi=Qu.create,bi=ei.propertyIsEnumerable,xi=ri.splice,ji=_i?_i.isConcatSpreadable:T,wi=_i?_i.iterator:T,mi=_i?_i.toStringTag:T,Ai=function(){
|
||||
try{var n=je(Qu,"defineProperty");return n({},"",{}),n}catch(n){}}(),Ei=mn.clearTimeout!==$n.clearTimeout&&mn.clearTimeout,ki=Gu&&Gu.now!==$n.Date.now&&Gu.now,Si=mn.setTimeout!==$n.setTimeout&&mn.setTimeout,Oi=Yu.ceil,Ii=Yu.floor,Ri=Qu.getOwnPropertySymbols,zi=pi?pi.isBuffer:T,Wi=mn.isFinite,Bi=ri.join,Li=B(Qu.keys,Qu),Ui=Yu.max,Ci=Yu.min,Di=Gu.now,Mi=mn.parseInt,Ti=Yu.random,$i=ri.reverse,Fi=je(mn,"DataView"),Ni=je(mn,"Map"),Pi=je(mn,"Promise"),Zi=je(mn,"Set"),qi=je(mn,"WeakMap"),Vi=je(Qu,"create"),Ki=qi&&new qi,Gi={},Hi=Te(Fi),Ji=Te(Ni),Yi=Te(Pi),Qi=Te(Zi),Xi=Te(qi),no=_i?_i.prototype:T,to=no?no.valueOf:T,ro=no?no.toString:T,eo=function(){
|
||||
function n(){}return function(t){return du(t)?yi?yi(t):(n.prototype=t,t=new n,n.prototype=T,t):{}}}();An.templateSettings={escape:J,evaluate:Y,interpolate:Q,variable:"",imports:{_:An}},An.prototype=En.prototype,An.prototype.constructor=An,On.prototype=eo(En.prototype),On.prototype.constructor=On,Un.prototype=eo(En.prototype),Un.prototype.constructor=Un,Mn.prototype.clear=function(){this.__data__=Vi?Vi(null):{},this.size=0},Mn.prototype.delete=function(n){return n=this.has(n)&&delete this.__data__[n],
|
||||
this.size-=n?1:0,n},Mn.prototype.get=function(n){var t=this.__data__;return Vi?(n=t[n],"__lodash_hash_undefined__"===n?T:n):oi.call(t,n)?t[n]:T},Mn.prototype.has=function(n){var t=this.__data__;return Vi?t[n]!==T:oi.call(t,n)},Mn.prototype.set=function(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=Vi&&t===T?"__lodash_hash_undefined__":t,this},Tn.prototype.clear=function(){this.__data__=[],this.size=0},Tn.prototype.delete=function(n){var t=this.__data__;return n=ft(t,n),!(0>n)&&(n==t.length-1?t.pop():xi.call(t,n,1),
|
||||
--this.size,true)},Tn.prototype.get=function(n){var t=this.__data__;return n=ft(t,n),0>n?T:t[n][1]},Tn.prototype.has=function(n){return-1<ft(this.__data__,n)},Tn.prototype.set=function(n,t){var r=this.__data__,e=ft(r,n);return 0>e?(++this.size,r.push([n,t])):r[e][1]=t,this},Fn.prototype.clear=function(){this.size=0,this.__data__={hash:new Mn,map:new(Ni||Tn),string:new Mn}},Fn.prototype.delete=function(n){return n=be(this,n).delete(n),this.size-=n?1:0,n},Fn.prototype.get=function(n){return be(this,n).get(n);
|
||||
},Fn.prototype.has=function(n){return be(this,n).has(n)},Fn.prototype.set=function(n,t){var r=be(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},Nn.prototype.add=Nn.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},Nn.prototype.has=function(n){return this.__data__.has(n)},Zn.prototype.clear=function(){this.__data__=new Tn,this.size=0},Zn.prototype.delete=function(n){var t=this.__data__;return n=t.delete(n),this.size=t.size,n},Zn.prototype.get=function(n){
|
||||
return this.__data__.get(n)},Zn.prototype.has=function(n){return this.__data__.has(n)},Zn.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Tn){var e=r.__data__;if(!Ni||199>e.length)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Fn(e)}return r.set(n,t),this.size=r.size,this};var uo=Fr(mt),io=Fr(At,true),oo=Nr(),fo=Nr(true),co=Ki?function(n,t){return Ki.set(n,t),n}:$u,ao=Ai?function(n,t){return Ai(n,"toString",{configurable:true,enumerable:false,value:Tu(t),writable:true})}:$u,lo=Ei||function(n){
|
||||
return $n.clearTimeout(n)},so=Zi&&1/U(new Zi([,-0]))[1]==$?function(n){return new Zi(n)}:Pu,ho=Ki?function(n){return Ki.get(n)}:Pu,po=Ri?function(n){return null==n?[]:(n=Qu(n),i(Ri(n),function(t){return bi.call(n,t)}))}:qu,_o=Ri?function(n){for(var t=[];n;)a(t,po(n)),n=di(n);return t}:qu,vo=Ot;(Fi&&"[object DataView]"!=vo(new Fi(new ArrayBuffer(1)))||Ni&&"[object Map]"!=vo(new Ni)||Pi&&"[object Promise]"!=vo(Pi.resolve())||Zi&&"[object Set]"!=vo(new Zi)||qi&&"[object WeakMap]"!=vo(new qi))&&(vo=function(n){
|
||||
var t=Ot(n);if(n=(n="[object Object]"==t?n.constructor:T)?Te(n):"")switch(n){case Hi:return"[object DataView]";case Ji:return"[object Map]";case Yi:return"[object Promise]";case Qi:return"[object Set]";case Xi:return"[object WeakMap]"}return t});var go=ui?_u:Vu,yo=Ce(co),bo=Si||function(n,t){return $n.setTimeout(n,t)},xo=Ce(ao),jo=function(n){n=cu(n,function(n){return 500===t.size&&t.clear(),n});var t=n.cache;return n}(function(n){var t=[];return 46===n.charCodeAt(0)&&t.push(""),n.replace(tn,function(n,r,e,u){
|
||||
t.push(e?u.replace(hn,"$1"):r||n)}),t}),wo=fr(function(n,t){return hu(n)?yt(n,wt(t,1,hu,true)):[]}),mo=fr(function(n,t){var r=Ve(t);return hu(r)&&(r=T),hu(n)?yt(n,wt(t,1,hu,true),ye(r,2)):[]}),Ao=fr(function(n,t){var r=Ve(t);return hu(r)&&(r=T),hu(n)?yt(n,wt(t,1,hu,true),T,r):[]}),Eo=fr(function(n){var t=c(n,Er);return t.length&&t[0]===n[0]?Wt(t):[]}),ko=fr(function(n){var t=Ve(n),r=c(n,Er);return t===Ve(r)?t=T:r.pop(),r.length&&r[0]===n[0]?Wt(r,ye(t,2)):[]}),So=fr(function(n){var t=Ve(n),r=c(n,Er);return(t=typeof t=="function"?t:T)&&r.pop(),
|
||||
r.length&&r[0]===n[0]?Wt(r,T,t):[]}),Oo=fr(Ke),Io=pe(function(n,t){var r=null==n?0:n.length,e=ht(n,t);return ur(n,c(t,function(n){return Se(n,r)?+n:n}).sort(Wr)),e}),Ro=fr(function(n){return br(wt(n,1,hu,true))}),zo=fr(function(n){var t=Ve(n);return hu(t)&&(t=T),br(wt(n,1,hu,true),ye(t,2))}),Wo=fr(function(n){var t=Ve(n),t=typeof t=="function"?t:T;return br(wt(n,1,hu,true),T,t)}),Bo=fr(function(n,t){return hu(n)?yt(n,t):[]}),Lo=fr(function(n){return mr(i(n,hu))}),Uo=fr(function(n){var t=Ve(n);return hu(t)&&(t=T),
|
||||
mr(i(n,hu),ye(t,2))}),Co=fr(function(n){var t=Ve(n),t=typeof t=="function"?t:T;return mr(i(n,hu),T,t)}),Do=fr(He),Mo=fr(function(n){var t=n.length,t=1<t?n[t-1]:T,t=typeof t=="function"?(n.pop(),t):T;return Je(n,t)}),To=pe(function(n){function t(t){return ht(t,n)}var r=n.length,e=r?n[0]:0,u=this.__wrapped__;return!(1<r||this.__actions__.length)&&u instanceof Un&&Se(e)?(u=u.slice(e,+e+(r?1:0)),u.__actions__.push({func:Qe,args:[t],thisArg:T}),new On(u,this.__chain__).thru(function(n){return r&&!n.length&&n.push(T),
|
||||
n})):this.thru(t)}),$o=Tr(function(n,t,r){oi.call(n,r)?++n[r]:st(n,r,1)}),Fo=Gr(Ne),No=Gr(Pe),Po=Tr(function(n,t,r){oi.call(n,r)?n[r].push(t):st(n,r,[t])}),Zo=fr(function(t,r,e){var u=-1,i=typeof r=="function",o=su(t)?Ku(t.length):[];return uo(t,function(t){o[++u]=i?n(r,t,e):Lt(t,r,e)}),o}),qo=Tr(function(n,t,r){st(n,r,t)}),Vo=Tr(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),Ko=fr(function(n,t){if(null==n)return[];var r=t.length;return 1<r&&Oe(n,t[0],t[1])?t=[]:2<r&&Oe(t[0],t[1],t[2])&&(t=[t[0]]),
|
||||
Xt(n,wt(t,1),[])}),Go=ki||function(){return $n.Date.now()},Ho=fr(function(n,t,r){var e=1;if(r.length)var u=L(r,de(Ho)),e=32|e;return fe(n,e,t,r,u)}),Jo=fr(function(n,t,r){var e=3;if(r.length)var u=L(r,de(Jo)),e=32|e;return fe(t,e,n,r,u)}),Yo=fr(function(n,t){return dt(n,1,t)}),Qo=fr(function(n,t,r){return dt(n,Su(t)||0,r)});cu.Cache=Fn;var Xo=fr(function(t,r){r=1==r.length&&ff(r[0])?c(r[0],k(ye())):c(wt(r,1),k(ye()));var e=r.length;return fr(function(u){for(var i=-1,o=Ci(u.length,e);++i<o;)u[i]=r[i].call(this,u[i]);
|
||||
return n(t,this,u)})}),nf=fr(function(n,t){return fe(n,32,T,t,L(t,de(nf)))}),tf=fr(function(n,t){return fe(n,64,T,t,L(t,de(tf)))}),rf=pe(function(n,t){return fe(n,256,T,T,T,t)}),ef=ee(It),uf=ee(function(n,t){return n>=t}),of=Ut(function(){return arguments}())?Ut:function(n){return yu(n)&&oi.call(n,"callee")&&!bi.call(n,"callee")},ff=Ku.isArray,cf=Vn?k(Vn):Ct,af=zi||Vu,lf=Kn?k(Kn):Dt,sf=Gn?k(Gn):Tt,hf=Hn?k(Hn):Nt,pf=Jn?k(Jn):Pt,_f=Yn?k(Yn):Zt,vf=ee(Kt),gf=ee(function(n,t){return n<=t}),df=$r(function(n,t){
|
||||
if(ze(t)||su(t))Cr(t,Wu(t),n);else for(var r in t)oi.call(t,r)&&ot(n,r,t[r])}),yf=$r(function(n,t){Cr(t,Bu(t),n)}),bf=$r(function(n,t,r,e){Cr(t,Bu(t),n,e)}),xf=$r(function(n,t,r,e){Cr(t,Wu(t),n,e)}),jf=pe(ht),wf=fr(function(n,t){n=Qu(n);var r=-1,e=t.length,u=2<e?t[2]:T;for(u&&Oe(t[0],t[1],u)&&(e=1);++r<e;)for(var u=t[r],i=Bu(u),o=-1,f=i.length;++o<f;){var c=i[o],a=n[c];(a===T||lu(a,ei[c])&&!oi.call(n,c))&&(n[c]=u[c])}return n}),mf=fr(function(t){return t.push(T,ae),n(Of,T,t)}),Af=Yr(function(n,t,r){
|
||||
null!=t&&typeof t.toString!="function"&&(t=ai.call(t)),n[t]=r},Tu($u)),Ef=Yr(function(n,t,r){null!=t&&typeof t.toString!="function"&&(t=ai.call(t)),oi.call(n,t)?n[t].push(r):n[t]=[r]},ye),kf=fr(Lt),Sf=$r(function(n,t,r){Yt(n,t,r)}),Of=$r(function(n,t,r,e){Yt(n,t,r,e)}),If=pe(function(n,t){var r={};if(null==n)return r;var e=false;t=c(t,function(t){return t=Sr(t,n),e||(e=1<t.length),t}),Cr(n,ve(n),r),e&&(r=_t(r,7,le));for(var u=t.length;u--;)xr(r,t[u]);return r}),Rf=pe(function(n,t){return null==n?{}:nr(n,t);
|
||||
}),zf=oe(Wu),Wf=oe(Bu),Bf=qr(function(n,t,r){return t=t.toLowerCase(),n+(r?Cu(t):t)}),Lf=qr(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Uf=qr(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Cf=Zr("toLowerCase"),Df=qr(function(n,t,r){return n+(r?"_":"")+t.toLowerCase()}),Mf=qr(function(n,t,r){return n+(r?" ":"")+$f(t)}),Tf=qr(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),$f=Zr("toUpperCase"),Ff=fr(function(t,r){try{return n(t,T,r)}catch(n){return pu(n)?n:new Hu(n)}}),Nf=pe(function(n,t){
|
||||
return r(t,function(t){t=Me(t),st(n,t,Ho(n[t],n))}),n}),Pf=Hr(),Zf=Hr(true),qf=fr(function(n,t){return function(r){return Lt(r,n,t)}}),Vf=fr(function(n,t){return function(r){return Lt(n,r,t)}}),Kf=Xr(c),Gf=Xr(u),Hf=Xr(h),Jf=re(),Yf=re(true),Qf=Qr(function(n,t){return n+t},0),Xf=ie("ceil"),nc=Qr(function(n,t){return n/t},1),tc=ie("floor"),rc=Qr(function(n,t){return n*t},1),ec=ie("round"),uc=Qr(function(n,t){return n-t},0);return An.after=function(n,t){if(typeof t!="function")throw new ti("Expected a function");
|
||||
return n=Eu(n),function(){if(1>--n)return t.apply(this,arguments)}},An.ary=eu,An.assign=df,An.assignIn=yf,An.assignInWith=bf,An.assignWith=xf,An.at=jf,An.before=uu,An.bind=Ho,An.bindAll=Nf,An.bindKey=Jo,An.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return ff(n)?n:[n]},An.chain=Ye,An.chunk=function(n,t,r){if(t=(r?Oe(n,t,r):t===T)?1:Ui(Eu(t),0),r=null==n?0:n.length,!r||1>t)return[];for(var e=0,u=0,i=Ku(Oi(r/t));e<r;)i[u++]=hr(n,e,e+=t);return i},An.compact=function(n){for(var t=-1,r=null==n?0:n.length,e=0,u=[];++t<r;){
|
||||
var i=n[t];i&&(u[e++]=i)}return u},An.concat=function(){var n=arguments.length;if(!n)return[];for(var t=Ku(n-1),r=arguments[0];n--;)t[n-1]=arguments[n];return a(ff(r)?Ur(r):[r],wt(t,1))},An.cond=function(t){var r=null==t?0:t.length,e=ye();return t=r?c(t,function(n){if("function"!=typeof n[1])throw new ti("Expected a function");return[e(n[0]),n[1]]}):[],fr(function(e){for(var u=-1;++u<r;){var i=t[u];if(n(i[0],this,e))return n(i[1],this,e)}})},An.conforms=function(n){return vt(_t(n,1))},An.constant=Tu,
|
||||
An.countBy=$o,An.create=function(n,t){var r=eo(n);return null==t?r:at(r,t)},An.curry=iu,An.curryRight=ou,An.debounce=fu,An.defaults=wf,An.defaultsDeep=mf,An.defer=Yo,An.delay=Qo,An.difference=wo,An.differenceBy=mo,An.differenceWith=Ao,An.drop=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),hr(n,0>t?0:t,e)):[]},An.dropRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),t=e-t,hr(n,0,0>t?0:t)):[]},An.dropRightWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),true,true):[];
|
||||
},An.dropWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),true):[]},An.fill=function(n,t,r,e){var u=null==n?0:n.length;if(!u)return[];for(r&&typeof r!="number"&&Oe(n,t,r)&&(r=0,e=u),u=n.length,r=Eu(r),0>r&&(r=-r>u?0:u+r),e=e===T||e>u?u:Eu(e),0>e&&(e+=u),e=r>e?0:ku(e);r<e;)n[r++]=t;return n},An.filter=function(n,t){return(ff(n)?i:jt)(n,ye(t,3))},An.flatMap=function(n,t){return wt(ru(n,t),1)},An.flatMapDeep=function(n,t){return wt(ru(n,t),$)},An.flatMapDepth=function(n,t,r){return r=r===T?1:Eu(r),
|
||||
wt(ru(n,t),r)},An.flatten=Ze,An.flattenDeep=function(n){return(null==n?0:n.length)?wt(n,$):[]},An.flattenDepth=function(n,t){return null!=n&&n.length?(t=t===T?1:Eu(t),wt(n,t)):[]},An.flip=function(n){return fe(n,512)},An.flow=Pf,An.flowRight=Zf,An.fromPairs=function(n){for(var t=-1,r=null==n?0:n.length,e={};++t<r;){var u=n[t];e[u[0]]=u[1]}return e},An.functions=function(n){return null==n?[]:Et(n,Wu(n))},An.functionsIn=function(n){return null==n?[]:Et(n,Bu(n))},An.groupBy=Po,An.initial=function(n){
|
||||
return(null==n?0:n.length)?hr(n,0,-1):[]},An.intersection=Eo,An.intersectionBy=ko,An.intersectionWith=So,An.invert=Af,An.invertBy=Ef,An.invokeMap=Zo,An.iteratee=Fu,An.keyBy=qo,An.keys=Wu,An.keysIn=Bu,An.map=ru,An.mapKeys=function(n,t){var r={};return t=ye(t,3),mt(n,function(n,e,u){st(r,t(n,e,u),n)}),r},An.mapValues=function(n,t){var r={};return t=ye(t,3),mt(n,function(n,e,u){st(r,e,t(n,e,u))}),r},An.matches=function(n){return Ht(_t(n,1))},An.matchesProperty=function(n,t){return Jt(n,_t(t,1))},An.memoize=cu,
|
||||
An.merge=Sf,An.mergeWith=Of,An.method=qf,An.methodOf=Vf,An.mixin=Nu,An.negate=au,An.nthArg=function(n){return n=Eu(n),fr(function(t){return Qt(t,n)})},An.omit=If,An.omitBy=function(n,t){return Lu(n,au(ye(t)))},An.once=function(n){return uu(2,n)},An.orderBy=function(n,t,r,e){return null==n?[]:(ff(t)||(t=null==t?[]:[t]),r=e?T:r,ff(r)||(r=null==r?[]:[r]),Xt(n,t,r))},An.over=Kf,An.overArgs=Xo,An.overEvery=Gf,An.overSome=Hf,An.partial=nf,An.partialRight=tf,An.partition=Vo,An.pick=Rf,An.pickBy=Lu,An.property=Zu,
|
||||
An.propertyOf=function(n){return function(t){return null==n?T:kt(n,t)}},An.pull=Oo,An.pullAll=Ke,An.pullAllBy=function(n,t,r){return n&&n.length&&t&&t.length?er(n,t,ye(r,2)):n},An.pullAllWith=function(n,t,r){return n&&n.length&&t&&t.length?er(n,t,T,r):n},An.pullAt=Io,An.range=Jf,An.rangeRight=Yf,An.rearg=rf,An.reject=function(n,t){return(ff(n)?i:jt)(n,au(ye(t,3)))},An.remove=function(n,t){var r=[];if(!n||!n.length)return r;var e=-1,u=[],i=n.length;for(t=ye(t,3);++e<i;){var o=n[e];t(o,e,n)&&(r.push(o),
|
||||
u.push(e))}return ur(n,u),r},An.rest=function(n,t){if(typeof n!="function")throw new ti("Expected a function");return t=t===T?t:Eu(t),fr(n,t)},An.reverse=Ge,An.sampleSize=function(n,t,r){return t=(r?Oe(n,t,r):t===T)?1:Eu(t),(ff(n)?et:ar)(n,t)},An.set=function(n,t,r){return null==n?n:lr(n,t,r)},An.setWith=function(n,t,r,e){return e=typeof e=="function"?e:T,null==n?n:lr(n,t,r,e)},An.shuffle=function(n){return(ff(n)?ut:sr)(n)},An.slice=function(n,t,r){var e=null==n?0:n.length;return e?(r&&typeof r!="number"&&Oe(n,t,r)?(t=0,
|
||||
r=e):(t=null==t?0:Eu(t),r=r===T?e:Eu(r)),hr(n,t,r)):[]},An.sortBy=Ko,An.sortedUniq=function(n){return n&&n.length?gr(n):[]},An.sortedUniqBy=function(n,t){return n&&n.length?gr(n,ye(t,2)):[]},An.split=function(n,t,r){return r&&typeof r!="number"&&Oe(n,t,r)&&(t=r=T),r=r===T?4294967295:r>>>0,r?(n=Iu(n))&&(typeof t=="string"||null!=t&&!hf(t))&&(t=yr(t),!t&&Rn.test(n))?Or(M(n),0,r):n.split(t,r):[]},An.spread=function(t,r){if(typeof t!="function")throw new ti("Expected a function");return r=null==r?0:Ui(Eu(r),0),
|
||||
fr(function(e){var u=e[r];return e=Or(e,0,r),u&&a(e,u),n(t,this,e)})},An.tail=function(n){var t=null==n?0:n.length;return t?hr(n,1,t):[]},An.take=function(n,t,r){return n&&n.length?(t=r||t===T?1:Eu(t),hr(n,0,0>t?0:t)):[]},An.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===T?1:Eu(t),t=e-t,hr(n,0>t?0:t,e)):[]},An.takeRightWhile=function(n,t){return n&&n.length?jr(n,ye(t,3),false,true):[]},An.takeWhile=function(n,t){return n&&n.length?jr(n,ye(t,3)):[]},An.tap=function(n,t){return t(n),
|
||||
n},An.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new ti("Expected a function");return du(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),fu(n,t,{leading:e,maxWait:t,trailing:u})},An.thru=Qe,An.toArray=mu,An.toPairs=zf,An.toPairsIn=Wf,An.toPath=function(n){return ff(n)?c(n,Me):wu(n)?[n]:Ur(jo(Iu(n)))},An.toPlainObject=Ou,An.transform=function(n,t,e){var u=ff(n),i=u||af(n)||_f(n);if(t=ye(t,4),null==e){var o=n&&n.constructor;e=i?u?new o:[]:du(n)&&_u(o)?eo(di(n)):{};
|
||||
}return(i?r:mt)(n,function(n,r,u){return t(e,n,r,u)}),e},An.unary=function(n){return eu(n,1)},An.union=Ro,An.unionBy=zo,An.unionWith=Wo,An.uniq=function(n){return n&&n.length?br(n):[]},An.uniqBy=function(n,t){return n&&n.length?br(n,ye(t,2)):[]},An.uniqWith=function(n,t){return t=typeof t=="function"?t:T,n&&n.length?br(n,T,t):[]},An.unset=function(n,t){return null==n||xr(n,t)},An.unzip=He,An.unzipWith=Je,An.update=function(n,t,r){return null==n?n:lr(n,t,kr(r)(kt(n,t)),void 0)},An.updateWith=function(n,t,r,e){
|
||||
return e=typeof e=="function"?e:T,null!=n&&(n=lr(n,t,kr(r)(kt(n,t)),e)),n},An.values=Uu,An.valuesIn=function(n){return null==n?[]:S(n,Bu(n))},An.without=Bo,An.words=Mu,An.wrap=function(n,t){return nf(kr(t),n)},An.xor=Lo,An.xorBy=Uo,An.xorWith=Co,An.zip=Do,An.zipObject=function(n,t){return Ar(n||[],t||[],ot)},An.zipObjectDeep=function(n,t){return Ar(n||[],t||[],lr)},An.zipWith=Mo,An.entries=zf,An.entriesIn=Wf,An.extend=yf,An.extendWith=bf,Nu(An,An),An.add=Qf,An.attempt=Ff,An.camelCase=Bf,An.capitalize=Cu,
|
||||
An.ceil=Xf,An.clamp=function(n,t,r){return r===T&&(r=t,t=T),r!==T&&(r=Su(r),r=r===r?r:0),t!==T&&(t=Su(t),t=t===t?t:0),pt(Su(n),t,r)},An.clone=function(n){return _t(n,4)},An.cloneDeep=function(n){return _t(n,5)},An.cloneDeepWith=function(n,t){return t=typeof t=="function"?t:T,_t(n,5,t)},An.cloneWith=function(n,t){return t=typeof t=="function"?t:T,_t(n,4,t)},An.conformsTo=function(n,t){return null==t||gt(n,t,Wu(t))},An.deburr=Du,An.defaultTo=function(n,t){return null==n||n!==n?t:n},An.divide=nc,An.endsWith=function(n,t,r){
|
||||
n=Iu(n),t=yr(t);var e=n.length,e=r=r===T?e:pt(Eu(r),0,e);return r-=t.length,0<=r&&n.slice(r,e)==t},An.eq=lu,An.escape=function(n){return(n=Iu(n))&&H.test(n)?n.replace(K,nt):n},An.escapeRegExp=function(n){return(n=Iu(n))&&en.test(n)?n.replace(rn,"\\$&"):n},An.every=function(n,t,r){var e=ff(n)?u:bt;return r&&Oe(n,t,r)&&(t=T),e(n,ye(t,3))},An.find=Fo,An.findIndex=Ne,An.findKey=function(n,t){return p(n,ye(t,3),mt)},An.findLast=No,An.findLastIndex=Pe,An.findLastKey=function(n,t){return p(n,ye(t,3),At);
|
||||
},An.floor=tc,An.forEach=nu,An.forEachRight=tu,An.forIn=function(n,t){return null==n?n:oo(n,ye(t,3),Bu)},An.forInRight=function(n,t){return null==n?n:fo(n,ye(t,3),Bu)},An.forOwn=function(n,t){return n&&mt(n,ye(t,3))},An.forOwnRight=function(n,t){return n&&At(n,ye(t,3))},An.get=Ru,An.gt=ef,An.gte=uf,An.has=function(n,t){return null!=n&&we(n,t,Rt)},An.hasIn=zu,An.head=qe,An.identity=$u,An.includes=function(n,t,r,e){return n=su(n)?n:Uu(n),r=r&&!e?Eu(r):0,e=n.length,0>r&&(r=Ui(e+r,0)),ju(n)?r<=e&&-1<n.indexOf(t,r):!!e&&-1<v(n,t,r);
|
||||
},An.indexOf=function(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Eu(r),0>r&&(r=Ui(e+r,0)),v(n,t,r)):-1},An.inRange=function(n,t,r){return t=Au(t),r===T?(r=t,t=0):r=Au(r),n=Su(n),n>=Ci(t,r)&&n<Ui(t,r)},An.invoke=kf,An.isArguments=of,An.isArray=ff,An.isArrayBuffer=cf,An.isArrayLike=su,An.isArrayLikeObject=hu,An.isBoolean=function(n){return true===n||false===n||yu(n)&&"[object Boolean]"==Ot(n)},An.isBuffer=af,An.isDate=lf,An.isElement=function(n){return yu(n)&&1===n.nodeType&&!xu(n)},An.isEmpty=function(n){
|
||||
if(null==n)return true;if(su(n)&&(ff(n)||typeof n=="string"||typeof n.splice=="function"||af(n)||_f(n)||of(n)))return!n.length;var t=vo(n);if("[object Map]"==t||"[object Set]"==t)return!n.size;if(ze(n))return!Vt(n).length;for(var r in n)if(oi.call(n,r))return false;return true},An.isEqual=function(n,t){return Mt(n,t)},An.isEqualWith=function(n,t,r){var e=(r=typeof r=="function"?r:T)?r(n,t):T;return e===T?Mt(n,t,T,r):!!e},An.isError=pu,An.isFinite=function(n){return typeof n=="number"&&Wi(n)},An.isFunction=_u,
|
||||
An.isInteger=vu,An.isLength=gu,An.isMap=sf,An.isMatch=function(n,t){return n===t||$t(n,t,xe(t))},An.isMatchWith=function(n,t,r){return r=typeof r=="function"?r:T,$t(n,t,xe(t),r)},An.isNaN=function(n){return bu(n)&&n!=+n},An.isNative=function(n){if(go(n))throw new Hu("Unsupported core-js use. Try https://npms.io/search?q=ponyfill.");return Ft(n)},An.isNil=function(n){return null==n},An.isNull=function(n){return null===n},An.isNumber=bu,An.isObject=du,An.isObjectLike=yu,An.isPlainObject=xu,An.isRegExp=hf,
|
||||
An.isSafeInteger=function(n){return vu(n)&&-9007199254740991<=n&&9007199254740991>=n},An.isSet=pf,An.isString=ju,An.isSymbol=wu,An.isTypedArray=_f,An.isUndefined=function(n){return n===T},An.isWeakMap=function(n){return yu(n)&&"[object WeakMap]"==vo(n)},An.isWeakSet=function(n){return yu(n)&&"[object WeakSet]"==Ot(n)},An.join=function(n,t){return null==n?"":Bi.call(n,t)},An.kebabCase=Lf,An.last=Ve,An.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;if(r!==T&&(u=Eu(r),u=0>u?Ui(e+u,0):Ci(u,e-1)),
|
||||
t===t){for(r=u+1;r--&&n[r]!==t;);n=r}else n=_(n,d,u,true);return n},An.lowerCase=Uf,An.lowerFirst=Cf,An.lt=vf,An.lte=gf,An.max=function(n){return n&&n.length?xt(n,$u,It):T},An.maxBy=function(n,t){return n&&n.length?xt(n,ye(t,2),It):T},An.mean=function(n){return y(n,$u)},An.meanBy=function(n,t){return y(n,ye(t,2))},An.min=function(n){return n&&n.length?xt(n,$u,Kt):T},An.minBy=function(n,t){return n&&n.length?xt(n,ye(t,2),Kt):T},An.stubArray=qu,An.stubFalse=Vu,An.stubObject=function(){return{}},An.stubString=function(){
|
||||
return""},An.stubTrue=function(){return true},An.multiply=rc,An.nth=function(n,t){return n&&n.length?Qt(n,Eu(t)):T},An.noConflict=function(){return $n._===this&&($n._=si),this},An.noop=Pu,An.now=Go,An.pad=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return!t||e>=t?n:(t=(t-e)/2,ne(Ii(t),r)+n+ne(Oi(t),r))},An.padEnd=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return t&&e<t?n+ne(t-e,r):n},An.padStart=function(n,t,r){n=Iu(n);var e=(t=Eu(t))?D(n):0;return t&&e<t?ne(t-e,r)+n:n},An.parseInt=function(n,t,r){
|
||||
return r||null==t?t=0:t&&(t=+t),Mi(Iu(n).replace(on,""),t||0)},An.random=function(n,t,r){if(r&&typeof r!="boolean"&&Oe(n,t,r)&&(t=r=T),r===T&&(typeof t=="boolean"?(r=t,t=T):typeof n=="boolean"&&(r=n,n=T)),n===T&&t===T?(n=0,t=1):(n=Au(n),t===T?(t=n,n=0):t=Au(t)),n>t){var e=n;n=t,t=e}return r||n%1||t%1?(r=Ti(),Ci(n+r*(t-n+Cn("1e-"+((r+"").length-1))),t)):ir(n,t)},An.reduce=function(n,t,r){var e=ff(n)?l:j,u=3>arguments.length;return e(n,ye(t,4),r,u,uo)},An.reduceRight=function(n,t,r){var e=ff(n)?s:j,u=3>arguments.length;
|
||||
return e(n,ye(t,4),r,u,io)},An.repeat=function(n,t,r){return t=(r?Oe(n,t,r):t===T)?1:Eu(t),or(Iu(n),t)},An.replace=function(){var n=arguments,t=Iu(n[0]);return 3>n.length?t:t.replace(n[1],n[2])},An.result=function(n,t,r){t=Sr(t,n);var e=-1,u=t.length;for(u||(u=1,n=T);++e<u;){var i=null==n?T:n[Me(t[e])];i===T&&(e=u,i=r),n=_u(i)?i.call(n):i}return n},An.round=ec,An.runInContext=x,An.sample=function(n){return(ff(n)?Qn:cr)(n)},An.size=function(n){if(null==n)return 0;if(su(n))return ju(n)?D(n):n.length;
|
||||
var t=vo(n);return"[object Map]"==t||"[object Set]"==t?n.size:Vt(n).length},An.snakeCase=Df,An.some=function(n,t,r){var e=ff(n)?h:pr;return r&&Oe(n,t,r)&&(t=T),e(n,ye(t,3))},An.sortedIndex=function(n,t){return _r(n,t)},An.sortedIndexBy=function(n,t,r){return vr(n,t,ye(r,2))},An.sortedIndexOf=function(n,t){var r=null==n?0:n.length;if(r){var e=_r(n,t);if(e<r&&lu(n[e],t))return e}return-1},An.sortedLastIndex=function(n,t){return _r(n,t,true)},An.sortedLastIndexBy=function(n,t,r){return vr(n,t,ye(r,2),true);
|
||||
},An.sortedLastIndexOf=function(n,t){if(null==n?0:n.length){var r=_r(n,t,true)-1;if(lu(n[r],t))return r}return-1},An.startCase=Mf,An.startsWith=function(n,t,r){return n=Iu(n),r=null==r?0:pt(Eu(r),0,n.length),t=yr(t),n.slice(r,r+t.length)==t},An.subtract=uc,An.sum=function(n){return n&&n.length?m(n,$u):0},An.sumBy=function(n,t){return n&&n.length?m(n,ye(t,2)):0},An.template=function(n,t,r){var e=An.templateSettings;r&&Oe(n,t,r)&&(t=T),n=Iu(n),t=bf({},t,e,ce),r=bf({},t.imports,e.imports,ce);var u,i,o=Wu(r),f=S(r,o),c=0;
|
||||
r=t.interpolate||jn;var a="__p+='";r=Xu((t.escape||jn).source+"|"+r.source+"|"+(r===Q?pn:jn).source+"|"+(t.evaluate||jn).source+"|$","g");var l=oi.call(t,"sourceURL")?"//# sourceURL="+(t.sourceURL+"").replace(/[\r\n]/g," ")+"\n":"";if(n.replace(r,function(t,r,e,o,f,l){return e||(e=o),a+=n.slice(c,l).replace(wn,z),r&&(u=true,a+="'+__e("+r+")+'"),f&&(i=true,a+="';"+f+";\n__p+='"),e&&(a+="'+((__t=("+e+"))==null?'':__t)+'"),c=l+t.length,t}),a+="';",(t=oi.call(t,"variable")&&t.variable)||(a="with(obj){"+a+"}"),
|
||||
a=(i?a.replace(P,""):a).replace(Z,"$1").replace(q,"$1;"),a="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(u?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+a+"return __p}",t=Ff(function(){return Ju(o,l+"return "+a).apply(T,f)}),t.source=a,pu(t))throw t;return t},An.times=function(n,t){if(n=Eu(n),1>n||9007199254740991<n)return[];var r=4294967295,e=Ci(n,4294967295);for(t=ye(t),n-=4294967295,e=A(e,t);++r<n;)t(r);return e},An.toFinite=Au,
|
||||
An.toInteger=Eu,An.toLength=ku,An.toLower=function(n){return Iu(n).toLowerCase()},An.toNumber=Su,An.toSafeInteger=function(n){return n?pt(Eu(n),-9007199254740991,9007199254740991):0===n?n:0},An.toString=Iu,An.toUpper=function(n){return Iu(n).toUpperCase()},An.trim=function(n,t,r){return(n=Iu(n))&&(r||t===T)?n.replace(un,""):n&&(t=yr(t))?(n=M(n),r=M(t),t=I(n,r),r=R(n,r)+1,Or(n,t,r).join("")):n},An.trimEnd=function(n,t,r){return(n=Iu(n))&&(r||t===T)?n.replace(fn,""):n&&(t=yr(t))?(n=M(n),t=R(n,M(t))+1,
|
||||
Or(n,0,t).join("")):n},An.trimStart=function(n,t,r){return(n=Iu(n))&&(r||t===T)?n.replace(on,""):n&&(t=yr(t))?(n=M(n),t=I(n,M(t)),Or(n,t).join("")):n},An.truncate=function(n,t){var r=30,e="...";if(du(t))var u="separator"in t?t.separator:u,r="length"in t?Eu(t.length):r,e="omission"in t?yr(t.omission):e;n=Iu(n);var i=n.length;if(Rn.test(n))var o=M(n),i=o.length;if(r>=i)return n;if(i=r-D(e),1>i)return e;if(r=o?Or(o,0,i).join(""):n.slice(0,i),u===T)return r+e;if(o&&(i+=r.length-i),hf(u)){if(n.slice(i).search(u)){
|
||||
var f=r;for(u.global||(u=Xu(u.source,Iu(_n.exec(u))+"g")),u.lastIndex=0;o=u.exec(f);)var c=o.index;r=r.slice(0,c===T?i:c)}}else n.indexOf(yr(u),i)!=i&&(u=r.lastIndexOf(u),-1<u&&(r=r.slice(0,u)));return r+e},An.unescape=function(n){return(n=Iu(n))&&G.test(n)?n.replace(V,tt):n},An.uniqueId=function(n){var t=++fi;return Iu(n)+t},An.upperCase=Tf,An.upperFirst=$f,An.each=nu,An.eachRight=tu,An.first=qe,Nu(An,function(){var n={};return mt(An,function(t,r){oi.call(An.prototype,r)||(n[r]=t)}),n}(),{chain:false
|
||||
}),An.VERSION="4.17.15",r("bind bindKey curry curryRight partial partialRight".split(" "),function(n){An[n].placeholder=An}),r(["drop","take"],function(n,t){Un.prototype[n]=function(r){r=r===T?1:Ui(Eu(r),0);var e=this.__filtered__&&!t?new Un(this):this.clone();return e.__filtered__?e.__takeCount__=Ci(r,e.__takeCount__):e.__views__.push({size:Ci(r,4294967295),type:n+(0>e.__dir__?"Right":"")}),e},Un.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),r(["filter","map","takeWhile"],function(n,t){
|
||||
var r=t+1,e=1==r||3==r;Un.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:ye(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),r(["head","last"],function(n,t){var r="take"+(t?"Right":"");Un.prototype[n]=function(){return this[r](1).value()[0]}}),r(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Un.prototype[n]=function(){return this.__filtered__?new Un(this):this[r](1)}}),Un.prototype.compact=function(){return this.filter($u)},Un.prototype.find=function(n){
|
||||
return this.filter(n).head()},Un.prototype.findLast=function(n){return this.reverse().find(n)},Un.prototype.invokeMap=fr(function(n,t){return typeof n=="function"?new Un(this):this.map(function(r){return Lt(r,n,t)})}),Un.prototype.reject=function(n){return this.filter(au(ye(n)))},Un.prototype.slice=function(n,t){n=Eu(n);var r=this;return r.__filtered__&&(0<n||0>t)?new Un(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==T&&(t=Eu(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},Un.prototype.takeRightWhile=function(n){
|
||||
return this.reverse().takeWhile(n).reverse()},Un.prototype.toArray=function(){return this.take(4294967295)},mt(Un.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=An[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t);u&&(An.prototype[t]=function(){function t(n){return n=u.apply(An,a([n],f)),e&&h?n[0]:n}var o=this.__wrapped__,f=e?[1]:arguments,c=o instanceof Un,l=f[0],s=c||ff(o);s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false);var h=this.__chain__,p=!!this.__actions__.length,l=i&&!h,c=c&&!p;
|
||||
return!i&&s?(o=c?o:new Un(this),o=n.apply(o,f),o.__actions__.push({func:Qe,args:[t],thisArg:T}),new On(o,h)):l&&c?n.apply(this,f):(o=this.thru(t),l?e?o.value()[0]:o.value():o)})}),r("pop push shift sort splice unshift".split(" "),function(n){var t=ri[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);An.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(ff(u)?u:[],n)}return this[r](function(r){return t.apply(ff(r)?r:[],n)});
|
||||
}}),mt(Un.prototype,function(n,t){var r=An[t];if(r){var e=r.name+"";oi.call(Gi,e)||(Gi[e]=[]),Gi[e].push({name:t,func:r})}}),Gi[Jr(T,2).name]=[{name:"wrapper",func:T}],Un.prototype.clone=function(){var n=new Un(this.__wrapped__);return n.__actions__=Ur(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Ur(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Ur(this.__views__),n},Un.prototype.reverse=function(){if(this.__filtered__){var n=new Un(this);
|
||||
n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},Un.prototype.value=function(){var n,t=this.__wrapped__.value(),r=this.__dir__,e=ff(t),u=0>r,i=e?t.length:0;n=i;for(var o=this.__views__,f=0,c=-1,a=o.length;++c<a;){var l=o[c],s=l.size;switch(l.type){case"drop":f+=s;break;case"dropRight":n-=s;break;case"take":n=Ci(n,f+s);break;case"takeRight":f=Ui(f,n-s)}}if(n={start:f,end:n},o=n.start,f=n.end,n=f-o,o=u?f:o-1,f=this.__iteratees__,c=f.length,a=0,l=Ci(n,this.__takeCount__),!e||!u&&i==n&&l==n)return wr(t,this.__actions__);
|
||||
e=[];n:for(;n--&&a<l;){for(o+=r,u=-1,i=t[o];++u<c;){var h=f[u],s=h.type,h=(0,h.iteratee)(i);if(2==s)i=h;else if(!h){if(1==s)continue n;break n}}e[a++]=i}return e},An.prototype.at=To,An.prototype.chain=function(){return Ye(this)},An.prototype.commit=function(){return new On(this.value(),this.__chain__)},An.prototype.next=function(){this.__values__===T&&(this.__values__=mu(this.value()));var n=this.__index__>=this.__values__.length;return{done:n,value:n?T:this.__values__[this.__index__++]}},An.prototype.plant=function(n){
|
||||
for(var t,r=this;r instanceof En;){var e=Fe(r);e.__index__=0,e.__values__=T,t?u.__wrapped__=e:t=e;var u=e,r=r.__wrapped__}return u.__wrapped__=n,t},An.prototype.reverse=function(){var n=this.__wrapped__;return n instanceof Un?(this.__actions__.length&&(n=new Un(this)),n=n.reverse(),n.__actions__.push({func:Qe,args:[Ge],thisArg:T}),new On(n,this.__chain__)):this.thru(Ge)},An.prototype.toJSON=An.prototype.valueOf=An.prototype.value=function(){return wr(this.__wrapped__,this.__actions__)},An.prototype.first=An.prototype.head,
|
||||
wi&&(An.prototype[wi]=Xe),An}();typeof define=="function"&&typeof define.amd=="object"&&define.amd?($n._=rt, define(function(){return rt})):Nn?((Nn.exports=rt)._=rt,Fn._=rt):$n._=rt}).call(this);
|
||||
4
nodered/rootfs/data/node_modules/node-red-dashboard/dist/js/tinycolor-min.js
generated
vendored
Normal file
78
nodered/rootfs/data/node_modules/node-red-dashboard/fixfa.js
generated
vendored
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Patch to fix Font-Awesome urls for loading font
|
||||
// and to add in fa-sm(all) and fa-xs(extra small) modifiers
|
||||
var fs = require("fs");
|
||||
fs.readFile("node_modules/font-awesome/css/font-awesome.css", 'utf8', function (err, file) {
|
||||
if (err) { return; }
|
||||
else {
|
||||
console.log("Fixing up Font-Awesome css");
|
||||
var res1 = file.replace(/\?v=4\.7\../g, '');
|
||||
var res2 = res1.replace(/\&v=4\.7\../g, '');
|
||||
var res3;
|
||||
if (res2.indexOf("fa-sm ") === -1) {
|
||||
res3 = res2.replace(/fa-lg/, 'fa-sm {font-size:0.875em;}\n.fa-xs {font-size:0.75em;}\n.fa-lg');
|
||||
}
|
||||
else { res3 = res2; }
|
||||
fs.writeFile("node_modules/font-awesome/css/font-awesome.css", res3, 'utf8', function (err) {
|
||||
if (err) { console.log("Failed to re-write file."); }
|
||||
else {
|
||||
console.log("Fixed up Font-Awesome css");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Google-Material-Font
|
||||
// Fix relative path of fonts from `./fonts/` to `../fonts/` in css file.
|
||||
fs.readFile('node_modules/material-design-icons-iconfont/dist/material-design-icons.css', 'utf8', function (err, file) {
|
||||
if (err) { return; }
|
||||
else {
|
||||
console.log('Fixing up Google-Material-Font css');
|
||||
const res1 = file
|
||||
.replace(/"\.\/fonts\//g, '"../fonts/')
|
||||
.replace(/'\.\/fonts\//g, '\'../fonts/');
|
||||
fs.writeFile('node_modules/material-design-icons-iconfont/dist/material-design-icons.css', res1, 'utf8', function (err) {
|
||||
if (err) {
|
||||
console.log('Failed to re-write file.');
|
||||
} else {
|
||||
console.log('Fixed up Google-Material-Font css');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Monkeypatch for justgage negative numbers...
|
||||
// fs.readFile("node_modules/justgage/justgage.js", 'utf8', function (err, file) {
|
||||
// if (err) { return; }
|
||||
// else {
|
||||
// console.log("Fixing up JustGage.js");
|
||||
// var res1 = file.replace(/var alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path;\n\n/, 'var alpha, Ro, Ri, Cx, Cy, Xo, Yo, Xi, Yi, path;\n\tif (min < 0) {max -= min; value -= min; min = 0; }\n\n');
|
||||
// var res2 = res1.replace(/value > \(\(max - min\)/g,'value - min > ((max - min)');
|
||||
// fs.writeFile("node_modules/justgage/justgage.js", res2, 'utf8', function (err) {
|
||||
// if (err) { console.log("Failed to re-write file."); }
|
||||
// else {
|
||||
// console.log("Fixed up JustGage.js");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
// Monkeypatch for colour picker ...
|
||||
// fs.readFile("node_modules/angularjs-color-picker/dist/angularjs-color-picker.js", 'utf8', function (err, file) {
|
||||
// if (err) { return; }
|
||||
// else {
|
||||
// console.log("Fixing up angularjs-color-picker.js");
|
||||
// var res1 = file.replace(/this\.saturation = tmpSaturation \* 100;/,'this.sat = tmpSaturation * 100;\n this.lightness = 100 - (tmpSaturation * 100);\n this.saturation = 100;');
|
||||
// var res2 = res1.replace(/var px = Math\.cos(angle) \* this\.saturation;/,'var px = Math.cos(angle) * this.sat;');
|
||||
// var res3 = res2.replace(/var py = -Math\.sin(angle) \* this\.saturation;/,'var py = -Math.sin(angle) * this.sat;');
|
||||
// var res4 = res3.replace(/background\.s = '0%';/,'background = "#ffffff";');
|
||||
//
|
||||
// fs.writeFile("node_modules/angularjs-color-picker/dist/angularjs-color-picker.js", res4, 'utf8', function (err) {
|
||||
// if (err) { console.log("Failed to re-write file."); }
|
||||
// else {
|
||||
// console.log("Fixed up angularjs-color-picker.js");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
161
nodered/rootfs/data/node_modules/node-red-dashboard/gulpfile.old
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
var
|
||||
gulp = require('gulp'),
|
||||
concat = require('gulp-concat'),
|
||||
eol = require('gulp-eol'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require('fs'),
|
||||
ghtmlSrc = require('gulp-html-src'),
|
||||
gulpif = require('gulp-if'),
|
||||
gutil = require('gulp-util'),
|
||||
header = require("gulp-header"),
|
||||
htmlreplace = require('gulp-html-replace'),
|
||||
jscs = require('gulp-jscs'),
|
||||
jshint = require('gulp-jshint'),
|
||||
manifest = require('gulp-manifest'),
|
||||
minifyCss = require('gulp-clean-css'),
|
||||
minifyHTML = require('gulp-htmlmin'),
|
||||
path = require('path'),
|
||||
replace = require('gulp-replace'),
|
||||
streamqueue = require('streamqueue'),
|
||||
templateCache = require('gulp-angular-templatecache'),
|
||||
uglify = require('gulp-uglify'),
|
||||
sass = require('gulp-sass'),
|
||||
rename = require('gulp-rename');
|
||||
|
||||
//gulp.task('default', ['manifest']);
|
||||
gulp.task('default', ['lint','jscs'], function() {
|
||||
gulp.start('manifest');
|
||||
//gulp.start('build');
|
||||
});
|
||||
|
||||
gulp.task('build', ['icon', 'js', 'css', 'less', 'index', 'fonts', 'gridstack']);
|
||||
|
||||
gulp.task('manifest', ['build'], function() {
|
||||
gulp.src(['dist/*','dist/css/*','dist/js/*','dist/fonts/*'], { base: 'dist/' })
|
||||
.pipe(manifest({
|
||||
hash: true,
|
||||
//preferOnline: true,
|
||||
network: ['*'],
|
||||
filename: 'dashboard.appcache',
|
||||
// exclude: 'dashboard.appcache'
|
||||
exclude: ['dashboard.appcache','index.html']
|
||||
}))
|
||||
.pipe(replace('tinycolor-min.js', 'tinycolor-min.js\nsocket.io/socket.io.js'))
|
||||
.pipe(eol('\n'))
|
||||
.pipe(gulp.dest('dist/'));
|
||||
});
|
||||
|
||||
gulp.task('lint', function() {
|
||||
return gulp.src('**/*.js')
|
||||
.pipe(jshint('.jshintrc'))
|
||||
.pipe(jshint.reporter('default'))
|
||||
.pipe(jshint.reporter('fail'));
|
||||
});
|
||||
|
||||
gulp.task('jscs', function() {
|
||||
return gulp.src(['*.js','nodes/*.js','src/*.js','src/*/*.js','src/*/*/*.js'])
|
||||
.pipe(jscs())
|
||||
//.pipe(jscs({fix: true}))
|
||||
.pipe(jscs.reporter("inline"))
|
||||
});
|
||||
|
||||
gulp.task('index', function() {
|
||||
return gulp.src('src/index.html')
|
||||
.pipe(htmlreplace({
|
||||
'css': 'css/app.min.css',
|
||||
'js': 'js/app.min.js',
|
||||
'less': '<link rel="stylesheet/less" href="css/app.min.less" />'
|
||||
}))
|
||||
.pipe(minifyHTML({collapseWhitespace:true, conservativeCollapse:true}))
|
||||
.pipe(eol('\n'))
|
||||
.pipe(gulp.dest('dist/'));
|
||||
});
|
||||
|
||||
gulp.task('icon', function() {
|
||||
// gulp.src('src/wheel.png').pipe(gulp.dest('dist/css/'));
|
||||
gulp.src('src/icon192x192.png').pipe(gulp.dest('dist/'));
|
||||
gulp.src('src/icon120x120.png').pipe(gulp.dest('dist/'));
|
||||
return gulp.src('src/icon64x64.png').pipe(gulp.dest('dist/'));
|
||||
});
|
||||
|
||||
gulp.task('fonts', function() {
|
||||
//return gulp.src('node_modules/font-awesome/fonts/*').pipe(gulp.dest('dist/fonts/'));
|
||||
gulp.src('node_modules/font-awesome/fonts/fontawesome-webfont.woff').pipe(gulp.dest('dist/fonts/'));
|
||||
gulp.src('node_modules/weather-icons-lite/fonts/weather-icons-lite.woff').pipe(gulp.dest('dist/fonts/'));
|
||||
gulp.src('node_modules/font-awesome/fonts/fontawesome-webfont.woff2').pipe(gulp.dest('dist/fonts/'));
|
||||
gulp.src('node_modules/weather-icons-lite/fonts/weather-icons-lite.woff2').pipe(gulp.dest('dist/fonts/'));
|
||||
return;
|
||||
});
|
||||
|
||||
gulp.task('js', function () {
|
||||
var scripts = gulp.src('src/index.html')
|
||||
.pipe(ghtmlSrc({getFileName:getFileName.bind(this, 'src')}));
|
||||
|
||||
var templates = gulp.src(['src/**/*.html', '!src/index.html'])
|
||||
.pipe(minifyHTML({collapseWhitespace:true, conservativeCollapse:true}))
|
||||
.pipe(templateCache('templates.js', {root:'', module:'ui'}));
|
||||
|
||||
var tiny = gulp.src('node_modules/tinycolor2/dist/tinycolor-min.js')
|
||||
.pipe(eol('\n'))
|
||||
.pipe(gulp.dest('./dist/js'));
|
||||
|
||||
var i18n = gulp.src('src/i18n.js')
|
||||
.pipe(eol('\n'))
|
||||
.pipe(gulp.dest('dist/'));
|
||||
|
||||
return streamqueue({ objectMode:true }, scripts, templates)
|
||||
.pipe(gulpif(/[.]min[.]js$/, gutil.noop(), uglify()))
|
||||
.pipe(concat('app.min.js'))
|
||||
.pipe(header(fs.readFileSync('license.js')))
|
||||
.pipe(eol('\n'))
|
||||
.pipe(gulp.dest('dist/js/'));
|
||||
});
|
||||
|
||||
gulp.task('css', function () {
|
||||
exec('node fixfa.js', function (err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
}
|
||||
});
|
||||
|
||||
return gulp.src('src/index.html')
|
||||
.pipe(ghtmlSrc({getFileName:getFileName.bind(this, 'href'), presets:'css'}))
|
||||
.pipe(minifyCss({compatibility:'ie8'}))
|
||||
.pipe(concat('app.min.css'))
|
||||
.pipe(header(fs.readFileSync('license.js')))
|
||||
.pipe(eol('\n'))
|
||||
.pipe(gulp.dest('dist/css/'));
|
||||
});
|
||||
|
||||
gulp.task('less', function() {
|
||||
return gulp.src(['src/*.less'])
|
||||
.pipe(concat('app.min.less'))
|
||||
.pipe(header(fs.readFileSync('license.js')))
|
||||
.pipe(eol('\n'))
|
||||
.pipe(gulp.dest('./dist/css'));
|
||||
});
|
||||
|
||||
gulp.task('gridstack', function() {
|
||||
gulp.src('node_modules/gridstack/dist/gridstack.min.css').pipe(gulp.dest('dist/css/'));
|
||||
gulp.src('node_modules/gridstack/dist/gridstack.jQueryUI.min.js').pipe(gulp.dest('dist/js/'));
|
||||
gulp.src('node_modules/gridstack/dist/gridstack.min.js').pipe(gulp.dest('dist/js/'));
|
||||
gulp.src('node_modules/gridstack/dist/gridstack.min.map').pipe(gulp.dest('dist/js/'));
|
||||
gulp.src('node_modules/lodash/lodash.min.js').pipe(gulp.dest('dist/js/'));
|
||||
gulp.src('node_modules/gridstack/src/gridstack-extra.scss')
|
||||
.pipe(replace('$gridstack-columns: 12 !default;','$gridstack-columns: 30;'))
|
||||
.pipe(sass({outputStyle: 'compressed'}))
|
||||
.pipe(rename({extname: '.min.css'}))
|
||||
.pipe(gulp.dest('dist/css'))
|
||||
return;
|
||||
});
|
||||
|
||||
var vendorPrefix = "vendor/";
|
||||
function getFileName(attr, node) {
|
||||
var file = node.attr(attr);
|
||||
if (file.indexOf(vendorPrefix) === 0) {
|
||||
file = path.join("..", "node_modules", file.substr(vendorPrefix.length));
|
||||
}
|
||||
return file;
|
||||
}
|
||||
136
nodered/rootfs/data/node_modules/node-red-dashboard/index.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var ui = null;
|
||||
|
||||
function init(RED) {
|
||||
if (!ui) {
|
||||
ui = require("./ui")(RED);
|
||||
}
|
||||
}
|
||||
|
||||
/* addWidget:
|
||||
- options
|
||||
- RED: RED object
|
||||
- options: options to create dashboard widget
|
||||
* [node] - the node that represents the control on a flow
|
||||
* format - HTML code of widget
|
||||
* [group] - group name (optional if templateScope = 'global')
|
||||
* [width] - width of widget (default automatic)
|
||||
* [height] - height of widget (default automatic)
|
||||
* [order] - property to hold the placement order of the widget (default 0)
|
||||
* [templateScope] - scope of widhget/global or local (default local)
|
||||
* [emitOnlyNewValues] - boolean (default true).
|
||||
If true, it checks if the payload changed before sending it
|
||||
to the front-end. If the payload is the same no message is sent.
|
||||
* [forwardInputMessages] - boolean (default true).
|
||||
If true, forwards input messages to the output
|
||||
* [storeFrontEndInputAsState] - boolean (default true).
|
||||
If true, any message received from front-end is stored as state
|
||||
* [convert] - callback to convert the value before sending it to the front-end
|
||||
* [beforeEmit] - callback to prepare the message that is emitted to the front-end
|
||||
* [convertBack] - callback to convert the message from front-end before sending it to the next connected node
|
||||
* [beforeSend] - callback to prepare the message that is sent to the output
|
||||
* [initController] - callback to initialize in controller
|
||||
*/
|
||||
|
||||
function addWidget(RED, options) {
|
||||
var is_local = (options.templateScope !== "global");
|
||||
var group = null;
|
||||
var tab = null;
|
||||
init(RED);
|
||||
|
||||
var ui_control = {
|
||||
type: "template",
|
||||
order: options.order,
|
||||
format: options.format
|
||||
};
|
||||
|
||||
var node = options.node;
|
||||
|
||||
if (isNaN(options.order)) {
|
||||
node.warn("*** Order property not set. Please contact developer. ***");
|
||||
}
|
||||
|
||||
if (is_local) {
|
||||
group = RED.nodes.getNode(options.group);
|
||||
tab = RED.nodes.getNode(group.config.tab);
|
||||
ui_control.width = options.hasOwnProperty("width") ? options.width : group.config.width;
|
||||
ui_control.height = options.hasOwnProperty("height") ? options.height : 0;
|
||||
}
|
||||
else {
|
||||
node = {
|
||||
id: "-dummy-",
|
||||
on: function() {}
|
||||
};
|
||||
}
|
||||
ui_control.templateScope = options.hasOwnProperty("templateScope") ? options.templateScope : "local";
|
||||
var ui_options = {
|
||||
node: node,
|
||||
control: ui_control
|
||||
}
|
||||
if (is_local) {
|
||||
ui_options.group = group;
|
||||
ui_options.tab = tab;
|
||||
}
|
||||
if (options.hasOwnProperty("emitOnlyNewValues")) {
|
||||
ui_options.emitOnlyNewValues = options.emitOnlyNewValues;
|
||||
}
|
||||
if (options.hasOwnProperty("forwardInputMessages")) {
|
||||
ui_options.forwardInputMessages = options.forwardInputMessages;
|
||||
}
|
||||
if (options.hasOwnProperty("storeFrontEndInputAsState")) {
|
||||
ui_options.storeFrontEndInputAsState = options.storeFrontEndInputAsState;
|
||||
}
|
||||
if (options.hasOwnProperty("convert")) {
|
||||
ui_options.convert = options.convert;
|
||||
}
|
||||
if (options.hasOwnProperty("beforeEmit")) {
|
||||
ui_options.beforeEmit = options.beforeEmit;
|
||||
}
|
||||
if (options.hasOwnProperty("convertBack")) {
|
||||
ui_options.convertBack = options.convertBack;
|
||||
}
|
||||
if (options.hasOwnProperty("beforeSend")) {
|
||||
ui_options.beforeSend = options.beforeSend;
|
||||
}
|
||||
if (options.hasOwnProperty("initController")) {
|
||||
ui_control.initController = options.initController.toString();
|
||||
}
|
||||
return ui.add(ui_options);
|
||||
}
|
||||
|
||||
/* getSizes:
|
||||
returns the grid size in pixels
|
||||
default - { sx: 48, sy: 48, gx: 6, gy: 6, cx: 6, cy: 6, px: 0, py: 0 }
|
||||
*/
|
||||
|
||||
/* getTheme:
|
||||
returns the current theme object
|
||||
*/
|
||||
|
||||
/* isDark:
|
||||
returns true or false if the dahsboard theme background is dark or light.
|
||||
*/
|
||||
|
||||
module.exports = function (RED) {
|
||||
return {
|
||||
addWidget: function (options) { return addWidget(RED, options); },
|
||||
getSizes: function() { return require("./ui")(RED).getSizes(); },
|
||||
getTheme: function() { return require("./ui")(RED).getTheme(); },
|
||||
isDark: function() { return require("./ui")(RED).isDark(); }
|
||||
};
|
||||
};
|
||||
17
nodered/rootfs/data/node_modules/node-red-dashboard/license.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/* */
|
||||
/* Copyright 2016,2019 JS Foundation and other contributors, https://js.foundation/ */
|
||||
/* Copyright 2016 IBM Corp. */
|
||||
/* Copyright 2015 Andrei Tatar */
|
||||
/* */
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License"); */
|
||||
/* you may not use this file except in compliance with the License. */
|
||||
/* You may obtain a copy of the License at */
|
||||
/* */
|
||||
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
||||
/* */
|
||||
/* Unless required by applicable law or agreed to in writing, software */
|
||||
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
||||
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
||||
/* See the License for the specific language governing permissions and */
|
||||
/* limitations under the License. */
|
||||
/* */
|
||||
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_button.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 336 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_chart.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 344 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_colour_picker.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 650 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_date_picker.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 153 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_dropdown.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 236 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_form.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 232 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_gauge.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 507 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_numeric.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 407 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_slider.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 216 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_switch.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 396 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_template.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 413 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_text.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 409 B |
BIN
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/icons/ui_toast.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 353 B |
96
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/en-US/ui_base.json
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"ui_base" : {
|
||||
"label" : {
|
||||
"dashboard" : "dashboard",
|
||||
"title" : "Title",
|
||||
"options" : "Options",
|
||||
"date-format" : "Date Format",
|
||||
"sizes" : "Sizes",
|
||||
"horizontal" : "Horizontal",
|
||||
"vertical" : "Vertical",
|
||||
"widget-size" : "1x1 Widget Size",
|
||||
"widget-spacing" : "Widget Spacing",
|
||||
"group-padding" : "Group Padding",
|
||||
"group-spacing" : "Group Spacing",
|
||||
"layout" : "Layout",
|
||||
"angular": "Angular",
|
||||
"theme" : "Theme",
|
||||
"site" : "Site"
|
||||
},
|
||||
"auto" : "auto",
|
||||
"title" : "Node-RED Dashboard",
|
||||
"layout" : {
|
||||
"tab-and-link" : "Tabs & Links",
|
||||
"tab" : "tab",
|
||||
"link" : "link",
|
||||
"group" : "group",
|
||||
"edit" : "edit",
|
||||
"spacer": "spacer",
|
||||
"layout" : "layout",
|
||||
"layout-editor" : "Dashboard layout editor",
|
||||
"width" : "Width"
|
||||
},
|
||||
"theme" : {
|
||||
"style" : "Style",
|
||||
"custom-profile" : "Custom Profile",
|
||||
"custom-profile-name" : "Untitled Theme 1",
|
||||
"base-settings" : "Base Settings",
|
||||
"page-settings" : "Page Settings",
|
||||
"page" : {
|
||||
"title" : "Title Bar Background",
|
||||
"page" : "Page Background",
|
||||
"side" : "Side Bar Background"
|
||||
},
|
||||
"group-settings" : "Group Settings",
|
||||
"group" : {
|
||||
"text" : "Group Text",
|
||||
"border" : "Group Border",
|
||||
"background" : "Group Background"
|
||||
},
|
||||
"widget-settings" : "Widget Settings",
|
||||
"widget" : {
|
||||
"text" : "Widget Text",
|
||||
"colour" : "Widget Colour",
|
||||
"background" : "Widget Background"
|
||||
}
|
||||
},
|
||||
"style" : {
|
||||
"light" : "Light (default)",
|
||||
"dark" : "Dark",
|
||||
"custom" : "Custom",
|
||||
"primary" : "Primary",
|
||||
"accents" : "Accents",
|
||||
"background" : "Background",
|
||||
"warnings" : "Warnings",
|
||||
"palette": "Light / Dark"
|
||||
},
|
||||
"base" : {
|
||||
"colour" : "Colour",
|
||||
"font" : "Font"
|
||||
},
|
||||
"font" : {
|
||||
"system" : "System Font (default)"
|
||||
},
|
||||
"site" : {
|
||||
"title" : "Node-RED Dashboard",
|
||||
"date-format" : "DD/MM/YYYY"
|
||||
},
|
||||
"title-bar" : {
|
||||
"show" : "Show the title bar",
|
||||
"hide" : "Hide the title bar"
|
||||
},
|
||||
"swipe" : {
|
||||
"no-swipe" : "No swipe between tabs",
|
||||
"allow-swipe" : "Allow swipe between tabs"
|
||||
},
|
||||
"lock" : {
|
||||
"clicked" : "Click to show side menu",
|
||||
"locked" : "Always show side menu"
|
||||
},
|
||||
"temp" : {
|
||||
"allow-theme" : "Node-RED theme everywhere",
|
||||
"no-theme" : "Use Angular theme in ui_template",
|
||||
"none" : "Angular theme everywhere"
|
||||
}
|
||||
}
|
||||
}
|
||||
14
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/en-US/ui_group.json
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ui_group" : {
|
||||
"label" : {
|
||||
"name" : "Name",
|
||||
"tab" : "Tab",
|
||||
"width" : "Width",
|
||||
"default" : "Default",
|
||||
"group" : "Group",
|
||||
"unassigned" : "unassigned"
|
||||
},
|
||||
"display-name" : "Display group name",
|
||||
"collapse-name" : "Allow group to be collapsed"
|
||||
}
|
||||
}
|
||||
14
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/en-US/ui_link.json
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ui_link" : {
|
||||
"label" : {
|
||||
"name" : "Name",
|
||||
"link" : "Link",
|
||||
"icon" : "Icon",
|
||||
"open-in" : "Open in",
|
||||
"new-tab" : "New Tab",
|
||||
"this-tab" : "This Tab",
|
||||
"iframe" : "iframe"
|
||||
},
|
||||
"tip" : "The <b>Icon</b> field can be either a <a href=\"https://klarsys.github.io/angular-material-icons/\" target=\"_blank\">Material Design icon</a> <i>(e.g. 'check', 'close')</i> or a <a href=\"https://fontawesome.com/v4.7.0/icons/\" target=\"_blank\">Font Awesome icon</a> <i>(e.g. 'fa-fire')</i>, or a <a href=\"https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md\" target=\"_blank\">Weather icon</a> <i>(e.g. 'wi-wu-sunny')</i>.</p><p>You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>"
|
||||
}
|
||||
}
|
||||
21
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/en-US/ui_tab.json
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"ui_tab" : {
|
||||
"label" : {
|
||||
"home" : "Home",
|
||||
"tab" : "Tab",
|
||||
"name" : "Name",
|
||||
"icon" : "Icon",
|
||||
"state" : "State",
|
||||
"navmenu" : "Nav. Menu",
|
||||
"enabled" : "Enabled",
|
||||
"disabled" : "Disabled",
|
||||
"visible" : "Visible",
|
||||
"hidden" : "Hidden"
|
||||
},
|
||||
"info": {
|
||||
"disabled": " Tab is inactive in Dashboard.",
|
||||
"hidden": " Tab is not shown in Navigation Menu."
|
||||
},
|
||||
"tip" : "The <b>Icon</b> field can be either a <a href=\"https://klarsys.github.io/angular-material-icons/\" target=\"_blank\">Material Design icon</a> <i>(e.g. 'check', 'close')</i> or a <a href=\"https://fontawesome.com/v4.7.0/icons/\" target=\"_blank\">Font Awesome icon</a> <i>(e.g. 'fa-fire')</i>, or a <a href=\"https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md\" target=\"_blank\">Weather icon</a> <i>(e.g. 'wi-wu-sunny')</i>.</p><p>You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>"
|
||||
}
|
||||
}
|
||||
17
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/en-US/ui_template.json
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"ui_template" : {
|
||||
"label" : {
|
||||
"category" : "dashboard",
|
||||
"type" : "Template type",
|
||||
"local" : "Widget in group",
|
||||
"global" : "Added to site <head> section",
|
||||
"group" : "Group",
|
||||
"size" : "Size",
|
||||
"name" : "Name",
|
||||
"pass-through" : "Pass through messages from input.",
|
||||
"store-state" : "Add output messages to stored state.",
|
||||
"template" : "Template",
|
||||
"expand": "Expand"
|
||||
}
|
||||
}
|
||||
}
|
||||
11
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/en-US/ui_ui_control.json
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ui_ui_control" : {
|
||||
"label" : {
|
||||
"category" : "dashboard",
|
||||
"name" : "Name"
|
||||
},
|
||||
"placeholder" : {
|
||||
"name" : "Name"
|
||||
}
|
||||
}
|
||||
}
|
||||
96
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_base.json
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"ui_base" : {
|
||||
"label" : {
|
||||
"dashboard" : "ダッシュボード",
|
||||
"title" : "タイトル",
|
||||
"options" : "オプション",
|
||||
"date-format" : "日付形式",
|
||||
"sizes" : "サイズ",
|
||||
"horizontal" : "横",
|
||||
"vertical" : "縦",
|
||||
"widget-size" : "最小Widgetサイズ",
|
||||
"widget-spacing" : "Widget間隔",
|
||||
"group-padding" : "グループパディング",
|
||||
"group-spacing" : "グループ間隔",
|
||||
"layout" : "配置",
|
||||
"angular": "Angular",
|
||||
"theme" : "テーマ",
|
||||
"site" : "サイト"
|
||||
},
|
||||
"auto" : "自動",
|
||||
"title" : "Node-REDダッシュボード",
|
||||
"layout" : {
|
||||
"tab-and-link" : "タブ & リンク",
|
||||
"tab" : "タブ",
|
||||
"link" : "リンク",
|
||||
"group" : "グループ",
|
||||
"edit" : "編集",
|
||||
"spacer": "スペーサ",
|
||||
"layout" : "レイアウト",
|
||||
"layout-editor" : "ダッシュボードレイアウトエディタ",
|
||||
"width" : "幅"
|
||||
},
|
||||
"theme" : {
|
||||
"style" : "スタイル",
|
||||
"custom-profile" : "カスタムプロファイル",
|
||||
"custom-profile-name" : "名称未設定テーマ 1",
|
||||
"base-settings" : "基本設定",
|
||||
"page-settings" : "ページ設定",
|
||||
"page" : {
|
||||
"title" : "タイトルバー背景色",
|
||||
"page" : "ページ背景色",
|
||||
"side" : "サイドバー背景色"
|
||||
},
|
||||
"group-settings" : "グループ設定",
|
||||
"group" : {
|
||||
"text" : "グループ文字色",
|
||||
"border" : "グループボーダー色",
|
||||
"background" : "グループ背景色"
|
||||
},
|
||||
"widget-settings" : "Widget設定",
|
||||
"widget" : {
|
||||
"text" : "Widget文字色",
|
||||
"colour" : "Widget色",
|
||||
"background" : "Widget背景色"
|
||||
}
|
||||
},
|
||||
"style" : {
|
||||
"light" : "ライト (デフォルト)",
|
||||
"dark" : "ダーク",
|
||||
"custom" : "カスタム",
|
||||
"primary" : "プライマリ",
|
||||
"accents" : "アクセント",
|
||||
"background" : "背景",
|
||||
"warnings" : "警告",
|
||||
"palette": "ライト/ダーク"
|
||||
},
|
||||
"base" : {
|
||||
"colour" : "色",
|
||||
"font" : "フォント"
|
||||
},
|
||||
"font" : {
|
||||
"system" : "システムフォント (デフォルト)"
|
||||
},
|
||||
"site" : {
|
||||
"title" : "Node-RED ダッシュボード",
|
||||
"date-format" : "YYYY/MM/DD"
|
||||
},
|
||||
"title-bar" : {
|
||||
"show" : "タイトルバー表示",
|
||||
"hide" : "タイトルバー非表示"
|
||||
},
|
||||
"swipe" : {
|
||||
"no-swipe" : "スワイプによるタブ切り替えをしない",
|
||||
"allow-swipe" : "スワイプによるタブ切り替えをする"
|
||||
},
|
||||
"lock" : {
|
||||
"clicked" : "サイドメニューをクリックで表示",
|
||||
"locked" : "サイドメニューを表示したままにする"
|
||||
},
|
||||
"temp" : {
|
||||
"no-theme" : "ui_templateでテーマ設定を許可しない",
|
||||
"allow-theme" : "ui_templateでテーマ設定を許可する",
|
||||
"none" : "Angularテーマを全ての箇所で使用"
|
||||
}
|
||||
}
|
||||
}
|
||||
14
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_group.json
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ui_group" : {
|
||||
"label" : {
|
||||
"name" : "名前",
|
||||
"tab" : "タブ",
|
||||
"width" : "幅",
|
||||
"default" : "デフォルト",
|
||||
"group" : "グループ",
|
||||
"unassigned" : "未設定"
|
||||
},
|
||||
"display-name" : "グループ名を表示する",
|
||||
"collapse-name" : "グループの折りたたみを有効にする"
|
||||
}
|
||||
}
|
||||
14
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_link.json
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ui_link" : {
|
||||
"label" : {
|
||||
"name" : "名前",
|
||||
"link" : "リンク",
|
||||
"icon" : "アイコン",
|
||||
"open-in" : "開く方法",
|
||||
"new-tab" : "新規タブ",
|
||||
"this-tab" : "このタブ",
|
||||
"iframe" : "iframe"
|
||||
},
|
||||
"tip" : "<b>アイコン</b>フィールドには <a href=\"https://klarsys.github.io/angular-material-icons/\" target=\"_blank\">Material Design icon</a> <i>(例: 'check', 'close')</i>、<a href=\"https://fontawesome.com/v4.7.0/icons/\" target=\"_blank\">Font Awesome icon</a> <i>(例: 'fa-fire')</i>、もしくは <a href=\"https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md\" target=\"_blank\">Weather icon</a> <i>(例: 'wi-wu-sunny')</i>を指定できます。</p>"
|
||||
}
|
||||
}
|
||||
21
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_tab.json
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"ui_tab" : {
|
||||
"label" : {
|
||||
"home" : "ホーム",
|
||||
"tab" : "タブ",
|
||||
"name" : "名前",
|
||||
"icon" : "アイコン",
|
||||
"state" : "状態",
|
||||
"navmenu" : "メニュー",
|
||||
"enabled" : "有効",
|
||||
"disabled" : "無効",
|
||||
"visible" : "表示",
|
||||
"hidden" : "非表示"
|
||||
},
|
||||
"info": {
|
||||
"disabled": " タブを無効化します",
|
||||
"hidden": " タブを移動メニューに表示しません"
|
||||
},
|
||||
"tip" : "<b>アイコン</b>フィールドには <a href=\"https://klarsys.github.io/angular-material-icons/\" target=\"_blank\">Material Design icon</a> <i>(例: 'check', 'close')</i>、<a href=\"https://fontawesome.com/v4.7.0/icons/\" target=\"_blank\">Font Awesome icon</a> <i>(例: 'fa-fire')</i>、もしくは <a href=\"https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md\" target=\"_blank\">Weather icon</a> <i>(例: 'wi-wu-sunny')</i>を指定できます。</p>"
|
||||
}
|
||||
}
|
||||
44
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_template.html
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<script type="text/html" data-help-name="ui_template">
|
||||
<p>Template WidgetにはHTMLコードおよびAngular/Angular-Materialディレクティブを指定できます。</p>
|
||||
<p>このノードで動的なユーザインターフェイス要素を作成し、入力によって見た目を変更したり、メッセージをNode-REDに送り返したりできます。</p>
|
||||
<p><b>例:</b><br>
|
||||
<pre style="font-size:smaller;"><div layout="row" layout-align="space-between">
|
||||
<p>数値は</p>
|
||||
<p ng-style="{color: (msg.payload || 0) % 2 === 0 ? 'green' : 'red'}">
|
||||
{{(msg.payload || 0) % 2 === 0 ? '偶数' : '奇数'}}
|
||||
</p>
|
||||
</div></pre>
|
||||
このコードは<code>msg.payload</code>で受け取った数値が偶数か奇数かを表示します。同時に、偶数であれば緑に、奇数であれば赤にテキストの色を変更します。<br/>
|
||||
次は、一意なIDをテンプレートに設定、デフォルトのテーマカラーを設定、入力メッセージの到着を監視する例です。</p>
|
||||
<pre style="font-size:smaller;">
|
||||
<div id="{{'my_'+$id}}" style="{{'color:'+theme.base_color}}">何らかのテキスト</div>
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.$watch('msg', function(msg) {
|
||||
if (msg) {
|
||||
// メッセージ同着時に適当な処理を実行
|
||||
$("#my_"+scope.$id).html(msg.payload);
|
||||
}
|
||||
});
|
||||
})(scope);
|
||||
</script></pre>
|
||||
<p>この方法で作成したテンプレートはコピー可能です。コピーはそれぞれ独立して利用できます。</p>
|
||||
<p><b>メッセージ送信:</b><br>
|
||||
<pre style="font-size:smaller;">
|
||||
<script>
|
||||
var value = "こんにちは世界";
|
||||
// もしくは、コールバック関数で値を書き換え
|
||||
this.scope.action = function() { return value; }
|
||||
</script>
|
||||
<md-button ng-click="send({payload:action()})">
|
||||
クリックすると「こんにちは世界」を送信します
|
||||
</md-button></pre>
|
||||
この例は、クリックするとペイロードに<code>'こんにちは世界'</code>を持つメッセージを送信するボタンを表示します。</p>
|
||||
<p><b><code>msg.template</code>の使用:</b><br>
|
||||
<code>msg.template</code>によってテンプレートを定義することもできます。例えば、外部ファイルに格納したテンプレートを用いる場合に有用です。<br>
|
||||
テンプレートは入力が変化した場合に再ロードされます。<br>
|
||||
「HTMLコード」フィールドに記述したコードは、<code>msg.template</code>が存在する場合には無視されます。</p>
|
||||
<p>以下のアイコンフォントの利用も可能です: <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icons</a>,
|
||||
<a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icons</a>,
|
||||
<a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md" target="_blank">Weather icons</a></p>
|
||||
</script>
|
||||
17
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_template.json
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"ui_template" : {
|
||||
"label" : {
|
||||
"category" : "dashboard",
|
||||
"type" : "コード種別",
|
||||
"local" : "グループ内のWidget",
|
||||
"global" : "<head>ヘッドセクションへ追加",
|
||||
"group" : "グループ",
|
||||
"size" : "サイズ",
|
||||
"name" : "名前",
|
||||
"pass-through" : "入力メッセージをそのまま渡す",
|
||||
"store-state" : "出力メッセージを状態として保存",
|
||||
"template" : "HTMLコード",
|
||||
"expand": "展開する"
|
||||
}
|
||||
}
|
||||
}
|
||||
15
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_ui_control.html
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<script type="text/html" data-help-name="ui_ui_control">
|
||||
<p>ダッシュボードの動的制御を行います</p>
|
||||
<p>表示されているタブの切り替えが可能です。<code>msg.payload</code>に
|
||||
The default function is to change the currently displayed tab. <code>msg.payload</code>に表示対象のタブもしくはリンクの<code>{tab:"タブ名"}</code>、<b>タブ名</b>、もしくは、<b>添字</b> (0起点)を指定します。</p>
|
||||
<p>空のタブ名("")を送信すると、表示されているページを更新します。また、"+1"を送ると次のタブ、"-1"を送ると前のタブに切り替えられます。</p>
|
||||
<p>widgetグループを表示を次のようなペイロードで制御できます。<br/>
|
||||
<code>{group:{hide:["タブ名_グループ名"], show:["他_グループ_表示"], focus:true}}</code><br/>
|
||||
<b>focus</b>は、グループが表示されるよう必要に応じて画面をスクロールするためのパラメータで、省略可能です。グループの指定は<i>タブ名</i>と<i>グループ名</i>を下線(_)で結合したものを用います。空白は下線で置き換えます。</p>
|
||||
<p>クライアントのブラウザが接続もしくは切断した場合、次のプロパティを持つメッセージを送信します:</p>
|
||||
<ul>
|
||||
<li><code>payload</code> - <i>connect</i>もしくは<i>lost</i>,
|
||||
<li><code>socketid</code> - ソケットID(ブラウザがページを再ロードする毎に変化します),
|
||||
<li><code>socketip</code> - 接続元のIPアドレス。
|
||||
</ul>
|
||||
</script>
|
||||
11
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/locales/ja/ui_ui_control.json
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ui_ui_control" : {
|
||||
"label" : {
|
||||
"category" : "dashboard",
|
||||
"name" : "名前"
|
||||
},
|
||||
"placeholder" : {
|
||||
"name" : "名前"
|
||||
}
|
||||
}
|
||||
}
|
||||
84
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_audio.html
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var myvoice = 0;
|
||||
var voices;
|
||||
RED.nodes.registerType('ui_audio',{
|
||||
category: 'dashboard',
|
||||
paletteLabel: 'audio out',
|
||||
color: 'rgb(119, 198, 204)',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
group: {type: 'ui_group', required: true},
|
||||
voice: {value:""},
|
||||
always: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "feed.png",
|
||||
align: "right",
|
||||
label: function() { return this.name||"audio out"; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
onpaletteadd: function() {
|
||||
if ('speechSynthesis' in window) { voices = window.speechSynthesis.getVoices(); }
|
||||
},
|
||||
oneditprepare: function() {
|
||||
if ('speechSynthesis' in window) {
|
||||
voices = window.speechSynthesis.getVoices();
|
||||
for (i = 0; i < voices.length ; i++) {
|
||||
//console.log(i,voices[i].name,voices[i].lang,voices[i].voiceURI,voices[i].default);
|
||||
var option = document.createElement('option');
|
||||
option.textContent = i + " : " + voices[i].name + ' (' + voices[i].lang + ')';
|
||||
if (voices[i].default) { option.textContent += ' -- DEFAULT'; }
|
||||
option.setAttribute('value', voices[i].lang);
|
||||
document.getElementById("node-input-voice").appendChild(option);
|
||||
}
|
||||
$('#node-input-voice').val(this.voice || 0);
|
||||
}
|
||||
else {
|
||||
$('#voice-input-row').hide();
|
||||
}
|
||||
|
||||
$("#node-input-voice").on("change", function() {
|
||||
myvoice = this.voice = $("#node-input-voice").val();
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_audio">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row" id="voice-input-row">
|
||||
<label for="node-input-voice"><i class="fa fa-language"></i> TTS Voice</label>
|
||||
<select id="node-input-voice" style="width:70%"></select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-always"></label>
|
||||
<input type="checkbox" checked id="node-input-always" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
Play audio when window not in focus.
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_audio">
|
||||
<p>Plays audio or text to speech (TTS) in the dashboard.</p>
|
||||
<p>To work the dashboard web page must be open.</p>
|
||||
<p>Expects <code>msg.payload</code> to contain a buffer of a <b>wav</b> or <b>mp3</b> file.</p>
|
||||
<p>If your browser has native support for Text-to-Speech then a <code>msg.payload</code>
|
||||
can also be a <b>string</b> to be read aloud.</p>
|
||||
<p>When a <code>msg.reset</code> is available with value <code>true</code>, then playback of the current audio fragment will be stopped.</p>
|
||||
<p>The <b>node status</b> reflects the current playback status:
|
||||
<ul>
|
||||
<li><b>started:</b> the audio fragment playback has been started.</li>
|
||||
<li><b>reset:</b> the audio fragment playback has been reset (i.e. stopped before completed).</li>
|
||||
</ul>
|
||||
As soon as the audio fragment playback is completed, the node status will be cleared automatically.</p>
|
||||
</script>
|
||||
46
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_audio.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function uiAudioNode(config) {
|
||||
RED.nodes.createNode(this,config);
|
||||
this.voice = config.voice;
|
||||
this.group = config.group;
|
||||
this.always = config.always || false;
|
||||
if (this.group && RED.nodes.getNode(this.group).hasOwnProperty("config")) {
|
||||
this.tabname = RED.nodes.getNode(RED.nodes.getNode(this.group).config.tab).name;
|
||||
}
|
||||
var node = this;
|
||||
node.status({});
|
||||
|
||||
this.on('input', function(msg) {
|
||||
if (msg.reset == true) {
|
||||
ui.emit('ui-audio', { reset:true, tabname:node.tabname, always:node.always });
|
||||
}
|
||||
else if (Buffer.isBuffer(msg.payload)) {
|
||||
ui.emit('ui-audio', { audio:msg.payload, tabname:node.tabname, always:node.always });
|
||||
}
|
||||
else if (typeof msg.payload === "string") {
|
||||
ui.emit('ui-audio', { tts:msg.payload, voice:(node.voice || msg.voice || 0), tabname:node.tabname, always:node.always });
|
||||
}
|
||||
});
|
||||
|
||||
var updateStatus = function(audioStatus) {
|
||||
if (audioStatus === "complete") {
|
||||
// When the audio or speech has played completely, clear the node status
|
||||
node.status({});
|
||||
}
|
||||
else if (audioStatus.indexOf("error") === 0) {
|
||||
node.status({shape:"ring",fill:"red",text:audioStatus});
|
||||
}
|
||||
else {
|
||||
node.status({shape:"dot",fill:"blue",text:audioStatus});
|
||||
}
|
||||
};
|
||||
ui.ev.on('audiostatus', updateStatus);
|
||||
|
||||
this.on('close', function() {
|
||||
ui.ev.removeListener('audiostatus', updateStatus);
|
||||
})
|
||||
}
|
||||
RED.nodes.registerType("ui_audio", uiAudioNode);
|
||||
}
|
||||
3406
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_base.html
generated
vendored
Normal file
@@ -0,0 +1,3406 @@
|
||||
<style>
|
||||
:root {
|
||||
--nr-db-dark-text: #444;
|
||||
--nr-db-light-text: #eee;
|
||||
--nr-db-disabled-text: #999;
|
||||
}
|
||||
.nr-db-sb {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
bottom: 2px;
|
||||
left: 1px;
|
||||
right: 1px;
|
||||
overflow-y: scroll;
|
||||
padding: 10px;
|
||||
}
|
||||
.nr-db-sb .form-row label {
|
||||
display: block;
|
||||
width: auto;
|
||||
}
|
||||
.nr-db-sb .form-row input,
|
||||
.nr-db-sb .form-row select {
|
||||
width: calc(100% - 100px);
|
||||
margin-bottom:0;
|
||||
}
|
||||
.nr-db-sb .compact {
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
.nr-db-sb .red-ui-editableList-container {
|
||||
padding: 0;
|
||||
min-height: 250px;
|
||||
height: auto;
|
||||
}
|
||||
.nr-db-sb-tab-list {
|
||||
min-height: 250px;
|
||||
height: auto;
|
||||
}
|
||||
.nr-db-sb-tab-list li {
|
||||
padding: 0;
|
||||
}
|
||||
.nr-db-sb-tab-list-item {
|
||||
border-radius: 4px;
|
||||
color: var(--nr-db-dark-text);
|
||||
}
|
||||
.nr-db-sb-list-header {
|
||||
cursor: pointer;
|
||||
position:relative;
|
||||
color: var(--nr-db-dark-text);
|
||||
padding:3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.nr-db-sb-list-header:hover {
|
||||
color: var(--nr-db-dark-text);
|
||||
}
|
||||
.nr-db-sb-title-hidden {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.nr-db-sb-title-disabled {
|
||||
color: var(--nr-db-disabled-text);
|
||||
}
|
||||
.nr-db-sb-tab-list-header {
|
||||
background: var(--nr-db-light-text);
|
||||
padding:5px;
|
||||
}
|
||||
.nr-db-sb-group-list-header:hover,
|
||||
.nr-db-sb-widget-list-header:hover {
|
||||
background: var(--nr-db-light-text);
|
||||
}
|
||||
.nr-db-sb-list-chevron {
|
||||
width: 15px;
|
||||
text-align: center;
|
||||
margin: 3px 5px 3px 5px;
|
||||
}
|
||||
.nr-db-sb-tab-list-item .red-ui-editableList-container {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
height: auto !important;
|
||||
min-height: unset;
|
||||
}
|
||||
.nr-db-sb-list-handle {
|
||||
vertical-align: top;
|
||||
opacity: 0;
|
||||
cursor: move;
|
||||
}
|
||||
.nr-db-sb-list-header:hover>.nr-db-sb-list-handle,
|
||||
.nr-db-sb-list-header:hover>.nr-db-sb-list-header-button-group {
|
||||
opacity: 1;
|
||||
}
|
||||
.nr-db-sb-list-header-button-group {
|
||||
opacity: 0;
|
||||
}
|
||||
.nr-db-sb-list-handle {
|
||||
color: var(--nr-db-light-text);
|
||||
padding:5px;
|
||||
}
|
||||
.nr-db-sb-tab-list-header>.nr-db-sb-list-chevron {
|
||||
margin-left: 0px;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
.nr-db-sb-group-list-header>.nr-db-sb-list-chevron {
|
||||
margin-left: 20px;
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
.nr-db-sb-group-list {
|
||||
min-height: 10px;
|
||||
}
|
||||
.nr-db-sb-group-list li {
|
||||
border-bottom-color: var(--nr-db-light-text);
|
||||
}
|
||||
.nr-db-sb-group-list>li.ui-sortable-helper {
|
||||
border-top: 1px solid var(--nr-db-light-text);
|
||||
}
|
||||
.nr-db-sb-group-list>li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.nr-db-sb-widget-list>li {
|
||||
border: none !important;
|
||||
}
|
||||
.nr-db-sb-group-list>li>.red-ui-editableList-item-handle {
|
||||
left: 10px;
|
||||
}
|
||||
.nr-db-sb-list-button-group {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 0px;
|
||||
z-index: 2;
|
||||
}
|
||||
.nr-db-sb-list-header-button-group {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 4px;
|
||||
}
|
||||
.nr-db-sb-list-header-button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.nr-db-sb li.ui-sortable-helper {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.nr-db-sb-widget-icon {
|
||||
margin-left: 56px;
|
||||
}
|
||||
.nr-db-sb-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.nr-db-sb-link {
|
||||
display: inline-block;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.nr-db-sb-link-name-container .fa-external-link {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.nr-db-sb-link-url {
|
||||
font-size: 0.8em;
|
||||
color: var(--nr-db-mid-grey);
|
||||
}
|
||||
span.nr-db-color-pick-container {
|
||||
max-width: 50px;
|
||||
border-radius: 3px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
input.nr-db-field-themeColor[type="color"] {
|
||||
width: 60px !important;
|
||||
padding: 0px;
|
||||
height: 20px;
|
||||
box-shadow: none;
|
||||
position: absolute;
|
||||
right: 36px;
|
||||
border-radius: 3px !important;
|
||||
border: solid 1px #ccc;
|
||||
-webkit-appearance: none;
|
||||
font-size: smaller;
|
||||
text-align: center;
|
||||
}
|
||||
input.nr-db-field-themeColor::-webkit-color-swatch {
|
||||
border: none;
|
||||
}
|
||||
.red-ui-tabs {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.red-ui-tab.hidden {
|
||||
display: none;
|
||||
}
|
||||
#dashboard-tabs-list li a:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
#dash-link-button {
|
||||
background: none;
|
||||
border: none;
|
||||
margin-top: 3px;
|
||||
display: inline-block;
|
||||
margin: 3px 0px 0px 3px;
|
||||
height: 32px;
|
||||
line-height: 29px;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
padding: 0px 7px 0px 7px;
|
||||
}
|
||||
ul.red-ui-dashboard-theme-styles {
|
||||
list-style: none;
|
||||
}
|
||||
ul.red-ui-dashboard-theme-styles li {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.nr-db-resetIcon {
|
||||
margin: 3px 6px 0px 6px;
|
||||
float: right;
|
||||
color: var(--nr-db-mid-grey);
|
||||
opacity: 0.8;
|
||||
display: block;
|
||||
}
|
||||
.nr-db-resetIcon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
#nr-db-field-font {
|
||||
margin-left: 2em;
|
||||
width: calc(100% - 81px);
|
||||
}
|
||||
.nr-db-theme-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
#custom-theme-library-container .btn-group {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<!-- Dashboard layout tool -->
|
||||
<link rel="stylesheet" href="./ui_base/css/gridstack.min.css">
|
||||
<link rel="stylesheet" href="./ui_base/css/gridstack-extra.min.css">
|
||||
<style>
|
||||
.grid-stack {
|
||||
background-color: #f8f8f8;
|
||||
border: solid 2px #C0C0C0;
|
||||
margin: auto;
|
||||
min-height: 46px;
|
||||
display: table-cell;
|
||||
background-image: linear-gradient(#C0C0C0 1px, transparent 0),
|
||||
linear-gradient(90deg, #C0C0C0 1px, transparent 0);
|
||||
background-size: 40px 47px;
|
||||
}
|
||||
.grid-stack>.grid-stack-item>.grid-stack-item-content {
|
||||
top: 3px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 3px;
|
||||
}
|
||||
.grid-stack-item-content {
|
||||
color: #2c3e50;
|
||||
text-align: center;
|
||||
background-color: #b0dfe3;
|
||||
border-radius: 2px;
|
||||
font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.grid-stack-item {
|
||||
cursor: move;
|
||||
}
|
||||
.nr-dashboard-layout-container-fluid {
|
||||
width: 100%;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
margin-right: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
.nr-dashboard-layout-row {
|
||||
width: 100%;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
margin-right: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
.nr-dashboard-layout-span12 {
|
||||
width: 98.4%;
|
||||
padding: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nr-dashboard-layout-span6 {
|
||||
width: 49.2%;
|
||||
padding: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nr-dashboard-layout-span4 {
|
||||
width: 32.7%;
|
||||
padding: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nr-dashboard-layout-span3 {
|
||||
width: 24.3%;
|
||||
padding: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nr-dashboard-layout-span2 {
|
||||
width: 16.0%;
|
||||
padding: 2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
.nr-dashboard-layout-resize-disable {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
position: relative;
|
||||
z-index: 90;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.nr-dashboard-layout-resize-enable {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
position: relative;
|
||||
z-index: 90;
|
||||
margin-right: 1px;
|
||||
}
|
||||
.grid-stack>.ui-state-disabled {
|
||||
opacity: 1;
|
||||
background-image: none;
|
||||
}
|
||||
.grid-stack>.grid-stack-item>.ui-resizable-handle {
|
||||
z-index: 90;
|
||||
margin-right: -7px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
var editSaveEventHandler;
|
||||
var nodesAddEventHandler;
|
||||
var nodesRemoveEventHandler;
|
||||
var layoutUpdateEventHandler; // Dashboard layout tool
|
||||
var uip = 'ui';
|
||||
var attemptedVendorLoad = false;
|
||||
var loadTinyColor = function(path) {
|
||||
$.ajax({ url: path,
|
||||
success: function (data) {
|
||||
var jsScript = document.createElement("script");
|
||||
jsScript.type = "application/javascript";
|
||||
jsScript.src = path;
|
||||
document.body.appendChild(jsScript);
|
||||
//console.log('Tiny Color Loaded:',path);
|
||||
},
|
||||
error: function (xhr, ajaxOptions, thrownError) {
|
||||
if (xhr.status === 404 && !attemptedVendorLoad) {
|
||||
loadTinyColor('/'+uip+'/vendor/tinycolor2/dist/tinycolor-min.js');
|
||||
attemptedVendorLoad = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// convert to i18 text
|
||||
function c_(x) {
|
||||
return RED._("node-red-dashboard/ui_base:ui_base."+x);
|
||||
}
|
||||
|
||||
// Try to load dist version first
|
||||
// then if fails, load non dist version
|
||||
loadTinyColor('ui_base/js/tinycolor-min.js');
|
||||
//loadTinyColor('ui_base/tinycolor2/dist/tinycolor-min.js');
|
||||
|
||||
|
||||
// Dashboard layout tool
|
||||
// Load gridstack library
|
||||
var loadGsLib = function(path, callback) {
|
||||
$.ajax({ url: path,
|
||||
success: function (data) {
|
||||
var jsScript = document.createElement("script");
|
||||
jsScript.type = "application/javascript";
|
||||
jsScript.src = path;
|
||||
document.body.appendChild(jsScript);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
error: function (xhr, ajaxOptions, thrownError) {
|
||||
// TODO
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
loadGsLib('ui_base/js/lodash.min.js', function() {
|
||||
loadGsLib('ui_base/js/gridstack.min.js', function() {
|
||||
loadGsLib('ui_base/js/gridstack.jQueryUI.min.js', null)
|
||||
});
|
||||
});
|
||||
|
||||
var tabDatas; // Layout editing tab data
|
||||
var oldSpacer; // Spacer not needed after editing
|
||||
|
||||
var widthChange; // Group width change
|
||||
var widgetMove; // Move widget event
|
||||
var widgetResize; // Change widget event
|
||||
var widgetDrag; // Drag wiget eevnt
|
||||
|
||||
var MAX_GROUP_WIDTH = 30; // The maximum width is 30
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Get widget under specified tab from node information
|
||||
/////////////////////////////////////////////////////////
|
||||
function getTabDataFromNodes(tabID) {
|
||||
var nodes = RED.nodes.createCompleteNodeSet(false);
|
||||
var tab = {};
|
||||
// Tab information
|
||||
for (var cnt = 0; cnt < nodes.length; cnt++) {
|
||||
if (nodes[cnt].type == "ui_tab" && nodes[cnt].id == tabID) {
|
||||
tab = {
|
||||
id: nodes[cnt].id,
|
||||
name: nodes[cnt].name,
|
||||
type: nodes[cnt].type,
|
||||
order: nodes[cnt].order,
|
||||
groups: []
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Group information
|
||||
for (var cnt = 0; cnt < nodes.length; cnt++) {
|
||||
if (nodes[cnt].type == "ui_group" && nodes[cnt].tab == tabID) {
|
||||
var group = {
|
||||
id: nodes[cnt].id,
|
||||
name: nodes[cnt].name,
|
||||
type: nodes[cnt].type,
|
||||
order: nodes[cnt].order,
|
||||
width: nodes[cnt].width,
|
||||
widgets: []
|
||||
};
|
||||
tab.groups.push(group);
|
||||
}
|
||||
}
|
||||
// Widget information
|
||||
var groupsIdx = {};
|
||||
for (var cnt = 0; cnt < tab.groups.length; cnt++) {
|
||||
groupsIdx[tab.groups[cnt].id] = tab.groups[cnt];
|
||||
}
|
||||
for (var cnt = 0; cnt < nodes.length; cnt++) {
|
||||
var group = groupsIdx[nodes[cnt].group];
|
||||
if (group != null && (/^ui_/.test(nodes[cnt].type) && nodes[cnt].type !== 'ui_link' && nodes[cnt].type !== 'ui_toast' && nodes[cnt].type !== 'ui_ui_control' && nodes[cnt].type !== 'ui_audio' && nodes[cnt].type !== 'ui_base' && nodes[cnt].type !== 'ui_group' && nodes[cnt].type !== 'ui_tab')) {
|
||||
var widget = {
|
||||
id: nodes[cnt].id,
|
||||
type: nodes[cnt].type,
|
||||
order: nodes[cnt].order,
|
||||
width: nodes[cnt].width,
|
||||
height: nodes[cnt].height,
|
||||
auto: nodes[cnt].width == 0 ? true : false
|
||||
};
|
||||
group.widgets.push(widget);
|
||||
|
||||
if (!isLayoutToolSupported(nodes[cnt].type)){
|
||||
console.log("LayoutTool warning: Unsupported widget. Widget="+JSON.stringify(widget));
|
||||
}
|
||||
}
|
||||
}
|
||||
return tab;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Update node information in the edited widget
|
||||
////////////////////////////////////////////////////
|
||||
function putTabDataToNodes() {
|
||||
// Delete old flow spacer node
|
||||
for (var cnt = 0; cnt < oldSpacer.length; cnt++) {
|
||||
RED.nodes.remove(oldSpacer[cnt]);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
|
||||
var t_groups = tabDatas.groups;
|
||||
for (var cnt1 = 0; cnt1 < t_groups.length; cnt1++){
|
||||
var n_group = RED.nodes.node(t_groups[cnt1].id);
|
||||
n_group.width = t_groups[cnt1].width;
|
||||
var t_widgets = t_groups[cnt1].widgets;
|
||||
for (var cnt2 = 0; cnt2 < t_widgets.length; cnt2++) {
|
||||
var n_widget = RED.nodes.node(t_widgets[cnt2].id);
|
||||
if (n_widget != null) {
|
||||
if (n_widget.group !== n_group.id) {
|
||||
var oldGroupNode = RED.nodes.node(n_widget.group);
|
||||
if (oldGroupNode) {
|
||||
var index = oldGroupNode.users.indexOf(n_widget);
|
||||
oldGroupNode.users.splice(index,1);
|
||||
}
|
||||
n_widget.group = n_group.id;
|
||||
n_group.users.push(n_widget);
|
||||
}
|
||||
n_widget.order = t_widgets[cnt2].order;
|
||||
if (t_widgets[cnt2].auto === true ) {
|
||||
n_widget.width = 0;
|
||||
n_widget.height = 0;
|
||||
} else {
|
||||
n_widget.width = t_widgets[cnt2].width;
|
||||
n_widget.height = t_widgets[cnt2].height;
|
||||
}
|
||||
|
||||
n_widget.changed = true;
|
||||
n_widget.dirty = true;
|
||||
RED.editor.validateNode(n_widget);
|
||||
RED.events.emit("layout:update",n_widget);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
} else {
|
||||
// Add a spacer node
|
||||
if (t_widgets[cnt2].type === 'ui_spacer') {
|
||||
var spaceNode = {
|
||||
_def: RED.nodes.getType("ui_spacer"),
|
||||
type: "ui_spacer",
|
||||
hasUsers: false,
|
||||
users: [],
|
||||
id: RED.nodes.id(),
|
||||
tab: tabDatas.id,
|
||||
group: n_group.id,
|
||||
order: t_widgets[cnt2].order,
|
||||
name: "spacer",
|
||||
width: t_widgets[cnt2].width,
|
||||
height: t_widgets[cnt2].height,
|
||||
label: function() { return this.name + " " + this.width + "x" + this.height; }
|
||||
};
|
||||
RED.nodes.add(spaceNode);
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
RED.sidebar.info.refresh();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// Sort by order
|
||||
////////////////////////////////////////
|
||||
function compareOrder(a, b) {
|
||||
var r = 0;
|
||||
if (a.order < b.order) { r = -1; }
|
||||
else if (a.order > b.order) { r = 1; }
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// Sort by XY
|
||||
////////////////////////////////////////
|
||||
function compareXY(a, b) {
|
||||
var r = 0;
|
||||
if (a.y < b.y) { r = -1; }
|
||||
else if (a.y > b.y) { r = 1; }
|
||||
else if (a.x < b.x) { r = -1; }
|
||||
else if (a.x > b.x) { r = 1; }
|
||||
return r;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// Placeable location search (placed in the upper left)
|
||||
///////////////////////////////////////////////////////
|
||||
function search_point(width, height, maxWidth, maxHeight, tbl){
|
||||
for (var y=0; y < maxHeight; y++) {
|
||||
for (var x=0; x < maxWidth; x++) {
|
||||
if (check_matrix(x, y, width, height, maxWidth, tbl)) {
|
||||
fill_matrix(x, y, width, height, maxWidth, tbl);
|
||||
return {x:x, y:y};
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Check placement position
|
||||
function check_matrix(px, py, width, height, maxWidth, tbl){
|
||||
if (px+width > maxWidth) return false;
|
||||
for (var y=py; y < py+height; y++) {
|
||||
for (var x=px; x<px+width; x++) {
|
||||
if (tbl[maxWidth*y+x]) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Mark the placement position
|
||||
function fill_matrix(px, py, width, height, maxWidth, tbl){
|
||||
for (var y=py; y < py+height; y++) {
|
||||
for (var x=px; x < px+width; x++) {
|
||||
tbl[maxWidth*y+x] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Apply edit result to tab information for editing
|
||||
////////////////////////////////////////////////////
|
||||
function saveGridDatas(){
|
||||
var groups = tabDatas.groups;
|
||||
for (var cnt = 0; cnt < groups.length; cnt++) {
|
||||
// Get layout editing results
|
||||
var gridID = '#grid'+cnt;
|
||||
var serializedData = _.map($(gridID+'.grid-stack > .grid-stack-item:visible'), function (el) {
|
||||
el = $(el);
|
||||
var node = el.data('_gridstack_node');
|
||||
return {
|
||||
id: el[0].dataset.noderedid,
|
||||
type: el[0].dataset.noderedtype,
|
||||
group: groups[cnt].id,
|
||||
width: Number(node.width),
|
||||
height: Number(node.height),
|
||||
x: node.x,
|
||||
y: node.y,
|
||||
auto: (el[0].dataset.noderedsizeauto == 'true') ? true : false
|
||||
};
|
||||
}, this);
|
||||
|
||||
var width = Number(groups[cnt].width);
|
||||
var height = 0;
|
||||
|
||||
// Search group height
|
||||
for (var i=0; i < serializedData.length; i++){
|
||||
var wd = serializedData[i];
|
||||
if (height < wd.y + wd.height) {
|
||||
height = wd.y + wd.height;
|
||||
}
|
||||
}
|
||||
|
||||
// Place widget on table
|
||||
var tbl = new Array(width * height);
|
||||
for (var i = 0; i< tbl.length; i++){
|
||||
tbl[i]=0;
|
||||
}
|
||||
for (var i = 0; i < serializedData.length; i++){
|
||||
var wd = serializedData[i];
|
||||
for (var y = wd.y; y < wd.y+wd.height; y++){
|
||||
for (var x = wd.x; x < wd.x+wd.width; x++){
|
||||
tbl[width*y+x]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add Spacer to Blank
|
||||
for (var y = 0; y < height; y++){
|
||||
var spacerAdded = false;
|
||||
for (var x = 0; x < width; x++){
|
||||
if (tbl[width*y+x]===0) {
|
||||
if (!spacerAdded) {
|
||||
// Add 1x1 spacer
|
||||
serializedData.push({
|
||||
x: x,
|
||||
y: y,
|
||||
width: 1,
|
||||
height: 1,
|
||||
name: 'spacer',
|
||||
type: 'ui_spacer'
|
||||
});
|
||||
spacerAdded = true;
|
||||
} else {
|
||||
// Extend the spacer width by 1
|
||||
serializedData[serializedData.length-1].width += 1;
|
||||
}
|
||||
} else {
|
||||
spacerAdded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort Gridstack objects by x, y information
|
||||
serializedData.sort(compareXY);
|
||||
|
||||
// Delete x and y elements as information for sorting, and give order
|
||||
var order = 0;
|
||||
for (i in serializedData) {
|
||||
order++;
|
||||
delete serializedData[i].x;
|
||||
delete serializedData[i].y;
|
||||
serializedData[i].order = order;
|
||||
}
|
||||
|
||||
// Update widget information in group with edited data
|
||||
var group = groups[cnt];
|
||||
delete group.widgets;
|
||||
group.widgets = serializedData;
|
||||
}
|
||||
|
||||
// Save process call
|
||||
putTabDataToNodes();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Get default height for automatic settings
|
||||
////////////////////////////////////////////////////
|
||||
function getDefaultHeight(nodeID, groupWidth) {
|
||||
var redNode = RED.nodes.node(nodeID);
|
||||
var height = 1;
|
||||
|
||||
if (redNode.type === 'ui_gauge') {
|
||||
if (redNode.gtype === 'gage') {
|
||||
height = Math.round(groupWidth/2)+1;
|
||||
} else if (redNode.gtype === 'wave') {
|
||||
if (groupWidth < 3) {
|
||||
height = 1;
|
||||
} else {
|
||||
height = Math.round(groupWidth*0.75);
|
||||
}
|
||||
} else { // donut or compass
|
||||
if (groupWidth < 3) {
|
||||
height = 1;
|
||||
} else if (groupWidth < 11) {
|
||||
height = groupWidth - 1;
|
||||
} else {
|
||||
height = Math.round(groupWidth*0.95);
|
||||
}
|
||||
}
|
||||
} else if (redNode.type === 'ui_chart') {
|
||||
height = Math.floor(groupWidth/2)+1;
|
||||
} else if (redNode.type === 'ui_form') {
|
||||
var optNum = redNode.options.length; // Sub widget number
|
||||
if (redNode.label) {
|
||||
height = optNum + 2; // Label and Button
|
||||
} else {
|
||||
height = optNum + 1; // Button only
|
||||
}
|
||||
} else if (redNode.type === 'ui_lineargauge') {
|
||||
if (redNode.unit && redNode.name) {
|
||||
height = 5;
|
||||
} else {
|
||||
height = 4;
|
||||
}
|
||||
} else if (redNode.type === 'ui_list') {
|
||||
height = 5;
|
||||
} else if (redNode.type === 'ui_vega') {
|
||||
height = 5;
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// Grid width change
|
||||
////////////////////////////
|
||||
var changeGroupWidth = function(id) {
|
||||
var widthID = '#change-width'+id;
|
||||
var gridID = '#grid'+id;
|
||||
$(widthID).spinner( {
|
||||
min: 1,
|
||||
max: MAX_GROUP_WIDTH,
|
||||
spin: function(event, ui){
|
||||
// Search current maximum width
|
||||
serializedData = _.map($(gridID+'.grid-stack > .grid-stack-item:visible'), function (el) {
|
||||
el = $(el);
|
||||
var node = el.data('_gridstack_node');
|
||||
return {
|
||||
width: Number(node.width),
|
||||
x: node.x,
|
||||
auto: (el[0].dataset.noderedsizeauto == 'true') ? true : false
|
||||
};
|
||||
}, this);
|
||||
var maxWidth = 0;
|
||||
for (var i=0; i < serializedData.length; i++){
|
||||
var wd = serializedData[i];
|
||||
if (wd.auto == false) {
|
||||
if (maxWidth < wd.x + wd.width) {
|
||||
maxWidth = wd.x + wd.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
var width = ui.value;
|
||||
if (width < maxWidth) {
|
||||
width = maxWidth;
|
||||
}
|
||||
|
||||
var grid = $(gridID+'.grid-stack').data('gridstack');
|
||||
$(gridID+'.grid-stack').css("width", width * 40);
|
||||
$(gridID+'.grid-stack').css("background-size", 100/width+"% 47px");
|
||||
grid.setGridWidth(tabDatas.groups[id].width, true);
|
||||
grid.setGridWidth(width, true);
|
||||
tabDatas.groups[id].width = width;
|
||||
|
||||
$(gridID+'.grid-stack > .grid-stack-item:visible').each( function(idx, el) {
|
||||
el = $(el);
|
||||
var node = el.data('_gridstack_node');
|
||||
var auto = (el[0].dataset.noderedsizeauto == 'true') ? true : false;
|
||||
var type = el[0].dataset.noderedtype;
|
||||
grid.resizable(el, !auto);
|
||||
if (auto === true) {
|
||||
grid.resize(el, width, getDefaultHeight(node.id, width));
|
||||
}
|
||||
});
|
||||
|
||||
if (width !== ui.value) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
// Move between groups of widgets
|
||||
//////////////////////////////////
|
||||
var moveGroupWidget = function(id) {
|
||||
|
||||
var toGridID = '#grid'+id;
|
||||
var toGrid = $(toGridID+'.grid-stack').data('gridstack');
|
||||
|
||||
toGrid.container.droppable({
|
||||
acccept: '.grid-stack-item',
|
||||
tolerance: 'pointer',
|
||||
drop: function( event, ui ) {
|
||||
|
||||
var fromGridID = '#' + ui.draggable[0].offsetParent.id;
|
||||
|
||||
// Move the widget
|
||||
if (fromGridID !== toGridID) {
|
||||
|
||||
var toGridOffset = $(toGridID).offset();
|
||||
var groupWidth = tabDatas.groups[id].width;
|
||||
|
||||
// Reset group width before moving (Grid stack measures)
|
||||
toGrid.setGridWidth(groupWidth, true);
|
||||
|
||||
// Current widget width factor for x position
|
||||
var curWidth = ($('#grid1').offset().left - $('#grid0').offset().left) * 0.9;
|
||||
var xfactor = curWidth / (groupWidth * 40);
|
||||
xfactor = xfactor > 1.0 ? 1.0 : xfactor;
|
||||
var x = Math.floor((ui.offset.left - toGridOffset.left)/(40 * xfactor));
|
||||
var y = Math.floor((ui.offset.top - toGridOffset.top)/47);
|
||||
var node = {
|
||||
type: ui.draggable[0].dataset.noderedtype,
|
||||
id: ui.draggable[0].dataset.noderedid,
|
||||
x: x,
|
||||
y: y,
|
||||
width: ui.draggable[0].dataset.gsWidth,
|
||||
height: ui.draggable[0].dataset.gsHeight,
|
||||
auto: (ui.draggable[0].dataset.noderedsizeauto == 'true') ? true : false
|
||||
};
|
||||
|
||||
var dispType = ui.draggable[0].dataset.nodereddisptype;
|
||||
var dispLabel = ui.draggable[0].dataset.nodereddisplabel;
|
||||
|
||||
var item = $('<div></div>', {
|
||||
'data-noderedtype': node.type,
|
||||
'data-noderedid': node.id,
|
||||
'data-nodereddisptype': dispType,
|
||||
'data-nodereddisplabel': dispLabel,
|
||||
'data-noderedsizeauto': node.auto
|
||||
});
|
||||
|
||||
if (node.auto === true) {
|
||||
node.x = 0;
|
||||
node.width = groupWidth;
|
||||
node.height = getDefaultHeight(node.id, groupWidth);
|
||||
}
|
||||
|
||||
var itemContent = $('<div></div>', {
|
||||
addClass: 'grid-stack-item-content',
|
||||
title: dispLabel + ':' + dispType
|
||||
});
|
||||
|
||||
if (node.auto === true) {
|
||||
itemContent.append('<i class="fa fa-unlock nr-dashboard-layout-resize-enable"></i>');
|
||||
itemContent.find('.nr-dashboard-layout-resize-enable').on('click',layoutResizeEnable);
|
||||
} else {
|
||||
itemContent.append('<i class="fa fa-lock nr-dashboard-layout-resize-disable"</i>');
|
||||
itemContent.find('.nr-dashboard-layout-resize-disable').on('click',layoutResizeDisable);
|
||||
}
|
||||
|
||||
itemContent.append('<b>'+ dispLabel +'</b><br/>'+ dispType);
|
||||
itemContent.appendTo(item);
|
||||
var newWidget = toGrid.addWidget(
|
||||
item,
|
||||
node.x, node.y, node.width, node.height, false, null, null,
|
||||
ui.draggable[0].dataset.gsMinHeight,
|
||||
ui.draggable[0].dataset.gsMaxHeight,
|
||||
node.id);
|
||||
|
||||
var fromWidget = ui.draggable[0];
|
||||
if (node.auto === true) {
|
||||
$(fromWidget).find('.nr-dashboard-layout-resize-enable').off('click');
|
||||
} else {
|
||||
$(fromWidget).find('.nr-dashboard-layout-resize-disable').off('click');
|
||||
}
|
||||
var fromGrid = $(fromGridID+'.grid-stack').data('gridstack');
|
||||
fromGrid.removeWidget(fromWidget);
|
||||
toGrid.resizable(newWidget, !node.auto);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Widget size change (start event)
|
||||
//////////////////////////////////////////
|
||||
var resizeGroupWidget = function(id) {
|
||||
var gridID = '#grid'+id;
|
||||
var grid = $(gridID+'.grid-stack').data('gridstack');
|
||||
$(gridID+'.grid-stack').on('resizestart', function(event, ui) {
|
||||
// Reset group width
|
||||
grid.setGridWidth(tabDatas.groups[id].width, true);
|
||||
});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Widget drag (start event)
|
||||
//////////////////////////////////////////
|
||||
var dragGroupWidget = function(id) {
|
||||
var gridID = '#grid'+id;
|
||||
var grid = $(gridID+'.grid-stack').data('gridstack');
|
||||
$(gridID+'.grid-stack').on('dragstart', function(event, ui) {
|
||||
// Reset group width
|
||||
grid.setGridWidth(tabDatas.groups[id].width, true);
|
||||
});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Layout resize Disable (Auto:false)
|
||||
//////////////////////////////////////////
|
||||
var layoutResizeDisable = function(e) {
|
||||
var target = $(e.target);
|
||||
var el = target.parents('.grid-stack-item:visible');
|
||||
var grid = target.parents('.grid-stack').data('gridstack');
|
||||
var node = el.data('_gridstack_node');
|
||||
|
||||
var id = Number(target.parents('.grid-stack').attr('id').slice(4));
|
||||
var width = Number(tabDatas.groups[id].width);
|
||||
|
||||
var nodeID = el[0].dataset.noderedid;
|
||||
var height = getDefaultHeight(nodeID, width);
|
||||
grid.move(el, 0, node.y);
|
||||
grid.resize(el, width, height);
|
||||
|
||||
grid.resizable(el, false);
|
||||
el.find('.nr-dashboard-layout-resize-disable').off('click');
|
||||
el.attr({'data-noderedsizeauto':'true'});
|
||||
target.removeClass().addClass('fa fa-unlock nr-dashboard-layout-resize-enable');
|
||||
el.find('.nr-dashboard-layout-resize-enable').on('click',layoutResizeEnable);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Layout resize Enable (Auto:true)
|
||||
//////////////////////////////////////////
|
||||
var layoutResizeEnable = function(e){
|
||||
var target = $(e.target);
|
||||
var el = target.parents('.grid-stack-item:visible');
|
||||
var grid = target.parents('.grid-stack').data('gridstack');
|
||||
|
||||
grid.resizable(el, true);
|
||||
el.find('.nr-dashboard-layout-resize-enable').off('click');
|
||||
el.attr({'data-noderedsizeauto':'false'});
|
||||
target.removeClass().addClass('fa fa-lock nr-dashboard-layout-resize-disable');
|
||||
el.find('.nr-dashboard-layout-resize-disable').on('click',layoutResizeDisable);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Check dashboard layout tool supported
|
||||
//////////////////////////////////////////
|
||||
function isLayoutToolSupported(nodeType){
|
||||
if (nodeType !== "ui_spacer" &&
|
||||
nodeType !== "ui_button" &&
|
||||
nodeType !== "ui_dropdown" &&
|
||||
nodeType !== "ui_switch" &&
|
||||
nodeType !== "ui_slider" &&
|
||||
nodeType !== "ui_numeric" &&
|
||||
nodeType !== "ui_text_input" &&
|
||||
nodeType !== "ui_date_picker" &&
|
||||
nodeType !== "ui_colour_picker" &&
|
||||
nodeType !== "ui_form" &&
|
||||
nodeType !== "ui_text" &&
|
||||
nodeType !== "ui_gauge" &&
|
||||
nodeType !== "ui_chart" &&
|
||||
nodeType !== "ui_template" &&
|
||||
nodeType !== "ui_list" &&
|
||||
nodeType !== "ui_table" &&
|
||||
nodeType !== "ui_lineargauge" &&
|
||||
nodeType !== "ui_my-little-ui-node" &&
|
||||
nodeType !== "ui_vega") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RED.nodes.registerType('ui_base',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {},
|
||||
theme: {},
|
||||
site: {}
|
||||
},
|
||||
hasUsers: false,
|
||||
paletteLabel: 'Dashboard',
|
||||
label: function() { return this.name || 'Node-RED Dashboard'; },
|
||||
labelStyle: function() { return this.name ? "node_label_italic" : ""; },
|
||||
onpaletteremove: function() {
|
||||
RED.sidebar.removeTab("dashboard");
|
||||
RED.events.off("editor:save",editSaveEventHandler);
|
||||
RED.events.off("nodes:add",nodesAddEventHandler);
|
||||
RED.events.off("nodes:remove",nodesRemoveEventHandler);
|
||||
RED.events.off("layout:update",layoutUpdateEventHandler); // Dashboard layout tool
|
||||
},
|
||||
onpaletteadd: function() {
|
||||
var globalDashboardNode = null;
|
||||
var editor;
|
||||
var baseStyles = ['base-color'];
|
||||
var configurableStyles = ['page-titlebar-backgroundColor', 'page-backgroundColor', 'page-sidebar-backgroundColor',
|
||||
'group-textColor', 'group-borderColor', 'group-backgroundColor',
|
||||
'widget-textColor', 'widget-backgroundColor','widget-borderColor'];
|
||||
var baseFontName = "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif";
|
||||
var aTheme = {primary:"indigo", accents:"blue", warn:"red", background:"grey"};
|
||||
// tiny colour implementation
|
||||
var colours = {
|
||||
leastReadable: function(base, colours) {
|
||||
var least = tinycolor.readability(base, colours[0]);
|
||||
var leastColor = colours[0];
|
||||
for (var i=1; i<colours.length; i++) {
|
||||
var readability = tinycolor.readability(base, colours[i]);
|
||||
if (readability < least) {
|
||||
least = readability;
|
||||
leastColor = colours[i];
|
||||
}
|
||||
}
|
||||
return leastColor;
|
||||
},
|
||||
whiteGreyMostReadable: function (base) {
|
||||
var rgb = tinycolor(base).toRgb();
|
||||
var level = ((rgb.r*299) + (rgb.g*587) + (rgb.b*114))/1000;
|
||||
var readable = (level >= 128) ? '#111111' : '#eeeeee';
|
||||
return readable;
|
||||
},
|
||||
whiteBlackLeastReadable: function(base) {
|
||||
return this.leastReadable(base, ["#000000", "#ffffff"]);
|
||||
},
|
||||
calculate_page_backgroundColor: function(base) {
|
||||
var pageBackground = "#fafafa";
|
||||
var theme = "light";
|
||||
if (globalDashboardNode && globalDashboardNode.hasOwnProperty("theme") && globalDashboardNode.theme.hasOwnProperty("name")) {
|
||||
theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
}
|
||||
if (theme === "dark") {
|
||||
pageBackground = "#111111";
|
||||
}
|
||||
else if (theme === "custom") {
|
||||
var whiteOrBlack = this.whiteBlackLeastReadable(base);
|
||||
if (whiteOrBlack === "#000000") { pageBackground = "#111111"; }
|
||||
}
|
||||
return pageBackground;
|
||||
},
|
||||
calculate_page_sidebar_backgroundColor: function(base) {
|
||||
return this.whiteBlackLeastReadable(base);
|
||||
},
|
||||
calculate_page_titlebar_backgroundColor: function(base) {
|
||||
return base;
|
||||
},
|
||||
calculate_group_textColor: function(base) {
|
||||
var groupTextColour = tinycolor(base).lighten(15).toHexString();
|
||||
//if (this.whiteBlackLeastReadable(base) === "#ffffff") { groupTextColour = "#000000"; }
|
||||
return groupTextColour;
|
||||
},
|
||||
calculate_group_backgroundColor: function(base) {
|
||||
var groupBackground = "#ffffff";
|
||||
var theme = "light";
|
||||
if (globalDashboardNode && globalDashboardNode.hasOwnProperty("theme") && globalDashboardNode.theme.hasOwnProperty("name")) {
|
||||
theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
}
|
||||
if (theme === "dark") {
|
||||
groupBackground = "#333333";
|
||||
}
|
||||
else if (theme === "custom") {
|
||||
var whiteOrBlack = this.whiteBlackLeastReadable(base);
|
||||
if (whiteOrBlack === "#000000") { groupBackground = "#333333"; }
|
||||
}
|
||||
return groupBackground;
|
||||
},
|
||||
calculate_group_borderColor: function(base) {
|
||||
var groupBackground = this.calculate_group_backgroundColor(base);
|
||||
return this.leastReadable(groupBackground, ["#ffffff", "#555555"]);
|
||||
},
|
||||
calculate_widget_textColor: function(base) {
|
||||
//most readable against group background
|
||||
var groupBackground = this.calculate_group_backgroundColor(base);
|
||||
return tinycolor.mostReadable(groupBackground, ["#111111", "#eeeeee"]).toHexString();
|
||||
},
|
||||
calculate_widget_backgroundColor: function(base) {
|
||||
//return tinycolor(base).darken(5).toHexString()
|
||||
return tinycolor(base).toHexString();
|
||||
},
|
||||
calculate_widget_borderColor: function(base) {
|
||||
var widgetBorder = "#ffffff";
|
||||
var theme = "light";
|
||||
if (globalDashboardNode && globalDashboardNode.hasOwnProperty("theme") && globalDashboardNode.theme.hasOwnProperty("name")) {
|
||||
theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
}
|
||||
if (theme === "dark") {
|
||||
widgetBorder = "#333333";
|
||||
}
|
||||
else if (theme === "custom") {
|
||||
var whiteOrBlack = this.whiteBlackLeastReadable(base);
|
||||
if (whiteOrBlack === "#000000") { widgetBorder = "#333333"; }
|
||||
}
|
||||
return widgetBorder;
|
||||
},
|
||||
calculate_base_font: function(base) {
|
||||
return baseFontName;
|
||||
}
|
||||
}
|
||||
var sizes = {
|
||||
sx: 48, // width of <1> grid square
|
||||
sy: 48, // height of <1> grid square
|
||||
gx: 6, // gap between groups
|
||||
gy: 6, // gap between groups
|
||||
cx: 6, // gap between components
|
||||
cy: 6, // gap between components
|
||||
px: 0, // padding of group's cards
|
||||
py: 0 // padding of group's cards
|
||||
};
|
||||
|
||||
function ensureDashboardNode(createMissing) {
|
||||
if (globalDashboardNode !== null) {
|
||||
// Check if it has been deleted beneath us
|
||||
var n = RED.nodes.node(globalDashboardNode.id);
|
||||
if (n === null) { globalDashboardNode = null; }
|
||||
}
|
||||
|
||||
// Find the old dashboard node
|
||||
if (globalDashboardNode === null) {
|
||||
var bases = [];
|
||||
RED.nodes.eachConfig(function(n) {
|
||||
if (n.type === 'ui_base') { bases.push(n); }
|
||||
});
|
||||
|
||||
// make sure we only have one ui_base node
|
||||
// at the moment this will just use our existing one - deleting any new base node and theme
|
||||
// at some point we may want to make this an option to select one or the other.
|
||||
while (bases.length > 1) {
|
||||
var n = bases.pop();
|
||||
RED.nodes.remove(n.id);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
|
||||
if (bases.length === 1) { globalDashboardNode = bases[0]; }
|
||||
|
||||
// If there is no dashboard node, ensure we create it after
|
||||
// initialising
|
||||
var noDashboardNode = (globalDashboardNode === null);
|
||||
|
||||
// set up theme state
|
||||
var themeState = {};
|
||||
var baseColor = "#0094CE"
|
||||
for (var i=0; i<baseStyles.length; i++) {
|
||||
themeState[baseStyles[i]] = { default:baseColor, value:baseColor, edited:false };
|
||||
}
|
||||
for (var j = 0; j < configurableStyles.length; j++) {
|
||||
var underscore = configurableStyles[j].split("-").join("_");
|
||||
var colour = colours['calculate_'+underscore](baseColor);
|
||||
themeState[configurableStyles[j]] = {value:colour, edited:false};
|
||||
}
|
||||
themeState["base-font"] = {value:baseFontName};
|
||||
|
||||
var missingFields = (!globalDashboardNode || !globalDashboardNode.theme || !globalDashboardNode.site || !globalDashboardNode.site.sizes );
|
||||
|
||||
if (missingFields && createMissing) {
|
||||
var lightTheme = {
|
||||
default: baseColor,
|
||||
baseColor: baseColor,
|
||||
baseFont: baseFontName,
|
||||
edited: false
|
||||
}
|
||||
var darkTheme = {
|
||||
default: "#097479",
|
||||
baseColor: "#097479",
|
||||
baseFont: baseFontName,
|
||||
edited: false
|
||||
}
|
||||
var customTheme = {
|
||||
name: 'Untitled Theme 1',
|
||||
default: "#4B7930",
|
||||
baseColor: "#4B7930",
|
||||
baseFont: baseFontName
|
||||
}
|
||||
var oldThemeName;
|
||||
if (globalDashboardNode && typeof(globalDashboardNode.theme === 'string')) { oldThemeName = globalDashboardNode.theme; }
|
||||
|
||||
var theme = {
|
||||
name: oldThemeName || "theme-light",
|
||||
lightTheme: lightTheme,
|
||||
darkTheme: darkTheme,
|
||||
customTheme: customTheme,
|
||||
themeState: themeState,
|
||||
angularTheme: aTheme
|
||||
}
|
||||
|
||||
var site_name = c_("site.title");
|
||||
var site_date_format = c_("site.date-format");
|
||||
var site = { name:site_name, hideToolbar:"false", allowSwipe:"false", lockMenu:"false", allowTempTheme:"true", dateFormat:site_date_format, sizes:sizes };
|
||||
if (globalDashboardNode !== null) {
|
||||
if (typeof globalDashboardNode.site !== "undefined") {
|
||||
site = {
|
||||
name: globalDashboardNode.site.name || globalDashboardNode.name,
|
||||
hideToolbar: globalDashboardNode.site.hideToolbar,
|
||||
lockMenu: globalDashboardNode.site.lockMenu,
|
||||
allowSwipe: globalDashboardNode.site.allowSwipe,
|
||||
allowTempTheme: globalDashboardNode.site.allowTempTheme,
|
||||
dateFormat: globalDashboardNode.site.dateFormat,
|
||||
sizes: globalDashboardNode.site.sizes
|
||||
}
|
||||
}
|
||||
if (globalDashboardNode.theme.hasOwnProperty("angularTheme")) {
|
||||
aTheme = globalDashboardNode.theme.angularTheme;
|
||||
}
|
||||
else { globalDashboardNode.theme.angularTheme = aTheme; }
|
||||
}
|
||||
|
||||
if (noDashboardNode) {
|
||||
globalDashboardNode = {
|
||||
id: RED.nodes.id(),
|
||||
_def: RED.nodes.getType("ui_base"),
|
||||
type: "ui_base",
|
||||
site: site,
|
||||
theme: theme,
|
||||
users: []
|
||||
}
|
||||
RED.nodes.add(globalDashboardNode);
|
||||
}
|
||||
else {
|
||||
globalDashboardNode["_def"] = RED.nodes.getType("ui_base");
|
||||
globalDashboardNode.site = site;
|
||||
globalDashboardNode.theme = theme;
|
||||
delete globalDashboardNode.name;
|
||||
}
|
||||
$("#nr-db-field-font").val(baseFontName);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var content = $("<div>").css({"position":"relative","height":"100%"});
|
||||
var mainContent = $("<div>",{class:"nr-db-sb"}).appendTo(content);
|
||||
var form = $('<form class="dialog-form">').appendTo(mainContent);
|
||||
|
||||
// Dashboard Tabs markup
|
||||
var divTab = $('<div class="red-ui-tabs">').appendTo(form);
|
||||
var ulDashboardTabs = $('<ul id="dashboard-tabs-list"></ul>').appendTo(divTab);
|
||||
var layout_label = c_("label.layout");
|
||||
var site_label = c_("label.site");
|
||||
var theme_label = c_("label.theme");
|
||||
var angular_label = c_("label.angular");
|
||||
var liLayoutTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Layout"><span>'+layout_label+'</span></a></li>').appendTo(ulDashboardTabs);
|
||||
var liSiteTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Site" style="width:60px;"><span>'+site_label+'</span></a></li>').appendTo(ulDashboardTabs);
|
||||
var liThemeTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Theme" style="width:80px;"><span>'+theme_label+'</span></a></li>').appendTo(ulDashboardTabs);
|
||||
var liAngularTab = $('<li class="red-ui-tab" style="width:70px;"><a class="red-ui-tab-label" title="Angular" style="width:80px;"><span>'+angular_label+'</span></a></li>').appendTo(ulDashboardTabs);
|
||||
|
||||
// Link out to dashboard
|
||||
$.getJSON('uisettings',function(data) {
|
||||
if (data.hasOwnProperty("path")) { uip = data.path; }
|
||||
var lnk = document.location.host+RED.settings.httpNodeRoot+"/"+uip;
|
||||
var re = new RegExp('\/{1,}','g');
|
||||
lnk = lnk.replace(re,'/');
|
||||
if (!RED.hasOwnProperty("actions")) {
|
||||
RED.keyboard.add("*",/* d */ 68,{ctrl:true, shift:true},function() { window.open(document.location.protocol+"//"+lnk, "nr-dashboard") });
|
||||
}
|
||||
else {
|
||||
RED.keyboard.add("*","ctrl-shift-d","dashboard:show-dashboard");
|
||||
RED.actions.add("dashboard:show-dashboard",function() { window.open(document.location.protocol+"//"+lnk, "nr-dashboard") });
|
||||
}
|
||||
$('<span id="dash-link-button" class="editor-button" style="position:absolute; right:0px;"><i class="fa fa-external-link"></i></span>')
|
||||
.click(function(evt) {
|
||||
window.open(document.location.protocol+"//"+lnk);
|
||||
evt.preventDefault();
|
||||
})
|
||||
.appendTo(ulDashboardTabs);
|
||||
});
|
||||
|
||||
// Dashboard Tab containers
|
||||
var layoutTab = $('<div id="dashboard-layout" style="height:calc(100% - 48px)">').appendTo(form);
|
||||
var siteTab = $('<div id="dashboard-site" style="display:none;">').appendTo(form);
|
||||
var themeTab = $('<div id="dashboard-theme" style="display:none;">').appendTo(form);
|
||||
var angularTab = $('<div id="dashboard-angular" style="display:none;">').appendTo(form);
|
||||
|
||||
ulDashboardTabs.children().first().addClass("active");
|
||||
|
||||
// Tab logic
|
||||
var onTabClick = function() {
|
||||
//Toggle tabs
|
||||
ulDashboardTabs.children().removeClass("active");
|
||||
ulDashboardTabs.children().css({"transition": "width 100ms"});
|
||||
$(this).parent().addClass("active");
|
||||
|
||||
var selectedTab = $(this)[0].title;
|
||||
if (selectedTab === 'Layout') {
|
||||
themeTab.hide();
|
||||
siteTab.hide();
|
||||
angularTab.hide();
|
||||
layoutTab.show();
|
||||
}
|
||||
else if (selectedTab === 'Angular') {
|
||||
themeTab.hide();
|
||||
siteTab.hide();
|
||||
angularTab.show();
|
||||
layoutTab.hide();
|
||||
}
|
||||
else if (selectedTab === 'Theme') {
|
||||
layoutTab.hide();
|
||||
siteTab.hide();
|
||||
angularTab.hide();
|
||||
themeTab.show();
|
||||
if ($("#nr-db-field-theme option:selected").val() === 'theme-custom') { themeSettingsContainer.show(); }
|
||||
else { themeSettingsContainer.hide(); }
|
||||
}
|
||||
else {
|
||||
layoutTab.hide();
|
||||
themeTab.hide();
|
||||
angularTab.hide();
|
||||
siteTab.show();
|
||||
}
|
||||
}
|
||||
|
||||
ulDashboardTabs.find("li.red-ui-tab a").on("click",onTabClick)
|
||||
|
||||
// Site Tab
|
||||
var divTitle = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
|
||||
$('<div>').html('<b>'+c_("label.title")+'</b>').appendTo(divTitle);
|
||||
$('<input type="text" id="nr-db-field-title">').val(site_name).css("width","100%")
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.site.name !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.site.name = $(this).val();
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
})
|
||||
.appendTo(divTitle);
|
||||
|
||||
var divHideToolbar = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
|
||||
$('<div>').html('<b>'+c_("label.options")+'</b>').appendTo(divHideToolbar);
|
||||
$('<select id="nr-db-field-hideToolbar">')
|
||||
.css("width","100%")
|
||||
.append($('<option>', { value:"false", text:c_("title-bar.show"), selected:true }))
|
||||
.append($('<option>', { value:"true", text:c_("title-bar.hide") }))
|
||||
.val("false")
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.site.hideToolbar !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.site.hideToolbar = $(this).val();
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
})
|
||||
.appendTo(divHideToolbar);
|
||||
|
||||
var divLockMenu = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
|
||||
$('<select id="nr-db-field-lockMenu">')
|
||||
.css("width","100%")
|
||||
.append($('<option>', { value:"false", text:c_("lock.clicked"), selected:true }))
|
||||
.append($('<option>', { value:"true", text:c_("lock.locked") }))
|
||||
.val("false")
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.site.lockMenu !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.site.lockMenu = $(this).val();
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
})
|
||||
.appendTo(divLockMenu);
|
||||
|
||||
var divAllowSwipe = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
|
||||
$('<select id="nr-db-field-allowSwipe">')
|
||||
.css("width","100%")
|
||||
.append($('<option>', { value:"false", text:c_("swipe.no-swipe"), selected:true }))
|
||||
.append($('<option>', { value:"true", text:c_("swipe.allow-swipe") }))
|
||||
.val("false")
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.site.allowSwipe !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.site.allowSwipe = $(this).val();
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
})
|
||||
.appendTo(divAllowSwipe);
|
||||
|
||||
var divAllowTempTheme = $('<div>',{class:"form-row compact"}).appendTo(siteTab);
|
||||
$('<select id="nr-db-field-allowTempTheme">')
|
||||
.css("width","100%")
|
||||
.append($('<option>', { value:"true", text:c_("temp.allow-theme"), selected:true }))
|
||||
.append($('<option>', { value:"false", text:c_("temp.no-theme") }))
|
||||
.append($('<option>', { value:"none", text:c_("temp.none") }))
|
||||
.val("true")
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.site.allowTempTheme !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.site.allowTempTheme = $(this).val();
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
if ($('#nr-db-field-allowTempTheme').val() === "none") {
|
||||
ulDashboardTabs.children().eq(2).addClass("hidden");
|
||||
ulDashboardTabs.children().eq(3).removeClass("hidden");
|
||||
}
|
||||
else {
|
||||
ulDashboardTabs.children().eq(2).removeClass("hidden");
|
||||
ulDashboardTabs.children().eq(3).addClass("hidden");
|
||||
}
|
||||
})
|
||||
.appendTo(divAllowTempTheme);
|
||||
|
||||
var site_name = c_("site.title");
|
||||
var site_date_format = c_("site.date-format");
|
||||
var divDateFormat = $('<div>',{class:"form-row"}).appendTo(siteTab);
|
||||
$('<div>').html('<b>'+c_("label.date-format")+'</b>')
|
||||
.css("width","80%")
|
||||
.css("display","inline-block")
|
||||
.appendTo(divDateFormat);
|
||||
$('<div>').html("<a href='https://momentjs.com/docs/#/displaying/format/' target='_new'><i class='fa fa-info-circle' style='color:grey;'></i></a>")
|
||||
.css("display","inline-block")
|
||||
.css("margin-right","6px")
|
||||
.css("float","right")
|
||||
.appendTo(divDateFormat);
|
||||
$('<input type="text" id="nr-db-field-dateFormat">').val(site_date_format).css("width","100%")
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.site.dateFormat !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.site.dateFormat = $(this).val();
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
})
|
||||
.appendTo(divDateFormat);
|
||||
|
||||
var divSetSizes = $('<div>',{class:"form-row"}).appendTo(siteTab);
|
||||
$('<span style="width:45%; display:inline-block">').html('<b>'+c_("label.sizes")+'</b>').appendTo(divSetSizes);
|
||||
$('<span style="width:25%; display:inline-block; font-size:smaller">').text(c_("label.horizontal")).appendTo(divSetSizes);
|
||||
$('<span style="width:20%; display:inline-block; font-size:smaller">').text(c_("label.vertical")).appendTo(divSetSizes);
|
||||
$('<i id="sizes-reset" class="fa fa-undo nr-db-resetIcon"></i>')
|
||||
.css({opacity:1.0})
|
||||
.click(function(e) {
|
||||
$("#nr-db-field-sx").val(sizes.sx); globalDashboardNode.site.sizes.sx = sizes.sx;
|
||||
$("#nr-db-field-sy").val(sizes.sy); globalDashboardNode.site.sizes.sy = sizes.sy;
|
||||
$("#nr-db-field-px").val(sizes.px); globalDashboardNode.site.sizes.px = sizes.px;
|
||||
$("#nr-db-field-py").val(sizes.py); globalDashboardNode.site.sizes.py = sizes.py;
|
||||
$("#nr-db-field-gx").val(sizes.gx); globalDashboardNode.site.sizes.gx = sizes.gx;
|
||||
$("#nr-db-field-gy").val(sizes.gy); globalDashboardNode.site.sizes.gy = sizes.gy;
|
||||
$("#nr-db-field-cx").val(sizes.cx); globalDashboardNode.site.sizes.cx = sizes.cx;
|
||||
$("#nr-db-field-cy").val(sizes.cy); globalDashboardNode.site.sizes.cy = sizes.cy;
|
||||
RED.nodes.dirty(true);
|
||||
})
|
||||
.appendTo(divSetSizes);
|
||||
|
||||
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.widget-size")).appendTo(divSetSizes);
|
||||
$('<input type="number" name="sx" min="24" id="nr-db-field-sx">').val(48).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.sx=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
|
||||
$('<input type="number" name="sy" min="24" id="nr-db-field-sy">').val(48).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.sy=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
|
||||
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.widget-spacing")).appendTo(divSetSizes);
|
||||
$('<input type="number" name="cx" min="0" id="nr-db-field-cx">').val(6).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.cx=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
|
||||
$('<input type="number" name="cy" min="0" id="nr-db-field-cy">').val(6).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.cy=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
|
||||
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.group-padding")).appendTo(divSetSizes);
|
||||
$('<input type="number" name="px" min="0" id="nr-db-field-px">').val(0).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.px=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
|
||||
$('<input type="number" name="py" min="0" id="nr-db-field-py">').val(0).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.py=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
|
||||
$('<br/><span style="width:45%; display:inline-block">').text(c_("label.group-spacing")).appendTo(divSetSizes);
|
||||
$('<input type="number" name="gx" min="0" id="nr-db-field-gx">').val(6).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.gx=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
$('<span style="width:5%; display:inline-block">').text(' ').appendTo(divSetSizes);
|
||||
$('<input type="number" name="gy" min="0" id="nr-db-field-gy">').val(6).css("width","20%")
|
||||
.on("change", function() { ensureDashboardNode(true); globalDashboardNode.site.sizes.gy=Number($(this).val()); RED.nodes.dirty(true); } )
|
||||
.appendTo(divSetSizes);
|
||||
|
||||
|
||||
// Angular Theme Tab
|
||||
var changed = function() {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.theme.angularTheme = aTheme;
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
|
||||
var angColorList = ["red", "pink", "purple", "deep-purple", "indigo", "blue", "light-blue", "cyan", "teal", "green", "light-green", "lime", "yellow", "amber", "orange", "deep-orange", "brown", "grey", "blue-grey"];
|
||||
var angColors = "";
|
||||
angColorList.forEach(function(c) { angColors += '<option value="' + c + '">' + c + '</option>'; });
|
||||
|
||||
var divPrimStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
|
||||
$('<span style="width:45%; display:inline-block">')
|
||||
.html('<b>'+c_("style.primary")+'</b>')
|
||||
.appendTo(divPrimStyle);
|
||||
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
|
||||
.css({opacity:1.0})
|
||||
.click(function(e) {
|
||||
$("#nr-db-field-angPrimary").val("indigo");
|
||||
globalDashboardNode.theme.angularTheme.primary = "indigo";
|
||||
RED.nodes.dirty(true);
|
||||
})
|
||||
.appendTo(divPrimStyle);
|
||||
$('<select id="nr-db-field-angPrimary">'+angColors+'</select>')
|
||||
.css("width","100%")
|
||||
.val(aTheme.primary)
|
||||
.on("change", function() { aTheme.primary = $(this).val(); changed(); })
|
||||
.appendTo(divPrimStyle);
|
||||
|
||||
var divAccStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
|
||||
$('<span style="width:45%; display:inline-block">')
|
||||
.html('<b>'+c_("style.accents")+'</b>')
|
||||
.appendTo(divAccStyle);
|
||||
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
|
||||
.css({opacity:1.0})
|
||||
.click(function(e) {
|
||||
$("#nr-db-field-angAccents").val("blue");
|
||||
globalDashboardNode.theme.angularTheme.accents = "blue";
|
||||
RED.nodes.dirty(true);
|
||||
})
|
||||
.appendTo(divAccStyle);
|
||||
$('<select id="nr-db-field-angAccents">'+angColors+'</select>')
|
||||
.css("width","100%")
|
||||
.val(aTheme.accents)
|
||||
.on("change", function() { aTheme.accents = $(this).val(); changed(); })
|
||||
.appendTo(divAccStyle);
|
||||
|
||||
var divWarnStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
|
||||
$('<span style="width:45%; display:inline-block">')
|
||||
.html('<b>'+c_("style.warnings")+'</b>')
|
||||
.appendTo(divWarnStyle);
|
||||
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
|
||||
.css({opacity:1.0})
|
||||
.click(function(e) {
|
||||
$("#nr-db-field-angWarn").val("red");
|
||||
globalDashboardNode.theme.angularTheme.warn = "red";
|
||||
RED.nodes.dirty(true);
|
||||
})
|
||||
.appendTo(divWarnStyle);
|
||||
$('<select id="nr-db-field-angWarn">'+angColors+'</select>')
|
||||
.css("width","100%")
|
||||
.val(aTheme.warn)
|
||||
.on("change", function() { aTheme.warn = $(this).val(); changed(); })
|
||||
.appendTo(divWarnStyle);
|
||||
|
||||
var divBackStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
|
||||
$('<span style="width:45%; display:inline-block">')
|
||||
.html('<b>'+c_("style.background")+'</b>')
|
||||
.appendTo(divBackStyle);
|
||||
$('<i id="ang-reset" class="fa fa-undo nr-db-resetIcon"></i>')
|
||||
.css({opacity:1.0})
|
||||
.click(function(e) {
|
||||
$("#nr-db-field-angBackground").val("grey");
|
||||
globalDashboardNode.theme.angularTheme.background = "grey";
|
||||
RED.nodes.dirty(true);
|
||||
})
|
||||
.appendTo(divBackStyle);
|
||||
$('<select id="nr-db-field-angBackground">'+angColors+'</select>')
|
||||
.css("width","100%")
|
||||
.val(aTheme.background)
|
||||
.on("change", function() { aTheme.background = $(this).val(); changed(); })
|
||||
.appendTo(divBackStyle);
|
||||
|
||||
var divPalStyle = $('<div>',{class:"form-row"}).appendTo(angularTab);
|
||||
$('<span style="width:45%; display:inline-block">')
|
||||
.html('<b>'+c_("style.palette")+'</b>')
|
||||
.appendTo(divPalStyle);
|
||||
var lightdark = '<option value="light">' +c_("style.light")+ '</option>';
|
||||
lightdark += '<option value="dark">' +c_("style.dark")+ '</option>';
|
||||
$('<select id="nr-db-field-angLook">'+lightdark+'</select>')
|
||||
.css("width","100%")
|
||||
.val(aTheme.palette || "light")
|
||||
.on("change", function() { aTheme.palette = $(this).val(); changed(); })
|
||||
.appendTo(divPalStyle);
|
||||
|
||||
// Theme Tab
|
||||
// For all customisable styles, generate and apply the css
|
||||
var generateColours = function(base) {
|
||||
var theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
if (!globalDashboardNode.theme.themeState.hasOwnProperty["base-font"]) {
|
||||
if (globalDashboardNode.theme[theme+"Theme"].baseFont === "Helvetica Neue") {
|
||||
globalDashboardNode.theme[theme+"Theme"].baseFont = baseFontName;
|
||||
}
|
||||
globalDashboardNode.theme.themeState["base-font"] = {value:globalDashboardNode.theme[theme+"Theme"].baseFont};
|
||||
$("#nr-db-field-font").val(globalDashboardNode.theme[theme+"Theme"].baseFont);
|
||||
}
|
||||
for (var i=0; i<configurableStyles.length; i++) {
|
||||
var styleID = configurableStyles[i];
|
||||
var underscore = styleID.split("-").join("_");
|
||||
if (!globalDashboardNode.theme.themeState.hasOwnProperty(styleID)) {
|
||||
globalDashboardNode.theme.themeState[styleID] = {value:"#fff",edited:false};
|
||||
}
|
||||
if (!globalDashboardNode.theme.themeState[styleID].edited || globalDashboardNode.theme[theme+'Theme'].reset) {
|
||||
var colour = colours['calculate_'+underscore](base);
|
||||
globalDashboardNode.theme.themeState[styleID].value = colour;
|
||||
}
|
||||
setColourPickerColour(styleID, globalDashboardNode.theme.themeState[styleID].value, globalDashboardNode.theme.themeState[styleID].edited);
|
||||
}
|
||||
globalDashboardNode.theme[theme+'Theme'].reset = false;
|
||||
}
|
||||
|
||||
var divThemeStyle = $('<div>',{class:"form-row"}).appendTo(themeTab);
|
||||
$('<label class="nr-db-theme-label">').text(c_("theme.style")).appendTo(divThemeStyle);
|
||||
var themeSelection = $('<select id="nr-db-field-theme">'+
|
||||
'<option value="theme-light">'+c_("style.light")+'</option>'+
|
||||
'<option value="theme-dark">'+c_("style.dark")+'</option>'+
|
||||
'<option value="theme-custom">'+c_("style.custom")+'</option>'+
|
||||
'</select>')
|
||||
.css("width","100%")
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.theme.name !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
var theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
var baseColour = globalDashboardNode.theme[theme+'Theme'].baseColor;
|
||||
var baseFont = globalDashboardNode.theme[theme+'Theme'].baseFont;
|
||||
globalDashboardNode.theme.name = $(this).val();
|
||||
theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
if (theme !== "custom") {
|
||||
baseColour = globalDashboardNode.theme[theme+'Theme'].default;
|
||||
}
|
||||
else { baseColour = globalDashboardNode.theme[theme+'Theme'].baseColor; }
|
||||
setColourPickerColour("base-color", baseColour);
|
||||
globalDashboardNode.theme.themeState['base-color'].value = baseColour;
|
||||
globalDashboardNode.theme.themeState['base-color'].default = baseColour;
|
||||
globalDashboardNode.theme.themeState['base-font'] = {value:baseFont};
|
||||
$("#nr-db-field-font").val(baseFont);
|
||||
globalDashboardNode.theme[theme+'Theme'].reset = true;
|
||||
//generate colours for all colour settings from base colour
|
||||
generateColours(baseColour);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
$('#base-color-reset').remove();
|
||||
if ($(this).val() === 'theme-custom') {
|
||||
$("#custom-theme-library-container").show(); //TODO undo this at some point
|
||||
$("#custom-theme-settings").show();
|
||||
//addResetButton('base-color', baseSettingsUl.children());
|
||||
}
|
||||
else {
|
||||
$("#custom-theme-library-container").hide();
|
||||
$("#custom-theme-settings").hide();
|
||||
addLightAndDarkResetButton('base-color', baseSettingsUl.children().first());
|
||||
}
|
||||
})
|
||||
.appendTo(divThemeStyle);
|
||||
|
||||
var customThemeLibraryContainer = $('<div id="custom-theme-library-container">').appendTo(themeTab);
|
||||
$('<label class="nr-db-theme-label">').text(c_("theme.custom-profile")).appendTo(customThemeLibraryContainer);
|
||||
$('<input type="text" id="ui-sidebar-name" style="vertical-align:top;" placeholder="profile name (not blank)">')
|
||||
.val(c_("theme.custom-profile-name"))
|
||||
.on("change", function() {
|
||||
if (!globalDashboardNode || globalDashboardNode.theme.customTheme.name !== $(this).val()) {
|
||||
ensureDashboardNode(true);
|
||||
globalDashboardNode.theme.customTheme.name = $(this).val();
|
||||
if (editor) {
|
||||
editor.setValue(JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site}),1);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
})
|
||||
.keyup(function() {
|
||||
if ($(this).val().length === 0) {
|
||||
$("#custom-theme-library-container div").css("pointer-events","none");
|
||||
}
|
||||
else { $("#custom-theme-library-container div").css("pointer-events","inherit"); }
|
||||
})
|
||||
.appendTo(customThemeLibraryContainer);
|
||||
$('<input type="hidden" id="nr-db-field-format">').appendTo(customThemeLibraryContainer);
|
||||
$('<div style="display:none;" class="node-text-editor" id="nr-db-field-format-editor"></div>').appendTo(customThemeLibraryContainer);
|
||||
|
||||
var baseThemeSettingsContainer = $('<div id="base-theme-settings">').appendTo(themeTab);
|
||||
|
||||
var baseSettings = $('<div>',{class:"form-row"}).appendTo(baseThemeSettingsContainer);
|
||||
$('<label class="nr-db-theme-label">').text(c_("theme.base-settings")).appendTo(baseSettings);
|
||||
var baseSettingsUl = $('<ul id="base-settings-ul" class="red-ui-dashboard-theme-styles"></ul>').appendTo(baseSettings);
|
||||
|
||||
var baseColourItem = $('<li class="red-ui-dashboard-theme-item"><span>'+c_("base.colour")+'</span></li>').appendTo(baseSettingsUl);
|
||||
var spanColorContainer = $('<span class="nr-db-color-pick-container"></span>').appendTo(baseColourItem);
|
||||
|
||||
$('<input id="base-color" class="nr-db-field-themeColor" type="color" value="#ffffff"/>')
|
||||
.on("change", function() {
|
||||
ensureDashboardNode(true);
|
||||
var value = $(this).val();
|
||||
var lightThemeMatch = globalDashboardNode.theme.lightTheme.baseColor === value;
|
||||
var darkThemeMatch = globalDashboardNode.theme.darkTheme.baseColor === value;
|
||||
var customThemeMatch = globalDashboardNode.theme.customTheme.baseColor === value;
|
||||
if (!globalDashboardNode || !lightThemeMatch || !darkThemeMatch || !customThemeMatch) {
|
||||
var theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
globalDashboardNode.theme[theme+'Theme'].baseColor = value;
|
||||
if (globalDashboardNode.theme.name === 'theme-light' || globalDashboardNode.theme.name === 'theme-dark') {
|
||||
//for light and dark themes, reset the colours
|
||||
globalDashboardNode.theme[theme+'Theme'].reset = true;
|
||||
}
|
||||
generateColours(value);
|
||||
editor.setValue(JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site}),1);
|
||||
colourPickerChangeHandler($(this).attr('id'), value);
|
||||
}
|
||||
})
|
||||
.appendTo(spanColorContainer);
|
||||
|
||||
var baseFontItem = $('<li class="red-ui-dashboard-theme-item"><span>'+c_("base.font")+'</span></li>').appendTo(baseSettingsUl);
|
||||
var fontSelector = $('<select id="nr-db-field-font">'+
|
||||
'<option value="'+baseFontName+'" style="font-family:'+baseFontName+'">'+c_("font.system")+'</option>'+
|
||||
'<option value="Arial,Arial,Helvetica,sans-serif" style="font-family:Arial,Arial,Helvetica,sans-serif">Arial</option>'+
|
||||
'<option value="Arial Black,Arial Black,Gadget,sans-serif" style="font-family:Arial Black,Arial Black,Gadget,sans-serif">Arial Black</option>'+
|
||||
'<option value="Arial Narrow,Nimbus Sans L,sans-serif" style="font-family:Arial Narrow,Nimbus Sans L,sans-serif">Arial Narrow</option>'+
|
||||
'<option value="Century Gothic,CenturyGothic,AppleGothic,sans-serif" style="font-family:Century Gothic,CenturyGothic,AppleGothic,sans-serif">Century Gothic</option>'+
|
||||
'<option value="Copperplate,Copperplate Gothic Light,fantasy" style="font-family:Copperplate,Copperplate Gothic Light,fantasy;">Copperplate</option>'+
|
||||
'<option value="Courier,monospace" style="font-family:Courier,monospace;">Courier</option>'+
|
||||
'<option value="Georgia,Georgia,serif" style="font-family:Georgia,Georgia,serif">Georgia</option>'+
|
||||
'<option value="Gill Sans,Geneva,sans-serif" style="font-family:Gill Sans,Geneva,sans-serif;">Gill Sans</option>'+
|
||||
//'<option value="Helvetica Neue,Helvetica,sans-serif" style="font-family:Helvetica Neue,Helvetica,sans-serif">Helvetica Neue</option>'+
|
||||
'<option value="Impact,Impact,Charcoal,sans-serif" style="font-family:Impact,Impact,Charcoal,sans-serif">Impact</option>'+
|
||||
'<option value="Lucida Sans Typewriter,Lucida Console,Monaco,monospace" style="font-family:Lucida Console,Monaco,monospace">Lucida Console</option>'+
|
||||
'<option value="Lucida Sans Unicode,Lucida Grande,sans-serif" style="font-family:Lucida Sans Unicode,Lucida Grande,sans-serif">Lucida Sans</option>'+
|
||||
'<option value="Palatino Linotype,Palatino,Book Antiqua,serif" style="font-family:Palatino Linotype,Palatino,Book Antiqua,serif">Palatino Linotype</option>'+
|
||||
'<option value="Tahoma,Geneva,sans-serif" style="font-family:Tahoma,Geneva,sans-serif">Tahoma</optionstyle="font-family:>'+
|
||||
'<option value="Times New Roman,Times,serif" style="font-family:Times New Roman,Times,serif">Times New Roman</option>'+
|
||||
'<option value="Trebuchet MS,Helvetica,sans-serif" style="font-family:Trebuchet MS,Helvetica,sans-serif">Trebuchet MS</option>'+
|
||||
'<option value="Verdana,Verdana,Geneva,sans-serif" style="font-family:Verdana,Verdana,Geneva,sans-serif">Verdana</option>'+
|
||||
'</select>')
|
||||
.on("change", function() {
|
||||
ensureDashboardNode(true);
|
||||
var theme = globalDashboardNode.theme.name.split('-')[1];
|
||||
globalDashboardNode.theme[theme+'Theme'].baseFont = $(this).val();
|
||||
globalDashboardNode.theme.themeState['base-font'] = {value:$(this).val()};
|
||||
RED.nodes.dirty(true);
|
||||
})
|
||||
.appendTo(baseFontItem);
|
||||
|
||||
var themeSettingsContainer = $('<div id="custom-theme-settings">').appendTo(themeTab);
|
||||
|
||||
// Markup
|
||||
// Page styles
|
||||
var divPageStyle = $('<div>',{class:"form-row"}).appendTo(themeSettingsContainer);
|
||||
$('<label class="nr-db-theme-label">').text(c_("theme.page-settings")).appendTo(divPageStyle);
|
||||
var pageStyles = $('<ul class="red-ui-dashboard-theme-styles"></ul>').appendTo(themeSettingsContainer);
|
||||
addCustomisableStyle('page-titlebar-backgroundColor', c_("theme.page.title"), pageStyles);
|
||||
addCustomisableStyle('page-backgroundColor', c_("theme.page.page"), pageStyles);
|
||||
addCustomisableStyle('page-sidebar-backgroundColor', c_("theme.page.side"), pageStyles);
|
||||
|
||||
// Group styles
|
||||
var divGroupStyle = $('<div>',{class:"form-row"}).appendTo(themeSettingsContainer);
|
||||
$('<label class="nr-db-theme-label">').text(c_("theme.group-settings")).appendTo(divGroupStyle);
|
||||
var groupStyles = $('<ul class="red-ui-dashboard-theme-styles"></ul>').appendTo(themeSettingsContainer);
|
||||
addCustomisableStyle('group-textColor', c_("theme.group.text"), groupStyles);
|
||||
addCustomisableStyle('group-borderColor', c_("theme.group.border"), groupStyles);
|
||||
addCustomisableStyle('group-backgroundColor', c_("theme.group.background"), groupStyles);
|
||||
|
||||
// Widget styles
|
||||
var divWidgetStyle = $('<div>',{class:"form-row"}).appendTo(themeSettingsContainer);
|
||||
$('<label class="nr-db-theme-label">').text(c_("theme.widget-settings")).appendTo(divWidgetStyle);
|
||||
var widgetStyles = $('<ul class="red-ui-dashboard-theme-styles"></ul>').appendTo(themeSettingsContainer);
|
||||
addCustomisableStyle('widget-textColor', c_("theme.widget.text"), widgetStyles);
|
||||
addCustomisableStyle('widget-backgroundColor', c_("theme.widget.colour"), widgetStyles);
|
||||
addCustomisableStyle('widget-borderColor', c_("theme.widget.background"), widgetStyles);
|
||||
|
||||
function addCustomisableStyle(id, name, parentUl) {
|
||||
var styleLi = $('<li class="red-ui-dashboard-theme-item"><span>'+name+'</span></li>').appendTo(parentUl);
|
||||
var spanColorContainer = $('<span class="nr-db-color-pick-container"></span>').appendTo(styleLi);
|
||||
$('<input id="'+id+'" class="nr-db-field-themeColor" type="color" value="#ffffff"/>')
|
||||
.on("change", function() {
|
||||
colourPickerChangeHandler($(this).attr('id'), $(this).val());
|
||||
})
|
||||
.appendTo(spanColorContainer);
|
||||
addResetButton(id, styleLi);
|
||||
}
|
||||
|
||||
function colourPickerChangeHandler(id, value) {
|
||||
$("#"+id).css("background-color", value);
|
||||
$("#"+id+"-reset").css({opacity:1});
|
||||
globalDashboardNode.theme.themeState[id].edited = true;
|
||||
globalDashboardNode.theme.themeState[id].value = value;
|
||||
if (editor) {
|
||||
editor.setValue(JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site}),1);
|
||||
}
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
|
||||
function addResetButton(id, parent) {
|
||||
var resetToDefault = $('<i id="'+id+'-reset" class="fa fa-undo nr-db-resetIcon"></i>')
|
||||
.css({opacity:0.2})
|
||||
.click(function(e) { resetClick(e); })
|
||||
.appendTo(parent);
|
||||
}
|
||||
|
||||
function addLightAndDarkResetButton(id, parent) {
|
||||
if ($("#" + id + "-reset").length === 0) {
|
||||
var resetToDefault = $('<i id="'+id+'-reset" class="fa fa-undo nr-db-resetIcon"></i>')
|
||||
.css({opacity:1})
|
||||
.click(function(e) { lightAndDarkResetClick(e); })
|
||||
.appendTo(parent);
|
||||
globalDashboardNode.theme[globalDashboardNode.theme.name.split('-')[1] + 'Theme'].edited = true;
|
||||
}
|
||||
}
|
||||
|
||||
function lightAndDarkResetClick(e) {
|
||||
var elementID = e.target.id.split('-reset')[0];
|
||||
var key = globalDashboardNode.theme.name.split('-')[1] + 'Theme';
|
||||
//sanity check - light and dark only allow base-color-reset
|
||||
if (elementID === 'base-color') { // && globalDashboardNode.theme[key].edited) {
|
||||
var defaultColor = globalDashboardNode.theme[key].default;
|
||||
globalDashboardNode.theme[key].reset = true;
|
||||
generateColours(defaultColor);
|
||||
setColourPickerColour(elementID, defaultColor);
|
||||
$("#"+elementID+"-reset").css({opacity:0.2});
|
||||
globalDashboardNode.theme.themeState[elementID].value = defaultColor;
|
||||
globalDashboardNode.theme[key].baseColor = defaultColor;
|
||||
globalDashboardNode.theme[key].edited = false;
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
function resetClick(e) {
|
||||
//take off -reset
|
||||
var elementID = e.target.id.split('-reset')[0];
|
||||
if (globalDashboardNode.theme.themeState[elementID].edited) {
|
||||
var defaultColor = globalDashboardNode.theme.themeState['base-color'].value;
|
||||
var colour;
|
||||
//set colour
|
||||
if (elementID === 'base-color') {
|
||||
colour = defaultColor;
|
||||
generateColours(colour);
|
||||
}
|
||||
else {
|
||||
var underscore = elementID.split('-').join('_');
|
||||
colour = colours['calculate_'+underscore](defaultColor);
|
||||
}
|
||||
setColourPickerColour(elementID, colour);
|
||||
$("#"+elementID+"-reset").css({opacity:0.2});
|
||||
globalDashboardNode.theme.themeState[elementID].edited = false;
|
||||
globalDashboardNode.theme.themeState[elementID].value = colour;
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
function setColourPickerColour(id, val, ed) {
|
||||
$("#"+id).val(val);
|
||||
$("#"+id).css("background-color", val);
|
||||
//call mostReadableGreyWhite to set text colour
|
||||
var textColor = colours.whiteGreyMostReadable(val);
|
||||
$("#"+id).css("color", textColor);
|
||||
if (ed === true) { $("#"+id+"-reset").css({opacity:1}); }
|
||||
else { $("#"+id+"-reset").css({opacity:0.2}); }
|
||||
}
|
||||
|
||||
//Layout Tab
|
||||
var divTabs = $('<div>',{class:"form-row",style:"position:relative"}).appendTo(layoutTab);
|
||||
$('<label>').html('<b>'+c_("layout.tab-and-link")+'</b>').appendTo(divTabs);
|
||||
|
||||
var buttonGroup = $('<div>',{class:"nr-db-sb-list-button-group"}).appendTo(divTabs);
|
||||
|
||||
//Toggle expand buttons
|
||||
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-angle-double-up"></i></a>')
|
||||
.click(function(evt) {
|
||||
tabContainer.find(".nr-db-sb-group-list-container").slideUp().addClass('nr-db-sb-collapsed');
|
||||
tabContainer.find(".nr-db-sb-tab-list-header>.nr-db-sb-list-chevron").css({"transform":"rotate(-90deg)"});
|
||||
evt.preventDefault();
|
||||
})
|
||||
.appendTo(buttonGroup);
|
||||
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-angle-double-down"></i></a>')
|
||||
.click(function(evt) {
|
||||
tabContainer.find(".nr-db-sb-group-list-container").slideDown().removeClass('nr-db-sb-collapsed');
|
||||
tabContainer.find(".nr-db-sb-tab-list-header>.nr-db-sb-list-chevron").css({"transform":""});
|
||||
evt.preventDefault();
|
||||
})
|
||||
.appendTo(buttonGroup);
|
||||
|
||||
//Add item button
|
||||
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-plus"></i> '+c_("layout.tab")+'</a>')
|
||||
.click(function(evt) {
|
||||
tabContainer.editableList('addItem',{type: 'ui_tab'});
|
||||
evt.preventDefault();
|
||||
})
|
||||
.appendTo(buttonGroup);
|
||||
$('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-plus"></i> '+c_("layout.link")+'</a>')
|
||||
.click(function(evt) {
|
||||
tabContainer.editableList('addItem',{type: 'ui_link'});
|
||||
evt.preventDefault();
|
||||
})
|
||||
.appendTo(buttonGroup);
|
||||
|
||||
var tabLists = {};
|
||||
var groupLists = {};
|
||||
|
||||
// toggle slide tab group content
|
||||
var titleToggle = function (id,content,chevron) {
|
||||
return function(evt) {
|
||||
if (content.is(":visible")) {
|
||||
content.slideUp();
|
||||
chevron.css({"transform":"rotate(-90deg)"});
|
||||
content.addClass('nr-db-sb-collapsed');
|
||||
listStates[id] = false;
|
||||
}
|
||||
else {
|
||||
content.slideDown();
|
||||
chevron.css({"transform":""});
|
||||
content.removeClass('nr-db-sb-collapsed');
|
||||
listStates[id] = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var addTabOrLinkItem = function(container,i,item) {
|
||||
// create node if needed
|
||||
if (!item.node) {
|
||||
var defaultItem = {
|
||||
'ui_tab': {
|
||||
_def: RED.nodes.getType('ui_tab'),
|
||||
type: 'ui_tab',
|
||||
users: [],
|
||||
icon: 'dashboard',
|
||||
name: 'Tab'
|
||||
},
|
||||
'ui_link': {
|
||||
_def: RED.nodes.getType('ui_link'),
|
||||
type: 'ui_link',
|
||||
users: [],
|
||||
icon: 'open_in_browser',
|
||||
name: 'Link',
|
||||
target: 'newtab'
|
||||
}
|
||||
}
|
||||
item.node = defaultItem[item.type]
|
||||
item.node.id = RED.nodes.id()
|
||||
item.node.order = i+1
|
||||
item.node.name += ' '+item.node.order
|
||||
listElements[item.node.id] = container;
|
||||
if (item.type === 'ui_tab') {
|
||||
item.groups = [];
|
||||
}
|
||||
RED.nodes.add(item.node);
|
||||
RED.history.push({
|
||||
t:'add',
|
||||
nodes:[item.node.id],
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
else if (item.type === undefined) {
|
||||
item.type = item.node.type
|
||||
}
|
||||
|
||||
listElements[item.node.id] = container;
|
||||
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
|
||||
RED.nodes.updateConfigNodeUsers(item.node);
|
||||
}
|
||||
|
||||
// title
|
||||
var titleRow = $('<div>',{class:"nr-db-sb-list-header nr-db-sb-tab-list-header"}).appendTo(container);
|
||||
switch (item.type) {
|
||||
case 'ui_tab': {
|
||||
container.addClass("nr-db-sb-tab-list-item");
|
||||
$('<i class="nr-db-sb-list-handle nr-db-sb-tab-list-handle fa fa-bars"></i>').appendTo(titleRow);
|
||||
var chevron = $('<i class="fa fa-angle-down nr-db-sb-list-chevron">',{style:"width:10px;"}).appendTo(titleRow);
|
||||
var tabicon = "fa-object-group";
|
||||
//var tabicon = item.node.disabled ? "fa-window-close-o" : item.node.hidden ? "fa-eye-slash" : "fa-object-group";
|
||||
$('<i>',{class:"nr-db-sb-icon nr-db-sb-tab-icon fa "+tabicon}).appendTo(titleRow);
|
||||
var tabhide = item.node.hidden ? " nr-db-sb-title-hidden" : "";
|
||||
var tabable = item.node.disabled ? " nr-db-sb-title-disabled" : "";
|
||||
$('<span>',{class:"nr-db-sb-title"+tabhide+tabable}).text(item.node.name||"").appendTo(titleRow);
|
||||
break;
|
||||
}
|
||||
case 'ui_link': {
|
||||
$('<i class="nr-db-sb-list-handle fa fa-bars"></i>').appendTo(titleRow);
|
||||
var title = $('<div class="nr-db-sb-link">').appendTo(titleRow);
|
||||
var nameContainer = $('<div class="nr-db-sb-link-name-container">').appendTo(title);
|
||||
$('<i class="fa fa-external-link"></i>').appendTo(nameContainer);
|
||||
$('<span class="nr-db-sb-link-name">').text(item.node.name||"untitled").appendTo(nameContainer);
|
||||
$('<div class="nr-db-sb-link-url">').text(item.node.link||"http://").appendTo(title);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// buttons
|
||||
var buttonGroup = $('<div>',{class:"nr-db-sb-list-header-button-group"}).appendTo(titleRow);
|
||||
if (item.type === 'ui_tab') {
|
||||
var addGroupButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-plus"></i> '+c_("layout.group")+'</a>').appendTo(buttonGroup);
|
||||
}
|
||||
var editButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.edit")+'</a>').appendTo(buttonGroup);
|
||||
editButton.on('click',function(evt) {
|
||||
RED.editor.editConfig("", item.type, item.node.id);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
});
|
||||
|
||||
// Dashboard layout tool
|
||||
if (item.type === 'ui_tab') {
|
||||
var layoutButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.layout")+'</a>').appendTo(buttonGroup);
|
||||
layoutButton.on('click',function(evt) {
|
||||
var editTabName = item.node.name ? item.node.name : item.node.id;
|
||||
var trayOptions = {
|
||||
title: c_("layout.layout-editor") + " : " + editTabName,
|
||||
width: Infinity,
|
||||
buttons: [
|
||||
{
|
||||
id: "node-dialog-cancel",
|
||||
text: RED._("common.label.cancel"),
|
||||
click: function() {
|
||||
// clean editor
|
||||
RED.tray.close();
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "node-dialog-ok",
|
||||
text: RED._("common.label.done"),
|
||||
class: "primary",
|
||||
click: function() {
|
||||
// Save data after editing
|
||||
saveGridDatas();
|
||||
RED.tray.close();
|
||||
}
|
||||
}
|
||||
],
|
||||
resize: function(dimensions) {
|
||||
//
|
||||
},
|
||||
open: function(tray) {
|
||||
// Get widget of specified tab from node information
|
||||
tabDatas = getTabDataFromNodes(item.node.id);
|
||||
// The width that can be handled by Layout is up to MAX_GROUP_WIDTH
|
||||
// Groups exceeding the maximum width are not supported.
|
||||
var tmpGroups = tabDatas.groups;
|
||||
tmpGroups.sort(compareOrder);
|
||||
var groups = [];
|
||||
for (var cnt = 0; cnt < tmpGroups.length; cnt++) {
|
||||
if (tmpGroups[cnt].width <= MAX_GROUP_WIDTH) {
|
||||
groups.push(tmpGroups[cnt]);
|
||||
}
|
||||
}
|
||||
tabDatas.groups = groups;
|
||||
|
||||
var editor = $('<div></div>',{addClass: 'nr-dashboard-layout-container-fluid'});
|
||||
var row = $('<div></div>',{addClass: 'nr-dashboard-layout-row'});
|
||||
var span_num = Math.floor(12 / groups.length); // bootstrap grid 12 splits
|
||||
span_num = span_num < 2 ? 2 : span_num; // max 6 groups per row
|
||||
for (var cnt = 0; cnt < groups.length; cnt++) {
|
||||
if (cnt !=0 && (cnt % 6) == 0) {
|
||||
editor.append(row);
|
||||
editor.append('<div><br></div>');
|
||||
row = $('<div></div>',{addClass: 'nr-dashboard-layout-row'});
|
||||
}
|
||||
var span = $('<div></div>',{addClass: 'nr-dashboard-layout-span' + span_num});
|
||||
var groupName = groups[cnt].name ? groups[cnt].name : groups[cnt].id;
|
||||
var title = $('<div></div>', {
|
||||
style: "margin-top:2px; margin-bottom:2px;"
|
||||
});
|
||||
var title_group = $('<div></div>', {
|
||||
title: groupName,
|
||||
style: "margin-left:4px; margin-right:8px; overflow:hidden;"
|
||||
}).appendTo(title);
|
||||
$("<b/>").text(groupName).appendTo(title_group);
|
||||
var title_width = $('<div></div>', {
|
||||
style: "text-align:right; margin-right:8px;"
|
||||
}).appendTo(title);
|
||||
$("<span/>", {
|
||||
style: "margin_right: 8px;"
|
||||
}).text(c_("layout.width")+': ').appendTo(title_width);
|
||||
var changeWidth = $('<input>', {
|
||||
id: 'change-width' + cnt,
|
||||
value: groups[cnt].width,
|
||||
style: 'width:30px;',
|
||||
readonly: true
|
||||
});
|
||||
title_width.append(changeWidth);
|
||||
|
||||
title.css('white-space','nowrap');
|
||||
title.css('overflow','hidden');
|
||||
var gridstack = $('<div></div>', {
|
||||
id: 'grid'+cnt,
|
||||
addClass: 'grid-stack'
|
||||
});
|
||||
span.append(title);
|
||||
span.append(gridstack);
|
||||
row.append(span);
|
||||
}
|
||||
if (groups.length != 0) {
|
||||
editor.append(row);
|
||||
}
|
||||
|
||||
// Show layout editor in tray
|
||||
var trayBody = tray.find('.red-ui-tray-body, .editor-tray-body');
|
||||
trayBody.css('overflow','auto');
|
||||
trayBody.append(editor);
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Gridstack.js option
|
||||
////////////////////////////////////////
|
||||
var options = {
|
||||
cellHeight: 46,
|
||||
verticalMargin: 1,
|
||||
float: true,
|
||||
alwaysShowResizeHandle: true,
|
||||
disableOneColumnMode : true
|
||||
};
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Editor screen generation
|
||||
/////////////////////////////////////////
|
||||
oldSpacer = [];
|
||||
widthChange = [];
|
||||
widgetMove = [];
|
||||
widgetResize = [];
|
||||
widgetDrag = [];
|
||||
for (var cnt=0; cnt < groups.length; cnt++) {
|
||||
var gridID='#grid' + cnt;
|
||||
// gridstack generation
|
||||
$(gridID).gridstack(options);
|
||||
|
||||
// Clear the contents of Grind
|
||||
var grid = $(gridID+'.grid-stack').data('gridstack');
|
||||
grid.removeAll();
|
||||
|
||||
// Set the width of the display area of gridstack
|
||||
var groupWidth = Number(groups[cnt].width);
|
||||
$(gridID+'.grid-stack').css("width", groupWidth * 40);
|
||||
$(gridID+'.grid-stack').css("background-size", 100/groupWidth+"% 47px");
|
||||
grid.setGridWidth(groupWidth, true);
|
||||
|
||||
// Determination of placement position of widget of Grid
|
||||
var widgets = groups[cnt].widgets;
|
||||
widgets.sort(compareOrder);
|
||||
|
||||
var tbl = {};
|
||||
for (var cnt2 = 0; cnt2 < widgets.length; cnt2++) {
|
||||
// Set default value when there is auto width
|
||||
if (widgets[cnt2].auto == true) {
|
||||
widgets[cnt2].width = groupWidth;
|
||||
// Adjust to the group width
|
||||
} else if (widgets[cnt2].width > groupWidth) {
|
||||
widgets[cnt2].width = groupWidth;
|
||||
}
|
||||
// Auto support
|
||||
if (widgets[cnt2].auto === true || widgets[cnt2].type === 'ui_form') {
|
||||
widgets[cnt2].height = getDefaultHeight(widgets[cnt2].id, groupWidth);
|
||||
}
|
||||
// Calculate coordinates to be placed
|
||||
var point = search_point(Number(widgets[cnt2].width), Number(widgets[cnt2].height), groupWidth, 256, tbl);
|
||||
if (point) {
|
||||
widgets[cnt2].x = point.x;
|
||||
widgets[cnt2].y = point.y;
|
||||
}
|
||||
}
|
||||
|
||||
var items = GridStackUI.Utils.sort(widgets);
|
||||
_.each(items, function (node) {
|
||||
var minHeight = null;
|
||||
var maxHeight = null;
|
||||
// ui_form is fixed to height 2
|
||||
if (node.type === 'ui_form') {
|
||||
minHeight = node.height;
|
||||
maxHeight = node.height;
|
||||
}
|
||||
if (node.type !== 'ui_spacer') {
|
||||
var dispNode = RED.nodes.node(node.id);
|
||||
var dispType = dispNode._def.paletteLabel;
|
||||
var dispLabel = dispNode._def.label;
|
||||
try {
|
||||
dispLabel = (typeof dispLabel === "function" ? dispLabel.call(dispNode) : dispLabel)||"";
|
||||
}
|
||||
catch(err) {
|
||||
console.log("Definition error: " + node.type + ".label",err);
|
||||
dispLabel = dispType;
|
||||
}
|
||||
|
||||
var item = $('<div></div>', {
|
||||
'data-noderedtype': node.type,
|
||||
'data-noderedid': node.id,
|
||||
'data-nodereddisptype': dispType,
|
||||
'data-nodereddisplabel': dispLabel,
|
||||
'data-noderedsizeauto': node.auto
|
||||
});
|
||||
var itemContent = $('<div></div>', {
|
||||
addClass: 'grid-stack-item-content',
|
||||
title: dispLabel + ':' + dispType
|
||||
});
|
||||
|
||||
if (node.auto === true) {
|
||||
itemContent.append('<i class="fa fa-unlock nr-dashboard-layout-resize-enable"></i>');
|
||||
} else {
|
||||
itemContent.append('<i class="fa fa-lock nr-dashboard-layout-resize-disable"></i>');
|
||||
}
|
||||
itemContent.append('<b>'+ dispLabel +'</b><br/>'+ dispType);
|
||||
item.append(itemContent);
|
||||
grid.addWidget(
|
||||
item,
|
||||
node.x, node.y, node.width, node.height, false, null, null,
|
||||
minHeight, maxHeight, node.id);
|
||||
} else {
|
||||
// Record the spacer node ID to be deleted
|
||||
oldSpacer.push(node.id);
|
||||
}
|
||||
});
|
||||
|
||||
$(gridID+'.grid-stack > .grid-stack-item:visible').each( function(idx, el) {
|
||||
el = $(el);
|
||||
var node = el.data('_gridstack_node');
|
||||
var auto = (el[0].dataset.noderedsizeauto == 'true') ? true : false;
|
||||
grid.resizable(el, !auto);
|
||||
});
|
||||
|
||||
// Group width change
|
||||
widthChange.push(new changeGroupWidth(cnt));
|
||||
// Move widgets between groups (drag and drop)
|
||||
widgetMove.push(new moveGroupWidget(cnt));
|
||||
// Resize widget in group (start event)
|
||||
widgetResize.push(new resizeGroupWidget(cnt));
|
||||
// Dragging widgets in a group (start event)
|
||||
widgetDrag.push(new dragGroupWidget(cnt));
|
||||
}
|
||||
$('.grid-stack>.grid-stack-item>.grid-stack-item-content>.nr-dashboard-layout-resize-disable').on('click',layoutResizeDisable);
|
||||
$('.grid-stack>.grid-stack-item>.grid-stack-item-content>.nr-dashboard-layout-resize-enable').on('click',layoutResizeEnable);
|
||||
},
|
||||
close: function() {
|
||||
//
|
||||
},
|
||||
show: function() {}
|
||||
}
|
||||
|
||||
RED.tray.show(trayOptions);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
if (item.type === 'ui_tab') {
|
||||
var content = $('<div>',{class:"nr-db-sb-group-list-container"}).appendTo(container);
|
||||
|
||||
// ui_tab group chevron
|
||||
if (listStates.hasOwnProperty(item.node.id) && !listStates[item.node.id]) {
|
||||
content.hide();
|
||||
chevron.css({"transform":"rotate(-90deg)"});
|
||||
content.addClass('nr-db-sb-collapsed');
|
||||
listStates[item.node.id] = false;
|
||||
}
|
||||
else {
|
||||
listStates[item.node.id] = true;
|
||||
}
|
||||
titleRow.click(titleToggle(item.node.id,content,chevron));
|
||||
|
||||
// ui_tab group list
|
||||
var ol = $('<ol>',{class:"nr-db-sb-group-list"}).appendTo(content).editableList({
|
||||
sortable:".nr-db-sb-group-list-header",
|
||||
addButton: false,
|
||||
height: 'auto',
|
||||
connectWith: ".nr-db-sb-group-list",
|
||||
addItem: function(container,i,group) {
|
||||
if (!group.node) {
|
||||
group.node = {
|
||||
id: RED.nodes.id(),
|
||||
_def: RED.nodes.getType("ui_group"),
|
||||
type: "ui_group",
|
||||
users: [],
|
||||
tab: item.node.id,
|
||||
order: i+1,
|
||||
name: "Group "+(i+1),
|
||||
width: 6,
|
||||
disp: true
|
||||
};
|
||||
listElements[group.node.id] = container;
|
||||
RED.nodes.add(group.node);
|
||||
group.widgets = [];
|
||||
RED.history.push({
|
||||
t:'add',
|
||||
nodes:[group.node.id],
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
|
||||
RED.nodes.updateConfigNodeUsers(group.node);
|
||||
}
|
||||
}
|
||||
var groupNode = group.node;
|
||||
elementParents[groupNode] = item.node.id;
|
||||
var titleRow = $('<div>',{class:"nr-db-sb-list-header nr-db-sb-group-list-header"}).appendTo(container);
|
||||
$('<i class="nr-db-sb-list-handle nr-db-sb-group-list-handle fa fa-bars"></i>').appendTo(titleRow);
|
||||
var chevron = $('<i class="fa fa-angle-down nr-db-sb-list-chevron">',{style:"width:10px;"}).appendTo(titleRow);
|
||||
$('<i class="nr-db-sb-icon nr-db-sb-group-icon fa fa-table"></i>').appendTo(titleRow);
|
||||
var title = $('<span class="nr-db-sb-title">').text(groupNode.name||groupNode.id||"").appendTo(titleRow);
|
||||
listElements[groupNode.id] = container;
|
||||
var buttonGroup = $('<div>',{class:"nr-db-sb-list-header-button-group"}).appendTo(titleRow);
|
||||
var spacerButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-plus"></i> '+c_("layout.spacer")+'</a>').appendTo(buttonGroup);
|
||||
spacerButton.on('click',function(evt) {
|
||||
var spaceNode = {
|
||||
_def: RED.nodes.getType("ui_spacer"),
|
||||
type: "ui_spacer",
|
||||
hasUsers: false,
|
||||
users: [],
|
||||
id: RED.nodes.id(),
|
||||
tab: item.node.name,
|
||||
group: group.node.id,
|
||||
order: i+1,
|
||||
name: "spacer",
|
||||
width: 1,
|
||||
height:1,
|
||||
label: function() { return "spacer " + this.width + "x" + this.height; }
|
||||
};
|
||||
RED.nodes.add(spaceNode);
|
||||
RED.editor.validateNode(spaceNode);
|
||||
RED.history.push({
|
||||
t:'add',
|
||||
nodes:[spaceNode.id],
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
});
|
||||
var editButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.edit")+'</a>').appendTo(buttonGroup);
|
||||
var content = $('<div>',{class:"nr-db-sb-widget-list-container"}).appendTo(container);
|
||||
if (!listStates.hasOwnProperty(groupNode.id) || !listStates[groupNode.id]) {
|
||||
content.hide();
|
||||
chevron.css({"transform":"rotate(-90deg)"});
|
||||
content.addClass('nr-db-sb-collapsed');
|
||||
listStates[groupNode.id] = false;
|
||||
}
|
||||
else {
|
||||
listStates[groupNode.id] = true;
|
||||
}
|
||||
|
||||
var ol = $('<ol>',{class:"nr-db-sb-widget-list"}).appendTo(content).editableList({
|
||||
sortable:".nr-db-sb-widget-list-header",
|
||||
addButton: false,
|
||||
height: 'auto',
|
||||
connectWith: ".nr-db-sb-widget-list",
|
||||
addItem: function(container,i,widgetNode) {
|
||||
elementParents[widgetNode.id] = groupNode.id;
|
||||
var titleRow = $('<div>',{class:"nr-db-sb-list-header nr-db-sb-widget-list-header"}).appendTo(container);
|
||||
$('<i class="nr-db-sb-list-handle nr-db-sb-widget-list-handle fa fa-bars"></i>').appendTo(titleRow);
|
||||
$('<i class="nr-db-sb-icon nr-db-sb-widget-icon fa fa-picture-o"></i>').click(function(e) { e.preventDefault(); RED.search.show(widgetNode.id); }).appendTo(titleRow);
|
||||
var l = widgetNode._def.label;
|
||||
try {
|
||||
l = (typeof l === "function" ? l.call(widgetNode) : l)||"";
|
||||
}
|
||||
catch(err) {
|
||||
console.log("Definition error: "+d.type+".label",err);
|
||||
l = d.type;
|
||||
}
|
||||
var title = $('<span class="nr-db-sb-title">').text(l).appendTo(titleRow);
|
||||
listElements[widgetNode.id] = container;
|
||||
var buttonGroup = $('<div>',{class:"nr-db-sb-list-header-button-group"}).appendTo(titleRow);
|
||||
var editButton = $('<a href="#" class="editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-pencil"></i> '+c_("layout.edit")+'</a>').appendTo(buttonGroup);
|
||||
container.on('mouseover',function() {
|
||||
widgetNode.highlighted = true;
|
||||
widgetNode.dirty = true;
|
||||
RED.view.redraw();
|
||||
});
|
||||
container.on('mouseout',function() {
|
||||
widgetNode.highlighted = false;
|
||||
widgetNode.dirty = true;
|
||||
RED.view.redraw();
|
||||
});
|
||||
editButton.on('click',function(evt) {
|
||||
RED.editor.edit(widgetNode);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
});
|
||||
},
|
||||
sortItems: function(items) {
|
||||
var historyEvents = [];
|
||||
items.each(function(i,el) {
|
||||
var node = el.data('data');
|
||||
var hev = {
|
||||
t:'edit',
|
||||
node:node,
|
||||
changes:{
|
||||
order:node.order,
|
||||
group:node.group
|
||||
},
|
||||
dirty:node.dirty,
|
||||
changed:node.changed
|
||||
};
|
||||
historyEvents.push(hev);
|
||||
var changed = false;
|
||||
if (node.order !== i+1) {
|
||||
node.order = i+1;
|
||||
changed = true;
|
||||
}
|
||||
if (node.group !== group.node.id) {
|
||||
var oldGroupNode = RED.nodes.node(node.group);
|
||||
if (oldGroupNode) {
|
||||
var index = oldGroupNode.users.indexOf(node);
|
||||
oldGroupNode.users.splice(index,1);
|
||||
}
|
||||
node.group = group.node.id;
|
||||
group.node.users.push(node);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
node.dirty = true;
|
||||
node.changed = true;
|
||||
}
|
||||
})
|
||||
RED.history.push({
|
||||
t:'multi',
|
||||
events: historyEvents
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
}
|
||||
});
|
||||
ol.css("min-height","5px");
|
||||
if (groupNode.id) {
|
||||
groupLists[groupNode.id] = ol;
|
||||
}
|
||||
titleRow.click(titleToggle(groupNode.id,content,chevron));
|
||||
editButton.on('click',function(evt) {
|
||||
RED.editor.editConfig("", groupNode.type, groupNode.id);
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
});
|
||||
group.widgets.forEach(function(widget) {
|
||||
ol.editableList('addItem',widget);
|
||||
})
|
||||
},
|
||||
sortItems: function(items) {
|
||||
var historyEvents = [];
|
||||
items.each(function(i,el) {
|
||||
var groupData = el.data('data');
|
||||
var node = groupData.node;
|
||||
var hev = {
|
||||
t:'edit',
|
||||
node:node,
|
||||
changes:{
|
||||
order:node.order,
|
||||
tab:node.tab
|
||||
},
|
||||
dirty:node.dirty,
|
||||
changed:node.changed
|
||||
};
|
||||
historyEvents.push(hev);
|
||||
var changed = false;
|
||||
if (node.order !== i+1) {
|
||||
node.order = i+1;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
node.dirty = true;
|
||||
node.changed = true;
|
||||
}
|
||||
if (node.tab !== item.node.id) {
|
||||
var oldTabNode = RED.nodes.node(node.tab);
|
||||
if (oldTabNode) {
|
||||
var index = oldTabNode.users.indexOf(node);
|
||||
oldTabNode.users.splice(index,1);
|
||||
}
|
||||
node.tab = item.node.id;
|
||||
item.node.users.push(node);
|
||||
changed = true;
|
||||
}
|
||||
})
|
||||
RED.history.push({
|
||||
t:'multi',
|
||||
events: historyEvents
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
}
|
||||
})
|
||||
tabLists[item.node.id] = ol;
|
||||
|
||||
addGroupButton.click(function(evt) {
|
||||
ol.editableList('addItem',{});
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
});
|
||||
item.groups.forEach(function(group) {
|
||||
ol.editableList('addItem',group);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var tabContainer = $('<ol>',{class:"nr-db-sb-tab-list"}).appendTo(divTabs).editableList({
|
||||
sortable:".nr-db-sb-tab-list-header",
|
||||
addButton: false,
|
||||
addItem: addTabOrLinkItem,
|
||||
sortItems: function(items) {
|
||||
var historyEvents = [];
|
||||
items.each(function(i,el) {
|
||||
var itemData = el.data('data');
|
||||
var node = itemData.node;
|
||||
var hev = {
|
||||
t:'edit',
|
||||
node:node,
|
||||
changes:{
|
||||
order:node.order
|
||||
},
|
||||
dirty:node.dirty,
|
||||
changed:node.changed
|
||||
}
|
||||
historyEvents.push(hev);
|
||||
var changed = false;
|
||||
if (node.order !== i+1) {
|
||||
node.order = i+1;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
node.dirty = true;
|
||||
node.changed = true;
|
||||
}
|
||||
})
|
||||
RED.history.push({
|
||||
t:'multi',
|
||||
events: historyEvents
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
RED.view.redraw();
|
||||
}
|
||||
});
|
||||
|
||||
var orphanedWidgets = $('<div>',{class:"form-row"}).appendTo(layoutTab);
|
||||
$('<span><i class="fa fa-info-circle"></i> There <span id="nr-db-missing-group-count"></span> not in a group. Click <a id="nr-db-add-missing-groups" href="#">here</a> to create the missing groups</span>').appendTo(orphanedWidgets);
|
||||
orphanedWidgets.find('a').click(function(event) {
|
||||
var unknownGroups = {};
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (/^ui_/.test(node.type) && node.type !== 'ui_link' && node.type !== 'ui_toast' && node.type !== 'ui_ui_control') {
|
||||
if (!RED.nodes.node(node.group)) {
|
||||
var g = node.group || "_BLANK_";
|
||||
unknownGroups[g] = unknownGroups[g] || [];
|
||||
unknownGroups[g].push(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
var tab = null;
|
||||
var tabs = tabContainer.editableList('items');
|
||||
tabs.first().each(function(i,el) {
|
||||
var tabData = el.data('data');
|
||||
tab = tabData.node;
|
||||
});
|
||||
|
||||
var hev = [];
|
||||
if (tab === null) {
|
||||
tab = {
|
||||
id: RED.nodes.id(),
|
||||
_def: RED.nodes.getType("ui_tab"),
|
||||
type: "ui_tab",
|
||||
users: [],
|
||||
order: 0,
|
||||
name: "Tab",
|
||||
icon: "dashboard"
|
||||
};
|
||||
RED.nodes.add(tab);
|
||||
hev.push(tab.id);
|
||||
}
|
||||
for (var groupId in unknownGroups) {
|
||||
if (unknownGroups.hasOwnProperty(groupId)) {
|
||||
var groupNode = {
|
||||
id: RED.nodes.id(),
|
||||
_def: RED.nodes.getType("ui_group"),
|
||||
type: "ui_group",
|
||||
users: [],
|
||||
tab: tab.id,
|
||||
order: i+1,
|
||||
name: (groupId==="_BLANK_"?"Group":groupId),
|
||||
width: 6,
|
||||
disp: true
|
||||
};
|
||||
hev.push(groupNode.id);
|
||||
RED.nodes.add(groupNode);
|
||||
RED.editor.validateNode(groupNode);
|
||||
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
|
||||
RED.nodes.updateConfigNodeUsers(groupNode);
|
||||
}
|
||||
var widgets = unknownGroups[groupId];
|
||||
for (var i=0; i<widgets.length; i++) {
|
||||
widgets[i].group = groupNode.id;
|
||||
widgets[i].changed = true;
|
||||
widgets[i].dirty = true;
|
||||
if (RED.nodes.hasOwnProperty('updateConfigNodeUsers')) {
|
||||
RED.nodes.updateConfigNodeUsers(widgets[i]);
|
||||
}
|
||||
RED.editor.validateNode(widgets[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
RED.history.push({
|
||||
t:'add',
|
||||
nodes: hev,
|
||||
dirty:RED.nodes.dirty()
|
||||
});
|
||||
RED.nodes.dirty(true);
|
||||
refresh();
|
||||
refreshOrphanedWidgets();
|
||||
RED.view.redraw();
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
var listElements = {};
|
||||
var dashboard = [];
|
||||
var listStates = {};
|
||||
var elementParents = {};
|
||||
var awaitingGroups = {};
|
||||
var awaitingTabs = {};
|
||||
|
||||
function getCurrentList() {
|
||||
var currentList = [];
|
||||
var tabs = tabContainer.editableList('items');
|
||||
var open = false;
|
||||
tabs.each(function(i,el) {
|
||||
var tabData = el.data('data');
|
||||
var tab = [];
|
||||
var groups = el.find('.nr-db-sb-group-list').editableList('items');
|
||||
groups.each(function(j,el) {
|
||||
var group = [];
|
||||
var groupData = el.data('data');
|
||||
var widgets = el.find('.nr-db-sb-widget-list').editableList('items');
|
||||
widgets.each(function(k,el) {
|
||||
var widgetData = el.data('data');
|
||||
group.push(widgetData.id);
|
||||
})
|
||||
tab.push({id:groupData.node.id, widgets:group});
|
||||
});
|
||||
currentList.push({id:tabData.node.id,groups:tab});
|
||||
});
|
||||
return currentList;
|
||||
}
|
||||
|
||||
function refreshOrphanedWidgets() {
|
||||
var unknownGroups = {};
|
||||
var count = 0;
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (/^ui_/.test(node.type) && node.type !== 'ui_link' && node.type !== 'ui_toast' && node.type !== 'ui_ui_control' && (node.type === 'ui_template' && node.templateScope !== 'global')) {
|
||||
if (!RED.nodes.node(node.group)) {
|
||||
var g = node.group || "_BLANK_";
|
||||
unknownGroups[g] = unknownGroups[g] || [];
|
||||
unknownGroups[g].push(node);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (count > 0) {
|
||||
orphanedWidgets.show();
|
||||
$("#nr-db-missing-group-count").text((count===1?"is ":"are ")+count+" widget"+(count === 1?"":"s"))
|
||||
}
|
||||
else {
|
||||
orphanedWidgets.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
var currentList = getCurrentList();
|
||||
dashboard = [];
|
||||
var tabs = {};
|
||||
var groups = {};
|
||||
var elements = [];
|
||||
var groupElements = {};
|
||||
var tabGroups = {};
|
||||
var groupId;
|
||||
var group;
|
||||
var tabId;
|
||||
var tab;
|
||||
var unknownGroups = 0;
|
||||
// Find all the tabs and groups
|
||||
RED.nodes.eachConfig(function(node) {
|
||||
switch (node.type) {
|
||||
case 'ui_tab':
|
||||
case 'ui_link': {
|
||||
tabs[node.id] = node;
|
||||
//tabContainer.editableList('addItem',node);
|
||||
break;
|
||||
}
|
||||
case 'ui_group': {
|
||||
groups[node.id] = node;
|
||||
break;
|
||||
}
|
||||
case 'ui_spacer': {
|
||||
if (groups.hasOwnProperty(node.group)) {
|
||||
groupElements[node.group] = groupElements[node.group]||[];
|
||||
groupElements[node.group].push(node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (groupId in groups) {
|
||||
if (groups.hasOwnProperty(groupId)) {
|
||||
group = groups[groupId];
|
||||
if (tabs.hasOwnProperty(group.tab)) {
|
||||
// This group belongs to a tab
|
||||
tabGroups[group.tab] = tabGroups[group.tab]||[];
|
||||
tabGroups[group.tab].push(group);
|
||||
}
|
||||
else {
|
||||
unknownGroups++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find all ui widgets - list them by their group id
|
||||
RED.nodes.eachNode(function(node) {
|
||||
if (/^ui_/.test(node.type)) {
|
||||
if (groups.hasOwnProperty(node.group)) {
|
||||
groupElements[node.group] = groupElements[node.group]||[];
|
||||
groupElements[node.group].push(node);
|
||||
}
|
||||
else if ((node.type !== 'ui_toast')&&(node.type !== 'ui_ui_control')&&(node.type === 'ui_template' && node.templateScope !== 'global')) {
|
||||
unknownGroups++;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (unknownGroups > 0) {
|
||||
$("#nr-db-missing-group-count").text((unknownGroups===1?"is ":"are ")+unknownGroups+" widget"+(unknownGroups === 1?"":"s"))
|
||||
orphanedWidgets.show();
|
||||
}
|
||||
else {
|
||||
orphanedWidgets.hide();
|
||||
}
|
||||
// Sort each group's array of widgets
|
||||
for (groupId in groupElements) {
|
||||
if (groupElements.hasOwnProperty(groupId)) {
|
||||
group = groupElements[groupId];
|
||||
groupElements[groupId] = group.map(function(v,i) { return {n:v,i:i} }).sort(function(A,B) {
|
||||
if (A.n.order < B.n.order) { return A.n.order!==0?-1:1;}
|
||||
if (A.n.order > B.n.order) { return B.n.order!==0?1:-1;}
|
||||
return A.i - B.i;
|
||||
}).map(function(v) { return v.n})
|
||||
}
|
||||
}
|
||||
// Sort each tabs's array of groups
|
||||
for (tabId in tabGroups) {
|
||||
if (tabGroups.hasOwnProperty(tabId)) {
|
||||
tab = tabGroups[tabId];
|
||||
tabGroups[tabId] = tab.map(function(v,i) { return {n:v,i:i} }).sort(function(A,B) {
|
||||
if (A.n.order < B.n.order) { return -1;}
|
||||
if (A.n.order > B.n.order) { return 1;}
|
||||
return A.i - B.i;
|
||||
}).map(function(v) { return v.n})
|
||||
}
|
||||
}
|
||||
var tabIds = Object.keys(tabs).map(function(v,i) { return {n:tabs[v],i:i} }).sort(function(A,B) {
|
||||
if (A.n.order < B.n.order) { return -1;}
|
||||
if (A.n.order > B.n.order) { return 1;}
|
||||
return A.i - B.i;
|
||||
}).map(function(v) { return v.n.id});
|
||||
tabIds.forEach(function(tabId) {
|
||||
var tab = {node:tabs[tabId],groups:[]};
|
||||
if (tabGroups[tabId]) {
|
||||
tabGroups[tabId].forEach(function(groupNode) {
|
||||
var group = {node:groupNode,widgets:[]};
|
||||
if (groupElements[groupNode.id]) {
|
||||
group.widgets = groupElements[groupNode.id];
|
||||
}
|
||||
tab.groups.push(group);
|
||||
});
|
||||
}
|
||||
dashboard.push(tab);
|
||||
});
|
||||
var newList = dashboard.map(function(t) {
|
||||
return {
|
||||
id: t.node.id,
|
||||
groups: t.groups.map(function(g) {
|
||||
return {
|
||||
id: g.node.id,
|
||||
widgets: g.widgets.map(function(w) {
|
||||
return w.id;
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
if (JSON.stringify(newList)!=JSON.stringify(currentList)) {
|
||||
listElements = {};
|
||||
groupLists = {};
|
||||
tabLists = {};
|
||||
tabs = {};
|
||||
groups = {};
|
||||
elementParents = {};
|
||||
tabContainer.empty();
|
||||
dashboard.forEach(function(tab) {
|
||||
tabContainer.editableList('addItem',tab);
|
||||
});
|
||||
}
|
||||
ensureDashboardNode(true);
|
||||
if (globalDashboardNode) {
|
||||
$("#nr-db-field-title").val(globalDashboardNode.site.name);
|
||||
$("#nr-db-field-allowSwipe").val(globalDashboardNode.site.allowSwipe || "false");
|
||||
$("#nr-db-field-allowTempTheme").val(globalDashboardNode.site.allowTempTheme || "true");
|
||||
$("#nr-db-field-hideToolbar").val(globalDashboardNode.site.hideToolbar || "false");
|
||||
$("#nr-db-field-dateFormat").val(globalDashboardNode.site.dateFormat);
|
||||
|
||||
if (typeof globalDashboardNode.site.sizes !== "object") {
|
||||
globalDashboardNode.site.sizes = sizes;
|
||||
}
|
||||
$("#nr-db-field-sx").val(globalDashboardNode.site.sizes.sx);
|
||||
$("#nr-db-field-sy").val(globalDashboardNode.site.sizes.sy);
|
||||
$("#nr-db-field-px").val(globalDashboardNode.site.sizes.px);
|
||||
$("#nr-db-field-py").val(globalDashboardNode.site.sizes.py);
|
||||
$("#nr-db-field-cx").val(globalDashboardNode.site.sizes.cx);
|
||||
$("#nr-db-field-cy").val(globalDashboardNode.site.sizes.cy);
|
||||
$("#nr-db-field-gx").val(globalDashboardNode.site.sizes.gx);
|
||||
$("#nr-db-field-gy").val(globalDashboardNode.site.sizes.gy);
|
||||
|
||||
if (typeof globalDashboardNode.theme.angularTheme !== "object") {
|
||||
globalDashboardNode.theme.angularTheme = aTheme;
|
||||
}
|
||||
$("#nr-db-field-angPrimary").val(globalDashboardNode.theme.angularTheme.primary || "indigo");
|
||||
$("#nr-db-field-angAccents").val(globalDashboardNode.theme.angularTheme.accents || "blue");
|
||||
$("#nr-db-field-angWarn").val(globalDashboardNode.theme.angularTheme.warn || "red");
|
||||
$("#nr-db-field-angBackground").val(globalDashboardNode.theme.angularTheme.background || "grey");
|
||||
$("#nr-db-field-angLook").val(globalDashboardNode.theme.angularTheme.palette || "light");
|
||||
|
||||
$("#nr-db-field-theme").val(globalDashboardNode.theme.name);
|
||||
$("#ui-sidebar-name").val(globalDashboardNode.theme.customTheme.name);
|
||||
if (globalDashboardNode.theme.name === 'theme-custom') {
|
||||
$("#custom-theme-library-container").show();
|
||||
$("#custom-theme-settings").show();
|
||||
}
|
||||
else {
|
||||
$("#custom-theme-library-container").hide();
|
||||
$("#custom-theme-settings").hide();
|
||||
}
|
||||
if ($('#nr-db-field-allowTempTheme').val() === "none") {
|
||||
ulDashboardTabs.children().eq(2).addClass("hidden");
|
||||
ulDashboardTabs.children().eq(3).removeClass("hidden");
|
||||
}
|
||||
else {
|
||||
ulDashboardTabs.children().eq(2).removeClass("hidden");
|
||||
ulDashboardTabs.children().eq(3).addClass("hidden");
|
||||
}
|
||||
|
||||
//set colour start
|
||||
if (typeof globalDashboardNode.theme.name !== "string") {
|
||||
globalDashboardNode.theme.name = "theme-light";
|
||||
}
|
||||
var currentTheme = globalDashboardNode.theme.name.split("-")[1];
|
||||
var startingValue = globalDashboardNode.theme[currentTheme+"Theme"].baseColor;
|
||||
setColourPickerColour("base-color", startingValue);
|
||||
$("#nr-db-field-font").val(globalDashboardNode.theme[currentTheme+"Theme"].baseFont);
|
||||
generateColours(startingValue);
|
||||
if (globalDashboardNode.theme.name === 'theme-light' || globalDashboardNode.theme.name === 'theme-dark') {
|
||||
addLightAndDarkResetButton('base-color', $('#base-settings-ul').children().first());
|
||||
}
|
||||
|
||||
if (editor === undefined) {
|
||||
editor = RED.editor.createEditor({
|
||||
id: 'nr-db-field-format-editor',
|
||||
mode: 'ace/mode/javascript',
|
||||
value: JSON.stringify({theme:globalDashboardNode.theme.themeState, site:globalDashboardNode.site})
|
||||
});
|
||||
|
||||
RED.library.create({
|
||||
url:"themes", // where to get the data from
|
||||
type:"theme", // the type of object the library is for
|
||||
editor: editor, // the field name the main text body goes to
|
||||
mode:"ace/mode/javascript",
|
||||
fields:['name'],
|
||||
elementPrefix:"ui-sidebar-"
|
||||
});
|
||||
}
|
||||
|
||||
editor.on('input', function() {
|
||||
// Check for any changes on the editor object
|
||||
// i.e. has the theme been customised compared
|
||||
// to what is stored
|
||||
var editorObject = JSON.parse(editor.getValue());
|
||||
// var objectsEqual = true;
|
||||
// var keysEqual = true;
|
||||
// var editorKeys = Object.keys(editorObject);
|
||||
// var themeKeys = Object.keys(editorObject.theme);
|
||||
// var siteKeys = Object.keys(editorObject.site);
|
||||
// var dashNodeKeys = Object.keys(globalDashboardNode.theme.themeState);
|
||||
|
||||
// // Test equality
|
||||
// for (var i=0; i<themeKeys.length; i++) {
|
||||
// if (themeKeys[i] !== dashNodeKeys[i]) {
|
||||
// keysEqual = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (keysEqual) {
|
||||
// for (var j=0; j<themeKeys.length; j++) {
|
||||
// var key = themeKeys[j];
|
||||
// if (editorObject.theme[key] !== globalDashboardNode.theme.themeState[key]) {
|
||||
// objectsEqual = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!objectsEqual) {
|
||||
// globalDashboardNode.theme.themeState = editorObject.theme;
|
||||
// }
|
||||
//
|
||||
// //If custom theme is chosen, update the elements and current state
|
||||
// if (globalDashboardNode.theme.name === 'theme-custom') {
|
||||
// //globalDashboardNode.theme.customTheme.baseColor = globalDashboardNode.theme.themeState['base-color'].default;
|
||||
// generateColours(globalDashboardNode.theme.customTheme.baseColor);
|
||||
// //setColourPickerColour("base-color", globalDashboardNode.theme.customTheme.baseColor);
|
||||
// if (!objectsEqual) { RED.nodes.dirty(true); }
|
||||
// }
|
||||
|
||||
//Update theme object if necessary
|
||||
if (JSON.stringify(editorObject.theme) !== JSON.stringify(globalDashboardNode.theme.themeState)) {
|
||||
globalDashboardNode.theme.themeState = editorObject.theme;
|
||||
if ($("#ui-sidebar-name").val() !== globalDashboardNode.theme.customTheme.name) {
|
||||
globalDashboardNode.theme.customTheme.name = $("#ui-sidebar-name").val();
|
||||
globalDashboardNode.theme.customTheme.baseColor = globalDashboardNode.theme.themeState["base-color"].value;
|
||||
setColourPickerColour("base-color", globalDashboardNode.theme.customTheme.baseColor);
|
||||
generateColours(globalDashboardNode.theme.themeState["base-color"].value);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
}
|
||||
if (JSON.stringify(aTheme) !== JSON.stringify(globalDashboardNode.theme.angularTheme)) {
|
||||
globalDashboardNode.theme.angularTheme = aTheme;
|
||||
}
|
||||
|
||||
//Update site object if necessary
|
||||
if (JSON.stringify(editorObject.site) !== JSON.stringify(globalDashboardNode.site)) {
|
||||
globalDashboardNode.site = editorObject.site;
|
||||
$("#nr-db-field-title").val(globalDashboardNode.site.name);
|
||||
$("#nr-db-field-hideToolbar").val(globalDashboardNode.site.hideToolbar);
|
||||
$("#nr-db-field-allowSwipe").val(globalDashboardNode.site.allowSwipe);
|
||||
$("#nr-db-field-allowTempTheme").val(globalDashboardNode.site.allowTempTheme);
|
||||
$("#nr-db-field-dateFormat").val(globalDashboardNode.site.dateFormat);
|
||||
$("#nr-db-field-sx").val(globalDashboardNode.site.sizes.sx);
|
||||
$("#nr-db-field-sy").val(globalDashboardNode.site.sizes.sy);
|
||||
$("#nr-db-field-px").val(globalDashboardNode.site.sizes.px);
|
||||
$("#nr-db-field-py").val(globalDashboardNode.site.sizes.py);
|
||||
$("#nr-db-field-gx").val(globalDashboardNode.site.sizes.gx);
|
||||
$("#nr-db-field-gy").val(globalDashboardNode.site.sizes.gy);
|
||||
$("#nr-db-field-cx").val(globalDashboardNode.site.sizes.cx);
|
||||
$("#nr-db-field-cy").val(globalDashboardNode.site.sizes.cy);
|
||||
RED.nodes.dirty(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
awaitingGroups = {};
|
||||
awaitingTabs = {};
|
||||
}
|
||||
|
||||
RED.sidebar.addTab({
|
||||
id: "dashboard",
|
||||
label: c_("label.dashboard"),
|
||||
name: "Dashboard",
|
||||
content: content,
|
||||
closeable: true,
|
||||
pinned: true,
|
||||
iconClass: "fa fa-bar-chart",
|
||||
disableOnEdit: true,
|
||||
onchange: function() { refresh(); }
|
||||
});
|
||||
|
||||
editSaveEventHandler = function(node) {
|
||||
if (/^ui_/.test(node.type)) {
|
||||
if (node.type === "ui_tab" || node.type === "ui_group") {
|
||||
if (listElements[node.id]) {
|
||||
// Existing element
|
||||
listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").text(node.name||node.id);
|
||||
if (node.type === "ui_group") {
|
||||
refresh();
|
||||
}
|
||||
else {
|
||||
if (node.hidden === true) { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").addClass('nr-db-sb-title-hidden'); }
|
||||
else { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").removeClass('nr-db-sb-title-hidden'); }
|
||||
if (node.disabled === true) { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").addClass('nr-db-sb-title-disabled'); }
|
||||
else { listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").removeClass('nr-db-sb-title-disabled'); }
|
||||
}
|
||||
}
|
||||
else if (node.type === "ui_tab") {
|
||||
// Adding a tab
|
||||
tabContainer.editableList('addItem',{node:node,groups:[]})
|
||||
}
|
||||
else {
|
||||
// Adding a group
|
||||
if (tabLists[node.tab]) {
|
||||
tabLists[node.tab].editableList('addItem',{node:node,widgets:[]})
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node.type === "ui_link") {
|
||||
if (listElements[node.id]) {
|
||||
var container = listElements[node.id];
|
||||
container.find(".nr-db-sb-link-name").text(node.name||"untitled");
|
||||
container.find(".nr-db-sb-link-url").text(node.link);
|
||||
}
|
||||
}
|
||||
else {
|
||||
refreshOrphanedWidgets();
|
||||
if (listElements[node.id]) {
|
||||
if (node.group != elementParents[node.id]) {
|
||||
// Moved to a different group
|
||||
if (groupLists[elementParents[node.id]]) {
|
||||
groupLists[elementParents[node.id]].editableList('removeItem',listElements[node.id].data('data'))
|
||||
}
|
||||
if (groupLists[node.group]) {
|
||||
groupLists[node.group].editableList('removeItem',node)
|
||||
groupLists[node.group].editableList('addItem',node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var l = node._def.label;
|
||||
try {
|
||||
l = (typeof l === "function" ? l.call(node) : l)||"";
|
||||
}
|
||||
catch(err) {
|
||||
console.log("Definition error: "+d.type+".label",err);
|
||||
l = d.type;
|
||||
}
|
||||
listElements[node.id].children(".nr-db-sb-list-header").find(".nr-db-sb-title").text(l);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (groupLists[node.group]) {
|
||||
if (node.order === 0) { node.order = groupLists[node.group].editableList('length'); }
|
||||
groupLists[node.group].editableList('addItem',node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
RED.events.on("editor:save",editSaveEventHandler);
|
||||
|
||||
// Dashboard layout tool
|
||||
layoutUpdateEventHandler = function(node) {
|
||||
if (/^ui_/.test(node.type) && node.type !== 'ui_link' && node.type !== 'ui_toast' && node.type !== 'ui_ui_control' && node.type !== 'ui_audio' && node.type !== 'ui_base' && node.type !== 'ui_group' && node.type !== 'ui_tab') {
|
||||
if (listElements[node.id]) {
|
||||
if (node.group != elementParents[node.id]) {
|
||||
// Moved to a different group
|
||||
if (groupLists[elementParents[node.id]]) {
|
||||
groupLists[elementParents[node.id]].editableList('removeItem',listElements[node.id].data('data'))
|
||||
}
|
||||
if (groupLists[node.group]) {
|
||||
groupLists[node.group].editableList('removeItem',node)
|
||||
groupLists[node.group].editableList('addItem',node);
|
||||
groupLists[node.group].editableList('sort',function(a,b){return a.order-b.order;});
|
||||
}
|
||||
}
|
||||
else {
|
||||
groupLists[node.group].editableList('sort',function(a,b){return a.order-b.order;});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
RED.events.on("layout:update",layoutUpdateEventHandler);
|
||||
|
||||
|
||||
var pendingAdd = [];
|
||||
var pendingAddTimer = null;
|
||||
|
||||
function handlePendingAdds() {
|
||||
var hasTabs = false;
|
||||
var hasGroups = false;
|
||||
pendingAdd.sort(function(A,B) {
|
||||
hasTabs = hasTabs || A.type === "ui_tab" || B.type === "ui_tab";
|
||||
hasGroups = hasGroups || A.type === "ui_group" || B.type === "ui_group";
|
||||
if (A.type === B.type) {
|
||||
return 0;
|
||||
}
|
||||
if (A.type === "ui_tab") {
|
||||
return -1;
|
||||
}
|
||||
else if (B.type === "ui_tab") {
|
||||
return 1;
|
||||
}
|
||||
else if (A.type === "ui_group") {
|
||||
return -1;
|
||||
}
|
||||
else if (B.type === "ui_group") {
|
||||
return 1;
|
||||
}
|
||||
return 0
|
||||
});
|
||||
for (var i=0; i<pendingAdd.length; i++) {
|
||||
var node = pendingAdd[i];
|
||||
if (node.type === "ui_tab") {
|
||||
tabContainer.editableList('addItem',{node:node,groups:[]});
|
||||
}
|
||||
else {
|
||||
if (hasTabs) {
|
||||
// We've added some tabs, need to give jquery time to add the lists
|
||||
pendingAdd = pendingAdd.slice(i);
|
||||
pendingAddTimer = setTimeout(handlePendingAdds,50);
|
||||
return;
|
||||
}
|
||||
if (node.type === "ui_group") {
|
||||
if (tabLists[node.tab]) {
|
||||
tabLists[node.tab].editableList('addItem',{node:node,widgets:[]});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hasGroups) {
|
||||
// We've added some tabs, need to give jquery time to add the lists
|
||||
pendingAdd = pendingAdd.slice(i);
|
||||
pendingAddTimer = setTimeout(handlePendingAdds,50);
|
||||
return;
|
||||
}
|
||||
if (groupLists[node.group]) {
|
||||
groupLists[node.group].editableList('addItem',node)
|
||||
}
|
||||
else {
|
||||
refreshOrphanedWidgets();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pendingAdd = [];
|
||||
}
|
||||
|
||||
nodesAddEventHandler = function(node) {
|
||||
if (/^ui_/.test(node.type) && !listElements[node.id]) {
|
||||
pendingAdd.push(node);
|
||||
clearTimeout(pendingAddTimer);
|
||||
pendingAddTimer = setTimeout(handlePendingAdds,100);
|
||||
}
|
||||
};
|
||||
RED.events.on("nodes:add", nodesAddEventHandler);
|
||||
|
||||
nodesRemoveEventHandler = function(node) {
|
||||
if (/^ui_/.test(node.type)) {
|
||||
if (node.type === "ui_tab" || node.type === "ui_link") {
|
||||
if (listElements[node.id]) {
|
||||
tabContainer.editableList('removeItem',listElements[node.id].data('data'));
|
||||
delete tabLists[node.id];
|
||||
}
|
||||
}
|
||||
else if (node.type === "ui_group") {
|
||||
if (tabLists[node.tab] && listElements[node.id]) {
|
||||
tabLists[node.tab].editableList('removeItem',listElements[node.id].data('data'));
|
||||
}
|
||||
delete groupLists[node.id];
|
||||
}
|
||||
else {
|
||||
if (groupLists[node.group]) {
|
||||
groupLists[node.group].editableList('removeItem',node)
|
||||
}
|
||||
}
|
||||
refreshOrphanedWidgets();
|
||||
delete listElements[node.id];
|
||||
}
|
||||
};
|
||||
RED.events.on("nodes:remove", nodesRemoveEventHandler);
|
||||
}
|
||||
});
|
||||
|
||||
$.widget("nodereddashboard.elementSizerByNum", {
|
||||
_create: function() {
|
||||
var that = this;
|
||||
var has_height = this.options.has_height;
|
||||
var pos = this.options.pos;
|
||||
var c_width = has_height ? '15%' : '6%';
|
||||
var container = $('<div>').css({
|
||||
position: 'absolute',
|
||||
background: 'white',
|
||||
padding: '10px 10px 10px 10px',
|
||||
border: '1px solid grey',
|
||||
zIndex: '20',
|
||||
borderRadius: "4px",
|
||||
display:"none",
|
||||
width: c_width
|
||||
}).appendTo(document.body);
|
||||
var box0 = $("<div>").css({
|
||||
fontSize: '13px',
|
||||
color: '#aaa',
|
||||
float: 'left',
|
||||
paddingTop: '1px'
|
||||
}).appendTo(container);
|
||||
|
||||
var width = $(this.options.width).val();
|
||||
var height = has_height ? $(this.options.height).val() : undefined;
|
||||
var max_w = '';
|
||||
var groupNode = this.options.groupNode;
|
||||
if(groupNode) {
|
||||
max_w = 'max="'+groupNode.width+'"';
|
||||
}
|
||||
width = (width > 0) ? width : 1;
|
||||
height = (height > 0) ? height : 1;
|
||||
var in0 = $('<input type="number" min="1" '+max_w+'>')
|
||||
.css("width", has_height ? "45%" : "100%")
|
||||
.val(width)
|
||||
.appendTo(box0);
|
||||
if(has_height) {
|
||||
var pad = $('<span>')
|
||||
.text(" x ")
|
||||
.appendTo(box0);
|
||||
var in1 = $('<input type="number" min="1">')
|
||||
.css("width", "45%")
|
||||
.val(height)
|
||||
.appendTo(box0);
|
||||
}
|
||||
var closeTimer;
|
||||
var closeFunc = function() {
|
||||
var w = in0.val();
|
||||
var h = has_height ? in1.val() : undefined;
|
||||
var label = that.options.label;
|
||||
label.text(w+(has_height ? (' x '+h) : ''));
|
||||
$(that.options.width).val(w).change();
|
||||
if(has_height) {
|
||||
$(that.options.height).val(h).change();
|
||||
}
|
||||
that.destroy();
|
||||
};
|
||||
container.keypress(function(e) {
|
||||
if(e.which === 13) { // pressed ENTER
|
||||
container.fadeOut(100, closeFunc);
|
||||
}
|
||||
});
|
||||
container.on('mouseleave', function(e) {
|
||||
closeTimer = setTimeout(function() {
|
||||
container.fadeOut(200, closeFunc);
|
||||
}, 100);
|
||||
});
|
||||
container.on('mouseenter', function(e) {
|
||||
clearTimeout(closeTimer);
|
||||
});
|
||||
container.css({
|
||||
top: (pos.top -10)+"px",
|
||||
left: (pos.left +10)+"px"
|
||||
});
|
||||
container.fadeIn(200);
|
||||
}
|
||||
});
|
||||
|
||||
$.widget( "nodereddashboard.elementSizer", {
|
||||
_create: function() {
|
||||
var that = this;
|
||||
var gridWidth = 6;
|
||||
var width = parseInt($(this.options.width).val()||0);
|
||||
var height = parseInt(this.options.hasOwnProperty('height')?$(this.options.height).val():"1")||0;
|
||||
var hasAuto = (!this.options.hasOwnProperty('auto') || this.options.auto);
|
||||
|
||||
this.element.css({
|
||||
minWidth: this.element.height()+4
|
||||
});
|
||||
var auto_text = c_("auto");
|
||||
var sizeLabel = (width === 0 && height === 0)?auto_text:width+(this.options.hasOwnProperty('height')?" x "+height:"");
|
||||
this.element.text(sizeLabel).on('mousedown',function(evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
|
||||
var width = parseInt($(that.options.width).val()||0);
|
||||
var height = parseInt(that.options.hasOwnProperty('height')?$(that.options.height).val():"1")||0;
|
||||
var maxWidth = 0;
|
||||
var maxHeight;
|
||||
var fixedWidth = false;
|
||||
var fixedHeight = false;
|
||||
var group = $(that.options.group).val();
|
||||
if (group) {
|
||||
var groupNode = RED.nodes.node(group);
|
||||
if (groupNode) {
|
||||
gridWidth = Math.max(6,groupNode.width,+width);
|
||||
maxWidth = groupNode.width || gridWidth;
|
||||
fixedWidth = true;
|
||||
}
|
||||
maxHeight = Math.max(6,+height+1);
|
||||
}
|
||||
else {
|
||||
gridWidth = Math.max(12,+width);
|
||||
maxWidth = gridWidth;
|
||||
maxHeight = 1;
|
||||
fixedHeight = true;
|
||||
}
|
||||
|
||||
var pos = $(this).offset();
|
||||
var container = $('<div>').css({
|
||||
position: 'absolute',
|
||||
background: 'white',
|
||||
padding: '5px 10px 10px 10px',
|
||||
border: '1px solid grey',
|
||||
zIndex: '20',
|
||||
borderRadius: "4px",
|
||||
display:"none"
|
||||
}).appendTo(document.body);
|
||||
var closeTimer;
|
||||
|
||||
container.on('mouseleave',function(evt) {
|
||||
closeTimer = setTimeout(function() {
|
||||
container.fadeOut(200, function() { $(this).remove(); });
|
||||
},100)
|
||||
});
|
||||
container.on('mouseenter',function() {
|
||||
clearTimeout(closeTimer);
|
||||
})
|
||||
|
||||
var label = $("<div>").css({
|
||||
fontSize: '13px',
|
||||
color: '#aaa',
|
||||
float: 'left',
|
||||
paddingTop: '1px'
|
||||
}).appendTo(container).text((width === 0 && height === 0)?auto_text:(width+(that.options.hasOwnProperty('height')?" x "+height:"")));
|
||||
label.hover(function() {
|
||||
$(this).css('text-decoration', 'underline');
|
||||
}, function() {
|
||||
$(this).css('text-decoration', 'none');
|
||||
});
|
||||
label.click(function(e) {
|
||||
var group = $(that.options.group).val();
|
||||
var groupNode = null;
|
||||
if(group) {
|
||||
groupNode = RED.nodes.node(group);
|
||||
if(groupNode === null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$(that).elementSizerByNum({
|
||||
width: that.options.width,
|
||||
height: that.options.height,
|
||||
groupNode: groupNode,
|
||||
pos: pos,
|
||||
label: that.element,
|
||||
has_height: that.options.hasOwnProperty('height')
|
||||
});
|
||||
closeTimer = setTimeout(function() {
|
||||
container.fadeOut(200, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
},100)
|
||||
});
|
||||
|
||||
var buttonRow = $('<div>',{style:"text-align:right; height:25px;"}).appendTo(container);
|
||||
|
||||
if (hasAuto) {
|
||||
var button = $('<a>',{href:"#",class:"editor-button editor-button-small",style:"margin-bottom:5px"})
|
||||
.text(auto_text)
|
||||
.appendTo(buttonRow)
|
||||
.on('mouseup',function(evt) {
|
||||
that.element.text(auto_text)
|
||||
$(that.options.width).val(0).change();
|
||||
$(that.options.height).val(0).change();
|
||||
evt.preventDefault();
|
||||
container.fadeOut(200, function() { $(this).remove(); });
|
||||
});
|
||||
}
|
||||
|
||||
var cellBorder = "1px dashed lightGray";
|
||||
var cellBorderExisting = "1px solid gray";
|
||||
var cellBorderHighlight = "1px dashed black";
|
||||
var rows = [];
|
||||
function addRow(i) {
|
||||
var row = $('<div>').css({padding:0,margin:0,height:"25px","box-sizing":"border-box"}).appendTo(container);
|
||||
rows.push(row);
|
||||
cells.push([])
|
||||
for (var j=0; j<gridWidth; j++) {
|
||||
addCell(i,j);
|
||||
}
|
||||
}
|
||||
function addCell(i,j) {
|
||||
var row = rows[i];
|
||||
var cell = $('<div>').css({
|
||||
display:"inline-block",
|
||||
width: "25px",
|
||||
height: "25px",
|
||||
borderRight: (j===(width-1)&&i<height)?cellBorderExisting:cellBorder,
|
||||
borderBottom: (i===(height-1)&&j<width)?cellBorderExisting:cellBorder,
|
||||
boxSizing: "border-box",
|
||||
cursor:"pointer",
|
||||
background: (j<maxWidth)?"#fff":"#eee"
|
||||
}).appendTo(row);
|
||||
cells[i].push(cell);
|
||||
if (j===0) {
|
||||
cell.css({borderLeft:((i<=height-1)?cellBorderExisting:cellBorder)});
|
||||
}
|
||||
if (i===0) {
|
||||
cell.css({borderTop:((j<=width-1)?cellBorderExisting:cellBorder)});
|
||||
}
|
||||
if (j<maxWidth) {
|
||||
cell.data("w",j);
|
||||
cell.data("h",i);
|
||||
cell.on("mouseup",function() {
|
||||
that.element.text(($(this).data("w")+1)+(that.options.hasOwnProperty('height')?" x "+($(this).data("h")+1):""))
|
||||
$(that.options.width).val($(this).data("w")+1).change();
|
||||
$(that.options.height).val($(this).data("h")+1).change();
|
||||
container.fadeOut(200, function() { $(this).remove(); });
|
||||
});
|
||||
cell.on("mouseover",function() {
|
||||
var w = $(this).data("w");
|
||||
var h = $(this).data("h");
|
||||
label.text((w+1)+(that.options.hasOwnProperty('height')?" x "+(h+1):""));
|
||||
for (var y = 0; y<maxHeight; y++) {
|
||||
for (var x = 0; x<maxWidth; x++) {
|
||||
cells[y][x].css({
|
||||
background: (y<=h && x<=w)?'#ddd':'#fff',
|
||||
borderLeft: (x===0&&y<=h)?cellBorderHighlight:(x===0)?((y<=height-1)?cellBorderExisting:cellBorder):'',
|
||||
borderTop: (y===0&&x<=w)?cellBorderHighlight:(y===0)?((x<=width-1)?cellBorderExisting:cellBorder):'',
|
||||
borderRight: (x===w&&y<=h)?cellBorderHighlight:((x===width-1&&y<=height-1)?cellBorderExisting:cellBorder),
|
||||
borderBottom: (y===h&&x<=w)?cellBorderHighlight:((y===height-1&&x<=width-1)?cellBorderExisting:cellBorder)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (!fixedHeight && h === maxHeight-1) {
|
||||
addRow(maxHeight++)
|
||||
}
|
||||
if (!fixedWidth && w === maxWidth-1) {
|
||||
maxWidth++;
|
||||
gridWidth++;
|
||||
for (var r=0; r<maxHeight; r++) {
|
||||
addCell(r,maxWidth-1);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
var cells = [];
|
||||
for (var i=0; i<maxHeight; i++) {
|
||||
addRow(i);
|
||||
}
|
||||
container.css({
|
||||
top:(pos.top)+"px",
|
||||
left:(pos.left)+"px"
|
||||
});
|
||||
container.fadeIn(200);
|
||||
})
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_base">
|
||||
<div class='form-row'>
|
||||
This <i>ui_base</i> node is the main node that all<br/>other dashboard widget nodes communicate to.<br/>
|
||||
<br/>One instance is required to support the dashboard.<br/>
|
||||
<br/>If you have no dashboard you can delete this node.<br/>
|
||||
It will be re-created automatically if required.<br/>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_base">
|
||||
</script>
|
||||
117
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_base.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
var path= require('path');
|
||||
var node;
|
||||
var set = RED.settings.ui || "{}";
|
||||
|
||||
function BaseNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
node = this;
|
||||
var baseFontName = "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif";
|
||||
|
||||
var defaultLightTheme = {
|
||||
baseColor: '#0094CE',
|
||||
baseFont: baseFontName
|
||||
}
|
||||
var defaultDarkTheme = {
|
||||
baseColor: '#097479',
|
||||
baseFont: baseFontName
|
||||
}
|
||||
var defaultCustomTheme = {
|
||||
name: 'Untitled Theme 1',
|
||||
baseColor: defaultLightTheme.baseColor,
|
||||
baseFont: baseFontName
|
||||
}
|
||||
var defaultAngularTheme = {
|
||||
primary:'indigo',
|
||||
accents:'teal',
|
||||
warn: "red",
|
||||
background:'grey'
|
||||
};
|
||||
|
||||
// Setup theme name
|
||||
// First try old format (for upgrading with old flow file)
|
||||
// Then try new format
|
||||
// Else fallback to theme-light
|
||||
var themeName;
|
||||
if (typeof(config.theme) === 'string') { themeName = config.theme; }
|
||||
else { themeName = config.theme.name || "theme-light"; }
|
||||
|
||||
// Setup other styles
|
||||
var defaultThemeState = {}
|
||||
if (themeName === 'theme-light') {
|
||||
defaultThemeState["base-font"] = {value: baseFontName};
|
||||
defaultThemeState["base-color"] = {value: "#0094CE"};
|
||||
defaultThemeState["page-backgroundColor"] = {value: "#fafafa"};
|
||||
defaultThemeState["page-titlebar-backgroundColor"] = {value: "#0094CE"};
|
||||
defaultThemeState["page-sidebar-backgroundColor"] = {value: "#ffffff"};
|
||||
defaultThemeState["group-backgroundColor"] = {value: "#ffffff"};
|
||||
defaultThemeState["group-textColor"] = {value: "#000000"};
|
||||
defaultThemeState["group-borderColor"] = {value: "#ffffff"};
|
||||
defaultThemeState["widget-textColor"] = {value: "#111111"};
|
||||
defaultThemeState["widget-backgroundColor"] = {value: "#0094CE"};
|
||||
}
|
||||
else {
|
||||
defaultThemeState["base-font"] = {value: baseFontName};
|
||||
defaultThemeState["base-color"] = {value: "#097479"};
|
||||
defaultThemeState["page-backgroundColor"] = {value: "#111111"};
|
||||
defaultThemeState["page-titlebar-backgroundColor"] = {value: "#097479"};
|
||||
defaultThemeState["page-sidebar-backgroundColor"] = {value: "#000000"};
|
||||
defaultThemeState["group-backgroundColor"] = {value: "#333333"};
|
||||
defaultThemeState["group-textColor"] = {value: "#10cfd8"};
|
||||
defaultThemeState["group-borderColor"] = {value: "#555555"};
|
||||
defaultThemeState["widget-textColor"] = {value: "#eeeeee"};
|
||||
defaultThemeState["widget-backgroundColor"] = {value: "#097479"};
|
||||
}
|
||||
|
||||
var defaultThemeObject = {
|
||||
name: themeName,
|
||||
lightTheme: config.theme.lightTheme || defaultLightTheme,
|
||||
darkTheme: config.theme.darkTheme || defaultDarkTheme,
|
||||
customTheme: config.theme.customTheme || defaultCustomTheme,
|
||||
angularTheme: config.theme.angularTheme || defaultAngularTheme,
|
||||
themeState: config.theme.themeState || defaultThemeState
|
||||
}
|
||||
|
||||
this.config = {
|
||||
theme: defaultThemeObject,
|
||||
site: config.site
|
||||
}
|
||||
ui.addBaseConfig(this.config);
|
||||
}
|
||||
RED.nodes.registerType("ui_base", BaseNode);
|
||||
|
||||
RED.library.register("themes");
|
||||
|
||||
RED.httpAdmin.get('/uisettings', function(req, res) {
|
||||
res.json(set);
|
||||
});
|
||||
|
||||
RED.httpAdmin.get('/ui_base/js/*', function(req, res) {
|
||||
var filename = path.join(__dirname , '../dist/js', req.params[0]);
|
||||
res.sendFile(filename, function (err) {
|
||||
if (err) {
|
||||
if (node) {
|
||||
node.warn(filename + " not found. Maybe running in dev mode.");
|
||||
}
|
||||
else {
|
||||
console.log("ui_base - error:",err);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
RED.httpAdmin.get('/ui_base/css/*', function(req, res) {
|
||||
var filename = path.join(__dirname , '../dist/css', req.params[0]);
|
||||
res.sendFile(filename, function (err) {
|
||||
if (err) {
|
||||
if (node) {
|
||||
node.warn(filename + " not found. Maybe running in dev mode.");
|
||||
}
|
||||
else {
|
||||
console.log("ui_base - error:",err);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
123
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_button.html
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_button',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
passthru: {value: false},
|
||||
label: {value: 'button'},
|
||||
tooltip: {value: ''},
|
||||
color: {value: ''},
|
||||
bgcolor: {value: ''},
|
||||
icon: {value: ''},
|
||||
payload: {value: '',validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('payloadType'):function(v) { return true})},
|
||||
payloadType: { value: 'str'},
|
||||
topic: {value: ''}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: function() { if (this.payloadType === "str") {
|
||||
return this.payload;
|
||||
} else {return this.payloadType; } },
|
||||
icon: "ui_button.png",
|
||||
paletteLabel: 'button',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'button'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
$('#node-input-payload').typedInput({
|
||||
default: 'str',
|
||||
typeField: $("#node-input-payloadType"),
|
||||
types: ['str','num','bool','json','bin','date','flow','global']
|
||||
})
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_button">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-icon"><i class="fa fa-picture-o"></i> Icon</label>
|
||||
<input type="text" id="node-input-icon" placeholder="optional icon ">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label" placeholder="optional label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
|
||||
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-color"><i class="fa fa-tint"></i> Colour</label>
|
||||
<input type="text" id="node-input-color" placeholder="optional text/icon color">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-bgcolor"><i class="fa fa-tint"></i> Background</label>
|
||||
<input type="text" id="node-input-bgcolor" placeholder="optional background color">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When clicked, send:</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-payload" style="padding-left: 25px; margin-right: -25px">Payload</label>
|
||||
<input type="text" id="node-input-payload" style="width:70%">
|
||||
<input type="hidden" id="node-input-payloadType">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic" style="padding-left: 25px; margin-right: -25px">Topic</label>
|
||||
<input type="text" id="node-input-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, emulate a button click: </label>
|
||||
<input type="checkbox" id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_button">
|
||||
<p>Adds a button to the user interface.</p>
|
||||
<p>Clicking the button generates a message with <code>msg.payload</code> set to the <b>Payload</b> field.
|
||||
If no payload is specified, the node id is used.</p>
|
||||
<p>The <b>Size</b> defaults to 3 by 1.</p>
|
||||
<p>The <b>Icon</b> can be defined, as either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
|
||||
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
|
||||
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
|
||||
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
|
||||
<p>The colours of the text and background may be set. They can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.background}}</code>.</p>
|
||||
<p>The label can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
|
||||
<p>If set to pass through mode a message arriving on the input will act like pressing the button.
|
||||
The output payload will be as defined in the node configuration.</p>
|
||||
<p>The <b>Topic</b> field can be used to set the <code>msg.topic</code> property that is output.</p>
|
||||
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the button.</p>
|
||||
</script>
|
||||
69
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_button.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function ButtonNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var payloadType = config.payloadType;
|
||||
var payload = config.payload;
|
||||
|
||||
if (payloadType === 'flow' || payloadType === 'global') {
|
||||
try {
|
||||
var parts = RED.util.normalisePropertyExpression(payload);
|
||||
if (parts.length === 0) {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
node.warn("Invalid payload property expression - defaulting to node id")
|
||||
payload = node.id;
|
||||
payloadType = 'str';
|
||||
}
|
||||
}
|
||||
else {
|
||||
payload = payload || node.id;
|
||||
}
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
emitOnlyNewValues: false,
|
||||
forwardInputMessages: config.passthru || false,
|
||||
storeFrontEndInputAsState: false,
|
||||
control: {
|
||||
type: 'button',
|
||||
label: config.label,
|
||||
tooltip: config.tooltip,
|
||||
color: config.color,
|
||||
bgcolor: config.bgcolor,
|
||||
icon: config.icon,
|
||||
order: config.order,
|
||||
value: payload,
|
||||
format: config.bgcolor,
|
||||
width: config.width || group.config.width || 3,
|
||||
height: config.height || 1
|
||||
},
|
||||
beforeSend: function (msg) {
|
||||
msg.topic = config.topic || msg.topic;
|
||||
},
|
||||
convertBack: function (value) {
|
||||
if (payloadType === "date") {
|
||||
value = Date.now();
|
||||
}
|
||||
else {
|
||||
value = RED.util.evaluateNodeProperty(payload,payloadType,node);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_button", ButtonNode);
|
||||
};
|
||||
295
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_chart.html
generated
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
<style>
|
||||
input.series-color {
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
input.series-color::-webkit-color-swatch {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_chart',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(119, 198, 204)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}},
|
||||
height: {value: 0},
|
||||
label: {value: 'chart'},
|
||||
chartType: {value: 'line'},
|
||||
legend: {value: 'false'},
|
||||
xformat: {value: 'HH:mm:ss'},
|
||||
interpolate: {value: 'linear', required:true},
|
||||
nodata: {value: ''},
|
||||
dot: {value: false},
|
||||
ymin: {value: '', validate:function(value) { return value === '' || RED.validators.number(); }},
|
||||
ymax: {value: '', validate:function(value) { return value === '' || RED.validators.number(); }},
|
||||
removeOlder: {value: 1, validate:RED.validators.number(), required:true},
|
||||
removeOlderPoints: {value: '', validate:function(value) { return value === '' || RED.validators.number(); }},
|
||||
removeOlderUnit: {value: '3600', required:true},
|
||||
cutout: {value: 0},
|
||||
useOneColor: {value: false},
|
||||
colors: {value: ['#1F77B4', '#AEC7E8', '#FF7F0E', '#2CA02C', '#98DF8A', '#D62728', '#FF9896', '#9467BD', '#C5B0D5']},
|
||||
useOldStyle: {value: false},
|
||||
outputs: {value: 1}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
inputLabels: function() { return this.chartType; },
|
||||
outputLabels: ["chart state"],
|
||||
align: "right",
|
||||
icon: "ui_chart.png",
|
||||
paletteLabel: 'chart',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'chart'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
var oldouts = this.outputs;
|
||||
if (RED.nodes.filterLinks({source:{id:this.id},sourcePort:1}).length > 0) { this.outputs = 2; }
|
||||
else { this.outputs = 1; }
|
||||
if (this.outputs !== oldouts) { this.changed = true; }
|
||||
if (!$("#node-input-chartType").val()) {
|
||||
$("#node-input-chartType").val("line");
|
||||
}
|
||||
if (this.useOldStyle === undefined) {
|
||||
$("#node-input-useOldStyle").prop('checked', true);
|
||||
}
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
$("#node-input-chartType").on("change", function() {
|
||||
$("#legend-show").hide();
|
||||
if ($(this).val() === "horizontalBar") {
|
||||
$("#y-label-show").hide();
|
||||
$("#x-label-show").show();
|
||||
}
|
||||
else {
|
||||
$("#y-label-show").show();
|
||||
$("#x-label-show").hide();
|
||||
}
|
||||
if ($(this).val() === "line") {
|
||||
$("#x-axis-show").show();
|
||||
$("#x-axis-label-show").show();
|
||||
$("#interpolate-show").show();
|
||||
$("#legend-show").show();
|
||||
$("#y-axis-show").show();
|
||||
$("#hole-size-show").hide();
|
||||
$("#show-dot-field").show();
|
||||
$("#show-useOneColor").hide();
|
||||
}
|
||||
else {
|
||||
$("#x-axis-show").hide();
|
||||
$("#x-axis-label-show").hide();
|
||||
$("#interpolate-show").hide();
|
||||
$("#show-dot-field").hide();
|
||||
if (($(this).val() === "bar")||($(this).val() === "horizontalBar")) {
|
||||
$("#show-useOneColor").show();
|
||||
$("#legend-show").show();
|
||||
}
|
||||
else {
|
||||
$("#show-useOneColor").hide();
|
||||
}
|
||||
if ($(this).val() === "pie") {
|
||||
$("#y-axis-show").hide();
|
||||
$("#legend-show").show();
|
||||
$("#hole-size-show").show();
|
||||
}
|
||||
else {
|
||||
$("#y-axis-show").show();
|
||||
$("#hole-size-show").hide();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
var setColour = function(id, value) {
|
||||
$(id).val(value);
|
||||
$(id).css("background-color", value);
|
||||
var rgb = tinycolor(value).toRgb();
|
||||
var level = ((rgb.r*299) + (rgb.g*587) + (rgb.b*114))/1000;
|
||||
var textColor = (level >= 128) ? '#111111' : '#eeeeee';
|
||||
$(id).css("color", textColor);
|
||||
}
|
||||
$(".series-color").on("change", function() {
|
||||
setColour("#"+$(this).attr("id"), $(this).val());
|
||||
});
|
||||
var oval = $("#node-input-xformat").val();
|
||||
if (!oval) { $("#node-input-xformat").val("HH:mm:ss"); }
|
||||
var odef = 'custom';
|
||||
if (oval === "HH:mm:ss") { odef = oval; }
|
||||
if (oval === "HH:mm") { odef = oval; }
|
||||
if (oval === "Y-M-D") { odef = oval; }
|
||||
if (oval === "D/M") { odef = oval; }
|
||||
if (oval === "dd HH:mm") { odef = oval; }
|
||||
if (oval === "auto") { odef = oval; }
|
||||
var ohms = {value:"HH:mm:ss", label:"HH:mm:ss", hasValue:false};
|
||||
var ohm = {value:"HH:mm", label:"HH:mm", hasValue:false};
|
||||
var oymd = {value:"Y-M-D", label:"Year-Month-Date", hasValue:false};
|
||||
var odm = {value:"D/M", label:"Date/Month", hasValue:false};
|
||||
var oahm = {value:"dd HH:mm", label:"Day HH:mm", hasValue:false};
|
||||
var ocus = {value:"custom", label:"custom", icon:"red/images/typedInput/az.png"};
|
||||
var oaut = {value:"auto", label:"automatic", hasValue:false};
|
||||
$("#node-input-xformat").typedInput({
|
||||
default: odef,
|
||||
types:[ ohms, ohm, oahm, odm, oymd, ocus, oaut ]
|
||||
});
|
||||
var defaultColors = ['#1F77B4', '#AEC7E8', '#FF7F0E', '#2CA02C', '#98DF8A', '#D62728', '#FF9896', '#9467BD', '#C5B0D5'];
|
||||
|
||||
if (this.colors) {
|
||||
for (var i=0; i<this.colors.length; i++) {
|
||||
var value = this.colors[i] || defaultColors[i];
|
||||
setColour("#node-input-color"+(i+1), value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var c=0; c<defaultColors.length; c++) {
|
||||
setColour("#node-input-color"+(c+1), defaultColors[c]);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
oneditsave: function() {
|
||||
if ($("#node-input-xformat").typedInput('type') !== 'custom') {
|
||||
$("#node-input-xformat").val($("#node-input-xformat").typedInput('type'));
|
||||
}
|
||||
this.colors = [$("#node-input-color1").val(),$("#node-input-color2").val(),$("#node-input-color3").val(),
|
||||
$("#node-input-color4").val(),$("#node-input-color5").val(),$("#node-input-color6").val(),
|
||||
$("#node-input-color7").val(),$("#node-input-color8").val(),$("#node-input-color9").val()];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_chart">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label" placeholder="optional chart title">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-removeOlder"><i class="fa fa-line-chart"></i> Type</label>
|
||||
<select id="node-input-chartType" style="width:159px; font-family:'FontAwesome','Helvetica Neue', Helvetica, Arial, sans-serif">
|
||||
<option value="line">  Line chart</option>
|
||||
<option value="bar">  Bar chart</option>
|
||||
<option value="horizontalBar">  Bar chart (H)</option>
|
||||
<option value="pie">  Pie chart</option>
|
||||
<option value="polar-area">  Polar area chart</option>
|
||||
<option value="radar">  Radar chart</option>
|
||||
</select>
|
||||
<div id="show-dot-field" style="display:inline-block;">
|
||||
<input type="checkbox" id="node-input-dot" style="display:inline-block; width:auto; vertical-align:baseline; margin-left:40px; margin-right:5px;">enlarge points
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" id="x-axis-show">
|
||||
<label for="node-input-removeOlder">X-axis</label>
|
||||
<label for="node-input-removeOlder" style="width:auto">last</label>
|
||||
<input type="text" id="node-input-removeOlder" style="width:50px;">
|
||||
<select id="node-input-removeOlderUnit" style="width:80px;">
|
||||
<option value="1">seconds</option>
|
||||
<option value="60">minutes</option>
|
||||
<option value="3600">hours</option>
|
||||
<option value="86400">days</option>
|
||||
<option value="604800">weeks</option>
|
||||
</select>
|
||||
<label for="node-input-removeOlderPoints" style="width:auto; margin-left:10px; margin-right:10px;">OR</label>
|
||||
<input type="text" id="node-input-removeOlderPoints" style="width:60px;" placeholder="1000">
|
||||
<span style="margin-left:5px;">points</span>
|
||||
</div>
|
||||
<div class="form-row" id="x-axis-label-show">
|
||||
<label for="node-input-xformat">X-axis Label</label>
|
||||
<input type="text" id="node-input-xformat" style="width:268px;">
|
||||
</div>
|
||||
<div class="form-row" id="y-axis-show">
|
||||
<label id="y-label-show" for="node-input-ymin">Y-axis</label>
|
||||
<label id="x-label-show" for="node-input-ymin">X-axis</label>
|
||||
<label for="node-input-ymin" style="width:auto">min</label>
|
||||
<input type="text" id="node-input-ymin" style="width:92px">
|
||||
<label for="not-input-ymax" style="width:auto; margin-left:20px;">max</label>
|
||||
<input type="text" id="node-input-ymax" style="width:92px">
|
||||
</div>
|
||||
<div class="form-row" id="legend-show">
|
||||
<label for="node-input-legend">Legend</label>
|
||||
<select id="node-input-legend" style="width:120px;">
|
||||
<option value="false">None</option>
|
||||
<option value="true">Show</option>
|
||||
</select>
|
||||
<span id="interpolate-show"> Interpolate
|
||||
<select id="node-input-interpolate" style="width:120px;">
|
||||
<option value="linear">linear</option>
|
||||
<option value="step">step</option>
|
||||
<option value="bezier">bezier</option>
|
||||
</select>
|
||||
</span>
|
||||
<span id="hole-size-show"> Cutout
|
||||
<input type="text" id="node-input-cutout" style="width:35px"> %
|
||||
</span>
|
||||
</div>
|
||||
<div id="show-useOneColor" style="display:none; height:24px;">
|
||||
<input type="checkbox" id="node-input-useOneColor" style="display:inline-block; width:auto; vertical-align:baseline; margin-left:105px; margin-right:5px;">Use first colour for all bars
|
||||
</div>
|
||||
<div class="form-row" id="ui-chart-colours">
|
||||
<label for="node-input-color1">Series Colours</label>
|
||||
<input type="color" id="node-input-color1" class="series-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color2" class="series-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color3" class="series-color" style="width:100px;"/>
|
||||
<div style="margin-top:5px; margin-left:104px;">
|
||||
<input type="color" id="node-input-color4" class="series-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color5" class="series-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color6" class="series-color" style="width:100px;"/>
|
||||
</div>
|
||||
<div style="margin-top:5px; margin-left:104px;">
|
||||
<input type="color" id="node-input-color7" class="series-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color8" class="series-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color9" class="series-color" style="width:100px;"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-nodata">Blank label</label>
|
||||
<input type="text" id="node-input-nodata" placeholder="display this text before valid data arrives">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input type="checkbox" id="node-input-useOldStyle" style="display:inline-block; width:auto; vertical-align:baseline; margin-left:105px; margin-right:5px;">Use deprecated (pre 2.5.0) data format.
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_chart">
|
||||
<p>Plots the input values on a chart. This can either be a time based line chart, a bar chart (vertical or horizontal),
|
||||
or a pie chart.</p>
|
||||
<p>Each input <code>msg.payload</code> value will be converted to a number. If the
|
||||
conversion fails, the message is ignored.</p>
|
||||
<p>Minimum and Maximum <b>Y</b> axis values are optional. The graph will auto-scale to any values received.</p>
|
||||
<p>Multiple series can be shown on the same chart by using a different <code>msg.topic</code>
|
||||
value on each input message. Multiple bars of the same series can be shown by using the <code>msg.label</code> property.</p>
|
||||
<p>The <b>X</b> axis defines a time window or a maximum number of points to display. Older data will be automatically removed from the graph.
|
||||
The axis labels can be formatted using a <a href="https://momentjs.com/docs/#/displaying/format/" target="_blank">
|
||||
Moment.js time formatted</a> string.</p>
|
||||
<p>Inputting a <code>msg.payload</code> containing a blank array <code>[]</code> will clear the chart.</p>
|
||||
<p>See <b><a href="https://github.com/node-red/node-red-dashboard/blob/master/Charts.md" target="_new">this information</a></b>
|
||||
for how to pre-format data to be passed in as a complete chart.</p>
|
||||
<p>The <b>Blank label</b> field can be used to display some text before any valid data is received.</p>
|
||||
<p>The label can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
|
||||
<p>The node output contains an array of the chart state that can be persisted if needed. This can be passed
|
||||
into the chart node to re-display the persisted data.</p>
|
||||
</script>
|
||||
280
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_chart.js
generated
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
var ChartIdList = {};
|
||||
|
||||
function ChartNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.chartType = config.chartType || "line";
|
||||
this.newStyle = (!config.hasOwnProperty("useOldStyle") || (config.useOldStyle === true)) ? false : true;
|
||||
var node = this;
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
if (config.width === "0") { delete config.width; }
|
||||
if (config.height === "0") { delete config.height; }
|
||||
// number of pixels wide the chart will be... 43 = sizes.sx - sizes.px
|
||||
//var pixelsWide = ((config.width || group.config.width || 6) - 1) * 43 - 15;
|
||||
if (!tab || !group) { return; }
|
||||
var dnow = Date.now();
|
||||
var options = {
|
||||
emitOnlyNewValues: true,
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
control: {
|
||||
type: 'chart',
|
||||
look: node.chartType,
|
||||
order: config.order,
|
||||
label: config.label,
|
||||
legend: config.legend || false,
|
||||
interpolate: config.interpolate,
|
||||
nodata: config.nodata,
|
||||
width: parseInt(config.width || group.config.width || 6),
|
||||
height: parseInt(config.height || group.config.width/2+1 || 4),
|
||||
ymin: config.ymin,
|
||||
ymax: config.ymax,
|
||||
dot: config.dot || false,
|
||||
xformat : config.xformat || "HH:mm:ss",
|
||||
cutout: parseInt(config.cutout || 0),
|
||||
colors: config.colors,
|
||||
useOneColor: config.useOneColor || false,
|
||||
animation: false,
|
||||
spanGaps: false,
|
||||
options: {},
|
||||
},
|
||||
convertBack: function(data) {
|
||||
if (node.newStyle) {
|
||||
if (data && data[0] && data[0].hasOwnProperty("values")) {
|
||||
return [data[0].values];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (data && data[0]) {
|
||||
if (data[0] && data[0].hasOwnProperty("values") && data[0].values.hasOwnProperty("series") ) {
|
||||
var o = [];
|
||||
for (var i=0; i<data[0].values.series.length; i++) {
|
||||
if (data[0].values.data[i] !== undefined) {
|
||||
if (node.chartType !== "line") {
|
||||
o.push({ key:data[0].values.series[i], values:data[0].values.data[i][0] });
|
||||
}
|
||||
else {
|
||||
var d = data[0].values.data[i].map(function(i) { return [i.x, i.y]; });
|
||||
o.push({ key:data[0].values.series[i], values:d });
|
||||
}
|
||||
}
|
||||
}
|
||||
data = o;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
convert: function(value, oldValue, msg) {
|
||||
var converted = {};
|
||||
if (ChartIdList.hasOwnProperty(node.id) && ChartIdList[node.id] !== node.chartType) {
|
||||
value = [];
|
||||
}
|
||||
if (this.control.look !== node.chartType) {
|
||||
if ((this.control.look === "line") || (node.chartType === "line")) { value = []; }
|
||||
node.chartType = this.control.look;
|
||||
}
|
||||
ChartIdList[node.id] = node.chartType;
|
||||
if (Array.isArray(value)) {
|
||||
if (value.length === 0) { // reset chart
|
||||
converted.update = false;
|
||||
converted.updatedValues = [];
|
||||
return converted;
|
||||
}
|
||||
// New style
|
||||
if (!value[0].hasOwnProperty("key")) {
|
||||
if (value[0].hasOwnProperty("series") && value[0].hasOwnProperty("data")) {
|
||||
var flag = true;
|
||||
for (var dd = 0; dd < value[0].data.length; dd++ ) {
|
||||
if (!isNaN(value[0].data[dd][0])) { flag = false; }
|
||||
}
|
||||
if (node.chartType === "line") {
|
||||
if (flag) { delete value[0].labels; }
|
||||
}
|
||||
else if (node.chartType === "bar" || node.chartType === "horizontalBar") {
|
||||
if (flag) {
|
||||
var tmp = [];
|
||||
for (var d=0; d<value[0].data.length; d++) {
|
||||
tmp.push([value[0].data[d]]);
|
||||
}
|
||||
value[0].data = tmp;
|
||||
var tmp2 = value[0].series;
|
||||
value[0].series = value[0].labels;
|
||||
value[0].labels = tmp2;
|
||||
}
|
||||
}
|
||||
value = [{ key:node.id, values:(value[0] || {series:[], data:[], labels:[]}) }];
|
||||
}
|
||||
else {
|
||||
node.warn("Bad data inject");
|
||||
value = oldValue;
|
||||
}
|
||||
}
|
||||
// Old style
|
||||
else {
|
||||
if (node.chartType !== "line") {
|
||||
var nb = { series:[], data:[], labels:[] };
|
||||
for (var v in value) {
|
||||
if (value.hasOwnProperty(v)) {
|
||||
nb.data.push([ value[v].values ]);
|
||||
nb.series.push(value[v].key);
|
||||
}
|
||||
}
|
||||
value = [{key:node.id, values:nb}];
|
||||
}
|
||||
else {
|
||||
if (value[0] && value[0].hasOwnProperty("values")) {
|
||||
if (Array.isArray(value[0].values)) { // Handle "old" style data array
|
||||
var na = {series:[], data:[]};
|
||||
for (var n=0; n<value.length; n++) {
|
||||
na.series.push(value[n].key);
|
||||
na.data.push(value[n].values.map(function(i) {
|
||||
return {x:i[0], y:i[1]};
|
||||
}));
|
||||
}
|
||||
value = [{ key:node.id, values:na }];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log("RETURN",JSON.stringify(value));
|
||||
converted.update = false;
|
||||
converted.updatedValues = value;
|
||||
}
|
||||
else {
|
||||
if (value === false) { value = null; } // let false also create gaps in chart
|
||||
if (value !== null) { // let null object through for gaps
|
||||
value = parseFloat(value); // only handle numbers
|
||||
if (isNaN(value)) { return; } // return if not a number
|
||||
}
|
||||
converted.newPoint = true;
|
||||
var label = msg.label || " ";
|
||||
var series = msg.series || msg.topic || "";
|
||||
//if (node.chartType === "bar" || node.chartType === "horizontalBar" || node.chartType === "pie") {
|
||||
if (node.chartType !== "line") {
|
||||
if (!node.newStyle || !msg.series) {
|
||||
label = msg.topic || msg.label || " ";
|
||||
series = msg.series || "";
|
||||
}
|
||||
}
|
||||
if ((!oldValue) || (oldValue.length === 0)) {
|
||||
oldValue = [{ key:node.id, values:{ series:[], data:[], labels:[] } }];
|
||||
}
|
||||
//if (node.chartType === "line" || node.chartType === "pie" || node.chartType === "bar" || node.chartType === "horizontalBar" || node.chartType === "radar") { // Line, Bar and Radar
|
||||
var refill = false;
|
||||
if (node.chartType === "line") { label = ""; }
|
||||
var s = oldValue[0].values.series.indexOf(series);
|
||||
if (!oldValue[0].values.hasOwnProperty("labels")) { oldValue[0].values.labels = []; }
|
||||
var l = oldValue[0].values.labels.indexOf(label);
|
||||
if (s === -1) {
|
||||
oldValue[0].values.series.push(series);
|
||||
s = oldValue[0].values.series.length - 1;
|
||||
oldValue[0].values.data[s] = [];
|
||||
if (l > 0) { refill = true; }
|
||||
}
|
||||
if (l === -1) {
|
||||
oldValue[0].values.labels.push(label);
|
||||
l = oldValue[0].values.labels.length - 1;
|
||||
if (l > 0) { refill = true; }
|
||||
}
|
||||
if (node.chartType === "line") {
|
||||
var time;
|
||||
if (msg.timestamp !== undefined) { time = new Date(msg.timestamp).getTime(); }
|
||||
else { time = new Date().getTime(); }
|
||||
var limitOffsetSec = parseInt(config.removeOlder) * parseInt(config.removeOlderUnit);
|
||||
var limitTime = time - limitOffsetSec * 1000;
|
||||
if (time < limitTime) { return oldValue; } // ignore if too old for window
|
||||
var point = { "x":time, "y":value };
|
||||
oldValue[0].values.data[s].push(point);
|
||||
converted.newPoint = [{ key:node.id, update:true, values:{ series:series, data:point, labels:label } }];
|
||||
var rc = 0;
|
||||
for (var u = 0; u < oldValue[0].values.data[s].length; u++) {
|
||||
if (oldValue[0].values.data[s][u].x >= limitTime) {
|
||||
break; // stop as soon as we are in time window.
|
||||
}
|
||||
else {
|
||||
oldValue[0].values.data[s].shift();
|
||||
rc += 1;
|
||||
}
|
||||
}
|
||||
if (config.removeOlderPoints) {
|
||||
while (oldValue[0].values.data[s].length > config.removeOlderPoints) {
|
||||
oldValue[0].values.data[s].shift();
|
||||
rc += 1;
|
||||
}
|
||||
}
|
||||
if (rc > 0) { converted.newPoint[0].remove = rc; }
|
||||
var swap; // insert correctly if a timestamp was earlier.
|
||||
for (var t = oldValue[0].values.data[s].length-2; t>=0; t--) {
|
||||
if (oldValue[0].values.data[s][t].x <= time) {
|
||||
break; // stop if we are in the right place
|
||||
}
|
||||
else {
|
||||
swap = oldValue[0].values.data[s][t];
|
||||
oldValue[0].values.data[s][t] = oldValue[0].values.data[s][t+1];
|
||||
oldValue[0].values.data[s][t+1] = swap;
|
||||
}
|
||||
}
|
||||
if (swap) { converted.newPoint = true; } // if inserted then update whole chart
|
||||
|
||||
if (Date.now() > (dnow + 60000)) {
|
||||
dnow = Date.now();
|
||||
for (var x = 0; x < oldValue[0].values.data.length; x++) {
|
||||
for (var y = 0; y < oldValue[0].values.data[x].length; y++) {
|
||||
if (oldValue[0].values.data[x][y].x >= limitTime) {
|
||||
break; // stop as soon as we are in time window.
|
||||
}
|
||||
else {
|
||||
oldValue[0].values.data[x].shift();
|
||||
converted.newPoint = true;
|
||||
y = y - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
oldValue[0].values.data[s][l] = value;
|
||||
if (refill) {
|
||||
for (var i = 0; i < oldValue[0].values.series.length; i++) {
|
||||
for (var k = 0; k < oldValue[0].values.labels.length; k++) {
|
||||
oldValue[0].values.data[i][k] = oldValue[0].values.data[i][k] || null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
converted.update = true;
|
||||
converted.updatedValues = oldValue;
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
};
|
||||
|
||||
var chgtab = function() {
|
||||
node.receive({payload:"R"});
|
||||
};
|
||||
ui.ev.on('changetab', chgtab);
|
||||
|
||||
var done = ui.add(options);
|
||||
|
||||
var st = setTimeout(function() {
|
||||
node.emit("input",{payload:"start"}); // trigger a redraw at start to flush out old data.
|
||||
if (node.wires.length === 2) { // if it's an old version of the node honour it
|
||||
node.send([null, {payload:"restore", for:node.id}]);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
node.on("close", function() {
|
||||
if (st) { clearTimeout(st); }
|
||||
ui.ev.removeListener('changetab', chgtab);
|
||||
done();
|
||||
})
|
||||
}
|
||||
RED.nodes.registerType("ui_chart", ChartNode);
|
||||
};
|
||||
151
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_colour_picker.html
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_colour_picker',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
format: {value: 'hex'},
|
||||
outformat: {value: 'string'},
|
||||
showSwatch: {value: true},
|
||||
showPicker: {value: false},
|
||||
showValue: {value: false},
|
||||
showHue: {value: false},
|
||||
showAlpha: {value: false},
|
||||
showLightness: {value: true},
|
||||
square: {value: "false"},
|
||||
dynOutput: {value: "false"},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
passthru: {value: true},
|
||||
topic: {value: ''}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: function() { return this.format; },
|
||||
icon: "ui_colour_picker.png",
|
||||
paletteLabel: 'colour picker',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'colour picker'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
if (this.square === undefined) {
|
||||
this.square = "false";
|
||||
$("#node-input-square").val("false");
|
||||
}
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
$("#node-input-format").on("change", function() {
|
||||
if ($(this).val() === "hex") {
|
||||
$("#node-alpha-control").hide();
|
||||
}
|
||||
else {
|
||||
$("#node-alpha-control").show();
|
||||
}
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if (!$("#node-input-showPicker").is(':checked') && !$("#node-input-showValue").is(':checked')) {
|
||||
$("#node-input-showSwatch").prop('checked', true);
|
||||
this.showSwatch = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_colour_picker">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-format"><i class="fa fa-keyboard-o"></i> Format</label>
|
||||
<select id="node-input-format" style="width:156px;">
|
||||
<option value="hex">hex</option>
|
||||
<option value="hex8">hex8</option>
|
||||
<option value="hsl">hsl</option>
|
||||
<option value="hsv">hsv</option>
|
||||
<option value="rgb">rgb</option>
|
||||
</select>
|
||||
<select id="node-input-square" style="width:130px; margin-left:30px">
|
||||
<option value="false">round</option>
|
||||
<option value="true">square</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label> Show hue slider : <input type="checkbox" id="node-input-showHue" style="display:inline-block; width:auto; vertical-align:baseline;">
|
||||
<br/>
|
||||
<label> </label> Show lightness slider : <input type="checkbox" id="node-input-showLightness" style="display:inline-block; width:auto; vertical-align:baseline;">
|
||||
<br/>
|
||||
<span id="node-alpha-control"><label> </label> Show transparency slider : <input type="checkbox" id="node-input-showAlpha" style="display:inline-block; width:auto; vertical-align:baseline;"></span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
If width is 4 or greater:<br/>
|
||||
<label> </label>
|
||||
Always show swatch : <input type="checkbox" checked id="node-input-showSwatch" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
<br/>
|
||||
<label> </label>
|
||||
Always show picker : <input type="checkbox" checked id="node-input-showPicker" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
<br/>
|
||||
<label> </label>
|
||||
Always show value field : <input type="checkbox" checked id="node-input-showValue" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
|
||||
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-dynOutput"><i class="fa fa-envelope-o"></i> Send</label>
|
||||
<select id="node-input-dynOutput" style="width:60%">
|
||||
<option value="false">one value when released/closed</option>
|
||||
<option value="true">multiple values during editing</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-outformat" style="padding-left: 25px; margin-right: -25px">Payload</label>
|
||||
<select id="node-input-outformat" style="width:60%">
|
||||
<option value="string">current value as a string</option>
|
||||
<option value="object">current value as an object</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic" style="padding-left: 25px; margin-right: -25px">Topic</label>
|
||||
<input type="text" id="node-input-topic" placeholder="optional topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_colour_picker">
|
||||
<p>Adds a colour picker to the dashboard.</p>
|
||||
<p>If the group width is 4 or greater then the picker can be set to be visible at all times.</p>
|
||||
<p><b>Format</b> can be rgb, hex, hex8, hsv, or hsl. Transparency is supported for all except hex.</p>
|
||||
<p>If a <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.</p>
|
||||
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the input.</p>
|
||||
<p>If set to ‘pass through mode’ a message arriving on the input will be evaluated for any colour format available
|
||||
as Format. If the conversion fails #000000 will be used.</p>
|
||||
</script>
|
||||
57
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_colour_picker.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
var tc = require('../dist/js/tinycolor-min');
|
||||
|
||||
function ColourPickerNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.format = config.format;
|
||||
this.outformat = config.outformat;
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
forwardInputMessages: config.passthru,
|
||||
control: {
|
||||
type: 'colour-picker',
|
||||
label: config.label,
|
||||
format: config.format,
|
||||
showPicker: config.showPicker,
|
||||
showSwatch: config.showSwatch,
|
||||
showValue: config.showValue,
|
||||
showHue: config.showHue,
|
||||
showAlpha: config.showAlpha,
|
||||
showLightness: config.showLightness,
|
||||
square: (config.square == 'true') || false,
|
||||
dynOutput: config.dynOutput,
|
||||
allowEmpty: true,
|
||||
order: config.order,
|
||||
value: '',
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1
|
||||
},
|
||||
beforeSend: function (msg) {
|
||||
if (node.outformat === 'object') {
|
||||
var pay = tc(msg.payload);
|
||||
if (node.format === 'rgb') { msg.payload = pay.toRgb(); }
|
||||
if (node.format === 'hsl') { msg.payload = pay.toHsl(); }
|
||||
if (node.format === 'hsv') { msg.payload = pay.toHsv(); }
|
||||
}
|
||||
msg.topic = config.topic || msg.topic;
|
||||
},
|
||||
convert: function(p,o,m) {
|
||||
if (m.payload === undefined) { return; }
|
||||
var colour = tc(m.payload);
|
||||
return colour.toString(config.format);
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_colour_picker", ColourPickerNode);
|
||||
};
|
||||
81
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_date_picker.html
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_date_picker',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: 'date'},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
passthru: {value: true},
|
||||
topic: {value: ''}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: ["epoch mS"],
|
||||
icon: "ui_date_picker.png",
|
||||
paletteLabel: 'date picker',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'date picker'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_date_picker">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
|
||||
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="padding-left:25px; margin-right:-25px">Payload</label>
|
||||
<label style="width:auto">Current value</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
|
||||
<input type="text" id="node-input-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_date_picker">
|
||||
<p>Adds a date picker widget to the user interface.</p>
|
||||
<p>The date display can be formatted in the Dashboard - Site tab using <a href="https://momentjs.com/docs/#/displaying/">
|
||||
moment.js</a> formatting. For example <code>MM/DD/YYYY</code>, <code>Do MMM YYYY</code> or <code>YYYY-MM-DD</code>.</p>
|
||||
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the input.</p>
|
||||
</script>
|
||||
47
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_date_picker.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function DatePickerNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
forwardInputMessages: config.passthru,
|
||||
control: {
|
||||
type: 'date-picker',
|
||||
label: config.label,
|
||||
order: config.order,
|
||||
ddd : new Date(),
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1
|
||||
},
|
||||
convert: function (p,o,m) {
|
||||
var d = new Date(m.payload);
|
||||
this.control.ddd = d;
|
||||
return m.payload;
|
||||
},
|
||||
beforeEmit: function (msg, value) {
|
||||
if (value === undefined) { return; }
|
||||
value = new Date(value);
|
||||
return { msg:msg, value:value };
|
||||
},
|
||||
convertBack: function (value) {
|
||||
var d = new Date(value).valueOf();
|
||||
return d;
|
||||
},
|
||||
beforeSend: function (msg) {
|
||||
msg.topic = config.topic || msg.topic;
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_date_picker", DatePickerNode);
|
||||
};
|
||||
163
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_dropdown.html
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_dropdown',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: ''},
|
||||
tooltip: {value: ''},
|
||||
place: {value: 'Select option'},
|
||||
group: {type: 'ui_group', required:true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
passthru: {value: true},
|
||||
options: {value:[{value: '', label : ''}]},
|
||||
payload: {value: ''},
|
||||
topic: {value: ''}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "ui_dropdown.png",
|
||||
paletteLabel: 'dropdown',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'dropdown'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
|
||||
function generateOption(i, option) {
|
||||
var container = $('<li/>',{style:"background: #fff; margin:0; padding:8px 0px 0px; border-bottom: 1px solid #ccc;"});
|
||||
var row = $('<div/>').appendTo(container);
|
||||
var row2 = $('<div/>',{style:"padding-top:5px; padding-left:175px;"}).appendTo(container);
|
||||
var row3 = $('<div/>',{style:"padding-top:5px; padding-left:120px;"}).appendTo(container);
|
||||
|
||||
$('<i style="color:#eee; cursor:move; margin-left:3px;" class="node-input-option-handle fa fa-bars"></i>').appendTo(row);
|
||||
|
||||
var valueField = $('<input/>',{class:"node-input-option-value",type:"text",style:"margin-left:7px; width:calc(50% - 32px);", placeholder: 'Value',value:option.value}).appendTo(row).typedInput({default:option.type||'str',types:['str','num','bool']});
|
||||
var labelField = $('<input/>',{class:"node-input-option-label",type:"text",style:"margin-left:7px; width:calc(50% - 32px);", placeholder: 'Label', value:option.label}).appendTo(row);
|
||||
|
||||
var finalspan = $('<span/>',{style:"float:right; margin-right:8px;"}).appendTo(row);
|
||||
var deleteButton = $('<a/>',{href:"#",class:"editor-button editor-button-small", style:"margin-top:7px; margin-left:5px;"}).appendTo(finalspan);
|
||||
$('<i/>',{class:"fa fa-remove"}).appendTo(deleteButton);
|
||||
|
||||
deleteButton.click(function() {
|
||||
container.css({"background":"#fee"});
|
||||
container.fadeOut(300, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
|
||||
$("#node-input-option-container").append(container);
|
||||
}
|
||||
|
||||
$("#node-input-add-option").click(function() {
|
||||
generateOption($("#node-input-option-container").children().length+1, {});
|
||||
$("#node-input-option-container-div").scrollTop($("#node-input-option-container-div").get(0).scrollHeight);
|
||||
});
|
||||
|
||||
for (var i=0; i<this.options.length; i++) {
|
||||
var option = this.options[i];
|
||||
generateOption(i+1,option);
|
||||
}
|
||||
|
||||
$( "#node-input-option-container" ).sortable({
|
||||
axis: "y",
|
||||
handle:".node-input-option-handle",
|
||||
cursor: "move"
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
var options = $("#node-input-option-container").children();
|
||||
var node = this;
|
||||
node.options = [];
|
||||
options.each(function(i) {
|
||||
var option = $(this);
|
||||
var o = {
|
||||
label: option.find(".node-input-option-label").val(),
|
||||
value: option.find(".node-input-option-value").typedInput('value'),
|
||||
type: option.find(".node-input-option-value").typedInput('type')
|
||||
};
|
||||
if (option.find(".node-input-option-value").typedInput('type') === "num") {
|
||||
o.value = Number(o.value);
|
||||
}
|
||||
if (option.find(".node-input-option-value").typedInput('type') === "bool") {
|
||||
o.value = (o.value == "true");
|
||||
}
|
||||
node.options.push(o);
|
||||
});
|
||||
},
|
||||
oneditresize: function() {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_dropdown">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-tag"></i> Label</label>
|
||||
<input type="text" id="node-input-label" placeholder="optional label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
|
||||
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-place"><i class="fa fa-tag"></i> Placeholder</label>
|
||||
<input type="text" id="node-input-place" placeholder="optional placeholder">
|
||||
</div>
|
||||
<div class="form-row node-input-option-container-row" style="margin-bottom: 0px;width: 100%">
|
||||
<label for="node-input-width" style="vertical-align:top"><i class="fa fa-list-alt"></i> Options</label>
|
||||
<div id="node-input-option-container-div" style="box-sizing: border-box; border-radius: 5px; height: 257px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;display: inline-block; width: calc(70% + 15px);">
|
||||
<ol id="node-input-option-container" style=" list-style-type:none; margin: 0;"></ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<a href="#" class="editor-button editor-button-small" id="node-input-add-option" style="margin-top: 4px; margin-left: 103px;"><i class="fa fa-plus"></i> <span>option</span></a>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
|
||||
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
|
||||
<input type="text" id="node-input-topic" placeholder="optional msg.topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_dropdown">
|
||||
<p>Adds a dropdown select box to the user interface.</p>
|
||||
<p>Multiple value / label pairs can be added as required. If the label is not specified the
|
||||
value will be used for both.</p>
|
||||
<p>The configured value of the selected item will be returned as <code>msg.payload</code>.</p>
|
||||
<p>Setting <code>msg.payload</code> to the value will set the pre-selected choice in the dropdown.</p>
|
||||
<p>Optionally the <b>Topic</b> field can be used to set the <code>msg.topic</code> property.</p>
|
||||
<p>The Options may be configured by inputting <code>msg.options</code> containing an array.
|
||||
If just text then the value will be the same as the label, otherwise you can specify both by
|
||||
using an object of <code>"label":"value"</code> pairs :</p>
|
||||
<code>[ "Choice 1", "Choice 2", {"Choice 3":"3"} ]</code>
|
||||
</script>
|
||||
150
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_dropdown.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function DropdownNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.pt = config.passthru;
|
||||
this.state = [" "," "];
|
||||
var node = this;
|
||||
node.status({});
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var control = {
|
||||
type: 'dropdown',
|
||||
label: config.label,
|
||||
tooltip: config.tooltip,
|
||||
place: config.place || "Select option",
|
||||
order: config.order,
|
||||
value: config.payload || node.id,
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1
|
||||
};
|
||||
|
||||
for (var o=0; o<config.options.length; o++) {
|
||||
config.options[o].label = config.options[o].label || config.options[o].value;
|
||||
}
|
||||
control.options = config.options;
|
||||
|
||||
var emitOptions;
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
forwardInputMessages: config.passthru,
|
||||
control: control,
|
||||
|
||||
convert: function (payload, oldValue, msg) {
|
||||
// convert msg
|
||||
// as of now, only allow a full replacement of options
|
||||
// beforeEmit is only called when a node linked to us sends a msg
|
||||
// we are expecting to receive an "update options" msg
|
||||
// which we expect to be an array of new options
|
||||
|
||||
// for convenience, we pass an indication to the node connected to this dropdown
|
||||
// that this is an "update options" message coming from the input sender
|
||||
// 'beforeEmit' is called before 'beforeSend', so we may pass in that info
|
||||
// otherwise that convenience info would not be sent (would not cause any problems)...
|
||||
|
||||
emitOptions = {isOptionsValid:false, value:undefined, newOptions:undefined};
|
||||
do {
|
||||
if (!msg.options || !Array.isArray(msg.options)) { break; }
|
||||
emitOptions.newOptions = [];
|
||||
if (msg.options.length === 0) {
|
||||
emitOptions.isOptionsValid = true;
|
||||
break;
|
||||
}
|
||||
// could check whether or not all members have same type
|
||||
for (var i = 0; i < msg.options.length; i++) {
|
||||
var opt = msg.options[i];
|
||||
if (opt === undefined || opt === null) { continue; }
|
||||
|
||||
switch (typeof opt) {
|
||||
case 'number': {
|
||||
opt = "" + opt;
|
||||
emitOptions.newOptions.push({label:opt, value:opt});
|
||||
break;
|
||||
}
|
||||
case 'string': {
|
||||
emitOptions.newOptions.push({label:opt, value:opt});
|
||||
break;
|
||||
}
|
||||
case 'object': {
|
||||
// assuming object of {label:value}
|
||||
for (var m in opt) {
|
||||
if (opt.hasOwnProperty(m)) {
|
||||
emitOptions.newOptions.push({label:m, value:opt[m]});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// do nothing, just continue with next option
|
||||
}
|
||||
}
|
||||
// send null object on change of menu list
|
||||
if (emitOptions.newOptions.length > 0) { emitOptions.value = null; }
|
||||
// or send the preselected value
|
||||
if (msg.payload) { emitOptions.value = msg.payload; }
|
||||
emitOptions.isOptionsValid = true;
|
||||
} while (false);
|
||||
// finally adjust msg to reflect the input
|
||||
msg._fromInput = true;
|
||||
if (emitOptions.isOptionsValid) {
|
||||
control.options = emitOptions.newOptions;
|
||||
control.value = emitOptions.value;
|
||||
}
|
||||
else {
|
||||
if (msg.options) {
|
||||
node.error("ERR: Invalid Options", msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (msg.hasOwnProperty("payload")) {
|
||||
emitOptions.value = msg.payload;
|
||||
control.value = emitOptions.value;
|
||||
emitOptions._fromInput = true;
|
||||
return emitOptions;
|
||||
}
|
||||
// we do not overide payload here due to 'opt.emitOnlyNewValues' in ui.js
|
||||
// when undefined is returned, msg will not be forwarded
|
||||
return emitOptions.isOptionsValid ? emitOptions : undefined; // always pass entire object (newValue == oldValue)
|
||||
},
|
||||
|
||||
beforeEmit: function (msg, newValue) {
|
||||
return emitOptions;
|
||||
},
|
||||
|
||||
beforeSend: function (msg) {
|
||||
var val = "";
|
||||
if (msg._fromInput) {
|
||||
delete msg.options;
|
||||
msg.payload = emitOptions.value;
|
||||
}
|
||||
for (var i=0; i<control.options.length; i++) {
|
||||
if (control.options[i].value === msg.payload) { val = control.options[i].label; }
|
||||
}
|
||||
msg.topic = config.topic || msg.topic;
|
||||
if (node.pt) {
|
||||
node.status({shape:"dot",fill:"grey",text:val});
|
||||
}
|
||||
else {
|
||||
node.state[1] = val;
|
||||
node.status({shape:"dot",fill:"grey",text:node.state[1] + " | " + node.state[1]});
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!node.pt) {
|
||||
node.on("input", function(msg) {
|
||||
node.state[0] = msg.payload;
|
||||
node.status({shape:"dot",fill:"grey",text:node.state[0] + " | " + node.state[1]});
|
||||
});
|
||||
}
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_dropdown", DropdownNode);
|
||||
};
|
||||
314
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_form.html
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_form',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
options: {value:[{value:'', label :'', type:'', required:true}], validate:function(value) {
|
||||
if (value.length ) {
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
if (!value[i].value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, required:true},
|
||||
formValue:{value:{}},
|
||||
payload: {value: ''},
|
||||
submit: {value: "submit"},
|
||||
cancel: {value: "cancel"},
|
||||
topic: {value: ''}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "ui_form.png",
|
||||
paletteLabel: 'form',
|
||||
label: function() { return this.name || this.label || 'form'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
if ($("#node-input-submit").val() === null) { $("#node-input-submit").val("submit"); }
|
||||
if ($("#node-input-cancel").val() === null) { $("#node-input-cancel").val("cancel"); }
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
|
||||
this.resizeRule = function(option,newWidth) {
|
||||
//option.find(".node-input-option-type").width(newWidth);
|
||||
// option.find(".node-input-option-label").width(newWidth);
|
||||
// option.find(".node-input-option-value").width(newWidth);
|
||||
}
|
||||
|
||||
function generateOption(i, option) {
|
||||
var container = $('<li/>',{style:"background: #fff; margin:0; padding:8px 0px 0px; border-bottom: 1px solid #ccc;"});
|
||||
var row = $('<div/>').appendTo(container);
|
||||
var row2 = $('<div/>',{style:"padding-top:5px; padding-left:175px;"}).appendTo(container);
|
||||
var row3 = $('<div/>',{style:"padding-top:5px; padding-left:120px;"}).appendTo(container);
|
||||
|
||||
$('<i style="color:#eee; cursor:move; margin-left:3px;" class="node-input-option-handle fa fa-bars"></i>').appendTo(row);
|
||||
|
||||
var labelField = $('<input/>',{class:"node-input-option-label",type:"text",style:"margin-left:7px; width:20%;", placeholder: 'e.g. Name', value:option.label}).appendTo(row);//.typedInput({default:'str',types:['str', 'num']});
|
||||
var valueClass ="node-input-option-value"
|
||||
if (!option.value) { valueClass ="node-input-option-value input-error"; }
|
||||
var valueField = $('<input/>',{class:valueClass,type:"text",style:"margin-left: 7px; width: 20%;", placeholder: 'e.g. name',value:option.value}).appendTo(row);//.typedInput({default:'str',types:['str','num','bool']});
|
||||
valueField.keyup(function() {
|
||||
if ($(this).val() && $(this).hasClass('input-error')) {
|
||||
$(this).removeClass('input-error')
|
||||
}
|
||||
else {
|
||||
if (!$(this).val()) {
|
||||
$(this).addClass('input-error')
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
// var typeField = $('<input/>',{class:"node-input-option-type",type:"text",style:"margin-left: 7px; width: 135px;", placeholder: 'Type', value:option.type}).appendTo(row).typedInput({default:'str',types:['str', 'num']});
|
||||
var typeField = $('<select/>',{class:"node-input-option-type",type:"text",style:"margin-left:7px; width:16%"}).appendTo(row);//.typedInput({default:'str',types:['str', 'num']});
|
||||
|
||||
var arr = [
|
||||
{val : "text", text: 'Text'},
|
||||
{val : "multiline", text: 'Multiline'},
|
||||
{val : "number", text: 'Number'},
|
||||
{val : "email", text: 'E-mail'},
|
||||
{val : "password", text: 'Password'},
|
||||
{val : "checkbox", text: 'Checkbox'},
|
||||
{val : "switch", text: 'Switch'},
|
||||
{val : "date", text: 'Date'}
|
||||
];
|
||||
|
||||
//var sel = $('<select>').appendTo('body');
|
||||
$(arr).each(function() {
|
||||
var isSelected= false;
|
||||
if (option.type == this.val) {
|
||||
isSelected = true;
|
||||
}
|
||||
typeField.append($("<option>").attr('value',this.val).text(this.text).prop('selected',isSelected));
|
||||
});
|
||||
|
||||
//var labelForRequried = $('<span/>',{style:"margin: 10px;"}).text('Required').appendTo(row);
|
||||
var requiredContainer= $('<div/>',{style:"display:inline-block; height:34px; width:13%; vertical-align: middle"}).appendTo(row);
|
||||
var requiredInnerContainer= $('<div/>',{style:"left:35%; position:relative; width:30px"}).appendTo(requiredContainer);
|
||||
var reqRow=$("<label />",{class:"switch",style:"top:10px; width:30px;"}).appendTo(requiredInnerContainer);
|
||||
//var required = $('<input/>',{class:"node-input-option-required",style:"margin: 5px;width:19%",type:"checkbox", checked:option.required}).appendTo(row);//labelForRequried);//.typedInput({default:'str',types:['str', 'num']});
|
||||
var required = $('<input/>',{class:"node-input-option-required", type:"checkbox", checked:option.required, style:"vertical-align:top;"}).appendTo(reqRow);//labelForRequried);//.typedInput({default:'str',types:['str', 'num']});
|
||||
var reqDiv=$("<div />",{class:"slider round"}).appendTo(reqRow);
|
||||
var vis = option.rows ? 'visible' : 'hidden';
|
||||
var rowsField = $('<input/>',{class:"node-input-option-rows", type:"number", style:"width:10%;", placeholder:'Rows', value:option.rows }).css('visibility',vis).appendTo(row);
|
||||
|
||||
var finalspan = $('<div/>',{style:"display:inline-block; width:5%;"}).appendTo(row);
|
||||
var deleteButton = $('<a/>',{href:"#",class:"editor-button", style:"font-size:1.3em; left:45%; position:relative;"}).appendTo(finalspan);
|
||||
$('<i/>',{class:"fa fa-trash-o"}).appendTo(deleteButton);
|
||||
|
||||
typeField.change(function(e){
|
||||
if (e.target.value != 'multiline') {
|
||||
rowsField.val(undefined)
|
||||
option.rows = null;
|
||||
rowsField.css('visibility','hidden')
|
||||
} else {
|
||||
rowsField.css('visibility','visible')
|
||||
if (!rowsField[0].value) rowsField[0].value = 3;
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
deleteButton.click(function() {
|
||||
container.find(".node-input-option-value").removeAttr('required')
|
||||
container.css({"background":"#fee"});
|
||||
container.fadeOut(300, function() {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
|
||||
$("#node-input-option-container").append(container);
|
||||
}
|
||||
|
||||
$("#node-input-add-option").click(function() {
|
||||
generateOption($("#node-input-option-container").children().length+1, {});
|
||||
$("#node-input-option-container-div").scrollTop($("#node-input-option-container-div").get(0).scrollHeight);
|
||||
});
|
||||
|
||||
for (var i=0; i<this.options.length; i++) {
|
||||
var option = this.options[i];
|
||||
generateOption(i+1,option);
|
||||
}
|
||||
|
||||
$( "#node-input-option-container" ).sortable({
|
||||
axis: "y",
|
||||
handle:".node-input-option-handle",
|
||||
cursor: "move"
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
var options = $("#node-input-option-container").children();
|
||||
var node = this;
|
||||
node.options = [];
|
||||
node.formValue = {};
|
||||
options.each(function(i) {
|
||||
var option = $(this);
|
||||
var o = {
|
||||
label: option.find(".node-input-option-label").val(),//typedInput('value'),
|
||||
value: option.find(".node-input-option-value").val(),//typedInput('value'),
|
||||
type: option.find(".node-input-option-type").val(),//typedInput('value')
|
||||
required: option.find(".node-input-option-required").is(':checked'),
|
||||
rows: parseInt(option.find(".node-input-option-rows").val())
|
||||
};
|
||||
// o.value= o.value||o.label||(o.type+"_"+i);
|
||||
node.formValue[o.value]= o.type == "checkbox" || o.type == "switch" ? false : "";
|
||||
node.options.push(o);
|
||||
});
|
||||
},
|
||||
oneditresize: function() {
|
||||
var options = $("#node-input-option-container").children();
|
||||
var newWidth = ($("#node-input-option-container").width() - 175)/2;
|
||||
var node = this;
|
||||
options.each(function(i) {
|
||||
node.resizeRule($(this),newWidth);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script type="text/html" data-template-name="ui_form">
|
||||
|
||||
<style>
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.switch input {display:none;}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
left: 2px;
|
||||
bottom: 2px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #910000;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #2196F3;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(11px);
|
||||
-ms-transform: translateX(11px);
|
||||
transform: translateX(11px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-tag"></i> Label</label>
|
||||
<input type="text" id="node-input-label" placeholder="optional label">
|
||||
</div>
|
||||
<div class="form-row node-input-option-container-row" style="margin-bottom:0px; width:100%; min-width:520px">
|
||||
<label style="vertical-align:top;"><i class="fa fa-list-alt"></i> Form elements</label>
|
||||
<div style="display:inline-block; width:78%; border:1px solid #ccc; border-radius:5px; box-sizing:border-box;">
|
||||
<div style="width:100%; display: inline-block; background-color:#f3f3f3; padding-top:10px; padding-buttom:10px; border-top:0px solid; border-radius:5px 5px 0 0; border-bottom:1px solid #ccc;">
|
||||
<div style="width:94%; display:inline-block; margin-left:27px">
|
||||
<div style="width:20%; text-align:center; float:left;">Label</div>
|
||||
<div style="width:20%; text-align:center; float:left; margin-left:9px">Name</div>
|
||||
<div style="margin-left:7px; width:16%; text-align:center; float:left; margin-left:9px">Type</div>
|
||||
<div style="width:16%; text-align:center; float:left;">Required</div>
|
||||
<div style="width:10%; text-align:center; float:left;">Rows</div>
|
||||
<div style="width:12%; text-align:center; float:left;">Remove</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="node-input-option-container-div" style=" height: 257px; padding: 5px; overflow-y:scroll;">
|
||||
<ol id="node-input-option-container" style=" list-style-type:none; margin: 0;"></ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<a href="#" class="editor-button editor-button-small" id="node-input-add-option" style="margin-top: 4px; margin-left: 103px;"><i class="fa fa-plus"></i> <span>element</span></a>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-submit"><i class="fa fa-square"></i> Buttons</label>
|
||||
<i class="fa fa-thumbs-o-up"></i> <input type="text" id="node-input-submit" placeholder="submit button text" style="width:35%;">
|
||||
<span style="margin-left:16px"><i class="fa fa-thumbs-o-down"></i></span>
|
||||
<input type="text" id="node-input-cancel" placeholder="cancel button text" style="width:35%;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
|
||||
<input type="text" id="node-input-topic" placeholder="optional msg.topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_form">
|
||||
<p>Adds a form to user interface.</p>
|
||||
<p>Helps to collect multiple value from the user on submit button click as an object in <code> msg.payload</code> </p>
|
||||
<p>Multiple input elements can be added using add elements button</p>
|
||||
<p>Each element contains following components:</p>
|
||||
<ul>
|
||||
<li> <b>Label</b> : Value that will be the label of the element in the user interface</li>
|
||||
<li> <b>Name</b> : Represents the key (variable name) in the <code>msg.payload</code> in which the value of the corresponding element present</li>
|
||||
<li> <b>Type</b> : Drop drown option to select the type of input element</li>
|
||||
<li> <b>Required</b> : On switching on the user has to supply the value before submitting</li>
|
||||
<li> <b>Rows</b> : number of UI rows for multiline text input</li>
|
||||
<li> <b>Delete</b> : To remove the current element form the form</li>
|
||||
</ul>
|
||||
<p>Optionally the <b>Topic</b> field can be used to set the <code>msg.topic</code> property.</p>
|
||||
<p>The Cancel button can be hidden by setting it's value to be blank "".</p>
|
||||
</script>
|
||||
38
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_form.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function FormNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
forwardInputMessages: false,
|
||||
control: {
|
||||
type: 'form',
|
||||
label: config.label,
|
||||
order: config.order,
|
||||
value: config.payload || node.id,
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || config.options.length ,
|
||||
options: config.options,
|
||||
formValue: config.formValue,
|
||||
submit: config.submit,
|
||||
cancel: config.cancel,
|
||||
sy: ui.getSizes().sy
|
||||
},
|
||||
beforeSend: function (msg) {
|
||||
msg.topic = config.topic || undefined;
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_form", FormNode);
|
||||
};
|
||||
183
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_gauge.html
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
<style>
|
||||
input.gauge-color {
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
input.gauge-color::-webkit-color-swatch {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_gauge',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(119, 198, 204)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v || 0;
|
||||
var currentGroup = $('#node-input-group').val() || this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
gtype: {value: 'gage'},
|
||||
title: {value: 'gauge'},
|
||||
label: {value: 'units'},
|
||||
format: {value: '{{value}}'},
|
||||
min: {value: 0, required: true, validate: RED.validators.number()},
|
||||
max: {value: 10, required: true, validate: RED.validators.number()},
|
||||
colors: {value: ["#00B500","#E6E600","#CA3838"]},
|
||||
seg1: {value: ""},
|
||||
seg2: {value: ""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
inputLabels: function() { return this.min+" - "+this.max; },
|
||||
align: "right",
|
||||
icon: "ui_gauge.png",
|
||||
paletteLabel: 'gauge',
|
||||
label: function() { return this.name || (~this.title.indexOf("{{") ? null : this.title) || ((this.gtype === "gage") ? "gauge" : this.gtype) || 'gauge'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
var setColour = function(id, value) {
|
||||
$(id).val(value);
|
||||
$(id).css("background-color", value);
|
||||
var rgb = tinycolor(value).toRgb();
|
||||
var level = ((rgb.r*299) + (rgb.g*587) + (rgb.b*114))/1000;
|
||||
var textColor = (level >= 128) ? '#111111' : '#eeeeee';
|
||||
$(id).css("color", textColor);
|
||||
}
|
||||
$(".gauge-color").on("change", function() {
|
||||
setColour("#"+$(this).attr("id"), $(this).val());
|
||||
});
|
||||
|
||||
var defaultColors = ['#00B500', '#E6E600', '#CA3838'];
|
||||
|
||||
if (this.colors) {
|
||||
for (var i=0; i<this.colors.length; i++) {
|
||||
var value = this.colors[i] || defaultColors[i];
|
||||
setColour("#node-input-color"+(i+1), value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var j=0; j<defaultColors.length; j++) {
|
||||
setColour("#node-input-color"+(j+1), defaultColors[j]);
|
||||
}
|
||||
}
|
||||
if (this.gtype === undefined) {
|
||||
this.gtype = "gage";
|
||||
$("#node-input-gtype").val("gage");
|
||||
}
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
$("#node-input-gtype").on("change", function() {
|
||||
if ($(this).val() === "wave") {
|
||||
$("#ui-gauge-format").hide();
|
||||
}
|
||||
else {
|
||||
$("#ui-gauge-format").show();
|
||||
}
|
||||
if (($(this).val() === "compass") || ($(this).val() === "wave")) {
|
||||
$("#ui-gauge-colours").hide();
|
||||
$("#ui-gauge-segments").hide();
|
||||
}
|
||||
else {
|
||||
$("#ui-gauge-colours").show();
|
||||
$("#ui-gauge-segments").show();
|
||||
}
|
||||
});
|
||||
$("#node-input-min").on("change", function() {
|
||||
$("#seg-min").text($(this).val());
|
||||
});
|
||||
$("#node-input-max").on("change", function() {
|
||||
$("#seg-max").text($(this).val());
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
this.colors = [$("#node-input-color1").val(),$("#node-input-color2").val(),$("#node-input-color3").val()];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_gauge">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-gtype"><i class="fa fa-list"></i> Type</label>
|
||||
<select id="node-input-gtype" style="width:200px !important">
|
||||
<option value="gage">Gauge</option>
|
||||
<option value="donut">Donut</option>
|
||||
<option value="compass">Compass</option>
|
||||
<option value="wave">Level</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="ui-gauge-labels">
|
||||
<div class="form-row">
|
||||
<label for="node-input-title"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-title">
|
||||
</div>
|
||||
<div class="form-row" id="ui-gauge-format">
|
||||
<label for="node-input-format"><i class="fa fa-i-cursor"></i> Value format</label>
|
||||
<input type="text" id="node-input-format" placeholder="{{value}}">
|
||||
</div>
|
||||
<div class="form-row" id="ui-gauge-units">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Units</label>
|
||||
<input type="text" id="node-input-label" placeholder="optional sub-label">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-min">Range</label>
|
||||
<span for="node-input-min">min</span>
|
||||
<input type="text" id="node-input-min" style="width:80px">
|
||||
<span for="node-input-max" style="margin-left:20px;">max</span>
|
||||
<input type="text" id="node-input-max" style="width:80px">
|
||||
</div>
|
||||
<div class="form-row" id="ui-gauge-colours">
|
||||
<label for="node-input-color1">Colour gradient</label>
|
||||
<input type="color" id="node-input-color1" class="gauge-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color2" class="gauge-color" style="width:100px;"/>
|
||||
<input type="color" id="node-input-color3" class="gauge-color" style="width:100px;"/>
|
||||
</div>
|
||||
<div class="form-row" id="ui-gauge-segments">
|
||||
<label>Sectors</label>
|
||||
<span id="seg-min" style="display:inline-block; width:40px;">0</span>...
|
||||
<input type="text" id="node-input-seg1" style="text-align:center; width:87px;" placeholder="optional"> ...
|
||||
<input type="text" id="node-input-seg2" style="text-align:center; width:87px;" placeholder="optional"> ...
|
||||
<span id="seg-max" style="display:inline-block; width:40px; text-align:right">10</span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_gauge">
|
||||
<p>Adds a gauge type widget to the user interface.</p>
|
||||
<p>The <code>msg.payload</code> is searched for a numeric <i>value</i> and is formatted in accordance with
|
||||
the defined <b>Value Format</b>, which can then be formatted using
|
||||
<a href="https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters" target="_blank">Angular filters</a>.</p>
|
||||
<p>For example : <code>{{value | number:1}}%</code> will round the value to one decimal place and append a % sign.</p>
|
||||
<p>The colours of each of 3 sectors can be specified and the gauge will blend between them.
|
||||
The colours should be specified in hex (#rrggbb) format.</p>
|
||||
<p>If you specify numbers for the sectors then the colours changes per sector.
|
||||
If not specified the colours are blended across the total range.</p>
|
||||
<p>The gauge has several modes. Regular gauge, donut, compass and wave.</p>
|
||||
<p>The label can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
|
||||
</script>
|
||||
85
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_gauge.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
module.exports = function (RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function GaugeNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.colors = config.colors || ["#00B500","#E6E600","#CA3838"];
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
if (config.width === "0") { delete config.width; }
|
||||
if (config.height === "0") { delete config.height; }
|
||||
if (config.height === "1") { config.hideMinMax = true; }
|
||||
node.autoheight = parseInt(group.config.width*0.5+1.5) || 4;
|
||||
if (config.gtype && config.gtype === "wave") { node.autoheight = parseInt(group.config.width*0.75+0.5); }
|
||||
if (config.gtype && config.gtype === "donut") { node.autoheight = parseInt(group.config.width -1); }
|
||||
if (config.gtype && config.gtype === "compass") { node.autoheight = parseInt(group.config.width -1); }
|
||||
|
||||
var sizes = ui.getSizes();
|
||||
var theme = ui.getTheme();
|
||||
if (theme === undefined) {
|
||||
theme = {"group-textColor":{value:"#000"}};
|
||||
theme["widget-textColor"] = {value:"#000"};
|
||||
theme["widget-backgroundColor"] = {value:'#1784be'};
|
||||
}
|
||||
|
||||
var gageoptions = {};
|
||||
gageoptions.lineWidth = {'theme-dark':0.75};
|
||||
gageoptions.pointerOptions = {'theme-dark':{color:'#8e8e93'}, 'theme-custom':theme["group-textColor"].value};
|
||||
gageoptions.backgroundColor = {'theme-dark':'#515151', 'theme-custom':theme["widget-textColor"].value };
|
||||
gageoptions.compassColor = {'theme-dark':'#0b8489', 'theme-light':'#1784be', 'theme-custom':theme["widget-backgroundColor"].value};
|
||||
|
||||
var waveoptions = {};
|
||||
waveoptions.circleColor = {'theme-dark':'#097479', 'theme-light':'#0094ce', 'theme-custom':theme["widget-backgroundColor"].value};
|
||||
waveoptions.waveColor = {'theme-dark':'#097479', 'theme-light':'#0094ce', 'theme-custom':theme["widget-backgroundColor"].value};
|
||||
waveoptions.textColor = {'theme-dark':'#0b8489', 'theme-light':'#1784be', 'theme-custom':theme["widget-textColor"].value};
|
||||
waveoptions.waveTextColor = {'theme-dark':'#0fbbc3', 'theme-light':'#a4dbf8', 'theme-custom':theme["widget-textColor"].value};
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
emitOnlyNewValues: false,
|
||||
control: {
|
||||
type: 'gauge',
|
||||
name: config.name,
|
||||
label: config.title,
|
||||
units: config.label,
|
||||
order: config.order,
|
||||
value: config.min,
|
||||
format: config.format,
|
||||
gtype: config.gtype || 'gage',
|
||||
min: (parseFloat(config.min) < parseFloat(config.max)) ? parseFloat(config.min) : parseFloat(config.max),
|
||||
seg1: (parseFloat(config.seg1) < parseFloat(config.seg2)) ? parseFloat(config.seg1) : parseFloat(config.seg2),
|
||||
seg2: (parseFloat(config.seg1) < parseFloat(config.seg2)) ? parseFloat(config.seg2) : parseFloat(config.seg1),
|
||||
max: (parseFloat(config.min) < parseFloat(config.max)) ? parseFloat(config.max) : parseFloat(config.min),
|
||||
reverse: (parseFloat(config.max) < parseFloat(config.min)) ? true : false,
|
||||
sizes: sizes,
|
||||
hideMinMax: config.hideMinMax,
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || node.autoheight,
|
||||
colors: node.colors,
|
||||
gageoptions: gageoptions,
|
||||
waveoptions: waveoptions,
|
||||
options: null
|
||||
},
|
||||
convert: function(p,o,m) {
|
||||
var form = config.format.replace(/{{/g,"").replace(/}}/g,"").replace(/\s/g,"") || "_zzz_zzz_zzz_";
|
||||
var value = RED.util.getMessageProperty(m,form);
|
||||
if (value !== undefined) {
|
||||
if (!isNaN(parseFloat(value))) { value = parseFloat(value); }
|
||||
return value;
|
||||
}
|
||||
if (!isNaN(parseFloat(p))) { p = parseFloat(p); }
|
||||
return p;
|
||||
//return ui.toFloat.bind(this, config);
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_gauge", GaugeNode);
|
||||
};
|
||||
86
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_group.html
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<script type="text/javascript">
|
||||
// convert to i18 text
|
||||
function c_ui_group(x) {
|
||||
return RED._("node-red-dashboard/ui_group:ui_group."+x);
|
||||
}
|
||||
|
||||
RED.nodes.registerType('ui_group',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {value: c_ui_group("label.default")},
|
||||
tab: {type:"ui_tab", required: true },
|
||||
order: {value: 0},
|
||||
disp: {value: true},
|
||||
width: {value: 6},
|
||||
collapse: {value: false},
|
||||
disabled: {value: false},
|
||||
hidden: {value: false}
|
||||
},
|
||||
sort: function(A,B) {
|
||||
if (A.tab !== B.tab) {
|
||||
var tabA = RED.nodes.node(A.tab);
|
||||
var tabB = RED.nodes.node(B.tab);
|
||||
if (!tabA && tabB) {
|
||||
return -1;
|
||||
}
|
||||
else if (tabA && !tabB) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return tabA.order - tabB.order;
|
||||
}
|
||||
}
|
||||
return A.order - B.order;
|
||||
},
|
||||
paletteLabel: 'dashboard group',
|
||||
label: function() {
|
||||
var tabNode = RED.nodes.node(this.tab);
|
||||
if (tabNode) {
|
||||
return "["+(tabNode.name||c_ui_group("label.tab"))+"] " + (this.name || c_ui_group("label.group"));
|
||||
}
|
||||
return "["+c_ui_group("label.unassigned")+"] " + (this.name || c_ui_group("label.group"));
|
||||
},
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-config-input-width",
|
||||
auto: false
|
||||
});
|
||||
$("#node-config-input-disp").on("change", function() {
|
||||
if ($("#node-config-input-disp").is(":checked")) {
|
||||
$("#group-collapse-flag").show();
|
||||
}
|
||||
else {
|
||||
$("#group-collapse-flag").hide();
|
||||
$("#node-config-input-collapse").prop("checked",false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_group">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_group.label.name"></span></label>
|
||||
<input type="text" id="node-config-input-name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-tab"><i class="fa fa-table"></i> <span data-i18n="ui_group.label.tab"></span></label>
|
||||
<input type="text" id="node-config-input-tab">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-width"><i class="fa fa-arrows-h"></i> <span data-i18n="ui_group.label.width"></span></label>
|
||||
<input type="hidden" id="node-config-input-width">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<input style="margin:8px 0 10px 102px; width:20px;" type="checkbox" checked id="node-config-input-disp"> <label style="width:auto" for="node-config-input-disp"><span data-i18n="ui_group.display-name"></span></label>
|
||||
</div>
|
||||
<div class="form-row" id="group-collapse-flag">
|
||||
<input style="margin:8px 0 10px 102px; width:20px;" type="checkbox" id="node-config-input-collapse"> <label style="width:auto" for="node-config-input-collapse"><span data-i18n="ui_group.collapse-name"></span></label>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_group">
|
||||
<p>Group</p>
|
||||
</script>
|
||||
19
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_group.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
module.exports = function(RED) {
|
||||
|
||||
function GroupNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.config = {
|
||||
name: config.name,
|
||||
disp: config.disp,
|
||||
width: config.width,
|
||||
order: config.order,
|
||||
tab: config.tab,
|
||||
collapse: config.collapse || false
|
||||
};
|
||||
if (!this.config.hasOwnProperty("disp")) { this.config.disp = true; }
|
||||
if (this.config.disp !== false) { this.config.disp = true; }
|
||||
if (!this.config.hasOwnProperty("collapse")) { this.config.collapse = false; }
|
||||
}
|
||||
|
||||
RED.nodes.registerType("ui_group", GroupNode);
|
||||
};
|
||||
68
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_link.html
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_link',{
|
||||
category: 'config',
|
||||
color: 'rgb( 63, 173, 181)',
|
||||
defaults: {
|
||||
name: {value: 'Google'},
|
||||
link: {value: 'https://www.google.com'},
|
||||
icon: {value: 'open_in_browser'},
|
||||
target: {value: 'newtab', validate :function() { return true; }},
|
||||
order: {value: 0}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:0,
|
||||
hasUsers: false,
|
||||
align: "right",
|
||||
icon: "ui_link.png",
|
||||
paletteLabel: 'link',
|
||||
label: function() { return this.name || 'link'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
document.getElementById('node-config-input-target-opentab').checked = (this.target === 'newtab');
|
||||
document.getElementById('node-config-input-target-openiframe').checked = (this.target === 'iframe');
|
||||
document.getElementById('node-config-input-target-openthis').checked = (this.target === 'thistab');
|
||||
},
|
||||
oneditsave : function () {
|
||||
var t = 'iframe';
|
||||
if (document.getElementById('node-config-input-target-opentab').checked) { t = 'newtab'; }
|
||||
if (document.getElementById('node-config-input-target-openthis').checked) { t = 'thistab'; }
|
||||
this.target = t;
|
||||
},
|
||||
onadd: function() {
|
||||
//console.log("PING");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_link">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_link.label.name"></span></label>
|
||||
<input type="text" id="node-config-input-name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-link"><i class="fa fa-link"></i> <span data-i18n="ui_link.label.link"></span></label>
|
||||
<input type="text" id="node-config-input-link">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-icon"><i class="fa fa-image"></i> <span data-i18n="ui_link.label.icon"></span></label>
|
||||
<input type="text" id="node-config-input-icon">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-link"></i> <span data-i18n="ui_link.label.open-in"></span></label>
|
||||
<input type="radio" id="node-config-input-target-opentab" name="open-link-method" style="width:20px; margin-top:0px; margin-bottom:5px" checked>
|
||||
<label for="node-config-input-target-opentab" data-i18n="ui_link.label.new-tab"></label><br/>
|
||||
<input type="radio" id="node-config-input-target-openthis" name="open-link-method" style="width:20px; margin-left:104px; margin-top:0px; margin-bottom:5px">
|
||||
<label for="node-config-input-target-openthis" data-i18n="ui_link.label.this-tab"></label><br/>
|
||||
<input type="radio" id="node-config-input-target-openiframe" name="open-link-method" style="width:20px; margin-left:104px; margin-top:0px; margin-bottom:5px">
|
||||
<label for="node-config-input-target-openiframe" data-i18n="ui_link.label.iframe"></label>
|
||||
</div>
|
||||
<div class="form-tips" data-i18n="[html]ui_link.tip"></div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_link">
|
||||
<p>The <b>Icon</b> can be defined, as either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
|
||||
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
|
||||
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
|
||||
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
|
||||
<p>The <b>Open in</b> field controls whether the link opens in a <i>New Tab</i>, or if the link is opened within an <i>iframe</i> on the same page. Some sites, including Google, do not allow the rendering of their page inside an iframe. If you select the <i>iframe</i> option and the site does not show, this is simply because that site forbids the use of it inside an iframe.</p>
|
||||
</script>
|
||||
12
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_link.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function LinkNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
var done = ui.addLink(config.name, config.link, config.icon, config.order, config.target);
|
||||
node.on("close", done);
|
||||
}
|
||||
|
||||
RED.nodes.registerType("ui_link", LinkNode);
|
||||
};
|
||||
118
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_numeric.html
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_numeric',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: 'numeric'},
|
||||
tooltip: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
wrap: {value: false},
|
||||
passthru: {value: true},
|
||||
topic: {value: ''},
|
||||
format: {value: '{{value}}'},
|
||||
min: {value: 0, required: true, validate: RED.validators.number()},
|
||||
max: {value: 10, required: true, validate: RED.validators.number()},
|
||||
step: {value: 1}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: function() { return this.min+" - "+this.max; },
|
||||
icon: "ui_numeric.png",
|
||||
paletteLabel: 'numeric',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'numeric'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_numeric">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
|
||||
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-format"><i class="fa fa-i-cursor"></i> Value Format</label>
|
||||
<input type="text" id="node-input-format" placeholder="{{value}}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-min"><i class="fa fa-arrows-h"></i> Range</label>
|
||||
<span for="node-input-min">min</span>
|
||||
<input type="text" id="node-input-min" style="width:60px">
|
||||
<span for="not-input-max" style="margin-left:22px;">max</span>
|
||||
<input type="text" id="node-input-max" style="width:60px">
|
||||
<span for="not-input-step" style="margin-left:22px;">step</span>
|
||||
<input type="text" id="node-input-step" style="width:60px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-wrap"><i class="fa fa-refresh"></i> Wrap value from max to min and min to max.</label>
|
||||
<input type="checkbox" id="node-input-wrap" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
|
||||
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="padding-left:25px; margin-right:-25px">Payload</label>
|
||||
<label style="width:auto">Current value</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
|
||||
<input type="text" id="node-input-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_numeric">
|
||||
<p>Adds a numeric input widget to the user interface.</p>
|
||||
<p>The user can set the value between
|
||||
the limits (<b>min</b> and <b>max</b>). Each value change will generate a <code>msg.payload</code>.</p>
|
||||
<p>If <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.<p>
|
||||
<p>Any input messages will be converted to a number, the <b>min</b> value will be used if conversion fails,
|
||||
and it will update the user interface. If the value changes, it will also be passed to the output.</p>
|
||||
<p>The <b>Value Format</b> field can be used to change the displayed format. For example, a <b>Value Format</b>
|
||||
of <code>{{value}} %</code>
|
||||
with a value of <b>23</b> will show <b>23 %</b> on the user interface. The <b>Value Format</b> field can contain
|
||||
HTML or Angular filters to format the output (eg: <code>&deg;</code> will show the degree symbol).</p>
|
||||
<p>Setting the Value Format field to <code>{{msg.payload}}</code> will make the input field editable so you can type in a number.</p>
|
||||
<p>The label can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
|
||||
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the widget output.</p>
|
||||
</script>
|
||||
60
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_numeric.js
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function NumericNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.pt = config.passthru;
|
||||
this.state = [" "," "];
|
||||
var node = this;
|
||||
node.status({});
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
forwardInputMessages: config.passthru,
|
||||
control: {
|
||||
type: 'numeric',
|
||||
label: config.label,
|
||||
tooltip: config.tooltip,
|
||||
order: config.order,
|
||||
format: config.format,
|
||||
pre: config.format.split('{{')[0] || "",
|
||||
post: config.format.split('}}')[1] || "",
|
||||
value: Number(config.min),
|
||||
min: Number(config.min),
|
||||
max: Number(config.max),
|
||||
step: Number(config.step || 1),
|
||||
wrap: config.wrap || false,
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1,
|
||||
ed: (config.format.includes("value") ? false : true)
|
||||
},
|
||||
beforeSend: function (msg) {
|
||||
msg.payload = parseFloat(msg.payload);
|
||||
msg.topic = config.topic || msg.topic;
|
||||
if (node.pt) {
|
||||
node.status({shape:"dot",fill:"grey",text:msg.payload});
|
||||
}
|
||||
else {
|
||||
node.state[1] = msg.payload;
|
||||
node.status({shape:"dot",fill:"grey",text:node.state[1] + " | " + node.state[1]});
|
||||
}
|
||||
},
|
||||
convert: ui.toFloat.bind(this, config)
|
||||
});
|
||||
if (!node.pt) {
|
||||
node.on("input", function(msg) {
|
||||
node.state[0] = msg.payload;
|
||||
node.status({shape:"dot",fill:"grey",text:node.state[0] + " | " + node.state[1]});
|
||||
});
|
||||
}
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_numeric", NumericNode);
|
||||
};
|
||||
116
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_slider.html
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_slider',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: 'slider'},
|
||||
tooltip: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
passthru: {value: true},
|
||||
outs: {value: 'all'},
|
||||
topic: {value: ''},
|
||||
min: {value: 0, required:true, validate:RED.validators.number()},
|
||||
max: {value: 10, required:true, validate:RED.validators.number()},
|
||||
step: {value: 1}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: function() { return this.min+" - "+this.max; },
|
||||
icon: "ui_slider.png",
|
||||
paletteLabel: 'slider',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'slider'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
if (!$("#node-input-outs").val()) { $("#node-input-outs").val("all") }
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_slider">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
|
||||
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-min"><i class="fa fa-arrows-h"></i> Range</label>
|
||||
<span for="node-input-min">min</span>
|
||||
<input type="text" id="node-input-min" style="width:60px">
|
||||
<span for="not-input-max" style="margin-left:22px;">max</span>
|
||||
<input type="text" id="node-input-max" style="width:60px">
|
||||
<span for="not-input-step" style="margin-left:22px;">step</span>
|
||||
<input type="text" id="node-input-step" style="width:60px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-outs"><i class="fa fa-sign-out"></i> Output</label>
|
||||
<select id="node-input-outs" style="width:204px">
|
||||
<option value="all">continuously while sliding</option>
|
||||
<option value="end">only on release</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, set slider to new payload value: </label>
|
||||
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="padding-left:25px; margin-right:-25px">Payload</label>
|
||||
<label style="width:auto">Current value</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
|
||||
<input type="text" id="node-input-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_slider">
|
||||
<p>Adds a slider widget to the user interface.</p>
|
||||
<p>The user can change its value between the limits (<b>min</b> and <b>max</b>). Each value change
|
||||
will generate a message with the value set as <b>payload</b>.</p>
|
||||
<p>A vertical slider can be created by setting the size so that the height is greater than the width.</p>
|
||||
<p>The slider can be reversed by setting the min value larger than the max value. e.g. min 100, max 0.</p>
|
||||
<p>If a <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.</p>
|
||||
<p>Input messages will be converted to a number. The <b>min</b> value will be used if conversion fails,
|
||||
and it will update the user interface. If the value changes, it will also be passed to the output.</p>
|
||||
<p>The label can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
|
||||
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the slider output.</p>
|
||||
<p>Note: An input msg to the slider node will not change the status information displayed unless the slider
|
||||
node output is connected to another node.</p>
|
||||
</script>
|
||||
56
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_slider.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function SliderNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.pt = config.passthru;
|
||||
this.state = [" "," "];
|
||||
var node = this;
|
||||
node.status({});
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
forwardInputMessages: config.passthru,
|
||||
control: {
|
||||
type: 'slider',
|
||||
label: config.label,
|
||||
tooltip: config.tooltip,
|
||||
order: config.order,
|
||||
value: config.min,
|
||||
min: Math.min(config.min, config.max),
|
||||
max: Math.max(config.max, config.min),
|
||||
invert: (parseFloat(config.min) > parseFloat(config.max)) ? true : undefined,
|
||||
step: Math.abs(config.step) || 1,
|
||||
outs: config.outs || "all",
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1
|
||||
},
|
||||
beforeSend: function (msg) {
|
||||
msg.topic = config.topic || msg.topic;
|
||||
if (node.pt) {
|
||||
node.status({shape:"dot",fill:"grey",text:msg.payload});
|
||||
}
|
||||
else {
|
||||
node.state[1] = msg.payload;
|
||||
node.status({shape:"dot",fill:"grey",text:node.state[1] + " | " + node.state[1]});
|
||||
}
|
||||
},
|
||||
convert: ui.toFloat.bind(this, config)
|
||||
});
|
||||
if (!node.pt) {
|
||||
node.on("input", function(msg) {
|
||||
node.state[0] = msg.payload;
|
||||
node.status({shape:"dot",fill:"grey",text:node.state[0] + " | " + node.state[1]});
|
||||
});
|
||||
}
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_slider", SliderNode);
|
||||
};
|
||||
51
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_spacer.html
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_spacer', {
|
||||
category: 'config',
|
||||
color: '#45ADB4',
|
||||
defaults: {
|
||||
name: {value: "spacer"},
|
||||
group: {type: 'ui_group', required:true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:0,
|
||||
hasUsers: false,
|
||||
icon: "ui_spacer.png",
|
||||
paletteLabel: 'spacer',
|
||||
label: function() { return this.name + " " + this.width + "x" + this.height; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_spacer">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_spacer">
|
||||
</script>
|
||||
27
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_spacer.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function SpacerNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
control: {
|
||||
type: 'spacer',
|
||||
order: config.order,
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_spacer", SpacerNode);
|
||||
};
|
||||
185
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_switch.html
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_switch',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: 'switch'},
|
||||
tooltip: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
passthru: {value: true},
|
||||
decouple: {value: "false"},
|
||||
topic: {value: ''},
|
||||
style: {value: ''},
|
||||
onvalue: {value: true, required:true, validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('onvalueType'):function(v) { return true})},
|
||||
onvalueType: {value: 'bool'},
|
||||
onicon: {value: '' },
|
||||
oncolor: {value: ''},
|
||||
offvalue: {value: false, required:true, validate: (RED.validators.hasOwnProperty('typedInput')?RED.validators.typedInput('offvalueType'):function(v) { return true})},
|
||||
offvalueType: {value: 'bool'},
|
||||
officon: {value: ''},
|
||||
offcolor: {value: ''},
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "ui_switch.png",
|
||||
paletteLabel: 'switch',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'switch'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
$('#node-input-custom-icons').on("change", function() {
|
||||
if ($('#node-input-custom-icons').val() === "default") {
|
||||
$(".form-row-custom-icons").hide();
|
||||
}
|
||||
else {
|
||||
$(".form-row-custom-icons").show();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.onicon !== "" || this.oncolor !== "" || this.officon !=="" || this.offcolor !== "") {
|
||||
$('#node-input-custom-icons').val('custom');
|
||||
}
|
||||
else {
|
||||
$(".form-row-custom-icons").hide();
|
||||
$('#node-input-custom-icons').change();
|
||||
}
|
||||
|
||||
$('#node-input-onvalue').typedInput({
|
||||
default: 'str',
|
||||
typeField: $("#node-input-onvalueType"),
|
||||
types: ['str','num','bool','json','bin','date','flow','global']
|
||||
});
|
||||
|
||||
$('#node-input-offvalue').typedInput({
|
||||
default: 'str',
|
||||
typeField: $("#node-input-offvalueType"),
|
||||
types: ['str','num','bool','json','bin','date','flow','global']
|
||||
});
|
||||
|
||||
$('#node-input-passthru').on("change", function() {
|
||||
if (this.checked) {
|
||||
$('.form-row-decouple').hide();
|
||||
$('#node-input-decouple').val("false");
|
||||
}
|
||||
else {
|
||||
$('.form-row-decouple').show();
|
||||
}
|
||||
});
|
||||
},
|
||||
oneditsave: function() {
|
||||
if ($('#node-input-custom-icons').val() === 'default') {
|
||||
$('#node-input-onicon').val('');
|
||||
$('#node-input-officon').val('');
|
||||
$('#node-input-oncolor').val('');
|
||||
$('#node-input-offcolor').val('');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_switch">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
|
||||
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-custom-icons"><i class="fa fa-picture-o"></i> Icon</label>
|
||||
<select id="node-input-custom-icons">
|
||||
<option value="default">Default</option>
|
||||
<option value="custom">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row form-row-custom-icons">
|
||||
<label for="node-input-onicon" style="text-align:right;"><i class="fa fa-toggle-on"></i> On Icon</label>
|
||||
<input type="text" id="node-input-onicon" style="width:120px">
|
||||
<label for="node-input-oncolor" style="width:50px; text-align:right;">Colour</label>
|
||||
<input type="text" id="node-input-oncolor" style="width:120px">
|
||||
</div>
|
||||
<div class="form-row form-row-custom-icons">
|
||||
<label for="node-input-officon" style="text-align:right;"><i class="fa fa-toggle-off"></i> Off Icon</label>
|
||||
<input type="text" id="node-input-officon" style="width:120px">
|
||||
<label for="node-input-offcolor" style="width:50px; text-align:right;">Colour</label>
|
||||
<input type="text" id="node-input-offcolor" style="width:120px">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> Pass though <code>msg</code> if payload matches new state: </label>
|
||||
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row form-row-decouple">
|
||||
<label for="node-input-decouple"><i class="fa fa-toggle-on"></i> Indicator</label>
|
||||
<select id="node-input-decouple" style="display: inline-block; vertical-align: middle; width:70%;">
|
||||
<option value="false">Switch icon shows state of the output</option>
|
||||
<option value="true">Switch icon shows state of the input</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-onvalue"><i class="fa fa-envelope-o"></i> When clicked, send:</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-onvalue" style="padding-left:25px; margin-right:-25px">On Payload</label>
|
||||
<input type="text" id="node-input-onvalue" style="width:70%">
|
||||
<input type="hidden" id="node-input-onvalueType">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-offvalue" style="padding-left:25px; margin-right:-25px">Off Payload</label>
|
||||
<input type="text" id="node-input-offvalue" style="width:70%">
|
||||
<input type="hidden" id="node-input-offvalueType">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic" style="padding-left:25px; margin-right:-25px">Topic</label>
|
||||
<input type="text" id="node-input-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_switch">
|
||||
<p>Adds a switch to the user interface.</p>
|
||||
<p>Each change in the state of the switch will generate
|
||||
a <code>msg.payload</code> with the specified <b>On</b> and <b>Off</b> values.</p>
|
||||
<p>The <b>On/Off Color</b> and <b>On/Off Icon</b> are optional fields. If they are all present, the default
|
||||
toggle switch will be replaced with the relevant icons and their respective colors.</p>
|
||||
<p>The <b>On/Off Icon</b> field can be either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
|
||||
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
|
||||
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
|
||||
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
|
||||
<p>In pass through mode the switch state can be updated by an incoming <code>msg.payload</code> with the specified values,
|
||||
that must also match the specified type (number, string, etc). When not in passthrough mode then the icon can either
|
||||
track the state of the output - or the input msg.payload, in order to provide a closed loop feedback.</p>
|
||||
<p>The label can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
|
||||
<p>If a <b>Topic</b> is specified, it will be added to the output as <code>msg.topic</code>.</p>
|
||||
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the switch widget.</p>
|
||||
</script>
|
||||
138
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_switch.js
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function validateSwitchValue(node,property,type,payload) {
|
||||
if (payloadType === 'flow' || payloadType === 'global') {
|
||||
try {
|
||||
var parts = RED.util.normalisePropertyExpression(payload);
|
||||
if (parts.length === '') {
|
||||
throw new Error();
|
||||
}
|
||||
} catch(err) {
|
||||
node.warn("Invalid payload property expression - defaulting to node id")
|
||||
payload = node.id;
|
||||
payloadType = 'str';
|
||||
}
|
||||
}
|
||||
else {
|
||||
payload = payload || node.id;
|
||||
}
|
||||
}
|
||||
function SwitchNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.pt = config.passthru;
|
||||
this.state = ["off"," "];
|
||||
this.decouple = (config.decouple === "true") ? false : true;
|
||||
var node = this;
|
||||
node.status({});
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var parts;
|
||||
var onvalue = config.onvalue;
|
||||
var onvalueType = config.onvalueType;
|
||||
if (onvalueType === 'flow' || onvalueType === 'global') {
|
||||
try {
|
||||
parts = RED.util.normalisePropertyExpression(onvalue);
|
||||
if (parts.length === 0) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch(err) {
|
||||
node.warn("Invalid onvalue property expression - defaulting to true")
|
||||
onvalue = true;
|
||||
onvalueType = 'bool';
|
||||
}
|
||||
}
|
||||
var offvalue = config.offvalue;
|
||||
var offvalueType = config.offvalueType;
|
||||
if (offvalueType === 'flow' || offvalueType === 'global') {
|
||||
try {
|
||||
parts = RED.util.normalisePropertyExpression(offvalue);
|
||||
if (parts.length === 0) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch(err) {
|
||||
node.warn("Invalid offvalue property expression - defaulting to false")
|
||||
offvalue = false;
|
||||
offvalueType = 'bool';
|
||||
}
|
||||
}
|
||||
|
||||
var done = ui.add({
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
emitOnlyNewValues: false,
|
||||
forwardInputMessages: config.passthru,
|
||||
storeFrontEndInputAsState: (config.decouple === "true") ? false : true, //config.passthru,
|
||||
state: false,
|
||||
control: {
|
||||
type: 'switch' + (config.style ? '-' + config.style : ''),
|
||||
label: config.label,
|
||||
tooltip: config.tooltip,
|
||||
order: config.order,
|
||||
value: false,
|
||||
onicon: config.onicon,
|
||||
officon: config.officon,
|
||||
oncolor: config.oncolor,
|
||||
offcolor: config.offcolor,
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1
|
||||
},
|
||||
convert: function (payload, oldval, msg) {
|
||||
var myOnValue,myOffValue;
|
||||
|
||||
if (onvalueType === "date") { myOnValue = Date.now(); }
|
||||
else { myOnValue = RED.util.evaluateNodeProperty(onvalue,onvalueType,node); }
|
||||
|
||||
if (offvalueType === "date") { myOffValue = Date.now(); }
|
||||
else { myOffValue = RED.util.evaluateNodeProperty(offvalue,offvalueType,node); }
|
||||
|
||||
if (!this.forwardInputMessages && this.storeFrontEndInputAsState) {
|
||||
if (myOnValue === oldval) { return true; }
|
||||
if (oldval === true) { return true; }
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
if (RED.util.compareObjects(myOnValue,msg.payload)) { node.state[0] = "on"; return true; }
|
||||
else if (RED.util.compareObjects(myOffValue,msg.payload)) { node.state[0] = "off"; return false; }
|
||||
else { return oldval; }
|
||||
},
|
||||
convertBack: function (value) {
|
||||
node.state[1] = value?"on":"off";
|
||||
if (node.pt) {
|
||||
node.status({fill:(value?"green":"red"),shape:(value?"dot":"ring"),text:value?"on":"off"});
|
||||
}
|
||||
else {
|
||||
var col = (node.decouple) ? ((node.state[1]=="on")?"green":"red") : ((node.state[0]=="on")?"green":"red");
|
||||
var shp = (node.decouple) ? ((node.state[1]=="on")?"dot":"ring") : ((node.state[0]=="on")?"dot":"ring");
|
||||
var txt = (node.decouple) ? (node.state[0] +" | "+node.state[1].toUpperCase()) : (node.state[0].toUpperCase() +" | "+node.state[1])
|
||||
node.status({fill:col, shape:shp, text:txt});
|
||||
}
|
||||
var payload = value ? onvalue : offvalue;
|
||||
var payloadType = value ? onvalueType : offvalueType;
|
||||
|
||||
if (payloadType === "date") { value = Date.now(); }
|
||||
else { value = RED.util.evaluateNodeProperty(payload,payloadType,node); }
|
||||
return value;
|
||||
},
|
||||
beforeSend: function (msg) {
|
||||
msg.topic = config.topic || msg.topic;
|
||||
}
|
||||
});
|
||||
|
||||
if (!node.pt) {
|
||||
node.on("input", function() {
|
||||
var col = (node.state[0]=="on") ? "green" : "red";
|
||||
var shp = (node.state[0]=="on") ? "dot" : "ring";
|
||||
var txt = (node.decouple) ? (node.state[0] +" | "+node.state[1].toUpperCase()) : (node.state[0].toUpperCase() +" | "+node.state[1])
|
||||
node.status({fill:col, shape:shp, text:txt});
|
||||
});
|
||||
}
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_switch", SwitchNode);
|
||||
};
|
||||
105
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_tab.html
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
<script type="text/javascript">
|
||||
// convert to i18 text
|
||||
function c_ui_tab(x) {
|
||||
return RED._("node-red-dashboard/ui_tab:ui_tab."+x);
|
||||
}
|
||||
|
||||
RED.nodes.registerType('ui_tab',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
name: {value: c_ui_tab("label.home")},
|
||||
icon: {value: 'dashboard'},
|
||||
order: {value: 0},
|
||||
disabled: {value: false},
|
||||
hidden: {value: false}
|
||||
},
|
||||
paletteLabel: 'dashboard tab',
|
||||
label: function() { return this.name || c_ui_tab("label.tab"); },
|
||||
sort: function(A,B) {
|
||||
return A.order - B.order;
|
||||
},
|
||||
oneditprepare: function() {
|
||||
$("#node-config-input-disabled-btn").on("click", function(e) {
|
||||
var i = $(this).find("i");
|
||||
var active = i.hasClass("fa-toggle-on");
|
||||
var newCls = "fa fa-toggle-" + (active ? "off" : "on");
|
||||
i.attr("class", newCls);
|
||||
$("#node-config-input-disabled").prop('checked',active);
|
||||
|
||||
var newTxt = c_ui_tab(active ? "label.disabled" : "label.enabled");
|
||||
$("#node-config-input-disabled-label").text(newTxt);
|
||||
|
||||
var info = $("#node-config-input-disabled-info");
|
||||
var done = active ? info.show() : info.hide();
|
||||
});
|
||||
if (this.disabled) {
|
||||
$("#node-config-input-disabled-btn").click();
|
||||
}
|
||||
else {
|
||||
$("#node-config-input-disabled-label").text(c_ui_tab("label.enabled"));
|
||||
}
|
||||
|
||||
$("#node-config-input-hidden-btn").on("click", function(e) {
|
||||
var i = $(this).find("i");
|
||||
var active = i.hasClass("fa-toggle-on");
|
||||
var newCls = "fa fa-toggle-" + (active ? "off" : "on");
|
||||
i.attr("class", newCls);
|
||||
$("#node-config-input-hidden").prop('checked',active);
|
||||
|
||||
var newTxt = c_ui_tab(active ? "label.hidden" : "label.visible");
|
||||
$("#node-config-input-hidden-label").text(newTxt);
|
||||
|
||||
var info = $("#node-config-input-hidden-info");
|
||||
var done = active ? info.show() : info.hide();
|
||||
});
|
||||
if (this.hidden) {
|
||||
$("#node-config-input-hidden-btn").click();
|
||||
}
|
||||
else {
|
||||
$("#node-config-input-hidden-label").text(c_ui_tab("label.visible"));
|
||||
}
|
||||
},
|
||||
oneditsave: function() {
|
||||
this.disabled = $("#node-config-input-disabled").prop("checked");
|
||||
this.hidden = $("#node-config-input-hidden").prop("checked");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_tab">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_tab.label.name"></span></label>
|
||||
<input type="text" id="node-config-input-name">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-icon"><i class="fa fa-file-image-o"></i> <span data-i18n="ui_tab.label.icon"></span></label>
|
||||
<input type="text" id="node-config-input-icon">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-disabled-btn"><i class="fa fa-ban"></i> <span data-i18n="ui_tab.label.state"></span></label>
|
||||
<button id="node-config-input-disabled-btn" class="editor-button" style="width:100px; margin-right:6px;"><i class="fa fa-toggle-on"></i> <span id="node-config-input-disabled-label"></span></button>
|
||||
<input type="checkbox" id="node-config-input-disabled" style="display:none;"/>
|
||||
<span id="node-config-input-disabled-info" data-i18n="[html]ui_tab.info.disabled" style="display:none;"></span>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-hidden-btn"><i class="fa fa-eye-slash"></i> <span data-i18n="ui_tab.label.navmenu"></span></label>
|
||||
<button id="node-config-input-hidden-btn" class="editor-button" style="width:100px; margin-right:6px;"><i class="fa fa-toggle-on"></i> <span id="node-config-input-hidden-label"></span></button>
|
||||
<input type="checkbox" id="node-config-input-hidden" style="display:none;"/>
|
||||
<span id="node-config-input-hidden-info" data-i18n="[html]ui_tab.info.hidden" style="display:none;"></span>
|
||||
</div>
|
||||
<div class="form-tips" data-i18n="[html]ui_tab.tip"></div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_tab">
|
||||
<p>Tab configuration for Dashboard</p>
|
||||
<p><b>Disabled</b> pages are not included in the Dashboard app, and are therefore not functional.
|
||||
The tab name still appears in the Navigation Menu (unless it is also hidden).
|
||||
</p>
|
||||
<p><b>Hidden</b> pages are not listed in the Left-hand Navigation Menu.
|
||||
However, they are still active in the Dashboard, and can be shown by using a `ui_control` msg.
|
||||
</p>
|
||||
<p>The <b>Icon</b> field can be either a <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
|
||||
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
|
||||
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
|
||||
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
|
||||
</script>
|
||||
15
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_tab.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
module.exports = function(RED) {
|
||||
|
||||
function TabNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
this.config = {
|
||||
name: config.name,
|
||||
order: config.order || 0,
|
||||
icon: config.icon || '',
|
||||
disabled: config.disabled || false,
|
||||
hidden: config.hidden || false
|
||||
};
|
||||
}
|
||||
|
||||
RED.nodes.registerType("ui_tab", TabNode);
|
||||
};
|
||||
246
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_template.html
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
<script type="text/javascript">
|
||||
// convert to i18 text
|
||||
function c_(x) {
|
||||
return RED._("node-red-dashboard/ui_template:ui_template."+x);
|
||||
}
|
||||
|
||||
RED.nodes.registerType('ui_template',{
|
||||
category: c_("label.category"),
|
||||
color: 'rgb( 63, 173, 181)',
|
||||
defaults: {
|
||||
group: {type: 'ui_group', required:false},
|
||||
name: {value: ''},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var valid = true
|
||||
if (this.templateScope !== 'global') {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
}
|
||||
return valid;
|
||||
}},
|
||||
height: {value: 0},
|
||||
format: {value: '<div ng-bind-html="msg.payload"></div>'},
|
||||
storeOutMessages: {value: true},
|
||||
fwdInMessages: {value: true},
|
||||
templateScope: {value: 'local'}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "ui_template.png",
|
||||
paletteLabel: 'template',
|
||||
label: function() { return this.name || 'template'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
if (RED.editor.hasOwnProperty("editText") && typeof RED.editor.editText === "function") {
|
||||
$("#node-template-expand-editor").show();
|
||||
}
|
||||
else {
|
||||
$("#node-template-expand-editor").hide();
|
||||
}
|
||||
var that = this;
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
|
||||
if (typeof this.storeOutMessages === 'undefined') {
|
||||
this.storeOutMessages = true;
|
||||
$('#node-input-storeOutMessages').prop('checked', true);
|
||||
}
|
||||
|
||||
if (typeof this.fwdInMessages === 'undefined') {
|
||||
this.fwdInMessages = true;
|
||||
$('#node-input-fwdInMessages').prop('checked', true);
|
||||
}
|
||||
|
||||
if (typeof this.templateScope === 'undefined') {
|
||||
this.templateScope = 'local';
|
||||
$('#node-input-templateScope').val(this.templateScope);
|
||||
}
|
||||
|
||||
$('#node-input-templateScope').on('change', function() {
|
||||
if ($('#node-input-templateScope').val() === 'global') {
|
||||
$('#template-row-group, #template-row-size, #template-pass-store').hide();
|
||||
that._def.defaults.group.required = false;
|
||||
}
|
||||
else {
|
||||
$('#template-row-group, #template-row-size, #template-pass-store').show();
|
||||
that._def.defaults.group.required = true;
|
||||
}
|
||||
|
||||
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
||||
var height = $("#dialog-form").height();
|
||||
for (var i=0; i<rows.size(); i++) {
|
||||
height = height - $(rows[i]).outerHeight(true);
|
||||
}
|
||||
if ($('#node-input-templateScope').val() === "global") { height += 240; }
|
||||
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
||||
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
if (this.editor) { this.editor.resize(); }
|
||||
})
|
||||
|
||||
this.editor = RED.editor.createEditor({
|
||||
id: 'node-input-format-editor',
|
||||
mode: 'ace/mode/html',
|
||||
value: $("#node-input-format").val()
|
||||
});
|
||||
|
||||
RED.library.create({
|
||||
url:"uitemplates", // where to get the data from
|
||||
type:"ui_template", // the type of object the library is for
|
||||
editor:this.editor, // the field name the main text body goes to
|
||||
mode:"ace/mode/html",
|
||||
fields:['name']
|
||||
});
|
||||
|
||||
this.editor.focus();
|
||||
|
||||
RED.popover.tooltip($("#node-template-expand-editor"),c_("label.expand"));
|
||||
|
||||
$("#node-template-expand-editor").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
var value = that.editor.getValue();
|
||||
RED.editor.editText({
|
||||
mode: 'html',
|
||||
value: value,
|
||||
width: "Infinity",
|
||||
cursor: that.editor.getCursorPosition(),
|
||||
complete: function(v,cursor) {
|
||||
that.editor.setValue(v, -1);
|
||||
that.editor.gotoLine(cursor.row+1,cursor.column,false);
|
||||
setTimeout(function() { that.editor.focus(); },300);
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
oneditsave: function() {
|
||||
var annot = this.editor.getSession().getAnnotations();
|
||||
this.noerr = 0;
|
||||
$("#node-input-noerr").val(0);
|
||||
for (var k=0; k < annot.length; k++) {
|
||||
if (annot[k].type === "error") {
|
||||
$("#node-input-noerr").val(annot.length);
|
||||
this.noerr = annot.length;
|
||||
}
|
||||
}
|
||||
$("#node-input-format").val(this.editor.getValue());
|
||||
this.editor.destroy();
|
||||
delete this.editor;
|
||||
},
|
||||
oneditcancel: function() {
|
||||
this.editor.destroy();
|
||||
delete this.editor;
|
||||
},
|
||||
oneditresize: function(size) {
|
||||
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
|
||||
var height = $("#dialog-form").height();
|
||||
for (var i=0; i<rows.size(); i++) {
|
||||
height = height - $(rows[i]).outerHeight(true);
|
||||
}
|
||||
if ($('#node-input-templateScope').val() === "global") { height += 232; }
|
||||
var editorRow = $("#dialog-form>div.node-text-editor-row");
|
||||
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
|
||||
$(".node-text-editor").css("height",height+"px");
|
||||
this.editor.resize();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_template">
|
||||
<div class="form-row">
|
||||
<label for="node-input-format"><span data-i18n="ui_template.label.type"></span></label>
|
||||
<select style="width:76%" id="node-input-templateScope">
|
||||
<option value="local" data-i18n="ui_template.label.local"></option>
|
||||
<option value="global" data-i18n="ui_template.label.global"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row" id="template-row-group">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> <span data-i18n="ui_template.label.group"></span></label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row" id="template-row-size">
|
||||
<label><i class="fa fa-object-group"></i> <span data-i18n="ui_template.label.size"></span></label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_template.label.name"></span></label>
|
||||
<div style="display:inline-block; width:calc(100% - 105px)">
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:0px;">
|
||||
<label for="node-input-format"><i class="fa fa-copy"></i> <span data-i18n="ui_template.label.template"></span></label>
|
||||
<input type="hidden" id="node-input-format">
|
||||
<button id="node-template-expand-editor" class="red-ui-button red-ui-button-small" style="float:right"><i class="fa fa-expand"></i></button>
|
||||
</div>
|
||||
<div class="form-row node-text-editor-row">
|
||||
<div style="height:250px; min-height:100px" class="node-text-editor" id="node-input-format-editor" ></div>
|
||||
</div>
|
||||
<div id="template-pass-store">
|
||||
<div class="form-row" style="margin-bottom:0px;">
|
||||
<input type="checkbox" id="node-input-fwdInMessages" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
|
||||
<label for="node-input-fwdInMessages" style="width:70%;"> <span data-i18n="ui_template.label.pass-through"></span></label>
|
||||
</div>
|
||||
<div class="form-row" style="margin-bottom:0px;">
|
||||
<input type="checkbox" id="node-input-storeOutMessages" style="display:inline-block; margin-left:8px; width:auto; vertical-align:top;">
|
||||
<label for="node-input-storeOutMessages" style="width:70%;"> <span data-i18n="ui_template.label.store-state"></span></label>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_template">
|
||||
<p>The template widget can contain any valid html and Angular/Angular-Material directives.</p>
|
||||
<p>This node can be used to create a dynamic user interface element that changes its appearence
|
||||
based on the input message and can send back messages to Node-RED.</p>
|
||||
<p><b>For example:</b><br>
|
||||
<pre style="font-size:smaller;"><div layout="row" layout-align="space-between">
|
||||
<p>The number is</p>
|
||||
<font color="{{((msg.payload || 0) % 2 === 0) ? 'green' : 'red'}}">
|
||||
{{(msg.payload || 0) % 2 === 0 ? 'even' : 'odd'}}
|
||||
</font>
|
||||
</div></pre>
|
||||
Will display if the number received as <code>msg.payload</code> is even or odd. It will also
|
||||
change the color of the text to green if the number is even or red if odd.<br/>
|
||||
The next example shows how to set a unique id for your template, pick up the default theme colour,
|
||||
and watch for any incoming message.</p>
|
||||
<pre style="font-size:smaller;">
|
||||
<div id="{{'my_'+$id}}" style="{{'color:'+theme.base_color}}">Some text</div>
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.$watch('msg', function(msg) {
|
||||
if (msg) {
|
||||
// Do something when msg arrives
|
||||
$("#my_"+scope.$id).html(msg.payload);
|
||||
}
|
||||
});
|
||||
})(scope);
|
||||
</script></pre>
|
||||
<p>Templates made in this way can be copied and remain independent of each other.</p>
|
||||
<p><b>Sending a message:</b><br>
|
||||
<pre style="font-size:smaller;">
|
||||
<script>
|
||||
var value = "hello world";
|
||||
// or overwrite value in your callback function ...
|
||||
this.scope.action = function() { return value; }
|
||||
</script>
|
||||
<md-button ng-click="send({payload:action()})">
|
||||
Click me to send a hello world
|
||||
</md-button></pre>
|
||||
Will display a button that when clicked will send a message with the payload <code>'Hello world'</code>.</p>
|
||||
<p><b>Using <code>msg.template</code>:</b><br>
|
||||
You can also define the template content via <code>msg.template</code>, so you can use external files for example.<br>
|
||||
Template will be reloaded on input if it has changed.<br>
|
||||
Code written in the Template field will be ignored when <code>msg.template</code> is present.</p>
|
||||
<p>The following icon fonts are available: <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
|
||||
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
|
||||
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
|
||||
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
|
||||
</script>
|
||||
88
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_template.js
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function TemplateNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group && config.templateScope !== 'global') { return; }
|
||||
var tab = null;
|
||||
if (config.templateScope !== 'global') {
|
||||
tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
if (!config.width) {
|
||||
config.width = group.config.width;
|
||||
}
|
||||
}
|
||||
var hei = Number(config.height|| 0);
|
||||
var previousTemplate = null
|
||||
var theme = ui.getTheme();
|
||||
var colortheme = {};
|
||||
for (var i in theme) {
|
||||
if (theme.hasOwnProperty(i)) {
|
||||
colortheme[i.replace(/-/g, "_")] = theme[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
var done = ui.add({
|
||||
forwardInputMessages: config.fwdInMessages,
|
||||
storeFrontEndInputAsState: config.storeOutMessages,
|
||||
emitOnlyNewValues: false,
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
control: {
|
||||
type: 'template',
|
||||
order: config.order,
|
||||
width: config.width || 6,
|
||||
height: hei,
|
||||
format: config.format,
|
||||
templateScope: config.templateScope,
|
||||
theme: colortheme
|
||||
},
|
||||
beforeEmit: function(msg) {
|
||||
var properties = Object.getOwnPropertyNames(msg).filter(function (p) { return p[0] != '_'; });
|
||||
var clonedMsg = {
|
||||
templateScope: config.templateScope
|
||||
};
|
||||
for (var i=0; i<properties.length; i++) {
|
||||
var property = properties[i];
|
||||
clonedMsg[property] = msg[property];
|
||||
}
|
||||
|
||||
// transform to string if msg.template is buffer
|
||||
if (clonedMsg.template !== undefined && Buffer.isBuffer(clonedMsg.template)) {
|
||||
clonedMsg.template = clonedMsg.template.toString();
|
||||
}
|
||||
|
||||
if (clonedMsg.template === undefined && previousTemplate !== null) {
|
||||
clonedMsg.template = previousTemplate;
|
||||
}
|
||||
|
||||
//This updates the whole page if the template input changes and
|
||||
//height set to auto - performance killer, but here just in case
|
||||
// if ((config.height == "0") && (value !== node.oldvalue)) {
|
||||
// node.oldvalue = value;
|
||||
// setImmediate(function() { ui.updateUi(); });
|
||||
// }
|
||||
|
||||
if (clonedMsg.template) {
|
||||
previousTemplate = clonedMsg.template
|
||||
}
|
||||
|
||||
return { msg:clonedMsg };
|
||||
},
|
||||
beforeSend: function (msg, original) {
|
||||
if (original) {
|
||||
var om = original.msg;
|
||||
om.socketid = original.socketid;
|
||||
return om;
|
||||
}
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_template", TemplateNode);
|
||||
RED.library.register("uitemplates");
|
||||
};
|
||||
182
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_text.html
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_text',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(119, 198, 204)',
|
||||
defaults: {
|
||||
group: {type: 'ui_group', required:true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
name: {value: ''},
|
||||
label: {value: 'text'},
|
||||
format: {value: '{{msg.payload}}'},
|
||||
layout: {value:'row-spread'}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
align: "right",
|
||||
icon: "ui_text.png",
|
||||
paletteLabel: 'text',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || 'text'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
|
||||
$(".nr-db-text-layout-"+(this.layout||'row-spread')).addClass('selected');
|
||||
|
||||
[ ".nr-db-text-layout-row-left",".nr-db-text-layout-row-center",".nr-db-text-layout-row-right",
|
||||
".nr-db-text-layout-row-spread",".nr-db-text-layout-col-center"].forEach(function(id) {
|
||||
$(id).click(function(e) {
|
||||
$(".nr-db-text-layout").removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
$('#node-input-layout').val(id.substring(".nr-db-text-layout-".length));
|
||||
e.preventDefault();
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_text">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-format"><i class="fa fa-i-cursor"></i> Value format</label>
|
||||
<input type="text" id="node-input-format" placeholder="{{msg.payload}}">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="vertical-align: top"><i class="fa fa-th-large"></i> Layout</label>
|
||||
<div style="display:inline-block">
|
||||
<input type="hidden" id="node-input-layout"><input type="hidden" id="node-input-layoutAlign">
|
||||
<div>
|
||||
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-left">
|
||||
<span class="nr-db-text-layout-label">label</span>
|
||||
<span class="nr-db-text-layout-value">value</span>
|
||||
<div class="nr-db-text-layout-checkbox"></div>
|
||||
</a>
|
||||
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-center">
|
||||
<span class="nr-db-text-layout-label">label</span>
|
||||
<span class="nr-db-text-layout-value">value</span>
|
||||
<div class="nr-db-text-layout-checkbox"></div>
|
||||
</a>
|
||||
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-right">
|
||||
<span class="nr-db-text-layout-label">label</span>
|
||||
<span class="nr-db-text-layout-value">value</span>
|
||||
<div class="nr-db-text-layout-checkbox"></div>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#" class="nr-db-text-layout nr-db-text-layout-row nr-db-text-layout-row-spread">
|
||||
<span class="nr-db-text-layout-label">label</span>
|
||||
<span class="nr-db-text-layout-value">value</span>
|
||||
<div class="nr-db-text-layout-checkbox"></div>
|
||||
</a>
|
||||
<a href="#" class="nr-db-text-layout nr-db-text-layout-col nr-db-text-layout-col-center">
|
||||
<span class="nr-db-text-layout-label">label</span>
|
||||
<span class="nr-db-text-layout-value">value</span>
|
||||
<div class="nr-db-text-layout-checkbox"></div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.nr-db-text-layout {
|
||||
position:relative;
|
||||
display: inline-block;
|
||||
width: 90px;
|
||||
height: 60px;
|
||||
border-radius:3px;
|
||||
border:1px solid #bbb;
|
||||
cursor:pointer;
|
||||
color: #666;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.nr-db-text-layout.selected, .nr-db-text-layout:hover {
|
||||
border-color: #333;
|
||||
color: #333;
|
||||
}
|
||||
.nr-db-text-layout span {
|
||||
position: absolute;
|
||||
}
|
||||
.nr-db-text-layout-value {
|
||||
font-weight: bold;
|
||||
}
|
||||
.nr-db-text-layout-row span { top: 20px; }
|
||||
.nr-db-text-layout-row-left .nr-db-text-layout-label { left: 2px; }
|
||||
.nr-db-text-layout-row-left .nr-db-text-layout-value { left: 34px; }
|
||||
.nr-db-text-layout-row-spread .nr-db-text-layout-label { left: 2px; }
|
||||
.nr-db-text-layout-row-spread .nr-db-text-layout-value { right: 2px; }
|
||||
.nr-db-text-layout-row-center .nr-db-text-layout-label { left: 11px; }
|
||||
.nr-db-text-layout-row-center .nr-db-text-layout-value { right: 11px; }
|
||||
.nr-db-text-layout-row-right .nr-db-text-layout-label { right: 40px; }
|
||||
.nr-db-text-layout-row-right .nr-db-text-layout-value { right: 2px; }
|
||||
|
||||
.nr-db-text-layout-col span { width: 90px; text-align: center; left: 0px;}
|
||||
.nr-db-text-layout-col-center .nr-db-text-layout-label { top: 12px; }
|
||||
.nr-db-text-layout-col-center .nr-db-text-layout-value { top: 26px; }
|
||||
.nr-db-text-layout-checkbox {
|
||||
display: none;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #bbb;
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
top: -5px;
|
||||
background: #fff;
|
||||
}
|
||||
.nr-db-text-layout.selected .nr-db-text-layout-checkbox {
|
||||
display:inline-block;
|
||||
box-shadow: inset 0px 0px 0px 2px #fff;
|
||||
background: #333;
|
||||
border-color: #333;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="text/html" data-help-name="ui_text">
|
||||
<p>Will display a non-editable text field on the user interface.</p>
|
||||
<p>Each received <code>msg.payload</code> will update the text based on the provided <b>Value Format</b>.</p>
|
||||
<p>The <b>Value Format</b> field can be used to change the displayed format and can contain valid HTML and
|
||||
<a href="https://scotch.io/tutorials/all-about-the-built-in-angularjs-filters" target="_blank">Angular filters</a>.</p>
|
||||
<p>For example: <code>{{value | uppercase}} &deg;</code> will uppercase the payload text and add the degree symbol.</p>
|
||||
<p>The label can also be set by a message property by setting
|
||||
the field to the name of the property, for example <code>{{msg.topic}}</code>.</p>
|
||||
<p>The following icon fonts are also available: <a href="https://klarsys.github.io/angular-material-icons/" target="_blank">Material Design icon</a>
|
||||
<i>(e.g. 'check', 'close')</i> or a <a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icon</a>
|
||||
<i>(e.g. 'fa-fire')</i>, or a <a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css_mappings.md">Weather icon</a>.
|
||||
You can use the full set of google material icons if you add 'mi-' to the icon name. e.g. 'mi-videogame_asset'.</p>
|
||||
<p>The widget also has a class of <code>nr-dashboard-widget-{the_widget_label_with_underscores}</code> which can be used for additional
|
||||
styling if required. You may need to use the <i>!important</i> flag to override the theme.</p>
|
||||
</script>
|
||||
51
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_text.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
module.exports = function(RED) {
|
||||
var ui = require('../ui')(RED);
|
||||
|
||||
function TextNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
var node = this;
|
||||
|
||||
var group = RED.nodes.getNode(config.group);
|
||||
if (!group) { return; }
|
||||
var tab = RED.nodes.getNode(group.config.tab);
|
||||
if (!tab) { return; }
|
||||
|
||||
var layout = config.layout||"row-spread";
|
||||
var angLayout = "row";
|
||||
var angLayoutAlign = "space-between center";
|
||||
if (layout === "row-spread") { angLayout = 'row'; angLayoutAlign = 'space-between center'}
|
||||
else if (layout === "row-left") { angLayout = 'row'; angLayoutAlign = 'start center'}
|
||||
else if (layout === "row-center") { angLayout = 'row'; angLayoutAlign = 'center center'}
|
||||
else if (layout === "row-right") { angLayout = 'row'; angLayoutAlign = 'end center'}
|
||||
else if (layout === "col-center") { angLayout = 'column'; angLayoutAlign = 'center center'}
|
||||
var done = ui.add({
|
||||
emitOnlyNewValues: false,
|
||||
node: node,
|
||||
tab: tab,
|
||||
group: group,
|
||||
control: {
|
||||
type: 'text',
|
||||
label: config.label,
|
||||
order: config.order,
|
||||
format: config.format,
|
||||
width: config.width || group.config.width || 6,
|
||||
height: config.height || 1,
|
||||
layout: angLayout,
|
||||
layoutAlign: angLayoutAlign
|
||||
},
|
||||
convert: function(value) {
|
||||
if (value !== undefined) {
|
||||
if (Buffer.isBuffer(value)) {
|
||||
value = value.toString('binary');
|
||||
}
|
||||
else {
|
||||
value = value.toString();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
node.on("close", done);
|
||||
}
|
||||
RED.nodes.registerType("ui_text", TextNode);
|
||||
};
|
||||
114
nodered/rootfs/data/node_modules/node-red-dashboard/nodes/ui_text_input.html
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('ui_text_input',{
|
||||
category: 'dashboard',
|
||||
color: 'rgb(176, 223, 227)',
|
||||
defaults: {
|
||||
name: {value: ''},
|
||||
label: {value: ''},
|
||||
tooltip: {value: ''},
|
||||
group: {type: 'ui_group', required: true},
|
||||
order: {value: 0},
|
||||
width: {value: 0, validate: function(v) {
|
||||
var width = v||0;
|
||||
var currentGroup = $('#node-input-group').val()||this.group;
|
||||
var groupNode = RED.nodes.node(currentGroup);
|
||||
var valid = !groupNode || +width <= +groupNode.width;
|
||||
$("#node-input-size").toggleClass("input-error",!valid);
|
||||
return valid;
|
||||
}
|
||||
},
|
||||
height: {value: 0},
|
||||
passthru: {value: true},
|
||||
mode: {value: 'text', required: true},
|
||||
delay: {value: 300, validate: RED.validators.number()},
|
||||
topic: {value: ''}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
outputLabels: function() { return this.mode; },
|
||||
icon: "ui_text.png",
|
||||
paletteLabel: 'text input',
|
||||
label: function() { return this.name || (~this.label.indexOf("{{") ? null : this.label) || this.mode+' input'; },
|
||||
labelStyle: function() { return this.name?"node_label_italic":""; },
|
||||
oneditprepare: function() {
|
||||
$("#node-input-size").elementSizer({
|
||||
width: "#node-input-width",
|
||||
height: "#node-input-height",
|
||||
group: "#node-input-group"
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-template-name="ui_text_input">
|
||||
<div class="form-row">
|
||||
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
||||
<input type="text" id="node-input-group">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label><i class="fa fa-object-group"></i> Size</label>
|
||||
<input type="hidden" id="node-input-width">
|
||||
<input type="hidden" id="node-input-height">
|
||||
<button class="editor-button" id="node-input-size"></button>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-label"><i class="fa fa-i-cursor"></i> Label</label>
|
||||
<input type="text" id="node-input-label">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-tooltip"><i class="fa fa-info-circle"></i> Tooltip</label>
|
||||
<input type="text" id="node-input-tooltip" placeholder="optional tooltip">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-mode"><i class="fa fa-keyboard-o"></i> Mode</label>
|
||||
<select style="width:128px" id="node-input-mode">
|
||||
<option value="text">text input</option>
|
||||
<option value="email">email address</option>
|
||||
<option value="password">password</option>
|
||||
<option value="number">number</option>
|
||||
<option value="tel">telephone input</option>
|
||||
<option value="color">color picker</option>
|
||||
<option value="time">time picker</option>
|
||||
<option value="week">week picker</option>
|
||||
<option value="month">month picker</option>
|
||||
</select>
|
||||
<label for="node-input-delay" style="text-align:right; width:100px"><i class="fa fa-clock-o"></i> Delay (ms)</label>
|
||||
<input type="text" style="width:58px" id="node-input-delay">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-passthru"><i class="fa fa-arrow-right"></i> If <code>msg</code> arrives on input, pass through to output: </label>
|
||||
<input type="checkbox" checked id="node-input-passthru" style="display:inline-block; width:auto; vertical-align:top;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="width:auto" for="node-input-payload"><i class="fa fa-envelope-o"></i> When changed, send:</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label style="padding-left: 25px; margin-right: -25px">Payload</label>
|
||||
<label style="width:auto">Current value</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic" style="padding-left: 25px; margin-right: -25px">Topic</label>
|
||||
<input type="text" id="node-input-topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name">
|
||||
</div>
|
||||
<div class="form-tips">Setting <b>Delay</b> to 0 waits for Enter or Tab key, to send input.</span></div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" data-help-name="ui_text_input">
|
||||
<p>Adds a text input field to the user interface. Mode can be regular text, email or color picker.</p>
|
||||
<p>Any input is sent as <code>msg.payload</code>. If set to ‘pass through mode’ an arriving <code>msg.payload</code>
|
||||
will be used if it is different from the existing text in the input field. This allows you to preset
|
||||
the text of the input field.</p>
|
||||
<p>The <b>Delay</b> <i>(default : 300ms)</i> sets the amount of time in milliseconds before the output is sent.
|
||||
Setting to <code>0</code> waits for "Enter" or "Tab" key to send. Enter will send payload but remain in focus.
|
||||
Tab will send payload and move to next field. Clicking elsewhere will also send the payload.</p>
|
||||
<p>The email mode will color in red if it is not a valid address and will return undefined.</p>
|
||||
<p>The time input type returns a number of milliseconds from midnight.</p>
|
||||
<p>Not all browsers support the <i>week</i> and <i>month</i> input types, and may return <i>undefined</i>.
|
||||
Please test your target browser(s) before use.</p>
|
||||
<p>If a <b>Topic</b> is specified, it will be added as <code>msg.topic</code>.</p>
|
||||
<p>Setting <code>msg.enabled</code> to <code>false</code> will disable the input.</p>
|
||||
</script>
|
||||