diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d4d8c..ec6048c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# 1.35.0 (07/21/2016) + +## Features + + - Header Widget: Added built-in Parameter editing to the Header Widget, standardizing a common use-case for many Dashboards. Supports editing via textbox, checkbox, dropdown, list of links, datetime, date, or time. Dropdowns or link lists can be populating using results from a Data Source. Datetime/date/time types feature a UI date time picker, or can be edited manually. + + - Widget Help Tooltips: Added new, optional help text to each Widget, which appears in a tooltip over a question mark icon in the top-right corner of the Widget. Useful to provide users some context or more information about the data being displayed. + + - Upgraded Modernizer to 3.3.1 and tweaked feature selection. + +## Bug Fixes + + - Fixed issues with Incompatible Browser message appearing in Chrome when zooming in. + # 1.34.0 (07/07/2016) ## Features diff --git a/cyclotron-site/app/partials/editor/parameter.jade b/cyclotron-site/app/partials/editor/parameter.jade index 5331e78..87e7d21 100644 --- a/cyclotron-site/app/partials/editor/parameter.jade +++ b/cyclotron-site/app/partials/editor/parameter.jade @@ -6,4 +6,4 @@ i.fa.fa-times span Remove Parameter -.editor-property-set(model='editor.selectedItem', definition='dashboardProperties.parameters.properties') +.editor-property-set(dashboard='editor.dashboard', model='editor.selectedItem', definition='dashboardProperties.parameters.properties') diff --git a/cyclotron-site/app/partials/editor/propertySet.jade b/cyclotron-site/app/partials/editor/propertySet.jade index 5f025e6..b5a7aca 100644 --- a/cyclotron-site/app/partials/editor/propertySet.jade +++ b/cyclotron-site/app/partials/editor/propertySet.jade @@ -30,7 +30,7 @@ .well.well-sm(ng-switch-when='propertyset') div.recursive - .editor-property-set(model='model[value.name]', definition='value.properties') + .editor-property-set(dashboard='dashboard', model='model[value.name]', definition='value.properties') .well.well-sm(ng-switch-when='propertyset[]') div.recursive diff --git a/cyclotron-site/app/partials/help/3rdparty.jade b/cyclotron-site/app/partials/help/3rdparty.jade index a5448b4..3bcdddf 100644 --- a/cyclotron-site/app/partials/help/3rdparty.jade +++ b/cyclotron-site/app/partials/help/3rdparty.jade @@ -103,6 +103,11 @@ table a(href='http://ivaynberg.github.io/select2/', target='_blank') Select2 td 3.5.0 td Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results + tr + td + a(href='http://xdsoft.net/jqplugins/datetimepicker/', target='_blank') DateTimePicker + td 2.5.4 + td jQuery Plugin Date and Time Picker tr td a(href='http://fgnass.github.io/spin.js/', target='_blank') spin.js diff --git a/cyclotron-site/app/partials/help/parameters.jade b/cyclotron-site/app/partials/help/parameters.jade index 64ce996..efb77c3 100644 --- a/cyclotron-site/app/partials/help/parameters.jade +++ b/cyclotron-site/app/partials/help/parameters.jade @@ -1,43 +1,82 @@ h3 Parameters -p The - em parameters - | property is an optional list of Parameters that can be used to configure the Dashboard. Each item in the array - | defines a Parameter by name. Each Parameter can have a - em defaultValue - | provided as well. +p Cyclotron provides support for Parameters, which are optionally-defined values used to configure the Dashboard. They can be used almost everywhere in Cyclotron, from Data Sources to Widgets, etc. Parameters should be used for values that can be modified while viewing the Dashboard, but are also convenient for constant values used in many places in a Dashboard, like connection information or a server name. -pre.code. - "parameters": [{ - "name": "numberOfHours" - "defaultValue": 4 - }] +strong Benefits of using Parameters + +ul + li Centralized configuration, making it easy to change configuration which might be repeated in multiple Data Sources or Widgets + li Automatic URL synchronization + li Persistent value across sessions + li Built-in editor in the Header Widget + +p These features are all optional per Parameter, so you can store both user-facing and internal configuration in Parameters. h4 Parameters in the URL -p Parameters can be set when loading the Dashboard by using URL query parameters. Here is an example that sets two Parameters via the URL: +p By default, Parameters are synchronized to/from the URL automatically. That is, Parameters can be loaded from the URL query string when loading a Dashboard, and any changes to the Parameters will be reflected back to the URL. This allows a user to copy and share the current URL, including the current configuration. + +p Here is an example that sets two Parameters via the URL: pre.code. http://cyclotron/MyDashboard?numberOfHours=8&includeFailures=true -p If any Parameters are modified by the Dashboard, the URL will be automatically updated with the new values. +p The URL contains two Parameters, + em numberOfHours + | and + em includeFailures + | , both of which will be initialized when the Dashboard opens. Any query string parameters will be loaded automatically into Cyclotron, even if they are not defined in the Dashboard configuration. + +p If any Parameters are modified by the Dashboard (e.g. by JavaScript), the URL will be automatically updated with the new, non-default values. If a Parameter has a + em defaultValue + | , it will only appear in the URL when it has a non-default value. -p All Parameters appear in the URL by default, but this can be disabled for individual Parameters by setting +p URL synchronization can be disabled for individual Parameters by setting em showInURL | to false. It is still possible to set these Parameters via the URL on load, but they will be automatically stripped from the URL after loading. h4 Persistent Parameters -p Persistent Parameters retain their value across multiple sessions of viewing a Dashboard. This is enabled by setting +p Persistent Parameters retain their value across multiple sessions of viewing a Dashboard with the same browser. This is disabled by default, but can be enabled by setting em persistent | to true. Once enabled, any changes to the Parameter will be immediately cached in the browser, and reloaded upon subsequent visits to the same dashboard. Persistent Parameters are stored by name, per Dashboard. +p Parameters are not stored server-side, so they will not persist across different browsers, devices, or after clearing browsing data. + p Cyclotron attempts to load Parameters in the following order: ol li All URL query string parameters are loaded li Persistent Parameters which are not yet set will have their value retrieved from cache (if possible) li Parameters which are not yet set will have be assigned a default value (if exists) +h4 Change Event + +p Each Parameter has an optional + em changeEvent + | property that, if defined, runs a custom JavaScript function whenever the value of the Parameter changes. It doesn't run upon initialization of the Dashboard, but only if the value is changed subsequently. + +p The property expects a JavaScript function in the following form: +pre.code. + function(parameterName, newValue, oldValue) { + // event handler + } + +h4 Editing via the Header Widget + +p The Header Widget has built-in support for modifying the value of Parameters while viewing a Dashboard. Each enabled Parameter will appear in the Header Widget with the current value, and users viewing the Dashboard can edit the Parameters' values using various editor types (e.g. textbox, checkbox, dropdown, datetime, etc.). Properties under the + em editing + | property set can determine how the Parameter is displayed and edited. + +p In order to enable this feature, the Header Widget must have the + em parameters.showParameters + | property set to true; additionally at least one Parameter must have the + em editInHeader + | property set to true (defaults to false). This feature is opt-in for each Parameter. + +p The Header Widget can also display a button for applying Parameter changes, with an event handler property that runs a JavaScript method whenever the user clicks on the button. Alternately, each Parameter can have the + em changeEvent + | property set, as described above. + h4 JavaScript API p Parameters are also exposed to Dashboards through JavaScript. The diff --git a/cyclotron-site/app/scripts/common/app.coffee b/cyclotron-site/app/scripts/common/app.coffee index 7c1ab44..7359aef 100644 --- a/cyclotron-site/app/scripts/common/app.coffee +++ b/cyclotron-site/app/scripts/common/app.coffee @@ -83,6 +83,7 @@ cyclotronApp.config ($stateProvider, $urlRouterProvider, $locationProvider, $con lazyLoad = (jsDependencies, cssDependencies) -> ['$q', '$rootScope', ($q, $rootScope) -> deferred = $q.defer() + cyclotronApp.loadedScripts ?= [] # Load stylesheets if cssDependencies? diff --git a/cyclotron-site/app/scripts/common/services/services.commonConfigService.coffee b/cyclotron-site/app/scripts/common/services/services.commonConfigService.coffee index 20393a1..25c472d 100644 --- a/cyclotron-site/app/scripts/common/services/services.commonConfigService.coffee +++ b/cyclotron-site/app/scripts/common/services/services.commonConfigService.coffee @@ -26,7 +26,7 @@ cyclotronServices.factory 'commonConfigService', -> exports = { - version: '1.34.0' + version: '1.35.0' logging: enableDebug: false @@ -360,6 +360,30 @@ cyclotronServices.factory 'commonConfigService', -> default: '1' required: false order: 101 + height: + label: 'Height' + description: 'If set, specifies the absolute display height of the widget. Any valid CSS value can be used (e.g. "200px", "40%", etc).' + placeholder: 'Height' + type: 'string' + required: false + defaultHidden: true + order: 102 + width: + label: 'Width' + description: 'If set, specifies the absolute display width of the widget. Any valid CSS value can be used (e.g. "200px", "40%", etc).' + placeholder: 'Width' + type: 'string' + required: false + defaultHidden: true + order: 103 + helpText: + label: 'Help Text' + description: 'Provides an optional help text for the Widget, available via a help icon in the corner of the Widget.' + type: 'string' + required: false + inlineJs: true + defaultHidden: true + order: 109 theme: label: 'Theme' description: 'If set, overrides the Page theme and allows a widget to have a different theme from the rest of the Page and Widgets.' @@ -367,7 +391,7 @@ cyclotronServices.factory 'commonConfigService', -> inherit: true required: false defaultHidden: true - order: 102 + order: 110 noData: label: 'No Data Message' description: 'If set, displays this message in the Widget when no data is loaded from the Data Source. If not set, no message will be displayed' @@ -375,7 +399,7 @@ cyclotronServices.factory 'commonConfigService', -> inlineJs: true required: false defaultHidden: true - order: 103 + order: 111 noscroll: label: 'No Scroll' description: 'If set to true, the widget will not have scrollbars and any overflow will be hidden. The effect of this setting varies per widget.' @@ -383,7 +407,7 @@ cyclotronServices.factory 'commonConfigService', -> default: false required: false defaultHidden: true - order: 104 + order: 112 allowFullscreen: label: 'Allow Fullscreen' description: 'If true, the Widget can be maximized to fill the entire Dashboard; if false, the ability to view in fullscreen is disabled. This property overrides the Page setting.' @@ -391,7 +415,7 @@ cyclotronServices.factory 'commonConfigService', -> inherit: true required: false defaultHidden: true - order: 105 + order: 113 showWidgetErrors: label: 'Show Error Messages on Widgets' description: 'If true, allows error messages to be displayed on Widgets. This property overrides the Page setting.' @@ -399,7 +423,7 @@ cyclotronServices.factory 'commonConfigService', -> required: false inherit: true defaultHidden: true - order: 106 + order: 114 hidden: label: 'Hidden' description: 'If true, the Widget will not be displayed in the Dashboard and will not occupy space in the Layout rendering. The Widget will still be initialized, however.' @@ -407,22 +431,7 @@ cyclotronServices.factory 'commonConfigService', -> default: false required: false defaultHidden: true - order: 107 - height: - label: 'Height' - description: 'If set, specifies the absolute display height of the widget. Any valid CSS value can be used (e.g. "200px", "40%", etc).' - placeholder: 'Height' - type: 'string' - required: false - defaultHidden: true - width: - label: 'Width' - description: 'If set, specifies the absolute display width of the widget. Any valid CSS value can be used (e.g. "200px", "40%", etc).' - placeholder: 'Width' - type: 'string' - required: false - defaultHidden: true - + order: 115 order: 3 duration: label: 'Auto-Rotate Duration (seconds)' @@ -1034,13 +1043,82 @@ cyclotronServices.factory 'commonConfigService', -> default: true required: false order: 2 + editInHeader: + label: 'Editable in Header' + description: 'If true, the Parameter will be displayed and configurable in the Parameter section of the Header Widget (if used).' + type: 'boolean' + default: false + required: false + order: 3 persistent: label: 'Persistent' description: 'If true, the value of this Parameter will be persisted in the user\'s browser across multiple sessions.' type: 'boolean' default: false required: false - order: 3 + order: 4 + changeEvent: + label: 'Change Event' + description: 'This event occurs when the Parameter value is modified. It does not fire when the Dashboard is being initialized. Expects a JavaScript function in the form function(parameterName, newValue, oldValue).' + type: 'editor' + editorMode: 'javascript' + required: false + defaultHidden: true + order: 10 + editing: + label: 'Editing' + description: 'Configuration for how this Parameter can be edited in the Dashboard.' + type: 'propertyset' + required: false + default: {} + defaultHidden: true + order: 15 + properties: + displayName: + label: 'Display Name' + description: 'The display name used for this Parameter.' + type: 'string' + required: false + placeholder: 'Display Name' + order: 1 + editorType: + label: 'Editor Type' + description: 'Determines the type of editor used to configured this Parameter (e.g. in the Header Widget).' + type: 'string' + required: false + default: 'textbox' + order: 2 + options: + textbox: + value: 'textbox' + dropdown: + value: 'dropdown' + links: + value: 'links' + checkbox: + value: 'checkbox' + datetime: + value: 'datetime' + date: + value: 'date' + time: + value: 'time' + dataSource: + label: 'Data Source' + description: 'Optionally specifies a Data Source providing dropdown options for this Parameter.' + placeholder: 'Data Source name' + type: 'string' + required: false + options: datasourceOptions + order: 4 + datetimeFormat: + label: 'Date/Time Format' + description: 'The Moment.js-compatible date/time format string used to read/write datetimes to this Parameter. Only used if the editor type is "datetime", "date", or "time". Defaults to an ISO 8601 format.' + type: 'string' + required: false + placeholder: 'Format' + defaultHidden: true + order: 5 sample: name: '' defaultValue: '' @@ -2249,6 +2327,51 @@ cyclotronServices.factory 'commonConfigService', -> required: false inlineJs: true order: 20 + + parameters: + label: 'Parameters' + description: 'Contains properties for displaying Dashboard Parameters in the header.' + type: 'propertyset' + order: 20 + properties: + showParameters: + label: 'Show Parameters' + description: 'Determines whether Parameters will be shown.' + type: 'boolean' + default: false + required: false + inlineJs: true + order: 1 + showUpdateButton: + label: 'Show Update Button' + description: 'If true, an "Update" button will be displayed after the Parameters. The updateEvent property must be used to apply an action to the button click event, else nothing will happen.' + type: 'boolean' + default: false + required: false + order: 2 + updateButtonLabel: + label: 'Update Button Label' + description: 'Customizes the label for the Update button, if shown.' + type: 'string' + default: 'Update' + defaultHidden: true + required: false + order: 2 + updateEvent: + label: 'Update Button Click Event' + description: 'This event occurs when the Update button is clicked, if shown.' + type: 'editor' + editorMode: 'javascript' + required: false + order: 10 + parametersIncluded: + label: 'Included Parameters' + description: 'Optionally specifies an array of Parameter names, limiting the Header to only displaying the specified Parameters. This does not override the editInHeader property of each Parameter, which needs to be set true to appear in the Header.' + type: 'string[]' + required: false + defaultHidden: true + order: 11 + customHtml: label: 'HTML Content' description: 'Provides additional HTML content to be displayed in the header. This can be used to customize the header display.' @@ -2256,7 +2379,7 @@ cyclotronServices.factory 'commonConfigService', -> editorMode: 'html' required: false inlineJs: true - order: 11 + order: 30 html: name: 'html' icon: 'fa-html5' diff --git a/cyclotron-site/app/scripts/dashboards/controller.dashboard.coffee b/cyclotron-site/app/scripts/dashboards/controller.dashboard.coffee index dba5830..250928a 100644 --- a/cyclotron-site/app/scripts/dashboards/controller.dashboard.coffee +++ b/cyclotron-site/app/scripts/dashboards/controller.dashboard.coffee @@ -250,6 +250,11 @@ cyclotronApp.controller 'DashboardController', ($scope, $stateParams, $localFora deeplinkOptions[key] = value exportOptions[key] = value + if parameterDefinition? and not _.isEqual value, oldParameters[key] + changeHandler = _.jsEval parameterDefinition.changeEvent + if _.isFunction changeHandler + changeHandler key, value, oldParameters[key] + return # Create export options from non-default parameters diff --git a/cyclotron-site/app/scripts/dashboards/directives/directives.datetimepicker.coffee b/cyclotron-site/app/scripts/dashboards/directives/directives.datetimepicker.coffee new file mode 100644 index 0000000..6ffd768 --- /dev/null +++ b/cyclotron-site/app/scripts/dashboards/directives/directives.datetimepicker.coffee @@ -0,0 +1,97 @@ +### +# Copyright (c) 2016 the original author or authors. +# +# Licensed under the MIT License (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.opensource.org/licenses/mit-license.php +# +# 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. +### + +cyclotronDirectives.directive 'datetimepicker', ($timeout) -> + { + restrict: 'EAC' + require: '?ngModel' + template: '' + scope: + options: '=' + + link: (scope, element, attrs, ngModelCtrl) -> + + textbox = element.find 'input[type=text]' + + # Default options + defaultOptions = + scrollMonth: false + format: 'Y-m-d H:i' + formatDate: 'Y-m-d' + formatTime: 'H:i' + onChangeDateTime: (value, input) -> + # Handle changes from the datetimepicker + if ngModelCtrl? then scope.$apply -> + # Set the model and re-initialize the datetimepicker + ngModelCtrl.$setViewValue value + ngModelCtrl.$render() + + # Convert back to the user-defined format and update textbox + formatted = moment(value).format mergedOptions.datetimeFormat + textbox.val formatted + + return + + + # Apply custom options over defaults + mergedOptions = _.merge defaultOptions, scope.options + + if ngModelCtrl? + ngModelCtrl.$render = -> + # Set the value of the datetimepicker + mergedOptions.value = moment(ngModelCtrl.$viewValue).toDate() + + # Initialize the datetimepicker plugin + element.datetimepicker mergedOptions + + return + + ngModelCtrl.$formatters.push (modelValue) -> + if modelValue + m = null + # Support either moments, dates, or strings + if moment.isMoment(modelValue) + m = modelValue + else if moment.isDate(modelValue) + m = moment(modelValue) + else + # Parse from string. Use specified format or ISO 8601 + m = moment(modelValue, [mergedOptions.datetimeFormat, moment.ISO_8601]) + + # Convert to the user-defined format and update textbox + formatted = m.format mergedOptions.datetimeFormat + textbox.val formatted + + # Return a JavaScript date to be used in the jQuery plugin + return m.toDate() + + ngModelCtrl.$parsers.push (viewValue) -> + if viewValue + # Convert to the user-defined format is update the model + formatted = moment(viewValue).format mergedOptions.datetimeFormat + return formatted + + # Handle manual changes to the textbox + textbox.on 'keyup', (e) -> + if ngModelCtrl? + modelValue = this.value + m = moment(modelValue, mergedOptions.datetimeFormat) + if m.isValid() then scope.$apply -> + # Update the view and re-initialize the plugin + ngModelCtrl.$setViewValue m.toDate() + ngModelCtrl.$render() + return + } diff --git a/cyclotron-site/app/scripts/dashboards/directives/directives.widget.coffee b/cyclotron-site/app/scripts/dashboards/directives/directives.widget.coffee index 06fe782..15811ca 100644 --- a/cyclotron-site/app/scripts/dashboards/directives/directives.widget.coffee +++ b/cyclotron-site/app/scripts/dashboards/directives/directives.widget.coffee @@ -101,6 +101,11 @@ cyclotronDirectives.directive 'widget', ($compile, $sce, $window, layoutService) $element.height scope.widgetHeight $element.css 'display', 'block' + if scope.widgetWidth < scope.widgetHeight + $element.addClass 'widget-skinny' + else + $element.removeClass 'widget-skinny' + # Set gutter padding (other sides are handled by masonry) $element.css 'margin-bottom', layout.gutter @@ -157,7 +162,11 @@ cyclotronDirectives.directive 'widget', ($compile, $sce, $window, layoutService) template = '
' if widget.allowFullscreen != false - template = '' + template + template = '' + template + + if widget.helpText? + scope.helpText = _.jsExec widget.helpText + template = '' + template compiledValue = $compile(template)(scope) diff --git a/cyclotron-site/app/styles/common/main.less b/cyclotron-site/app/styles/common/main.less index 325ba33..43a35f2 100644 --- a/cyclotron-site/app/styles/common/main.less +++ b/cyclotron-site/app/styles/common/main.less @@ -16,8 +16,6 @@ @import 'variables.less'; -@bodyColor: #222; - html, body { margin: 0; padding: 0; diff --git a/cyclotron-site/app/styles/common/variables.less b/cyclotron-site/app/styles/common/variables.less index 0c2cff8..d83105c 100644 --- a/cyclotron-site/app/styles/common/variables.less +++ b/cyclotron-site/app/styles/common/variables.less @@ -16,9 +16,10 @@ @phonePortraitMaxWidth: 400px; -@highlight-shadow-color: rgba(81, 203, 238, 1); - +@accentColor: #4A89DC; +@bodyColor: #222; @lighterText: #777; +@highlight-shadow-color: rgba(81, 203, 238, 1); /* Customize scrollbar (webkit) */ .custom-scrollbar() { diff --git a/cyclotron-site/app/styles/dashboards/dashboard.less b/cyclotron-site/app/styles/dashboards/dashboard.less index 5bcce34..94d7c06 100644 --- a/cyclotron-site/app/styles/dashboards/dashboard.less +++ b/cyclotron-site/app/styles/dashboards/dashboard.less @@ -133,21 +133,37 @@ top: 0; width: 100%; } + } + + .dashboard-widgetwrapper { + float: left; + background: none; - .widget-fullscreen { + > i { position: absolute; - right: 4px; top: 4px; - opacity: .4; cursor: pointer; z-index: 1000; .user-select(none); + + opacity: 0.4; + &:hover { + opacity: 0.7; + } + } + > i.widget-fullscreen { + right: 4px; } - } - .dashboard-widgetwrapper { - float: left; - background: none; + > i.widget-helptext { + right: 24px; + } + + > .tooltip { + .tooltip-arrow { + right: 1px !important; + } + } > .dashboard-widget { .box-sizing(border-box); @@ -171,6 +187,14 @@ @media only screen and (max-width: 1024px) { font-size: 2.5em; line-height: 1.3em; } @media only screen and (max-width: 600px) { font-size: 2.0em; line-height: 1.3em; } } + + i.fa.fa-question-circle { + opacity: 0.7; + &:hover { + opacity: 1; + } + } + } /* Center in the middle of the widget */ diff --git a/cyclotron-site/app/styles/themes/dark.less b/cyclotron-site/app/styles/themes/dark.less index 144053a..c01ecba 100644 --- a/cyclotron-site/app/styles/themes/dark.less +++ b/cyclotron-site/app/styles/themes/dark.less @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 the original author or authors. + * Copyright (c) 2013-2016 the original author or authors. * * Licensed under the MIT License (the "License"); * you may not use this file except in compliance with the License. @@ -23,10 +23,12 @@ @color: #D1D1D1; @pageBackgroundColor: #2f2f2f; @widgetBackgroundColor: #202020; +@widgetBackgroundAccentColor: @pageBackgroundColor; +@widgetBackgroundAccentBorderColor: lighten(@widgetBackgroundAccentColor, 10%); @linkColor: lighten(@color, 15%); -@accentColor: lighten(@widgetBackgroundColor, 20%); @headerColor: #202020; +@tableRowHoverBackgroundColor: lighten(@widgetBackgroundColor, 20%); @tableBorderColor: #ccc; /* Dashboard Styles */ @@ -76,30 +78,44 @@ } /* Widget styles */ -.dashboard-dark.dashboard-widgetwrapper > .dashboard-widget { - - color: @color; - background-color: @widgetBackgroundColor; +.dashboard-dark.dashboard-widgetwrapper { - h1,h2,h3,h4,h5,h6 { - color: White; + > .tooltip { + .tooltip-inner { + background-color: @pageBackgroundColor; + color: @color; + } + .tooltip-arrow { + border-top-color: @pageBackgroundColor; + border-bottom-color: @pageBackgroundColor; + } } - button, - input, - optgroup, - select, - textarea { - color: black; - } + > .dashboard-widget { - a { - color: @linkColor; - text-decoration: none; - border-bottom: 1px dotted #888; + color: @color; + background-color: @widgetBackgroundColor; - &:hover { - color: lighten(@color, 30%); + h1,h2,h3,h4,h5,h6 { + color: White; + } + + button, + input, + optgroup, + select, + textarea { + color: black; + } + + a { + color: @linkColor; + text-decoration: none; + border-bottom: 1px dotted #888; + + &:hover { + color: lighten(@color, 30%); + } } } } @@ -131,7 +147,26 @@ @import "../../widgets/youtube/_youtube.less"; /* Extra styles */ + h1.title { + > .tooltip { + .tooltip-inner { + background-color: @pageBackgroundColor; + color: @color; + } + .tooltip-arrow { + border-top-color: @pageBackgroundColor; + border-bottom-color: @pageBackgroundColor; + } + } + } + .table-widget table th { font-style: italic; } + + .header-widget .parameters { + .header-parameter, button { + .rounded(4px); + } + } } diff --git a/cyclotron-site/app/styles/themes/dark2.less b/cyclotron-site/app/styles/themes/dark2.less index 69ab395..93d077f 100644 --- a/cyclotron-site/app/styles/themes/dark2.less +++ b/cyclotron-site/app/styles/themes/dark2.less @@ -23,13 +23,15 @@ @color: #D1D1D1; @pageBackgroundColor: #000; @widgetBackgroundColor: #000; +@widgetBackgroundAccentColor: #202020; +@widgetBackgroundAccentBorderColor: lighten(@widgetBackgroundAccentColor, 10%); -@linkColor: lighten(@color, 10%); @accentColor: #0A5D9C; +@linkColor: lighten(@color, 10%); @headerColor: #202020; -@tableBorderColor: #ccc; - +@tableRowHoverBackgroundColor: @accentColor; @headerPadding: 5px; +@tableBorderColor: #ccc; /* Dashboard Styles */ .dashboard.dashboard-dark2 { @@ -68,49 +70,62 @@ &.dashboard-dark2 { color: @color; background-color: @pageBackgroundColor; - - .widget-fullscreen { - top: (2*@headerPadding); - right: (2*@headerPadding); - - &:hover { - color: @accentColor; - } - } } } /* Widget styles */ -.dashboard-dark2.dashboard-widgetwrapper > .dashboard-widget { - - color: @color; - background-color: @widgetBackgroundColor; +.dashboard-dark2.dashboard-widgetwrapper { + > .widget-fullscreen, > .widget-helptext { + top: (2*@headerPadding); + right: (2*@headerPadding); - h1,h2,h3,h4,h5,h6 { - color: White; + &:hover { + color: @accentColor; + } } - h1.title { - background-color: @headerColor; - margin: 0; - padding: @headerPadding; + > .tooltip { + .tooltip-inner { + background-color: #666; + color: White; + } + .tooltip-arrow { + border-top-color: #666; + border-bottom-color: #666; + } } - button, - input, - optgroup, - select, - textarea { - color: black; - } + > .dashboard-widget { - a { - color: @linkColor; - text-decoration: none; - border-bottom: 0; + color: @color; + background-color: @widgetBackgroundColor; - &:hover { - color: lighten(@color, 5%); + h1,h2,h3,h4,h5,h6 { + color: White; + } + + h1.title { + background-color: @headerColor; + margin: 0; + padding: @headerPadding; + } + + button, + input, + optgroup, + select, + textarea { + color: black; + } + + a { + color: @linkColor; + text-decoration: none; + border-bottom: 0; + + &:hover { + color: lighten(@color, 5%); + } } } } diff --git a/cyclotron-site/app/styles/themes/gto.less b/cyclotron-site/app/styles/themes/gto.less index 34dcd57..a238a9c 100644 --- a/cyclotron-site/app/styles/themes/gto.less +++ b/cyclotron-site/app/styles/themes/gto.less @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 the original author or authors. + * Copyright (c) 2013-2016 the original author or authors. * * Licensed under the MIT License (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,16 @@ /* Variables */ @color: black; -@pageBackgroundColor: white; -@widgetBackgroundColor: white; - @linkColor: #081F79; -@accentColor: #efefef; @headerColor: #16365c; +@tableRowHoverBackgroundColor: #efefef; @tableBorderColor: #555; +@pageBackgroundColor: white; +@widgetBackgroundColor: white; +@widgetBackgroundAccentColor: @tableRowHoverBackgroundColor; +@widgetBackgroundAccentBorderColor: darken(@widgetBackgroundAccentColor, 10%); + /* Dashboard Styles */ .dashboard.dashboard-gto { background-color: @pageBackgroundColor; diff --git a/cyclotron-site/app/styles/themes/light.less b/cyclotron-site/app/styles/themes/light.less index 43a7add..b54ec1b 100644 --- a/cyclotron-site/app/styles/themes/light.less +++ b/cyclotron-site/app/styles/themes/light.less @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 the original author or authors. + * Copyright (c) 2013-2016 the original author or authors. * * Licensed under the MIT License (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,16 @@ /* Variables */ @color: black; -@pageBackgroundColor: white; -@widgetBackgroundColor: white; - @linkColor: #081F79; -@accentColor: #efefef; @headerColor: white; +@tableRowHoverBackgroundColor: #efefef; @tableBorderColor: #555; +@pageBackgroundColor: white; +@widgetBackgroundColor: white; +@widgetBackgroundAccentColor: @tableRowHoverBackgroundColor; +@widgetBackgroundAccentBorderColor: darken(@widgetBackgroundAccentColor, 10%); + /* Dashboard Styles */ .dashboard.dashboard-light { background-color: @pageBackgroundColor; @@ -52,10 +54,7 @@ .dashboard-light.dashboard-widgetwrapper > .dashboard-widget { .rounded(4px); padding: 10px; - -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 6px 0px; - -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 6px 0px; - -o-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 0 1px 6px 0px; - box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0, rgba(0, 0, 0, 0.8) 1px 1px 6px 0px; + .box-shadow(1px 1px 6px 0 rgba(0, 0, 0, 0.8)); } } @@ -113,4 +112,10 @@ .table-widget table th { font-style: italic; } + + .header-widget .parameters { + .header-parameter, button { + .rounded(4px); + } + } } diff --git a/cyclotron-site/app/styles/themes/lightborderless.less b/cyclotron-site/app/styles/themes/lightborderless.less index 5c86cff..9973a79 100644 --- a/cyclotron-site/app/styles/themes/lightborderless.less +++ b/cyclotron-site/app/styles/themes/lightborderless.less @@ -23,10 +23,12 @@ @color: black; @pageBackgroundColor: white; @widgetBackgroundColor: white; +@widgetBackgroundAccentColor: white; +@widgetBackgroundAccentBorderColor: white; @linkColor: #081F79; -@accentColor: #efefef; @headerColor: white; +@tableRowHoverBackgroundColor: #efefef; @tableBorderColor: #555; /* Dashboard Styles */ diff --git a/cyclotron-site/app/widgets/header/_header.less b/cyclotron-site/app/widgets/header/_header.less index 3ad5cb5..d3d493a 100644 --- a/cyclotron-site/app/widgets/header/_header.less +++ b/cyclotron-site/app/widgets/header/_header.less @@ -22,10 +22,15 @@ a { color: unset; text-decoration: none; + border-bottom: none; cursor: unset; + &.actionable { cursor: pointer } + h1 { + display: inline-block; + } } .logo { @@ -42,4 +47,80 @@ font-size: 80%; } } + + .parameters { + &:first-child { + // Prevent top margin when parameters is the first element in the header. + margin-top: -0.5rem; + } + + .header-parameter { + float: left; + display: inline-block; + margin-right: 0.5rem; + margin-top: 0.5rem; + padding: 0.75rem; + + i.fa.fa-cog { + margin-left: 0.5rem; + } + + label { + font-weight: 400; + margin-bottom: 0; + } + + input { + margin: 0; padding: 0; + } + input[type="checkbox"] { + margin: 5px 0; + } + select { + margin: 2px 0; + } + + background-color: @widgetBackgroundAccentColor; + border: 1px solid @widgetBackgroundAccentBorderColor; + + .links a.btn { + padding: 0; + margin-left: 0.5rem; + color: @color; + &.selected { + color: @accentColor; + } + } + } + + button { + float: left; + display: inline-block; + color: @color; + margin: 12px 0; + height: 36px; + border: 1px solid @widgetBackgroundAccentBorderColor; + } + } + + .custom-box { + clear: both; + } +} + +.widget-noscroll .header-widget { + overflow-y: hidden; + overflow-x: hidden; +} + +// Skinny overrides +&.widget-skinny { + .header-widget { + .parameters { + .header-parameter { + display: block; + float: none; + } + } + } } diff --git a/cyclotron-site/app/widgets/header/directives.headerParameter.coffee b/cyclotron-site/app/widgets/header/directives.headerParameter.coffee new file mode 100644 index 0000000..fffca7f --- /dev/null +++ b/cyclotron-site/app/widgets/header/directives.headerParameter.coffee @@ -0,0 +1,95 @@ +### +# Copyright (c) 2016 the original author or authors. +# +# Licensed under the MIT License (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.opensource.org/licenses/mit-license.php +# +# 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. +### + +cyclotronDirectives.directive 'headerParameter', ($window, dashboardService, dataService, logService) -> + { + restrict: 'CA' + scope: + dashboard: '=' + parameterDefinition: '=' + replace: true + templateUrl: '/widgets/header/headerParameter.html' + + controller: ($scope) -> + + originalValue = $window.Cyclotron.parameters[$scope.parameterDefinition.name] + + $scope.parameter = + displayName: $scope.parameterDefinition.editing?.displayName || $scope.parameterDefinition.name + editorType: $scope.parameterDefinition.editing?.editorType + value: originalValue + + switch $scope.parameter.editorType + when 'datetime' + $scope.parameter.datetimeOptions = + datepicker: true + timepicker: true + + if $scope.parameterDefinition.editing?.datetimeFormat? + $scope.parameter.datetimeOptions.datetimeFormat = $scope.parameterDefinition.editing.datetimeFormat + else + $scope.parameter.datetimeOptions.datetimeFormat = 'YYYY-MM-DD HH:mm' + + when 'date' + $scope.parameter.datetimeOptions = + datepicker: true + timepicker: false + + if $scope.parameterDefinition.editing?.datetimeFormat? + $scope.parameter.datetimeOptions.datetimeFormat = $scope.parameterDefinition.editing.datetimeFormat + else + $scope.parameter.datetimeOptions.datetimeFormat = 'YYYY-MM-DD' + + when 'time' + $scope.parameter.datetimeOptions = + datepicker: false + timepicker: true + + if $scope.parameterDefinition.editing?.datetimeFormat? + $scope.parameter.datetimeOptions.datetimeFormat = $scope.parameterDefinition.editing.datetimeFormat + else + $scope.parameter.datetimeOptions.datetimeFormat = 'HH:mm' + + $scope.selectValue = (value) -> + $scope.parameter.value = value + $scope.updateParameter() + + $scope.updateParameter = -> + if not _.isEqual $scope.parameter.value, originalValue + $window.Cyclotron.parameters[$scope.parameterDefinition.name] = $scope.parameter.value + originalValue = $scope.parameter.value + logService.debug 'Header Widget:', 'Updated Parameter [' + $scope.parameterDefinition.name + ']:', $scope.parameter.value + + # Initialize DataSource (optional) + dsDefinition = dashboardService.getDataSource $scope.dashboard, $scope.parameterDefinition.editing + $scope.dataSource = dataService.get dsDefinition + if $scope.dataSource? + $scope.dataVersion = 0 + $scope.loading = true + + # Data Source (re)loaded + $scope.$on 'dataSource:' + dsDefinition.name + ':data', (event, eventData) -> + return unless eventData.version > $scope.dataVersion + $scope.dataVersion = eventData.version + $scope.dataSourceData = eventData.data[dsDefinition.resultSet].data + $scope.loading = false + + # Initialize the Data Source + $scope.dataSource.init dsDefinition + + return + + } diff --git a/cyclotron-site/app/widgets/header/header.jade b/cyclotron-site/app/widgets/header/header.jade index 18e669d..8bcebf7 100644 --- a/cyclotron-site/app/widgets/header/header.jade +++ b/cyclotron-site/app/widgets/header/header.jade @@ -1,10 +1,13 @@ div.header-widget(ng-controller='HeaderWidget') - .title(ng-show='showTitle') + .title(ng-if='showTitle') a(ng-href='{{ headerTitle.link }}', ng-class='{ actionable: headerTitle.link }') - h1(ng-show='showTitle', ng-style='{ "font-size": headerTitle.titleSize }') + h1(ng-style='{ "font-size": headerTitle.titleSize }') img.logo(ng-src='{{ headerTitle.logoUrl }}', ng-show='headerTitle.logoUrl', ng-style='{ "height": headerTitle.logoSize }') span {{ title }} span.page-name.separator(ng-if='headerTitle.showPageName') {{ headerTitle.pageNameSeparator }} span.page-name(ng-if='headerTitle.showPageName') {{ page.name }} + .parameters(ng-if='showParameters && parameters.length > 0') + .header-parameter(ng-repeat='parameter in parameters', dashboard='dashboard', parameter-definition='parameter') + button.btn.btn-link(ng-if='showUpdateButton', ng-click='updateButtonClick()') {{ updateButtonLabel }} .custom-box(ng-show='showCustomHtml', ng-bind-html='customHtml()') diff --git a/cyclotron-site/app/widgets/header/headerParameter.jade b/cyclotron-site/app/widgets/header/headerParameter.jade new file mode 100644 index 0000000..c2b26b0 --- /dev/null +++ b/cyclotron-site/app/widgets/header/headerParameter.jade @@ -0,0 +1,25 @@ +.parameter(ng-switch='parameter.editorType') + div(ng-switch-when='dropdown') + label {{ parameter.displayName }}: + select(ng-hide='loading', ng-model='parameter.value', ng-change='updateParameter()', ng-options='item.value as item.name for item in dataSourceData') + i.fa.fa-cog.fa-spin(ng-show='loading') + div.links(ng-switch-when='links') + label {{ parameter.displayName }}: + a.btn.btn-link(ng-hide='loading', ng-repeat='item in dataSourceData', ng-click='selectValue(item.value)', ng-class='{selected: parameter.value == item.value}') {{ item.name }} + i.fa.fa-cog.fa-spin(ng-show='loading') + div(ng-switch-when='checkbox') + label + input(type='checkbox', ng-model='parameter.value', ng-change='updateParameter()') + | {{ parameter.displayName }} + div(ng-switch-when='datetime') + label {{ parameter.displayName }}: + span(datetimepicker, options='parameter.datetimeOptions', ng-model='parameter.value', ng-change='updateParameter()') + div(ng-switch-when='date') + label {{ parameter.displayName }}: + span(datetimepicker, options='parameter.datetimeOptions', ng-model='parameter.value', ng-change='updateParameter()') + div(ng-switch-when='time') + label {{ parameter.displayName }}: + span(datetimepicker, options='parameter.datetimeOptions', ng-model='parameter.value', ng-change='updateParameter()') + div(ng-switch-default) + label {{ parameter.displayName }}: + input(type='text', ng-model='parameter.value', ng-blur='updateParameter()') diff --git a/cyclotron-site/app/widgets/header/headerWidget.coffee b/cyclotron-site/app/widgets/header/headerWidget.coffee index 94fd5d4..e2ba27d 100644 --- a/cyclotron-site/app/widgets/header/headerWidget.coffee +++ b/cyclotron-site/app/widgets/header/headerWidget.coffee @@ -32,3 +32,24 @@ cyclotronApp.controller 'HeaderWidget', ($scope, $sce, configService) -> $scope.customHtml = -> $sce.trustAsHtml _.jsExec($scope.widget.customHtml) + + $scope.showParameters = $scope.widget.parameters?.showParameters == true + + # If Parameters are show in the Widget... + if $scope.showParameters + $scope.showUpdateButton = $scope.widget.parameters.showUpdateButton + $scope.updateButtonLabel = $scope.widget.parameters.updateButtonLabel || 'Update' + + $scope.parameters = _.filter $scope.dashboard.parameters, { editInHeader: true } + + # Filter further using the Widget's parametersIncluded property + if _.isArray($scope.widget.parameters.parametersIncluded) and $scope.widget.parameters.parametersIncluded.length > 0 + $scope.parameters = _.filter $scope.parameters, (param) -> + _.contains $scope.widget.parameters.parametersIncluded, param.name + + updateEventHandler = _.jsEval $scope.widget.parameters.updateEvent + if !_.isFunction(updateEventHandler) then updateEventHandler = null + + $scope.updateButtonClick = -> + updateEventHandler() unless _.isNull updateEventHandler + diff --git a/cyclotron-site/app/widgets/header/help.jade b/cyclotron-site/app/widgets/header/help.jade index 489d6fd..c3fe3fa 100644 --- a/cyclotron-site/app/widgets/header/help.jade +++ b/cyclotron-site/app/widgets/header/help.jade @@ -2,7 +2,7 @@ h3 Header Widget p. The Header Widget is useful for generating a header at the top of a Dashboard. It has various properties for generating common header features, as well as allowing for additional HTML content p. - Since this is a Widget, it must be copied onto each page individually. However this can be beneficial if differences are desired between the pages. + Since this is a Widget, it won't appear automatically on every page, but rather must be copied onto each page individually. One benefit of this is that it allows for configuration differences between pages. h4 Sizing p @@ -11,6 +11,32 @@ p | property for the Page. This property should be set to the negative header height, minus the gutter. This | will allow the header height to be fixed while the other Widgets scale to match the browser. +h4 Parameters +p + | The Header Widget has integrated support for editing selected Dashboard Parameters. In order to enable this feature, the Header Widget must have the + em parameters.showParameters + | property set to true; additionally at least one Parameter must have the + em editInHeader + | property set to true (defaults to false). + +p + | There are two approaches to trigger updates for changing Parameters. The first is to add a JavaScript event handler to each Parameter's + em changeEvent + | property. This event is fired whenever the Parameter is changed, either programmatically or via the Header Widget. The second approach is to enable + em parameters.showUpdateButton + | , which appears after the Parameters in the Header. It has a corresponding event handler, + em parameters.updateEvent + | , which fires after being clicked. Implementing this event handler supports the pattern of allowing the user to make multiple changes to Parameters, and click a button to apply the changes. + +p The + em parameters.updateEvent + | expects a JavaScript function in the following form: + +pre.code. + function () { + // event handler + } + h4 Properties p. These are the properties specific to this widget. diff --git a/cyclotron-site/app/widgets/html/html.jade b/cyclotron-site/app/widgets/html/html.jade index 2a10321..d29ea5a 100644 --- a/cyclotron-site/app/widgets/html/html.jade +++ b/cyclotron-site/app/widgets/html/html.jade @@ -1,4 +1,3 @@ - //- Embedded Html Widget .html-widget(ng-controller='HtmlWidget') diff --git a/cyclotron-site/app/widgets/table/_table.less b/cyclotron-site/app/widgets/table/_table.less index acab483..3d36e46 100644 --- a/cyclotron-site/app/widgets/table/_table.less +++ b/cyclotron-site/app/widgets/table/_table.less @@ -68,7 +68,7 @@ } tbody > tr:hover { - background-color: @accentColor; + background-color: @tableRowHoverBackgroundColor; } } diff --git a/cyclotron-site/bower.json b/cyclotron-site/bower.json index 1cc1b77..d65883c 100644 --- a/cyclotron-site/bower.json +++ b/cyclotron-site/bower.json @@ -19,7 +19,7 @@ "angular": "1.4.9", "angular-bootstrap": "1.2.4", "angular-cookies": "1.4.9", - "angular-google-chart": "angular-google-chart#75fdd22", + "angular-google-chart": "angular-google-chart#9588ed2", "angular-hotkeys": "0.2.2", "angular-localForage": "1.2.5", "angular-mocks": "1.4.9", @@ -29,11 +29,12 @@ "angular-tablesort": "1.1.0", "angular-ui-ace": "0.2.3", "angular-ui-router": "0.2.14", - "angular-ui-select": "0.12.1", + "angular-ui-select": "0.18.1", "angular-ui-switch": "~0.1.1", "bowser": "1.0.0", "c3": "0.4.10", "d3": "3.5.6", + "datetimepicker": "~2.5.4", "fontawesome": "4.3.0", "highcharts-release": "4.2.0", "jquery": "2.1.4", @@ -60,7 +61,9 @@ "uri.js": "1.15.1" }, "resolutions": { - "d3": "3.5.6" + "d3": "3.5.6", + "angular": "1.4.9", + "datetimepicker": "~2.5.4" }, "overrides": { "ace-builds": { @@ -125,6 +128,7 @@ "lato": { "main": [ "./css/lato.css", + "./font/lato-bold/*", "./font/lato-light/*", "./font/lato-lightitalic/*" ] diff --git a/cyclotron-site/package.json b/cyclotron-site/package.json index 15b0423..6eb47b4 100644 --- a/cyclotron-site/package.json +++ b/cyclotron-site/package.json @@ -1,7 +1,7 @@ { "name": "cyclotron-site", "description": "Cyclotron: website", - "version": "1.34.0", + "version": "1.35.0", "author": "Dave Bauman ", "license": "MIT", "private": true, diff --git a/cyclotron-site/vendor/modernizr/LICENSE b/cyclotron-site/vendor/modernizr/LICENSE index 0bfe3ff..ca68c82 100644 --- a/cyclotron-site/vendor/modernizr/LICENSE +++ b/cyclotron-site/vendor/modernizr/LICENSE @@ -1 +1 @@ -/* Modernizr 2.8.3 (Custom Build) | MIT & BSD \ No newline at end of file +Modernizr 3.3.1 (Custom Build) | MIT diff --git a/cyclotron-site/vendor/modernizr/modernizr.js b/cyclotron-site/vendor/modernizr/modernizr.js index e86295e..b32956a 100644 --- a/cyclotron-site/vendor/modernizr/modernizr.js +++ b/cyclotron-site/vendor/modernizr/modernizr.js @@ -1,4 +1,3 @@ -/* Modernizr 2.8.3 (Custom Build) | MIT & BSD - * Build: http://modernizr.com/download/#-fontface-borderradius-boxshadow-opacity-rgba-textshadow-cssanimations-generatedcontent-canvas-history-websockets-svg-mq-cssclasses-teststyles-testprop-testallprops-prefixes-domprefixes-cors-css_boxsizing-css_mediaqueries-json-load - */ -;window.Modernizr=function(a,b,c){function C(a){j.cssText=a}function D(a,b){return C(n.join(a+";")+(b||""))}function E(a,b){return typeof a===b}function F(a,b){return!!~(""+a).indexOf(b)}function G(a,b){for(var d in a){var e=a[d];if(!F(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function H(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:E(f,"function")?f.bind(d||b):f}return!1}function I(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return E(b,"string")||E(b,"undefined")?G(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),H(e,b,c))}var d="2.8.3",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l=":)",m={}.toString,n=" -webkit- -moz- -o- -ms- ".split(" "),o="Webkit Moz O ms",p=o.split(" "),q=o.toLowerCase().split(" "),r={svg:"http://www.w3.org/2000/svg"},s={},t={},u={},v=[],w=v.slice,x,y=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["­",'"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b)&&c(b).matches||!1;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A={}.hasOwnProperty,B;!E(A,"undefined")&&!E(A.call,"undefined")?B=function(a,b){return A.call(a,b)}:B=function(a,b){return b in a&&E(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.history=function(){return!!a.history&&!!history.pushState},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return C("background-color:rgba(150,255,150,.5)"),F(j.backgroundColor,"rgba")},s.borderradius=function(){return I("borderRadius")},s.boxshadow=function(){return I("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return D("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return I("animationName")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect};for(var J in s)B(s,J)&&(x=J.toLowerCase(),e[x]=s[J](),v.push((e[x]?"":"no-")+x));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)B(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},C(""),i=k=null,e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.testProp=function(a){return G([a])},e.testAllProps=I,e.testStyles=y,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f7)}); +/*! modernizr 3.3.1 (Custom Build) | MIT * + * https://modernizr.com/download/?-borderradius-boxshadow-boxsizing-canvas-cors-cssanimations-fontface-fullscreen-history-json-mediaqueries-opacity-rgba-svg-textshadow-websockets-domprefixes-mq-prefixes-setclasses-testallprops-testprop-teststyles !*/ +!function(e,t,n){function r(e,t){return typeof e===t}function s(){var e,t,n,s,o,i,a;for(var d in x)if(x.hasOwnProperty(d)){if(e=[],t=x[d],t.name&&(e.push(t.name.toLowerCase()),t.options&&t.options.aliases&&t.options.aliases.length))for(n=0;nc;c++)if(g=e[c],h=L.style[g],l(g,"-")&&(g=u(g)),L.style[g]!==n){if(o||r(s,"undefined"))return a(),"pfx"==t?g:!0;try{L.style[g]=s}catch(y){}if(L.style[g]!=h)return a(),"pfx"==t?g:!0}return a(),!1}function h(e,t,n,s,o){var i=e.charAt(0).toUpperCase()+e.slice(1),a=(e+" "+k.join(i+" ")+i).split(" ");return r(t,"string")||r(t,"undefined")?g(a,t,s,o):(a=(e+" "+E.join(i+" ")+i).split(" "),c(a,t,n))}function v(e,t,r){return h(e,n,n,t,r)}var y=[],x=[],w={_version:"3.3.1",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){x.push({name:e,fn:t,options:n})},addAsyncTest:function(e){x.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=w,Modernizr=new Modernizr,Modernizr.addTest("cors","XMLHttpRequest"in e&&"withCredentials"in new XMLHttpRequest),Modernizr.addTest("history",function(){var t=navigator.userAgent;return-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone")?e.history&&"pushState"in e.history:!1}),Modernizr.addTest("json","JSON"in e&&"parse"in JSON&&"stringify"in JSON),Modernizr.addTest("svg",!!t.createElementNS&&!!t.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect);var S=!1;try{S="WebSocket"in e&&2===e.WebSocket.CLOSING}catch(b){}Modernizr.addTest("websockets",S);var C=w._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];w._prefixes=C;var T=t.documentElement,_="svg"===T.nodeName.toLowerCase(),O="Moz O ms Webkit",E=w._config.usePrefixes?O.toLowerCase().split(" "):[];w._domPrefixes=E,Modernizr.addTest("canvas",function(){var e=i("canvas");return!(!e.getContext||!e.getContext("2d"))}),Modernizr.addTest("opacity",function(){var e=i("a").style;return e.cssText=C.join("opacity:.55;"),/^0.55$/.test(e.opacity)}),Modernizr.addTest("rgba",function(){var e=i("a").style;return e.cssText="background-color:rgba(150,255,150,.5)",(""+e.backgroundColor).indexOf("rgba")>-1});var N=function(){var t=e.matchMedia||e.msMatchMedia;return t?function(e){var n=t(e);return n&&n.matches||!1}:function(t){var n=!1;return d("@media "+t+" { #modernizr { position: absolute; } }",function(t){n="absolute"==(e.getComputedStyle?e.getComputedStyle(t,null):t.currentStyle).position}),n}}();w.mq=N,Modernizr.addTest("mediaqueries",N("only all"));var R=w.testStyles=d,z=function(){var e=navigator.userAgent,t=e.match(/applewebkit\/([0-9]+)/gi)&&parseFloat(RegExp.$1),n=e.match(/w(eb)?osbrowser/gi),r=e.match(/windows phone/gi)&&e.match(/iemobile\/([0-9])+/gi)&&parseFloat(RegExp.$1)>=9,s=533>t&&e.match(/android/gi);return n||s||r}();z?Modernizr.addTest("fontface",!1):R('@font-face {font-family:"font";src:url("https://")}',function(e,n){var r=t.getElementById("smodernizr"),s=r.sheet||r.styleSheet,o=s?s.cssRules&&s.cssRules[0]?s.cssRules[0].cssText:s.cssText||"":"",i=/src/i.test(o)&&0===o.indexOf(n.split(" ")[0]);Modernizr.addTest("fontface",i)});var k=w._config.usePrefixes?O.split(" "):[];w._cssomPrefixes=k;var P=function(t){var r,s=C.length,o=e.CSSRule;if("undefined"==typeof o)return n;if(!t)return!1;if(t=t.replace(/^@/,""),r=t.replace(/-/g,"_").toUpperCase()+"_RULE",r in o)return"@"+t;for(var i=0;s>i;i++){var a=C[i],d=a.toUpperCase()+"_"+r;if(d in o)return"@-"+a.toLowerCase()+"-"+t}return!1};w.atRule=P;var A={elem:i("modernizr")};Modernizr._q.push(function(){delete A.elem});var L={style:A.elem.style};Modernizr._q.unshift(function(){delete L.style});var M=w.testProp=function(e,t,r){return g([e],n,t,r)};Modernizr.addTest("textshadow",M("textShadow","1px 1px")),w.testAllProps=h,w.testAllProps=v,Modernizr.addTest("cssanimations",v("animationName","a",!0)),Modernizr.addTest("borderradius",v("borderRadius","0px",!0)),Modernizr.addTest("boxshadow",v("boxShadow","1px 1px",!0)),Modernizr.addTest("boxsizing",v("boxSizing","border-box",!0)&&(t.documentMode===n||t.documentMode>7));var j=w.prefixed=function(e,t,n){return 0===e.indexOf("@")?P(e):(-1!=e.indexOf("-")&&(e=u(e)),t?h(e,t,n):h(e,"pfx"))};Modernizr.addTest("fullscreen",!(!j("exitFullscreen",t,!1)&&!j("cancelFullScreen",t,!1))),s(),o(y),delete w.addTest,delete w.addAsyncTest;for(var q=0;q\n

Additional Content

\n", "gridHeight": 1, "headerTitle": { "link": "http://cyclotron.io", "logoSize": "72px", - "logoUrl": "http://www.cyclotron.io/img/favicon128.png", + "logoUrl": "/img/favicon128.png", "pageNameSeparator": "|", "showPageName": true, "showTitle": true, "titleSize": "2.5rem" }, - "height": "150px", + "height": "100px", "widget": "header" }, { "gridHeight": 1, "gridWidth": 1, + "theme": "light", "widget": "clock" }] }, { "frequency": 1, "layout": { - "gridColumns": 1, - "gridHeightAdjustment": -160, + "gridColumns": 2, + "gridHeightAdjustment": -110, "gridRows": 1, "gutter": 10, "margin": 10 }, "name": "Another Awesome Page", + "theme": "light", "widgets": [{ "allowFullscreen": false, - "customHtml": "
\n

Additional Content

\n
", "gridHeight": 1, + "gridWidth": 2, "headerTitle": { "link": "http://cyclotron.io", "logoSize": "72px", - "logoUrl": "http://www.cyclotron.io/img/favicon128.png", + "logoUrl": "/img/favicon128.png", "pageNameSeparator": "|", "showPageName": true, "showTitle": true, "titleSize": "2.5rem" }, - "height": "150px", + "height": "100px", + "theme": "lightborderless", "widget": "header" }, { "gridHeight": 1, "gridWidth": 1, "widget": "clock" + }, { + "columns": [{ + "headerTooltip": "The Year", + "name": "Year" + }, { + "name": "Total" + }, { + "name": "Burglary" + }, { + "name": "Robbery" + }, { + "name": "Murder" + }], + "dataSource": "uscrime", + "title": "US Crime Over Time (some columns)", + "widget": "table" + }] + }, { + "frequency": 1, + "layout": { + "gridColumns": 1, + "gridHeightAdjustment": -170, + "gridRows": 1, + "gutter": 10, + "margin": 10 + }, + "name": "Header With Parameters", + "theme": "light", + "widgets": [{ + "allowFullscreen": false, + "customHtml": "
This chart updates whenever a Parameter is changed, because the Change Event for each Parameter re-executes the Data Source.
", + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "link": "http://cyclotron.io", + "logoSize": "64px", + "logoUrl": "/img/favicon128.png", + "pageNameSeparator": "|", + "showPageName": true, + "showTitle": true, + "titleSize": "2rem" + }, + "height": "160px", + "noscroll": true, + "parameters": { + "parametersIncluded": ["selectedCrime", "showTotal"], + "showParameters": true + }, + "theme": "lightborderless", + "widget": "header" + }, { + "dataSource": "uscrime-filtered", + "gridHeight": 1, + "gridWidth": 1, + "highchart": { + "series": [{ + "x": "Year", + "y": "*" + }], + "xAxis": [{ + "type": "linear" + }], + "yAxis": [{ + "title": { + "text": "Values" + } + }] + }, + "title": "US Crime Over Time", + "widget": "chart" + }] + }, { + "frequency": 1, + "layout": { + "gridColumns": 1, + "gridHeightAdjustment": -170, + "gridRows": 1, + "gutter": 10, + "margin": 10 + }, + "name": "Header With Parameters and Change Button", + "theme": "dark", + "widgets": [{ + "allowFullscreen": false, + "customHtml": "
This chart only updates when the Change button is clicked, because an event handler for the button re-executes the Data Source.
", + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "link": "http://cyclotron.io", + "logoSize": "64px", + "logoUrl": "/img/favicon128.png", + "pageNameSeparator": "|", + "showPageName": true, + "showTitle": true, + "titleSize": "2rem" + }, + "height": "160px", + "noscroll": true, + "parameters": { + "parametersIncluded": ["selectedCrime", "showTotal"], + "showParameters": true, + "showUpdateButton": true, + "updateButtonLabel": "Change", + "updateEvent": "e = function() {\n // Re-execute the Data Source whenever the button is clicked\n Cyclotron.dataSources['uscrime-filtered2'].execute(true);\n}" + }, + "widget": "header" + }, { + "dataSource": "uscrime-filtered2", + "gridHeight": 1, + "gridWidth": 1, + "highchart": { + "series": [{ + "x": "Year", + "y": "*" + }], + "xAxis": [{ + "type": "linear" + }], + "yAxis": [{ + "title": { + "text": "Values" + } + }] + }, + "title": "US Crime Over Time", + "widget": "chart" + }] + }, { + "frequency": 1, + "layout": { + "gridColumns": 1, + "gridHeightAdjustment": -170, + "gridRows": 1, + "gutter": 10, + "margin": 10 + }, + "name": "Header With Parameters and Change Button 2", + "theme": "dark", + "widgets": [{ + "allowFullscreen": false, + "customHtml": "
This chart only updates when the Change button is clicked, because an event handler for the button re-executes the Data Source.
", + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "link": "http://cyclotron.io", + "logoSize": "64px", + "logoUrl": "/img/favicon128.png", + "pageNameSeparator": "|", + "showPageName": true, + "showTitle": true, + "titleSize": "2rem" + }, + "height": "160px", + "noscroll": true, + "parameters": { + "parametersIncluded": ["selectedCrimeLinks", "showTotal"], + "showParameters": true, + "showUpdateButton": true, + "updateButtonLabel": "Change", + "updateEvent": "e = function() {\n // Re-execute the Data Source whenever the button is clicked\n Cyclotron.dataSources['uscrime-filtered-links'].execute(true);\n}" + }, + "widget": "header" + }, { + "dataSource": "uscrime-filtered-links", + "gridHeight": 1, + "gridWidth": 1, + "highchart": { + "series": [{ + "x": "Year", + "y": "*" + }], + "xAxis": [{ + "type": "linear" + }], + "yAxis": [{ + "title": { + "text": "Values" + } + }] + }, + "title": "US Crime Over Time", + "widget": "chart" + }] + }, { + "frequency": 1, + "layout": { + "gridColumns": 1, + "gridHeightAdjustment": -175, + "gridRows": 1, + "gutter": 10, + "margin": 10 + }, + "name": "Header With Separate Parameters", + "theme": "light", + "widgets": [{ + "allowFullscreen": false, + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "link": "http://cyclotron.io", + "logoSize": "64px", + "logoUrl": "/img/favicon128.png", + "pageNameSeparator": "|", + "showPageName": true, + "showTitle": true, + "titleSize": "2rem" + }, + "height": "85px", + "noscroll": true, + "theme": "lightborderless", + "widget": "header" + }, { + "allowFullscreen": false, + "customHtml": "
This chart only updates when the Change button is clicked, because an event handler for the button re-executes the Data Source.
", + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "showTitle": false + }, + "height": "70px", + "noscroll": true, + "parameters": { + "parametersIncluded": ["selectedCrimeLinks", "showTotal"], + "showParameters": true, + "showUpdateButton": true, + "updateButtonLabel": "Change", + "updateEvent": "e = function() {\n // Re-execute the Data Source whenever the button is clicked\n Cyclotron.dataSources['uscrime-filtered-links'].execute(true);\n}" + }, + "widget": "header" + }, { + "dataSource": "uscrime-filtered-links", + "gridHeight": 1, + "gridWidth": 1, + "highchart": { + "series": [{ + "x": "Year", + "y": "*" + }], + "xAxis": [{ + "type": "linear" + }], + "yAxis": [{ + "title": { + "text": "Values" + } + }] + }, + "title": "US Crime Over Time", + "widget": "chart" + }] + }, { + "frequency": 1, + "layout": { + "gridColumns": 1, + "gridHeightAdjustment": -170, + "gridRows": 1, + "gutter": 10, + "margin": 10 + }, + "name": "Header With DateTime Parameters", + "theme": "light", + "widgets": [{ + "allowFullscreen": false, + "customHtml": "
This chart updates whenever a Parameter is changed, because the Change Event for each Parameter re-executes the Data Source.
", + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "link": "http://cyclotron.io", + "logoSize": "64px", + "logoUrl": "/img/favicon128.png", + "pageNameSeparator": "|", + "showPageName": true, + "showTitle": true, + "titleSize": "2rem" + }, + "height": "160px", + "noscroll": true, + "parameters": { + "parametersIncluded": ["datetime", "date", "time"], + "showParameters": true + }, + "theme": "lightborderless", + "widget": "header" + }, { + "dataSource": "uscrime-types", + "filters": { + "x": "y" + }, + "gridHeight": 1, + "gridWidth": 1, + "layout": {}, + "noData": "No Data", + "widget": "chart" }] + }, { + "frequency": 1, + "layout": { + "gridColumns": 1, + "gridHeightAdjustment": -170, + "gridRows": 1, + "gutter": 10, + "margin": 10 + }, + "name": "Header With DateTime Parameters", + "theme": "light", + "widgets": [{ + "allowFullscreen": false, + "customHtml": "
This chart updates whenever a Parameter is changed, because the Change Event for each Parameter re-executes the Data Source.
", + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "link": "http://cyclotron.io", + "logoSize": "64px", + "logoUrl": "/img/favicon128.png", + "pageNameSeparator": "|", + "showPageName": true, + "showTitle": true, + "titleSize": "2rem" + }, + "height": "160px", + "noscroll": true, + "parameters": { + "parametersIncluded": ["datetime", "date", "time"], + "showParameters": true + }, + "theme": "lightborderless", + "widget": "header" + }, { + "dataSource": "uscrime-types", + "filters": { + "x": "y" + }, + "gridHeight": 1, + "gridWidth": 1, + "layout": {}, + "noData": "No Data", + "widget": "chart" + }] + }, { + "frequency": 1, + "layout": { + "gridColumns": 5, + "gridRows": 1, + "gutter": 10, + "margin": 10 + }, + "name": "Side Header", + "theme": "light", + "widgets": [{ + "allowFullscreen": false, + "gridHeight": 1, + "gridWidth": 1, + "headerTitle": { + "link": "http://cyclotron.io", + "logoSize": "48px", + "logoUrl": "/img/favicon128.png", + "pageNameSeparator": "|", + "showPageName": false, + "showTitle": true, + "titleSize": "1.5rem" + }, + "parameters": { + "showParameters": true + }, + "theme": "light", + "title": "Side Header", + "widget": "header" + }, { + "dataSource": "uscrime-filtered", + "gridHeight": 1, + "gridWidth": 4, + "highchart": { + "series": [{ + "x": "Year", + "y": "*" + }], + "xAxis": [{ + "type": "linear" + }], + "yAxis": [{ + "title": { + "text": "Values" + } + }] + }, + "title": "US Crime Over Time", + "widget": "chart" + }] + }], + "parameters": [{ + "changeEvent": "e = function(parameterName, value, oldValue) {\n // Re-execute the Data Source whenever the value changes\n if (Cyclotron.dataSources['uscrime-filtered']) {\n Cyclotron.dataSources['uscrime-filtered'].execute(true);\n }\n}", + "defaultValue": "Burglary", + "editInHeader": true, + "editing": { + "dataSource": "uscrime-types", + "displayName": "Selected Crime", + "editorType": "dropdown" + }, + "name": "selectedCrime" + }, { + "changeEvent": "e = function(parameterName, value, oldValue) {\n // Re-execute the Data Source whenever the value changes\n if (Cyclotron.dataSources['uscrime-filtered']) {\n Cyclotron.dataSources['uscrime-filtered'].execute(true);\n }\n}", + "defaultValue": "Burglary", + "editInHeader": true, + "editing": { + "dataSource": "uscrime-types", + "displayName": "Selected Crime", + "editorType": "links" + }, + "name": "selectedCrimeLinks" + }, { + "changeEvent": "e = function(parameterName, value, oldValue) {\n // Re-execute the Data Source whenever the value changes\n if (Cyclotron.dataSources['uscrime-filtered']) {\n Cyclotron.dataSources['uscrime-filtered'].execute(true);\n }\n}", + "defaultValue": "${true}", + "editInHeader": true, + "editing": { + "displayName": "Show Total Crimes", + "editorType": "checkbox" + }, + "name": "showTotal" + }, { + "defaultValue": "${moment()}", + "editInHeader": true, + "editing": { + "displayName": "Date/Time", + "editorType": "datetime" + }, + "name": "datetime" + }, { + "defaultValue": "2016-06-08", + "editInHeader": true, + "editing": { + "displayName": "Date", + "editorType": "date" + }, + "name": "date" + }, { + "defaultValue": "15:30", + "editInHeader": true, + "editing": { + "displayName": "Time", + "editorType": "time" + }, + "name": "time" }], - "parameters": [], - "theme": "dark" + "scripts": [], + "theme": "lightborderless" } diff --git a/cyclotron-svc/package.json b/cyclotron-svc/package.json index 6eef149..68aacc8 100644 --- a/cyclotron-svc/package.json +++ b/cyclotron-svc/package.json @@ -1,7 +1,7 @@ { "name": "cyclotron-svc", "description": "Cyclotron: REST API", - "version": "1.34.0", + "version": "1.35.0", "author": "Dave Bauman ", "license": "MIT", "private": true,