diff --git a/CODESCRATCH.md b/CODESCRATCH.md new file mode 100644 index 00000000..eaf25332 --- /dev/null +++ b/CODESCRATCH.md @@ -0,0 +1,6 @@ +# Codescratch changes + +1. Bug fix if `adfWidgetModalOptions` was undefined. +2. Adding `adfDashboardStructureChange` event. +3. Adding `Edit` and `Save` text to title icons. +4. Adding title link option so that you can link somewhere in the title. diff --git a/dist/angular-dashboard-framework-tpls.js b/dist/angular-dashboard-framework-tpls.js index 9f0c6c07..e941776a 100644 --- a/dist/angular-dashboard-framework-tpls.js +++ b/dist/angular-dashboard-framework-tpls.js @@ -34,7 +34,7 @@ angular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap']) angular.module("adf").run(["$templateCache", function($templateCache) {$templateCache.put("../src/templates/dashboard-column.html","
"); $templateCache.put("../src/templates/dashboard-edit.html"," "); $templateCache.put("../src/templates/dashboard-row.html","
"); -$templateCache.put("../src/templates/dashboard-title.html","

{{model.title}}

"); +$templateCache.put("../src/templates/dashboard-title.html","

{{model.title}} {{!editMode ? \'Edit\' : \'Save\' }}

"); $templateCache.put("../src/templates/dashboard.html","
"); $templateCache.put("../src/templates/structure-preview.html","

{{name}}

"); $templateCache.put("../src/templates/widget-add.html"," "); @@ -458,6 +458,46 @@ angular.module('adf') } }]); +/* +* The MIT License +* +* Copyright (c) 2015, Sebastian Sdorra +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + + +/* global angular */ +angular.module('adf') + .filter('adfOrderByObjectKey', ["$filter", function($filter) { + + + return function(item, key){ + var array = []; + angular.forEach(item, function(value, objectKey){ + value[key] = objectKey; + array.push(value); + }); + return $filter('orderBy')(array, key); + }; + }]); + /* * The MIT License * @@ -1012,6 +1052,7 @@ angular.module('adf') * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard. * @param {string=} structure the default structure of the dashboard. * @param {object=} adfModel model object of the dashboard. + * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal * @param {function=} adfWidgetFilter function to filter widgets on the add dialog. * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove * events during edit mode not reset it if edit mode is exited. @@ -1036,6 +1077,7 @@ angular.module('adf') continuousEditMode: '=', maximizable: '@', adfModel: '=', + adfAddWidgetModalOptions: '=', adfWidgetFilter: '=', categories: '@' }, @@ -1180,6 +1222,7 @@ angular.module('adf') if (model.structure !== name){ model.structure = name; } + $rootScope.$broadcast('adfDashboardStructureChange'); }; editDashboardScope.closeDialog = function(){ // copy the new title back to the model @@ -1227,6 +1270,10 @@ angular.module('adf') backdrop: 'static' }; + if (angular.isDefined($scope.adfAddWidgetModalOptions)) { + opts = angular.merge(opts, $scope.adfAddWidgetModalOptions); + } + var instance = $uibModal.open(opts); addScope.addWidget = function(widget){ var w = { @@ -1526,46 +1573,6 @@ angular.module('adf') }]); -/* -* The MIT License -* -* Copyright (c) 2015, Sebastian Sdorra -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - - -/* global angular */ -angular.module('adf') - .filter('adfOrderByObjectKey', ["$filter", function($filter) { - - - return function(item, key){ - var array = []; - angular.forEach(item, function(value, objectKey){ - value[key] = objectKey; - array.push(value); - }); - return $filter('orderBy')(array, key); - }; - }]); - /* * The MIT License * diff --git a/dist/angular-dashboard-framework-tpls.min.js b/dist/angular-dashboard-framework-tpls.min.js index de2062dd..b2698feb 100644 --- a/dist/angular-dashboard-framework-tpls.min.js +++ b/dist/angular-dashboard-framework-tpls.min.js @@ -1,2 +1,2 @@ -!function(e,t){"use strict";angular.module("adf",["adf.provider","adf.locale","ui.bootstrap"]).value("adfTemplatePath","../src/templates/").value("rowTemplate",'').value("columnTemplate",'').value("adfVersion","0.13.0-SNAPSHOT"),angular.module("adf").run(["$templateCache",function(e){e.put("../src/templates/dashboard-column.html",'
'),e.put("../src/templates/dashboard-edit.html",' '),e.put("../src/templates/dashboard-row.html","
"),e.put("../src/templates/dashboard-title.html",'

{{model.title}}

'),e.put("../src/templates/dashboard.html",'
'),e.put("../src/templates/structure-preview.html",'

{{name}}

'),e.put("../src/templates/widget-add.html",' '),e.put("../src/templates/widget-delete.html",' '),e.put("../src/templates/widget-edit.html",'
'),e.put("../src/templates/widget-fullscreen.html",' '),e.put("../src/templates/widget-title.html",'

{{definition.title}}

'),e.put("../src/templates/widget.html",'
')}]),angular.module("adf").factory("widgetService",["$http","$q","$sce","$templateCache","dashboard",function(e,t,a,i,o){function l(e){var t=e;return e.indexOf("{widgetsPath}")>=0&&(t=e.replace("{widgetsPath}",o.widgetsPath).replace("//","/"),0===t.indexOf("/")&&(t=t.substring(1))),t}var n={};return n.getTemplate=function(o){var n=t.defer();if(o.template)n.resolve(o.template);else if(o.templateUrl){var d=i.get(o.templateUrl);if(d)n.resolve(d);else{var r=a.getTrustedResourceUrl(l(o.templateUrl));e.get(r).then(function(e){return e.data}).then(function(e){i.put(o.templateUrl,e),n.resolve(e)})["catch"](function(){n.reject("could not load template")})}}return n.promise},n}]),angular.module("adf").factory("adfUtilsService",function(){function e(e){switch(angular.isString(e)?e.toLowerCase():null){case"true":case"yes":case"1":return!0;case"false":case"no":case"0":case null:return!1;default:return Boolean(e)}}function t(e,t){var a=[],i=0;return angular.forEach(e,function(e,o){var l=i++%t;a[l]||(a[l]={}),a[l][o]=e}),a}var a={stringToBoolean:e,split:t};return a}),angular.module("adf").factory("adfStructurePreviewService",function(){function e(t){if(t.rows&&t.rows.length>0){var a=100/t.rows.length;angular.forEach(t.rows,function(t){t.style={height:a+"%"},t.columns&&angular.forEach(t.columns,function(t){e(t)})})}}var t={adjustRowHeight:e};return t}),angular.module("adf").factory("adfDashboardService",["$log","dashboard","$rootScope",function(e,t,a){function i(e,t){if(e.widgets&&e.widgets.length>0)for(var a=e.widgets.shift();a;)t.widgets.push(a),a=e.widgets.shift()}function o(e,t,a){return a=a||0,angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.widgets||(e.widgets=[]),angular.isDefined(t[a])&&angular.isUndefined(e.rows)&&(i(t[a],e),a++),a=o(e,t,a)})}),a}function l(e,t){return t=t||[],angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.hasOwnProperty("rows")||t.push(e),l(e,t)})}),t}function n(e,t){var a=l(e),i=0;for(e.rows=angular.copy(t.rows);i=0&&e.widgets.splice(t,1)}r.remove(),o.$broadcast("adfWidgetRemovedFromColumn",s)};d.remove=function(){if(d.options.enableConfirmDelete){var e=d.$new();e.translate=l.translate;var t=n+"widget-delete.html";s.deleteTemplateUrl&&(t=s.deleteTemplateUrl);var a={scope:e,templateUrl:t,windowClass:"adf-remove-widget-modal",backdrop:"static"},o=i.open(a);e.closeDialog=function(){o.close(),e.$destroy()},e.deleteDialog=function(){c(),e.closeDialog()}}else c()},d.reload=function(){d.$broadcast("widgetReload")},d.edit=function(){function a(e){var a;if("boolean"==typeof e){var i=t.defer();e?i.resolve():i.reject(),a=i.promise}else a=t.when(e);return a}var o=d.$new();o.translate=l.translate,o.definition=angular.copy(s);var r=n+"widget-edit.html";s.editTemplateUrl&&(r=s.editTemplateUrl);var c={scope:o,templateUrl:r,windowClass:"adf-edit-widget-modal",backdrop:"static"},u=i.open(c);o.closeDialog=function(){u.close(),o.$destroy()},o.saveDialog=function(){o.validationError=null;var t,i=d.widget;t=i.edit?i.edit.apply:function(){return!0};var l={widget:i,definition:o.definition,config:o.definition.config},n=e.invoke(t,t,l);a(n).then(function(){s.title=o.definition.title,angular.extend(s.config,o.definition.config),i.edit&&i.edit.reload&&d.$broadcast("widgetConfigChanged"),o.closeDialog()},function(e){e?o.validationError=e:o.validationError="Validation durring apply failed"})}}}else a.debug("widget not found")}function s(e){e.$on("adfDashboardCollapseExpand",function(t,a){e.widgetState.isCollapsed=a.collapseExpandStatus}),e.$on("adfWidgetEnterEditMode",function(t,a){l.idEquals(e.definition.wid,a.wid)&&e.edit()}),e.widgetClasses=function(t,a){var i=a.styleClass||"";return t&&t.frameless&&!e.editMode||(i+=" panel panel-default"),i},e.openFullScreen=function(){var t=e.definition,a=e.$new(),o={scope:a,templateUrl:n+"widget-fullscreen.html",size:t.modalSize||"lg",backdrop:"static",windowClass:t.fullScreen?"dashboard-modal widget-fullscreen":"dashboard-modal"},l=i.open(o);a.closeDialog=function(){l.close(),a.$destroy()}}}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,templateUrl:l.customWidgetTemplatePath?l.customWidgetTemplatePath:n+"widget.html",scope:{adfModel:"=",definition:"=",col:"=column",editMode:"=",options:"=",widgetState:"="},controller:s,compile:function(){return{pre:d,post:r}}}}]),angular.module("adf").directive("adfWidgetContent",["$log","$q","widgetService","$compile","$controller","$injector","dashboard",function(e,t,a,i,o,l,n){function d(t,a){e.warn(a),t.html(n.messageTemplate.replace(/{}/g,a))}function r(e,t,a){var i=e.model,o=e.content,l=a;if(i)if(o)l=s(e,t,a,i,o);else{var n="widget content is undefined, please have a look at your browser log";d(t,n)}else d(t,"model is undefined");return l}function s(e,r,s,c,u){r.html(n.loadingTemplate);var g=e.$new();c.config||(c.config={}),g.config=c.config;var f={$scope:g,widget:c,config:c.config},p={};return p.$tpl=a.getTemplate(u),u.resolve&&angular.forEach(u.resolve,function(e,t){angular.isString(e)?p[t]=l.get(e):p[t]=l.invoke(e,e,f)}),t.all(p).then(function(e){angular.extend(e,f),u.resolveAs&&(g[u.resolveAs]=e);var t=e.$tpl;if(r.html(t),u.controller){var a=o(u.controller,e);u.controllerAs&&(g[u.controllerAs]=a),r.children().data("$ngControllerController",a)}i(r.contents())(g)},function(e){var t="Could not resolve all promises";e&&(t+=": "+e),d(r,t)}),s&&s.$destroy(),g}function c(e,t){var a=r(e,t,null);e.$on("widgetConfigChanged",function(){a=r(e,t,a)}),e.$on("widgetReload",function(){a=r(e,t,a)})}return{replace:!0,restrict:"EA",transclude:!1,scope:{adfModel:"=",model:"=",content:"="},link:c}}]),angular.module("adf").directive("adfStructurePreview",["adfTemplatePath","adfStructurePreviewService",function(e,t){function a(e){var a=angular.copy(e.structure);t.adjustRowHeight(a),e.preview=a}return{restrict:"E",replace:!0,scope:{name:"=",structure:"=",selected:"="},templateUrl:e+"structure-preview.html",link:a}}]),angular.module("adf").directive("adfDashboard",["$rootScope","$log","$timeout","$uibModal","dashboard","adfTemplatePath","adfDashboardService","adfUtilsService",function(e,t,a,i,o,l,n,d){function r(e,t){a(function(){e.$broadcast("adfWidgetEnterEditMode",t)},200)}function s(a){function s(){var e=a.$new();return e.translate=o.translate,e}var c={},u={},g=null,f={},p=a.name;a.$watch("adfModel",function(e,i){(null!==i||null===e&&null===i)&&(c=a.adfModel,g=a.adfWidgetFilter,c&&c.rows||(f=a.structure,u=o.structures[f],u?(c?c.rows=angular.copy(u).rows:c=angular.copy(u),c.structure=f):t.error("could not find structure "+f)),c?(c.title||(c.title="Dashboard"),c.titleTemplateUrl||(c.titleTemplateUrl=l+"dashboard-title.html"),a.model=c):t.error("could not find or create model"))},!0),a.editMode=!1,a.editClass="",a.translate=o.translate,a.toggleEditMode=function(){a.editMode=!a.editMode,a.editMode&&(a.continuousEditMode||(a.modelCopy=angular.copy(a.adfModel,{}),e.$broadcast("adfIsEditMode"))),a.editMode||e.$broadcast("adfDashboardChanged",p,c)},a.$on("adfToggleEditMode",function(){a.toggleEditMode()}),a.collapseAll=function(t){e.$broadcast("adfDashboardCollapseExpand",{collapseExpandStatus:t})},a.cancelEditMode=function(){a.editMode=!1,a.continuousEditMode||(a.modelCopy=angular.copy(a.modelCopy,a.adfModel)),e.$broadcast("adfDashboardEditsCancelled")},a.editDashboardDialog=function(){var e=s();e.copy={title:c.title},e.structures=o.structures,e.split=d.split;var a=l+"dashboard-edit.html";c.editTemplateUrl&&(a=c.editTemplateUrl);var r=i.open({scope:e,templateUrl:a,backdrop:"static",windowClass:"adf-edit-dashboard-modal",size:"lg"});e.changeStructure=function(e,a){t.info("change structure to "+e),n.changeStructure(c,a),c.structure!==e&&(c.structure=e)},e.closeDialog=function(){c.title=e.copy.title,r.close(),e.$destroy()}},a.addWidgetDialog=function(){var e,t=s(),d=a.model;angular.isFunction(g)?(e={},angular.forEach(o.widgets,function(t,a){g(t,a,d)&&(e[a]=t)})):e=o.widgets,t.widgets=e,t.translate=a.translate,a.options.categories&&(a.createCategories=n.createCategories);var c=l+"widget-add.html";d.addTemplateUrl&&(c=d.addTemplateUrl);var u={scope:t,templateUrl:c,windowClass:"adf-add-widget-modal",backdrop:"static"},f=i.open(u);t.addWidget=function(e){var i={type:e,config:n.createConfiguration(e)};n.addNewWidgetToModel(d,i,p),f.close(),t.$destroy(),n.isEditModeImmediate(e)&&r(a,i)},t.closeDialog=function(){f.close(),t.$destroy()}},a.addNewWidgetToModel=n.addNewWidgetToModel}function c(e,t,a){var i={name:a.name,editable:!0,enableConfirmDelete:d.stringToBoolean(a.enableConfirmDelete),maximizable:d.stringToBoolean(a.maximizable),collapsible:d.stringToBoolean(a.collapsible),categories:d.stringToBoolean(a.categories)};angular.isDefined(a.editable)&&(i.editable=d.stringToBoolean(a.editable)),e.options=i}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,scope:{structure:"@",name:"@",collapsible:"@",editable:"@",editMode:"@",continuousEditMode:"=",maximizable:"@",adfModel:"=",adfWidgetFilter:"=",categories:"@"},controller:s,link:c,templateUrl:l+"dashboard.html"}}]),angular.module("adf").directive("adfDashboardRow",["$compile","adfTemplatePath","columnTemplate",function(e,t,a){function i(t,i){angular.isDefined(t.row.columns)&&angular.isArray(t.row.columns)&&e(a)(t,function(e){i.append(e)})}return{restrict:"E",replace:!0,scope:{row:"=",adfModel:"=",editMode:"=",continuousEditMode:"=",options:"="},templateUrl:t+"dashboard-row.html",link:i}}]),angular.module("adf").directive("adfDashboardColumn",["$log","$compile","$rootScope","adfTemplatePath","rowTemplate","dashboard",function(e,t,a,i,o,l){function n(e,t,i){var o=t.widgets;e.$apply(function(){o.splice(i.newIndex,0,o.splice(i.oldIndex,1)[0]),a.$broadcast("adfWidgetMovedInColumn")})}function d(e,t){for(var a=null,i=0;i{}',r='
\n
\n loading ...\n
\n
',s=null,c=function(){return!0},u=e.defaultLocale,g=e.frameworkLocales;this.widget=function(e,t){var a=angular.extend({reload:!1,frameless:!1},t);if(a.edit){var i={reload:!0,immediate:!1,apply:c};angular.extend(i,a.edit),a.edit=i}return o[e]=a,this},this.widgetsPath=function(e){return l=e,this},this.structure=function(e,t){return n[e]=t,this},this.messageTemplate=function(e){return d=e,this},this.loadingTemplate=function(e){return r=e,this},this.customWidgetTemplatePath=function(e){return s=e,this},this.setLocale=function(e){if(!g[e])throw new Error("Cannot set locale: "+e+". Locale is not defined.");return u=e,this},this.addLocale=function(e,t){if(!angular.isString(e))throw new Error("locale must be an string");if(!angular.isObject(t))throw new Error("translations must be an object");return g[e]=t,this},this.$get=function(){var e=0;return{widgets:o,widgetsPath:l,structures:n,messageTemplate:d,loadingTemplate:r,setLocale:this.setLocale,locales:t,activeLocale:a,translate:i,customWidgetTemplatePath:s,id:function(){return(new Date).getTime()+"-"+ ++e},idEquals:function(e,t){return e&&t&&e.toString()===t.toString()}}}}]),angular.module("adf.locale",[]),angular.module("adf.locale").constant("adfLocale",{defaultLocale:"en-GB",frameworkLocales:{"en-GB":{ADF_COMMON_CLOSE:"Close",ADF_COMMON_DELETE:"Delete",ADF_COMMON_TITLE:"Title",ADF_COMMON_CANCEL:"Cancel",ADF_COMMON_APPLY:"Apply",ADF_COMMON_EDIT_DASHBOARD:"Edit dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Structure",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Add new widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Save changes",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Enable edit mode",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Undo changes",ADF_WIDGET_ADD_HEADER:"Add new widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Are you sure you want to delete this widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Reload widget Content",ADF_WIDGET_TOOLTIP_MOVE:"Change widget location",ADF_WIDGET_TOOLTIP_COLLAPSE:"Collapse widget",ADF_WIDGET_TOOLTIP_EXPAND:"Expand widget",ADF_WIDGET_TOOLTIP_EDIT:"Edit widget configuration",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Fullscreen widget",ADF_WIDGET_TOOLTIP_REMOVE:"Remove widget"},"sv-SE":{ADF_COMMON_CLOSE:"Stäng",ADF_COMMON_DELETE:"Ta bort",ADF_COMMON_TITLE:"Titel",ADF_COMMON_CANCEL:"Avbryt",ADF_COMMON_APPLY:"Använd",ADF_COMMON_EDIT_DASHBOARD:"Redigera dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Struktur",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Lägg till ny widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Spara förändringar",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Slå på redigeringsläge",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Ångra förändringar",ADF_WIDGET_ADD_HEADER:"Lägg till ny widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Är du säker på att du vill ta bort denna widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Ladda om widget",ADF_WIDGET_TOOLTIP_MOVE:"Ändra widgets position",ADF_WIDGET_TOOLTIP_COLLAPSE:"Stäng widget",ADF_WIDGET_TOOLTIP_EXPAND:"Öppna widget",ADF_WIDGET_TOOLTIP_EDIT:"Ändra widget konfigurering",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Visa widget i fullskärm",ADF_WIDGET_TOOLTIP_REMOVE:"Ta bort widget"}}})}(window); +!function(e,t){"use strict";angular.module("adf",["adf.provider","adf.locale","ui.bootstrap"]).value("adfTemplatePath","../src/templates/").value("rowTemplate",'').value("columnTemplate",'').value("adfVersion","0.13.0-SNAPSHOT"),angular.module("adf").run(["$templateCache",function(e){e.put("../src/templates/dashboard-column.html",'
'),e.put("../src/templates/dashboard-edit.html",' '),e.put("../src/templates/dashboard-row.html","
"),e.put("../src/templates/dashboard-title.html",'

{{model.title}} {{!editMode ? \'Edit\' : \'Save\' }}

'),e.put("../src/templates/dashboard.html",'
'),e.put("../src/templates/structure-preview.html",'

{{name}}

'),e.put("../src/templates/widget-add.html",' '),e.put("../src/templates/widget-delete.html",' '),e.put("../src/templates/widget-edit.html",'
'),e.put("../src/templates/widget-fullscreen.html",' '),e.put("../src/templates/widget-title.html",'

{{definition.title}}

'),e.put("../src/templates/widget.html",'
')}]),angular.module("adf").factory("widgetService",["$http","$q","$sce","$templateCache","dashboard",function(e,t,a,i,o){function l(e){var t=e;return e.indexOf("{widgetsPath}")>=0&&(t=e.replace("{widgetsPath}",o.widgetsPath).replace("//","/"),0===t.indexOf("/")&&(t=t.substring(1))),t}var n={};return n.getTemplate=function(o){var n=t.defer();if(o.template)n.resolve(o.template);else if(o.templateUrl){var d=i.get(o.templateUrl);if(d)n.resolve(d);else{var r=a.getTrustedResourceUrl(l(o.templateUrl));e.get(r).then(function(e){return e.data}).then(function(e){i.put(o.templateUrl,e),n.resolve(e)})["catch"](function(){n.reject("could not load template")})}}return n.promise},n}]),angular.module("adf").factory("adfUtilsService",function(){function e(e){switch(angular.isString(e)?e.toLowerCase():null){case"true":case"yes":case"1":return!0;case"false":case"no":case"0":case null:return!1;default:return Boolean(e)}}function t(e,t){var a=[],i=0;return angular.forEach(e,function(e,o){var l=i++%t;a[l]||(a[l]={}),a[l][o]=e}),a}var a={stringToBoolean:e,split:t};return a}),angular.module("adf").factory("adfStructurePreviewService",function(){function e(t){if(t.rows&&t.rows.length>0){var a=100/t.rows.length;angular.forEach(t.rows,function(t){t.style={height:a+"%"},t.columns&&angular.forEach(t.columns,function(t){e(t)})})}}var t={adjustRowHeight:e};return t}),angular.module("adf").factory("adfDashboardService",["$log","dashboard","$rootScope",function(e,t,a){function i(e,t){if(e.widgets&&e.widgets.length>0)for(var a=e.widgets.shift();a;)t.widgets.push(a),a=e.widgets.shift()}function o(e,t,a){return a=a||0,angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.widgets||(e.widgets=[]),angular.isDefined(t[a])&&angular.isUndefined(e.rows)&&(i(t[a],e),a++),a=o(e,t,a)})}),a}function l(e,t){return t=t||[],angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.hasOwnProperty("rows")||t.push(e),l(e,t)})}),t}function n(e,t){var a=l(e),i=0;for(e.rows=angular.copy(t.rows);i=0&&e.widgets.splice(t,1)}r.remove(),o.$broadcast("adfWidgetRemovedFromColumn",s)};d.remove=function(){if(d.options.enableConfirmDelete){var e=d.$new();e.translate=l.translate;var t=n+"widget-delete.html";s.deleteTemplateUrl&&(t=s.deleteTemplateUrl);var a={scope:e,templateUrl:t,windowClass:"adf-remove-widget-modal",backdrop:"static"},o=i.open(a);e.closeDialog=function(){o.close(),e.$destroy()},e.deleteDialog=function(){c(),e.closeDialog()}}else c()},d.reload=function(){d.$broadcast("widgetReload")},d.edit=function(){function a(e){var a;if("boolean"==typeof e){var i=t.defer();e?i.resolve():i.reject(),a=i.promise}else a=t.when(e);return a}var o=d.$new();o.translate=l.translate,o.definition=angular.copy(s);var r=n+"widget-edit.html";s.editTemplateUrl&&(r=s.editTemplateUrl);var c={scope:o,templateUrl:r,windowClass:"adf-edit-widget-modal",backdrop:"static"},u=i.open(c);o.closeDialog=function(){u.close(),o.$destroy()},o.saveDialog=function(){o.validationError=null;var t,i=d.widget;t=i.edit?i.edit.apply:function(){return!0};var l={widget:i,definition:o.definition,config:o.definition.config},n=e.invoke(t,t,l);a(n).then(function(){s.title=o.definition.title,angular.extend(s.config,o.definition.config),i.edit&&i.edit.reload&&d.$broadcast("widgetConfigChanged"),o.closeDialog()},function(e){e?o.validationError=e:o.validationError="Validation durring apply failed"})}}}else a.debug("widget not found")}function s(e){e.$on("adfDashboardCollapseExpand",function(t,a){e.widgetState.isCollapsed=a.collapseExpandStatus}),e.$on("adfWidgetEnterEditMode",function(t,a){l.idEquals(e.definition.wid,a.wid)&&e.edit()}),e.widgetClasses=function(t,a){var i=a.styleClass||"";return t&&t.frameless&&!e.editMode||(i+=" panel panel-default"),i},e.openFullScreen=function(){var t=e.definition,a=e.$new(),o={scope:a,templateUrl:n+"widget-fullscreen.html",size:t.modalSize||"lg",backdrop:"static",windowClass:t.fullScreen?"dashboard-modal widget-fullscreen":"dashboard-modal"},l=i.open(o);a.closeDialog=function(){l.close(),a.$destroy()}}}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,templateUrl:l.customWidgetTemplatePath?l.customWidgetTemplatePath:n+"widget.html",scope:{adfModel:"=",definition:"=",col:"=column",editMode:"=",options:"=",widgetState:"="},controller:s,compile:function(){return{pre:d,post:r}}}}]),angular.module("adf").directive("adfWidgetContent",["$log","$q","widgetService","$compile","$controller","$injector","dashboard",function(e,t,a,i,o,l,n){function d(t,a){e.warn(a),t.html(n.messageTemplate.replace(/{}/g,a))}function r(e,t,a){var i=e.model,o=e.content,l=a;if(i)if(o)l=s(e,t,a,i,o);else{var n="widget content is undefined, please have a look at your browser log";d(t,n)}else d(t,"model is undefined");return l}function s(e,r,s,c,u){r.html(n.loadingTemplate);var g=e.$new();c.config||(c.config={}),g.config=c.config;var f={$scope:g,widget:c,config:c.config},p={};return p.$tpl=a.getTemplate(u),u.resolve&&angular.forEach(u.resolve,function(e,t){angular.isString(e)?p[t]=l.get(e):p[t]=l.invoke(e,e,f)}),t.all(p).then(function(e){angular.extend(e,f),u.resolveAs&&(g[u.resolveAs]=e);var t=e.$tpl;if(r.html(t),u.controller){var a=o(u.controller,e);u.controllerAs&&(g[u.controllerAs]=a),r.children().data("$ngControllerController",a)}i(r.contents())(g)},function(e){var t="Could not resolve all promises";e&&(t+=": "+e),d(r,t)}),s&&s.$destroy(),g}function c(e,t){var a=r(e,t,null);e.$on("widgetConfigChanged",function(){a=r(e,t,a)}),e.$on("widgetReload",function(){a=r(e,t,a)})}return{replace:!0,restrict:"EA",transclude:!1,scope:{adfModel:"=",model:"=",content:"="},link:c}}]),angular.module("adf").directive("adfStructurePreview",["adfTemplatePath","adfStructurePreviewService",function(e,t){function a(e){var a=angular.copy(e.structure);t.adjustRowHeight(a),e.preview=a}return{restrict:"E",replace:!0,scope:{name:"=",structure:"=",selected:"="},templateUrl:e+"structure-preview.html",link:a}}]),angular.module("adf").directive("adfDashboard",["$rootScope","$log","$timeout","$uibModal","dashboard","adfTemplatePath","adfDashboardService","adfUtilsService",function(e,t,a,i,o,l,n,d){function r(e,t){a(function(){e.$broadcast("adfWidgetEnterEditMode",t)},200)}function s(a){function s(){var e=a.$new();return e.translate=o.translate,e}var c={},u={},g=null,f={},p=a.name;a.$watch("adfModel",function(e,i){(null!==i||null===e&&null===i)&&(c=a.adfModel,g=a.adfWidgetFilter,c&&c.rows||(f=a.structure,u=o.structures[f],u?(c?c.rows=angular.copy(u).rows:c=angular.copy(u),c.structure=f):t.error("could not find structure "+f)),c?(c.title||(c.title="Dashboard"),c.titleTemplateUrl||(c.titleTemplateUrl=l+"dashboard-title.html"),a.model=c):t.error("could not find or create model"))},!0),a.editMode=!1,a.editClass="",a.translate=o.translate,a.toggleEditMode=function(){a.editMode=!a.editMode,a.editMode&&(a.continuousEditMode||(a.modelCopy=angular.copy(a.adfModel,{}),e.$broadcast("adfIsEditMode"))),a.editMode||e.$broadcast("adfDashboardChanged",p,c)},a.$on("adfToggleEditMode",function(){a.toggleEditMode()}),a.collapseAll=function(t){e.$broadcast("adfDashboardCollapseExpand",{collapseExpandStatus:t})},a.cancelEditMode=function(){a.editMode=!1,a.continuousEditMode||(a.modelCopy=angular.copy(a.modelCopy,a.adfModel)),e.$broadcast("adfDashboardEditsCancelled")},a.editDashboardDialog=function(){var a=s();a.copy={title:c.title},a.structures=o.structures,a.split=d.split;var r=l+"dashboard-edit.html";c.editTemplateUrl&&(r=c.editTemplateUrl);var u=i.open({scope:a,templateUrl:r,backdrop:"static",windowClass:"adf-edit-dashboard-modal",size:"lg"});a.changeStructure=function(a,i){t.info("change structure to "+a),n.changeStructure(c,i),c.structure!==a&&(c.structure=a),e.$broadcast("adfDashboardStructureChange")},a.closeDialog=function(){c.title=a.copy.title,u.close(),a.$destroy()}},a.addWidgetDialog=function(){var e,t=s(),d=a.model;angular.isFunction(g)?(e={},angular.forEach(o.widgets,function(t,a){g(t,a,d)&&(e[a]=t)})):e=o.widgets,t.widgets=e,t.translate=a.translate,a.options.categories&&(a.createCategories=n.createCategories);var c=l+"widget-add.html";d.addTemplateUrl&&(c=d.addTemplateUrl);var u={scope:t,templateUrl:c,windowClass:"adf-add-widget-modal",backdrop:"static"};angular.isDefined(a.adfAddWidgetModalOptions)&&(u=angular.merge(u,a.adfAddWidgetModalOptions));var f=i.open(u);t.addWidget=function(e){var i={type:e,config:n.createConfiguration(e)};n.addNewWidgetToModel(d,i,p),f.close(),t.$destroy(),n.isEditModeImmediate(e)&&r(a,i)},t.closeDialog=function(){f.close(),t.$destroy()}},a.addNewWidgetToModel=n.addNewWidgetToModel}function c(e,t,a){var i={name:a.name,editable:!0,enableConfirmDelete:d.stringToBoolean(a.enableConfirmDelete),maximizable:d.stringToBoolean(a.maximizable),collapsible:d.stringToBoolean(a.collapsible),categories:d.stringToBoolean(a.categories)};angular.isDefined(a.editable)&&(i.editable=d.stringToBoolean(a.editable)),e.options=i}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,scope:{structure:"@",name:"@",collapsible:"@",editable:"@",editMode:"@",continuousEditMode:"=",maximizable:"@",adfModel:"=",adfAddWidgetModalOptions:"=",adfWidgetFilter:"=",categories:"@"},controller:s,link:c,templateUrl:l+"dashboard.html"}}]),angular.module("adf").directive("adfDashboardRow",["$compile","adfTemplatePath","columnTemplate",function(e,t,a){function i(t,i){angular.isDefined(t.row.columns)&&angular.isArray(t.row.columns)&&e(a)(t,function(e){i.append(e)})}return{restrict:"E",replace:!0,scope:{row:"=",adfModel:"=",editMode:"=",continuousEditMode:"=",options:"="},templateUrl:t+"dashboard-row.html",link:i}}]),angular.module("adf").directive("adfDashboardColumn",["$log","$compile","$rootScope","adfTemplatePath","rowTemplate","dashboard",function(e,t,a,i,o,l){function n(e,t,i){var o=t.widgets;e.$apply(function(){o.splice(i.newIndex,0,o.splice(i.oldIndex,1)[0]),a.$broadcast("adfWidgetMovedInColumn")})}function d(e,t){for(var a=null,i=0;i{}',r='
\n
\n loading ...\n
\n
',s=null,c=function(){return!0},u=e.defaultLocale,g=e.frameworkLocales;this.widget=function(e,t){var a=angular.extend({reload:!1,frameless:!1},t);if(a.edit){var i={reload:!0,immediate:!1,apply:c};angular.extend(i,a.edit),a.edit=i}return o[e]=a,this},this.widgetsPath=function(e){return l=e,this},this.structure=function(e,t){return n[e]=t,this},this.messageTemplate=function(e){return d=e,this},this.loadingTemplate=function(e){return r=e,this},this.customWidgetTemplatePath=function(e){return s=e,this},this.setLocale=function(e){if(!g[e])throw new Error("Cannot set locale: "+e+". Locale is not defined.");return u=e,this},this.addLocale=function(e,t){if(!angular.isString(e))throw new Error("locale must be an string");if(!angular.isObject(t))throw new Error("translations must be an object");return g[e]=t,this},this.$get=function(){var e=0;return{widgets:o,widgetsPath:l,structures:n,messageTemplate:d,loadingTemplate:r,setLocale:this.setLocale,locales:t,activeLocale:a,translate:i,customWidgetTemplatePath:s,id:function(){return(new Date).getTime()+"-"+ ++e},idEquals:function(e,t){return e&&t&&e.toString()===t.toString()}}}}]),angular.module("adf.locale",[]),angular.module("adf.locale").constant("adfLocale",{defaultLocale:"en-GB",frameworkLocales:{"en-GB":{ADF_COMMON_CLOSE:"Close",ADF_COMMON_DELETE:"Delete",ADF_COMMON_TITLE:"Title",ADF_COMMON_CANCEL:"Cancel",ADF_COMMON_APPLY:"Apply",ADF_COMMON_EDIT_DASHBOARD:"Edit dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Structure",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Add new widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Save changes",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Enable edit mode",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Undo changes",ADF_WIDGET_ADD_HEADER:"Add new widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Are you sure you want to delete this widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Reload widget Content",ADF_WIDGET_TOOLTIP_MOVE:"Change widget location",ADF_WIDGET_TOOLTIP_COLLAPSE:"Collapse widget",ADF_WIDGET_TOOLTIP_EXPAND:"Expand widget",ADF_WIDGET_TOOLTIP_EDIT:"Edit widget configuration",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Fullscreen widget",ADF_WIDGET_TOOLTIP_REMOVE:"Remove widget"},"sv-SE":{ADF_COMMON_CLOSE:"Stäng",ADF_COMMON_DELETE:"Ta bort",ADF_COMMON_TITLE:"Titel",ADF_COMMON_CANCEL:"Avbryt",ADF_COMMON_APPLY:"Använd",ADF_COMMON_EDIT_DASHBOARD:"Redigera dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Struktur",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Lägg till ny widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Spara förändringar",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Slå på redigeringsläge",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Ångra förändringar",ADF_WIDGET_ADD_HEADER:"Lägg till ny widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Är du säker på att du vill ta bort denna widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Ladda om widget",ADF_WIDGET_TOOLTIP_MOVE:"Ändra widgets position",ADF_WIDGET_TOOLTIP_COLLAPSE:"Stäng widget",ADF_WIDGET_TOOLTIP_EXPAND:"Öppna widget",ADF_WIDGET_TOOLTIP_EDIT:"Ändra widget konfigurering",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Visa widget i fullskärm",ADF_WIDGET_TOOLTIP_REMOVE:"Ta bort widget"}}})}(window); //# sourceMappingURL=angular-dashboard-framework-tpls.min.js.map diff --git a/dist/angular-dashboard-framework-tpls.min.js.map b/dist/angular-dashboard-framework-tpls.min.js.map index 8f36316a..a7e3c03c 100644 --- a/dist/angular-dashboard-framework-tpls.min.js.map +++ b/dist/angular-dashboard-framework-tpls.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["adf.module.js","angular-dashboard-framework.tpl.js","services/widget.service.js","services/adf-utils.service.js","services/adf-structure-preview.service.js","services/adf-dashboard.service.js","directives/adf-widget.directive.js","angular-dashboard-framework-tpls.min.js","directives/adf-widget-content.directive.js","directives/adf-structure-preview.directive.js","directives/adf-dashboard.directive.js","directives/adf-dashboard-row.directive.js","directives/adf-dashboard-column.directive.js","filters/adf-order-by-object-key.filter.js","dashboard.provider.js","adf.locale.module.js","adf.locale.constants.js","angular-dashboard-framework-tpls.js"],"names":["window","undefined","angular","module","value","run","$templateCache","put","factory","$http","$q","$sce","dashboard","parseUrl","url","parsedUrl","indexOf","replace","widgetsPath","substring","exposed","getTemplate","widget","deferred","defer","template","resolve","templateUrl","tpl","get","getTrustedResourceUrl","then","response","data","reject","promise","stringToBoolean","string","isString","toLowerCase","Boolean","split","object","size","arr","i","forEach","key","index","service","adjustRowHeight","container","rows","length","height","row","style","columns","column","$log","$rootScope","_copyWidgets","source","target","widgets","w","shift","push","_fillStructure","root","counter","isDefined","isUndefined","_readColumns","col","hasOwnProperty","changeStructure","model","structure","copy","createConfiguration","type","cfg","config","_findFirstWidgetColumn","isArray","error","j","addNewWidgetToModel","name","unshift","$broadcast","isEditModeImmediate","edit","immediate","createCategories","categories","category","_tests","directive","$injector","$uibModal","adfTemplatePath","preLink","$scope","definition","translate","title","titleTemplateUrl","editTemplateUrl","frameless","styleClass","wid","id","fromJson","widgetState","isCollapsed","collapsed","warn","debug","postLink","$element","deleteWidget","splice","remove","options","enableConfirmDelete","deleteScope","$new","deleteTemplateUrl","opts","scope","windowClass","backdrop","instance","open","closeDialog","close","$destroy","deleteDialog","reload","createApplyPromise","result","when","editScope","adfEditTemplatePath","saveDialog","validationError","applyFn","apply","locals","invoke","extend","err","controller","$on","event","args","collapseExpandStatus","idEquals","widgetClasses","classes","editMode","openFullScreen","fullScreenScope","modalSize","$inject","restrict","transclude","customWidgetTemplatePath","adfModel","compile","pre","post","widgetService","$compile","$controller","renderError","msg","html","messageTemplate","compileWidget","currentScope","content","newScope","renderWidget","loadingTemplate","templateScope","base","resolvers","$tpl","all","resolveAs","templateCtrl","controllerAs","children","contents","reason","link","adfStructurePreviewService","preview","selected","$timeout","adfDashboardService","adfUtilsService","_openEditMode","getNewModalScope","widgetFilter","structureName","$watch","oldVal","newVal","adfWidgetFilter","structures","editClass","toggleEditMode","continuousEditMode","modelCopy","collapseAll","cancelEditMode","editDashboardDialog","editDashboardScope","info","addWidgetDialog","addScope","isFunction","adfAddTemplatePath","addTemplateUrl","addWidget","$attr","editable","maximizable","collapsible","columnTemplate","cloned","append","rowTemplate","moveWidgetInColumn","evt","$apply","newIndex","oldIndex","findWidget","findColumn","r","c","cid","getId","el","getAttribute","addWidgetToColumn","targetColumn","from","sourceColumn","item","removeWidgetFromColumn","applySortable","sortable","Sortable","create","group","handle","ghostClass","animation","onAdd","onRemove","onUpdate","on","destroy","filter","$filter","array","objectKey","provider","adfLocale","getLocales","locales","getActiveLocale","activeLocale","label","translation","defaultApplyFunction","defaultLocale","frameworkLocales","this","path","templatePath","setLocale","locale","Error","addLocale","translations","isObject","$get","Date","getTime","other","toString","constant","en-GB","ADF_COMMON_CLOSE","ADF_COMMON_DELETE","ADF_COMMON_TITLE","ADF_COMMON_CANCEL","ADF_COMMON_APPLY","ADF_COMMON_EDIT_DASHBOARD","ADF_EDIT_DASHBOARD_STRUCTURE_LABEL","ADF_DASHBOARD_TITLE_TOOLTIP_ADD","ADF_DASHBOARD_TITLE_TOOLTIP_SAVE","ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE","ADF_DASHBOARD_TITLE_TOOLTIP_UNDO","ADF_WIDGET_ADD_HEADER","ADF_WIDGET_DELETE_CONFIRM_MESSAGE","ADF_WIDGET_TOOLTIP_REFRESH","ADF_WIDGET_TOOLTIP_MOVE","ADF_WIDGET_TOOLTIP_COLLAPSE","ADF_WIDGET_TOOLTIP_EXPAND","ADF_WIDGET_TOOLTIP_EDIT","ADF_WIDGET_TOOLTIP_FULLSCREEN","ADF_WIDGET_TOOLTIP_REMOVE","sv-SE"],"mappings":"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","file":"angular-dashboard-framework-tpls.min.js","sourcesContent":["/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '<>');\n",null,"\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n 'use strict';\n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n 'use strict';\n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n 'use strict';\n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n 'use strict';\n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\nangular.module(\"adf\").run([\"$templateCache\", function($templateCache) {$templateCache.put(\"../src/templates/dashboard-column.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-edit.html\",\" \");\n$templateCache.put(\"../src/templates/dashboard-row.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-title.html\",\"

{{model.title}}

\");\n$templateCache.put(\"../src/templates/dashboard.html\",\"
\");\n$templateCache.put(\"../src/templates/structure-preview.html\",\"

{{name}}

\");\n$templateCache.put(\"../src/templates/widget-add.html\",\" \");\n$templateCache.put(\"../src/templates/widget-delete.html\",\" \");\n$templateCache.put(\"../src/templates/widget-edit.html\",\"
\");\n$templateCache.put(\"../src/templates/widget-fullscreen.html\",\" \");\n$templateCache.put(\"../src/templates/widget-title.html\",\"

{{definition.title}}

\");\n$templateCache.put(\"../src/templates/widget.html\",\"
\");}]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', [\"$http\", \"$q\", \"$sce\", \"$templateCache\", \"dashboard\", function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', [\"$log\", \"dashboard\", \"$rootScope\", function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', [\"$log\", \"$q\", \"widgetService\", \"$compile\", \"$controller\", \"$injector\", \"dashboard\", function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', [\"adfTemplatePath\", \"adfStructurePreviewService\", function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', [\"$rootScope\", \"$log\", \"$timeout\", \"$uibModal\", \"dashboard\", \"adfTemplatePath\", \"adfDashboardService\", \"adfUtilsService\", function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n controller.$inject = [\"$scope\"];\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', [\"$compile\", \"adfTemplatePath\", \"columnTemplate\", function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', [\"$log\", \"$compile\", \"$rootScope\", \"adfTemplatePath\", \"rowTemplate\", \"dashboard\", function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n 'use strict';\n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf.locale', [])\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n'use strict';\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\nangular.module(\"adf\").run([\"$templateCache\", function($templateCache) {$templateCache.put(\"../src/templates/dashboard-column.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-edit.html\",\" \");\n$templateCache.put(\"../src/templates/dashboard-row.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-title.html\",\"

{{model.title}}

\");\n$templateCache.put(\"../src/templates/dashboard.html\",\"
\");\n$templateCache.put(\"../src/templates/structure-preview.html\",\"

{{name}}

\");\n$templateCache.put(\"../src/templates/widget-add.html\",\" \");\n$templateCache.put(\"../src/templates/widget-delete.html\",\" \");\n$templateCache.put(\"../src/templates/widget-edit.html\",\"
\");\n$templateCache.put(\"../src/templates/widget-fullscreen.html\",\" \");\n$templateCache.put(\"../src/templates/widget-title.html\",\"

{{definition.title}}

\");\n$templateCache.put(\"../src/templates/widget.html\",\"
\");}]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);"]} \ No newline at end of file +{"version":3,"sources":["adf.module.js","angular-dashboard-framework.tpl.js","services/widget.service.js","services/adf-utils.service.js","services/adf-structure-preview.service.js","services/adf-dashboard.service.js","filters/adf-order-by-object-key.filter.js","directives/adf-widget.directive.js","angular-dashboard-framework-tpls.min.js","directives/adf-widget-content.directive.js","directives/adf-structure-preview.directive.js","directives/adf-dashboard.directive.js","directives/adf-dashboard-row.directive.js","directives/adf-dashboard-column.directive.js","dashboard.provider.js","adf.locale.module.js","adf.locale.constants.js","angular-dashboard-framework-tpls.js"],"names":["window","undefined","angular","module","value","run","$templateCache","put","factory","$http","$q","$sce","dashboard","parseUrl","url","parsedUrl","indexOf","replace","widgetsPath","substring","exposed","getTemplate","widget","deferred","defer","template","resolve","templateUrl","tpl","get","getTrustedResourceUrl","then","response","data","reject","promise","stringToBoolean","string","isString","toLowerCase","Boolean","split","object","size","arr","i","forEach","key","index","service","adjustRowHeight","container","rows","length","height","row","style","columns","column","$log","$rootScope","_copyWidgets","source","target","widgets","w","shift","push","_fillStructure","root","counter","isDefined","isUndefined","_readColumns","col","hasOwnProperty","changeStructure","model","structure","copy","createConfiguration","type","cfg","config","_findFirstWidgetColumn","isArray","error","j","addNewWidgetToModel","name","unshift","$broadcast","isEditModeImmediate","edit","immediate","createCategories","categories","category","_tests","filter","$filter","item","array","objectKey","directive","$injector","$uibModal","adfTemplatePath","preLink","$scope","definition","translate","title","titleTemplateUrl","editTemplateUrl","frameless","styleClass","wid","id","fromJson","widgetState","isCollapsed","collapsed","warn","debug","postLink","$element","deleteWidget","splice","remove","options","enableConfirmDelete","deleteScope","$new","deleteTemplateUrl","opts","scope","windowClass","backdrop","instance","open","closeDialog","close","$destroy","deleteDialog","reload","createApplyPromise","result","when","editScope","adfEditTemplatePath","saveDialog","validationError","applyFn","apply","locals","invoke","extend","err","controller","$on","event","args","collapseExpandStatus","idEquals","widgetClasses","classes","editMode","openFullScreen","fullScreenScope","modalSize","$inject","restrict","transclude","customWidgetTemplatePath","adfModel","compile","pre","post","widgetService","$compile","$controller","renderError","msg","html","messageTemplate","compileWidget","currentScope","content","newScope","renderWidget","loadingTemplate","templateScope","base","resolvers","$tpl","all","resolveAs","templateCtrl","controllerAs","children","contents","reason","link","adfStructurePreviewService","preview","selected","$timeout","adfDashboardService","adfUtilsService","_openEditMode","getNewModalScope","widgetFilter","structureName","$watch","oldVal","newVal","adfWidgetFilter","structures","editClass","toggleEditMode","continuousEditMode","modelCopy","collapseAll","cancelEditMode","editDashboardDialog","editDashboardScope","info","addWidgetDialog","addScope","isFunction","adfAddTemplatePath","addTemplateUrl","adfAddWidgetModalOptions","merge","addWidget","$attr","editable","maximizable","collapsible","columnTemplate","cloned","append","rowTemplate","moveWidgetInColumn","evt","$apply","newIndex","oldIndex","findWidget","findColumn","r","c","cid","getId","el","getAttribute","addWidgetToColumn","targetColumn","from","sourceColumn","removeWidgetFromColumn","applySortable","sortable","Sortable","create","group","handle","ghostClass","animation","onAdd","onRemove","onUpdate","on","destroy","provider","adfLocale","getLocales","locales","getActiveLocale","activeLocale","label","translation","defaultApplyFunction","defaultLocale","frameworkLocales","this","path","templatePath","setLocale","locale","Error","addLocale","translations","isObject","$get","Date","getTime","other","toString","constant","en-GB","ADF_COMMON_CLOSE","ADF_COMMON_DELETE","ADF_COMMON_TITLE","ADF_COMMON_CANCEL","ADF_COMMON_APPLY","ADF_COMMON_EDIT_DASHBOARD","ADF_EDIT_DASHBOARD_STRUCTURE_LABEL","ADF_DASHBOARD_TITLE_TOOLTIP_ADD","ADF_DASHBOARD_TITLE_TOOLTIP_SAVE","ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE","ADF_DASHBOARD_TITLE_TOOLTIP_UNDO","ADF_WIDGET_ADD_HEADER","ADF_WIDGET_DELETE_CONFIRM_MESSAGE","ADF_WIDGET_TOOLTIP_REFRESH","ADF_WIDGET_TOOLTIP_MOVE","ADF_WIDGET_TOOLTIP_COLLAPSE","ADF_WIDGET_TOOLTIP_EXPAND","ADF_WIDGET_TOOLTIP_EDIT","ADF_WIDGET_TOOLTIP_FULLSCREEN","ADF_WIDGET_TOOLTIP_REMOVE","sv-SE"],"mappings":"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","file":"angular-dashboard-framework-tpls.min.js","sourcesContent":["/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '<>');\n",null,"\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n 'use strict';\n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n 'use strict';\n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n 'use strict';\n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n 'use strict';\n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\nangular.module(\"adf\").run([\"$templateCache\", function($templateCache) {$templateCache.put(\"../src/templates/dashboard-column.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-edit.html\",\" \");\n$templateCache.put(\"../src/templates/dashboard-row.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-title.html\",\"

{{model.title}} {{!editMode ? \\'Edit\\' : \\'Save\\' }}

\");\n$templateCache.put(\"../src/templates/dashboard.html\",\"
\");\n$templateCache.put(\"../src/templates/structure-preview.html\",\"

{{name}}

\");\n$templateCache.put(\"../src/templates/widget-add.html\",\" \");\n$templateCache.put(\"../src/templates/widget-delete.html\",\" \");\n$templateCache.put(\"../src/templates/widget-edit.html\",\"
\");\n$templateCache.put(\"../src/templates/widget-fullscreen.html\",\" \");\n$templateCache.put(\"../src/templates/widget-title.html\",\"

{{definition.title}}

\");\n$templateCache.put(\"../src/templates/widget.html\",\"
\");}]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', [\"$http\", \"$q\", \"$sce\", \"$templateCache\", \"dashboard\", function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', [\"$log\", \"dashboard\", \"$rootScope\", function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', [\"$log\", \"$q\", \"widgetService\", \"$compile\", \"$controller\", \"$injector\", \"dashboard\", function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', [\"adfTemplatePath\", \"adfStructurePreviewService\", function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', [\"$rootScope\", \"$log\", \"$timeout\", \"$uibModal\", \"dashboard\", \"adfTemplatePath\", \"adfDashboardService\", \"adfUtilsService\", function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n controller.$inject = [\"$scope\"];\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfAddWidgetModalOptions: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n $rootScope.$broadcast('adfDashboardStructureChange');\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n if (angular.isDefined($scope.adfAddWidgetModalOptions)) {\n opts = angular.merge(opts, $scope.adfAddWidgetModalOptions);\n }\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', [\"$compile\", \"adfTemplatePath\", \"columnTemplate\", function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', [\"$log\", \"$compile\", \"$rootScope\", \"adfTemplatePath\", \"rowTemplate\", \"dashboard\", function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n 'use strict';\n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfAddWidgetModalOptions: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n $rootScope.$broadcast('adfDashboardStructureChange');\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n if (angular.isDefined($scope.adfAddWidgetModalOptions)) {\n opts = angular.merge(opts, $scope.adfAddWidgetModalOptions);\n }\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf.locale', [])\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n'use strict';\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\nangular.module(\"adf\").run([\"$templateCache\", function($templateCache) {$templateCache.put(\"../src/templates/dashboard-column.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-edit.html\",\" \");\n$templateCache.put(\"../src/templates/dashboard-row.html\",\"
\");\n$templateCache.put(\"../src/templates/dashboard-title.html\",\"

{{model.title}} {{!editMode ? \\'Edit\\' : \\'Save\\' }}

\");\n$templateCache.put(\"../src/templates/dashboard.html\",\"
\");\n$templateCache.put(\"../src/templates/structure-preview.html\",\"

{{name}}

\");\n$templateCache.put(\"../src/templates/widget-add.html\",\" \");\n$templateCache.put(\"../src/templates/widget-delete.html\",\" \");\n$templateCache.put(\"../src/templates/widget-edit.html\",\"
\");\n$templateCache.put(\"../src/templates/widget-fullscreen.html\",\" \");\n$templateCache.put(\"../src/templates/widget-title.html\",\"

{{definition.title}}

\");\n$templateCache.put(\"../src/templates/widget.html\",\"
\");}]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfAddWidgetModalOptions: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n $rootScope.$broadcast('adfDashboardStructureChange');\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n if (angular.isDefined($scope.adfAddWidgetModalOptions)) {\n opts = angular.merge(opts, $scope.adfAddWidgetModalOptions);\n }\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);"]} \ No newline at end of file diff --git a/dist/angular-dashboard-framework.js b/dist/angular-dashboard-framework.js index dcebbc5f..c452a2e6 100644 --- a/dist/angular-dashboard-framework.js +++ b/dist/angular-dashboard-framework.js @@ -446,6 +446,46 @@ angular.module('adf') } }]); +/* +* The MIT License +* +* Copyright (c) 2015, Sebastian Sdorra +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + + +/* global angular */ +angular.module('adf') + .filter('adfOrderByObjectKey', ["$filter", function($filter) { + + + return function(item, key){ + var array = []; + angular.forEach(item, function(value, objectKey){ + value[key] = objectKey; + array.push(value); + }); + return $filter('orderBy')(array, key); + }; + }]); + /* * The MIT License * @@ -1000,6 +1040,7 @@ angular.module('adf') * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard. * @param {string=} structure the default structure of the dashboard. * @param {object=} adfModel model object of the dashboard. + * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal * @param {function=} adfWidgetFilter function to filter widgets on the add dialog. * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove * events during edit mode not reset it if edit mode is exited. @@ -1024,6 +1065,7 @@ angular.module('adf') continuousEditMode: '=', maximizable: '@', adfModel: '=', + adfAddWidgetModalOptions: '=', adfWidgetFilter: '=', categories: '@' }, @@ -1168,6 +1210,7 @@ angular.module('adf') if (model.structure !== name){ model.structure = name; } + $rootScope.$broadcast('adfDashboardStructureChange'); }; editDashboardScope.closeDialog = function(){ // copy the new title back to the model @@ -1215,6 +1258,10 @@ angular.module('adf') backdrop: 'static' }; + if (angular.isDefined($scope.adfAddWidgetModalOptions)) { + opts = angular.merge(opts, $scope.adfAddWidgetModalOptions); + } + var instance = $uibModal.open(opts); addScope.addWidget = function(widget){ var w = { @@ -1514,46 +1561,6 @@ angular.module('adf') }]); -/* -* The MIT License -* -* Copyright (c) 2015, Sebastian Sdorra -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -*/ - - -/* global angular */ -angular.module('adf') - .filter('adfOrderByObjectKey', ["$filter", function($filter) { - - - return function(item, key){ - var array = []; - angular.forEach(item, function(value, objectKey){ - value[key] = objectKey; - array.push(value); - }); - return $filter('orderBy')(array, key); - }; - }]); - /* * The MIT License * diff --git a/dist/angular-dashboard-framework.min.js b/dist/angular-dashboard-framework.min.js index ccffe574..95ff1f1b 100644 --- a/dist/angular-dashboard-framework.min.js +++ b/dist/angular-dashboard-framework.min.js @@ -1,2 +1,2 @@ -!function(e,t){"use strict";angular.module("adf",["adf.provider","adf.locale","ui.bootstrap"]).value("adfTemplatePath","../src/templates/").value("rowTemplate",'').value("columnTemplate",'').value("adfVersion","0.13.0-SNAPSHOT"),angular.module("adf").factory("widgetService",["$http","$q","$sce","$templateCache","dashboard",function(e,t,a,o,n){function r(e){var t=e;return e.indexOf("{widgetsPath}")>=0&&(t=e.replace("{widgetsPath}",n.widgetsPath).replace("//","/"),0===t.indexOf("/")&&(t=t.substring(1))),t}var i={};return i.getTemplate=function(n){var i=t.defer();if(n.template)i.resolve(n.template);else if(n.templateUrl){var l=o.get(n.templateUrl);if(l)i.resolve(l);else{var d=a.getTrustedResourceUrl(r(n.templateUrl));e.get(d).then(function(e){return e.data}).then(function(e){o.put(n.templateUrl,e),i.resolve(e)})["catch"](function(){i.reject("could not load template")})}}return i.promise},i}]),angular.module("adf").factory("adfUtilsService",function(){function e(e){switch(angular.isString(e)?e.toLowerCase():null){case"true":case"yes":case"1":return!0;case"false":case"no":case"0":case null:return!1;default:return Boolean(e)}}function t(e,t){var a=[],o=0;return angular.forEach(e,function(e,n){var r=o++%t;a[r]||(a[r]={}),a[r][n]=e}),a}var a={stringToBoolean:e,split:t};return a}),angular.module("adf").factory("adfStructurePreviewService",function(){function e(t){if(t.rows&&t.rows.length>0){var a=100/t.rows.length;angular.forEach(t.rows,function(t){t.style={height:a+"%"},t.columns&&angular.forEach(t.columns,function(t){e(t)})})}}var t={adjustRowHeight:e};return t}),angular.module("adf").factory("adfDashboardService",["$log","dashboard","$rootScope",function(e,t,a){function o(e,t){if(e.widgets&&e.widgets.length>0)for(var a=e.widgets.shift();a;)t.widgets.push(a),a=e.widgets.shift()}function n(e,t,a){return a=a||0,angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.widgets||(e.widgets=[]),angular.isDefined(t[a])&&angular.isUndefined(e.rows)&&(o(t[a],e),a++),a=n(e,t,a)})}),a}function r(e,t){return t=t||[],angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.hasOwnProperty("rows")||t.push(e),r(e,t)})}),t}function i(e,t){var a=r(e),o=0;for(e.rows=angular.copy(t.rows);o=0&&e.widgets.splice(t,1)}d.remove(),n.$broadcast("adfWidgetRemovedFromColumn",s)};l.remove=function(){if(l.options.enableConfirmDelete){var e=l.$new();e.translate=r.translate;var t=i+"widget-delete.html";s.deleteTemplateUrl&&(t=s.deleteTemplateUrl);var a={scope:e,templateUrl:t,windowClass:"adf-remove-widget-modal",backdrop:"static"},n=o.open(a);e.closeDialog=function(){n.close(),e.$destroy()},e.deleteDialog=function(){c(),e.closeDialog()}}else c()},l.reload=function(){l.$broadcast("widgetReload")},l.edit=function(){function a(e){var a;if("boolean"==typeof e){var o=t.defer();e?o.resolve():o.reject(),a=o.promise}else a=t.when(e);return a}var n=l.$new();n.translate=r.translate,n.definition=angular.copy(s);var d=i+"widget-edit.html";s.editTemplateUrl&&(d=s.editTemplateUrl);var c={scope:n,templateUrl:d,windowClass:"adf-edit-widget-modal",backdrop:"static"},u=o.open(c);n.closeDialog=function(){u.close(),n.$destroy()},n.saveDialog=function(){n.validationError=null;var t,o=l.widget;t=o.edit?o.edit.apply:function(){return!0};var r={widget:o,definition:n.definition,config:n.definition.config},i=e.invoke(t,t,r);a(i).then(function(){s.title=n.definition.title,angular.extend(s.config,n.definition.config),o.edit&&o.edit.reload&&l.$broadcast("widgetConfigChanged"),n.closeDialog()},function(e){e?n.validationError=e:n.validationError="Validation durring apply failed"})}}}else a.debug("widget not found")}function s(e){e.$on("adfDashboardCollapseExpand",function(t,a){e.widgetState.isCollapsed=a.collapseExpandStatus}),e.$on("adfWidgetEnterEditMode",function(t,a){r.idEquals(e.definition.wid,a.wid)&&e.edit()}),e.widgetClasses=function(t,a){var o=a.styleClass||"";return t&&t.frameless&&!e.editMode||(o+=" panel panel-default"),o},e.openFullScreen=function(){var t=e.definition,a=e.$new(),n={scope:a,templateUrl:i+"widget-fullscreen.html",size:t.modalSize||"lg",backdrop:"static",windowClass:t.fullScreen?"dashboard-modal widget-fullscreen":"dashboard-modal"},r=o.open(n);a.closeDialog=function(){r.close(),a.$destroy()}}}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,templateUrl:r.customWidgetTemplatePath?r.customWidgetTemplatePath:i+"widget.html",scope:{adfModel:"=",definition:"=",col:"=column",editMode:"=",options:"=",widgetState:"="},controller:s,compile:function(){return{pre:l,post:d}}}}]),angular.module("adf").directive("adfWidgetContent",["$log","$q","widgetService","$compile","$controller","$injector","dashboard",function(e,t,a,o,n,r,i){function l(t,a){e.warn(a),t.html(i.messageTemplate.replace(/{}/g,a))}function d(e,t,a){var o=e.model,n=e.content,r=a;if(o)if(n)r=s(e,t,a,o,n);else{var i="widget content is undefined, please have a look at your browser log";l(t,i)}else l(t,"model is undefined");return r}function s(e,d,s,c,u){d.html(i.loadingTemplate);var f=e.$new();c.config||(c.config={}),f.config=c.config;var g={$scope:f,widget:c,config:c.config},p={};return p.$tpl=a.getTemplate(u),u.resolve&&angular.forEach(u.resolve,function(e,t){angular.isString(e)?p[t]=r.get(e):p[t]=r.invoke(e,e,g)}),t.all(p).then(function(e){angular.extend(e,g),u.resolveAs&&(f[u.resolveAs]=e);var t=e.$tpl;if(d.html(t),u.controller){var a=n(u.controller,e);u.controllerAs&&(f[u.controllerAs]=a),d.children().data("$ngControllerController",a)}o(d.contents())(f)},function(e){var t="Could not resolve all promises";e&&(t+=": "+e),l(d,t)}),s&&s.$destroy(),f}function c(e,t){var a=d(e,t,null);e.$on("widgetConfigChanged",function(){a=d(e,t,a)}),e.$on("widgetReload",function(){a=d(e,t,a)})}return{replace:!0,restrict:"EA",transclude:!1,scope:{adfModel:"=",model:"=",content:"="},link:c}}]),angular.module("adf").directive("adfStructurePreview",["adfTemplatePath","adfStructurePreviewService",function(e,t){function a(e){var a=angular.copy(e.structure);t.adjustRowHeight(a),e.preview=a}return{restrict:"E",replace:!0,scope:{name:"=",structure:"=",selected:"="},templateUrl:e+"structure-preview.html",link:a}}]),angular.module("adf").directive("adfDashboard",["$rootScope","$log","$timeout","$uibModal","dashboard","adfTemplatePath","adfDashboardService","adfUtilsService",function(e,t,a,o,n,r,i,l){function d(e,t){a(function(){e.$broadcast("adfWidgetEnterEditMode",t)},200)}function s(a){function s(){var e=a.$new();return e.translate=n.translate,e}var c={},u={},f=null,g={},p=a.name;a.$watch("adfModel",function(e,o){(null!==o||null===e&&null===o)&&(c=a.adfModel,f=a.adfWidgetFilter,c&&c.rows||(g=a.structure,u=n.structures[g],u?(c?c.rows=angular.copy(u).rows:c=angular.copy(u),c.structure=g):t.error("could not find structure "+g)),c?(c.title||(c.title="Dashboard"),c.titleTemplateUrl||(c.titleTemplateUrl=r+"dashboard-title.html"),a.model=c):t.error("could not find or create model"))},!0),a.editMode=!1,a.editClass="",a.translate=n.translate,a.toggleEditMode=function(){a.editMode=!a.editMode,a.editMode&&(a.continuousEditMode||(a.modelCopy=angular.copy(a.adfModel,{}),e.$broadcast("adfIsEditMode"))),a.editMode||e.$broadcast("adfDashboardChanged",p,c)},a.$on("adfToggleEditMode",function(){a.toggleEditMode()}),a.collapseAll=function(t){e.$broadcast("adfDashboardCollapseExpand",{collapseExpandStatus:t})},a.cancelEditMode=function(){a.editMode=!1,a.continuousEditMode||(a.modelCopy=angular.copy(a.modelCopy,a.adfModel)),e.$broadcast("adfDashboardEditsCancelled")},a.editDashboardDialog=function(){var e=s();e.copy={title:c.title},e.structures=n.structures,e.split=l.split;var a=r+"dashboard-edit.html";c.editTemplateUrl&&(a=c.editTemplateUrl);var d=o.open({scope:e,templateUrl:a,backdrop:"static",windowClass:"adf-edit-dashboard-modal",size:"lg"});e.changeStructure=function(e,a){t.info("change structure to "+e),i.changeStructure(c,a),c.structure!==e&&(c.structure=e)},e.closeDialog=function(){c.title=e.copy.title,d.close(),e.$destroy()}},a.addWidgetDialog=function(){var e,t=s(),l=a.model;angular.isFunction(f)?(e={},angular.forEach(n.widgets,function(t,a){f(t,a,l)&&(e[a]=t)})):e=n.widgets,t.widgets=e,t.translate=a.translate,a.options.categories&&(a.createCategories=i.createCategories);var c=r+"widget-add.html";l.addTemplateUrl&&(c=l.addTemplateUrl);var u={scope:t,templateUrl:c,windowClass:"adf-add-widget-modal",backdrop:"static"},g=o.open(u);t.addWidget=function(e){var o={type:e,config:i.createConfiguration(e)};i.addNewWidgetToModel(l,o,p),g.close(),t.$destroy(),i.isEditModeImmediate(e)&&d(a,o)},t.closeDialog=function(){g.close(),t.$destroy()}},a.addNewWidgetToModel=i.addNewWidgetToModel}function c(e,t,a){var o={name:a.name,editable:!0,enableConfirmDelete:l.stringToBoolean(a.enableConfirmDelete),maximizable:l.stringToBoolean(a.maximizable),collapsible:l.stringToBoolean(a.collapsible),categories:l.stringToBoolean(a.categories)};angular.isDefined(a.editable)&&(o.editable=l.stringToBoolean(a.editable)),e.options=o}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,scope:{structure:"@",name:"@",collapsible:"@",editable:"@",editMode:"@",continuousEditMode:"=",maximizable:"@",adfModel:"=",adfWidgetFilter:"=",categories:"@"},controller:s,link:c,templateUrl:r+"dashboard.html"}}]),angular.module("adf").directive("adfDashboardRow",["$compile","adfTemplatePath","columnTemplate",function(e,t,a){function o(t,o){angular.isDefined(t.row.columns)&&angular.isArray(t.row.columns)&&e(a)(t,function(e){o.append(e)})}return{restrict:"E",replace:!0,scope:{row:"=",adfModel:"=",editMode:"=",continuousEditMode:"=",options:"="},templateUrl:t+"dashboard-row.html",link:o}}]),angular.module("adf").directive("adfDashboardColumn",["$log","$compile","$rootScope","adfTemplatePath","rowTemplate","dashboard",function(e,t,a,o,n,r){function i(e,t,o){var n=t.widgets;e.$apply(function(){n.splice(o.newIndex,0,n.splice(o.oldIndex,1)[0]),a.$broadcast("adfWidgetMovedInColumn")})}function l(e,t){for(var a=null,o=0;o{}',d='
\n
\n loading ...\n
\n
',s=null,c=function(){return!0},u=e.defaultLocale,f=e.frameworkLocales;this.widget=function(e,t){var a=angular.extend({reload:!1,frameless:!1},t);if(a.edit){var o={reload:!0,immediate:!1,apply:c};angular.extend(o,a.edit),a.edit=o}return n[e]=a,this},this.widgetsPath=function(e){return r=e,this},this.structure=function(e,t){return i[e]=t,this},this.messageTemplate=function(e){return l=e,this},this.loadingTemplate=function(e){return d=e,this},this.customWidgetTemplatePath=function(e){return s=e,this},this.setLocale=function(e){if(!f[e])throw new Error("Cannot set locale: "+e+". Locale is not defined.");return u=e,this},this.addLocale=function(e,t){if(!angular.isString(e))throw new Error("locale must be an string");if(!angular.isObject(t))throw new Error("translations must be an object");return f[e]=t,this},this.$get=function(){var e=0;return{widgets:n,widgetsPath:r,structures:i,messageTemplate:l,loadingTemplate:d,setLocale:this.setLocale,locales:t,activeLocale:a,translate:o,customWidgetTemplatePath:s,id:function(){return(new Date).getTime()+"-"+ ++e},idEquals:function(e,t){return e&&t&&e.toString()===t.toString()}}}}]),angular.module("adf.locale",[]),angular.module("adf.locale").constant("adfLocale",{defaultLocale:"en-GB",frameworkLocales:{"en-GB":{ADF_COMMON_CLOSE:"Close",ADF_COMMON_DELETE:"Delete",ADF_COMMON_TITLE:"Title",ADF_COMMON_CANCEL:"Cancel",ADF_COMMON_APPLY:"Apply",ADF_COMMON_EDIT_DASHBOARD:"Edit dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Structure",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Add new widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Save changes",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Enable edit mode",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Undo changes",ADF_WIDGET_ADD_HEADER:"Add new widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Are you sure you want to delete this widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Reload widget Content",ADF_WIDGET_TOOLTIP_MOVE:"Change widget location",ADF_WIDGET_TOOLTIP_COLLAPSE:"Collapse widget",ADF_WIDGET_TOOLTIP_EXPAND:"Expand widget",ADF_WIDGET_TOOLTIP_EDIT:"Edit widget configuration",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Fullscreen widget",ADF_WIDGET_TOOLTIP_REMOVE:"Remove widget"},"sv-SE":{ADF_COMMON_CLOSE:"Stäng",ADF_COMMON_DELETE:"Ta bort",ADF_COMMON_TITLE:"Titel",ADF_COMMON_CANCEL:"Avbryt",ADF_COMMON_APPLY:"Använd",ADF_COMMON_EDIT_DASHBOARD:"Redigera dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Struktur",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Lägg till ny widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Spara förändringar",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Slå på redigeringsläge",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Ångra förändringar",ADF_WIDGET_ADD_HEADER:"Lägg till ny widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Är du säker på att du vill ta bort denna widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Ladda om widget",ADF_WIDGET_TOOLTIP_MOVE:"Ändra widgets position",ADF_WIDGET_TOOLTIP_COLLAPSE:"Stäng widget",ADF_WIDGET_TOOLTIP_EXPAND:"Öppna widget",ADF_WIDGET_TOOLTIP_EDIT:"Ändra widget konfigurering",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Visa widget i fullskärm",ADF_WIDGET_TOOLTIP_REMOVE:"Ta bort widget"}}})}(window); +!function(e,t){"use strict";angular.module("adf",["adf.provider","adf.locale","ui.bootstrap"]).value("adfTemplatePath","../src/templates/").value("rowTemplate",'').value("columnTemplate",'').value("adfVersion","0.13.0-SNAPSHOT"),angular.module("adf").factory("widgetService",["$http","$q","$sce","$templateCache","dashboard",function(e,t,a,o,n){function r(e){var t=e;return e.indexOf("{widgetsPath}")>=0&&(t=e.replace("{widgetsPath}",n.widgetsPath).replace("//","/"),0===t.indexOf("/")&&(t=t.substring(1))),t}var i={};return i.getTemplate=function(n){var i=t.defer();if(n.template)i.resolve(n.template);else if(n.templateUrl){var l=o.get(n.templateUrl);if(l)i.resolve(l);else{var d=a.getTrustedResourceUrl(r(n.templateUrl));e.get(d).then(function(e){return e.data}).then(function(e){o.put(n.templateUrl,e),i.resolve(e)})["catch"](function(){i.reject("could not load template")})}}return i.promise},i}]),angular.module("adf").factory("adfUtilsService",function(){function e(e){switch(angular.isString(e)?e.toLowerCase():null){case"true":case"yes":case"1":return!0;case"false":case"no":case"0":case null:return!1;default:return Boolean(e)}}function t(e,t){var a=[],o=0;return angular.forEach(e,function(e,n){var r=o++%t;a[r]||(a[r]={}),a[r][n]=e}),a}var a={stringToBoolean:e,split:t};return a}),angular.module("adf").factory("adfStructurePreviewService",function(){function e(t){if(t.rows&&t.rows.length>0){var a=100/t.rows.length;angular.forEach(t.rows,function(t){t.style={height:a+"%"},t.columns&&angular.forEach(t.columns,function(t){e(t)})})}}var t={adjustRowHeight:e};return t}),angular.module("adf").factory("adfDashboardService",["$log","dashboard","$rootScope",function(e,t,a){function o(e,t){if(e.widgets&&e.widgets.length>0)for(var a=e.widgets.shift();a;)t.widgets.push(a),a=e.widgets.shift()}function n(e,t,a){return a=a||0,angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.widgets||(e.widgets=[]),angular.isDefined(t[a])&&angular.isUndefined(e.rows)&&(o(t[a],e),a++),a=n(e,t,a)})}),a}function r(e,t){return t=t||[],angular.isDefined(e.rows)&&angular.forEach(e.rows,function(e){angular.forEach(e.columns,function(e){e.hasOwnProperty("rows")||t.push(e),r(e,t)})}),t}function i(e,t){var a=r(e),o=0;for(e.rows=angular.copy(t.rows);o=0&&e.widgets.splice(t,1)}d.remove(),n.$broadcast("adfWidgetRemovedFromColumn",s)};l.remove=function(){if(l.options.enableConfirmDelete){var e=l.$new();e.translate=r.translate;var t=i+"widget-delete.html";s.deleteTemplateUrl&&(t=s.deleteTemplateUrl);var a={scope:e,templateUrl:t,windowClass:"adf-remove-widget-modal",backdrop:"static"},n=o.open(a);e.closeDialog=function(){n.close(),e.$destroy()},e.deleteDialog=function(){c(),e.closeDialog()}}else c()},l.reload=function(){l.$broadcast("widgetReload")},l.edit=function(){function a(e){var a;if("boolean"==typeof e){var o=t.defer();e?o.resolve():o.reject(),a=o.promise}else a=t.when(e);return a}var n=l.$new();n.translate=r.translate,n.definition=angular.copy(s);var d=i+"widget-edit.html";s.editTemplateUrl&&(d=s.editTemplateUrl);var c={scope:n,templateUrl:d,windowClass:"adf-edit-widget-modal",backdrop:"static"},u=o.open(c);n.closeDialog=function(){u.close(),n.$destroy()},n.saveDialog=function(){n.validationError=null;var t,o=l.widget;t=o.edit?o.edit.apply:function(){return!0};var r={widget:o,definition:n.definition,config:n.definition.config},i=e.invoke(t,t,r);a(i).then(function(){s.title=n.definition.title,angular.extend(s.config,n.definition.config),o.edit&&o.edit.reload&&l.$broadcast("widgetConfigChanged"),n.closeDialog()},function(e){e?n.validationError=e:n.validationError="Validation durring apply failed"})}}}else a.debug("widget not found")}function s(e){e.$on("adfDashboardCollapseExpand",function(t,a){e.widgetState.isCollapsed=a.collapseExpandStatus}),e.$on("adfWidgetEnterEditMode",function(t,a){r.idEquals(e.definition.wid,a.wid)&&e.edit()}),e.widgetClasses=function(t,a){var o=a.styleClass||"";return t&&t.frameless&&!e.editMode||(o+=" panel panel-default"),o},e.openFullScreen=function(){var t=e.definition,a=e.$new(),n={scope:a,templateUrl:i+"widget-fullscreen.html",size:t.modalSize||"lg",backdrop:"static",windowClass:t.fullScreen?"dashboard-modal widget-fullscreen":"dashboard-modal"},r=o.open(n);a.closeDialog=function(){r.close(),a.$destroy()}}}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,templateUrl:r.customWidgetTemplatePath?r.customWidgetTemplatePath:i+"widget.html",scope:{adfModel:"=",definition:"=",col:"=column",editMode:"=",options:"=",widgetState:"="},controller:s,compile:function(){return{pre:l,post:d}}}}]),angular.module("adf").directive("adfWidgetContent",["$log","$q","widgetService","$compile","$controller","$injector","dashboard",function(e,t,a,o,n,r,i){function l(t,a){e.warn(a),t.html(i.messageTemplate.replace(/{}/g,a))}function d(e,t,a){var o=e.model,n=e.content,r=a;if(o)if(n)r=s(e,t,a,o,n);else{var i="widget content is undefined, please have a look at your browser log";l(t,i)}else l(t,"model is undefined");return r}function s(e,d,s,c,u){d.html(i.loadingTemplate);var f=e.$new();c.config||(c.config={}),f.config=c.config;var g={$scope:f,widget:c,config:c.config},p={};return p.$tpl=a.getTemplate(u),u.resolve&&angular.forEach(u.resolve,function(e,t){angular.isString(e)?p[t]=r.get(e):p[t]=r.invoke(e,e,g)}),t.all(p).then(function(e){angular.extend(e,g),u.resolveAs&&(f[u.resolveAs]=e);var t=e.$tpl;if(d.html(t),u.controller){var a=n(u.controller,e);u.controllerAs&&(f[u.controllerAs]=a),d.children().data("$ngControllerController",a)}o(d.contents())(f)},function(e){var t="Could not resolve all promises";e&&(t+=": "+e),l(d,t)}),s&&s.$destroy(),f}function c(e,t){var a=d(e,t,null);e.$on("widgetConfigChanged",function(){a=d(e,t,a)}),e.$on("widgetReload",function(){a=d(e,t,a)})}return{replace:!0,restrict:"EA",transclude:!1,scope:{adfModel:"=",model:"=",content:"="},link:c}}]),angular.module("adf").directive("adfStructurePreview",["adfTemplatePath","adfStructurePreviewService",function(e,t){function a(e){var a=angular.copy(e.structure);t.adjustRowHeight(a),e.preview=a}return{restrict:"E",replace:!0,scope:{name:"=",structure:"=",selected:"="},templateUrl:e+"structure-preview.html",link:a}}]),angular.module("adf").directive("adfDashboard",["$rootScope","$log","$timeout","$uibModal","dashboard","adfTemplatePath","adfDashboardService","adfUtilsService",function(e,t,a,o,n,r,i,l){function d(e,t){a(function(){e.$broadcast("adfWidgetEnterEditMode",t)},200)}function s(a){function s(){var e=a.$new();return e.translate=n.translate,e}var c={},u={},f=null,g={},p=a.name;a.$watch("adfModel",function(e,o){(null!==o||null===e&&null===o)&&(c=a.adfModel,f=a.adfWidgetFilter,c&&c.rows||(g=a.structure,u=n.structures[g],u?(c?c.rows=angular.copy(u).rows:c=angular.copy(u),c.structure=g):t.error("could not find structure "+g)),c?(c.title||(c.title="Dashboard"),c.titleTemplateUrl||(c.titleTemplateUrl=r+"dashboard-title.html"),a.model=c):t.error("could not find or create model"))},!0),a.editMode=!1,a.editClass="",a.translate=n.translate,a.toggleEditMode=function(){a.editMode=!a.editMode,a.editMode&&(a.continuousEditMode||(a.modelCopy=angular.copy(a.adfModel,{}),e.$broadcast("adfIsEditMode"))),a.editMode||e.$broadcast("adfDashboardChanged",p,c)},a.$on("adfToggleEditMode",function(){a.toggleEditMode()}),a.collapseAll=function(t){e.$broadcast("adfDashboardCollapseExpand",{collapseExpandStatus:t})},a.cancelEditMode=function(){a.editMode=!1,a.continuousEditMode||(a.modelCopy=angular.copy(a.modelCopy,a.adfModel)),e.$broadcast("adfDashboardEditsCancelled")},a.editDashboardDialog=function(){var a=s();a.copy={title:c.title},a.structures=n.structures,a.split=l.split;var d=r+"dashboard-edit.html";c.editTemplateUrl&&(d=c.editTemplateUrl);var u=o.open({scope:a,templateUrl:d,backdrop:"static",windowClass:"adf-edit-dashboard-modal",size:"lg"});a.changeStructure=function(a,o){t.info("change structure to "+a),i.changeStructure(c,o),c.structure!==a&&(c.structure=a),e.$broadcast("adfDashboardStructureChange")},a.closeDialog=function(){c.title=a.copy.title,u.close(),a.$destroy()}},a.addWidgetDialog=function(){var e,t=s(),l=a.model;angular.isFunction(f)?(e={},angular.forEach(n.widgets,function(t,a){f(t,a,l)&&(e[a]=t)})):e=n.widgets,t.widgets=e,t.translate=a.translate,a.options.categories&&(a.createCategories=i.createCategories);var c=r+"widget-add.html";l.addTemplateUrl&&(c=l.addTemplateUrl);var u={scope:t,templateUrl:c,windowClass:"adf-add-widget-modal",backdrop:"static"};angular.isDefined(a.adfAddWidgetModalOptions)&&(u=angular.merge(u,a.adfAddWidgetModalOptions));var g=o.open(u);t.addWidget=function(e){var o={type:e,config:i.createConfiguration(e)};i.addNewWidgetToModel(l,o,p),g.close(),t.$destroy(),i.isEditModeImmediate(e)&&d(a,o)},t.closeDialog=function(){g.close(),t.$destroy()}},a.addNewWidgetToModel=i.addNewWidgetToModel}function c(e,t,a){var o={name:a.name,editable:!0,enableConfirmDelete:l.stringToBoolean(a.enableConfirmDelete),maximizable:l.stringToBoolean(a.maximizable),collapsible:l.stringToBoolean(a.collapsible),categories:l.stringToBoolean(a.categories)};angular.isDefined(a.editable)&&(o.editable=l.stringToBoolean(a.editable)),e.options=o}return s.$inject=["$scope"],{replace:!0,restrict:"EA",transclude:!1,scope:{structure:"@",name:"@",collapsible:"@",editable:"@",editMode:"@",continuousEditMode:"=",maximizable:"@",adfModel:"=",adfAddWidgetModalOptions:"=",adfWidgetFilter:"=",categories:"@"},controller:s,link:c,templateUrl:r+"dashboard.html"}}]),angular.module("adf").directive("adfDashboardRow",["$compile","adfTemplatePath","columnTemplate",function(e,t,a){function o(t,o){angular.isDefined(t.row.columns)&&angular.isArray(t.row.columns)&&e(a)(t,function(e){o.append(e)})}return{restrict:"E",replace:!0,scope:{row:"=",adfModel:"=",editMode:"=",continuousEditMode:"=",options:"="},templateUrl:t+"dashboard-row.html",link:o}}]),angular.module("adf").directive("adfDashboardColumn",["$log","$compile","$rootScope","adfTemplatePath","rowTemplate","dashboard",function(e,t,a,o,n,r){function i(e,t,o){var n=t.widgets;e.$apply(function(){n.splice(o.newIndex,0,n.splice(o.oldIndex,1)[0]),a.$broadcast("adfWidgetMovedInColumn")})}function l(e,t){for(var a=null,o=0;o{}',d='
\n
\n loading ...\n
\n
',s=null,c=function(){return!0},u=e.defaultLocale,f=e.frameworkLocales;this.widget=function(e,t){var a=angular.extend({reload:!1,frameless:!1},t);if(a.edit){var o={reload:!0,immediate:!1,apply:c};angular.extend(o,a.edit),a.edit=o}return n[e]=a,this},this.widgetsPath=function(e){return r=e,this},this.structure=function(e,t){return i[e]=t,this},this.messageTemplate=function(e){return l=e,this},this.loadingTemplate=function(e){return d=e,this},this.customWidgetTemplatePath=function(e){return s=e,this},this.setLocale=function(e){if(!f[e])throw new Error("Cannot set locale: "+e+". Locale is not defined.");return u=e,this},this.addLocale=function(e,t){if(!angular.isString(e))throw new Error("locale must be an string");if(!angular.isObject(t))throw new Error("translations must be an object");return f[e]=t,this},this.$get=function(){var e=0;return{widgets:n,widgetsPath:r,structures:i,messageTemplate:l,loadingTemplate:d,setLocale:this.setLocale,locales:t,activeLocale:a,translate:o,customWidgetTemplatePath:s,id:function(){return(new Date).getTime()+"-"+ ++e},idEquals:function(e,t){return e&&t&&e.toString()===t.toString()}}}}]),angular.module("adf.locale",[]),angular.module("adf.locale").constant("adfLocale",{defaultLocale:"en-GB",frameworkLocales:{"en-GB":{ADF_COMMON_CLOSE:"Close",ADF_COMMON_DELETE:"Delete",ADF_COMMON_TITLE:"Title",ADF_COMMON_CANCEL:"Cancel",ADF_COMMON_APPLY:"Apply",ADF_COMMON_EDIT_DASHBOARD:"Edit dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Structure",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Add new widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Save changes",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Enable edit mode",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Undo changes",ADF_WIDGET_ADD_HEADER:"Add new widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Are you sure you want to delete this widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Reload widget Content",ADF_WIDGET_TOOLTIP_MOVE:"Change widget location",ADF_WIDGET_TOOLTIP_COLLAPSE:"Collapse widget",ADF_WIDGET_TOOLTIP_EXPAND:"Expand widget",ADF_WIDGET_TOOLTIP_EDIT:"Edit widget configuration",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Fullscreen widget",ADF_WIDGET_TOOLTIP_REMOVE:"Remove widget"},"sv-SE":{ADF_COMMON_CLOSE:"Stäng",ADF_COMMON_DELETE:"Ta bort",ADF_COMMON_TITLE:"Titel",ADF_COMMON_CANCEL:"Avbryt",ADF_COMMON_APPLY:"Använd",ADF_COMMON_EDIT_DASHBOARD:"Redigera dashboard",ADF_EDIT_DASHBOARD_STRUCTURE_LABEL:"Struktur",ADF_DASHBOARD_TITLE_TOOLTIP_ADD:"Lägg till ny widget",ADF_DASHBOARD_TITLE_TOOLTIP_SAVE:"Spara förändringar",ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE:"Slå på redigeringsläge",ADF_DASHBOARD_TITLE_TOOLTIP_UNDO:"Ångra förändringar",ADF_WIDGET_ADD_HEADER:"Lägg till ny widget",ADF_WIDGET_DELETE_CONFIRM_MESSAGE:"Är du säker på att du vill ta bort denna widget ?",ADF_WIDGET_TOOLTIP_REFRESH:"Ladda om widget",ADF_WIDGET_TOOLTIP_MOVE:"Ändra widgets position",ADF_WIDGET_TOOLTIP_COLLAPSE:"Stäng widget",ADF_WIDGET_TOOLTIP_EXPAND:"Öppna widget",ADF_WIDGET_TOOLTIP_EDIT:"Ändra widget konfigurering",ADF_WIDGET_TOOLTIP_FULLSCREEN:"Visa widget i fullskärm",ADF_WIDGET_TOOLTIP_REMOVE:"Ta bort widget"}}})}(window); //# sourceMappingURL=angular-dashboard-framework.min.js.map diff --git a/dist/angular-dashboard-framework.min.js.map b/dist/angular-dashboard-framework.min.js.map index c857aed9..0de48370 100644 --- a/dist/angular-dashboard-framework.min.js.map +++ b/dist/angular-dashboard-framework.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["adf.module.js","services/widget.service.js","services/adf-utils.service.js","services/adf-structure-preview.service.js","services/adf-dashboard.service.js","directives/adf-widget.directive.js","angular-dashboard-framework.min.js","directives/adf-widget-content.directive.js","directives/adf-structure-preview.directive.js","directives/adf-dashboard.directive.js","directives/adf-dashboard-row.directive.js","directives/adf-dashboard-column.directive.js","filters/adf-order-by-object-key.filter.js","dashboard.provider.js","adf.locale.module.js","adf.locale.constants.js","angular-dashboard-framework.js"],"names":["window","undefined","angular","module","value","factory","$http","$q","$sce","$templateCache","dashboard","parseUrl","url","parsedUrl","indexOf","replace","widgetsPath","substring","exposed","getTemplate","widget","deferred","defer","template","resolve","templateUrl","tpl","get","getTrustedResourceUrl","then","response","data","put","reject","promise","stringToBoolean","string","isString","toLowerCase","Boolean","split","object","size","arr","i","forEach","key","index","service","adjustRowHeight","container","rows","length","height","row","style","columns","column","$log","$rootScope","_copyWidgets","source","target","widgets","w","shift","push","_fillStructure","root","counter","isDefined","isUndefined","_readColumns","col","hasOwnProperty","changeStructure","model","structure","copy","createConfiguration","type","cfg","config","_findFirstWidgetColumn","isArray","error","j","addNewWidgetToModel","name","unshift","$broadcast","isEditModeImmediate","edit","immediate","createCategories","categories","category","_tests","directive","$injector","$uibModal","adfTemplatePath","preLink","$scope","definition","translate","title","titleTemplateUrl","editTemplateUrl","frameless","styleClass","wid","id","fromJson","widgetState","isCollapsed","collapsed","warn","debug","postLink","$element","deleteWidget","splice","remove","options","enableConfirmDelete","deleteScope","$new","deleteTemplateUrl","opts","scope","windowClass","backdrop","instance","open","closeDialog","close","$destroy","deleteDialog","reload","createApplyPromise","result","when","editScope","adfEditTemplatePath","saveDialog","validationError","applyFn","apply","locals","invoke","extend","err","controller","$on","event","args","collapseExpandStatus","idEquals","widgetClasses","classes","editMode","openFullScreen","fullScreenScope","modalSize","$inject","restrict","transclude","customWidgetTemplatePath","adfModel","compile","pre","post","widgetService","$compile","$controller","renderError","msg","html","messageTemplate","compileWidget","currentScope","content","newScope","renderWidget","loadingTemplate","templateScope","base","resolvers","$tpl","all","resolveAs","templateCtrl","controllerAs","children","contents","reason","link","adfStructurePreviewService","preview","selected","$timeout","adfDashboardService","adfUtilsService","_openEditMode","getNewModalScope","widgetFilter","structureName","$watch","oldVal","newVal","adfWidgetFilter","structures","editClass","toggleEditMode","continuousEditMode","modelCopy","collapseAll","cancelEditMode","editDashboardDialog","editDashboardScope","info","addWidgetDialog","addScope","isFunction","adfAddTemplatePath","addTemplateUrl","addWidget","$attr","editable","maximizable","collapsible","columnTemplate","cloned","append","rowTemplate","moveWidgetInColumn","evt","$apply","newIndex","oldIndex","findWidget","findColumn","r","c","cid","getId","el","getAttribute","addWidgetToColumn","targetColumn","from","sourceColumn","item","removeWidgetFromColumn","applySortable","sortable","Sortable","create","group","handle","ghostClass","animation","onAdd","onRemove","onUpdate","on","destroy","filter","$filter","array","objectKey","provider","adfLocale","getLocales","locales","getActiveLocale","activeLocale","label","translation","defaultApplyFunction","defaultLocale","frameworkLocales","this","path","templatePath","setLocale","locale","Error","addLocale","translations","isObject","$get","Date","getTime","other","toString","constant","en-GB","ADF_COMMON_CLOSE","ADF_COMMON_DELETE","ADF_COMMON_TITLE","ADF_COMMON_CANCEL","ADF_COMMON_APPLY","ADF_COMMON_EDIT_DASHBOARD","ADF_EDIT_DASHBOARD_STRUCTURE_LABEL","ADF_DASHBOARD_TITLE_TOOLTIP_ADD","ADF_DASHBOARD_TITLE_TOOLTIP_SAVE","ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE","ADF_DASHBOARD_TITLE_TOOLTIP_UNDO","ADF_WIDGET_ADD_HEADER","ADF_WIDGET_DELETE_CONFIRM_MESSAGE","ADF_WIDGET_TOOLTIP_REFRESH","ADF_WIDGET_TOOLTIP_MOVE","ADF_WIDGET_TOOLTIP_COLLAPSE","ADF_WIDGET_TOOLTIP_EXPAND","ADF_WIDGET_TOOLTIP_EDIT","ADF_WIDGET_TOOLTIP_FULLSCREEN","ADF_WIDGET_TOOLTIP_REMOVE","sv-SE"],"mappings":"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","file":"angular-dashboard-framework.min.js","sourcesContent":["/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '<>');\n","\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n 'use strict';\n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n 'use strict';\n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n 'use strict';\n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n 'use strict';\n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', [\"$http\", \"$q\", \"$sce\", \"$templateCache\", \"dashboard\", function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', [\"$log\", \"dashboard\", \"$rootScope\", function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', [\"$log\", \"$q\", \"widgetService\", \"$compile\", \"$controller\", \"$injector\", \"dashboard\", function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', [\"adfTemplatePath\", \"adfStructurePreviewService\", function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', [\"$rootScope\", \"$log\", \"$timeout\", \"$uibModal\", \"dashboard\", \"adfTemplatePath\", \"adfDashboardService\", \"adfUtilsService\", function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n controller.$inject = [\"$scope\"];\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', [\"$compile\", \"adfTemplatePath\", \"columnTemplate\", function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', [\"$log\", \"$compile\", \"$rootScope\", \"adfTemplatePath\", \"rowTemplate\", \"dashboard\", function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n 'use strict';\n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf.locale', [])\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n'use strict';\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);"]} \ No newline at end of file +{"version":3,"sources":["adf.module.js","services/widget.service.js","services/adf-utils.service.js","services/adf-structure-preview.service.js","services/adf-dashboard.service.js","filters/adf-order-by-object-key.filter.js","directives/adf-widget.directive.js","angular-dashboard-framework.min.js","directives/adf-widget-content.directive.js","directives/adf-structure-preview.directive.js","directives/adf-dashboard.directive.js","directives/adf-dashboard-row.directive.js","directives/adf-dashboard-column.directive.js","dashboard.provider.js","adf.locale.module.js","adf.locale.constants.js","angular-dashboard-framework.js"],"names":["window","undefined","angular","module","value","factory","$http","$q","$sce","$templateCache","dashboard","parseUrl","url","parsedUrl","indexOf","replace","widgetsPath","substring","exposed","getTemplate","widget","deferred","defer","template","resolve","templateUrl","tpl","get","getTrustedResourceUrl","then","response","data","put","reject","promise","stringToBoolean","string","isString","toLowerCase","Boolean","split","object","size","arr","i","forEach","key","index","service","adjustRowHeight","container","rows","length","height","row","style","columns","column","$log","$rootScope","_copyWidgets","source","target","widgets","w","shift","push","_fillStructure","root","counter","isDefined","isUndefined","_readColumns","col","hasOwnProperty","changeStructure","model","structure","copy","createConfiguration","type","cfg","config","_findFirstWidgetColumn","isArray","error","j","addNewWidgetToModel","name","unshift","$broadcast","isEditModeImmediate","edit","immediate","createCategories","categories","category","_tests","filter","$filter","item","array","objectKey","directive","$injector","$uibModal","adfTemplatePath","preLink","$scope","definition","translate","title","titleTemplateUrl","editTemplateUrl","frameless","styleClass","wid","id","fromJson","widgetState","isCollapsed","collapsed","warn","debug","postLink","$element","deleteWidget","splice","remove","options","enableConfirmDelete","deleteScope","$new","deleteTemplateUrl","opts","scope","windowClass","backdrop","instance","open","closeDialog","close","$destroy","deleteDialog","reload","createApplyPromise","result","when","editScope","adfEditTemplatePath","saveDialog","validationError","applyFn","apply","locals","invoke","extend","err","controller","$on","event","args","collapseExpandStatus","idEquals","widgetClasses","classes","editMode","openFullScreen","fullScreenScope","modalSize","$inject","restrict","transclude","customWidgetTemplatePath","adfModel","compile","pre","post","widgetService","$compile","$controller","renderError","msg","html","messageTemplate","compileWidget","currentScope","content","newScope","renderWidget","loadingTemplate","templateScope","base","resolvers","$tpl","all","resolveAs","templateCtrl","controllerAs","children","contents","reason","link","adfStructurePreviewService","preview","selected","$timeout","adfDashboardService","adfUtilsService","_openEditMode","getNewModalScope","widgetFilter","structureName","$watch","oldVal","newVal","adfWidgetFilter","structures","editClass","toggleEditMode","continuousEditMode","modelCopy","collapseAll","cancelEditMode","editDashboardDialog","editDashboardScope","info","addWidgetDialog","addScope","isFunction","adfAddTemplatePath","addTemplateUrl","adfAddWidgetModalOptions","merge","addWidget","$attr","editable","maximizable","collapsible","columnTemplate","cloned","append","rowTemplate","moveWidgetInColumn","evt","$apply","newIndex","oldIndex","findWidget","findColumn","r","c","cid","getId","el","getAttribute","addWidgetToColumn","targetColumn","from","sourceColumn","removeWidgetFromColumn","applySortable","sortable","Sortable","create","group","handle","ghostClass","animation","onAdd","onRemove","onUpdate","on","destroy","provider","adfLocale","getLocales","locales","getActiveLocale","activeLocale","label","translation","defaultApplyFunction","defaultLocale","frameworkLocales","this","path","templatePath","setLocale","locale","Error","addLocale","translations","isObject","$get","Date","getTime","other","toString","constant","en-GB","ADF_COMMON_CLOSE","ADF_COMMON_DELETE","ADF_COMMON_TITLE","ADF_COMMON_CANCEL","ADF_COMMON_APPLY","ADF_COMMON_EDIT_DASHBOARD","ADF_EDIT_DASHBOARD_STRUCTURE_LABEL","ADF_DASHBOARD_TITLE_TOOLTIP_ADD","ADF_DASHBOARD_TITLE_TOOLTIP_SAVE","ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE","ADF_DASHBOARD_TITLE_TOOLTIP_UNDO","ADF_WIDGET_ADD_HEADER","ADF_WIDGET_DELETE_CONFIRM_MESSAGE","ADF_WIDGET_TOOLTIP_REFRESH","ADF_WIDGET_TOOLTIP_MOVE","ADF_WIDGET_TOOLTIP_COLLAPSE","ADF_WIDGET_TOOLTIP_EXPAND","ADF_WIDGET_TOOLTIP_EDIT","ADF_WIDGET_TOOLTIP_FULLSCREEN","ADF_WIDGET_TOOLTIP_REMOVE","sv-SE"],"mappings":"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","file":"angular-dashboard-framework.min.js","sourcesContent":["/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '<>');\n","\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n 'use strict';\n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n 'use strict';\n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n 'use strict';\n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n 'use strict';\n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', [\"$http\", \"$q\", \"$sce\", \"$templateCache\", \"dashboard\", function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', [\"$log\", \"dashboard\", \"$rootScope\", function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', [\"$log\", \"$q\", \"widgetService\", \"$compile\", \"$controller\", \"$injector\", \"dashboard\", function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', [\"adfTemplatePath\", \"adfStructurePreviewService\", function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', [\"$rootScope\", \"$log\", \"$timeout\", \"$uibModal\", \"dashboard\", \"adfTemplatePath\", \"adfDashboardService\", \"adfUtilsService\", function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n controller.$inject = [\"$scope\"];\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfAddWidgetModalOptions: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n $rootScope.$broadcast('adfDashboardStructureChange');\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n if (angular.isDefined($scope.adfAddWidgetModalOptions)) {\n opts = angular.merge(opts, $scope.adfAddWidgetModalOptions);\n }\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', [\"$compile\", \"adfTemplatePath\", \"columnTemplate\", function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n }]);\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', [\"$log\", \"$compile\", \"$rootScope\", \"adfTemplatePath\", \"rowTemplate\", \"dashboard\", function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n }]);\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n 'use strict';\n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfAddWidgetModalOptions: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n $rootScope.$broadcast('adfDashboardStructureChange');\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n if (angular.isDefined($scope.adfAddWidgetModalOptions)) {\n opts = angular.merge(opts, $scope.adfAddWidgetModalOptions);\n }\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n 'use strict';\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n","/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n'use strict';\n\nangular.module('adf.locale', [])\n","/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n'use strict';\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n","(function(window, undefined) {'use strict';\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf', ['adf.provider', 'adf.locale', 'ui.bootstrap'])\n .value('adfTemplatePath', '../src/templates/')\n .value('rowTemplate', '')\n .value('columnTemplate', '')\n .value('adfVersion', '0.13.0-SNAPSHOT');\n\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n/**\n * The widget service provide helper functions to render widgets and their content.\n */\nangular.module('adf')\n .factory('widgetService', function($http, $q, $sce, $templateCache, dashboard) {\n \n\n function parseUrl(url) {\n var parsedUrl = url;\n if (url.indexOf('{widgetsPath}') >= 0) {\n parsedUrl = url.replace('{widgetsPath}', dashboard.widgetsPath)\n .replace('//', '/');\n if (parsedUrl.indexOf('/') === 0) {\n parsedUrl = parsedUrl.substring(1);\n }\n }\n return parsedUrl;\n }\n\n var exposed = {};\n\n exposed.getTemplate = function(widget){\n var deferred = $q.defer();\n\n if (widget.template) {\n deferred.resolve(widget.template);\n } else if (widget.templateUrl) {\n // try to fetch template from cache\n var tpl = $templateCache.get(widget.templateUrl);\n if (tpl) {\n deferred.resolve(tpl);\n } else {\n var url = $sce.getTrustedResourceUrl(parseUrl(widget.templateUrl));\n $http.get(url)\n .then(function(response) {\n return response.data;\n })\n .then(function(data) {\n // put response to cache, with unmodified url as key\n $templateCache.put(widget.templateUrl, data);\n deferred.resolve(data);\n })\n .catch(function() {\n deferred.reject('could not load template');\n });\n }\n }\n\n return deferred.promise;\n };\n\n return exposed;\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfUtilsService', function () {\n \n\n var service = {\n stringToBoolean: stringToBoolean,\n split: split\n };\n return service;\n\n function stringToBoolean(string){\n switch(angular.isString(string) ? string.toLowerCase() : null){\n case 'true': case 'yes': case '1': return true;\n case 'false': case 'no': case '0': case null: return false;\n default: return Boolean(string);\n }\n }\n\n /**\n * Splits an object into an array multiple objects inside.\n *\n * @param object source object\n * @param size size of array\n *\n * @return array of splitted objects\n */\n function split(object, size) {\n var arr = [];\n var i = 0;\n angular.forEach(object, function(value, key){\n var index = i++ % size;\n if (!arr[index]){\n arr[index] = {};\n }\n arr[index][key] = value;\n });\n return arr;\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfStructurePreviewService', function () {\n \n\n var service = {\n adjustRowHeight: adjustRowHeight\n };\n return service;\n\n function adjustRowHeight(container){\n if (container.rows && container.rows.length > 0){\n var height = 100 / container.rows.length;\n angular.forEach(container.rows, function(row){\n row.style = {\n height: height + '%'\n }\n\n if (row.columns){\n angular.forEach(row.columns, function(column){\n adjustRowHeight(column);\n });\n }\n });\n }\n }\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nangular.module('adf')\n .factory('adfDashboardService', function ($log, dashboard, $rootScope) {\n \n\n var service = {\n changeStructure: changeStructure,\n createConfiguration: createConfiguration,\n addNewWidgetToModel: addNewWidgetToModel,\n isEditModeImmediate: isEditModeImmediate,\n createCategories: createCategories,\n\n // expose internal functions for testing purposes\n // TODO find a nicer way\n _tests: {\n _readColumns: _readColumns\n }\n };\n return service;\n\n function _copyWidgets(source, target) {\n if ( source.widgets && source.widgets.length > 0 ){\n var w = source.widgets.shift();\n while (w){\n target.widgets.push(w);\n w = source.widgets.shift();\n }\n }\n }\n\n /**\n * Copy widget from old columns to the new model\n * @param object root the model\n * @param array of columns\n * @param counter\n */\n function _fillStructure(root, columns, counter) {\n counter = counter || 0;\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (column) {\n // if the widgets prop doesn't exist, create a new array for it.\n // this allows ui.sortable to do it's thing without error\n if (!column.widgets) {\n column.widgets = [];\n }\n\n // if a column exist at the counter index, copy over the column\n if (angular.isDefined(columns[counter])) {\n // do not add widgets to a column, which uses nested rows\n if (angular.isUndefined(column.rows)){\n _copyWidgets(columns[counter], column);\n counter++;\n }\n }\n\n // run fillStructure again for any sub rows/columns\n counter = _fillStructure(column, columns, counter);\n });\n });\n }\n return counter;\n }\n\n /**\n * Read Columns: recursively searches an object for the 'columns' property\n * @param object model\n * @param array an array of existing columns; used when recursion happens\n */\n function _readColumns(root, columns) {\n columns = columns || [];\n\n if (angular.isDefined(root.rows)) {\n angular.forEach(root.rows, function (row) {\n angular.forEach(row.columns, function (col) {\n if (!col.hasOwnProperty('rows')) {\n columns.push(col);\n }\n // keep reading columns until we can't any more\n _readColumns(col, columns);\n });\n });\n }\n\n return columns;\n }\n\n function changeStructure(model, structure){\n var columns = _readColumns(model);\n var counter = 0;\n\n model.rows = angular.copy(structure.rows);\n\n while ( counter < columns.length ){\n counter = _fillStructure(model, columns, counter);\n }\n }\n\n function createConfiguration(type){\n var cfg = {};\n var config = dashboard.widgets[type].config;\n if (config){\n cfg = angular.copy(config);\n }\n return cfg;\n }\n\n /**\n * Find first widget column in model.\n *\n * @param dashboard model\n */\n function _findFirstWidgetColumn(model){\n var column = null;\n if (!angular.isArray(model.rows)){\n $log.error('model does not have any rows');\n return null;\n }\n for (var i=0; i= 0) {\n column.widgets.splice(index, 1);\n }\n }\n $element.remove();\n $rootScope.$broadcast('adfWidgetRemovedFromColumn', definition);\n };\n\n $scope.remove = function() {\n if ($scope.options.enableConfirmDelete) {\n var deleteScope = $scope.$new();\n deleteScope.translate = dashboard.translate;\n\n var deleteTemplateUrl = adfTemplatePath + 'widget-delete.html';\n if (definition.deleteTemplateUrl) {\n deleteTemplateUrl = definition.deleteTemplateUrl;\n }\n var opts = {\n scope: deleteScope,\n templateUrl: deleteTemplateUrl,\n windowClass: 'adf-remove-widget-modal',\n backdrop: 'static'\n };\n var instance = $uibModal.open(opts);\n\n deleteScope.closeDialog = function() {\n instance.close();\n deleteScope.$destroy();\n };\n deleteScope.deleteDialog = function() {\n deleteWidget();\n deleteScope.closeDialog();\n };\n } else {\n deleteWidget();\n }\n };\n\n // bind reload function\n $scope.reload = function() {\n $scope.$broadcast('widgetReload');\n };\n\n // bind edit function\n $scope.edit = function() {\n var editScope = $scope.$new();\n editScope.translate = dashboard.translate;\n editScope.definition = angular.copy(definition);\n\n var adfEditTemplatePath = adfTemplatePath + 'widget-edit.html';\n if (definition.editTemplateUrl) {\n adfEditTemplatePath = definition.editTemplateUrl;\n }\n\n var opts = {\n scope: editScope,\n templateUrl: adfEditTemplatePath,\n windowClass: 'adf-edit-widget-modal',\n backdrop: 'static'\n };\n\n var instance = $uibModal.open(opts);\n\n editScope.closeDialog = function() {\n instance.close();\n editScope.$destroy();\n };\n\n // TODO create util method\n function createApplyPromise(result){\n var promise;\n if (typeof result === 'boolean'){\n var deferred = $q.defer();\n if (result){\n deferred.resolve();\n } else {\n deferred.reject();\n }\n promise = deferred.promise;\n } else {\n promise = $q.when(result);\n }\n return promise;\n }\n\n editScope.saveDialog = function() {\n // clear validation error\n editScope.validationError = null;\n\n // build injection locals\n var widget = $scope.widget;\n\n // create a default apply method for widgets\n // without edit mode\n // see issue https://goo.gl/KHPQLZ\n var applyFn;\n if (widget.edit){\n applyFn = widget.edit.apply;\n } else {\n applyFn = function(){\n return true;\n };\n }\n\n // injection locals\n var locals = {\n widget: widget,\n definition: editScope.definition,\n config: editScope.definition.config\n };\n\n // invoke apply function and apply if success\n var result = $injector.invoke(applyFn, applyFn, locals);\n createApplyPromise(result).then(function(){\n definition.title = editScope.definition.title;\n angular.extend(definition.config, editScope.definition.config);\n if (widget.edit && widget.edit.reload) {\n // reload content after edit dialog is closed\n $scope.$broadcast('widgetConfigChanged');\n }\n editScope.closeDialog();\n }, function(err){\n if (err){\n editScope.validationError = err;\n } else {\n editScope.validationError = 'Validation durring apply failed';\n }\n });\n };\n\n };\n } else {\n $log.debug('widget not found');\n }\n }\n\n function controller($scope){\n\n $scope.$on('adfDashboardCollapseExpand', function(event, args) {\n $scope.widgetState.isCollapsed = args.collapseExpandStatus;\n });\n\n $scope.$on('adfWidgetEnterEditMode', function(event, widget){\n if (dashboard.idEquals($scope.definition.wid, widget.wid)){\n $scope.edit();\n }\n });\n\n $scope.widgetClasses = function(w, definition){\n var classes = definition.styleClass || '';\n // w is undefined, if the type of the widget is unknown\n // see issue #216\n if (!w || !w.frameless || $scope.editMode){\n classes += ' panel panel-default';\n }\n return classes;\n };\n\n $scope.openFullScreen = function() {\n var definition = $scope.definition;\n var fullScreenScope = $scope.$new();\n var opts = {\n scope: fullScreenScope,\n templateUrl: adfTemplatePath + 'widget-fullscreen.html',\n size: definition.modalSize || 'lg', // 'sm', 'lg'\n backdrop: 'static',\n windowClass: (definition.fullScreen) ? 'dashboard-modal widget-fullscreen' : 'dashboard-modal'\n };\n\n var instance = $uibModal.open(opts);\n fullScreenScope.closeDialog = function() {\n instance.close();\n fullScreenScope.$destroy();\n };\n };\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf')\n .directive('adfWidgetContent', function($log, $q, widgetService, $compile, $controller, $injector, dashboard) {\n\n return {\n replace: true,\n restrict: 'EA',\n transclude: false,\n scope: {\n adfModel: '=',\n model: '=',\n content: '='\n },\n link: link\n };\n\n function renderError($element, msg){\n $log.warn(msg);\n $element.html(dashboard.messageTemplate.replace(/{}/g, msg));\n }\n\n function compileWidget($scope, $element, currentScope) {\n var model = $scope.model;\n var content = $scope.content;\n\n var newScope = currentScope;\n if (!model){\n renderError($element, 'model is undefined')\n } else if (!content){\n var msg = 'widget content is undefined, please have a look at your browser log';\n renderError($element, msg);\n } else {\n newScope = renderWidget($scope, $element, currentScope, model, content);\n }\n return newScope;\n }\n\n function renderWidget($scope, $element, currentScope, model, content) {\n // display loading template\n $element.html(dashboard.loadingTemplate);\n\n // create new scope\n var templateScope = $scope.$new();\n\n // pass config object to scope\n if (!model.config) {\n model.config = {};\n }\n\n templateScope.config = model.config;\n\n // local injections\n var base = {\n $scope: templateScope,\n widget: model,\n config: model.config\n };\n\n // get resolve promises from content object\n var resolvers = {};\n resolvers.$tpl = widgetService.getTemplate(content);\n if (content.resolve) {\n angular.forEach(content.resolve, function(promise, key) {\n if (angular.isString(promise)) {\n resolvers[key] = $injector.get(promise);\n } else {\n resolvers[key] = $injector.invoke(promise, promise, base);\n }\n });\n }\n\n // resolve all resolvers\n $q.all(resolvers).then(function(locals) {\n angular.extend(locals, base);\n\n // pass resolve map to template scope as defined in resolveAs\n if (content.resolveAs){\n templateScope[content.resolveAs] = locals;\n }\n\n // compile & render template\n var template = locals.$tpl;\n $element.html(template);\n if (content.controller) {\n var templateCtrl = $controller(content.controller, locals);\n if (content.controllerAs) {\n templateScope[content.controllerAs] = templateCtrl;\n }\n $element.children().data('$ngControllerController', templateCtrl);\n }\n $compile($element.contents())(templateScope);\n }, function(reason) {\n // handle promise rejection\n var msg = 'Could not resolve all promises';\n if (reason) {\n msg += ': ' + reason;\n }\n renderError($element, msg);\n });\n\n // destroy old scope\n if (currentScope) {\n currentScope.$destroy();\n }\n\n return templateScope;\n }\n\n function link($scope, $element) {\n var currentScope = compileWidget($scope, $element, null);\n $scope.$on('widgetConfigChanged', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n $scope.$on('widgetReload', function() {\n currentScope = compileWidget($scope, $element, currentScope);\n });\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfStructurePreview', function(adfTemplatePath, adfStructurePreviewService) {\n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n name: '=',\n structure: '=',\n selected: '='\n },\n templateUrl: adfTemplatePath + 'structure-preview.html',\n link: link\n };\n\n function link($scope){\n var structure = angular.copy($scope.structure);\n adfStructurePreviewService.adjustRowHeight(structure);\n $scope.preview = structure;\n }\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * @ngdoc directive\n * @name adf.directive:adfDashboard\n * @element div\n * @restrict EA\n * @scope\n * @description\n *\n * `adfDashboard` is a directive which renders the dashboard with all its\n * components. The directive requires a name attribute. The name of the\n * dashboard can be used to store the model.\n *\n * @param {string} name name of the dashboard. This attribute is required.\n * @param {boolean=} editable false to disable the editmode of the dashboard.\n * @param {boolean=} collapsible true to make widgets collapsible on the dashboard.\n * @param {boolean=} maximizable true to add a button for open widgets in a large modal panel.\n * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard.\n * @param {string=} structure the default structure of the dashboard.\n * @param {object=} adfModel model object of the dashboard.\n * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal\n * @param {function=} adfWidgetFilter function to filter widgets on the add dialog.\n * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove\n * events during edit mode not reset it if edit mode is exited.\n * @param {boolean=} categories enable categories for the add widget dialog.\n */\n\nangular.module('adf')\n .directive('adfDashboard', function ($rootScope, $log, $timeout, $uibModal, dashboard, adfTemplatePath, adfDashboardService, adfUtilsService) {\n \n\n return {\n replace: true,\n restrict: 'EA',\n transclude : false,\n scope: {\n structure: '@',\n name: '@',\n collapsible: '@',\n editable: '@',\n editMode: '@',\n continuousEditMode: '=',\n maximizable: '@',\n adfModel: '=',\n adfAddWidgetModalOptions: '=',\n adfWidgetFilter: '=',\n categories: '@'\n },\n controller: controller,\n link: link,\n templateUrl: adfTemplatePath + 'dashboard.html'\n };\n\n /**\n * Opens the edit mode of the specified widget.\n *\n * @param dashboard scope\n * @param widget\n */\n function _openEditMode($scope, widget){\n // wait some time before fire enter edit mode event\n $timeout(function(){\n $scope.$broadcast('adfWidgetEnterEditMode', widget);\n }, 200);\n }\n\n /**\n * Directive controller function.\n *\n * @param dashboard scope\n */\n function controller($scope){\n var model = {};\n var structure = {};\n var widgetFilter = null;\n var structureName = {};\n var name = $scope.name;\n\n // Watching for changes on adfModel\n $scope.$watch('adfModel', function(oldVal, newVal) {\n // has model changed or is the model attribute not set\n if (newVal !== null || (oldVal === null && newVal === null)) {\n model = $scope.adfModel;\n widgetFilter = $scope.adfWidgetFilter;\n if ( ! model || ! model.rows ){\n structureName = $scope.structure;\n structure = dashboard.structures[structureName];\n if (structure){\n if (model){\n model.rows = angular.copy(structure).rows;\n } else {\n model = angular.copy(structure);\n }\n model.structure = structureName;\n } else {\n $log.error( 'could not find structure ' + structureName);\n }\n }\n\n if (model) {\n if (!model.title){\n model.title = 'Dashboard';\n }\n if (!model.titleTemplateUrl) {\n model.titleTemplateUrl = adfTemplatePath + 'dashboard-title.html';\n }\n $scope.model = model;\n } else {\n $log.error('could not find or create model');\n }\n }\n }, true);\n\n // edit mode\n $scope.editMode = false;\n $scope.editClass = '';\n\n //passs translate function from dashboard so we can translate labels inside html templates\n $scope.translate = dashboard.translate;\n\n function getNewModalScope() {\n var scope = $scope.$new();\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n scope.translate = dashboard.translate;\n return scope;\n }\n\n $scope.toggleEditMode = function(){\n $scope.editMode = ! $scope.editMode;\n if ($scope.editMode){\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.adfModel, {});\n $rootScope.$broadcast('adfIsEditMode');\n }\n }\n\n if (!$scope.editMode){\n $rootScope.$broadcast('adfDashboardChanged', name, model);\n }\n };\n\n $scope.$on('adfToggleEditMode', function() {\n $scope.toggleEditMode();\n });\n\n $scope.collapseAll = function(collapseExpandStatus){\n $rootScope.$broadcast('adfDashboardCollapseExpand',{collapseExpandStatus : collapseExpandStatus});\n };\n\n $scope.cancelEditMode = function(){\n $scope.editMode = false;\n if (!$scope.continuousEditMode) {\n $scope.modelCopy = angular.copy($scope.modelCopy, $scope.adfModel);\n }\n $rootScope.$broadcast('adfDashboardEditsCancelled');\n };\n\n // edit dashboard settings\n $scope.editDashboardDialog = function(){\n var editDashboardScope = getNewModalScope();\n // create a copy of the title, to avoid changing the title to\n // \"dashboard\" if the field is empty\n editDashboardScope.copy = {\n title: model.title\n };\n\n // pass dashboard structure to scope\n editDashboardScope.structures = dashboard.structures;\n\n // pass split function to scope, to be able to display structures in multiple columns\n editDashboardScope.split = adfUtilsService.split;\n\n var adfEditTemplatePath = adfTemplatePath + 'dashboard-edit.html';\n if(model.editTemplateUrl) {\n adfEditTemplatePath = model.editTemplateUrl;\n }\n var instance = $uibModal.open({\n scope: editDashboardScope,\n templateUrl: adfEditTemplatePath,\n backdrop: 'static',\n windowClass: 'adf-edit-dashboard-modal',\n size: 'lg'\n });\n editDashboardScope.changeStructure = function(name, structure){\n $log.info('change structure to ' + name);\n adfDashboardService.changeStructure(model, structure);\n if (model.structure !== name){\n model.structure = name;\n }\n $rootScope.$broadcast('adfDashboardStructureChange');\n };\n editDashboardScope.closeDialog = function(){\n // copy the new title back to the model\n model.title = editDashboardScope.copy.title;\n // close modal and destroy the scope\n instance.close();\n editDashboardScope.$destroy();\n };\n };\n\n // add widget dialog\n $scope.addWidgetDialog = function(){\n var addScope = getNewModalScope();\n var model = $scope.model;\n var widgets;\n if (angular.isFunction(widgetFilter)){\n widgets = {};\n angular.forEach(dashboard.widgets, function(widget, type){\n if (widgetFilter(widget, type, model)){\n widgets[type] = widget;\n }\n });\n } else {\n widgets = dashboard.widgets;\n }\n addScope.widgets = widgets;\n\n //pass translate function to the new scope so we can translate the labels inside the modal dialog\n addScope.translate = $scope.translate;\n\n // pass createCategories function to scope, if categories option is enabled\n if ($scope.options.categories){\n $scope.createCategories = adfDashboardService.createCategories;\n }\n\n var adfAddTemplatePath = adfTemplatePath + 'widget-add.html';\n if(model.addTemplateUrl) {\n adfAddTemplatePath = model.addTemplateUrl;\n }\n\n var opts = {\n scope: addScope,\n templateUrl: adfAddTemplatePath,\n windowClass: 'adf-add-widget-modal',\n backdrop: 'static'\n };\n\n if (angular.isDefined($scope.adfAddWidgetModalOptions)) {\n opts = angular.merge(opts, $scope.adfAddWidgetModalOptions);\n }\n\n var instance = $uibModal.open(opts);\n addScope.addWidget = function(widget){\n var w = {\n type: widget,\n config: adfDashboardService.createConfiguration(widget)\n };\n adfDashboardService.addNewWidgetToModel(model, w, name);\n // close and destroy\n instance.close();\n addScope.$destroy();\n\n // check for open edit mode immediately\n if (adfDashboardService.isEditModeImmediate(widget)){\n _openEditMode($scope, w);\n }\n };\n addScope.closeDialog = function(){\n // close and destroy\n instance.close();\n addScope.$destroy();\n };\n };\n\n $scope.addNewWidgetToModel = adfDashboardService.addNewWidgetToModel;\n }\n\n /**\n * Directive link function.\n *\n * @param dashboard scope\n * @param directive DOM element\n * @param directive attributes\n */\n function link($scope, $element, $attr) {\n // pass options to scope\n var options = {\n name: $attr.name,\n editable: true,\n enableConfirmDelete: adfUtilsService.stringToBoolean($attr.enableConfirmDelete),\n maximizable: adfUtilsService.stringToBoolean($attr.maximizable),\n collapsible: adfUtilsService.stringToBoolean($attr.collapsible),\n categories: adfUtilsService.stringToBoolean($attr.categories)\n };\n if (angular.isDefined($attr.editable)){\n options.editable = adfUtilsService.stringToBoolean($attr.editable);\n }\n $scope.options = options;\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardRow', function ($compile, adfTemplatePath, columnTemplate) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n row: '=',\n adfModel: '=',\n editMode: '=',\n continuousEditMode: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-row.html',\n link: link\n };\n\n function link($scope, $element) {\n if (angular.isDefined($scope.row.columns) && angular.isArray($scope.row.columns)) {\n $compile(columnTemplate)($scope, function(cloned) {\n $element.append(cloned);\n });\n }\n }\n });\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n/* global angular */\nangular.module('adf')\n .directive('adfDashboardColumn', function ($log, $compile, $rootScope, adfTemplatePath, rowTemplate, dashboard) {\n \n\n return {\n restrict: 'E',\n replace: true,\n scope: {\n column: '=',\n editMode: '=',\n continuousEditMode: '=',\n adfModel: '=',\n options: '='\n },\n templateUrl: adfTemplatePath + 'dashboard-column.html',\n link: link\n };\n\n /**\n * moves a widget in between a column\n */\n function moveWidgetInColumn($scope, column, evt){\n var widgets = column.widgets;\n // move widget and apply to scope\n $scope.$apply(function(){\n widgets.splice(evt.newIndex, 0, widgets.splice(evt.oldIndex, 1)[0]);\n $rootScope.$broadcast('adfWidgetMovedInColumn');\n });\n }\n\n /**\n * finds a widget by its id in the column\n */\n function findWidget(column, index){\n var widget = null;\n for (var i=0; i=}` - An optional map of dependencies which should\n * be injected into the controller. If any of these dependencies are promises, the widget\n * will wait for them all to be resolved or one to be rejected before the controller is\n * instantiated.\n * If all the promises are resolved successfully, the values of the resolved promises are\n * injected.\n *\n * The map object is:\n * - `key` – `{string}`: a name of a dependency to be injected into the controller.\n * - `factory` - `{string|function}`: If `string` then it is an alias for a service.\n * Otherwise if function, then it is {@link http://docs.angularjs.org/api/AUTO.$injector#invoke injected}\n * and the return value is treated as the dependency. If the result is a promise, it is\n * resolved before its value is injected into the controller.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `edit` - `{object}` - Edit modus of the widget.\n * - `controller` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `controllerAs` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `template` - `{string=|function()=}` - Same as above, but for the edit mode of the widget.\n * - `templateUrl` - `{string=}` - Same as above, but for the edit mode of the widget.\n * - `resolve` - `{Object.=}` - Same as above, but for the edit mode of the widget.\n * - `resolveAs` - `{string=}` - The name under which the resolve map will be available\n * on the scope of the widget.\n * - `reload` - {boolean} - true if the widget should be reloaded, after the edit mode is closed.\n * Default is true.\n * - `immediate` - {boolean} - The widget enters the edit mode immediately after creation. Default is false.\n * - `apply` - `{function()=}` - The apply function is called, before the widget is saved.\n * The function have to return a boolean or an promise which can be resolved to a boolean.\n * The function can use injection.\n *\n * @returns {Object} self\n */\n this.widget = function(name, widget){\n var w = angular.extend({reload: false, frameless: false}, widget);\n if ( w.edit ){\n var edit = {\n reload: true,\n immediate: false,\n apply: defaultApplyFunction\n };\n angular.extend(edit, w.edit);\n w.edit = edit;\n }\n widgets[name] = w;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#widgetsPath\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Sets the path to the directory which contains the widgets. The widgets\n * path is used for widgets with a templateUrl which contains the\n * placeholder {widgetsPath}. The placeholder is replaced with the\n * configured value, before the template is loaded, but the template is\n * cached with the unmodified templateUrl (e.g.: {widgetPath}/src/widgets).\n * The default value of widgetPaths is ''.\n *\n *\n * @param {string} path to the directory which contains the widgets\n *\n * @returns {Object} self\n */\n this.widgetsPath = function(path){\n widgetsPath = path;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#structure\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Registers a new structure.\n *\n * @param {string} name of the structure\n * @param {object} structure to be registered.\n *\n * Object properties:\n *\n * - `rows` - `{Array.}` - Rows of the dashboard structure.\n * - `styleClass` - `{string}` - CSS Class of the row.\n * - `columns` - `{Array.}` - Columns of the row.\n * - `styleClass` - `{string}` - CSS Class of the column.\n *\n * @returns {Object} self\n */\n this.structure = function(name, structure){\n structures[name] = structure;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#messageTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template for messages.\n *\n * @param {string} template for messages.\n *\n * @returns {Object} self\n */\n this.messageTemplate = function(template){\n messageTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#loadingTemplate\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the template which is displayed as\n * long as the widget resources are not resolved.\n *\n * @param {string} template loading template\n *\n * @returns {Object} self\n */\n this.loadingTemplate = function(template){\n loadingTemplate = template;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#customWidgetTemplatePath\n * @propertyOf adf.dashboardProvider\n * @description\n *\n * Changes the container template for the widgets\n *\n * @param {string} path to the custom widget template\n *\n * @returns {Object} self\n */\n this.customWidgetTemplatePath = function(templatePath) {\n customWidgetTemplatePath = templatePath;\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#setLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Changes the locale setting of adf\n *\n * @param {string} ISO Language Code\n *\n * @returns {Object} self\n */\n this.setLocale = function(locale){\n if(locales[locale]) {\n activeLocale = locale;\n } else {\n throw new Error('Cannot set locale: ' + locale + '. Locale is not defined.');\n }\n return this;\n };\n\n /**\n * @ngdoc method\n * @name adf.dashboardProvider#addLocale\n * @methodOf adf.dashboardProvider\n * @description\n *\n * Adds a new locale to adf\n *\n * @param {string} ISO Language Code for the new locale\n * @param {object} translations for the locale.\n *\n * @returns {Object} self\n */\n this.addLocale = function(locale, translations){\n if(!angular.isString(locale)) {\n throw new Error('locale must be an string');\n }\n\n if(!angular.isObject(translations)) {\n throw new Error('translations must be an object');\n }\n\n locales[locale] = translations;\n return this;\n };\n\n /**\n * @ngdoc service\n * @name adf.dashboard\n * @description\n *\n * The dashboard holds all options, structures and widgets.\n *\n * @property {Array.} widgets Array of registered widgets.\n * @property {string} widgetsPath Default path for widgets.\n * @property {Array.} structures Array of registered structures.\n * @property {string} messageTemplate Template for messages.\n * @property {string} loadingTemplate Template for widget loading.\n * @property {method} sets locale of adf.\n * @property {Array.} hold all of the locale translations.\n * @property {string} the active locale setting.\n * @property {method} translation function passed to templates.\n *\n * @returns {Object} self\n */\n this.$get = function(){\n var cid = 0;\n\n return {\n widgets: widgets,\n widgetsPath: widgetsPath,\n structures: structures,\n messageTemplate: messageTemplate,\n loadingTemplate: loadingTemplate,\n setLocale: this.setLocale,\n locales: getLocales,\n activeLocale: getActiveLocale,\n translate: translate,\n customWidgetTemplatePath: customWidgetTemplatePath,\n\n /**\n * @ngdoc method\n * @name adf.dashboard#id\n * @methodOf adf.dashboard\n * @description\n *\n * Creates an ongoing numeric id. The method is used to create ids for\n * columns and widgets in the dashboard.\n */\n id: function(){\n return new Date().getTime() + '-' + (++cid);\n },\n\n /**\n * @ngdoc method\n * @name adf.dashboard#idEqual\n * @methodOf adf.dashboard\n * @description\n *\n * Checks if the given ids are equal.\n *\n * @param {string} id widget or column id\n * @param {string} other widget or column id\n */\n idEquals: function(id, other){\n // use toString, because old ids are numbers\n return ((id) && (other)) && (id.toString() === other.toString());\n }\n };\n };\n\n });\n\n/*\n * The MIT License\n *\n * Copyright (c) 2015, Sebastian Sdorra\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n\n\nangular.module('adf.locale', [])\n\n/*\n* The MIT License\n*\n* Copyright (c) 2015, Sebastian Sdorra\n*\n* Permission is hereby granted, free of charge, to any person obtaining a copy\n* of this software and associated documentation files (the \"Software\"), to deal\n* in the Software without restriction, including without limitation the rights\n* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the Software is\n* furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in\n* all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n* SOFTWARE.\n*/\n\n\n\n/**\n* @ngdoc object\n* @name adf.locale#adfLocale\n* @description\n*\n* Holds settings and values for framework supported locales\n*/\nangular.module('adf.locale')\n.constant('adfLocale',\n {\n defaultLocale: 'en-GB',\n frameworkLocales: {\n 'en-GB': {\n ADF_COMMON_CLOSE: 'Close',\n ADF_COMMON_DELETE: 'Delete',\n ADF_COMMON_TITLE: 'Title',\n ADF_COMMON_CANCEL: 'Cancel',\n ADF_COMMON_APPLY: 'Apply',\n ADF_COMMON_EDIT_DASHBOARD: 'Edit dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Structure',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Add new widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Save changes',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Enable edit mode',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Undo changes',\n ADF_WIDGET_ADD_HEADER: 'Add new widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Are you sure you want to delete this widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Reload widget Content',\n ADF_WIDGET_TOOLTIP_MOVE: 'Change widget location',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Collapse widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Expand widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Edit widget configuration',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Fullscreen widget',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Remove widget'\n },\n 'sv-SE': {\n ADF_COMMON_CLOSE: 'Stäng',\n ADF_COMMON_DELETE: 'Ta bort',\n ADF_COMMON_TITLE: 'Titel',\n ADF_COMMON_CANCEL: 'Avbryt',\n ADF_COMMON_APPLY: 'Använd',\n ADF_COMMON_EDIT_DASHBOARD: 'Redigera dashboard',\n ADF_EDIT_DASHBOARD_STRUCTURE_LABEL: 'Struktur',\n ADF_DASHBOARD_TITLE_TOOLTIP_ADD: 'Lägg till ny widget',\n ADF_DASHBOARD_TITLE_TOOLTIP_SAVE: 'Spara förändringar',\n ADF_DASHBOARD_TITLE_TOOLTIP_EDIT_MODE: 'Slå på redigeringsläge',\n ADF_DASHBOARD_TITLE_TOOLTIP_UNDO: 'Ångra förändringar',\n ADF_WIDGET_ADD_HEADER: 'Lägg till ny widget',\n ADF_WIDGET_DELETE_CONFIRM_MESSAGE: 'Är du säker på att du vill ta bort denna widget ?',\n ADF_WIDGET_TOOLTIP_REFRESH: 'Ladda om widget',\n ADF_WIDGET_TOOLTIP_MOVE: 'Ändra widgets position',\n ADF_WIDGET_TOOLTIP_COLLAPSE: 'Stäng widget',\n ADF_WIDGET_TOOLTIP_EXPAND: 'Öppna widget',\n ADF_WIDGET_TOOLTIP_EDIT: 'Ändra widget konfigurering',\n ADF_WIDGET_TOOLTIP_FULLSCREEN: 'Visa widget i fullskärm',\n ADF_WIDGET_TOOLTIP_REMOVE: 'Ta bort widget'\n }\n }\n }\n);\n\n})(window);"]} \ No newline at end of file diff --git a/src/scripts/directives/adf-dashboard.directive.js b/src/scripts/directives/adf-dashboard.directive.js index bef0370a..db785bec 100644 --- a/src/scripts/directives/adf-dashboard.directive.js +++ b/src/scripts/directives/adf-dashboard.directive.js @@ -41,6 +41,7 @@ * @param {boolean=} enableConfirmDelete true to ask before remove an widget from the dashboard. * @param {string=} structure the default structure of the dashboard. * @param {object=} adfModel model object of the dashboard. + * @param {object=} adfAddWidgetModalOptions options to provide to the add-widget modal * @param {function=} adfWidgetFilter function to filter widgets on the add dialog. * @param {boolean=} continuousEditMode enable continuous edit mode, to fire add/change/remove * events during edit mode not reset it if edit mode is exited. @@ -64,6 +65,7 @@ angular.module('adf') continuousEditMode: '=', maximizable: '@', adfModel: '=', + adfAddWidgetModalOptions: '=', adfWidgetFilter: '=', categories: '@' }, @@ -208,6 +210,7 @@ angular.module('adf') if (model.structure !== name){ model.structure = name; } + $rootScope.$broadcast('adfDashboardStructureChange'); }; editDashboardScope.closeDialog = function(){ // copy the new title back to the model @@ -255,6 +258,10 @@ angular.module('adf') backdrop: 'static' }; + if (angular.isDefined($scope.adfAddWidgetModalOptions)) { + opts = angular.merge(opts, $scope.adfAddWidgetModalOptions); + } + var instance = $uibModal.open(opts); addScope.addWidget = function(widget){ var w = { diff --git a/src/templates/dashboard-title.html b/src/templates/dashboard-title.html index 8d80e6be..ad48e01c 100644 --- a/src/templates/dashboard-title.html +++ b/src/templates/dashboard-title.html @@ -1,5 +1,8 @@

{{model.title}} + + + @@ -8,7 +11,7 @@

- + {{!editMode ? 'Edit' : 'Save' }}