├── inst
├── www
│ ├── styles
│ │ ├── default
│ │ │ └── default.css
│ │ ├── loading.css
│ │ ├── parsleyjs
│ │ │ └── parsley.scss
│ │ ├── viewercontrols.scss
│ │ ├── jqModal
│ │ │ └── jqModal.scss
│ │ ├── vars.scss
│ │ └── mixins.scss
│ ├── partials
│ │ ├── iframe.htm
│ │ ├── _404.htm
│ │ ├── dialogs
│ │ │ ├── templates
│ │ │ │ ├── newProfileVariable.tpl
│ │ │ │ ├── viewerDataDownload.tpl
│ │ │ │ ├── profileVariables.tpl
│ │ │ │ ├── executionOrderDetails.tpl
│ │ │ │ ├── viewerDataUpload.tpl
│ │ │ │ └── viewerProfileVariables.tpl
│ │ │ ├── _confirmDialog.htm
│ │ │ ├── _styleEditorDialog.htm
│ │ │ ├── _siteSettings.htm
│ │ │ ├── _designerSettings.htm
│ │ │ ├── _viewerDataUpload.htm
│ │ │ ├── _profileSettings.htm
│ │ │ ├── _viewerProfileSettings.htm
│ │ │ ├── _controlSettings.htm
│ │ │ ├── _viewerDataDownload.htm
│ │ │ ├── _executionOrderDialog.htm
│ │ │ ├── _dataSourceSettings.htm
│ │ │ ├── _timerSettings.htm
│ │ │ ├── _pageSettings.htm
│ │ │ ├── _addPage.htm
│ │ │ └── _formBuilder.htm
│ │ └── viewer.htm
│ ├── img
│ │ └── spinner.gif
│ ├── js
│ │ ├── ui
│ │ │ ├── controls
│ │ │ │ ├── templates
│ │ │ │ │ ├── interactivePlot.tpl
│ │ │ │ │ ├── htmlWidget.tpl
│ │ │ │ │ ├── profileConfigurator.tpl
│ │ │ │ │ ├── actionButton.tpl
│ │ │ │ │ ├── image.tpl
│ │ │ │ │ ├── rText.tpl
│ │ │ │ │ ├── rPrint.tpl
│ │ │ │ │ ├── dataDownload.tpl
│ │ │ │ │ ├── iframe.tpl
│ │ │ │ │ ├── dataUpload.tpl
│ │ │ │ │ ├── message.tpl
│ │ │ │ │ ├── rPlot.tpl
│ │ │ │ │ ├── spinner.tpl
│ │ │ │ │ ├── leaflet.tpl
│ │ │ │ │ └── dataTable.tpl
│ │ │ │ ├── child
│ │ │ │ │ ├── templates
│ │ │ │ │ │ ├── submitButton.tpl
│ │ │ │ │ │ ├── heading.tpl
│ │ │ │ │ │ ├── textField.tpl
│ │ │ │ │ │ ├── datePicker.tpl
│ │ │ │ │ │ ├── checkboxList.tpl
│ │ │ │ │ │ ├── radioButtonGroup.tpl
│ │ │ │ │ │ ├── dropdown.tpl
│ │ │ │ │ │ ├── slider.tpl
│ │ │ │ │ │ ├── multiSelect.tpl
│ │ │ │ │ │ └── dateRange.tpl
│ │ │ │ │ ├── separator.js
│ │ │ │ │ ├── submitButton.js
│ │ │ │ │ ├── datePicker.js
│ │ │ │ │ ├── textField.js
│ │ │ │ │ ├── heading.js
│ │ │ │ │ ├── dropdown.js
│ │ │ │ │ ├── checkboxList.js
│ │ │ │ │ ├── radioButtonGroup.js
│ │ │ │ │ ├── multiSelect.js
│ │ │ │ │ └── dateRange.js
│ │ │ │ ├── images
│ │ │ │ │ ├── layers.png
│ │ │ │ │ ├── layers-2x.png
│ │ │ │ │ ├── marker-icon.png
│ │ │ │ │ ├── marker-icon-2x.png
│ │ │ │ │ └── marker-shadow.png
│ │ │ │ ├── text.js
│ │ │ │ ├── factories
│ │ │ │ │ └── controlPropertyFactory.js
│ │ │ │ ├── profileConfigurator.js
│ │ │ │ ├── spinner.js
│ │ │ │ ├── message.js
│ │ │ │ ├── interactivePlot.js
│ │ │ │ ├── iframe.js
│ │ │ │ ├── rPrint.js
│ │ │ │ ├── htmlWidget.js
│ │ │ │ ├── rText.js
│ │ │ │ ├── actionButton.js
│ │ │ │ ├── dataUpload.js
│ │ │ │ ├── rPlot.js
│ │ │ │ ├── dataDownload.js
│ │ │ │ └── image.js
│ │ │ ├── templates
│ │ │ │ ├── pageMenuItem.tpl
│ │ │ │ ├── selectOptions.tpl
│ │ │ │ ├── dataSourceMenuItem.tpl
│ │ │ │ ├── controlsMenu.tpl
│ │ │ │ ├── timerMenuItem.tpl
│ │ │ │ └── siteSettingsMenu.tpl
│ │ │ ├── properties
│ │ │ │ ├── templates
│ │ │ │ │ ├── checkboxList.tpl
│ │ │ │ │ ├── radioButtonGroup.tpl
│ │ │ │ │ ├── multlineTextControl.tpl
│ │ │ │ │ ├── ace.tpl
│ │ │ │ │ ├── rangeControl.tpl
│ │ │ │ │ ├── autocomplete.tpl
│ │ │ │ │ ├── dropdownControl.tpl
│ │ │ │ │ ├── textControl.tpl
│ │ │ │ │ ├── wysiwyg.tpl
│ │ │ │ │ ├── colorControl.tpl
│ │ │ │ │ └── multiOptionControl.tpl
│ │ │ │ ├── baseProperty.js
│ │ │ │ ├── multilineTextProperty.js
│ │ │ │ ├── radioButtonGroupProperty.js
│ │ │ │ ├── autocompleteProperty.js
│ │ │ │ ├── checkboxListProperty.js
│ │ │ │ ├── wysiwygProperty.js
│ │ │ │ ├── aceProperty.js
│ │ │ │ ├── dropdownProperty.js
│ │ │ │ ├── textProperty.js
│ │ │ │ ├── colorProperty.js
│ │ │ │ ├── rangeProperty.js
│ │ │ │ └── stringValueProperty.js
│ │ │ ├── message.js
│ │ │ ├── infoBarManager.js
│ │ │ ├── messageManager.js
│ │ │ └── dialogUtils.js
│ │ ├── profileManager.js
│ │ ├── require-rcap.js
│ │ ├── pages
│ │ │ ├── pageManager.js
│ │ │ └── page.js
│ │ ├── utils
│ │ │ ├── rCloud.js
│ │ │ ├── rcapLogger.js
│ │ │ ├── request.js
│ │ │ ├── variableHandler.js
│ │ │ ├── historyManager.js
│ │ │ └── pageWalker.js
│ │ ├── data
│ │ │ ├── dataSource.js
│ │ │ └── timer.js
│ │ ├── versionConverters
│ │ │ └── versionConverter.js
│ │ ├── site
│ │ │ └── siteSettings.js
│ │ └── Class.js
│ └── fonts
│ │ ├── clvatt-book-webfont.eot
│ │ ├── clvatt-book-webfont.ttf
│ │ ├── clvatt-book-webfont.woff
│ │ └── clvatt-book-webfont.woff2
├── package.json
├── .jshintrc
├── bower.json
└── Gruntfile.js
├── LICENSE
├── youtube.png
├── tests
├── testthat.R
└── testthat
│ ├── test-bfs.R
│ ├── test-parse-controls.R
│ ├── test-generate-table-css.R
│ ├── test-controller.R
│ ├── test-generate-table-ids-df.R
│ ├── test-controls.R
│ ├── testConfig.json
│ └── test-topo-sort.R
├── .gitignore
├── .Rbuildignore
├── R
├── styles.R
├── ocaps.R
├── eventHandlerR6.R
├── showUpdates.R
├── rcap.user.profile.R
├── rcap.messageWidget.R
├── rcap.progressSpinner.R
└── utils.R
├── app.Rproj
├── man
├── rcapSessionInfo.Rd
├── isEditMode.Rd
├── control_classes.Rd
├── RPlotControl.Rd
├── or.Rd
├── rcloudEnv.Rd
├── parseSizesJson.Rd
├── twistAdjlist.Rd
├── bfs.Rd
├── rcloud.rcap.caps.Rd
├── rcloud.rcap.global.functions.Rd
├── rcap.result.Rd
├── topologicalSort.Rd
├── Controller.Rd
├── getControls.Rd
└── Control.Rd
├── NAMESPACE
├── .github
└── ISSUE_TEMPLATE.md
├── DESCRIPTION
└── README.md
/inst/www/styles/default/default.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2012-2017
2 | COPYRIGHT HOLDER: AT&T Intellectual Property
3 |
--------------------------------------------------------------------------------
/youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/youtube.png
--------------------------------------------------------------------------------
/inst/www/partials/iframe.htm:
--------------------------------------------------------------------------------
1 |
The source of this iframe will be determined at runtime.
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(rcloud.rcap)
3 |
4 | test_check("rcloud.rcap")
5 |
--------------------------------------------------------------------------------
/inst/www/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/img/spinner.gif
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/interactivePlot.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/submitButton.tpl:
--------------------------------------------------------------------------------
1 | <%=text%>
--------------------------------------------------------------------------------
/inst/www/fonts/clvatt-book-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/fonts/clvatt-book-webfont.eot
--------------------------------------------------------------------------------
/inst/www/fonts/clvatt-book-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/fonts/clvatt-book-webfont.ttf
--------------------------------------------------------------------------------
/inst/www/fonts/clvatt-book-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/fonts/clvatt-book-webfont.woff
--------------------------------------------------------------------------------
/inst/www/fonts/clvatt-book-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/fonts/clvatt-book-webfont.woff2
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/js/ui/controls/images/layers.png
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/js/ui/controls/images/layers-2x.png
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/js/ui/controls/images/marker-icon.png
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/htmlWidget.tpl:
--------------------------------------------------------------------------------
1 | Please wait while the widget is loaded...
2 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/js/ui/controls/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/att/rcloud.rcap/develop/inst/www/js/ui/controls/images/marker-shadow.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | inst/www/vendor
2 | node_modules
3 | .sass-cache
4 | bower_components
5 | .Rproj.user
6 | attrcap.Rproj
7 | .vagrant
8 | /rcloud.rcap-develop
9 | output
10 | .vscode
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/profileConfigurator.tpl:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/actionButton.tpl:
--------------------------------------------------------------------------------
1 | <%=control.controlProperties[1].value%>
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/image.tpl:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/rText.tpl:
--------------------------------------------------------------------------------
1 | Please wait while the content is loaded...
2 | <%if(designTimeDescription.length && isDesignTime) {%>
3 | <%=designTimeDescription%>
4 | <%}%>
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/rPrint.tpl:
--------------------------------------------------------------------------------
1 | Please wait while the content is loaded...
2 | <%if(designTimeDescription.length && isDesignTime) {%>
3 | <%=designTimeDescription%>
4 | <%}%>
--------------------------------------------------------------------------------
/inst/www/js/profileManager.js:
--------------------------------------------------------------------------------
1 | define(['pubsub', 'site/pubSubTable'
2 | ], function (/*PubSub, pubSubTable*/) {
3 |
4 | 'use strict';
5 |
6 | var ProfileManager = function () {
7 | this.initialise = function () {
8 |
9 | };
10 | };
11 |
12 | return ProfileManager;
13 |
14 | });
15 |
--------------------------------------------------------------------------------
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^app.Rproj$
2 | ^.github$
3 | ^inst/bower_components$
4 | ^inst/bower.json$
5 | ^inst/build$
6 | ^inst/Gruntfile.js$
7 | ^inst/.jshintrc
8 | ^inst/internals.md
9 | ^inst/node_modules$
10 | ^inst/package.json$
11 | ^mkdist$
12 | ^inst/npm-debug.log.*
13 |
14 | ^.*\.Rproj$
15 | ^\.Rproj\.user$
16 |
--------------------------------------------------------------------------------
/inst/www/js/require-rcap.js:
--------------------------------------------------------------------------------
1 | requirejs.config(requirejs_config_obj); // jshint ignore:line
2 |
3 | var deps = common_deps; // jshint ignore:line
4 |
5 | deps.push(
6 | // rcloud's mini.js and bundle
7 | '../../shared.R/rcloud.rcap/js/rcap', 'rcloud_bundle');
8 |
9 | start_require(deps); // jshint ignore:line
10 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/dataDownload.tpl:
--------------------------------------------------------------------------------
1 |
2 | <%=control.getPropertyValue('buttontext')%>
3 |
4 |
--------------------------------------------------------------------------------
/inst/www/partials/_404.htm:
--------------------------------------------------------------------------------
1 | 404 - Page not found
2 | We are sorry, the page you requested cannot be found
3 | This site contains the following (top level) pages:
4 |
9 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/iframe.tpl:
--------------------------------------------------------------------------------
1 | <% if(control.controlProperties[0].value.search('https?://')>-1) { %>
2 |
3 | <% } else { %>
4 |
5 | <% } %>
6 |
7 |
8 |
--------------------------------------------------------------------------------
/inst/www/styles/loading.css:
--------------------------------------------------------------------------------
1 |
2 | #rcloud-rcap-loading {
3 | position: fixed;
4 | top: 50%;
5 | left: 50%;
6 | -webkit-transform: translate(-50%, -50%);
7 | -moz-transform: translate(-50%, -50%);
8 | -ms-transform: translate(-50%, -50%);
9 | -o-transform: translate(-50%, -50%);
10 | transform: translate(-50%, -50%);
11 | }
12 |
--------------------------------------------------------------------------------
/inst/www/js/pages/pageManager.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/Class'], function() {
2 |
3 | 'use strict';
4 |
5 | var PageManager = Class.extend({
6 | init: function(options) {
7 | options = options || {};
8 |
9 |
10 |
11 | }
12 | });
13 |
14 | return PageManager;
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/inst/www/js/ui/templates/pageMenuItem.tpl:
--------------------------------------------------------------------------------
1 |
2 | Settings
3 | <% if(p.canAddChild) { %>
4 | Add child page
5 | <% } %>
6 | Duplicate
7 |
8 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/templates/newProfileVariable.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/R/styles.R:
--------------------------------------------------------------------------------
1 |
2 | getRCAPStyles <- function() {
3 | pkgs <- rownames(installed.packages())
4 | style <- grep("^rcloud\\.rcap\\.style\\.", pkgs, value = TRUE)
5 | title <- vapply(style, function(x) packageDescription(x)$Title, "")
6 | desc <- vapply(style, function(x) packageDescription(x)$Description, "")
7 | unname(mapply(c, style, title, desc, SIMPLIFY = FALSE))
8 | }
9 |
--------------------------------------------------------------------------------
/app.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | BuildType: Package
16 | PackageUseDevtools: Yes
17 | PackageInstallArgs: --no-multiarch --with-keep.source
18 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/dataUpload.tpl:
--------------------------------------------------------------------------------
1 |
2 | <%=control.getPropertyValue('buttontext')%>
3 |
4 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_confirmDialog.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/checkboxList.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% _.each(property.checkboxListOptions, function(o, i){ %>
4 |
5 |
6 | <%=o.label%>
7 |
8 | <% }); %>
9 |
10 |
--------------------------------------------------------------------------------
/man/rcapSessionInfo.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{rcapSessionInfo}
4 | \alias{rcapSessionInfo}
5 | \title{Return relevant session info in a named list}
6 | \usage{
7 | rcapSessionInfo()
8 | }
9 | \value{
10 | A list with username and nodename (host)
11 | }
12 | \description{
13 | This information is returned to the front end
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/heading.tpl:
--------------------------------------------------------------------------------
1 | <<%=control.controlProperties[1].value%>>
2 | <%
3 | if(typeof control.controlProperties[0].value !== 'undefined' && control.controlProperties[0].value.length > 0) {
4 | %>
5 | <%=control.controlProperties[0].value%>
6 | <% }else {%>
7 |
8 | <%=control.controlProperties[0].defaultValue%>
9 | <% } %>
10 |
11 | <%=control.controlProperties[1].value%>>
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/message.tpl:
--------------------------------------------------------------------------------
1 |
2 | <% if(isDesignTime) { %>
3 | <% if(control.getPropertyValue('variablename')) { %><- <%=control.getPropertyValue('variablename')%><% } %>
4 | <% } else { %>
5 |
6 | <% } %>
7 |
8 |
--------------------------------------------------------------------------------
/man/isEditMode.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/rcap.result.R
3 | \name{isEditMode}
4 | \alias{isEditMode}
5 | \title{Is the page that called this function edit or mini (or derviatives)}
6 | \usage{
7 | isEditMode()
8 | }
9 | \value{
10 | Logical: TRUE if it is the edit page
11 | }
12 | \description{
13 | Retrieves the url from the .session info and regex's it for edit.html
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/inst/www/js/ui/templates/selectOptions.tpl:
--------------------------------------------------------------------------------
1 |
2 |
×
3 |
4 | <% if(label) { %>
5 |
Select a value for <%=label%>
6 | <% } %>
7 | <% _.each(values, function(o, i){ %>
8 |
"><%=o.value%>
9 | <% }); %>
10 |
11 |
12 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/radioButtonGroup.tpl:
--------------------------------------------------------------------------------
1 |
2 | <% _.each(property.radioButtonOptions, function(o, i){ %>
3 | <%=o.label%>
4 | >
5 | <% }); %>
6 |
7 |
8 |
--------------------------------------------------------------------------------
/inst/www/js/utils/rCloud.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 |
3 | 'use strict';
4 |
5 | return {
6 | getLoggedInUser: function() {
7 | return window.rcloud.username();
8 | },
9 | getRcapViewUrl: function() {
10 | return window.ui_utils.make_url('shared.R/rcloud.rcap/rcap.html', { // jshint ignore:line
11 | notebook: window.shell.gistname()
12 | });
13 | }
14 | };
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/man/control_classes.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/controlTypes.R
3 | \docType{data}
4 | \name{control_classes}
5 | \alias{control_classes}
6 | \title{Front-end control types and matching back-end classes}
7 | \format{An object of class \code{list} of length 21.}
8 | \usage{
9 | control_classes
10 | }
11 | \description{
12 | Front-end control types and matching back-end classes
13 | }
14 | \keyword{datasets}
15 |
16 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/rPlot.tpl:
--------------------------------------------------------------------------------
1 | <%if(typeof control.controlProperties[1].value != 'undefined' && control.controlProperties[1].value.length) {%>
2 |
3 | Please wait while the plot is loaded...
4 |
5 | <%} else {%>
6 | Please wait while the plot is loaded...
7 | <% } %>
--------------------------------------------------------------------------------
/inst/www/partials/viewer.htm:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/man/RPlotControl.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/controlTypes.R
3 | \docType{data}
4 | \name{RPlotControl}
5 | \alias{RPlotControl}
6 | \title{Control class for an R plot}
7 | \format{An object of class \code{R6ClassGenerator} of length 24.}
8 | \usage{
9 | RPlotControl
10 | }
11 | \description{
12 | It runs an R function to update the plot, and then pushes
13 | the new plot to the front-end.
14 | }
15 | \keyword{datasets}
16 |
17 |
--------------------------------------------------------------------------------
/inst/www/js/utils/rcapLogger.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 |
3 | 'use strict';
4 |
5 | return function() {
6 |
7 | var me = this,
8 | messagesOn = localStorage.getItem('rcap-logging') === 'on';
9 |
10 | ['log', 'info', 'warn', 'error'].forEach(function(consoleFunc) {
11 | me[consoleFunc] = messagesOn ? function() { console[consoleFunc].apply(console, arguments); } : function() {};
12 | });
13 |
14 | };
15 |
16 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/separator.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl'], function(BaseControl) {
2 |
3 | 'use strict';
4 |
5 | var SeparatorControl = BaseControl.extend({
6 | init: function() {
7 | this._super({
8 | type : 'separator',
9 | label : 'Separator',
10 | icon: 'ellipsis-horizontal',
11 | controlProperties: [
12 |
13 | ]
14 | });
15 | },
16 | render: function() {
17 | return ' ';
18 | }
19 | });
20 |
21 | return SeparatorControl;
22 |
23 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/spinner.tpl:
--------------------------------------------------------------------------------
1 |
2 | <% if(isDesignTime) { %>
3 |
<% if(control.getPropertyValue('variablename')) { %><- <%=control.getPropertyValue('variablename')%><% } %>
4 | <% } else { %>
5 |
6 |
7 | <% } %>
8 |
9 |
--------------------------------------------------------------------------------
/man/or.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{or}
4 | \alias{\%||\%}
5 | \alias{or}
6 | \title{Evaluate rhs if lhs is NULL}
7 | \usage{
8 | l \%||\% r
9 | }
10 | \arguments{
11 | \item{l}{Left hand side, evaluate this first.}
12 |
13 | \item{r}{Right had side, only evaluate it if \code{l} is \code{NULL}.}
14 | }
15 | \value{
16 | \code{l} if it is not \code{NULL}, otherwise \code{r}.
17 | }
18 | \description{
19 | Evaluate rhs if lhs is NULL
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/multlineTextControl.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_styleEditorDialog.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/templates/dataSourceMenuItem.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%if(ds.variable || ds.function) {%>
5 | Function: <%=ds.code%>
6 |
7 | Variable: <%=ds.variable%>
8 | <%} else {%>
9 | This data source is not configured
10 | <%}%>
11 | Settings
12 |
13 |
--------------------------------------------------------------------------------
/man/rcloudEnv.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils.R
3 | \name{rcloudEnv}
4 | \alias{rcloudEnv}
5 | \title{The environment the notebook and mini.html are run in}
6 | \usage{
7 | rcloudEnv()
8 | }
9 | \value{
10 | An environment.
11 | }
12 | \description{
13 | This environment is used to search for functions that are used
14 | to update the dashboard, and for variables that are associated
15 | with dashboard controls.
16 | }
17 | \details{
18 | This is currently the global environment.
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/inst/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RCloud.RCap",
3 | "version": "0.1.0",
4 | "devDependencies": {
5 | "bower": "~1.7.9",
6 | "grunt": "~0.4.2",
7 | "grunt-cli": "~1.1.0",
8 | "grunt-contrib-jshint": "^0.11.2",
9 | "grunt-contrib-watch": "^0.6.1",
10 | "grunt-newer": "^1.1.1",
11 | "grunt-nodemailer": "^0.3.0",
12 | "grunt-open": "^0.2.3",
13 | "grunt-sass": "^1.2.1",
14 | "jshint-stylish": "^2.0.1",
15 | "main-bower-files": "^2.13.1",
16 | "time-grunt": "^1.2.1",
17 | "uglifyjs": "2.4.10"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/inst/www/js/ui/templates/controlsMenu.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/textField.tpl:
--------------------------------------------------------------------------------
1 | <%
2 | if(typeof control.controlProperties[0].value !== 'undefined' && control.controlProperties[0].value.length > 0) {
3 | %>
4 |
5 | <%=control.controlProperties[0].value%>
6 |
7 | <% } %>
8 |
9 |
10 |
--------------------------------------------------------------------------------
/man/parseSizesJson.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/controllerR6.R
3 | \name{parseSizesJson}
4 | \alias{parseSizesJson}
5 | \title{Get plot sizes from JSON}
6 | \usage{
7 | parseSizesJson(json)
8 | }
9 | \arguments{
10 | \item{json}{A JSON string from the client. Must have an element named plotSizes}
11 | }
12 | \value{
13 | List with control IDs as names and named vector of widths and heights
14 | as list items.
15 | }
16 | \description{
17 | Parse the JSON string sent from the client, find the plot IDs and sizes, and
18 | return as a neat R object.
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/inst/www/js/ui/templates/timerMenuItem.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%if(t.variable && t.interval) {%>
5 | <%if(t.variable) {%>
6 |
7 | Variable: <%=t.variable%>
8 | <%}%>
9 |
10 | Every: <%=t.interval%> seconds
11 | <%} else {%>
12 | This timer is not configured
13 | <%}%>
14 | Settings
15 |
16 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_siteSettings.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/man/twistAdjlist.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/topo-sort.R
3 | \name{twistAdjlist}
4 | \alias{twistAdjlist}
5 | \title{Convert an in-adjacency list to an out-adjacency list, or the other way}
6 | \usage{
7 | twistAdjlist(adjlist)
8 | }
9 | \arguments{
10 | \item{adjlist}{The adjacencly list of the graph. See
11 | \code{topologicalSort} for the expected format.}
12 | }
13 | \value{
14 | Another adjacency list, corresponding to the graph
15 | with all edge directions reversed.
16 | }
17 | \description{
18 | In other words, it reverses the direction of each edge in a graph.
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_designerSettings.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_viewerDataUpload.htm:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_profileSettings.htm:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_viewerProfileSettings.htm:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/inst/www/js/data/dataSource.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/Class'], function() {
2 |
3 | 'use strict';
4 |
5 | var DataSource = Class.extend({
6 | init: function(options) {
7 | options = options || {};
8 |
9 | this.id = 'rcap' + Math.random().toString(16).slice(2);
10 | this.variable = '';
11 | this.code = '';
12 | },
13 | toJSON: function() {
14 | return {
15 | 'id' : this.id,
16 | 'variable': this.variable,
17 | 'code': this.code,
18 | 'type': 'dataSource'
19 | };
20 | }
21 | });
22 |
23 | return DataSource;
24 | });
--------------------------------------------------------------------------------
/man/bfs.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/topo-sort.R
3 | \name{bfs}
4 | \alias{bfs}
5 | \title{BFS of a graph.}
6 | \usage{
7 | bfs(adjlist, seeds)
8 | }
9 | \arguments{
10 | \item{adjlist}{The adjacency list of the graph. See
11 | \code{topologicalSort} for the expected format.}
12 |
13 | \item{seeds}{Character vector, vertex ids to start the BFS from.}
14 | }
15 | \value{
16 | Character vector with all vertex ids that are reachable
17 | from the \code{seeds}.
18 | }
19 | \description{
20 | From the given vertices we collect all vertices that the reachable
21 | from them. There are all the controls that we need to update.
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/inst/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "undef": true,
16 | "unused": true,
17 | "strict": true,
18 | "trailing": true,
19 | "smarttabs": true,
20 | "globals": {
21 | "angular": false,
22 | "require": false,
23 | "define" : false,
24 | "_" : false,
25 | "$" : false,
26 | "RCloud" : false,
27 | "Notebook" : false,
28 | "alert" : false,
29 | "Class" : false,
30 | "requirejs": false
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_controlSettings.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/templates/viewerDataDownload.tpl:
--------------------------------------------------------------------------------
1 | <% if(files.length) { %>
2 |
3 |
4 |
5 | Name
6 | Size
7 | Last modified
8 |
9 |
10 |
11 | <% _.each(files, function(file){ %>
12 |
13 | <%=file.filename%>
14 | <%=file.filesize%>
15 | <%=file.lastmodified%>
16 |
17 | <% }); %>
18 |
19 |
20 | <% } else { %>
21 | No files available
22 | <% } %>
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/templates/profileVariables.tpl:
--------------------------------------------------------------------------------
1 |
21 |
22 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/ace.tpl:
--------------------------------------------------------------------------------
1 | <%if(property.isHorizontal) { %>
2 |
3 |
4 |
5 | <%=property.label%>
6 |
7 |
8 |
9 |
<%=property.helpText%>
10 |
11 |
12 |
13 | <% } else { %>
14 |
15 |
23 |
24 | <% } %>
--------------------------------------------------------------------------------
/inst/www/js/ui/templates/siteSettingsMenu.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/datePicker.tpl:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 | <%
16 | if(typeof control.controlProperties[0].value !== 'undefined' && control.controlProperties[0].value.length > 0) {
17 | %>
18 |
19 | <%=control.controlProperties[0].value%>
20 |
21 | <% } %>
22 |
--------------------------------------------------------------------------------
/inst/www/styles/parsleyjs/parsley.scss:
--------------------------------------------------------------------------------
1 | input.parsley-success,
2 | select.parsley-success,
3 | textarea.parsley-success {
4 | color: #468847;
5 | background-color: #DFF0D8;
6 | border: 1px solid #D6E9C6;
7 | }
8 |
9 | input.parsley-error,
10 | select.parsley-error,
11 | textarea.parsley-error {
12 | color: #B94A48;
13 | background-color: #F2DEDE;
14 | border: 1px solid #EED3D7;
15 | }
16 |
17 | .parsley-errors-list {
18 | margin: 2px 0 3px;
19 | padding: 0;
20 | list-style-type: none;
21 | font-size: 0.9em;
22 | line-height: 0.9em;
23 | opacity: 0;
24 |
25 | transition: all .3s ease-in;
26 | -o-transition: all .3s ease-in;
27 | -moz-transition: all .3s ease-in;
28 | -webkit-transition: all .3s ease-in;
29 | }
30 |
31 | .parsley-errors-list.filled {
32 | opacity: 1;
33 | }
34 |
--------------------------------------------------------------------------------
/man/rcloud.rcap.caps.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/zzz.R
3 | \docType{data}
4 | \name{rcloud.rcap.caps}
5 | \alias{rcloud.rcap.caps}
6 | \title{List of OCAPS}
7 | \format{An object of class \code{NULL} of length 0.}
8 | \usage{
9 | rcloud.rcap.caps
10 | }
11 | \description{
12 | \itemize{
13 | \item \code{getRFunctions} Query all R functions in the
14 | rcloud environment. It calls
15 | \code{\link{rcloud.rcap.global.functions}}.
16 | \item \code{getRTime} Query the current time of the R interpreter.
17 | This is used for debugging.
18 | \item \code{updateControls} Send an update request from the
19 | front-end to the back-end. It calls the \code{update} method
20 | of the Controller.
21 | }
22 | }
23 | \keyword{datasets}
24 |
25 |
--------------------------------------------------------------------------------
/man/rcloud.rcap.global.functions.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/ocaps.R
3 | \name{rcloud.rcap.global.functions}
4 | \alias{rcloud.rcap.global.functions}
5 | \title{Find all functions in the rcloud environment}
6 | \usage{
7 | rcloud.rcap.global.functions()
8 | }
9 | \value{
10 | A character vector of function names
11 | }
12 | \description{
13 | The rcloud environment is the environment the notebook
14 | runs in. This is currently the global environment, i.e. .GlobalEnv.
15 | }
16 | \details{
17 | This function is used by the designer, to provide suggestions
18 | whenever the designer user needs to supply an R function name;
19 | E.g. when creating an R plot, the function that does the plotting,
20 | or when a dropdown is populated by an R function.
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_viewerDataDownload.htm:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Downloading
12 |
13 |
14 | An error occurred
15 |
16 |
17 |
18 |
21 |
--------------------------------------------------------------------------------
/R/ocaps.R:
--------------------------------------------------------------------------------
1 |
2 | #' Find all functions in the rcloud environment
3 | #'
4 | #' The rcloud environment is the environment the notebook
5 | #' runs in. This is currently the global environment, i.e. .GlobalEnv.
6 | #'
7 | #' This function is used by the designer, to provide suggestions
8 | #' whenever the designer user needs to supply an R function name;
9 | #' E.g. when creating an R plot, the function that does the plotting,
10 | #' or when a dropdown is populated by an R function.
11 | #'
12 | #' @return A character vector of function names
13 |
14 | rcloud.rcap.global.functions <- function() {
15 |
16 | ## Get all objects
17 | globalObjects <- ls(envir = rcloudEnv())
18 |
19 | ## Keep the functions
20 | Filter(
21 | function(x) is.function(get(x, envir = rcloudEnv())),
22 | globalObjects
23 | )
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/checkboxList.tpl:
--------------------------------------------------------------------------------
1 | <%=control.controlProperties[0].value%>
2 |
17 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/leaflet.tpl:
--------------------------------------------------------------------------------
1 | <%if(typeof control.controlProperties[1].value !== 'undefined' && control.controlProperties[1].value.length) {%>
2 | Please wait while the map is loaded...
3 |
4 | <%} else {%>
5 | Please wait while the map is loaded...
6 | <% } %>
7 |
8 |
9 | <%if(typeof control.controlProperties[1].value !== 'undefined' && control.controlProperties[1].value.length) {%>
10 |
15 | <% } %>
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/radioButtonGroup.tpl:
--------------------------------------------------------------------------------
1 | <%=control.controlProperties[0].value%>
2 |
17 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/text.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'rcap/js/ui/properties/textProperty',
3 | 'rcap/js/ui/properties/wysiwygProperty'], function(GridControl, TextProperty, WysiwygProperty) {
4 |
5 | 'use strict';
6 |
7 | var TextControl = GridControl.extend({
8 | init: function() {
9 | this._super({
10 | type : 'text',
11 | controlCategory: 'HTML',
12 | label : 'Text',
13 | icon: 'pencil',
14 | controlProperties: [
15 | new WysiwygProperty({
16 | uid: 'content',
17 | label : 'Content',
18 | defaultValue : '',
19 | isRequired: true
20 | })
21 | ]
22 | });
23 | },
24 | render: function() {
25 | return '' + this.controlProperties[0].value + '
';
26 | }
27 | });
28 |
29 | return TextControl;
30 |
31 | });
32 |
--------------------------------------------------------------------------------
/man/rcap.result.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/rcap.result.R
3 | \name{rcap.result}
4 | \alias{rcap.result}
5 | \title{Set up a dashboard}
6 | \usage{
7 | rcap.result(rcapConfigFileName = "rcap_designer.json")
8 | }
9 | \arguments{
10 | \item{rcapConfigFileName}{Character vector:
11 | The name of the json file in the assets.}
12 | }
13 | \description{
14 | This function must called from the last cell of the notebook.
15 | When running in mini.html, it requests the asset that contains the
16 | configuration of the dashboard, and initializes the viewer from it.
17 | }
18 | \details{
19 | Then it creates the server side controller, and the controller
20 | creates all the control objects that corresponds to the elements
21 | of the dashboard.
22 |
23 | This function should not be called from the notebook itself.
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/inst/www/js/ui/message.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 |
3 | 'use strict';
4 |
5 | var Message = function(options) {
6 |
7 | this.validMessageTypes = ['Information', 'Warning', 'Error'];
8 |
9 | options = options || {};
10 |
11 | var messageType = options.messageType || 'Information';
12 |
13 | if(this.validMessageTypes.indexOf(messageType) === -1) {
14 | throw new Error('Message type ' + messageType + ' is not valid.');
15 | }
16 |
17 | if(!options.content){
18 | throw new Error('Expected non zero length content parameter');
19 | }
20 |
21 | this.messageType = messageType;
22 | this.content = options.content;
23 |
24 | };
25 |
26 | Message.prototype.getValidMessageTypes = function() {
27 | return this.validMessageTypes;
28 | };
29 |
30 | return Message;
31 | });
32 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/rangeControl.tpl:
--------------------------------------------------------------------------------
1 | <% if(property.isHorizontal) { %>
2 |
3 |
4 |
5 | <%=property.label%>
6 |
7 |
8 |
9 |
10 |
11 |
12 | <% } else { %>
13 |
14 |
15 | <%=property.label%>
16 |
17 |
18 |
19 | <% } %>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/dropdown.tpl:
--------------------------------------------------------------------------------
1 | <%
2 | if(typeof control.controlProperties[0].value !== 'undefined' && control.controlProperties[0].value.length > 0) {
3 | %>
4 |
5 | <%=control.controlProperties[0].value%>
6 |
7 | <% } %>
8 |
9 |
10 | <%
11 | if( control.controlProperties[2].optionType == 'manual') {
12 | %>
13 | <% _.each(control.controlProperties[2].value, function(o, i){ %>
14 | <%=o.label%>
15 | <% }); %>
16 |
17 | <% } else { %>
18 |
19 | <% if(isDesignTime) { %>
20 |
21 | {{ Runtime generated }}
22 |
23 | <% } %>
24 |
25 | <% } %>
26 |
27 |
28 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/slider.tpl:
--------------------------------------------------------------------------------
1 | <%
2 | if(typeof control.controlProperties[0].value !== 'undefined' && control.controlProperties[0].value.length > 0) {
3 | %>
4 |
5 | <%=control.controlProperties[0].value%>
6 |
7 | <% } %>
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/testthat/test-bfs.R:
--------------------------------------------------------------------------------
1 |
2 | context("BFS")
3 |
4 | test_that("BFS on a dependency graph", {
5 |
6 | G <- list(
7 | "a" = "b",
8 | "b" = character(),
9 | "c" = "d",
10 | "d" = character(),
11 | "e" = "f",
12 | "f" = character()
13 | )
14 |
15 | expect_equal(bfs(G, "a"), "b")
16 | expect_equal(bfs(G, "c"), "d")
17 | expect_equal(sort(bfs(G, c("a", "c"))), c("b", "d"))
18 |
19 | G <- list(
20 | "7" = c("11", "8"),
21 | "5" = "11",
22 | "3" = c("8", "10"),
23 | "11" = c("2", "9", "10"),
24 | "8" = "9",
25 | "2" = character(),
26 | "9" = character(),
27 | "10" = character()
28 | )
29 |
30 | expect_equal(sort(bfs(G, character())), character())
31 | expect_equal(sort(bfs(G, "10")), character())
32 | expect_equal(sort(bfs(G, "7")), c("10", "11", "2", "8", "9"))
33 | expect_equal(
34 | sort(bfs(G, c("7", "5"))),
35 | c("10", "11", "2", "8", "9")
36 | )
37 | })
38 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export(rcap.result)
4 | export(rcapSessionInfo)
5 | export(showUpdates)
6 | export(rcap.getDataUploadPath)
7 | export(rcap.ls.datasets)
8 | export(rcap.ls.dataset.files)
9 | export(rcap.messageWidget.msg)
10 | export(rcap.messageWidget.write)
11 | export(rcap.progressSpinner.msg)
12 | export(rcap.progressSpinner.write)
13 | importFrom(R6,R6Class)
14 | importFrom(Rserve,Rserve.context)
15 | importFrom(codetools,findGlobals)
16 | importFrom(jsonlite,fromJSON)
17 | import(rcloud.htmlwidgets)
18 | importFrom(rcloud.support,RCloudDevice)
19 | importFrom(rcloud.support,rcloud.flush.plot)
20 | importFrom(rcloud.support,rcloud.get.asset)
21 | importFrom(rcloud.support,rcloud.get.url)
22 | importFrom(rcloud.support,rcloud.html.out)
23 | importFrom(rcloud.support,rcloud.output.context)
24 | importFrom(rcloud.web,rcw.append)
25 | importFrom(rcloud.web,rcw.resolve)
26 | importFrom(rcloud.web,rcw.result)
27 | importFrom(rcloud.web,rcw.set)
28 |
--------------------------------------------------------------------------------
/tests/testthat/test-parse-controls.R:
--------------------------------------------------------------------------------
1 |
2 | context("Parsing controls")
3 |
4 | test_that("we can parse controls from JSON", {
5 | resp <- paste(readLines("testConfig.json"), collapse = "\n")
6 | resp <- fromJSON(resp, simplifyVector = FALSE)
7 | ctrls <- getControls(resp)
8 |
9 | expect_equal(length(ctrls), 11)
10 | expect_equal(
11 | vapply(ctrls, "[[", "", "type"),
12 | c("datepicker", "datepicker", "separator", "checkboxlist", "form",
13 | "rplot", "image", "rplot", "rplot", "datepicker", "form")
14 | )
15 | expect_equal(names(ctrls[[1]]), c("type", "id", "controlProperties"))
16 | expect_equal(
17 | names(ctrls[[5]]),
18 | c("type", "x", "y", "width", "height", "id", "controlProperties",
19 | "childControls")
20 | )
21 | expect_equal(
22 | names(ctrls[[6]]),
23 | c("type", "x", "y", "width", "height", "id", "controlProperties",
24 | "isOnGrid")
25 | )
26 | expect_equal(length(ctrls[[1]]$controlProperties), 2)
27 | })
28 |
--------------------------------------------------------------------------------
/inst/www/js/ui/infoBarManager.js:
--------------------------------------------------------------------------------
1 | define(['pubsub', 'site/pubSubTable'], function(PubSub, pubSubTable) {
2 |
3 | 'use strict';
4 |
5 | var InfoBarManager = function() {
6 |
7 | this.initialise = function() {
8 |
9 | PubSub.subscribe(pubSubTable.changeSelectedPage, function(msg, page) {
10 | $('#current-page')
11 | .data('id', page.id)
12 | .html(page.navigationTitle);
13 | });
14 |
15 | PubSub.subscribe(pubSubTable.updatePage, function(msg, page) {
16 | if($('#current-page').data('id') === page.id) {
17 | $('#current-page').html(page.navigationTitle);
18 | }
19 | });
20 |
21 | //
22 | $('#current-page-status').click(function() {
23 | PubSub.publish(pubSubTable.showPageFlyout);
24 | });
25 |
26 | this.initialise = function() {};
27 | };
28 | };
29 |
30 | return InfoBarManager;
31 | });
32 |
--------------------------------------------------------------------------------
/R/eventHandlerR6.R:
--------------------------------------------------------------------------------
1 | #' Abstract class for event handlers
2 | #'
3 | #' @section Methods:
4 | #'
5 | #' \code{supports(event = list())} \code{TRUE} if handler supports the event, \code{FALSE} otherwise
6 | #'
7 | #' \code{handle(event = list())} handles the event, returns a response object with outcome of the processing and result data.
8 | #'
9 | EventHandler <- R6::R6Class("EventHandler",
10 |
11 | public = list(
12 |
13 | initialize = function() {
14 |
15 | },
16 |
17 | supports = function(event = list()) {
18 | FALSE
19 | },
20 | handle = function(event = list()) {
21 |
22 | }
23 | ),
24 |
25 | private = list(
26 | )
27 | )
--------------------------------------------------------------------------------
/tests/testthat/test-generate-table-css.R:
--------------------------------------------------------------------------------
1 |
2 | context("Generate Table CSS")
3 |
4 | test_that("createTableCss returns the expected results", {
5 |
6 | colNames <- colnames(mtcars)
7 |
8 | options <- list(columnWidths = c("50%", rep("5%", length(colnames(mtcars)) - 1)),
9 | rightAlign = "hp",
10 | columnColor = c("mpg" = "red", "cyl" = "blue", "drat" = "green"),
11 | textColor = c("mpg" = "green", "drat" = "yellow", "hp" = "red"))
12 |
13 | getClassNames <- createTableIdDf(options = options, colNames = colNames, id = "table")
14 |
15 | getCss <- createTableCss(getClassNames, id = "table")
16 |
17 | expectedRes <- ""
18 |
19 | expect_equal(getCss, expectedRes)
20 | })
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/autocomplete.tpl:
--------------------------------------------------------------------------------
1 | <%if(property.isHorizontal) { %>
2 |
3 |
4 |
5 | <%=property.label%>
6 |
7 |
8 |
9 |
<%=property.helpText%>
10 |
11 |
12 |
13 | <% } else { %>
14 |
15 |
20 |
21 | <% } %>
22 |
23 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/multiSelect.tpl:
--------------------------------------------------------------------------------
1 | <%
2 | if(typeof control.controlProperties[0].value !== 'undefined' && control.controlProperties[0].value.length > 0) {
3 | %>
4 |
5 | <%=control.controlProperties[0].value%>
6 |
7 | <% } %>
8 |
9 |
10 | <%
11 | if( control.controlProperties[3].optionType == 'manual') {
12 | %>
13 | <% _.each(control.controlProperties[3].value, function(o, i){ %>
14 | <%=o.label%>
15 | <% }); %>
16 | <% } else { %>
17 | <% if(isDesignTime) { %>
18 | {{ Runtime generated }}
19 | <% } %>
20 | <% } %>
21 |
22 |
23 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_executionOrderDialog.htm:
--------------------------------------------------------------------------------
1 |
29 |
--------------------------------------------------------------------------------
/inst/www/styles/viewercontrols.scss:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // RCAP Controls, View Mode
4 | //
5 |
6 | .select2-selection__choice {
7 | color: black;
8 | }
9 |
10 | .select2-container--default .select2-selection--multiple {
11 | border-radius: 0;
12 | }
13 |
14 | ////////////////////////////////////////////// page menu /////////////////////////////////////////////////
15 | .rcap-pagemenu {
16 | margin: 0;
17 | padding: 0;
18 | }
19 |
20 | .rcap-pagemenu li {
21 | padding: 0;
22 | color: #369;
23 | list-style-type: none;
24 | }
25 |
26 | .rcap-pagemenu a {
27 | padding: 5px;
28 | display: block;
29 | text-decoration: none;
30 | }
31 |
32 | .rcap-pagemenu li.current {
33 | background-color: #369;
34 | }
35 |
36 | .rcap-pagemenu li.current a {
37 | color: white;
38 | }
39 |
40 | .rcap-pagemenu li:not(.current) a:hover {
41 | background-color: lighten(#369, 50%);
42 | }
43 |
44 | .rcap-pagemenu-horizontal li {
45 | float: left;
46 | }
47 |
48 | .rcap-pagemenu-hamburger {}
49 |
--------------------------------------------------------------------------------
/tests/testthat/test-controller.R:
--------------------------------------------------------------------------------
1 |
2 | context("Controller")
3 |
4 | test_that("controller builds dependency graph and update order", {
5 |
6 | resp <- paste(readLines("testConfig.json"), collapse = "\n")
7 | resp <- fromJSON(resp, simplifyVector = FALSE)
8 |
9 | ## TODO: this is a hack that will break at some point
10 | on.exit(rm(list = "makePlot1", envir = .GlobalEnv), add = TRUE)
11 | assign(
12 | "makePlot1",
13 | function() { datePicker1 + datePicker2 },
14 | envir = .GlobalEnv
15 | )
16 |
17 | skip("Cannot test currently without rcloud")
18 |
19 | cnt <- Controller$new(resp)
20 | succList <- cnt$.__enclos_env__$private$succList
21 |
22 | expect_equal(succList$rcap16014ed1, rcap630974bf)
23 | expect_equal(succList$rcapc43838c4, rcap630974bf)
24 |
25 | topoSort <- cnt$.__enclos_env__$private$topoSort
26 |
27 | expect_equal(sort(names(succList)), sort(topoSort))
28 | expect_true(
29 | match("rcapc43838c4", topoSort) < match(rcap630974bf, topoSort)
30 | )
31 | expect_true(
32 | match("rcap16014ed1", topoSort) < match(rcap630974bf, topoSort)
33 | )
34 | })
35 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/submitButton.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl', 'rcap/js/ui/properties/textProperty',
2 | 'text!rcap/js/ui/controls/child/templates/submitButton.tpl'], function(BaseControl, TextProperty, tpl) {
3 |
4 | 'use strict';
5 |
6 | var SubmitButtonControl = BaseControl.extend({
7 | init: function() {
8 | this._super({
9 | type: 'submitbutton',
10 | label: 'Submit Button',
11 | icon: 'youtube-play',
12 | controlProperties: [
13 | new TextProperty({
14 | uid: 'text',
15 | label: 'Text',
16 | defaultValue: 'Submit',
17 | isHorizontal: false
18 | })
19 | ]
20 | });
21 | },
22 | render: function() {
23 | var template = _.template(tpl);
24 |
25 | return template({
26 | text: this.getPropertyValueOrDefault('text')
27 | });
28 | }
29 | });
30 |
31 | return SubmitButtonControl;
32 |
33 | });
34 |
--------------------------------------------------------------------------------
/tests/testthat/test-generate-table-ids-df.R:
--------------------------------------------------------------------------------
1 |
2 | context("Generate Table IDs DataFrame")
3 |
4 | test_that("createTableIdDf returns the expected results", {
5 |
6 | colNames <- colnames(mtcars)
7 |
8 | options <- list(columnWidths = c("50%", rep("5%", length(colnames(mtcars)) - 1)),
9 | rightAlign = "hp",
10 | columnColor = c("mpg" = "red", "cyl" = "blue", "drat" = "green"),
11 | textColor = c("mpg" = "green", "drat" = "yellow", "hp" = "red"))
12 |
13 | getClassNames <- createTableIdDf(options = options, colNames = colNames, id = "table")
14 | expectedRes <- structure(
15 | list(
16 | targets = c("cyl", "drat", "hp", "hp", "mpg"),
17 | className = c("dt-table-1", "dt-table-4", "dt-body-right dt-table-3", "dt-table-3", "dt-table-0"),
18 | `background-color` = c("blue", "green", NA, NA, "red"),
19 | color = c(NA, "yellow", NA, "red", "green")),
20 | .Names = c("targets", "className", "background-color", "color"),
21 | row.names = c(NA, 5L),
22 | class = "data.frame")
23 |
24 | expect_equal(getClassNames, expectedRes)
25 | })
--------------------------------------------------------------------------------
/inst/www/js/utils/request.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 |
3 | 'use strict';
4 |
5 | return {
6 | getUrlSearchValue : function(query) {
7 | if(_.isUndefined(window.URLSearchParams)) {
8 | return undefined;
9 | }
10 | var searchParams = new window.URLSearchParams(window.location.search);
11 | return searchParams.get(query);
12 | },
13 | getGridPreferences : function() {
14 | var width = this.getUrlSearchValue('width'),
15 | height = this.getUrlSearchValue('height'),
16 | align = this.getUrlSearchValue('align'),
17 | prefs = {};
18 |
19 | if(width && !isNaN(width)) {
20 | prefs.width = +width;
21 | }
22 |
23 | if(height && !isNaN(height)) {
24 | prefs.height = +height;
25 | }
26 |
27 | if(align && ['left', 'center'].indexOf(align) !== -1) {
28 | prefs.align = align;
29 | }
30 |
31 | return Object.keys(prefs).length ? prefs : null;
32 | }
33 | };
34 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/factories/controlPropertyFactory.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'rcap/js/ui/properties/colorProperty',
3 | 'rcap/js/ui/properties/dropdownProperty',
4 | 'rcap/js/ui/properties/textProperty',
5 | 'rcap/js/ui/properties/wysiwygProperty'
6 | ], function(ColorProperty, DropdownProperty, TextProperty, WysiwygProperty) {
7 |
8 | 'use strict';
9 |
10 | function PropertyFactory() {
11 | this.controlProperties = [
12 | new ColorProperty(),
13 | new DropdownProperty(),
14 | new TextProperty(),
15 | new WysiwygProperty()
16 | ];
17 | }
18 |
19 | PropertyFactory.prototype.getAll = function() {
20 | return this.controlProperties;
21 | };
22 |
23 | PropertyFactory.prototype.getByKey = function(key) {
24 |
25 | var Property;
26 |
27 | switch(key){
28 | case 'color': Property = new ColorProperty(); break;
29 | case 'dropdown': Property = new DropdownProperty(); break;
30 | case 'text': Property = new TextProperty(); break;
31 | case 'wysiwyg': Property = new WysiwygProperty(); break;
32 | default: Property = undefined; break;
33 | }
34 |
35 | return Property;
36 | };
37 |
38 | return PropertyFactory;
39 |
40 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/profileConfigurator.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'text!controlTemplates/profileConfigurator.tpl',
3 | 'pubsub',
4 | 'site/pubSubTable',
5 | ], function(GridControl, tpl, PubSub, pubSubTable) {
6 |
7 | 'use strict';
8 |
9 | var ProfileConfiguratorControl = GridControl.extend({
10 | init: function() {
11 | this._super({
12 | type: 'profileconfigurator',
13 | controlCategory: 'Dynamic',
14 | label: 'Profile',
15 | icon: 'user',
16 | controlProperties: []
17 | });
18 | },
19 | render: function() {
20 |
21 | var template = _.template(tpl);
22 |
23 | return template({
24 | control: this
25 | });
26 |
27 | },
28 | initialiseViewerItems: function() {
29 | $('.grid-stack-item-content.rcap-controltype-profileconfigurator').click(function() {
30 | PubSub.publish(pubSubTable.getViewerProfile);
31 | });
32 | }
33 | });
34 |
35 | return ProfileConfiguratorControl;
36 |
37 | });
38 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/baseProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/Class'], function() {
2 |
3 | 'use strict';
4 |
5 | var BaseProperty = Class.extend({
6 | init : function(options) {
7 |
8 | options = options || {};
9 |
10 | this.uid = options.uid;
11 | this.type = options.type;
12 | this.label = options.label;
13 | this.helpText = options.helpText;
14 | this.defaultValue = options.defaultValue;
15 | this.value = options.value;
16 | this.isRequired = options.isRequired || false;
17 | this.className = options.className || '';
18 | this.id = 'ctrl' + this.type + Math.random().toString(16).slice(2);
19 |
20 | },
21 | toJSON : function() {
22 | return {
23 | 'uid': this.uid,
24 | 'value': this.value,
25 | 'id': this.id
26 | };
27 | },
28 | render : function() {
29 | return '';
30 | },
31 | getDialogValue : function() {
32 | return '';
33 | },
34 | getValueOrDefault : function() {
35 | if(_.isUndefined(this.value)) {
36 | return this.defaultValue;
37 | }
38 |
39 | return this.value;
40 | },
41 | finalise: function() {
42 |
43 | }
44 | });
45 |
46 | return BaseProperty;
47 |
48 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/multilineTextProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/multlineTextControl.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | var MultiLineTextProperty = BaseProperty.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this._super({
9 | type : 'multilinetext',
10 | label : options.label || '',
11 | helpText : options.helpText || '',
12 | defaultValue : options.defaultValue || '',
13 | isRequired : options.isRequired || false,
14 | uid : options.uid,
15 | className : options.className,
16 | value: options.value
17 | });
18 |
19 | // additional assignments go here:
20 | this.rows = options.rows || 10;
21 | this.cols = options.cols || 80;
22 | },
23 | render: function(childIndex) {
24 |
25 | var template = _.template(tpl);
26 |
27 | return template({
28 | property : this,
29 | childIndex : childIndex
30 | });
31 |
32 | },
33 | getDialogValue : function() {
34 | return $('#' + this.id).val();
35 | }
36 | });
37 |
38 | return MultiLineTextProperty;
39 |
40 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/radioButtonGroupProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/radioButtonGroup.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | var RadioButtonGroupProperty = BaseProperty.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this._super({
9 | type : 'radiobuttongroup',
10 | label : options.label || '',
11 | helpText : options.helpText || '',
12 | defaultValue : options.defaultValue || '',
13 | isRequired : options.isRequired || false,
14 | uid : options.uid,
15 | className : options.className
16 | });
17 |
18 | // additional assignments go here:
19 | this.radioButtonOptions = options.radioButtonOptions || [];
20 | },
21 | render: function(childIndex) {
22 |
23 | var template = _.template(tpl);
24 |
25 | return template({
26 | property : this,
27 | childIndex : childIndex
28 | });
29 |
30 | },
31 | getDialogValue : function() {
32 | return $('#' + this.id + ' input[type="radio"]:checked:first').val();
33 | }
34 | });
35 |
36 | return RadioButtonGroupProperty;
37 |
38 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/autocompleteProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/autocomplete.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | var AutocompleteProperty = BaseProperty.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this._super({
9 | type : 'autocomplete',
10 | label : options.label || '',
11 | helpText : options.helpText || '',
12 | defaultValue : options.defaultValue || '',
13 | isRequired : options.isRequired || false,
14 | uid : options.uid,
15 | className : options.className,
16 | value: options.value
17 | });
18 |
19 | this.serviceName = options.serviceName || 'getRFunctions';
20 | this.isHorizontal = _.isUndefined(options.isHorizontal) ? true : options.isHorizontal;
21 | },
22 | render: function(childIndex) {
23 |
24 | var template = _.template(tpl);
25 |
26 | return template({
27 | property : this,
28 | childIndex : childIndex
29 | });
30 |
31 | },
32 | getDialogValue : function() {
33 | return $('#' + this.id).val();
34 | }
35 | });
36 |
37 | return AutocompleteProperty;
38 |
39 | });
40 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/spinner.js:
--------------------------------------------------------------------------------
1 | define(['pubsub',
2 | 'site/pubSubTable',
3 | 'rcap/js/ui/controls/gridControl',
4 | 'rcap/js/ui/properties/textProperty',
5 | 'text!controlTemplates/spinner.tpl'
6 | ], function (PubSub, pubSubTable, GridControl, TextProperty, tpl) {
7 |
8 | 'use strict';
9 |
10 | var SpinnerControl = GridControl.extend({
11 | init: function () {
12 | this._super({
13 | type: 'spinner',
14 | controlCategory: 'Dynamic',
15 | label: 'Spinner',
16 | icon: 'spinner',
17 | initialSize: [2, 2],
18 | controlProperties: [
19 | new TextProperty({
20 | uid: 'variablename',
21 | label: 'Variable',
22 | helpText: 'The variable associated with this spinner',
23 | isRequired: true
24 | })
25 | ]
26 | });
27 | },
28 | render: function (options) {
29 | options = options || {};
30 |
31 | var template = _.template(tpl);
32 |
33 | return template({
34 | control: this,
35 | isDesignTime: options.isDesignTime || false
36 | });
37 |
38 | },
39 | initialiseViewerItems: function () {
40 |
41 | }
42 | });
43 |
44 | return SpinnerControl;
45 |
46 |
47 | });
48 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/checkboxListProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/checkboxList.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | var CheckboxListProperty = BaseProperty.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this._super({
9 | type : 'radiobuttongroup',
10 | label : options.label || '',
11 | helpText : options.helpText || '',
12 | defaultValue : options.defaultValue || '',
13 | isRequired : options.isRequired || false,
14 | uid : options.uid,
15 | className : options.className
16 | });
17 |
18 | // additional assignments go here:
19 | this.checkboxListOptions = options.checkboxListOptions || [];
20 | },
21 | render: function(childIndex) {
22 |
23 | var template = _.template(tpl);
24 |
25 | return template({
26 | property : this,
27 | childIndex : childIndex
28 | });
29 |
30 | },
31 | getDialogValue : function() {
32 |
33 | return $('#' + this.id + ' input:checkbox:checked').map(function() {
34 | return $(this).val();
35 | }).get();
36 |
37 | }
38 | });
39 |
40 | return CheckboxListProperty;
41 |
42 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/wysiwygProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty',
2 | 'text!templates/wysiwyg.tpl',
3 | 'quill/quill',
4 | 'rcap/js/utils/quillRcapLink'
5 | ], function(BaseProperty, tpl, Quill, registerQuillLink) { // jshint ignore:line
6 | 'use strict';
7 |
8 | var WysiwygProperty = BaseProperty.extend({
9 | init: function(options) {
10 | options = options || {};
11 | this._super({
12 | type : 'wysiwyg',
13 | label : options.label || '',
14 | helpText : options.helpText || '',
15 | defaultValue : options.defaultValue || '',
16 | isRequired : options.isRequired || false,
17 | value : options.value || '',
18 | uid : options.uid,
19 | className : options.className
20 | });
21 | },
22 | render: function(childIndex) {
23 |
24 | if(!window.Quill) {
25 | window.Quill = Quill;
26 | }
27 |
28 | registerQuillLink();
29 |
30 | var template = _.template(tpl);
31 |
32 | return template({
33 | property : this,
34 | childIndex : childIndex
35 | });
36 |
37 | },
38 | getDialogValue : function() {
39 | return $('#' + this.id).find('.ql-editor').html();
40 | }
41 | });
42 |
43 | return WysiwygProperty;
44 |
45 | });
46 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_dataSourceSettings.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/datePicker.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl', 'rcap/js/ui/properties/textProperty',
2 | 'rcap/js/ui/properties/colorProperty', 'text!rcap/js/ui/controls/child/templates/datePicker.tpl'], function(BaseControl, TextProperty, ColorProperty, tpl) {
3 |
4 | 'use strict';
5 |
6 | var DatePickerControl = BaseControl.extend({
7 | init: function() {
8 | this._super({
9 | type : 'datepicker',
10 | label : 'Date Picker',
11 | icon: 'calendar',
12 | controlProperties: [
13 | new TextProperty({
14 | uid: 'label',
15 | label : 'Label',
16 | defaultValue : 'Label',
17 | helpText : 'The label for this control',
18 | isHorizontal: false
19 | }),
20 | new TextProperty({
21 | uid: 'variablename',
22 | label : 'Variable name',
23 | defaultValue : 'variable',
24 | helpText : 'The variable associated with this control',
25 | isRequired: true,
26 | isHorizontal: false
27 | })
28 | ]
29 | });
30 | },
31 | render: function() {
32 | var template = _.template(tpl);
33 |
34 | return template({
35 | control: this
36 | });
37 | }
38 | });
39 |
40 | return DatePickerControl;
41 |
42 | });
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/templates/executionOrderDetails.tpl:
--------------------------------------------------------------------------------
1 | <% _.forEach(orderDetails, function(page) { %>
2 | <% _.forEach(page.controls, function(control) {%>
3 |
4 | <% if(control.label == 'Form') { %>
5 | <% _.forEach(control.childControls, function(childControl) {%>
6 |
7 | <%= page.navigationTitle %>
8 | Form <%= childControl.label %>
9 | <%= _.filter(childControl.controlProperties, function(prop) { return prop.uid == 'variablename' || prop.uid == 'code' })[0].value %>
10 |
11 |
12 | <% }); %>
13 | <% } else { %>
14 |
15 | <%= page.navigationTitle %>
16 | <%= control.label %>
17 | <%= _.filter(control.controlProperties, function(prop) { return prop.uid == 'variablename' || prop.uid == 'code' })[0].value %>
18 |
19 |
20 | <% } %>
21 | <% }); %>
22 | <% }); %>
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/aceProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/ace.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | var AceProperty = BaseProperty.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this._super({
9 | type: 'text',
10 | label: options.label || '',
11 | helpText: options.helpText || '',
12 | defaultValue: options.defaultValue || '',
13 | isRequired: options.isRequired || false,
14 | uid: options.uid,
15 | className: options.className
16 | });
17 |
18 | this.isHorizontal = _.isUndefined(options.isHorizontal) ? true : options.isHorizontal;
19 | },
20 | render: function(childIndex) {
21 |
22 | var template = _.template(tpl);
23 |
24 | return template({
25 | property: this,
26 | childIndex: childIndex
27 | });
28 |
29 | },
30 | getDialogValue: function() {
31 | //return $('#' + this.id).val();
32 |
33 | return 'AceProperty.js TODO';
34 | }
35 | });
36 |
37 | return AceProperty;
38 |
39 | });
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_timerSettings.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/dropdownProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/dropdownControl.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | var DropdownProperty = BaseProperty.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this._super({
9 | type : 'dropdown',
10 | label : options.label || '',
11 | helpText : options.helpText || '',
12 | defaultValue : options.defaultValue || '',
13 | isRequired : options.isRequired || false,
14 | uid : options.uid,
15 | className : options.className,
16 | value: options.value
17 | });
18 |
19 | // additional assignments go here:
20 | this.availableOptions = options.availableOptions || [];
21 | this.isHorizontal = _.isUndefined(options.isHorizontal) ? true : options.isHorizontal;
22 | this.defaultOptionText = options.defaultOptionText || 'Select an option';
23 | },
24 | render: function(childIndex) {
25 |
26 | var template = _.template(tpl);
27 |
28 | return template({
29 | property : this,
30 | childIndex : childIndex
31 | });
32 |
33 | },
34 | getDialogValue : function() {
35 | return $('#' + this.id).find('option:selected').val();
36 | }
37 | });
38 |
39 | return DropdownProperty;
40 |
41 | });
42 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_pageSettings.htm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/message.js:
--------------------------------------------------------------------------------
1 | define(['pubsub',
2 | 'site/pubSubTable',
3 | 'rcap/js/ui/controls/gridControl',
4 | 'rcap/js/ui/properties/textProperty',
5 | /*
6 | 'rcap/js/ui/properties/stringValueProperty',
7 | 'utils/variableHandler',
8 | */
9 | 'text!controlTemplates/message.tpl'
10 | ], function (PubSub, pubSubTable, GridControl, TextProperty, /*StringValueProperty, variableHandler,*/ tpl) {
11 |
12 | 'use strict';
13 |
14 | var MessageControl = GridControl.extend({
15 | init: function () {
16 | this._super({
17 | type: 'message',
18 | controlCategory: 'Dynamic',
19 | label: 'Message',
20 | icon: 'comment',
21 | initialSize: [2, 2],
22 | controlProperties: [
23 | new TextProperty({
24 | uid: 'variablename',
25 | label: 'Variable',
26 | helpText: 'The variable associated with this message',
27 | isRequired: true
28 | })
29 | ]
30 | });
31 | },
32 | render: function (options) {
33 | options = options || {};
34 |
35 | var template = _.template(tpl);
36 |
37 | return template({
38 | control: this,
39 | isDesignTime: options.isDesignTime || false
40 | });
41 |
42 | },
43 | initialiseViewerItems: function () {
44 |
45 | }
46 | });
47 |
48 | return MessageControl;
49 |
50 |
51 | });
52 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
8 |
9 | ## Expected Behavior
10 |
11 |
12 |
13 | ## Current Behavior
14 |
15 |
16 |
17 | ## Possible Solution
18 |
19 |
20 |
21 | ## Steps to Reproduce (for bugs)
22 |
23 |
24 | 1.
25 | 2.
26 | 3.
27 | 4.
28 |
29 | ## Context
30 |
31 |
32 |
33 | ## Environment
34 |
35 | * Browser name and version:
36 |
--------------------------------------------------------------------------------
/man/topologicalSort.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/topo-sort.R
3 | \name{topologicalSort}
4 | \alias{topologicalSort}
5 | \title{Topological sorting of a directed graph, represented by
6 | adjacency lists. Graph vertices are represented by strings.}
7 | \usage{
8 | topologicalSort(adjlist)
9 | }
10 | \arguments{
11 | \item{adjlist}{List of successors of all vertices.
12 | Itmust be named, and the vertex names must be the vertices.}
13 | }
14 | \value{
15 | The vertex ids, in topologically sorted order. I.e.
16 | if v2 comes after v1 in the list, then there must not be an
17 | edge from v2 to v1.
18 | }
19 | \description{
20 | It uses Taarjan's depth-first search algorithm, see
21 | https://en.wikipedia.org/wiki/Topological_sorting#Tarjan.27s_algorithm
22 | }
23 | \details{
24 | \preformatted{
25 | L <- Empty list that will contain the sorted nodes
26 | while there are unmarked nodes do
27 | select an unmarked node n
28 | visit(n)
29 |
30 | function visit(node n)
31 | if n has a temporary mark then stop (not a DAG)
32 | if n is not marked (i.e. has not been visited yet) then
33 | mark n temporarily
34 | for each node m with an edge from n to m do
35 | visit(m)
36 | mark n permanently
37 | unmark n temporarily
38 | add n to head of L
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/inst/www/js/data/timer.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/Class'], function() {
2 |
3 | 'use strict';
4 |
5 | var Timer = Class.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this.variable = '';
9 | this.id = 'rcap' + Math.random().toString(16).slice(2);
10 | this.interval = 60;
11 | },
12 | start: function() {
13 | var varName = this.variable;
14 | var id = this.id;
15 |
16 | var eventFunction = function(varName, id) {
17 | return function() {
18 | var updateVarsJSON = JSON.stringify({
19 | updatedVariables:[{
20 | variableName: varName,
21 | controlId: id,
22 | value: 0
23 | }]
24 | });
25 | window.RCAP.updateControls(updateVarsJSON);
26 | };
27 | };
28 |
29 | setInterval(eventFunction(varName, id), this.interval * 1000);
30 | },
31 | toJSON: function() {
32 | return {
33 | 'id' : this.id,
34 | 'variable': this.variable,
35 | 'interval': this.interval,
36 | 'type': 'timer'
37 | };
38 | }
39 | });
40 |
41 | return Timer;
42 | });
--------------------------------------------------------------------------------
/tests/testthat/test-controls.R:
--------------------------------------------------------------------------------
1 |
2 | context("Controls")
3 |
4 | test_that("controls public API is OK", {
5 |
6 | skip("Cannot test currently without rcloud")
7 |
8 | resp <- paste(readLines("testConfig.json"), collapse = "\n")
9 | resp <- fromJSON(resp, simplifyVector = FALSE)
10 | cnt <- Controller$new(resp)
11 | ctrls <- cnt$.__enclos_env__$private$controls
12 |
13 | expect_equivalent(
14 | vapply(ctrls, function(x) x$getVariableName(), ""),
15 | c("datePicker1", "datePicker2", NA, "option1", NA, NA, NA, NA, NA,
16 | "datePicker3", NA)
17 | )
18 | })
19 |
20 | test_that("dependentVariables works", {
21 |
22 | skip("Cannot test currently without rcloud")
23 |
24 | resp <- paste(readLines("testConfig.json"), collapse = "\n")
25 | resp <- fromJSON(resp, simplifyVector = FALSE)
26 | cnt <- Controller$new(resp)
27 | ctrls <- cnt$.__enclos_env__$private$controls
28 |
29 | makePlot1 <- function() {
30 | var1 + var2
31 | }
32 |
33 | expect_equal(
34 | ctrls[[6]]$dependentVariables(
35 | c("var1", "var2", "var3"),
36 | envir = environment()
37 | ),
38 | c("var1", "var2")
39 | )
40 |
41 | expect_equal(
42 | ctrls[[6]]$dependentVariables(c("var1"), envir = environment()),
43 | "var1"
44 | )
45 |
46 | expect_equal(
47 | ctrls[[6]]$dependentVariables(character(), envir = environment()),
48 | character()
49 | )
50 |
51 | })
52 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: rcloud.rcap
2 | Title: Interactive Dashboard and Website Builder for RCloud
3 | Version: 0.4.7.1
4 | Authors@R: c(
5 | person("Shane", "Porter", email = "sporter@mango-solutions.com",
6 | role = c("aut", "cre")),
7 | person("Mateusz", "Rogalski", role = c("aut")),
8 | person("Douglas", "Ashton", role = c("aut")),
9 | person("Gábor", "Csárdi", role = c("aut")),
10 | person("Paulin", "Shek", role = "aut"),
11 | person("Nathan", "Eastwood", role = "aut"))
12 | Description: RCloud powered dashboards and websites.
13 | Depends:
14 | rcloud.htmlwidgets
15 | Imports:
16 | Rserve,
17 | rcloud.support,
18 | rcloud.web,
19 | jsonlite,
20 | R6,
21 | codetools
22 | Suggests:
23 | sankey,
24 | testthat
25 | License: MIT + file LICENSE
26 | RCloud-Extension: gui
27 | RoxygenNote: 5.0.1
28 | SystemRequirements: node.js and npm, bower, Grunt, GNU make
29 | Collate:
30 | 'controlR6.R'
31 | 'dataTableControl.R'
32 | 'controlTypes.R'
33 | 'controllerR6.R'
34 | 'eventHandlerR6.R'
35 | 'getControls.R'
36 | 'ocaps.R'
37 | 'rcap.dataDownload.R'
38 | 'rcap.events.R'
39 | 'rcap.messageWidget.R'
40 | 'rcap.progressSpinner.R'
41 | 'rcap.result.R'
42 | 'rcap.user.profile.R'
43 | 'rcap.upload.data.R'
44 | 'showUpdates.R'
45 | 'styles.R'
46 | 'topo-sort.R'
47 | 'utils.R'
48 | 'zzz.R'
49 | Encoding: UTF-8
50 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/textProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/textControl.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | var TextProperty = BaseProperty.extend({
6 | init: function(options) {
7 | options = options || {};
8 | this._super({
9 | type: 'text',
10 | label: options.label || '',
11 | helpText: options.helpText || '',
12 | defaultValue: options.defaultValue || '',
13 | isRequired: options.isRequired || false,
14 | uid: options.uid,
15 | className: options.className,
16 | value: options.value || options.defaultValue
17 | });
18 |
19 | // additional assignments go here:
20 | this.validationDataType = options.validationDataType;
21 |
22 | this.isHorizontal = _.isUndefined(options.isHorizontal) ? true : options.isHorizontal;
23 | },
24 | render: function(childIndex) {
25 |
26 | var template = _.template(tpl);
27 |
28 | return template({
29 | property: this,
30 | childIndex: childIndex
31 | });
32 |
33 | },
34 | getDialogValue: function() {
35 | return $('#' + this.id).val();
36 | }
37 | });
38 |
39 | return TextProperty;
40 |
41 | });
--------------------------------------------------------------------------------
/man/Controller.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/controllerR6.R
3 | \docType{data}
4 | \name{Controller}
5 | \alias{Controller}
6 | \title{Orchestrate the updates of the controls in the back-end}
7 | \format{An object of class \code{R6ClassGenerator} of length 24.}
8 | \usage{
9 | Controller
10 | }
11 | \description{
12 | Orchestrate the updates of the controls in the back-end
13 | }
14 | \section{Methods}{
15 |
16 |
17 | \code{initialize(rcapConfig)} The object is constructed from the
18 | parsed designer JSON configuration file.
19 |
20 | \code{update(controls)} update some controls. The argument is the
21 | JSON of the update request from the front-end.
22 | }
23 |
24 | \section{Private methods and variables}{
25 |
26 |
27 | \code{controls} named list of all controls, \code{Control} objects.
28 |
29 | \code{succList} the adjacency list representation of the control
30 | dependency graph. This is used at initialization to calculate the
31 | update order, and at each update to decide which other controls
32 | must be updated.
33 |
34 | \code{topoSort} ids of all controls, in topological (i.e. update) order.
35 |
36 | \code{updateInOrder(ids)} update the controls in
37 | the specified order, with the specified values. This function is
38 | called to perform the actual updates, once the order is decided
39 | based on the topological sorting.
40 | }
41 | \keyword{datasets}
42 |
43 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/colorProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty',
2 | 'text!templates/colorControl.tpl',
3 | 'spectrum/spectrum'], function(BaseProperty, tpl) {
4 | 'use strict';
5 |
6 | var ColorProperty = BaseProperty.extend({
7 | init: function(options) {
8 | options = options || {};
9 | this._super({
10 | type : 'color',
11 | label : options.label || '',
12 | helpText : options.helpText || '',
13 | defaultValue : options.defaultValue || '',
14 | isRequired : options.isRequired || false,
15 | uid : options.uid,
16 | className : options.className
17 | });
18 |
19 | // additional assignments go here:
20 | this.isHorizontal = _.isUndefined(options.isHorizontal) ? true : options.isHorizontal;
21 | this.showAlpha = _.isUndefined(options.showAlpha) ? false : options.showAlpha;
22 |
23 | // default value dependent on alpha support:
24 | if(this.defaultValue === '') {
25 | this.defaultValue = this.showAlpha ? 'rgba(255, 255, 255, 0)' : 'rgb(255, 255, 255)';
26 | }
27 | },
28 | render: function(childIndex) {
29 |
30 | var template = _.template(tpl);
31 |
32 | return template({
33 | property : this,
34 | childIndex : childIndex
35 | });
36 |
37 | },
38 | getDialogValue : function() {
39 | return $('#' + this.id).spectrum('get').toRgbString();
40 | }
41 | });
42 |
43 | return ColorProperty;
44 |
45 | });
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_addPage.htm:
--------------------------------------------------------------------------------
1 |
29 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/dropdownControl.tpl:
--------------------------------------------------------------------------------
1 | <%if(property.isHorizontal) { %>
2 |
3 |
4 |
5 | <%=property.label%>
6 |
7 |
8 |
>
9 | <%=property.defaultOptionText%>
10 | <% _.each(property.availableOptions, function(o){ %>
11 | ><%=o.text%>
12 | <% }); %>
13 |
14 |
<%=property.helpText%>
15 |
16 |
17 |
18 | <% } else { %>
19 |
20 |
31 |
32 | <% } %>
33 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/textControl.tpl:
--------------------------------------------------------------------------------
1 | <%if(property.isHorizontal) { %>
2 |
3 |
4 |
5 | <%=property.label%>
6 |
7 |
8 |
9 | <% if (typeof property.validationDataType !== 'undefined' && property.validationDataType.length > 0) { %>
10 | data-parsley-type="<%= property.validationDataType %>"
11 | <% } %>
12 | />
13 |
<%=property.helpText%>
14 |
15 |
16 |
17 | <% } else { %>
18 |
19 |
29 |
30 | <% } %>
--------------------------------------------------------------------------------
/inst/www/js/utils/variableHandler.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/utils/rcapLogger'], function(RcapLogger) {
2 |
3 | 'use strict';
4 |
5 | return {
6 | submitChange: function(variableData) {
7 |
8 | if(!variableData) {
9 | return;
10 | }
11 |
12 | if(!_.isArray(variableData)) {
13 | variableData = [variableData];
14 | }
15 |
16 | if(variableData.length) {
17 | var plotSizes = [];
18 |
19 | $('.rplot, .r-interactiveplot, .rhtmlwidget').each(function() {
20 | var container = $(this).closest('.grid-stack-item-content');
21 | plotSizes.push({
22 | id : $(this).attr('id'),
23 | width : container.data('width'),
24 | height : container.data('height')
25 | });
26 | });
27 |
28 | var dataToSubmit = JSON.stringify({
29 | updatedVariables : variableData,
30 | plotSizes : plotSizes
31 | });
32 |
33 | var rcapLogger = new RcapLogger();
34 | rcapLogger.log('%cJS%c → %cR%c: ' + dataToSubmit, 'color: black; background-color: yellow; font-weight: bold', 'color: black', 'font-weight: bold; color: blue; background-color: #eee', 'color: black');
35 |
36 | window.RCAP.updateControls(dataToSubmit);
37 | }
38 |
39 | }
40 | };
41 |
42 | });
43 |
--------------------------------------------------------------------------------
/man/getControls.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/getControls.R
3 | \name{getControls}
4 | \alias{getControls}
5 | \title{Return a list of all controls}
6 | \usage{
7 | getControls(rcapConfig)
8 | }
9 | \arguments{
10 | \item{rcapConfig}{a list generated by
11 | \code{jsonlite::fromJSON}, with \code{simplifyVector = TRUE}.}
12 | }
13 | \value{
14 | List of controls (each a list itself).
15 | }
16 | \description{
17 | The pages of the dashboard and the controls form a hierarchy,
18 | as controls can have child controls. This parser goes over the
19 | hierarchy recursively, and returns a flat list containing
20 | all controls.
21 | }
22 | \details{
23 | Each list element corresponds to a control, it is a list itself,
24 | with the followinf members:
25 | \itemize{
26 | \item \code{type} see \code{control_classes} for the types.
27 | \item \code{x}, \code{y} position on the grid.
28 | \item \code{width}, \code{height} size on te grid.
29 | \item \code{id} unique identifier, this is used in the protocol.
30 | \item \code{controlProperties} another list, with \code{uid},
31 | code{value} pairs, containing the configuration of the control.
32 | (E.g. labels, associated R variables, or R function, etc.)
33 | \item \code{childControls} if a control has children, they are
34 | recursively included here.
35 | }
36 |
37 | See \preformatted{ system.file("tests", "testthat",
38 | "testConfig.json", package = "rcloud.rcap")
39 | } for an example JSON file describing controls.
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/inst/www/js/versionConverters/versionConverter.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'pubsub', 'site/pubSubTable',
3 | 'text!rcap/js/versionConverters/legacyThemes/att.css',
4 | 'text!rcap/js/versionConverters/legacyThemes/bragi.css'
5 | ], function(PubSub, pubSubTable, themeAtt, themeBragi) {
6 |
7 | 'use strict';
8 |
9 | var VersionConverter = function() {
10 |
11 | var converters = [{
12 | from: undefined,
13 | to: 1.0,
14 | convert: function(json) {
15 | if(['bragi', 'att'].indexOf(json.theme) !== -1) {
16 | PubSub.publish(pubSubTable.updateTheme, json.theme === 'bragi' ? themeBragi : themeAtt);
17 | }
18 | json.theme = undefined;
19 |
20 | return json;
21 | }
22 | },
23 |
24 | // add more converters here:
25 |
26 | ];
27 |
28 | this.processJson = function(json) {
29 |
30 | var convertedJson = json;
31 |
32 | _.each(converters, function(converter) {
33 |
34 | if(_.isUndefined(convertedJson.version) && _.isUndefined(converter.from) ||
35 | convertedJson.version && converter.from && convertedJson.version === converter.from) {
36 | convertedJson = converter.convert(convertedJson);
37 | convertedJson.vesion = converter.to;
38 | }
39 | });
40 |
41 | return convertedJson;
42 | };
43 |
44 | };
45 |
46 | return VersionConverter;
47 |
48 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/interactivePlot.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'rcap/js/ui/properties/textProperty',
3 | 'rcap/js/ui/properties/autocompleteProperty',
4 | 'text!controlTemplates/interactivePlot.tpl',
5 | 'text!controlTemplates/interactivePlot-design.tpl'
6 | ], function(GridControl, TextProperty, AutocompleteProperty, tpl, dtpl) {
7 |
8 | 'use strict';
9 |
10 | var InteractivePlotControl = GridControl.extend({
11 | init: function() {
12 | this._super({
13 | type: 'interactiveplot',
14 | controlCategory: 'Dynamic',
15 | label: 'Interactive Plot',
16 | icon: 'bar-chart',
17 | controlProperties: [
18 | new AutocompleteProperty({
19 | uid: 'code',
20 | label: 'R Function',
21 | helpText: 'R Function for this control.',
22 | isRequired: true
23 | })
24 | ]
25 | });
26 | },
27 | render: function(options) {
28 |
29 | options = options || {};
30 | var isDesignTime = options.isDesignTime || false;
31 |
32 | var template = isDesignTime ? _.template(dtpl) : _.template(tpl);
33 |
34 | return template({
35 | control: this
36 | });
37 |
38 | },
39 | initialiseViewerItems: function() {
40 |
41 | }
42 | });
43 |
44 | return InteractivePlotControl;
45 |
46 | });
47 |
--------------------------------------------------------------------------------
/inst/www/styles/jqModal/jqModal.scss:
--------------------------------------------------------------------------------
1 | /* jqModal base Styling courtesy of;
2 | Brice Burgess */
3 |
4 | /* The Window's CSS z-index value is respected (takes priority). If none is supplied,
5 | the Window's z-index value will be set to 3000 by default (via jqModal.js). */
6 |
7 | .jqmWindow {
8 | display: none;
9 |
10 | position: fixed;
11 | top: 17%;
12 | left: 50%;
13 |
14 | margin-left: -800px;
15 | min-width: 600px;
16 | max-width: 80%;
17 |
18 | background-color: #EEE;
19 | color: #333;
20 | border: 1px solid black;
21 | padding: 12px;
22 |
23 | max-height: calc(100% - 23px);
24 |
25 | @include noselect();
26 | }
27 |
28 | .jqmWindow .body {
29 | max-height: calc(100% - 102px);
30 | overflow: auto;
31 | }
32 |
33 | .jqmOverlay { background-color: #000; }
34 |
35 | /* Background iframe styling for IE6. Prevents ActiveX bleed-through ( form elements, etc.) */
36 | * iframe.jqm {position:absolute;top:0;left:0;z-index:-1;
37 | width: expression(this.parentNode.offsetWidth+'px');
38 | height: expression(this.parentNode.offsetHeight+'px');
39 | }
40 |
41 | /* Fixed posistioning emulation for IE6
42 | Star selector used to hide definition from browsers other than IE6
43 | For valid CSS, use a conditional include instead */
44 | * html .jqmWindow {
45 | position: absolute;
46 | top: expression((document.documentElement.scrollTop || document.body.scrollTop) + Math.round(17 * (document.documentElement.offsetHeight || document.body.clientHeight) / 100) + 'px');
47 | }
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/rangeProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/rangeControl.tpl',
2 | 'ionrangeslider/js/ion.rangeSlider',
3 | 'css!ionrangeslider/css/ion.rangeSlider.css',
4 | 'css!ionrangeslider/css/ion.rangeSlider.skinHTML5.css'
5 | ], function(BaseProperty, tpl) {
6 |
7 | 'use strict';
8 |
9 | var RangeProperty = BaseProperty.extend({
10 | init: function(options) {
11 | options = options || {};
12 | this._super({
13 | type: 'range',
14 | label: options.label || '',
15 | helpText: options.helpText || '',
16 | defaultValue: options.defaultValue || '',
17 | isRequired: options.isRequired || false,
18 | uid: options.uid,
19 | className: options.className,
20 | value: options.value || '0'
21 | });
22 |
23 | // additional assignments go here:
24 | this.minValue = options.minValue || 0;
25 | this.maxValue = options.maxValue || 20;
26 |
27 | this.isHorizontal = _.isUndefined(options.isHorizontal) ? true : options.isHorizontal;
28 | },
29 | render: function(childIndex) {
30 |
31 | var template = _.template(tpl);
32 |
33 | return template({
34 | property: this,
35 | childIndex: childIndex
36 | });
37 |
38 | },
39 | getDialogValue: function() {
40 | return $('#' + this.id).val();
41 | }
42 | });
43 |
44 | return RangeProperty;
45 |
46 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/iframe.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | //'rcap/js/ui/properties/textProperty',
3 | 'rcap/js/ui/properties/autocompleteProperty',
4 | 'rcap/js/ui/properties/dropdownProperty',
5 | 'rcap/js/ui/properties/colorProperty',
6 | 'rcap/js/ui/properties/radioButtonGroupProperty',
7 | 'rcap/js/ui/properties/checkboxListProperty',
8 | 'text!controlTemplates/iframe.tpl'
9 |
10 | ], function(GridControl, AutocompleteProperty, DropdownProperty, ColorProperty, RadioButtonGroupProperty,
11 | CheckboxListProperty, tpl) {
12 |
13 | 'use strict';
14 |
15 | var IFrameControl = GridControl.extend({
16 | init: function() {
17 | this._super({
18 | type: 'iframe',
19 | controlCategory: 'HTML',
20 | label: 'iFrame',
21 | icon: 'cloud',
22 | controlProperties: [
23 | new AutocompleteProperty({
24 | uid: 'source',
25 | label: 'Source',
26 | defaultValue: '',
27 | helpText: 'The URL that the iFrame will show (prefix with http:// or https://), or the R Function that assigns the value',
28 | isRequired: true
29 | })
30 | ]
31 | });
32 | },
33 | render: function() {
34 |
35 | var template = _.template(tpl);
36 |
37 | return template({
38 | control: this
39 | });
40 |
41 | }
42 | });
43 |
44 | return IFrameControl;
45 |
46 | });
--------------------------------------------------------------------------------
/R/showUpdates.R:
--------------------------------------------------------------------------------
1 |
2 | #' @export
3 |
4 | showUpdates <- function(rcapConfigFileName = "rcap_designer.json",
5 | mar = c(0, 7, 0, 5) + 0.2, ...) {
6 |
7 | ## Only run in edit mode, if the proper controller is running,
8 | ## then we are on the dashboard
9 | if (haveController()) return(invisible())
10 |
11 | ## We also need the sankey package
12 | if (!havePackage("sankey")) {
13 | stop("you need the 'sankey' package for update plots")
14 | }
15 |
16 | ## Retrieve the designer config from the notebook
17 | rcapJson <- rcloud.get.asset(name = rcapConfigFileName)
18 |
19 | ## Convert the JSON into a list
20 | rcapConfig <- jsonlite::fromJSON(rcapJson, simplifyVector = FALSE)
21 |
22 | ## Create controller object. This does not do any updates
23 | ## until contacted from the front end, so it is perfect for us
24 | cnt <- Controller$new(rcapConfig)
25 |
26 | ## This is the graph
27 | graph <- cnt$getUpdateGraph()
28 |
29 | ## Create better labels
30 | graph$vertices$label <- with(
31 | graph$vertices,
32 | setGraphLabel(type, variable, func)
33 | )
34 |
35 | ## Create and do the sankey plot
36 | sp <- sankey::make_sankey(graph$vertices, graph$edges, break_edges = TRUE)
37 | sankey::sankey(sp, mar = mar, ...)
38 | }
39 |
40 | setGraphLabel <- function(type, variable, func) {
41 | ifelse(
42 | !is.na(variable) & !is.na(func),
43 | paste0(type, "\n", func, "() → ", variable, " →"),
44 | ifelse(
45 | is.na(variable) & is.na(func),
46 | type,
47 | ifelse(
48 | is.na(variable),
49 | paste0(type, "\n→ ", func, "()"),
50 | paste0(type, "\n", variable, " →")
51 | )))
52 | }
53 |
--------------------------------------------------------------------------------
/R/rcap.user.profile.R:
--------------------------------------------------------------------------------
1 |
2 | is.empty.or.null <- function(x) {
3 | is.null(x) || x == "" || length(x) == 0
4 | }
5 |
6 | #' @export
7 | rcap.getUserProfileValue <- function(var=NULL, val=NULL) {
8 | if(is.empty.or.null(var)) {
9 | return (invisible(NULL))
10 | }
11 | profileVal <- user.profile.store.getValue(var)
12 | if(is.empty.or.null(profileVal)) {
13 | return (val)
14 | }
15 | if(is.empty.or.null(val)) {
16 | return(profileVal)
17 | }
18 | return(intersect(profileVal, val))
19 | }
20 |
21 | user.profile.store.getValue <- function(var) {
22 | json <- rcap.user.profile.store.getValue(var)
23 | if(!is.null(json)) {
24 | return (fromJSON(json, simplifyVector = FALSE))
25 | }
26 | return(NULL);
27 | }
28 |
29 | user.profile.store.setValue <- function(var, value) {
30 | rcap.user.profile.store.setValue(var, value)
31 | return(NULL);
32 | }
33 |
34 | #' @export
35 | rcap.setUserProfileValue <- function(var=NULL, val=NULL) {
36 | if(is.empty.or.null(var)) {
37 | return (invisible(NULL))
38 | }
39 | if(is.empty.or.null(val)) {
40 | user.profile.store.setValue(var, NULL)
41 | return (invisible(NULL))
42 | }
43 | user.profile.store.setValue(var, val)
44 | return (invisible(NULL))
45 | }
46 |
47 | #' @export
48 | rcap.deleteUserProfileValue <- function(var=NULL) {
49 | if(is.empty.or.null(var)) {
50 | return (invisible(NULL))
51 | }
52 | user.profile.store.setValue(var, NULL)
53 | return (invisible(NULL))
54 | }
55 |
56 | #' export
57 | rcap.listUserProfileVariables <- function() {
58 | json <- rcap.user.profile.store.list.variables()
59 | if(!is.null(json)) {
60 | return (fromJSON(json, simplifyVector = FALSE))
61 | }
62 | return(c())
63 | }
64 |
--------------------------------------------------------------------------------
/inst/www/js/ui/messageManager.js:
--------------------------------------------------------------------------------
1 | define(['pubsub', 'site/pubSubTable'], function(PubSub, pubSubTable) {
2 |
3 | 'use strict';
4 |
5 | var MessageManager = function(options) {
6 |
7 | options = options || {};
8 | var messageTimeout = options.messageTimeout || 2000;
9 | var selector = '#rcap-message';
10 |
11 | this.initialise = function() {
12 |
13 | PubSub.subscribe(pubSubTable.showMessage, function(msg, message) {
14 |
15 | //console.info('messageManager: pubSubTable.showMessage');
16 |
17 | // set the text and show for a little while:
18 | $(selector)
19 | .stop() // cancel any previous animation shenanigans
20 | .hide() // and start from a hidden state
21 | .removeClass(message.getValidMessageTypes().join(' ').toLowerCase())
22 | .addClass(message.messageType.toLowerCase())
23 | .text(message.content)
24 | .fadeIn(200, function() {
25 | setTimeout(function() {
26 |
27 | var preMoveTop = $(selector).css('top');
28 |
29 | $(selector).animate({ 'top' : '-=100', 'opacity' : '0' }, 350, function() {
30 | $(this).hide();
31 | $(this).css({
32 | 'top' : preMoveTop,
33 | 'opacity' : '1'
34 | });
35 | });
36 |
37 | }, messageTimeout);
38 | });
39 | });
40 | };
41 | };
42 |
43 | return MessageManager;
44 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/rPrint.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'rcap/js/ui/properties/autocompleteProperty',
3 | 'text!controlTemplates/rPrint.tpl',
4 | 'text!controlTemplates/rPrint-design.tpl'
5 | ], function(GridControl, AutocompleteProperty, tpl, dtpl) {
6 |
7 | 'use strict';
8 |
9 | var RPlotControl = GridControl.extend({
10 | init: function() {
11 | this._super({
12 | type: 'rprint',
13 | controlCategory: 'Dynamic',
14 | label: 'R Print',
15 | icon: 'print',
16 | controlProperties: [
17 | new AutocompleteProperty({
18 | uid: 'code',
19 | label: 'R Function',
20 | helpText: 'R Function for this control.',
21 | isRequired: true
22 | })
23 | ]
24 | });
25 | },
26 | render: function(options) {
27 |
28 | options = options || {};
29 | var isDesignTime = options.isDesignTime || false;
30 | var designTimeDescription = '';
31 |
32 | if(isDesignTime && this.controlProperties[0].value) {
33 | designTimeDescription += 'Function: ' + this.controlProperties[0].value;
34 | }
35 |
36 | var template = isDesignTime ? _.template(dtpl) : _.template(tpl);
37 |
38 | return template({
39 | control: this,
40 | designTimeDescription : designTimeDescription
41 | });
42 |
43 | },
44 | initialiseViewerItems: function() {
45 |
46 | }
47 | });
48 |
49 | return RPlotControl;
50 |
51 |
52 | });
53 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/htmlWidget.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'rcap/js/ui/properties/autocompleteProperty',
3 | 'text!controlTemplates/htmlWidget.tpl',
4 | 'text!controlTemplates/htmlWidget-design.tpl'
5 | ], function(GridControl, AutocompleteProperty, tpl, dtpl) {
6 |
7 | 'use strict';
8 |
9 | var HtmlWidgetControl = GridControl.extend({
10 | init: function() {
11 | this._super({
12 | type: 'htmlwidget',
13 | controlCategory: 'Dynamic',
14 | label: 'HTML Widget',
15 | icon: 'certificate',
16 | controlProperties: [
17 | new AutocompleteProperty({
18 | uid: 'code',
19 | label: 'R Function',
20 | helpText: 'R Function for this control.',
21 | isRequired: true,
22 | horizontal: true
23 | })
24 | ]
25 | });
26 | },
27 | render: function(options) {
28 |
29 | options = options || {};
30 | var isDesignTime = options.isDesignTime || false;
31 | var designTimeDescription = '';
32 |
33 | if(isDesignTime && this.controlProperties[0].value) {
34 | designTimeDescription += 'Function: ' + this.controlProperties[0].value;
35 | }
36 |
37 | var template = isDesignTime ? _.template(dtpl) : _.template(tpl);
38 |
39 | return template({
40 | control: this,
41 | designTimeDescription : designTimeDescription
42 | });
43 |
44 | },
45 | initialiseViewerItems: function() {
46 |
47 | }
48 | });
49 |
50 | return HtmlWidgetControl;
51 |
52 |
53 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/textField.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl', 'rcap/js/ui/properties/textProperty',
2 | 'text!rcap/js/ui/controls/child/templates/textField.tpl'
3 | ], function (BaseControl, TextProperty, tpl) {
4 |
5 | 'use strict';
6 |
7 | var TextFieldControl = BaseControl.extend({
8 | init: function () {
9 | this._super({
10 | type: 'textfield',
11 | label: 'Text Field',
12 | icon: 'check-empty',
13 | controlProperties: [
14 | new TextProperty({
15 | uid: 'label',
16 | label: 'Label',
17 | defaultValue: 'Label',
18 | helpText: 'The label for this control',
19 | isHorizontal: false
20 | }),
21 | new TextProperty({
22 | uid: 'variablename',
23 | label: 'Variable name',
24 | defaultValue: 'variable',
25 | helpText: 'The variable associated with this control',
26 | isRequired: true,
27 | isHorizontal: false
28 | }),
29 | new TextProperty({
30 | uid: 'text',
31 | label: 'Default text',
32 | defaultValue: '',
33 | isHorizontal: false
34 | }),
35 | new TextProperty({
36 | uid: 'controlwidth',
37 | label: 'Width',
38 | defaultValue: '',
39 | helpText: 'Specify as a percentage or pixels (e.g. 100% or 200px)',
40 | isHorizontal: false
41 | })
42 | ]
43 | });
44 | },
45 | render: function () {
46 | var template = _.template(tpl);
47 |
48 | return template({
49 | text: this.getPropertyValueOrDefault('text'),
50 | control: this
51 | });
52 | }
53 | });
54 |
55 | return TextFieldControl;
56 |
57 | });
58 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/rText.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'rcap/js/ui/properties/autocompleteProperty',
3 | 'text!controlTemplates/rText.tpl',
4 | 'text!controlTemplates/rText-design.tpl'
5 | ], function(GridControl, AutocompleteProperty, tpl, dtpl) {
6 |
7 | 'use strict';
8 |
9 | var RTextControl = GridControl.extend({
10 | init: function() {
11 | this._super({
12 | type: 'rtext',
13 | controlCategory: 'Dynamic',
14 | label: 'R Text',
15 | icon: 'edit',
16 | controlProperties: [
17 | new AutocompleteProperty({
18 | uid: 'code',
19 | label: 'R Function',
20 | helpText: 'R Function for this control.',
21 | isRequired: true
22 | })
23 | ]
24 | });
25 | },
26 | render: function(options) {
27 |
28 | options = options || {};
29 | var isDesignTime = options.isDesignTime || false;
30 | var designTimeDescription = '';
31 |
32 | if(isDesignTime && this.controlProperties[0].value) {
33 | designTimeDescription += 'Function: ' + this.controlProperties[0].value;
34 | }
35 |
36 | var template = isDesignTime ? _.template(dtpl) : _.template(tpl);
37 |
38 | return template({
39 | control: this,
40 | designTimeDescription : designTimeDescription
41 | });
42 |
43 | },
44 | initialiseViewerItems: function() {
45 |
46 | },
47 | updateData : function(controlId, data) {
48 | $('#' + controlId).html(data);
49 |
50 | }
51 | });
52 |
53 | return RTextControl;
54 |
55 |
56 | });
57 |
--------------------------------------------------------------------------------
/man/Control.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/controlR6.R
3 | \docType{data}
4 | \name{Control}
5 | \alias{Control}
6 | \title{Abstract class for controls}
7 | \format{An object of class \code{R6ClassGenerator} of length 24.}
8 | \usage{
9 | Control
10 | }
11 | \description{
12 | Abstract class for controls
13 | }
14 | \section{Methods}{
15 |
16 |
17 | \code{initialize(cl)} Initialization from the parsed JSON
18 | control descriptions, from \code{\link{getControls}}.
19 |
20 | \code{getId()} get the controls id. All controls should have a
21 | unique id.
22 |
23 | \code{getVariableName()} get name of associated global variable.
24 | If there is no such variable, then \code{NULL} is returned.
25 |
26 | \code{setVariable(new_value = NULL)} set an R variable
27 | of a control to the specified value, coming from a
28 | front-end update.
29 |
30 | \code{update()} method to perform an update.
31 | This method is called when an update is requested from the
32 | frontend, and also when the dashboard page is built up the
33 | first time. It is also called when the control depends on
34 | another control that was changed in the frontend.
35 |
36 | \code{dependentVariables(clientVars, envir = rcloudEnv())}
37 | find all variables the update function of the control
38 | depends on, in the rcloud environment by default.
39 | }
40 |
41 | \section{Private variables}{
42 |
43 |
44 | \code{id} the control id.
45 |
46 | \code{type} the control type, see \code{\link{control_classes}}
47 | for the list of control types.
48 |
49 | \code{json} the original (parsed) JSON configuration of the control.
50 |
51 | \code{controlFunction} the function to run to update the
52 | back-end side representation of the control.
53 |
54 | \code{varibaleName} name of the associated R varible, in the
55 | rcloud environment (i.e. the notebook environment).
56 | }
57 | \keyword{datasets}
58 |
59 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/templates/dateRange.tpl:
--------------------------------------------------------------------------------
1 | <%
2 | if(typeof control.controlProperties[0].value !== 'undefined' && control.controlProperties[0].value.length > 0) {
3 | %>
4 |
5 | <%=control.controlProperties[0].value%>
6 |
7 | <% } %>
8 |
9 |
11 |
12 |
13 |
14 | <% if(control.getPropertyValue('intervalType') != '') { %>
15 |
16 | plus
17 |
18 | <%=control.singularInterval()%>
19 |
20 |
38 |
39 | <% } else { %>
40 | to
41 | <% } %>
42 |
43 |
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/templates/viewerDataUpload.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dataset Subject
4 | (Please only use the following characters: letters, digits, hyphens and underscores)
5 |
6 |
7 |
12 |
13 |
14 |
15 | Description
16 |
17 |
18 |
23 |
24 |
25 |
26 | File
27 | (Please only use the following characters: letters, digits, spaces, hyphens and underscores)
28 |
29 |
30 |
--------------------------------------------------------------------------------
/inst/www/js/utils/historyManager.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'rcap/js/utils/rcapLogger',
3 | 'pubsub',
4 | 'site/pubSubTable',
5 | 'text!rcap/partials/_404.htm'
6 | ], function(RcapLogger, PubSub, pubSubTable, pageNotFoundPartial) {
7 |
8 | 'use strict';
9 |
10 | var rcapLogger = new RcapLogger();
11 |
12 | var HistoryManager = function() {
13 |
14 | var pageNotFoundSelector = '#viewer-404';
15 |
16 | this.initialise = function() {
17 |
18 | // append the '404':
19 | $('#inner-stage').append('
');
20 |
21 | window.addEventListener('popstate', function( /*e*/ ) {
22 | rcapLogger.log('history manager: popstate');
23 | });
24 |
25 | window.onhashchange = function() {
26 |
27 | // assume that this will be found:
28 | $(pageNotFoundSelector).hide();
29 |
30 | PubSub.publish(pubSubTable.changeSelectedPageByTitle, window.unescape(location.hash.substring(1)));
31 | };
32 |
33 | PubSub.subscribe(pubSubTable.show404, function(msg, data) {
34 | var template = _.template(pageNotFoundPartial);
35 | $(pageNotFoundSelector).html(template({
36 | pages : data.site.pages,
37 | requestedPage : data.requestedPage
38 | })).show();
39 | });
40 |
41 | };
42 |
43 | this.setInitialState = function() {
44 | if (location.hash.length) {
45 | // show the specific 'page':
46 | PubSub.publish(pubSubTable.changeSelectedPageByTitle, window.unescape(location.hash.substring(1)));
47 | } else {
48 | // the first is as good as any:
49 | PubSub.publish(pubSubTable.viewerShowFirstPage);
50 | }
51 | };
52 |
53 | };
54 |
55 | return HistoryManager;
56 |
57 | });
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/templates/viewerProfileVariables.tpl:
--------------------------------------------------------------------------------
1 |
2 | <% if(hasStaleItem) { %>
3 |
4 | <% _.each(profileDataItems, function(o, i){ %>
5 | <% if(o.staleValues.length) { %>
6 |
7 | Your saved selection (<% _.each(o.staleValues, function(staleValue) { %>
8 | <%=staleValue%>
9 | <% }); %>) for variable '<%=o.description%>' <%= (o.allStale) ? ' was not found in the currently available values.' : ' has some values that are no longer current.' %>
10 |
11 | <% } %>
12 | <% }); %>
13 |
14 | <% } %>
15 |
16 |
17 |
18 |
19 | Variable
20 | Selection method
21 | Values
22 |
23 |
24 |
25 | <% _.each(profileDataItems, function(o, i){ %>
26 |
27 | <%=o.description%>
28 |
29 |
30 | >All values
31 | >Selection
32 |
33 |
34 |
35 | ">All
36 | >
37 |
38 | <% _.each(o.options, function(option, i) { %>
39 | ><%=option.value%>
40 | <% }); %>
41 |
42 |
43 |
44 |
45 |
46 | <% }); %>
47 |
48 |
49 |
--------------------------------------------------------------------------------
/inst/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "RCAP",
3 | "version": "0.0.0",
4 | "description": "RCAP for RCloud",
5 | "keywords": [
6 | "rcloud",
7 | "r"
8 | ],
9 | "authors": [
10 | "Shane Porter",
11 | "Douglas Ashton"
12 | ],
13 | "license": "MIT",
14 | "ignore": [
15 | "**/.*",
16 | "node_modules",
17 | "bower_components",
18 | "test",
19 | "tests"
20 | ],
21 | "dependencies": {
22 | "requirejs-plugins": "~1.0.3",
23 | "requirejs-text": "~2.0.14",
24 | "select2": "~4.0.0",
25 | "spectrum": "~1.8",
26 | "ionrangeslider": "~2.1.2",
27 | "datatables.net": "~1.10.10",
28 | "datatables.net-buttons": "~1.2.1",
29 | "datatables.net-buttons-dt": "~1.2.1",
30 | "jquery.sparkline": "~2.1.2",
31 | "datatables.net-fixedheader": "~3.1.2",
32 | "datatables.net-fixedheader-dt": "~3.1.2",
33 | "pubsub-js": "~1.5.2",
34 | "parsleyjs": "~2.7.2",
35 | "jquery.hotkeys": "*",
36 | "require-css": "~0.1.8"
37 | },
38 | "overrides": {
39 | "jquery.sparkline": {
40 | "main": "dist/jquery.sparkline.min.js"
41 | },
42 | "parsleyjs": {
43 | "main": "dist/parsley.min.js"
44 | },
45 | "datatables.net": {
46 | "main": ["js/jquery.dataTables.min.js",
47 | "js/jquery.dataTables.js"
48 | ]
49 | },
50 | "datatables.net-buttons": {
51 | "main": ["js/dataTables.buttons.js",
52 | "js/buttons.colVis.js",
53 | "js/buttons.flash.js",
54 | "js/buttons.html5.min.js",
55 | "js/buttons.print.js"
56 | ]
57 | },
58 | "select2": {
59 | "main": [
60 | "dist/js/select2.js", "dist/css/select2.min.css"
61 | ]
62 | },
63 | "ionrangeslider": {
64 | "main": [
65 | "js/ion.rangeSlider.js",
66 | "css/ion.rangeSlider.css",
67 | "css/ion.rangeSlider.skinFlat.css",
68 | "css/ion.rangeSlider.skinHTML5.css",
69 | "img/sprite-skin-flat.png"
70 | ]
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/templates/dataTable.tpl:
--------------------------------------------------------------------------------
1 |
3 |
4 | <%if(designTimeDescription.length && isDesignTime) {%>
5 | <%=designTimeDescription%>
6 | <%}%>
7 |
8 | <% if(isDesignTime) { %>
9 |
30 | <% } %>
31 |
32 |
44 |
--------------------------------------------------------------------------------
/R/rcap.messageWidget.R:
--------------------------------------------------------------------------------
1 | #' @title Write message to message widget with specified id
2 | #'
3 | #' @param variableName the name of the variable linked with message widget control
4 | #' @param message the message that should be displayed
5 | #' @param append should the message be appended
6 | #' @return NULL invisibly
7 | #' @export
8 | rcap.messageWidget.write <- function(variableName, message, append=FALSE) {
9 | if(haveController()) {
10 | cnt <- get("rcapController", envir = rcapEnv)
11 | control <- Filter(function(x) {x$getVariableName()==variableName}, cnt$getControls())
12 | if(length(control)!=1) {
13 | stop(paste0("Control for variable '", variableName, "' not found!"));
14 | }
15 | control <- control[[1]]
16 | event <- list("eventType" = "MessageWidgetWrite",
17 | "controlId" = control$getId(),
18 | "data" = list("append" = append, "message" = message)
19 | )
20 | response <- rcap.events.send(event)
21 | if(response$status != 'Success') {
22 | warning(paste0("Event processing failed ", response$msg))
23 | }
24 | } else {
25 | warning("Writting to message widget is only available in dashboard view.")
26 | }
27 | invisible(NULL)
28 | }
29 |
30 | #' @title Write message to a collection of Message widgets
31 | #'
32 | #' @param msg named list of messages, with keys being Message widget variableNames
33 | #' @param append flag specifying if the messages should be appended to widgets' content or not
34 | #' @param ... named parameters, if 'msg' is not defined, these specify progress spinners and messages that should be written.
35 | #' @return NULL invisibly
36 | #' @export
37 | rcap.messageWidget.msg <- function(msg=NULL, append=FALSE, ...) {
38 | parms <- list(...)
39 | if(is.null(msg) && length(parms) >0 ) {
40 | msg <- parms
41 | }
42 | if( length(msg) > 0 ) {
43 | msg <- as.list(msg)
44 | for(p in 1:length(msg)) {
45 | if(!is.na(names(msg)[[p]])) {
46 | rcloud.rcap:::rcap.messageWidget.write(names(msg)[[p]], msg[[p]], append = append)
47 | }
48 | }
49 | }
50 | invisible(NULL)
51 | }
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/actionButton.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'rcap/js/ui/properties/textProperty',
3 | 'utils/variableHandler',
4 | 'text!controlTemplates/actionButton.tpl'
5 | ], function(GridControl, TextProperty, variableHandler, tpl) {
6 |
7 | 'use strict';
8 |
9 | var RPlotControl = GridControl.extend({
10 | init: function() {
11 | this._super({
12 | type: 'actionbutton',
13 | controlCategory: 'Dynamic',
14 | label: 'Action Button',
15 | icon: 'exclamation-sign',
16 | initialSize: [2, 2],
17 | controlProperties: [
18 | new TextProperty({
19 | uid: 'variablename',
20 | label: 'Variable',
21 | helpText: 'The variable associated with this control',
22 | isRequired: true
23 | }),
24 | new TextProperty({
25 | uid: 'buttonText',
26 | label : 'Button Text',
27 | defaultValue : '',
28 | helpText : 'The text that appears on the button',
29 | isRequired: true
30 | })
31 | ]
32 | });
33 | },
34 | getVariableData: function() {
35 |
36 | },
37 | render: function() {
38 |
39 | var template = _.template(tpl);
40 |
41 | return template({
42 | control: this
43 | });
44 |
45 | },
46 | initialiseViewerItems: function() {
47 |
48 | $('[data-controltype="actionbutton"]').click(function() {
49 | variableHandler.submitChange({
50 | variableName: $(this).attr('data-variablename'),
51 | controlId: $(this).attr('id'),
52 | value: Math.random().toString(16).slice(2).substring(0, 6)
53 | });
54 | });
55 | }
56 | });
57 |
58 | return RPlotControl;
59 |
60 |
61 | });
62 |
--------------------------------------------------------------------------------
/inst/www/js/utils/pageWalker.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 |
3 | 'use strict';
4 |
5 | return function(pages) {
6 |
7 | this.findPage = function(pageId) {
8 | return _.findWhere(pages, {
9 | id: pageId
10 | });
11 | };
12 |
13 | this.getDescendantsAndSelf = function(rootPageId) {
14 |
15 | var traversedPages = [];
16 |
17 | var walkPages = function(subsetOfPages) {
18 |
19 | _.each(subsetOfPages, function(p) {
20 |
21 | traversedPages.push(p);
22 |
23 | var childPages = _.filter(pages, function(sp) {
24 | return sp.parentId === p.id;
25 | });
26 |
27 | if (childPages.length > 0) {
28 | walkPages(childPages);
29 | }
30 | });
31 | };
32 |
33 | walkPages(_.filter(pages, function(p) {
34 | return rootPageId ? p.id === rootPageId : !p.parentId;
35 | }));
36 |
37 | return traversedPages;
38 |
39 | };
40 |
41 | this.getAncestorsAndSelf = function(pageId) {
42 |
43 | var foundPage, treeItems = [];
44 |
45 | do {
46 | foundPage = _.findWhere(pages, {
47 | id: pageId
48 | });
49 | pageId = foundPage.parentId;
50 |
51 | treeItems.unshift(foundPage);
52 |
53 | } while (foundPage && pageId);
54 |
55 | return treeItems;
56 | };
57 |
58 | this.removePage = function(pageId) {
59 |
60 | var pageIds = _.pluck(this.getDescendantsAndSelf(pageId), 'id');
61 |
62 | return _.filter(pages, function(p) {
63 | return pageIds.indexOf(p.id) === -1;
64 | });
65 | };
66 |
67 | this.setPageEnabledStatus = function(pageId, isEnabled) {
68 |
69 | _.each(this.getDescendantsAndSelf(), function(p) {
70 | p.isEnabled = isEnabled;
71 | });
72 |
73 | };
74 |
75 | };
76 |
77 | });
78 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/heading.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl', 'rcap/js/ui/properties/textProperty',
2 | 'rcap/js/ui/properties/dropdownProperty',
3 | 'text!rcap/js/ui/controls/child/templates/heading.tpl'], function(BaseControl, TextProperty, DropdownProperty, tpl) {
4 |
5 | 'use strict';
6 |
7 | var HeadingControl = BaseControl.extend({
8 | init: function() {
9 | this._super({
10 | type: 'heading',
11 | label: 'Heading',
12 | icon: 'font',
13 | controlProperties: [
14 | new TextProperty({
15 | uid: 'text',
16 | label: 'Text',
17 | defaultValue: 'Heading',
18 | isHorizontal: false
19 | }),
20 | new DropdownProperty({
21 | uid: 'testdropdown',
22 | label: 'Heading type',
23 | helpText: 'Heading size',
24 | isRequired: true,
25 | availableOptions: [{
26 | text: 'Largest',
27 | value: 'h1'
28 | }, {
29 | text: 'Large',
30 | value: 'h2'
31 | }, {
32 | text: 'Medium',
33 | value: 'h3'
34 | }, {
35 | text: 'Small',
36 | value: 'h4'
37 | }, {
38 | text: 'Smallest',
39 | value: 'h5'
40 | }],
41 | value: 'h1', // default to the largest 'h1'
42 | isHorizontal: false
43 | })
44 | ]
45 | });
46 | },
47 | render: function() {
48 | var template = _.template(tpl);
49 |
50 | return template({
51 | control: this
52 | });
53 | }
54 | });
55 |
56 | return HeadingControl;
57 |
58 | });
59 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/wysiwyg.tpl:
--------------------------------------------------------------------------------
1 |
48 |
49 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/colorControl.tpl:
--------------------------------------------------------------------------------
1 | <%if(property.isHorizontal) { %>
2 |
3 |
4 |
5 | <%=property.label%>
6 |
7 |
8 |
9 |
<%=property.helpText%>
10 |
26 |
27 |
28 |
29 | <% } else { %>
30 |
31 |
54 |
55 | <% } %>
56 |
--------------------------------------------------------------------------------
/inst/www/js/site/siteSettings.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/textProperty', 'rcap/js/ui/properties/dropdownProperty'], function(TextProperty, DropdownProperty) {
2 |
3 | 'use strict';
4 |
5 | var SiteSettings = Class.extend({
6 | init: function() {
7 | this.properties = [
8 | new DropdownProperty({
9 | uid: 'gridControlPadding',
10 | label: 'Grid Control Padding',
11 | isRequired: false,
12 | availableOptions: _.map([0, 5, 10, 20], function(val) { return {
13 | text: val.toString(),
14 | value: val.toString()
15 | };
16 | }),
17 | value: '20',
18 | helpText: 'The amount of padding around each control (in pixels)'
19 | }),
20 | new TextProperty({
21 | uid: 'pageClass',
22 | label : 'Page class',
23 | defaultValue : '',
24 | helpText : 'Apply a CSS class to each page',
25 | isRequired: false,
26 | }),
27 | new DropdownProperty({
28 | uid: 'siteThemePackage',
29 | label: 'Site Theme Package',
30 | isRequired: false,
31 | availableOptions: window.RCAP.getRCAPStyles ? window.RCAP.getRCAPStyles().map(function(style) {
32 | return {
33 | text: style.package,
34 | value: style.package
35 | };
36 | }) : [],
37 | helpText: 'Custom theme'
38 | })
39 | ];
40 | },
41 | getSettingValue: function(uid) {
42 | return _.findWhere(this.properties, {
43 | uid: uid
44 | }).value;
45 | },
46 | extract: function() {
47 | var obj = {};
48 |
49 | this.properties.forEach(function(prop) {
50 | obj[prop.uid] = prop.value;
51 | });
52 |
53 | return obj;
54 | }
55 | });
56 |
57 | return SiteSettings;
58 |
59 | });
60 |
--------------------------------------------------------------------------------
/tests/testthat/testConfig.json:
--------------------------------------------------------------------------------
1 | {"saveTicks":1445253670794,"pages":[{"depth":1,"id":"rcapda189c91","navigationTitle":"Home","isEnabled":true,"controls":[{"type":"form","x":0,"y":1,"width":4,"height":3,"id":"rcapd77d04dd","controlProperties":[],"childControls":[{"type":"datepicker","id":"rcap16014ed1","controlProperties":[{"uid":"label","value":"Start Date","id":"ctrltext03c6f82b"},{"uid":"variablename","value":"datePicker1","id":"ctrltextff6451db"}]},{"type":"datepicker","id":"rcapc43838c4","controlProperties":[{"uid":"label","value":"End Date","id":"ctrltext00b111e6"},{"uid":"variablename","value":"datePicker2","id":"ctrltextb81ce3cc"}]},{"type":"separator","id":"rcapd2b608e4","controlProperties":[]},{"type":"checkboxlist","id":"rcap1cc91a8e","controlProperties":[{"uid":"description","value":"Some Options","id":"ctrltext842f058a"},{"uid":"variablename","value":"option1","id":"ctrltexte02aea9e"},{"uid":"options","value":[{"label":"Option 1","value":""},{"label":"Option 2","value":""}],"id":"ctrlmultioptionf2691ded"}]}]},{"type":"rplot","x":4,"y":1,"width":5,"height":4,"id":"rcap630974bf","controlProperties":[{"uid":"code","value":"makePlot1","id":"ctrlmultilinetext4039fea7"}],"isOnGrid":true},{"type":"image","x":0,"y":4,"width":4,"height":3,"id":"rcap08ca0d2f","controlProperties":[{"uid":"imagesource","value":"http://www.dougashton.net/pics/profpic.jpg","id":"ctrltext6f623218"},{"uid":"imageLayout","value":"background-size: cover;","id":"ctrldropdowne3054be5"}],"isOnGrid":true}]},{"depth":1,"id":"rcap961dec28","navigationTitle":"Second Page","isEnabled":true,"controls":[{"type":"rplot","x":0,"y":1,"width":6,"height":4,"id":"rcapcea65234","controlProperties":[{"uid":"code","value":"makePlot2","id":"ctrlmultilinetext2f3c4efc"}],"isOnGrid":true}]},{"depth":2,"id":"rcap2282b1ae","parentId":"rcap961dec28","navigationTitle":"Child of Second Page","isEnabled":true,"controls":[{"type":"rplot","x":0,"y":1,"width":5,"height":4,"id":"rcapc4281584","controlProperties":[{"uid":"code","value":"makePlotChild2","id":"ctrlmultilinetext4255d1a5"}],"isOnGrid":true},{"type":"form","x":5,"y":1,"width":5,"height":4,"id":"rcap6d1badca","controlProperties":[],"childControls":[{"type":"datepicker","id":"rcapa9b893f5","controlProperties":[{"uid":"label","value":"Third Date","id":"ctrltext6c484784"},{"uid":"variablename","value":"datePicker3","id":"ctrltext53419aee"}]}]}]}]}
2 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/templates/multiOptionControl.tpl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inst/www/js/ui/dialogUtils.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/vendor/jqModal.min'], function () {
2 |
3 | 'use strict';
4 |
5 | var DialogUtils = function() {
6 | this.initialise = function () {
7 |
8 | var sizeModalBodyHeight = function (modal) {
9 |
10 | var availableHeight = $(/*document*/window).height() - 165;
11 | var maxHeight = modal.find('.body').data('maxheight');
12 |
13 | var $modalBody = modal.find('.body');
14 |
15 | if (!maxHeight) {
16 | var initialHeight = modal.find('.body').height();
17 |
18 | if (initialHeight > availableHeight) {
19 | $modalBody.height(availableHeight + 'px');
20 | } else {
21 | $modalBody.height(initialHeight + 'px');
22 | }
23 |
24 | modal.find('.body').data('maxheight', initialHeight);
25 |
26 | } else {
27 |
28 | if (maxHeight === 'useavailable') {
29 | $modalBody.height(availableHeight + 'px');
30 | } else {
31 | if (availableHeight > maxHeight) {
32 | $modalBody.height(maxHeight + 'px');
33 | } else {
34 | $modalBody.height(availableHeight + 'px');
35 | }
36 | }
37 | }
38 | };
39 |
40 | // initialise each of the dialogs:
41 | $('.jqmWindow').each(function () {
42 | $(this).jqm({
43 | modal: true,
44 | onShow: function (hash) {
45 |
46 | // display the overlay (prepend to body) if not disabled
47 | if (hash.c.overlay > 0) {
48 | hash.o.prependTo('body');
49 | }
50 |
51 | // make modal visible
52 | hash.w.show();
53 |
54 | // call focusFunc (attempts to focus on first input in modal)
55 | $.jqm.focusFunc(hash.w, null);
56 |
57 | sizeModalBodyHeight(hash.w);
58 |
59 | return true;
60 | },
61 | onHide: function (hash) {
62 |
63 | // hide modal and if overlay, remove overlay.
64 | hash.w.hide();
65 | hash.o.remove();
66 |
67 | hash.w.find('body').removeData('maxheight');
68 |
69 | return true;
70 | }
71 | });
72 | });
73 |
74 | $(window).resize(function () {
75 | sizeModalBodyHeight($('.jqmWindow:visible'));
76 | });
77 | };
78 | };
79 |
80 | return DialogUtils;
81 | });
82 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/dropdown.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl', 'rcap/js/ui/properties/textProperty',
2 | 'rcap/js/ui/properties/multiOptionProperty', 'rcap/js/ui/properties/dropdownProperty', 'text!rcap/js/ui/controls/child/templates/dropdown.tpl'],
3 | function(BaseControl, TextProperty, MultiOptionProperty, DropdownProperty, tpl) {
4 |
5 | 'use strict';
6 |
7 | var DropdownControl = BaseControl.extend({
8 | init: function() {
9 | this._super({
10 | type : 'dropdown',
11 | label : 'Dropdown',
12 | icon: 'list',
13 | controlProperties: [
14 | new TextProperty({
15 | uid: 'label',
16 | label : 'Label',
17 | defaultValue : 'Label',
18 | helpText : 'The label for this control',
19 | isHorizontal: false
20 | }),
21 | new TextProperty({
22 | uid: 'variablename',
23 | label : 'Variable name',
24 | defaultValue : 'variable',
25 | helpText : 'The variable associated with this control',
26 | isRequired: true,
27 | isHorizontal: false
28 | }),
29 | // options:
30 | new MultiOptionProperty({
31 | uid: 'options',
32 | label: 'Options',
33 | helpText: 'Enter options, one per line',
34 | value: [{
35 | label: 'Option 1',
36 | value: '1'
37 | }, {
38 | label: 'Option 2',
39 | value: '2'
40 | }],
41 | isRequired: true,
42 | isHorizontal: false
43 | }),
44 | // selection style (default or dialog)
45 | new DropdownProperty({
46 | uid: 'selectionStyle',
47 | label: 'Selection style',
48 | helpText: 'Use default style or show options in a dialog',
49 | isRequired: false,
50 | availableOptions: [{
51 | text: 'Dialog',
52 | value: 'dialog'
53 | }],
54 | defaultOptionText: 'Default',
55 | isHorizontal: false
56 | }),
57 | ]
58 | });
59 | },
60 | render: function(options) {
61 |
62 | options = options || {};
63 |
64 | var template = _.template(tpl);
65 |
66 | return template({
67 | control: this,
68 | isDesignTime: options.isDesignTime || false
69 | });
70 |
71 | }
72 | });
73 |
74 | return DropdownControl;
75 |
76 | });
77 |
--------------------------------------------------------------------------------
/tests/testthat/test-topo-sort.R:
--------------------------------------------------------------------------------
1 |
2 | context("Topological sorting")
3 |
4 | test_that("toplogical sorting works", {
5 |
6 | G <- list(
7 | "7" = c("11", "8"),
8 | "5" = "11",
9 | "3" = c("8", "10"),
10 | "11" = c("2", "9", "10"),
11 | "8" = "9",
12 | "2" = character(),
13 | "9" = character(),
14 | "10" = character()
15 | )
16 |
17 | topo <- topologicalSort(G)
18 |
19 | expect_true(match("7", topo) < match("11", topo))
20 | expect_true(match("7", topo) < match("8", topo))
21 | expect_true(match("5", topo) < match("11", topo))
22 | expect_true(match("3", topo) < match("8", topo))
23 | expect_true(match("3", topo) < match("10", topo))
24 | expect_true(match("11", topo) < match("2", topo))
25 | expect_true(match("11", topo) < match("9", topo))
26 | expect_true(match("11", topo) < match("10", topo))
27 | expect_true(match("8", topo) < match("9", topo))
28 |
29 | })
30 |
31 | test_that("topological sorting works on sparse graphs", {
32 |
33 | G <- list(
34 | "a" = "b",
35 | "b" = character(),
36 | "c" = "d",
37 | "d" = character(),
38 | "e" = "f",
39 | "f" = character()
40 | )
41 |
42 | topo <-topologicalSort(G)
43 |
44 | expect_true(match("a", topo) < match("b", topo))
45 | expect_true(match("c", topo) < match("d", topo))
46 | expect_true(match("e", topo) < match("f", topo))
47 |
48 | topo2 <- topologicalSort(
49 | list("a" = "b", "b" = "c", "c" = "d", "d" = "e", "e" = character())
50 | )
51 |
52 | expect_equal(topo2, c("a", "b", "c", "d", "e"))
53 |
54 | topo3 <- topologicalSort(list("a" = character(), "b" = character()))
55 |
56 | expect_equal(sort(topo3), c("a", "b"))
57 |
58 | })
59 |
60 | test_that("twistAdjlist works", {
61 |
62 | G1 <- list(
63 | "7" = c("11", "8"),
64 | "5" = "11",
65 | "3" = c("8", "10"),
66 | "11" = c("2", "9", "10"),
67 | "8" = "9",
68 | "2" = character(),
69 | "9" = character(),
70 | "10" = character()
71 | )
72 |
73 | G11 <- twistAdjlist(G1)
74 |
75 | expect_equal(names(G11), names(G1))
76 | expect_equal(
77 | G11,
78 | list(
79 | "7" = character(),
80 | "5" = character(),
81 | "3" = character(),
82 | "11" = c("7", "5"),
83 | "8" = c("7", "3"),
84 | "2" = "11",
85 | "9" = c("11", "8"),
86 | "10" = c("3", "11")
87 | )
88 | )
89 |
90 | G111 <- twistAdjlist(G11)
91 | expect_equal(G1, G111)
92 | })
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # RCAP
3 |
4 | ## Introduction
5 |
6 | RCAP is an Interactive Dashboard Builder extension for [RCloud](https://github.com/att/rcloud#readme).
7 | An RCAP dashboard is an RCloud asset associated with an RCloud notebook. Use RCAP to create and edit
8 | the dashboard, and `rcap.html` mode to view and share it.
9 |
10 | [](http://www.youtube.com/watch?v=h9ErbyvD_FA)
11 |
12 | ## Building
13 |
14 | Build has the following environment dependencies:
15 |
16 | * `node.js` & `npm`, `bower`,
17 | * `grunt` and `GNU make`.
18 |
19 | To build RCAP package run the following command from package source:
20 |
21 |
22 | git clone https://github.com/att/rcloud.rcap
23 | cd rcloud.rcap
24 | sh ./mkdist
25 |
26 | The 'mkdist' script accepts a number of optional parameters useful during development:
27 |
28 | ```sh
29 | Usage: ./mkdist [{--no-npm | --no-js | --no-clean > | --help}] [install]
30 | --no-clean - skips clean phase
31 | --no-npm - skips npm processing step (implies --no-clean option)
32 | --no-js - skips entire JavaScript processing step (implies --no-npm option)
33 | --help - displays usage information
34 |
35 | --install - should package be installed after it has been built.
36 | ```
37 |
38 |
39 | ## Installation
40 |
41 | ### RCAP bundle
42 |
43 | It is possible to install RCAP from R package bundle, which contains all JS dependencies.
44 |
45 | ```sh
46 | wget 'https://github.com/att/rcloud.rcap/releases/download/0.4.7.1/rcloud.rcap_0.4.7.1.tar.gz'
47 | R CMD INSTALL rcloud.rcap_0.4.7.1.tar.gz
48 | ```
49 |
50 |
51 | ### devtools
52 |
53 | To install the latest released build, you can use the `devtools` package:
54 | ```r
55 | devtools::install_url(
56 | "https://github.com/att/rcloud.rcap/releases/download/0.4.7.1/rcloud.rcap_0.4.7.1.tar.gz"
57 | )
58 | ```
59 | You can also run this from within an RCloud notebook, assuming you have
60 | access rights to install R packages on the RCloud server.
61 |
62 | To install the development version, use
63 | ```r
64 | devtools::install_github("att/rcloud.rcap@develop", local = FALSE)
65 | ```
66 |
67 | ## Configuration
68 |
69 | After installing the R package, you can enable RCAP in RCloud in the
70 | `Settings` menu (on the bottom left). Add `rcloud.rcap` to the
71 | `Enable Extensions` line, and reload the notebook.
72 |
73 | You can start the designer from the `Advanced` menu.
74 |
75 | ## License
76 |
77 | MIT @ AT&T
78 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/checkboxList.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl',
2 | 'rcap/js/ui/properties/textProperty',
3 | 'rcap/js/ui/properties/multiOptionProperty',
4 | 'text!rcap/js/ui/controls/child/templates/checkboxList.tpl'
5 | ], function(BaseControl, TextProperty, MultiOptionProperty, tpl) {
6 |
7 | 'use strict';
8 |
9 | var CheckboxListControl = BaseControl.extend({
10 | init: function() {
11 |
12 | this._super({
13 | type : 'checkboxlist',
14 | label : 'Checkbox Group',
15 | icon: 'check',
16 | controlProperties: [
17 | new TextProperty({
18 | uid: 'description',
19 | label: 'Description',
20 | defaultValue: 'Description',
21 | helpText: 'Instructions / help text for this control',
22 | isHorizontal: false
23 | }),
24 | new TextProperty({
25 | uid: 'variablename',
26 | label : 'Variable name',
27 | defaultValue : 'variable',
28 | helpText : 'The variable associated with this control',
29 | isRequired: true,
30 | isHorizontal: false
31 | }),
32 | // options:
33 | new MultiOptionProperty({
34 | uid: 'options',
35 | label: 'Options',
36 | helpText: 'Enter options, one per line',
37 | value: [{
38 | label: 'Option 1',
39 | value: '1'
40 | }, {
41 | label: 'Option 2',
42 | value: '2'
43 | }],
44 | isRequired: true,
45 | isHorizontal: false
46 | })
47 | ]
48 | });
49 | },
50 | render: function(options) {
51 |
52 | options = options || {};
53 |
54 | var template = _.template(tpl);
55 |
56 | return template({
57 | control: this,
58 | isDesignTime: options.isDesignTime || false
59 | });
60 | }
61 |
62 | });
63 |
64 | return CheckboxListControl;
65 |
66 | });
67 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/dataUpload.js:
--------------------------------------------------------------------------------
1 | define(['pubsub',
2 | 'site/pubSubTable',
3 | 'rcap/js/ui/controls/gridControl',
4 | 'rcap/js/ui/properties/textProperty',
5 | 'rcap/js/ui/properties/stringValueProperty',
6 | 'utils/variableHandler',
7 | 'text!controlTemplates/dataUpload.tpl'
8 | ], function (PubSub, pubSubTable, GridControl, TextProperty, StringValueProperty, variableHandler, tpl) {
9 |
10 | 'use strict';
11 |
12 | var DataUploadControl = GridControl.extend({
13 | init: function () {
14 | this._super({
15 | type: 'dataupload',
16 | controlCategory: 'Dynamic',
17 | label: 'Data Upload',
18 | icon: 'cloud-upload',
19 | initialSize: [2, 2],
20 | controlProperties: [
21 | new TextProperty({
22 | uid: 'variablename',
23 | label: 'Variable',
24 | helpText: 'The variable associated with this data upload',
25 | isRequired: true
26 | }),
27 | new TextProperty({
28 | uid: 'allowedtypes',
29 | label: 'Allowed types',
30 | helpText: 'List of allowed file types, comma-separated, e.g. csv,tsv. Leave blank for "all"',
31 | isRequired: false
32 | }),
33 | new TextProperty({
34 | uid: 'buttontext',
35 | label: 'Button Text',
36 | defaultValue: '',
37 | helpText: 'The text that appears on the button',
38 | isRequired: true
39 | }),
40 | new StringValueProperty({
41 | uid: 'path',
42 | label: 'Save path',
43 | defaultValue: '',
44 | helpText: 'The file path under which uploaded files will be saved',
45 | codeHelpText: 'The R function that returns the path under which uploaded files will be saved',
46 | isRequired: true
47 | })
48 | ]
49 | });
50 | },
51 | getVariableData: function () {
52 |
53 | },
54 | render: function () {
55 |
56 | var template = _.template(tpl);
57 |
58 | return template({
59 | control: this
60 | });
61 |
62 | },
63 | initialiseViewerItems: function () {
64 | $('[data-controltype="dataupload"]').click(function () {
65 | var params = $(this).data();
66 | params.controlId = this.id;
67 | PubSub.publish(pubSubTable.showDataUploadDialog, params);
68 | });
69 | }
70 | });
71 |
72 | return DataUploadControl;
73 |
74 |
75 | });
76 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/radioButtonGroup.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl',
2 | 'rcap/js/ui/properties/textProperty',
3 | 'rcap/js/ui/properties/multiOptionProperty',
4 | 'text!rcap/js/ui/controls/child/templates/radioButtonGroup.tpl'
5 | ], function(BaseControl, TextProperty, MultiOptionProperty, tpl) {
6 |
7 | 'use strict';
8 |
9 | var RadioButtonGroupControl = BaseControl.extend({
10 | init: function() {
11 |
12 | this._super({
13 | type: 'radiobuttongroup',
14 | label: 'Radio Button Group',
15 | icon: 'circle-blank',
16 | controlProperties: [
17 | new TextProperty({
18 | uid: 'description',
19 | label: 'Description',
20 | defaultValue: 'Description',
21 | helpText: 'Instructions / help text for this control',
22 | isHorizontal: false
23 | }),
24 | new TextProperty({
25 | uid: 'variablename',
26 | label: 'Variable name',
27 | defaultValue: 'variable',
28 | helpText: 'The variable associated with this control',
29 | isRequired: true,
30 | isHorizontal: false
31 | }),
32 | // options:
33 | new MultiOptionProperty({
34 | uid: 'options',
35 | label: 'Options',
36 | helpText: 'Enter options, one per line',
37 | value: [{
38 | label: 'Option 1',
39 | value: '1'
40 | }, {
41 | label: 'Option 2',
42 | value: '2'
43 | }],
44 | isRequired: true,
45 | isHorizontal: false
46 | })
47 | ]
48 | });
49 | },
50 | render: function(options) {
51 |
52 | options = options || {};
53 |
54 | var template = _.template(tpl);
55 |
56 | return template({
57 | control: this,
58 | isDesignTime: options.isDesignTime || false
59 | });
60 |
61 | }
62 |
63 | });
64 |
65 | return RadioButtonGroupControl;
66 |
67 | });
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/rPlot.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl',
2 | 'rcap/js/ui/properties/textProperty',
3 | 'rcap/js/ui/properties/dropdownProperty',
4 | 'rcap/js/ui/properties/autocompleteProperty',
5 | 'text!controlTemplates/rPlot.tpl',
6 | 'text!controlTemplates/rPlot-design.tpl'
7 | ], function(GridControl, TextProperty, DropdownProperty, AutocompleteProperty, tpl, dtpl) {
8 |
9 | 'use strict';
10 |
11 | var RPlotControl = GridControl.extend({
12 | init: function() {
13 | this._super({
14 | type: 'rplot',
15 | controlCategory: 'Dynamic',
16 | label: 'R Plot',
17 | icon: 'signal',
18 | controlProperties: [
19 | new AutocompleteProperty({
20 | uid: 'code',
21 | label: 'R Function',
22 | helpText: 'R Function for this control.',
23 | isRequired: true
24 | }),
25 | new TextProperty({
26 | uid: 'linkUrl',
27 | label : 'Link url',
28 | defaultValue : '',
29 | helpText : 'Link url',
30 | isRequired: false,
31 | }),
32 | new DropdownProperty({
33 | uid: 'linkTarget',
34 | label: 'Link target',
35 | isRequired: false,
36 | availableOptions: [{
37 | text: 'Same window',
38 | value: '_self'
39 | }, {
40 | text: 'New window',
41 | value: '_blank'
42 | }],
43 | helpText: 'Where should the link open',
44 | value: '_self'
45 | })
46 | ]
47 | });
48 | },
49 | render: function(options) {
50 |
51 | options = options || {};
52 | var isDesignTime = options.isDesignTime || false;
53 |
54 | var template = isDesignTime ? _.template(dtpl) : _.template(tpl);
55 |
56 | return template({
57 | control: this
58 | });
59 |
60 | },
61 | initialiseViewerItems: function() {
62 |
63 | }
64 | });
65 |
66 | return RPlotControl;
67 |
68 |
69 | });
70 |
--------------------------------------------------------------------------------
/R/rcap.progressSpinner.R:
--------------------------------------------------------------------------------
1 | #' @title Write message to ProgressSpinner with specified id
2 | #'
3 | #' @param variableName the name of the variable linked with ProgressSpinner widget control
4 | #' @param message the message that should be displayed
5 | #' @param append should the message be appended to already displayed content
6 | #' @return NULL invisibly
7 | #' @export
8 | rcap.progressSpinner.write <- function(variableName, message, append = FALSE) {
9 | if(haveController()) {
10 | cnt <- get("rcapController", envir = rcapEnv)
11 | control <- Filter(function(x) {x$getVariableName()==variableName}, cnt$getControls())
12 | if(length(control)!=1) {
13 | stop(paste0("Control for variable '", variableName, "' not found!"));
14 | }
15 | control <- control[[1]]
16 | event <- list("eventType" = "ProgressSpinnerWrite",
17 | "controlId" = control$getId(),
18 | "data" = list("message" = message,
19 | "append" = append)
20 | )
21 | response <- rcap.events.send(event)
22 | if(response$status != 'Success') {
23 | warning(paste0("Event processing failed ", response$msg))
24 | }
25 | } else {
26 | warning("Writting to message widget is only available in dashboard view.")
27 | }
28 | invisible(NULL)
29 | }
30 |
31 | #' @title Write message to a collection of ProgressSpinner widgets
32 | #'
33 | #' @param msg named list of messages, with keys being ProgressSpinner widget variableNames
34 | #' @param append single flag or vector of flags controlling if corresponding message should be appended to the widgets content. Last element gets replicated to fit the number of targets.
35 | #' @param ... named parameters, if 'msg' is not defined, these specify progress spinners and messages that should be written.
36 | #' @return NULL invisibly
37 | #' @export
38 | rcap.progressSpinner.msg <- function(msg=NULL, append=FALSE, ...) {
39 | parms <- list(...)
40 | if( is.null(msg) && length(parms) >0 ) {
41 | msg <- parms
42 | }
43 | if( length(msg) > 0 ) {
44 | if(length(append) >= length(msg)) {
45 | appends <- append
46 | } else {
47 | appends <- c(append, rep(append[[length(append)]], length.out = (length(msg) - length(append))))
48 | }
49 | msg <- as.list(msg)
50 | for(p in 1:length(msg)) {
51 | if(!is.na(names(msg)[[p]])) {
52 | rcloud.rcap:::rcap.progressSpinner.write(names(msg)[[p]], msg[[p]], append = appends[p])
53 | }
54 | }
55 | }
56 | invisible(NULL)
57 | }
58 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/multiSelect.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl', 'rcap/js/ui/properties/textProperty',
2 | 'rcap/js/ui/properties/multiOptionProperty', 'text!rcap/js/ui/controls/child/templates/multiSelect.tpl', 'select2/js/select2', 'css!select2/css/select2.min.css'],
3 | function(BaseControl, TextProperty, MultiOptionProperty, tpl) {
4 |
5 | 'use strict';
6 |
7 | var MultiSelectControl = BaseControl.extend({
8 | init: function() {
9 | this._super({
10 | type : 'multiselect',
11 | label : 'Multi-select',
12 | icon: 'indent-right',
13 | controlProperties: [
14 | new TextProperty({
15 | uid: 'label',
16 | label : 'Label',
17 | defaultValue : 'Label',
18 | helpText : 'The label for this control',
19 | isHorizontal: false
20 | }),
21 | new TextProperty({
22 | uid: 'placeholder',
23 | label : 'Placeholder',
24 | defaultValue : 'Please select an option',
25 | helpText : 'The placeholder for this control',
26 | isHorizontal: false
27 | }),
28 | new TextProperty({
29 | uid: 'variablename',
30 | label : 'Variable name',
31 | defaultValue : 'variable',
32 | helpText : 'The variable associated with this control',
33 | isRequired: true,
34 | isHorizontal: false
35 | }),
36 | // options:
37 | new MultiOptionProperty({
38 | uid: 'options',
39 | label: 'Options',
40 | helpText: 'Enter options, one per line',
41 | value: [{
42 | label: 'Option 1',
43 | value: '1'
44 | }, {
45 | label: 'Option 2',
46 | value: '2'
47 | }],
48 | isRequired: true,
49 | isHorizontal: false
50 | })
51 | ]
52 | });
53 | },
54 | render: function(options) {
55 |
56 | options = options || {};
57 | options.isInFormBuilder = options.isInFormBuilder || false;
58 |
59 | var template = _.template(tpl);
60 |
61 | return template({
62 | control: this,
63 | // to differentiate it from the control that may already exist on the main design surface:
64 | controlId: options.isInFormBuilder ? this.id + '-formbuilderhosted' : this.id,
65 | isDesignTime: options.isDesignTime || false
66 | });
67 |
68 | }
69 | });
70 |
71 | return MultiSelectControl;
72 |
73 | });
--------------------------------------------------------------------------------
/inst/www/styles/vars.scss:
--------------------------------------------------------------------------------
1 | $bg: #fff;
2 | $fg: rgb(62, 62, 62);
3 | $defaultFontSize: 12px;
4 | $bgColor: #F2F2F2;
5 | $defaultFont: 'Open Sans',sans-serif;
6 |
7 | $mainNavBackgroundColor: #222;
8 | $mainNavBackgroundColorHover: lighten($mainNavBackgroundColor, 5%);
9 | $mainNavCurrentPageHover: #070707;
10 | $mainNavColor: #efefef;
11 | $noItemsColor: lighten($mainNavBackgroundColor, 30%);
12 |
13 | $toolbarButtonColorHover: #fff;
14 | $toolbarButtonColor: darken($toolbarButtonColorHover, 15%);
15 |
16 | $messageInformationColor: #3c763d;
17 | $messageWarningColor: #ddc033;
18 | $messageErrorColor: #a94442;
19 |
20 | $topLevelButtonColor: #c37e00;
21 |
22 | /* https://vt.vtp-media.com/ecp/documents/product_Product/521/Logos/4546/att_gdl_glance.pdf */
23 | /*
24 | $attNewOrange: #ff7200;
25 | $attOrangeHighlight: #fcb314;
26 | $attBlue: #067ab4;
27 | $attBlueHightlight: #3aa5dc;
28 |
29 | $attLime: #b6bf00;
30 | $attLimeHighlight: #dbd810;
31 | $attGreen: #6ebb1f;
32 | $attGreenHighlight: #c4d82d;
33 | $attBurgundy: #b30a3c;
34 | $attBurgundyHighlight: #da3872;
35 | $attPurple: #81017e;
36 | $attPurpleHighlight: #b8509e;
37 | $attDarkBlue: #0c2577;
38 | $attDarkBlueHighlight: #020bb3;
39 | */
40 |
41 | $attBlue: #009fdb;
42 | $attBlack: #000000;
43 | $attWhite: #ffffff;
44 | $attOrange: #ea7400;
45 | $attLightBlue: #71c5e8;
46 | $attDarkBlue: #0568ae;
47 | $attLightGray: #d2d2d2;
48 | $attGray: #959595;
49 | $attDarkGray: #5a5a5a;
50 | $attYellow: #ffb81c;
51 | $attLightGreen: #b5bd00;
52 | $attGreen: #4ca90c;
53 | $attDarkGreen: #007a3e;
54 | $attLightPurple: #caa2dd;
55 | $attPurple: #9063cd;
56 | $attDarkPurple: #702f8a;
57 |
58 | $attFunctionalLinkBlue: #0568ae;
59 | $attFunctionalDigitalTextBlue: #191919;
60 | $attFunctionalBackgroundGray: #f2f2f2;
61 | $attFunctionalRed: #cf2a2a;
62 | $attFunctionalYellow: #ffb81c;
63 | $attFunctionalGreen: #007a3e;
--------------------------------------------------------------------------------
/inst/www/partials/dialogs/_formBuilder.htm:
--------------------------------------------------------------------------------
1 |
53 |
--------------------------------------------------------------------------------
/inst/www/js/pages/page.js:
--------------------------------------------------------------------------------
1 | define(['controls/factories/controlFactory',
2 | 'rcap/js/Class'], function(ControlFactory) {
3 |
4 | 'use strict';
5 |
6 | var controlFactory = new ControlFactory();
7 |
8 | var generateId = function() {
9 | return 'rcap' + Math.random().toString(16).slice(2);
10 | };
11 |
12 | var Page = Class.extend({
13 | init: function(options) {
14 | options = options || {};
15 |
16 | this.navigationTitle = options.navigationTitle || 'New Page';
17 | this.isEnabled = true;
18 | this.depth = 1;
19 | this.parentId = options.parentId;
20 | this.id = options.id || generateId();
21 |
22 | this.controls = options.controls || [];
23 | },
24 | deserialize: function() {
25 |
26 | },
27 | serialize: function() {
28 |
29 | },
30 | render: function() {
31 |
32 | },
33 | getDialogMarkup: function() {
34 |
35 | },
36 | getDialogValue: function() {
37 |
38 | },
39 | toJSON: function() {
40 | return {
41 | 'depth': this.depth,
42 | 'id': this.id,
43 | 'parentId' : this.parentId,
44 | 'navigationTitle': this.navigationTitle,
45 | 'isEnabled': this.isEnabled,
46 | 'controls': this.controls,
47 | 'pages': this.pages
48 | };
49 | },
50 | getControlByID: function(controlID) {
51 | return _.findWhere(this.controls, {
52 | id: controlID
53 | });
54 | },
55 | duplicate: function() {
56 | var dupe = $.extend(true, {}, this);
57 | dupe.id = generateId();
58 | dupe.controls = [];
59 |
60 | _.each(this.controls, function(c) {
61 | /*
62 | var currentControl = $.extend(true, {}, c);
63 | currentControl.id = generateId();
64 | dupe.controls.push(currentControl);
65 | */
66 |
67 | /*
68 | var control = controlFactory.getByKey(c.type);
69 | control.isOnGrid = true;
70 | dupe.controls.push(control);
71 | console.info('pushing control: ', control);
72 | */
73 |
74 | dupe.controls.push(controlFactory.duplicateControl(c));
75 | });
76 |
77 | return dupe;
78 | },
79 | canAddChild: function() {
80 | return this.depth <= 2;
81 | }
82 | });
83 |
84 | return Page;
85 |
86 | });
87 |
--------------------------------------------------------------------------------
/inst/www/js/ui/properties/stringValueProperty.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/properties/baseProperty', 'text!templates/stringValueControl.tpl'], function(BaseProperty, tpl) {
2 |
3 | 'use strict';
4 |
5 | // var getValueType = function(value) {
6 | // if( typeof(value) === 'string') {
7 | // return 'code';
8 | // } else if (Object.prototype.toString.call(value) === '[object String]') {
9 | // return 'manual';
10 | // } else {
11 | // // throw new TypeError('was expecting a string or an array');
12 | // return 'shane';
13 | // }
14 | // };
15 |
16 | var StringValueProperty = BaseProperty.extend({
17 | init: function(options) {
18 | options = options || {};
19 | this._super({
20 | type: 'stringvalue',
21 | label: options.label || '',
22 | helpText: options.helpText || '',
23 | defaultValue: options.defaultValue || '',
24 | isRequired: options.isRequired || false,
25 | uid: options.uid,
26 | value: options.value
27 | });
28 |
29 | this.valueType = options.valueType || 'manual';
30 | this.codeHelpText = options.codeHelpText || 'Enter a function that retrieves the value at runtime';
31 | this.serviceName = options.serviceName || 'getRFunctions';
32 |
33 | },
34 | render: function(childIndex) {
35 |
36 | var template = _.template(tpl);
37 |
38 | return template({
39 | property: this,
40 | childIndex: childIndex
41 | });
42 |
43 | },
44 | toJSON: function() {
45 | var json = this._super();
46 | json.valueType = this.valueType; // getValueType(this.value);
47 | return json;
48 | },
49 | getDialogValue: function() {
50 | if ($('#valueType-manual-' + this.id).is(':checked')) {
51 |
52 | this.valueType = 'manual';
53 |
54 | // return an array:
55 | return $('#input-valueType-manual-' + this.id).val();
56 | } else {
57 |
58 | this.valueType = 'code';
59 |
60 | // return a string:
61 | return $('#input-valueType-code-' + this.id).val();
62 | }
63 | },
64 | translateValueToText: function() {
65 | return _.pluck(this.value, 'label').join('\n');
66 | },
67 | finalise : function() {
68 | this.optionType = this.valueType; // getValueType(this.value);
69 | }
70 | });
71 |
72 | return StringValueProperty;
73 |
74 | });
75 |
--------------------------------------------------------------------------------
/inst/www/styles/mixins.scss:
--------------------------------------------------------------------------------
1 | /// Stroke font-character
2 | /// @param {Integer} $stroke - Stroke width
3 | /// @param {Color} $color - Stroke color
4 | /// @return {List} - text-shadow list
5 | @function stroke($stroke, $color) {
6 | $shadow: ();
7 | $from: $stroke*-1;
8 | @for $i from $from through $stroke {
9 | @for $j from $from through $stroke {
10 | $shadow: append($shadow, $i*1px $j*1px 0 $color, comma);
11 | }
12 | }
13 | @return $shadow;
14 | }
15 |
16 | /// Stroke font-character
17 | /// @param {Integer} $stroke - Stroke width
18 | /// @param {Color} $color - Stroke color
19 | /// @return {Style} - text-shadow
20 | @mixin stroke($stroke, $color) {
21 | text-shadow: stroke($stroke, $color)!important;
22 | }
23 |
24 | @mixin noselect() {
25 | -webkit-touch-callout: none;
26 | -webkit-user-select: none;
27 | -khtml-user-select: none;
28 | -moz-user-select: none;
29 | -ms-user-select: none;
30 | user-select: none;
31 | }
32 |
33 | @mixin menuseparator() {
34 | padding-top: 21px;
35 | border-top: 1px solid rgba(255, 255, 255, 0.1);
36 | }
37 |
38 | @mixin cover() {
39 | margin: auto;
40 | position: absolute;
41 | left: 0;
42 | right: 0;
43 | top: 0;
44 | bottom: 0;
45 | }
46 |
47 | @mixin background-opacity($color, $opacity: 0.3) {
48 | background: $color; /* The Fallback */
49 | background: rgba($color, $opacity);
50 | }
51 |
52 | $gridstack-columns: 24 !default;
53 |
54 | @mixin grid-stack-items($gridstack-columns) {
55 |
56 | .grid-stack.grid-stack {
57 |
58 | > .grid-stack-item {
59 | min-width: 100% / $gridstack-columns;
60 |
61 | @for $i from 1 through $gridstack-columns {
62 | &[data-gs-width='#{$i}'] { width: (100% / $gridstack-columns) * $i; }
63 | &[data-gs-x='#{$i}'] { left: (100% / $gridstack-columns) * $i; }
64 | &[data-gs-min-width='#{$i}'] { min-width: (100% / $gridstack-columns) * $i; }
65 | &[data-gs-max-width='#{$i}'] { max-width: (100% / $gridstack-columns) * $i; }
66 | }
67 | }
68 | }
69 | }
70 |
71 | @mixin fontFace($family,$src,$style: normal,$weight: normal) {
72 | @font-face {
73 | font-family: $family;
74 | src: url('#{$src}.eot'); // IE9 compat
75 | src: url('#{$src}.eot?#iefix') format('embedded-opentype'), // IE8 and below
76 | url('#{$src}.woff') format('woff'), // standards
77 | url('#{$src}.ttf') format('truetype'), // Safari, Android, iOS
78 | url('#{$src}.svg##{$family}') format('svg'); // legacy iOS
79 |
80 | font-style: $style;
81 | font-weight: $weight;
82 | }
83 | }
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/dataDownload.js:
--------------------------------------------------------------------------------
1 | define(['pubsub',
2 | 'site/pubSubTable',
3 | 'rcap/js/ui/controls/gridControl',
4 | 'rcap/js/ui/properties/textProperty',
5 | 'rcap/js/ui/properties/stringValueProperty',
6 | 'utils/variableHandler',
7 | 'text!controlTemplates/dataDownload.tpl'
8 | ], function (PubSub, pubSubTable, GridControl, TextProperty, StringValueProperty, variableHandler, tpl) {
9 |
10 | 'use strict';
11 |
12 | var DataUploadControl = GridControl.extend({
13 | init: function () {
14 | this._super({
15 | type: 'datadownload',
16 | controlCategory: 'Dynamic',
17 | label: 'Data Download',
18 | icon: 'cloud-download',
19 | initialSize: [2, 2],
20 | controlProperties: [
21 | new TextProperty({
22 | uid: 'variablename',
23 | label: 'Variable',
24 | helpText: 'The variable associated with this data download',
25 | isRequired: true
26 | }),
27 | /*new TextProperty({
28 | uid: 'allowedtypes',
29 | label: 'Allowed types',
30 | helpText: 'List of allowed file types, comma-separated, e.g. csv,tsv. Leave blank for "all"',
31 | isRequired: false
32 | }),*/
33 | new TextProperty({
34 | uid: 'buttontext',
35 | label: 'Button Text',
36 | defaultValue: '',
37 | helpText: 'The text that appears on the button',
38 | isRequired: true
39 | }),
40 | new StringValueProperty({
41 | uid: 'path',
42 | label: 'Save path',
43 | defaultValue: '',
44 | helpText: 'The file path under which uploaded files will be saved',
45 | codeHelpText: 'The R function that returns the path from which files will be served',
46 | isRequired: true
47 | })
48 | ]
49 | });
50 | },
51 | getVariableData: function () {
52 |
53 | },
54 | render: function () {
55 |
56 | var template = _.template(tpl);
57 |
58 | return template({
59 | control: this
60 | });
61 |
62 | },
63 | initialiseViewerItems: function () {
64 | $('[data-controltype="datadownload"]').click(function () {
65 | var controlId = this.id;
66 | window.RCAP.listFiles(controlId).then(function(response) {
67 | if(response.status.toLowerCase() === 'success') {
68 | PubSub.publish(pubSubTable.showDataDownloadDialog, {
69 | files: response.data,
70 | id: controlId
71 | });
72 | }
73 | //TODO display error so it is not just printed on the console
74 | });
75 | });
76 | }
77 | });
78 |
79 | return DataUploadControl;
80 |
81 |
82 | });
83 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/child/dateRange.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/baseControl', 'rcap/js/ui/properties/textProperty',
2 | 'rcap/js/ui/properties/dropdownProperty',
3 | 'text!rcap/js/ui/controls/child/templates/dateRange.tpl'], function(BaseControl, TextProperty, DropdownProperty, tpl) {
4 |
5 | 'use strict';
6 |
7 | var DatePickerControl = BaseControl.extend({
8 | init: function() {
9 | this._super({
10 | type : 'daterange',
11 | label : 'Date Range',
12 | icon: 'tags',
13 | controlProperties: [
14 | new TextProperty({
15 | uid: 'label',
16 | label : 'Label',
17 | defaultValue : 'Label',
18 | helpText : 'The label for this range control',
19 | isHorizontal: false
20 | }),
21 | new DropdownProperty({
22 | uid: 'intervalType',
23 | label: 'Use interval',
24 | helpText: 'If an interval type is specified, a start date plus interval will be shown rather than the start/end date',
25 | isRequired: false,
26 | availableOptions: [{
27 | text: 'Days',
28 | value: 'days'
29 | }, {
30 | text: 'Weeks',
31 | value: 'weeks'
32 | }, {
33 | text: 'Months',
34 | value: 'months'
35 | }, {
36 | text: 'Years',
37 | value: 'years'
38 | }],
39 | isHorizontal: false
40 | }),
41 | new TextProperty({
42 | uid: 'variablename',
43 | label : 'Start/end date variable name',
44 | defaultValue : 'variable',
45 | helpText : 'The start/end date variable',
46 | isRequired: true,
47 | isHorizontal: false
48 | })
49 | ]
50 | });
51 | },
52 | singularInterval: function() {
53 | var intervalType = this.getPropertyValue('intervalType');
54 | return intervalType ? intervalType.substring(0, intervalType.length - 1) : '';
55 | },
56 | render: function() {
57 | var template = _.template(tpl);
58 |
59 | return template({
60 | control: this
61 | });
62 | }
63 | });
64 |
65 | return DatePickerControl;
66 |
67 | });
68 |
--------------------------------------------------------------------------------
/R/utils.R:
--------------------------------------------------------------------------------
1 |
2 | #' Evaluate rhs if lhs is NULL
3 | #'
4 | #' @param l Left hand side, evaluate this first.
5 | #' @param r Right had side, only evaluate it if \code{l} is \code{NULL}.
6 | #' @return \code{l} if it is not \code{NULL}, otherwise \code{r}.
7 | #' @name or
8 |
9 | `%||%` <- function(l, r) {
10 | if (is.null(l)) r else l
11 | }
12 |
13 | #' The environment the notebook and mini.html are run in
14 | #'
15 | #' This environment is used to search for functions that are used
16 | #' to update the dashboard, and for variables that are associated
17 | #' with dashboard controls.
18 | #'
19 | #' This is currently the global environment.
20 | #'
21 | #' @return An environment.
22 |
23 | rcloudEnv <- function() .GlobalEnv
24 |
25 | #' Return relevant session info in a named list
26 | #'
27 | #' This information is returned to the front end
28 | #' @return A list with username and nodename (host)
29 | #'
30 | #' @export
31 |
32 | rcapSessionInfo <- function() {
33 |
34 | list(user=Sys.info()[c("user")],
35 | nodename=toupper(Sys.info()["nodename"]))
36 |
37 | }
38 |
39 |
40 | havePackage <- function(package) {
41 | requireNamespace(package, quietly = TRUE)
42 | }
43 |
44 |
45 | dataFrame <- function(..., stringsAsFactors = FALSE) {
46 | data.frame(
47 | stringsAsFactors = stringsAsFactors,
48 | ...
49 | )
50 | }
51 |
52 | randomId <- function(prefix = "x") {
53 | rand <- sample(c(letters, 0:9), 8, replace = TRUE)
54 | paste(c(prefix, rand), collapse = "")
55 | }
56 |
57 | #' Return the RCAP version number
58 | #'
59 | #' Check the version number of the loaded package, otherwise check the
60 | #' version installed on the disk.
61 | getRCAPVersion <- function() {
62 | tryCatch(
63 | paste0("v", asNamespace("rcloud.rcap")$`.__NAMESPACE__.`$spec[["version"]]),
64 | error = function(c) {
65 | paste0("v", packageDescription("rcloud.rcap", fields = "Version"))
66 | }
67 | )
68 | }
69 |
70 | pasteEmpty <- function(...) {
71 | args <- list(...)
72 | argsLens <- vapply(args, length, 1L)
73 | if (any(argsLens == 0)) {
74 | c()
75 | } else {
76 | paste0(...)
77 | }
78 | }
79 |
80 | with_options <- function(new, code) {
81 | old <- set_options(new)
82 | on.exit(set_options(old))
83 | force(code)
84 | }
85 |
86 | set_options <- function(opts) {
87 | do.call(options, as.list(opts))
88 | }
89 |
90 | rcap.settings.list <- function() {
91 | ls(envir = rcloud.rcap.settings)
92 | }
93 |
94 | rcap.settings.set <- function(name, value) {
95 | assign(name, value, envir = rcloud.rcap.settings)
96 | }
97 |
98 | rcap.settings.is_set <- function(name) {
99 | exists(name, where = rcloud.rcap.settings)
100 | }
101 |
102 | rcap.settings.get <- function(name) {
103 | get(name, envir = rcloud.rcap.settings)
104 | }
--------------------------------------------------------------------------------
/inst/www/js/Class.js:
--------------------------------------------------------------------------------
1 | /* jshint ignore:start */
2 | define([], function() {
3 |
4 | /* Simple JavaScript Inheritance for ES 5.1
5 | * based on http://ejohn.org/blog/simple-javascript-inheritance/
6 | * (inspired by base2 and Prototype)
7 | * MIT Licensed.
8 | */
9 | (function(global) {
10 | "use strict";
11 | var fnTest = /xyz/.test(function() {
12 | xyz;
13 | }) ? /\b_super\b/ : /.*/;
14 |
15 | // The base Class implementation (does nothing)
16 | function BaseClass() {}
17 |
18 | // Create a new Class that inherits from this class
19 | BaseClass.extend = function(props) {
20 | var _super = this.prototype;
21 |
22 | // Set up the prototype to inherit from the base class
23 | // (but without running the init constructor)
24 | var proto = Object.create(_super);
25 |
26 | // Copy the properties over onto the new prototype
27 | for (var name in props) {
28 | // Check if we're overwriting an existing function
29 | proto[name] = typeof props[name] === "function" &&
30 | typeof _super[name] == "function" && fnTest.test(props[name]) ? (function(name, fn) {
31 | return function() {
32 | var tmp = this._super;
33 |
34 | // Add a new ._super() method that is the same method
35 | // but on the super-class
36 | this._super = _super[name];
37 |
38 | // The method only need to be bound temporarily, so we
39 | // remove it when we're done executing
40 | var ret = fn.apply(this, arguments);
41 | this._super = tmp;
42 |
43 | return ret;
44 | };
45 | })(name, props[name]) : props[name];
46 | }
47 |
48 | // The new constructor
49 | var newClass = typeof proto.init === "function" ? proto.hasOwnProperty("init") ? proto.init // All construction is actually done in the init method
50 | : function SubClass() {
51 | _super.init.apply(this, arguments);
52 | } : function EmptyClass() {};
53 |
54 | // Populate our constructed prototype object
55 | newClass.prototype = proto;
56 |
57 | // Enforce the constructor to be what we expect
58 | proto.constructor = newClass;
59 |
60 | // And make this class extendable
61 | newClass.extend = BaseClass.extend;
62 |
63 | return newClass;
64 | };
65 |
66 | // export
67 | global.Class = BaseClass;
68 | })(this);
69 |
70 | });
71 | /* jshint ignore:end */
72 |
--------------------------------------------------------------------------------
/inst/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | 'use strict';
4 |
5 | var appConfig = {
6 | appPath: require('./bower.json').appPath || '.',
7 | };
8 |
9 | grunt.initConfig({
10 | pkg: grunt.file.readJSON('package.json'),
11 | appConfig: appConfig,
12 | sass: {
13 | all: {
14 | options: {
15 |
16 | },
17 | files: {
18 | 'www/styles/default.css': 'www/styles/default.scss'
19 | },
20 | trace: true
21 | }
22 | },
23 | jshint: {
24 | options: {
25 | jshintrc: '.jshintrc',
26 | reporter: require('jshint-stylish')
27 | },
28 | all: {
29 | src: [
30 | 'Gruntfile.js',
31 | '<%= appConfig.appPath %>/javascript/**/*.js',
32 | '<%= appConfig.appPath %>/www/**/*.js',
33 | '!<%= appConfig.appPath %>/www/js/vendor/**/*.js',
34 | '!<%= appConfig.appPath %>/www/bower_components/**/*.js',
35 | '!<%= appConfig.appPath %>/www/vendor/**/*.js'
36 | ]
37 | }
38 | },
39 | watch: {
40 | css: {
41 | files: '**/*.scss',
42 | tasks: ['sass']
43 | },
44 | js: {
45 | files: [
46 | '<%= appConfig.app %>/javascript/**/*.js',
47 | '<%= appConfig.app %>/www/**/*.js',
48 | '!<%= appConfig.appPath %>/www/js/vendor/**/*.js',
49 | '!<%= appConfig.appPath %>/www/bower_components/**/*.js',
50 | '!<%= appConfig.appPath %>/www/vendor/**/*.js'
51 | ],
52 | tasks: ['newer:jshint:all']
53 | }
54 | },
55 | bower: {
56 | dev: {
57 | base: 'bower_components',
58 | dest: 'www/vendor',
59 | options: {
60 | checkExistence: true,
61 | debugging: false,
62 | paths: {
63 | bowerDirectory: 'bower_components',
64 | bowerrc: '.bowerrc',
65 | bowerJson: 'bower.json'
66 | }
67 | }
68 | }
69 | }
70 | });
71 |
72 | grunt.loadNpmTasks('grunt-contrib-copy');
73 | grunt.loadNpmTasks('grunt-sass');
74 | grunt.loadNpmTasks('grunt-contrib-watch');
75 | grunt.loadNpmTasks('grunt-contrib-jshint');
76 | grunt.loadNpmTasks('grunt-newer');
77 | grunt.loadNpmTasks('main-bower-files');
78 |
79 | require('time-grunt')(grunt);
80 |
81 | // dev
82 | grunt.registerTask('default', ['newer:jshint', 'sass', 'bower:dev']);
83 |
84 | };
85 |
--------------------------------------------------------------------------------
/inst/www/js/ui/controls/image.js:
--------------------------------------------------------------------------------
1 | define(['rcap/js/ui/controls/gridControl', 'rcap/js/ui/properties/textProperty', 'rcap/js/ui/properties/dropdownProperty',
2 | 'text!controlTemplates/image.tpl'],
3 | function(GridControl, TextProperty, DropdownProperty, tpl) {
4 |
5 | 'use strict';
6 |
7 | var ImageControl = GridControl.extend({
8 | init: function() {
9 | this._super({
10 | type : 'image',
11 | controlCategory: 'HTML',
12 | label : 'Image',
13 | icon: 'picture',
14 | controlProperties: [
15 | new TextProperty({
16 | uid: 'imagesource',
17 | label : 'Image source',
18 | defaultValue : '',
19 | helpText : 'The source of the image',
20 | isRequired: true
21 | }),
22 | new DropdownProperty({
23 | uid: 'imageLayout',
24 | label: 'Image style',
25 | helpText: 'Whether the image should be tiled, stretched or placed as is.',
26 | isRequired: true,
27 | availableOptions: [{
28 | text: 'Initial size',
29 | value: 'background-repeat:no-repeat;'
30 | }, {
31 | text: 'Tiled along x axis',
32 | value: 'background-repeat: repeat-x;'
33 | }, {
34 | text: 'Tiled along y axis',
35 | value: 'background-repeat: repeat-y;'
36 | }, {
37 | text: 'Tiled',
38 | value: 'background-repeat: repeat;'
39 | }, {
40 | text: 'Cover',
41 | value: 'background-size: cover;'
42 | }, {
43 | text: 'Stretch',
44 | value: 'background-size: 100% 100%'
45 | }],
46 | defaultValue: 'background-repeat:no-repeat;'
47 | })
48 | ]
49 | });
50 | },
51 | render: function() {
52 |
53 | var template = _.template(tpl);
54 |
55 | return template({
56 | control: this
57 | });
58 | },
59 | initialiseViewerItems : function() {
60 |
61 | $('.grid-stack-item-content.rcap-controltype-image').click(function() {
62 | $('#rcap-stretcher .js-rcap-dynamic').append($(' ').attr('src', $(this).find('div').attr('data-imgsrc')));
63 | $('body').addClass('rcap-stretched');
64 | $('#rcap-stretcher').show();
65 |
66 | $('#rcap-stretcher img').resizable({ aspectRatio: true, maxHeight: $('#rcap-stretcher .js-rcap-dynamic').height() });
67 | });
68 |
69 | $('#rcap-stretcher .stretcher-close').click(function() {
70 | $('#rcap-stretcher .js-rcap-dynamic').empty();
71 | $('body').removeClass('rcap-stretched');
72 | $('#rcap-stretcher').hide();
73 | });
74 |
75 | }
76 | });
77 |
78 | return ImageControl;
79 |
80 | });
--------------------------------------------------------------------------------