diff options
author | Thomas Steur <thomas.steur@gmail.com> | 2015-07-03 03:54:27 +0300 |
---|---|---|
committer | sgiehl <stefan@piwik.org> | 2015-10-06 18:25:13 +0300 |
commit | 9ba8f216fd7856ce5fef06bf82ecb8f8a2e7e630 (patch) | |
tree | 6ce07d18a85d00b39ab720abe042361c0775aead /plugins/CoreHome/angularjs | |
parent | 8ccc9dc05da021325cdbf141a548637fa52f16b2 (diff) |
generate pages instead of implementing them in each controller
Diffstat (limited to 'plugins/CoreHome/angularjs')
30 files changed, 1391 insertions, 19 deletions
diff --git a/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js new file mode 100644 index 0000000000..4417cea7ac --- /dev/null +++ b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js @@ -0,0 +1,31 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Shows a general loading message while [loading] is set to true. + * + * @param {Boolean} loading If true, the activity indicator is shown, otherwise the indicator is hidden. + * + * Example: + * <div piwik-activity-indicator loading="true|false"></div> + */ +(function () { + angular.module('piwikApp').directive('piwikActivityIndicator', piwikActivityIndicator); + + piwikActivityIndicator.$inject = ['piwik']; + + function piwikActivityIndicator(piwik){ + return { + restrict: 'A', + transclude: true, + scope: { + loading: '=' + }, + templateUrl: 'plugins/CoreHome/angularjs/activity-indicator/activityindicator.html?cb=' + piwik.cacheBuster + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html new file mode 100644 index 0000000000..f6080ae817 --- /dev/null +++ b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html @@ -0,0 +1,3 @@ +<div ng-show="loading" class="loadingPiwik"> + <img src="plugins/Morpheus/images/loading-blue.gif" alt=""/>{{ 'General_LoadingData'|translate }} +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js b/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js index 89d572cedf..2eef346ec6 100644 --- a/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js +++ b/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js @@ -132,7 +132,9 @@ scope.ajaxForm.data[name] = val; if (!skipScopeApply) { - scope.$apply(); + setTimeout(function () { + scope.$apply(); + }, 0); } } }; diff --git a/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js b/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js index 0617c5df88..ee1a2cf219 100644 --- a/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js +++ b/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js @@ -24,13 +24,17 @@ function onClickOutsideElement (event) { if (element.has(event.target).length === 0) { - scope.$apply(attr.piwikFocusAnywhereButHere); + setTimeout(function () { + scope.$apply(attr.piwikFocusAnywhereButHere); + }, 0); } } function onEscapeHandler (event) { if (event.which === 27) { - scope.$apply(attr.piwikFocusAnywhereButHere); + setTimeout(function () { + scope.$apply(attr.piwikFocusAnywhereButHere); + }, 0); } } diff --git a/plugins/CoreHome/angularjs/common/filters/escape.js b/plugins/CoreHome/angularjs/common/filters/escape.js new file mode 100644 index 0000000000..382e84b5ac --- /dev/null +++ b/plugins/CoreHome/angularjs/common/filters/escape.js @@ -0,0 +1,16 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.filter').filter('escape', escape); + + function escape() { + + return function(value) { + return piwikHelper.escape(piwikHelper.htmlEntities(value)); + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js b/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js new file mode 100644 index 0000000000..f831995810 --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js @@ -0,0 +1,14 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').service('globalAjaxQueue', ajaxQueue); + + function ajaxQueue() { + + return globalAjaxQueue; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/piwik-url.js b/plugins/CoreHome/angularjs/common/services/piwik-url.js new file mode 100644 index 0000000000..f2d6e9bb0c --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/piwik-url.js @@ -0,0 +1,54 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').service('piwikUrl', piwikUrl); + + piwikUrl.$inject = ['$location', 'piwik']; + + /** + * Similar to angulars $location but works around some limitation. Use it if you need to access search params + */ + function piwikUrl($location, piwik) { + + var model = { + getSearchParam: getSearchParam + } + + return model; + + function getSearchParam(paramName) + { + if (paramName === 'segment') { + var hash = window.location.href.split('#'); + if (hash && hash[1]) { + return piwik.broadcast.getValueFromHash(paramName, hash[1]); + } + + return broadcast.getValueFromUrl(paramName); + } + + // available in global scope + var search = $location.search(); + + if (!search[paramName]) { + // see https://github.com/angular/angular.js/issues/7239 (issue is resolved but problem still exists) + search[paramName] = piwik.broadcast.getValueFromUrl(paramName); + } + + if (search[paramName]) { + var value = search[paramName]; + + if (angular.isArray(search[paramName])) { + // use last one. Eg when having period=day&period=year angular would otherwise return ['day', 'year'] + return value[value.length - 1]; + } + + return value; + } + } + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/report-metadata-model.js b/plugins/CoreHome/angularjs/common/services/report-metadata-model.js new file mode 100644 index 0000000000..f158861423 --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/report-metadata-model.js @@ -0,0 +1,52 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').factory('reportMetadataModel', reportMetadataModel); + + reportMetadataModel.$inject = ['piwik', 'piwikApi']; + + function reportMetadataModel (piwik, piwikApi) { + + var reportsPromise = null; + + var model = { + reports: [], + fetchReportMetadata: fetchReportMetadata, + findReport: findReport + }; + + return model; + + function findReport(module, action) + { + var found = []; + + angular.forEach(model.reports, function (report) { + if (report.module === module && report.action === action) { + found = report; + } + }); + + return found; + } + + function fetchReportMetadata() + { + if (!reportsPromise) { + reportsPromise = piwikApi.fetch({ + method: 'API.getReportMetadata', + idSites: piwik.idSite || piwik.broadcast.getValueFromUrl('idSite'), + }).then(function (response) { + model.reports = response; + return response; + }); + } + + return reportsPromise; + } + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js b/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js new file mode 100644 index 0000000000..1b1e406c95 --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js @@ -0,0 +1,58 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').factory('reportingPagesModel', reportingPagesModelService); + + reportingPagesModelService.$inject = ['piwikApi']; + + function reportingPagesModelService (piwikApi) { + var fetchAllPagesPromise = false; + + // those sites are going to be displayed + var model = { + pages : [], + findPage: findPage, + reloadAllPages : reloadAllPages, + getAllPages : getAllPages + }; + + return model; + + function findPage(categoryId, subcategoryId) + { + var found = null; + + angular.forEach(model.pages, function (page) { + if (page && + page.category && page.subcategory && + page.category.id === categoryId && ('' + page.subcategory.id) === subcategoryId) { + found = page; + } + }); + + return found; + } + + function reloadAllPages() + { + fetchAllPagesPromise = null; + return getAllPages(); + } + + function getAllPages() + { + if (!fetchAllPagesPromise) { + fetchAllPagesPromise = piwikApi.fetch({method: 'API.getReportPagesMetadata'}).then(function (response) { + model.pages = response; + return response; + }); + } + + return fetchAllPagesPromise; + } + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/history/history.service.js b/plugins/CoreHome/angularjs/history/history.service.js index 2c6486a517..7dadf35ad0 100644 --- a/plugins/CoreHome/angularjs/history/history.service.js +++ b/plugins/CoreHome/angularjs/history/history.service.js @@ -36,6 +36,19 @@ loadCurrentPage(); } + function cleanHash(hash) + { + var chars = ['#', '/', '?']; + for (var i = 0; i != chars.length; ++i) { + var charToRemove = chars[i]; + if (hash.charAt(0) == charToRemove) { + hash = hash.substring(1); + } + } + + return hash; + } + // currently, the AJAX content URL is stored in $location.search(), but before it was stored in $location.path(). // this function makes sure URLs like http://piwik.net/?...#/module=Whatever&action=whatever still work. function changePathToSearch() { @@ -82,13 +95,7 @@ function load(hash) { // make sure the hash is just the query parameter values, w/o a starting #, / or ? char. broadcast.pageload & $location.path should get neither - var chars = ['#', '/', '?']; - for (var i = 0; i != chars.length; ++i) { - var charToRemove = chars[i]; - if (hash.charAt(0) == charToRemove) { - hash = hash.substring(1); - } - } + hash = cleanHash(hash); if (location.hash === '#?' + hash) { loadCurrentPage(); // it would not trigger a location change success event as URL is the same, call it manually diff --git a/plugins/CoreHome/angularjs/http404check.js b/plugins/CoreHome/angularjs/http404check.js index f2e2a86edf..5b720c9472 100644 --- a/plugins/CoreHome/angularjs/http404check.js +++ b/plugins/CoreHome/angularjs/http404check.js @@ -1,9 +1,9 @@ (function () { angular.module('piwikApp').factory('http404CheckInterceptor', http404CheckInterceptor); - http404CheckInterceptor.$inject = ['$q']; + http404CheckInterceptor.$inject = ['$q', 'globalAjaxQueue']; - function http404CheckInterceptor($q) { + function http404CheckInterceptor($q, globalAjaxQueue) { function isClientError(rejection) { @@ -15,8 +15,8 @@ } return { - 'responseError': function(rejection) { + if (rejection && isClientError(rejection) && rejection.config && diff --git a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html index d1964d1ac4..14191ac20e 100644 --- a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html +++ b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html @@ -23,7 +23,7 @@ class="reset" src="plugins/CoreHome/images/reset_search.png"/> </div> - <div ng-transclude> + <div ng-transclude ng-click="selectItem($event)"> </div> </div> diff --git a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js index 00fbf87d7b..313ef00d6c 100644 --- a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js +++ b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js @@ -34,10 +34,10 @@ templateUrl: 'plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html?cb=' + piwik.cacheBuster, link: function(scope, element, attrs) { - element.find('.item').on('click', function () { - var $self = angular.element(this); + scope.selectItem = function (event) { + var $self = angular.element(event.target); - if ($self.hasClass('disabled') || $self.hasClass('separator')) { + if (!$self.hasClass('item') || $self.hasClass('disabled') || $self.hasClass('separator')) { return; } @@ -47,11 +47,14 @@ }); } scope.$eval('view.showItems = false'); - scope.$apply(); + + setTimeout(function () { + scope.$apply(); + }, 0); element.find('.item').removeClass('active'); $self.addClass('active'); - }); + }; scope.searchItems = function (searchTerm) { diff --git a/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js b/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js new file mode 100644 index 0000000000..ea15f025b0 --- /dev/null +++ b/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js @@ -0,0 +1,74 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * When present in the page it listens to a popover URL parameter. + * + * If present it will try to load the related content in a popover or if the URL is empty it will close an + * opened popover. + * + * Example: + * <div piwik-popover-handler></div> + */ +(function () { + angular.module('piwikApp').directive('piwikPopoverHandler', piwikPopoverHandler); + + piwikPopoverHandler.$inject = ['$location', '$rootScope', 'piwik']; + + function piwikPopoverHandler($location, $rootScope, piwik){ + + return { + restrict: 'A', + scope: {}, + controller: function () { + + function close() + { + Piwik_Popover.close(); + } + + function open(popoverParam) + { + // in case the $ was encoded (e.g. when using copy&paste on urls in some browsers) + popoverParam = decodeURIComponent(popoverParam); + // revert special encoding from broadcast.propagateNewPopoverParameter() + popoverParam = popoverParam.replace(/\$/g, '%'); + popoverParam = decodeURIComponent(popoverParam); + + var popoverParamParts = popoverParam.split(':'); + var handlerName = popoverParamParts[0]; + popoverParamParts.shift(); + var param = popoverParamParts.join(':'); + if (typeof piwik.broadcast.popoverHandlers[handlerName] != 'undefined' + && !piwik.broadcast.isLoginPage()) { + piwik.broadcast.popoverHandlers[handlerName](param); + } + } + + function openOrClose() + { + // should be rather done by routing + var popoverParam = $location.search().popover; + if (popoverParam) { + open(popoverParam); + } else { + close(); + } + } + + $rootScope.$on('$locationChangeSuccess', function () { + // should be rather done by routing + $(function () { + // make sure all popover handles were registered + openOrClose(); + }); + }); + + } + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js new file mode 100644 index 0000000000..adc1b97936 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js @@ -0,0 +1,153 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').factory('reportingMenuModel', reportingMenuModelService); + + reportingMenuModelService.$inject = ['$filter', '$q', 'piwikApi', 'reportingPagesModel', '$location']; + + function reportingMenuModelService ($filter, $q, piwikApi, reportingPagesModel, $location) { + + // those sites are going to be displayed + var model = { + menu: [], + selected: [], + fetchMenuItems: fetchMenuItems, + reloadMenuItems: reloadMenuItems, + findSubcategory: findSubcategory + }; + + return model; + + function isNumeric(text) { + return !isNaN(parseFloat(text)) && isFinite(text); + } + + function findSubcategory(categoryId, subcategoryId) + { + var foundCategory = null; + var foundSubcategory = null; + + angular.forEach(model.menu, function (category) { + if (category.id !== categoryId) { + return; + } + angular.forEach(category.subcategories, function (subcategory) { + if (subcategory.id === subcategoryId) { + foundCategory = category; + foundSubcategory = subcategory; + } + }); + }); + + return {category: foundCategory, subcategory: foundSubcategory}; + } + + function buildMenuFromPages(pages) + { + var menu = []; + + var activeCategory = $location.search().category; + var activeSubcategory = $location.search().subcategory; + + var categoriesHandled = {}; + angular.forEach(pages, function (page, key) { + var category = page.category; + var categoryId = category.id; + + if (categoriesHandled[categoryId]) { + return; + } + + categoriesHandled[categoryId] = true; + + if (activeCategory && category.id === activeCategory) { + // this doesn't really belong here but placed it here for convenience + category.active = true; + category.hover = true; + } + + category.subcategories = []; + + var goalsGroup = false; + + angular.forEach(pages, function (page, key) { + if (page.category.id === categoryId) { + var subcategory = page.subcategory; + + if (subcategory.id === activeSubcategory) { + subcategory.active = true; + } + + if (page.widgets && page.widgets[0] && page.category.id === 'Goals_Goals' && isNumeric(page.subcategory.id)) { + // we handle a goal + if (!goalsGroup) { + goalsGroup = angular.copy(subcategory); + goalsGroup.name = $filter('translate')('Goals_ChooseGoal'); + goalsGroup.isGroup = true; + goalsGroup.subcategories = []; + goalsGroup.order = 10; + } + + if (subcategory.active) { + goalsGroup.name = subcategory.name; + } + + var goalId = page.subcategory.id; + subcategory.tooltip = subcategory.name + ' (id = ' + goalId + ' )'; + + goalsGroup.subcategories.push(subcategory); + return; + } + + category.subcategories.push(subcategory); + } + }); + + if (goalsGroup && goalsGroup.subcategories && goalsGroup.subcategories.length <= 3) { + angular.forEach(goalsGroup.subcategories, function (subcategory) { + category.subcategories.push(subcategory); + }); + } else if(goalsGroup) { + category.subcategories.push(goalsGroup); + } + + category.subcategories = sortMenuItems(category.subcategories); + + menu.push(category); + + return menu; + }); + + menu = sortMenuItems(menu); + + return menu; + } + + function sortMenuItems(menu) { + return $filter('orderBy')(menu, 'order'); + }; + + function reloadMenuItems() + { + var pagesPromise = reportingPagesModel.reloadAllPages(); + return pagesPromise.then(function (pages) { + model.menu = buildMenuFromPages(pages); + }); + } + + function fetchMenuItems() + { + var pagesPromise = reportingPagesModel.getAllPages(); + + return pagesPromise.then(function (pages) { + model.menu = buildMenuFromPages(pages); + + return model.menu; + }); + } + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js new file mode 100644 index 0000000000..85dc0f17c5 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js @@ -0,0 +1,125 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').controller('ReportingMenuController', ReportingMenuController); + + ReportingMenuController.$inject = ['$scope', 'piwik', '$location', '$timeout', 'reportingMenuModel', '$rootScope']; + + function ReportingMenuController($scope, piwik, $location, $timeout, menuModel, $rootScope) { + + function markAllCategoriesAsInactive() + { + angular.forEach(menuModel.menu, function (cat) { + cat.active = false; + cat.hover = false; + angular.forEach(cat.subcategories, function (subcat) { + subcat.active = false; + }); + }); + } + + function getUrlParam(param) + { + var value = piwik.broadcast.getValueFromHash(param); + if (!value) { + value = piwik.broadcast.getValueFromUrl(param); + } + return value; + } + + $scope.menuModel = menuModel; + + var timeoutPromise = null; + + // show subcategories of the currently hovered category + $scope.enterCategory = function (category) { + + if (timeoutPromise) { + $timeout.cancel(timeoutPromise); + } + + angular.forEach(menuModel.menu, function (cat) { + cat.hover = false; + }); + + category.hover = true; + }; + + // show subcategories of the current active category again (after 2 sec max) + $scope.leaveCategory = function (category) { + + if (timeoutPromise) { + $timeout.cancel(timeoutPromise); + } + + timeoutPromise = $timeout(function () { + angular.forEach(menuModel.menu, function (cat) { + if (cat.active) { + cat.hover = true; + } else { + cat.hover = false; + } + }); + }, 2000); + }; + + // highlight the currently hovered subcategory (and category) + $scope.enterSubcategory = function (category, subcategory) { + if (!category || !subcategory) { + return; + } + + markAllCategoriesAsInactive(); + + category.active = true; + category.hover = true; + subcategory.active = true; + }; + + var idSite = getUrlParam('idSite'); + var period = getUrlParam('period'); + var date = getUrlParam('date'); + var segment = getUrlParam('segment'); + + $scope.makeUrl = function (category, subcategory) { + var url = 'idSite=' + idSite + '&period=' + period + '&date=' + date + '&category=' + category.id + '&subcategory=' + subcategory.id; + if (segment) { + url+= '&segment='+ segment; + } + return url; + } + + $scope.loadSubcategory = function (category, subcategory) { + if (subcategory && subcategory.active) { + // this menu item is already active, a location change success would not be triggered, + // instead trigger an event + $rootScope.$emit('loadPage', category.id, subcategory.id); + } + }; + + menuModel.fetchMenuItems().then(function (menu) { + if (!$location.search().subcategory) { + // load first, initial page if no subcategory is present + $scope.enterSubcategory(menu[0], menu[0].subcategories[0]); + $location.search($scope.makeUrl(menu[0], menu[0].subcategories[0])); + } + }); + + $rootScope.$on('$locationChangeSuccess', function () { + var category = $location.search().category; + var subcategory = $location.search().subcategory; + + if (!category || !subcategory) { + return; + } + + var found = menuModel.findSubcategory(category, subcategory); + $scope.enterSubcategory(found.category, found.subcategory); + }); + + } +})(); diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html new file mode 100644 index 0000000000..bbfd687517 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html @@ -0,0 +1,40 @@ +<div class="Menu--dashboard"> + <ul class="Menu-tabList"> + <li ng-repeat="category in menuModel.menu" + ng-class="{'sfActive': category.active, 'sfHover': category.hover}" + ng-mouseenter="enterCategory(category)" + ng-mouseleave="leaveCategory(category)"> + <a class="menuItem" + ng-href="#?{{ makeUrl(category,category.subcategories[0]) }}" + ng-click="loadSubcategory(category, category.subcategories[0])"> + {{ category.name }} + </a> + <ul ng-show="(category.subcategories|length) > 1"> + <li ng-repeat="subcategory in category.subcategories" + ng-class="{'sfHover': subcategory.active}"> + <div ng-if="subcategory.isGroup" piwik-menudropdown show-search="true" menu-title="{{ subcategory.name|escape }}"> + <a class="item" + ng-repeat="subcat in subcategory.subcategories" + title="{{ subcat.tooltip }}" + ng-class="{'active': subcat.active}" + ng-href="#?{{ makeUrl(category,subcat) }}" + ng-click='loadSubcategory(category, subcat)'> + {{ subcat.name }} + </a> + </div> + + <a ng-if="!subcategory.isGroup" + ng-href="#?{{ makeUrl(category,subcategory) }}" + class="menuItem" + ng-click='loadSubcategory(category, subcategory)'> + {{ subcategory.name }} + </a> + </li> + </ul> + </li> + <li id="Searchmenu"> + <span piwik-quick-access></span> + </li> + </ul> + +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js new file mode 100644 index 0000000000..7cdd9e951b --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js @@ -0,0 +1,31 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Shows the Piwik reporting menu. + * + * It automatically calls the API to fetch all data. + * + * Example: + * <div piwik-reporting-menu></div> + */ + +(function () { + angular.module('piwikApp').directive('piwikReportingMenu', piwikReportingMenu); + + piwikReportingMenu.$inject = ['piwik']; + + function piwikReportingMenu(piwik){ + + return { + restrict: 'A', + scope: {}, + templateUrl: 'plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html?cb=' + piwik.cacheBuster, + controller: 'ReportingMenuController' + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js new file mode 100644 index 0000000000..4018fcee8c --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js @@ -0,0 +1,196 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').factory('reportingPageModel', reportingPageModelService); + + reportingPageModelService.$inject = ['$filter', 'piwikApi', 'reportingPagesModel', 'reportMetadataModel']; + + function reportingPageModelService ($filter, piwikApi, reportingPagesModel, reportMetadataModel) { + var init = false; + + // those sites are going to be displayed + var model = { + fetchPage: fetchPage, + resetPage: resetPage, + widgets: [], + page: null, + pageContentUrl: '', + evolutionReports: [], + sparklineReports: [] + }; + + return model; + + function resetPage() + { + model.page = null; + model.widgets = []; + model.pageContentUrl = ''; + model.evolutionReports = []; + model.sparklineReports = []; + } + + function sortWidgets(widgets) + { + return $filter('orderBy')(widgets, 'order'); + } + + function shouldBeRenderedWithFullWidth(widget) + { + // rather controller logic + if ((widget.isContainer && widget.layout && widget.layout === 'ByDimension') + || widget.viewDataTable === 'bydimension') { + return true; + } + + return widget.viewDataTable && widget.viewDataTable === 'tableAllColumns'; + } + + function buildPage(page) + { + if (!page) { + return; + } + + var widgets = []; + var evolutionReports = []; + var sparklineReports = []; + var reportsToIgnore = []; + + angular.forEach(page.widgets, function (widget) { + + if (isIgnoredReport(reportsToIgnore, widget)) { + return; + } + + reportsToIgnore = reportsToIgnore.concat(getRelatedReports(widget)); + + if (widget.viewDataTable && widget.viewDataTable === 'graphEvolution') { + evolutionReports.push(widget); + } else if (widget.viewDataTable && widget.viewDataTable === 'sparklines') { + sparklineReports.push(widget); + } else { + widgets.push(widget); + } + }); + + widgets = sortWidgets(widgets); + + var groupedWidgets = []; + + if (widgets.length === 1) { + // if there is only one widget, we always display it full width + groupedWidgets = widgets; + } else { + for (var i = 0; i < widgets.length; i++) { + var widget = widgets[i]; + + if (shouldBeRenderedWithFullWidth(widget) || (widgets[i+1] && shouldBeRenderedWithFullWidth(widgets[i+1]))) { + widget.widgets = sortWidgets(widget.widgets); + + groupedWidgets.push(widget); + } else { + + var counter = 0; + var left = [widget]; + var right = []; + + while (widgets[i+1] && !shouldBeRenderedWithFullWidth(widgets[i+1])) { + i++; + counter++; + if (counter % 2 === 0) { + left.push(widgets[i]); + } else { + right.push(widgets[i]); + } + } + + groupedWidgets.push({group: true, left: left, right: right}); + } + } + } + + var copyWidgets = angular.copy(groupedWidgets); + var copyEvolution = angular.copy(evolutionReports); + var copySparklines = angular.copy(sparklineReports); + + if (copyEvolution.length) { + copyEvolution = markWidgetsInFirstRowOfPage(copyEvolution); + } else if (copySparklines.length) { + copySparklines = markWidgetsInFirstRowOfPage(copySparklines); + } else { + copyWidgets = markWidgetsInFirstRowOfPage(copyWidgets); + } + + // angular.copy forces the page to re-render. Otherwise it won't reload some pages + model.evolutionReports = copyEvolution; + model.sparklineReports = copySparklines; + model.widgets = copyWidgets; + } + + function markWidgetsInFirstRowOfPage(widgets) + { + if (widgets && widgets[0]) { + if (widgets[0].group) { + markWidgetsInFirstRowOfPage(widgets[0].left); + markWidgetsInFirstRowOfPage(widgets[0].right); + } else { + widgets[0].isFirstInPage = true; + } + } + + return widgets; + } + + function getRelatedReports(widget) + { + if (widget.isReport) { + var report = reportMetadataModel.findReport(widget.module, widget.action); + + if (report && report.relatedReports) { + return report.relatedReports; + } + } + + return []; + } + + function isIgnoredReport(reportsToIgnore, widget) + { + var found = false; + + if (widget.isReport) { + angular.forEach(reportsToIgnore, function (report) { + if (report.module === widget.module && + report.action === widget.action) { + found = true; + } + }); + } + + return found; + } + + function fetchPage(category, subcategory) + { + resetPage(); + + var pagesPromise = reportingPagesModel.getAllPages(); + var reportsPromise = reportMetadataModel.fetchReportMetadata(); + + return pagesPromise.then(function () { + model.page = reportingPagesModel.findPage(category, subcategory); + + reportsPromise.then(function () { + buildPage(model.page); + }); + + return model.page; + }); + } + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js new file mode 100644 index 0000000000..cf0d424b55 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js @@ -0,0 +1,56 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').controller('ReportingPageController', ReportingPageController); + + ReportingPageController.$inject = ['$scope', 'piwik', '$rootScope', '$location', 'reportingPageModel']; + + function ReportingPageController($scope, piwik, $rootScope, $location, pageModel) { + pageModel.resetPage(); + $scope.pageModel = pageModel; + + var currentCategory = null; + var currentSubcategory = null; + + $scope.renderPage = function (category, subcategory) { + if (!category || !subcategory) { + pageModel.resetPage(); + $scope.loading = false; + return; + } + + currentCategory = category; + currentSubcategory = subcategory; + + pageModel.fetchPage(category, subcategory).then(function () { + $scope.hasNoPage = !pageModel.page; + $scope.loading = false; + }); + } + + $scope.loading = true; // we only set loading on initial load + + $scope.renderPage($location.search().category, $location.search().subcategory); + + $rootScope.$on('$locationChangeSuccess', function () { + // should be handled by $route + var category = $location.search().category; + var subcategory = $location.search().subcategory; + + if (category === currentCategory && subcategory === currentSubcategory) { + // this page is already loaded + return; + } + + $scope.renderPage(category, subcategory); + }); + + $rootScope.$on('loadPage', function (event, category, subcategory) { + $scope.renderPage(category, subcategory); + }); + } +})(); diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html new file mode 100644 index 0000000000..9a8974e313 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html @@ -0,0 +1,25 @@ +<div class="reporting-page"> + + <div piwik-activity-indicator loading="loading"/> + + <div ng-show="hasNoPage">{{ 'CoreHome_NoSuchPage'|translate }}</div> + + <div class="row" ng-repeat="evolutionReport in pageModel.evolutionReports"> + <div class="col-md-12" piwik-widget="evolutionReport"></div> + </div> + + <div class="row" ng-repeat="sparklineReport in pageModel.sparklineReports"> + <div class="col-md-12" piwik-widget="sparklineReport"></div> + </div> + + <div class="row" ng-repeat="widget in pageModel.widgets"> + <div class="col-md-12" ng-if="!widget.group" piwik-widget="widget"></div> + + <div ng-if="widget.group" class="col-md-6"> + <div ng-repeat="widgetInGroup in widget.left" piwik-widget="widgetInGroup"></div> + </div> + <div ng-if="widget.group" class="col-md-6"> + <div ng-repeat="widgetInGroup in widget.right" piwik-widget="widgetInGroup"></div> + </div> + </div> +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js new file mode 100644 index 0000000000..a146ed3112 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js @@ -0,0 +1,31 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Shows a piwik reporting page. + * + * The content to be displayed is automatically loaded via API based on the current URL. The URL parameters + * 'category' and 'subcategory' need to be present in the URL in order to see something in the reporting page. + * + * Example: + * <div piwik-reporting-page></div> + */ +(function () { + angular.module('piwikApp').directive('piwikReportingPage', piwikReportingPage); + + piwikReportingPage.$inject = ['piwik']; + + function piwikReportingPage(piwik){ + + return { + restrict: 'A', + scope: {}, + templateUrl: 'plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html?cb=' + piwik.cacheBuster, + controller: 'ReportingPageController' + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html new file mode 100644 index 0000000000..db98dee895 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html @@ -0,0 +1,25 @@ +<div class="reportsByDimensionView"> + + <div class="entityList"> + <div class='dimensionCategory' ng-repeat="category in widgetsByCategory"> + {{ category.name }} + <ul class='listCircle'> + <li ng-repeat="widget in category.widgets" + class="reportDimension" + ng-class="{activeDimension: (selectedWidget.uniqueId===widget.uniqueId)}" + ng-click="selectWidget(widget)"> + <span class='dimension'>{{widget.name}}</span> + </li> + </ul> + </div> + </div> + + <div style="float:left;max-width:900px;"> + <h2 ng-if="selectedWidget.name" class="noTopMargin">{{ selectedWidget.name }}</h2> + + <div ng-if="selectedWidget.parameters" class="dimensionReport" + piwik-widget-loader="selectedWidget.parameters"></div> + </div> + <div class="clear"></div> + +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js new file mode 100644 index 0000000000..1620be2a9d --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js @@ -0,0 +1,67 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Renders a widget that is a container widget having the layout "ByDimension". + * + * The "ByDimension" layout shows a menu on the left letting you choose any widgets within this container. The + * currently selected widget is shown on the right. + * + * @param {Object} piwikWidgetByDimensionContainer a widget object as returned by the WidgetMetadata API. + * + * Example: + * <div piwik-widget-by-dimension-container="containerWidget"></div> + */ +(function () { + angular.module('piwikApp').directive('piwikWidgetByDimensionContainer', piwikWidgetContainer); + + piwikWidgetContainer.$inject = ['piwik', '$filter']; + + function piwikWidgetContainer(piwik, $filter){ + return { + restrict: 'A', + scope: { + container: '=piwikWidgetByDimensionContainer' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html?cb=' + piwik.cacheBuster, + compile: function (element, attrs) { + + return function (scope, element, attrs, ngModel) { + + var widgetsSorted = $filter('orderBy')(scope.container.widgets, 'order'); + var widgetsByCategory = {}; + + angular.forEach(widgetsSorted, function (widget) { + var category = widget.subcategory.name; + + if (!widgetsByCategory[category]) { + widgetsByCategory[category] = {name: category, order: widget.order, widgets: []}; + } + + widgetsByCategory[category].widgets.push(widget); + }); + + // only an array can be sorted + var finalWidgetsByCategory = []; + angular.forEach(widgetsByCategory, function (category) { + finalWidgetsByCategory.push(category); + }); + + scope.widgetsByCategory = $filter('orderBy')(finalWidgetsByCategory, 'order'); + + scope.selectWidget = function (widget) { + scope.selectedWidget = widget; + } + + if (widgetsSorted && widgetsSorted.length) { + scope.selectWidget(widgetsSorted[0]); + } + }; + } + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html new file mode 100644 index 0000000000..21ebd3d0cd --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html @@ -0,0 +1,10 @@ +<div> + <!-- custom template prevents recursion --> + <script id="mywidget.html" type="text/ng-template"> + <div piwik-widget="widget"></div> + </script> + + <div ng-repeat="widget in container.widgets"> + <div ng-include src="'mywidget.html'"/> + </div> +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js new file mode 100644 index 0000000000..c378637c71 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js @@ -0,0 +1,32 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Renders a widget that is a container widget having no specific layout (which is the default). + * + * It shows all widgets vertically aligned one widget after another. + * + * @param {Object} piwikWidgetContainer a widget object as returned by the WidgetMetadata API. + * + * Example: + * <div piwik-widget-container="containerWidget"></div> + */ +(function () { + angular.module('piwikApp').directive('piwikWidgetContainer', piwikWidgetContainer); + + piwikWidgetContainer.$inject = ['piwik']; + + function piwikWidgetContainer(piwik){ + return { + restrict: 'A', + scope: { + container: '=piwikWidgetContainer' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html?cb=' + piwik.cacheBuster + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html new file mode 100644 index 0000000000..d1f0cb51f1 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html @@ -0,0 +1,13 @@ +<div> + + <div piwik-activity-indicator loading="loading"/> + + <div ng-show="loadingFailed"> + <div class="notification system notification-error"> + {{ 'General_ErrorRequest'|translate:(''):('') }} + </div> + </div> + + <div class="theWidgetContent"></div> + +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js new file mode 100644 index 0000000000..4e1859e789 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js @@ -0,0 +1,134 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Loads any custom widget or URL based on the given parameters. + * + * The currently active idSite, period, date and segment (if needed) is automatically appended to the parameters. If + * this widget is removed from the DOM and requests are in progress, these requests will be aborted. A loading message + * or an error message on failure is shown as well. It's kinda similar to ng-include but there it is not possible to + * listen to HTTP errors etc. + * + * Example: + * <div piwik-widget-loader="{module: '', action: '', ...}"></div> + */ +(function () { + angular.module('piwikApp').directive('piwikWidgetLoader', piwikWidgetLoader); + + piwikWidgetLoader.$inject = ['piwik', 'piwikUrl', '$http', '$compile', '$q']; + + function piwikWidgetLoader(piwik, piwikUrl, $http, $compile, $q){ + return { + restrict: 'A', + transclude: true, + scope: { + piwikWidgetLoader: '=' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html?cb=' + piwik.cacheBuster, + compile: function (element, attrs) { + + return function (scope, element, attrs, ngModel) { + var changeCounter = 0, + currentScope, + currentElement, + httpCanceler, + contentNode = element.find('.theWidgetContent'); + + var cleanupLastWidgetContent = function() { + if (currentElement) { + currentElement.remove(); + currentElement = null; + } + if (currentScope) { + currentScope.$destroy(); + currentScope = null; + } + }; + + var abortHttpRequestIfNeeded = function () { + if (httpCanceler) { + httpCanceler.resolve(); + httpCanceler = null; + } + } + + function getFullWidgetUrl(parameters) { + + var url = $.param(parameters); + + var idSite = piwikUrl.getSearchParam('idSite'); + var period = piwikUrl.getSearchParam('period'); + var date = piwikUrl.getSearchParam('date'); + var segment = piwikUrl.getSearchParam('segment'); + + url += '&idSite=' + idSite + '&period=' + period; + url += '&date=' + date + '&random=' + parseInt(Math.random() * 10000); + + if (segment) { + url += '&segment=' + segment; + } + + return '?' + url; + } + + function loadWidgetUrl(parameters, thisChangeId) + { + scope.loading = true; + + var url = getFullWidgetUrl(parameters); + + abortHttpRequestIfNeeded(); + cleanupLastWidgetContent(); + + httpCanceler = $q.defer(); + + $http.get(url, {timeout: httpCanceler.promise}).success(function(response) { + if (thisChangeId !== changeCounter || !response) { + // another widget was requested meanwhile, ignore this response + return; + } + + httpCanceler = null; + + var newScope = scope.$new(); + currentScope = newScope; + + scope.loading = false; + scope.loadingFailed = false; + + currentElement = contentNode.html(response).children(); + $compile(currentElement)(newScope); + + }).error(function () { + if (thisChangeId !== changeCounter) { + // another widget was requested meanwhile, ignore this response + return; + } + + httpCanceler = null; + + cleanupLastWidgetContent(); + + scope.loading = false; + scope.loadingFailed = true; + }); + } + + scope.$watch('piwikWidgetLoader', function (parameters, oldUrl) { + if (parameters) { + loadWidgetUrl(parameters, ++changeCounter); + } + }); + + element.on('$destroy', function() { + abortHttpRequestIfNeeded(); + }); + }; + } + }; + } +})();
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget/widget.directive.html b/plugins/CoreHome/angularjs/widget/widget.directive.html new file mode 100644 index 0000000000..86cdc91291 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget/widget.directive.html @@ -0,0 +1,23 @@ +<div id="{{ widget.uniqueId }}" + ng-show="view.showWidget" + class="{{widget.viewDataTable}}" + ng-class="{'smallTopMargin': (!widget.isFirstInPage && (!widget.name || widgetized))}" + > + <!--smallTopMargin: we display small margin if it's not the first widget on the page and if there's no headline --> + <h2 ng-if="!widget.parameters.widget && widget.name && !widgetized" + piwik-enriched-headline + ng-class="{'noTopMargin': widget.isFirstInPage}" + feature-name="{{widget.name}}">{{widget.name}}</h2> + <h2 ng-if="widget.parameters.widget && widget.name && !widgetized">{{widget.name}}</h2> + + <div ng-if="!widget.isContainer && widget.parameters" + piwik-widget-loader="widget.parameters"></div> + + <div ng-if="widget.isContainer && widget.layout!='ByDimension'"> + <div piwik-widget-container="widget"></div> + </div> + + <div ng-if="widget.isContainer && widget.layout=='ByDimension'"> + <div piwik-widget-by-dimension-container="widget"></div> + </div> +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget/widget.directive.js b/plugins/CoreHome/angularjs/widget/widget.directive.js new file mode 100644 index 0000000000..86574870f2 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget/widget.directive.js @@ -0,0 +1,93 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Renders any kind of widget. If you have a widget and you want to have it rendered, use this directive. It will + * display a name on top and the actual widget below. It can handle any kind of widget, no matter whether it is a + * regular widget or a container. + * + * @param {Object} piwikWidget A widget object as returned by the WidgetMetadata API. + * @param {Object} piwikWidget.middlewareParameters If present, we will request a URL using the given parameters and + * only if this URL returns a JSON `true` the widget will be shown. + * Otherwise the widget won't be shown. + * @param {String} containerId If you do not have a widget object but a containerId we will find the correct widget + * object based on the given containerId. Be aware that we might not find the widget if + * it is for example not available for the current user or period/date. + * @param {Boolean} widgetized true if the widget is widgetized (eg in Dashboard or exported). In this case we will add + * a URL parameter widget=1 to all widgets. Eg sparklines will be then displayed one after + * another (vertically aligned) instead of two next to each other. + * + * Example: + * <div piwik-widget="widget"></div> + * <div piwik-widget containerid="widgetGoalsOverview"></div> // in this case we will find the correct widget automatically + * <div piwik-widget="widget" widetized="true"></div> // disables rating feature, no initial headline + */ +(function () { + angular.module('piwikApp').directive('piwikWidget', piwikWidget); + + piwikWidget.$inject = ['piwik', 'piwikApi']; + + function piwikWidget(piwik, piwikApi){ + + function findContainerWidget(containerId, scope) { + widgetsHelper.getAvailableWidgets(function (categorizedWidgets) { + + angular.forEach(categorizedWidgets, function (widgets) { + angular.forEach(widgets, function (widget) { + + if (widget && widget.isContainer && widget.parameters.containerId === containerId) { + widget = angular.copy(widget); + if (scope.widgetized) { + widget.isFirstInPage = '1'; + widget.parameters.widget = '1'; + angular.forEach(widget.widgets, function (widget) { + widget.parameters.widget = '1'; + }); + } + scope.widget = widget; + applyMiddleware(scope); + } + }); + }); + + }); + } + + function applyMiddleware(scope) + { + if (!scope.widget.middlewareParameters) { + scope.$eval('view.showWidget = true'); + } else { + var params = angular.copy(scope.widget.middlewareParameters); + piwikApi.fetch(params).then(function (response) { + var enabled = response ? 'true' : 'false'; + scope.$eval('view.showWidget = ' + enabled); + }); + } + } + + return { + restrict: 'A', + scope: { + widget: '=?piwikWidget', + widgetized: '=?', + containerid: '=' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget/widget.directive.html?cb=' + piwik.cacheBuster, + compile: function (element, attrs) { + + return function (scope, element, attrs, ngModel) { + if (scope.widget) { + applyMiddleware(scope); + } else if (attrs.containerid) { + findContainerWidget(attrs.containerid, scope); + } + } + } + }; + } +})();
\ No newline at end of file |