diff --git a/beat/web/reports/static/reports/app/directives/view/panelItems.js b/beat/web/reports/static/reports/app/directives/dragHandle.js similarity index 70% rename from beat/web/reports/static/reports/app/directives/view/panelItems.js rename to beat/web/reports/static/reports/app/directives/dragHandle.js index cb0dc0b90000827a3a31d83d5cf2e4b888f3310c..4eb0fce3646b9fc1caaccfb8a4814dfb6f2e8a74 100644 --- a/beat/web/reports/static/reports/app/directives/view/panelItems.js +++ b/beat/web/reports/static/reports/app/directives/dragHandle.js @@ -21,27 +21,26 @@ */ /* - * groupPanelItems + * dragHandle * Desc: - * displays the panel of report items of the group, - * using the item container adaptor + * displays the drag handle button, and adds the specified element class + * to the parent el */ -angular.module('reportApp').directive("groupPanelItems", [function(){ +angular.module('reportApp') +.directive("dragHandle", [function(){ return { scope: { - group: '=' + handleHelperClass: '@' }, - link: function(scope){ + link: function(scope, el){ + el.addClass(`${scope.handleHelperClass} btn-group`); }, template: ` -<div> - <div group-item-container - style='margin-top: 5px;' - ng-repeat='item in group.reportItems' - group='group' - report-item='item'> - </div> -</div> +<span + class='btn btn-default drag-handle' + data-toggle='tooltip' data-placement='top' title='Drag to re-order'> + <i class='fa fa-arrows fa-lg'></i> +</span> ` }; }]); diff --git a/beat/web/reports/static/reports/app/directives/edit/itemContainer.js b/beat/web/reports/static/reports/app/directives/edit/itemContainer.js deleted file mode 100644 index ad80156fc0bec09e50026c2cfb6a7b73fee49cd6..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/edit/itemContainer.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupItemContainer - * Desc: - * container for an item in the group. - * depending of the type of the item (found in the item's id) - * it creates a table, plot, or text item - */ -angular.module('reportApp') -.directive("groupItemContainer", [function(){ - return { - scope: { - group: '=', - reportItem: '=' - }, - link: function(scope){ - scope.item = scope.reportItem; - // report-wide-unique prefix for the item to use - scope.domId = `${scope.group.name}_${scope.id}`; - }, - template: ` -<div - group-table-item - ng-if="item.id.includes('table')" - class='panel panel-default' - group='group' - item-id='item.id' - content='item.content' - > -</div> -<div - group-plot-item - ng-if="item.id.includes('plot')" - class='panel panel-default' - group='group' - item-id='item.id' - content='item.content' - > -</div> -<div - group-text-item - ng-if="item.id.includes('text')" - class='panel panel-default' - group='group' - report-item='item' - item-id='item.id' - > -</div> -` - }; -}]); diff --git a/beat/web/reports/static/reports/app/directives/edit/layout.js b/beat/web/reports/static/reports/app/directives/edit/layout.js deleted file mode 100644 index ddedd21165ccf8abf4c54f0cdbc544865f65301f..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/edit/layout.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupsLayout - * Desc: - * controls the layout of the reports content, - * generating group panels using the GroupsService data, - * and holding the menu for adding a group - */ -angular.module('reportApp').directive("groupsLayout", ['GroupsService', function(GroupsService){ - return { - scope: { - }, - link: function(scope, el, attr){ - scope.groups = GroupsService.groups; - scope.GroupsService = GroupsService; - - // drag handle CSS selector - scope.sortableOptions = { - handle: '.panel-heading > .panel-title > .action-buttons > .drag-handle' - }; - }, - template: ` -<experiments-table></experiments-table> -<div group-add-group-menu class='panel'></div> - -<div ui-sortable='sortableOptions' ng-model='GroupsService.groups' id='groupsLayout' class='panel-group'> - <div - group-panel-content - class='panel panel-default' - ng-repeat='group in GroupsService.groups' - group='group' - > - </div> -</div> -` - }; -}]); diff --git a/beat/web/reports/static/reports/app/directives/edit/plotItem.js b/beat/web/reports/static/reports/app/directives/edit/plotItem.js deleted file mode 100644 index 614a6999ea2f13115977d9698bc94d717d43877d..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/edit/plotItem.js +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupPlotItem - * Desc: - * displays a plot report item (basically a container for the plots code to insert into) - */ -angular.module('reportApp') -.directive("groupPlotItem", ['ExperimentsService', 'PlotService', '$timeout', function(ExperimentsService, PlotService, $timeout){ - return { - scope: { - group: '=', - itemId: '=', - content: '=' - }, - link: function(scope){ - const group = scope.group; - scope.domId = `${scope.group.name}_${scope.itemId}`; - - // container for the plots applet to insert into - scope.renderDivId = `${scope.domId}-render`; - - // the callback for when the plot renders - // (called every time the plot re-renders, e.g. user changes config/merged - const updatePlotConfig = (selectedPlotter, selectedConfig, isMerged) => { - scope.content.merged = isMerged; - scope.content.savedPlotter = selectedPlotter; - scope.content.savedConfig = selectedConfig; - }; - - // wait until the container html element is rendered. - // angular will run these functions called with $timeout - // after everything has been rendered - $timeout(function() { - PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig); - }); - - let plotTimer; - - const updatePlot = () => { - clearTimeout(plotTimer); - - const queueUpdate = () => { - let el = document.querySelector(`#${scope.renderDivId}`); - // if the container is rendered and it already has had a render, - // redo the render - if(el && el.childNodes.length > 0){ - el.innerHTML = ''; - return PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig); - } - }; - - plotTimer = setTimeout(queueUpdate, 1000); - }; - - - // if the group has exps added/removed, rerender the plot - scope.$watch( - // angular doesnt watch arrays properly (i.e. watching scope.group._experimentNames), - // as it doesnt register array changes. - // it also doesnt watch getters properly (i.e. watching scope.group.experiments), - // because it compares shallowly and getters commonly return a new obj each time. - // so, watch the getters length instead - () => scope.group.experiments.length, - updatePlot - ); - - // if the group has aliases changed, rerender the plot - scope.$watch( - () => JSON.stringify(scope.group._aliases), - updatePlot - ); - - // if the user selected different plotter or config, rerender - scope.$watch( - () => `${scope.content.savedPlotter}|${scope.content.savedConfig}`, - updatePlot - ); - - scope.toggleMerged = () => { - scope.content.merged = !scope.content.merged; - updatePlot(); - }; - - scope.getPlotter = () => PlotService.getPlotter(scope.content); - scope.getPossiblePlotters = () => PlotService.plotters.filter(p => p.dataformat === scope.content.type).map(p => p.name); - scope.getPossibleConfigs = () => PlotService.getPossibleConfigs(scope.getPlotter()); - }, - template: ` -<div id="{{domId}}-heading" class="panel-heading" role="tab"> - <h4 class="panel-title"> - <a - class='' - role="button" - data-toggle="collapse" - data-parent="#{{domId}}-heading" - href="#collapse-{{domId}}" - aria-expanded="true" - aria-controls="collapse-{{domId}}"> - </a> - <editable-label obj='content' field='itemName'></editable-label> - <div class='btn-group action-buttons'> - <span - ng-click='group.removeReportItem(itemId)' - class="btn btn-default btn-delete" - data-toggle="tooltip" data-placement="top" title="Delete Plot"> - <i class="fa fa-times fa-lg"></i> - </span> - <span - class='btn btn-default drag-handle' - data-toggle='tooltip' data-placement='top' title='Drag to re-order item'> - <i class='fa fa-arrows fa-lg'></i> - </span> - </div> - <div class='btn-group' role='group'> - <download-link - class='btn-group' - dom-id='{{ domId }}' - group='group' - item-id='itemId'> - </download-link> - <button ng-if='group.experiments.length > 1' class='btn btn-default' ng-click='toggleMerged()'> - <span ng-if='content.merged'><i class='fa fa-expand'></i> Expand</span> - <span ng-if='!content.merged'><i class='fa fa-compress'></i> Merge</span> - </button> - <div class='btn-group' role='group'> - <button - ng-class='{disabled: getPossiblePlotters().length === 1}' - class='btn btn-default dropdown-toggle' - type="button" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false"> - Plotter: {{ content.savedPlotter }} - <span class="caret"></span> - </button> - <ul class="dropdown-menu"> - <li ng-click='content.savedPlotter = p' ng-repeat='p in getPossiblePlotters()'><a>{{ p }}</a></li> - </ul> - </div> - <div class='btn-group' role='group'> - <button - ng-class='{disabled: getPossibleConfigs().length === 1}' - class='btn btn-default dropdown-toggle' - type="button" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false"> - Config: {{ content.savedConfig }} - <span class="caret"></span> - </button> - <ul class="dropdown-menu"> - <li ng-click='content.savedConfig = c' ng-repeat='c in getPossibleConfigs()'><a>{{ c }}</a></li> - </ul> - </div> - </div> - </h4> -</div> -<div id="collapse-{{domId}}" - class="panel-collapse collapse in" - role="tabpanel" - aria-labelledby="{{domId}}-heading"> - <div class='panel-body'> - <div id='{{ renderDivId }}'></div> - </div> -</div> -` - }; -}]); diff --git a/beat/web/reports/static/reports/app/directives/edit/tableItem.js b/beat/web/reports/static/reports/app/directives/edit/tableItem.js deleted file mode 100644 index 70bf876207bffa1782b4a5d4b7240cd66e806808..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/edit/tableItem.js +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupTableItem - * Desc: - * displays a table report item and lets the user - * manage this table's selected cols and float precision - */ -angular.module('reportApp') -.directive("groupTableItem", ['GroupsService', 'ExperimentsService', function(GroupsService, ExperimentsService){ - return { - scope: { - group: '=', - itemId: '=', - content: '=' - }, - link: function(scope){ - // aliases - scope.fields = scope.content.fields; - // ids - scope.domId = `${scope.group.name}_${scope.itemId}`; - scope.colSelectorId = `${scope.domId}_columnSelector`; - - // 1 - 10 - // probably the most concise way of generating 1-10 computationally - // also vastly more complex than writing [1,2,3,4,5,6,7,9,10] - scope.floatingPointRange = [...(new Array(10)).keys()].map(i => i + 1); - - // init the chosen cols for the table with the saved cols - scope.chosenCols = Array.from(scope.fields); - - // save new cols choice - // due to how angular handles functions passed as props to an element, - // it must return a function that does the actual work. - scope.saveChosenCols = () => () => { - // we want to keep the selected columns in order, - // so try to add new columns in their correct indices, - // and rm cols by mutating the array - - const newCols = scope.chosenCols - .filter(c => !scope.fields.includes(c)); - - const rmCols = scope.fields - .filter(f => !scope.chosenCols.includes(f) && f !== 'Experiment'); - - rmCols.forEach(rf => scope.fields.splice(scope.fields.indexOf(rf), 1)); - - newCols.forEach(nf => scope.fields.push(nf)); - }; - - // toggle val for viewing CSV - scope.isViewingCSV = { val: false }; - scope.toggleViewingCSV = () => { - scope.isViewingCSV.val = !scope.isViewingCSV.val; - }; - }, - template: ` -<div id="{{domId}}-heading" class="panel-heading" role="tab"> - <h4 class="panel-title"> - <a - class='' - role="button" - data-toggle="collapse" - data-parent="#{{domId}}-heading" - href="#collapse-{{domId}}" - aria-expanded="true" - aria-controls="collapse-{{domId}}"> - </a> - <editable-label obj='content' field='itemName'></editable-label> - <div class='btn-group action-buttons'> - <span - ng-click='group.removeReportItem(itemId)' - class="btn btn-default btn-delete" - data-toggle="tooltip" data-placement="top" title="Delete Table"> - <i class="fa fa-times fa-lg"></i> - </span> - <span - class='btn btn-default drag-handle' - data-toggle='tooltip' data-placement='top' title='Drag to re-order item'> - <i class='fa fa-arrows fa-lg'></i> - </span> - </div> - <div class="btn-group" role="group" role='tab'> - <div class="btn-group" role="group" - group-table-field-selector - id='colSelectorId' - group='group' - cols-selected='chosenCols' - button-action='saveChosenCols()' - title="Choose Columns" - button-text="Save Column Choices" - > - </div> - <div class='btn-group' role='group'> - <button class='btn btn-default' id="{{domId}}-precision" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - Float Precision: {{ content.precision }} - <span class="caret"></span> - </button> - <ul class="dropdown-menu" aria-labelledby="{{domId}}-precision"> - <li ng-click='content.precision = i' ng-repeat='i in floatingPointRange'><a>{{ i }}</a></li> - </ul> - </div> - <button class='btn btn-default' ng-click='toggleViewingCSV()'> - Toggle CSV View - </button> - </div> - </h4> -</div> -<div id="collapse-{{domId}}" - class="panel-collapse collapse in" - role="tabpanel" - aria-labelledby="{{domId}}-heading"> - <div table-item class='panel-body' group='group' content='content' is-viewing-csv='isViewingCSV'></div> -</div> -` - }; -}]); diff --git a/beat/web/reports/static/reports/app/directives/editableLabel.js b/beat/web/reports/static/reports/app/directives/editableLabel.js index 5fe652eeae078468b931cd32a9df2d864b9ebdf2..01f9eecd3ef2664dba66a86995ad93f1a916b858 100644 --- a/beat/web/reports/static/reports/app/directives/editableLabel.js +++ b/beat/web/reports/static/reports/app/directives/editableLabel.js @@ -25,17 +25,20 @@ * Desc: * represents an editable label (group name, report item name, etc.) */ -angular.module('reportApp').directive("editableLabel", [function(){ +angular.module('reportApp').directive("editableLabel", ['UrlService', function(UrlService){ return { scope: { obj: '=', field: '@' }, link: function(scope){ + scope.isViewmode = UrlService.isViewmode; }, template: ` <span style='display: inline-block;'> + <span ng-if='isViewmode()'>{{ obj[field] }}</span> <input + ng-if='!isViewmode()' style='display: inline;' required type='text' diff --git a/beat/web/reports/static/reports/app/directives/view/layout.js b/beat/web/reports/static/reports/app/directives/layout.js similarity index 70% rename from beat/web/reports/static/reports/app/directives/view/layout.js rename to beat/web/reports/static/reports/app/directives/layout.js index ba578adaffb082ef97f7621aae92d92262aa802e..f32d9a5271abcba1d23fe006a55a0ed0e1b934b9 100644 --- a/beat/web/reports/static/reports/app/directives/view/layout.js +++ b/beat/web/reports/static/reports/app/directives/layout.js @@ -27,25 +27,37 @@ * generating group panels using the GroupsService data, * and holding the menu for adding a group */ -angular.module('reportApp').directive("groupsLayout", ['GroupsService', function(GroupsService){ +angular.module('reportApp').directive("groupsLayout", ['GroupsService', 'UrlService', function(GroupsService, UrlService){ return { scope: { }, link: function(scope, el, attr){ scope.GroupsService = GroupsService; - console.log(scope.GroupsService.groups); + scope.isViewmode = UrlService.isViewmode; + + // drag handle CSS selector + scope.sortableOptions = { + handle: '.dragGroup .drag-handle' + }; }, template: ` <experiments-table></experiments-table> +<div ng-if='!isViewmode()' group-add-group-menu class='panel'></div> <div id='groupsLayout' class='panel-group'> - <div ng-if='GroupsService.groups.length > 1' group-panel-content - class='panel panel-default' - ng-repeat='group in GroupsService.groups' - group='group' - > + <div ng-if='!isViewmode() || GroupsService.groups.length > 1' + ui-sortable='sortableOptions' + ng-model='GroupsService.groups' + id='groupsLayout' + class='panel-group'> + <div + group-panel-content + style='margin-bottom: 5px;' + ng-repeat='group in GroupsService.groups' + group='group'> + </div> </div> - <div ng-if='GroupsService.groups.length == 1'> + <div ng-if='isViewmode() && GroupsService.groups.length == 1'> <group-panel-items group='GroupsService.groups[0]'></group-panel-items> </div> </div> diff --git a/beat/web/reports/static/reports/app/directives/view/tableItem.js b/beat/web/reports/static/reports/app/directives/panelContainer.js similarity index 65% rename from beat/web/reports/static/reports/app/directives/view/tableItem.js rename to beat/web/reports/static/reports/app/directives/panelContainer.js index c357900edca1ad7cc372e3057c8190dac3ad9c34..e971fe661eafad4686000287745cbda4d403c313 100644 --- a/beat/web/reports/static/reports/app/directives/view/tableItem.js +++ b/beat/web/reports/static/reports/app/directives/panelContainer.js @@ -21,27 +21,24 @@ */ /* - * groupTableItem + * panelContainer * Desc: - * displays a table report item and lets the user view the CSV + * displays a Bootstrap panel with the specified header & body content */ angular.module('reportApp') -.directive("groupTableItem", ['GroupsService', 'ExperimentsService', function(GroupsService, ExperimentsService){ +.directive("panelContainer", [function(){ return { scope: { - group: '=', - itemId: '=', - content: '=' + noPanelBody: '=', + domId: '=' }, - link: function(scope){ - // ids - scope.domId = `${scope.group.name}_${scope.itemId}`; - - // toggle val for viewing CSV - scope.isViewingCSV = { val: false }; - scope.toggleViewingCSV = () => { - scope.isViewingCSV.val = !scope.isViewingCSV.val; - }; + restrict: 'A', + transclude: { + 'headerSlot': 'header', + 'contentSlot': 'content' + }, + link: function(scope, el){ + el.addClass('panel panel-default'); }, template: ` <div id="{{domId}}-heading" class="panel-heading" role="tab"> @@ -54,22 +51,16 @@ angular.module('reportApp') href="#collapse-{{domId}}" aria-expanded="true" aria-controls="collapse-{{domId}}"> - {{ content.itemName }} </a> - - <div class="btn-group" role="group" role='tab'> - <button class='btn btn-primary' ng-click='toggleViewingCSV()'> - Toggle CSV View - </button> - </div> + <span ng-transclude='headerSlot'>Header Content</span> </h4> </div> <div id="collapse-{{domId}}" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="{{domId}}-heading"> - <div class='panel-body'> - <table-item group='group' content='content' is-viewing-csv='isViewingCSV'></table-item> + <div ng-class='{ "panel-body": !noPanelBody }' ng-transclude='contentSlot'> + Body Content with hasPanelBody: {{ hasPanelBody }} </div> </div> ` diff --git a/beat/web/reports/static/reports/app/directives/edit/panelContent.js b/beat/web/reports/static/reports/app/directives/panelContent.js similarity index 77% rename from beat/web/reports/static/reports/app/directives/edit/panelContent.js rename to beat/web/reports/static/reports/app/directives/panelContent.js index 881b0161e833c453009d239ae06d6baacd70635b..9f6319b036b2e8e4c739cc3502f38410a8d73bed 100644 --- a/beat/web/reports/static/reports/app/directives/edit/panelContent.js +++ b/beat/web/reports/static/reports/app/directives/panelContent.js @@ -29,21 +29,18 @@ * - panel header also contains the buttons to add report items * - two sub-panels are added: the experiments list, and the items list */ -angular.module('reportApp').directive("groupPanelContent", ['GroupsService', function(GroupsService){ +angular.module('reportApp').directive("groupPanelContent", ['GroupsService', 'UrlService', function(GroupsService, UrlService){ return { scope: { group: '=' }, link: function(scope){ scope.deleteGroup = GroupsService.deleteGroup; - scope.editingGroupName = false; - scope.toggleEditingGroupName = () => { - scope.editingGroupName = !scope.editingGroupName; - }; + scope.isViewmode = UrlService.isViewmode; }, template: ` -<div id="{{group.name}}-heading" class="panel-heading" role="tab"> - <h4 class="panel-title"> +<div panel-container class='dragGroup' domId='group.name'> + <header> <a class='' role="button" @@ -54,31 +51,22 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun aria-controls="collapse-{{group.name}}"> </a> <editable-label obj='group' field='_name'></editable-label> - <div class='btn-group action-buttons'> + <div ng-if='!isViewmode()' class='btn-group action-buttons'> <span ng-click='deleteGroup(group.name)' class="btn btn-default btn-delete" data-toggle="tooltip" data-placement="top" title="Delete Group"> <i class="fa fa-times fa-lg"></i> </span> - <span - class='btn btn-default drag-handle' - data-toggle='tooltip' data-placement='top' title='Drag to re-order group'> - <i class='fa fa-arrows fa-lg'></i> - </span> + <span drag-handle handle-helper-class='dragGroup'></span> </div> - <div + <div ng-if='!isViewmode()' group-add-items-menu class="btn-group" role="group" role='tab' group='group'> </div> - </h4> -</div> -<div id="collapse-{{group.name}}" - class="panel-collapse collapse in" - role="tabpanel" - aria-labelledby="{{group.name}}-heading"> - <div class="panel-body panel-group"> + </header> + <content> <div group-panel-experiments group='group' class='panel panel-default'></div> <div style='margin-top: 5px;' @@ -87,7 +75,7 @@ angular.module('reportApp').directive("groupPanelContent", ['GroupsService', fun group='group' > </div> - </div> + </content> </div> ` }; diff --git a/beat/web/reports/static/reports/app/directives/edit/panelItems.js b/beat/web/reports/static/reports/app/directives/panelItems.js similarity index 72% rename from beat/web/reports/static/reports/app/directives/edit/panelItems.js rename to beat/web/reports/static/reports/app/directives/panelItems.js index 0c73d467701c8372a7cd9881484d6426f211f8bd..358862dd6011b54b7979a23511a80f8491d41a08 100644 --- a/beat/web/reports/static/reports/app/directives/edit/panelItems.js +++ b/beat/web/reports/static/reports/app/directives/panelItems.js @@ -36,18 +36,33 @@ angular.module('reportApp').directive("groupPanelItems", [function(){ // TODO: this needs to be changed each time the HTML hierarchy changes. // Make it hierarchy-independent scope.sortableOptions = { - handle: '.panel-heading > .panel-title > .action-buttons > .drag-handle' + handle: '.dragItem .drag-handle' }; }, template: ` -<div ui-sortable='sortableOptions' ng-model='group._reportItems'> - <div - group-item-container - ng-repeat='item in group.reportItems' - group='group' - report-item='item' - style='margin-bottom: 5px;' - > +<div ui-sortable='sortableOptions' ng-model='group._reportItems' class='panel-group'> + <div ng-repeat='item in group.reportItems'> + <div group-table-item + style='margin-bottom: 5px;' + ng-if="item.id.includes('table')" + group='group' + item-id='item.id' + content='item.content'> + </div> + <div group-plot-item + style='margin-bottom: 5px;' + ng-if="item.id.includes('plot')" + group='group' + item-id='item.id' + content='item.content'> + </div> + <div group-text-item + style='margin-bottom: 5px;' + ng-if="item.id.includes('text')" + group='group' + report-item='item' + item-id='item.id'> + </div> </div> </div> ` diff --git a/beat/web/reports/static/reports/app/directives/view/plotItem.js b/beat/web/reports/static/reports/app/directives/plotItem.js similarity index 88% rename from beat/web/reports/static/reports/app/directives/view/plotItem.js rename to beat/web/reports/static/reports/app/directives/plotItem.js index 41766da6b5bba88e512083e2baaf70b57e90fcdf..4c7655b1ba4429d745673cf24f0112a195eca054 100644 --- a/beat/web/reports/static/reports/app/directives/view/plotItem.js +++ b/beat/web/reports/static/reports/app/directives/plotItem.js @@ -26,7 +26,7 @@ * displays a plot report item (basically a container for the plots code to insert into) */ angular.module('reportApp') -.directive("groupPlotItem", ['ExperimentsService', 'PlotService', '$timeout', function(ExperimentsService, PlotService, $timeout){ +.directive("groupPlotItem", ['ExperimentsService', 'PlotService', '$timeout', 'UrlService', function(ExperimentsService, PlotService, $timeout, UrlService){ return { scope: { group: '=', @@ -87,20 +87,21 @@ angular.module('reportApp') scope.getPlotter = () => PlotService.getPlotter(scope.content); scope.getPossiblePlotters = () => PlotService.plotters.filter(p => p.dataformat === scope.content.type).map(p => p.name); scope.getPossibleConfigs = () => PlotService.getPossibleConfigs(scope.getPlotter()); + scope.isViewmode = UrlService.isViewmode; }, template: ` -<div id="{{domId}}-heading" class="panel-heading" role="tab"> - <h4 class="panel-title"> - <a - class='' - role="button" - data-toggle="collapse" - data-parent="#{{domId}}-heading" - href="#collapse-{{domId}}" - aria-expanded="true" - aria-controls="collapse-{{domId}}"> - </a> - {{ content.itemName }} +<div panel-container dom-id='domId'> + <header> + <editable-label obj='content' field='itemName'></editable-label> + <div ng-if='!isViewmode()' class='btn-group action-buttons'> + <span + ng-click='group.removeReportItem(itemId)' + class="btn btn-default btn-delete" + data-toggle="tooltip" data-placement="top" title="Delete Plot"> + <i class="fa fa-times fa-lg"></i> + </span> + <span drag-handle handle-helper-class='dragItem'></span> + </div> <div class='btn-group' role='group'> <download-link class='btn-group' @@ -143,15 +144,10 @@ angular.module('reportApp') </ul> </div> </div> - </h4> -</div> -<div id="collapse-{{domId}}" - class="panel-collapse collapse in" - role="tabpanel" - aria-labelledby="{{domId}}-heading"> - <div class='panel-body'> + </header> + <content> <div id='{{ renderDivId }}'></div> - </div> + </content> </div> ` }; diff --git a/beat/web/reports/static/reports/app/directives/tableItem.js b/beat/web/reports/static/reports/app/directives/tableItem.js index 343a7b8b8f79d4fbc2a9477c64a594fd94e83ca9..e157b69f6039b476303bbedc5baa28ea4c27317b 100644 --- a/beat/web/reports/static/reports/app/directives/tableItem.js +++ b/beat/web/reports/static/reports/app/directives/tableItem.js @@ -23,17 +23,57 @@ /* * tableItem * Desc: - * displays a table report item + * displays a table report item and lets the user + * manage this table's selected cols and float precision */ angular.module('reportApp') -.directive("tableItem", ['GroupsService', 'ExperimentsService', 'UrlService', function(GroupsService, ExperimentsService, UrlService){ +.directive("groupTableItem", ['GroupsService', 'ExperimentsService', 'UrlService', function(GroupsService, ExperimentsService, UrlService){ return { scope: { group: '=', - content: '=', - isViewingCsv: '=' + itemId: '=', + content: '=' }, link: function(scope){ + // aliases + scope.fields = scope.content.fields; + // ids + scope.domId = `${scope.group.name}_${scope.itemId}`; + scope.colSelectorId = `${scope.domId}_columnSelector`; + + // 1 - 10 + // probably the most concise way of generating 1-10 computationally + // also vastly more complex than writing [1,2,3,4,5,6,7,9,10] + scope.floatingPointRange = [...(new Array(10)).keys()].map(i => i + 1); + + // init the chosen cols for the table with the saved cols + scope.chosenCols = Array.from(scope.fields); + + // save new cols choice + // due to how angular handles functions passed as props to an element, + // it must return a function that does the actual work. + scope.saveChosenCols = () => () => { + // we want to keep the selected columns in order, + // so try to add new columns in their correct indices, + // and rm cols by mutating the array + + const newCols = scope.chosenCols + .filter(c => !scope.fields.includes(c)); + + const rmCols = scope.fields + .filter(f => !scope.chosenCols.includes(f) && f !== 'Experiment'); + + rmCols.forEach(rf => scope.fields.splice(scope.fields.indexOf(rf), 1)); + + newCols.forEach(nf => scope.fields.push(nf)); + }; + + // toggle val for viewing CSV + scope.isViewingCSV = { val: false }; + scope.toggleViewingCSV = () => { + scope.isViewingCSV.val = !scope.isViewingCSV.val; + }; + // aliases scope.fields = scope.content.fields; @@ -165,44 +205,88 @@ angular.module('reportApp') scope.sortableOptions = { items: `th:not(:first-child)` }; + + scope.isViewmode = UrlService.isViewmode; }, template: ` -<div ng-if='isViewingCsv.val'> - <pre>{{ getCSV() }}</pre> -</div> -<div ng-if='!isViewingCsv.val' style='height: 100%; overflow-x: auto;'> - <table class="table table-striped table-hover"> - <thead> - <tr ui-sortable='sortableOptions' ng-model='fields'> - <th ng-repeat='field in fields'> - <span - ng-if="sortField.val == field" - class='glyphicon' - ng-class="{ - 'glyphicon-chevron-up': sortField.isReversed, - 'glyphicon-chevron-down': !sortField.isReversed - }" - > - </span> - <a role='button' ng-click='setSortField(field)'> - {{ field }} <i>({{ getFieldType(field) }})</i> - </a> - </th> - </tr> - </thead> - <tbody> - <tr ng-repeat="exp in group.experiments | orderBy:sortFunc:sortField.isReversed"> - <td ng-repeat='field in fields'> - <a ng-if='$index == 0 && getExperimentUrl(exp)' href='{{ getExperimentUrl(exp) }}'> - {{ getFieldVal(exp, field) }} - </a> - <span ng-if='!$index == 0 || !getExperimentUrl(exp)'> - {{ getFieldVal(exp, field) }} - </span> - </td> - </tr> - </tbody> - </table> +<div panel-container dom-id='domId'> + <header> + <editable-label obj='content' field='itemName'></editable-label> + <div ng-if='!isViewmode()' class='btn-group action-buttons'> + <span + ng-click='group.removeReportItem(itemId)' + class="btn btn-default btn-delete" + data-toggle="tooltip" data-placement="top" title="Delete Table"> + <i class="fa fa-times fa-lg"></i> + </span> + <span drag-handle handle-helper-class='dragItem'></span> + </div> + <div class="btn-group" role="group" role='tab'> + <div ng-if='!isViewmode()' class="btn-group" role="group" + group-table-field-selector + id='colSelectorId' + group='group' + cols-selected='chosenCols' + button-action='saveChosenCols()' + title="Choose Columns" + button-text="Save Column Choices" + > + </div> + <div class='btn-group' role='group'> + <button class='btn btn-default' id="{{domId}}-precision" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + Float Precision: {{ content.precision }} + <span class="caret"></span> + </button> + <ul class="dropdown-menu" aria-labelledby="{{domId}}-precision"> + <li ng-click='content.precision = i' ng-repeat='i in floatingPointRange'><a>{{ i }}</a></li> + </ul> + </div> + <button class='btn btn-default' ng-click='toggleViewingCSV()'> + Toggle CSV View + </button> + </div> + </header> + <content> + <div class='panel-body'> + <div ng-if='isViewingCSV.val'> + <pre>{{ getCSV() }}</pre> + </div> + <div ng-if='!isViewingCSV.val' style='height: 100%; overflow-x: auto;'> + <table class="table table-striped table-hover"> + <thead> + <tr ui-sortable='sortableOptions' ng-model='fields'> + <th ng-repeat='field in fields'> + <span + ng-if="sortField.val == field" + class='glyphicon' + ng-class="{ + 'glyphicon-chevron-up': sortField.isReversed, + 'glyphicon-chevron-down': !sortField.isReversed + }" + > + </span> + <a role='button' ng-click='setSortField(field)'> + {{ field }} <i>({{ getFieldType(field) }})</i> + </a> + </th> + </tr> + </thead> + <tbody> + <tr ng-repeat="exp in group.experiments | orderBy:sortFunc:sortField.isReversed"> + <td ng-repeat='field in fields'> + <a ng-if='$index == 0 && getExperimentUrl(exp)' href='{{ getExperimentUrl(exp) }}'> + {{ getFieldVal(exp, field) }} + </a> + <span ng-if='!$index == 0 || !getExperimentUrl(exp)'> + {{ getFieldVal(exp, field) }} + </span> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </content> </div> ` }; diff --git a/beat/web/reports/static/reports/app/directives/edit/textItem.js b/beat/web/reports/static/reports/app/directives/textItem.js similarity index 77% rename from beat/web/reports/static/reports/app/directives/edit/textItem.js rename to beat/web/reports/static/reports/app/directives/textItem.js index c7af4cd4f09dde6e2ad51492a6bae16bfefa4798..72a2c9967bb523a1fdefbad820dc022c0748a2b5 100644 --- a/beat/web/reports/static/reports/app/directives/edit/textItem.js +++ b/beat/web/reports/static/reports/app/directives/textItem.js @@ -43,9 +43,12 @@ angular.module('reportApp') scope.item = scope.reportItem; scope.domId = `${scope.group.name}_${scope.item.id}`; + scope.isViewmode = UrlService.isViewmode; + // codemirror options scope.uicmOptions = { mode: 'rst', + readOnly: scope.isViewmode() }; // handle compiling content @@ -53,7 +56,8 @@ angular.module('reportApp') scope.compiledContent = { val: '' }; scope.compileContent = () => { let url = UrlService.getCompileRstUrl(); - let content = scope.item.content.text; + let content = !scope.isViewmode() ? scope.item.content.text : + `${scope.group.name}|${scope.group.reportItems.indexOf(scope.reportItem)}`; return reportFactory.compileRST(url, content) .then(data => { @@ -63,61 +67,46 @@ angular.module('reportApp') }; // handle edit/save/cancel buttons - scope.isEditing = { val: false }; + scope.isSrcMode = { val: false }; // when editing, use a buffer to hold the raw text scope.unsavedContent = { val: `${scope.item.content.text}` }; // save the buffer to the actual report item content scope.saveAction = () => { scope.item.content.text = scope.unsavedContent.val; scope.compileContent(); - scope.isEditing.val = false; + scope.isSrcMode.val = false; }; // discard buffer and use report item content scope.cancelAction = () => { scope.unsavedContent.val = `${scope.item.content.text}`; - scope.isEditing.val = false; + scope.isSrcMode.val = false; }; // compile the content when loaded scope.compileContent(); }, template: ` -<div id="{{domId}}-heading" class="panel-heading" role="tab"> - <h4 class="panel-title"> - <a - class='' - role="button" - data-toggle="collapse" - data-parent="#{{domId}}-heading" - href="#collapse-{{domId}}" - aria-expanded="true" - aria-controls="collapse-{{domId}}"> - </a> +<div panel-container dom-id='domId'> + <header> <editable-label obj='item.content' field='itemName'></editable-label> - <div class='btn-group action-buttons'> + <div ng-if='!isViewmode()' class='btn-group action-buttons'> <span ng-click='group.removeReportItem(item.id)' class="btn btn-default btn-delete" data-toggle="tooltip" data-placement="top" title="Delete Text Block"> <i class="fa fa-times fa-lg"></i> </span> - <span - class='btn btn-default drag-handle' - data-toggle='tooltip' data-placement='top' title='Drag to re-order item'> - <i class='fa fa-arrows fa-lg'></i> - </span> + <span drag-handle handle-helper-class='dragItem'></span> </div> - </h4> -</div> -<div id="collapse-{{domId}}" - class="panel-collapse collapse in" - role="tabpanel" - aria-labelledby="{{domId}}-heading"> - <div class='panel-body'> - <div class='row'> + <button ng-if='isViewmode()' class='btn btn-primary' ng-click='isSrcMode.val = !isSrcMode.val'> + Toggle Source View + </button> + </header> + <content> + <div ng-if='!isViewmode()' class='row'> <div class='col-sm-10'> - <div ng-if='!isEditing.val' ng-bind-html='trustAsHtml(compiledContent.val)'></div> - <div ng-if='isEditing.val'> + <div ng-if='!isSrcMode.val' ng-bind-html='trustAsHtml(compiledContent.val)'></div> + <div ng-if='isSrcMode.val'> <ui-codemirror ng-model='unsavedContent.val' ui-codemirror-opts='uicmOptions'></ui-codemirror> <p class='help-block'> Describe the object thoroughly using <a href="http://docutils.sourceforge.net/rst.html">reStructuredText mark-up</a><br><i class="fa fa-thumbs-up"></i> The ruler at 80 columns indicate suggested <a href="https://en.wikipedia.org/wiki/POSIX">POSIX line breaks</a> (for readability).<br><i class="fa fa-thumbs-up"></i> The editor will automatically enlarge to accomodate the entirety of your input<br><i class="fa fa-thumbs-up"></i> Use <a href="http://codemirror.net/doc/manual.html#commands">keyboard shortcuts</a> for search/replace and faster editing. For example, use Ctrl-F (PC) or Cmd-F (Mac) to search through this box @@ -127,19 +116,19 @@ angular.module('reportApp') <div class='col-sm-2'> <div class="pull-right action-buttons"> <a - ng-if='!isEditing.val' - ng-click='isEditing.val = !isEditing.val' + ng-if='!isSrcMode.val' + ng-click='isSrcMode.val = !isSrcMode.val' class="btn btn-primary btn-sm"> <i class="fa fa-edit fa-lg"></i> Edit </a> <a - ng-if='isEditing.val' + ng-if='isSrcMode.val' ng-click='cancelAction()' class="btn btn-danger btn-sm"> <i class="fa fa-times fa-lg"></i> Cancel </a> <a - ng-if='isEditing.val' + ng-if='isSrcMode.val' ng-click='saveAction()' class="btn btn-success btn-sm"> <i class="fa fa-save fa-lg"></i> Save @@ -147,7 +136,16 @@ angular.module('reportApp') </div> </div> </div> - </div> + <div ng-if='isViewmode()' class='row'> + <div class='col-sm-12'> + <div ng-if='!isSrcMode.val' ng-bind-html='trustAsHtml(compiledContent.val)'></div> + <div ng-if='isSrcMode.val'> + <i>Readonly view</i> + <ui-codemirror ng-model='item.content.text' ui-codemirror-opts='uicmOptions'></ui-codemirror> + </div> + </div> + </div> + </content> </div> ` }; diff --git a/beat/web/reports/static/reports/app/directives/view/itemContainer.js b/beat/web/reports/static/reports/app/directives/view/itemContainer.js deleted file mode 100644 index ad80156fc0bec09e50026c2cfb6a7b73fee49cd6..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/view/itemContainer.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupItemContainer - * Desc: - * container for an item in the group. - * depending of the type of the item (found in the item's id) - * it creates a table, plot, or text item - */ -angular.module('reportApp') -.directive("groupItemContainer", [function(){ - return { - scope: { - group: '=', - reportItem: '=' - }, - link: function(scope){ - scope.item = scope.reportItem; - // report-wide-unique prefix for the item to use - scope.domId = `${scope.group.name}_${scope.id}`; - }, - template: ` -<div - group-table-item - ng-if="item.id.includes('table')" - class='panel panel-default' - group='group' - item-id='item.id' - content='item.content' - > -</div> -<div - group-plot-item - ng-if="item.id.includes('plot')" - class='panel panel-default' - group='group' - item-id='item.id' - content='item.content' - > -</div> -<div - group-text-item - ng-if="item.id.includes('text')" - class='panel panel-default' - group='group' - report-item='item' - item-id='item.id' - > -</div> -` - }; -}]); diff --git a/beat/web/reports/static/reports/app/directives/view/panelContent.js b/beat/web/reports/static/reports/app/directives/view/panelContent.js deleted file mode 100644 index e3a58c72ce198bd0d8d07a7bbf0a3b659f6ba734..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/view/panelContent.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupPanelContent - * Desc: - * presents the group to the user in logical blocks: - * - a panel holds content - * - panel header contains an (editable) group name label - * - panel header also contains the buttons to add report items - * - two sub-panels are added: the experiments list, and the items list - */ -angular.module('reportApp').directive("groupPanelContent", ['GroupsService', function(GroupsService){ - return { - scope: { - group: '=' - }, - link: function(scope){ - }, - template: ` -<div id="{{group.name}}-heading" class="panel-heading" role="tab"> - <h4 class="panel-title"> - <a - class='collapsed' - role="button" - data-toggle="collapse" - data-parent="#{{group.name}}-heading" - href="#collapse-{{group.name}}" - aria-expanded="false" - aria-controls="collapse-{{group.name}}"> - {{ group.name }} - </a> - </h4> -</div> -<div id="collapse-{{group.name}}" - class="panel-collapse collapse" - role="tabpanel" - aria-labelledby="{{group.name}}-heading"> - <div class="panel-body panel-group"> - <div group-panel-experiments class='panel panel-default' group='group'></div> - <group-panel-items group='group'></group-panel-items> - </div> -</div> -` - }; -}]); - diff --git a/beat/web/reports/static/reports/app/directives/view/textItem.js b/beat/web/reports/static/reports/app/directives/view/textItem.js deleted file mode 100644 index e03d56a804b5f40089f2ec61d1603bf708698f7e..0000000000000000000000000000000000000000 --- a/beat/web/reports/static/reports/app/directives/view/textItem.js +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/ - * Contact: beat.support@idiap.ch - * - * This file is part of the beat.web module of the BEAT platform. - * - * Commercial License Usage - * Licensees holding valid commercial BEAT licenses may use this file in - * accordance with the terms contained in a written agreement between you - * and Idiap. For further information contact tto@idiap.ch - * - * Alternatively, this file may be used under the terms of the GNU Affero - * Public License version 3 as published by the Free Software and appearing - * in the file LICENSE.AGPL included in the packaging of this file. - * The BEAT platform is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero Public License along - * with the BEAT platform. If not, see http://www.gnu.org/licenses/. - */ - -/* - * groupTextItem - * Desc: - * displays a text report item: - * - sends the raw RST to the server to be compiled, - * and displays the returned HTML - * - the user can edit the RST using codemirror - * - the compile is async and doesnt require refreshing the page - */ -angular.module('reportApp') -.directive("groupTextItem", ['GroupsService', '$sce', 'UrlService', 'reportFactory', function(GroupsService, $sce, UrlService, reportFactory){ - return { - scope: { - group: '=', - reportItem: '=', - }, - link: function(scope){ - // aliases - // angular requires that compiling raw html be sanitized - scope.trustAsHtml = $sce.trustAsHtml; - scope.item = scope.reportItem; - scope.domId = `${scope.group.name}_${scope.item.id}`; - - // readonly codemirror options - scope.srccmOptions = { - mode: 'rst', - readOnly: true - }; - - // handle compiling content - // holds the last response from the server - scope.compiledContent = { val: '' }; - scope.compileContent = () => { - let url = UrlService.getCompileRstUrl(); - let mapToTextBlock = `${scope.group.name}|${scope.group.reportItems.indexOf(scope.reportItem)}`; - - return reportFactory.compileRST(url, mapToTextBlock) - .then(data => { - // when compiled, save the raw html - scope.compiledContent.val = data.data.html_str; - }); - }; - - // handle toggling between html & rst view - scope.isViewingSrc = { val: false }; - - // compile the content when loaded - scope.compileContent(); - }, - template: ` -<div id="{{domId}}-heading" class="panel-heading" role="tab"> - <h4 class="panel-title"> - <a - class='' - role="button" - data-toggle="collapse" - data-parent="#{{domId}}-heading" - href="#collapse-{{domId}}" - aria-expanded="true" - aria-controls="collapse-{{domId}}"> - {{ item.content.itemName }} - </a> - <button class='btn btn-primary' ng-click='isViewingSrc.val = !isViewingSrc.val'> - Toggle Source View - </button> - </h4> -</div> -<div id="collapse-{{domId}}" - class="panel-collapse collapse in" - role="tabpanel" - aria-labelledby="{{domId}}-heading"> - <div class='panel-body'> - <div class='row'> - <div class='col-sm-12'> - <div ng-if='!isViewingSrc.val' ng-bind-html='trustAsHtml(compiledContent.val)'></div> - <div ng-if='isViewingSrc.val'> - <i>Readonly view</i> - <ui-codemirror ng-model='item.content.text' ui-codemirror-opts='srccmOptions'></ui-codemirror> - </div> - </div> - </div> - </div> -</div> -` - }; -}]); diff --git a/beat/web/reports/templates/reports/report.html b/beat/web/reports/templates/reports/report.html index 35eb58321825cc82720b245c8e48893934a38175..bdaebcf58feb42cf19d3fab46a5e721222b725f5 100644 --- a/beat/web/reports/templates/reports/report.html +++ b/beat/web/reports/templates/reports/report.html @@ -95,7 +95,6 @@ <!-- directives --> <!-- new --> - <script src="{% fingerprint "reports/app/directives/tableItem.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/downloadLink.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/bootstrapModal.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/publish.js" %}" type="text/javascript" charset="utf-8"></script> @@ -106,28 +105,22 @@ <script src="{% fingerprint "reports/app/directives/lastEdited.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/editableLabel.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/panelExperiments.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/panelContainer.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/dragHandle.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/panelContent.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/panelItems.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/layout.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/tableItem.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/plotItem.js" %}" type="text/javascript" charset="utf-8"></script> + <script src="{% fingerprint "reports/app/directives/textItem.js" %}" type="text/javascript" charset="utf-8"></script> <!-- edit view --> {% if not report_number and report.get_status_display == 'Editable' and owner %} <script src="{% fingerprint "reports/app/directives/edit/addGroupMenu.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/edit/addItemsMenu.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/itemContainer.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/layout.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/panelContent.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/panelItems.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/plotItem.js" %}" type="text/javascript" charset="utf-8"></script> <script src="{% fingerprint "reports/app/directives/edit/tableFieldSelector.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/tableItem.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/edit/textItem.js" %}" type="text/javascript" charset="utf-8"></script> {% else %} <!-- readonly view --> - <script src="{% fingerprint "reports/app/directives/view/layout.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/view/panelContent.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/view/panelItems.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/view/itemContainer.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/view/plotItem.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/view/tableItem.js" %}" type="text/javascript" charset="utf-8"></script> - <script src="{% fingerprint "reports/app/directives/view/textItem.js" %}" type="text/javascript" charset="utf-8"></script> {% endif %} <script src="{% fingerprint "ui/js/smartselector.js" %}" type="text/javascript" charset="utf-8"></script>