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/Dashboard | |
parent | 8ccc9dc05da021325cdbf141a548637fa52f16b2 (diff) |
generate pages instead of implementing them in each controller
Diffstat (limited to 'plugins/Dashboard')
-rw-r--r-- | plugins/Dashboard/API.php | 54 | ||||
-rw-r--r-- | plugins/Dashboard/Categories/DashboardCategory.php | 17 | ||||
-rw-r--r-- | plugins/Dashboard/Controller.php | 17 | ||||
-rw-r--r-- | plugins/Dashboard/Dashboard.php | 64 | ||||
-rw-r--r-- | plugins/Dashboard/Menu.php | 19 | ||||
-rw-r--r-- | plugins/Dashboard/Model.php | 8 | ||||
-rw-r--r-- | plugins/Dashboard/angularjs/common/services/dashboards-model.js | 68 | ||||
-rw-r--r-- | plugins/Dashboard/angularjs/dashboard/dashboard.directive.js | 103 | ||||
-rw-r--r-- | plugins/Dashboard/javascripts/dashboard.js | 106 | ||||
-rw-r--r-- | plugins/Dashboard/javascripts/dashboardObject.js | 143 | ||||
-rwxr-xr-x | plugins/Dashboard/javascripts/dashboardWidget.js | 9 | ||||
-rw-r--r-- | plugins/Dashboard/javascripts/widgetMenu.js | 102 | ||||
-rw-r--r-- | plugins/Dashboard/templates/embeddedIndex.twig | 8 |
13 files changed, 478 insertions, 240 deletions
diff --git a/plugins/Dashboard/API.php b/plugins/Dashboard/API.php index f4637e862a..7bd5bd73a5 100644 --- a/plugins/Dashboard/API.php +++ b/plugins/Dashboard/API.php @@ -8,7 +8,6 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Piwik; -use Piwik\WidgetsList; /** * This API is the <a href='http://piwik.org/docs/analytics-api/reference/' rel='noreferrer' target='_blank'>Dashboard API</a>: it gives information about dashboards. @@ -43,25 +42,22 @@ class API extends \Piwik\Plugin\API /** * Get the default dashboard. - * - * @return array[] + * @return \array[] */ private function getDefaultDashboard() { $defaultLayout = $this->dashboard->getDefaultLayout(); $defaultLayout = $this->dashboard->decodeLayout($defaultLayout); + $defaultDashboard = array('name' => Piwik::translate('Dashboard_Dashboard'), 'layout' => $defaultLayout, 'iddashboard' => 1); - $defaultDashboard = array('name' => Piwik::translate('Dashboard_Dashboard'), 'layout' => $defaultLayout); - - $widgets = $this->getExistingWidgetsWithinDashboard($defaultDashboard); + $widgets = $this->getVisibleWidgetsWithinDashboard($defaultDashboard); return $this->buildDashboard($defaultDashboard, $widgets); } /** * Get all dashboards which a user has created. - * - * @return array[] + * @return \array[] */ private function getUserDashboards() { @@ -71,17 +67,14 @@ class API extends \Piwik\Plugin\API $dashboards = array(); foreach ($userDashboards as $userDashboard) { - - if ($this->hasDashboardColumns($userDashboard)) { - $widgets = $this->getExistingWidgetsWithinDashboard($userDashboard); - $dashboards[] = $this->buildDashboard($userDashboard, $widgets); - } + $widgets = $this->getVisibleWidgetsWithinDashboard($userDashboard); + $dashboards[] = $this->buildDashboard($userDashboard, $widgets); } return $dashboards; } - private function getExistingWidgetsWithinDashboard($dashboard) + private function getVisibleWidgetsWithinDashboard($dashboard) { $columns = $this->getColumnsFromDashboard($dashboard); @@ -91,7 +84,7 @@ class API extends \Piwik\Plugin\API foreach ($columns as $column) { foreach ($column as $widget) { - if ($this->widgetIsNotHidden($widget) && $this->widgetExists($widget)) { + if ($this->widgetIsNotHidden($widget) && !empty($widget->parameters->module)) { $module = $widget->parameters->module; $action = $widget->parameters->action; @@ -105,39 +98,24 @@ class API extends \Piwik\Plugin\API private function getColumnsFromDashboard($dashboard) { - if (is_array($dashboard['layout'])) { - - return $dashboard['layout']; + if (empty($dashboard['layout'])) { + return array(); } - return $dashboard['layout']->columns; - } - - private function hasDashboardColumns($dashboard) - { if (is_array($dashboard['layout'])) { + return $dashboard['layout']; + } - return !empty($dashboard['layout']); + if (!empty($dashboard['layout']->columns)) { + return $dashboard['layout']->columns; } - return !empty($dashboard['layout']->columns); + return array(); } private function buildDashboard($dashboard, $widgets) { - return array('name' => $dashboard['name'], 'widgets' => $widgets); - } - - private function widgetExists($widget) - { - if (empty($widget->parameters->module)) { - return false; - } - - $module = $widget->parameters->module; - $action = $widget->parameters->action; - - return WidgetsList::isDefined($module, $action); + return array('name' => $dashboard['name'], 'id' => $dashboard['iddashboard'], 'widgets' => $widgets); } private function widgetIsNotHidden($widget) diff --git a/plugins/Dashboard/Categories/DashboardCategory.php b/plugins/Dashboard/Categories/DashboardCategory.php new file mode 100644 index 0000000000..99a3785c84 --- /dev/null +++ b/plugins/Dashboard/Categories/DashboardCategory.php @@ -0,0 +1,17 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\Dashboard\Categories; + +use Piwik\Category\Category; + +class DashboardCategory extends Category +{ + protected $id = 'Dashboard_Dashboard'; + protected $order = 0; +} diff --git a/plugins/Dashboard/Controller.php b/plugins/Dashboard/Controller.php index d77c283273..bef5a89237 100644 --- a/plugins/Dashboard/Controller.php +++ b/plugins/Dashboard/Controller.php @@ -13,8 +13,6 @@ use Piwik\Db; use Piwik\Piwik; use Piwik\Session\SessionNamespace; use Piwik\View; -use Piwik\WidgetsList; -use Piwik\FrontController; /** * Dashboard Controller @@ -39,24 +37,21 @@ class Controller extends \Piwik\Plugin\Controller $view = new View($template); $this->setGeneralVariablesView($view); - $view->availableWidgets = json_encode(WidgetsList::get()); $view->availableLayouts = $this->getAvailableLayouts(); $view->dashboardId = Common::getRequestVar('idDashboard', 1, 'int'); - // get the layout via FrontController so controller events are posted - $view->dashboardLayout = FrontController::getInstance()->dispatch('Dashboard', 'getDashboardLayout', - array($checkToken = false)); - return $view; } + // this public function embeddedIndex() { $view = $this->_getDashboardView('@Dashboard/embeddedIndex'); return $view->render(); } + // this is the exported widget public function index() { $view = $this->_getDashboardView('@Dashboard/index'); @@ -70,14 +65,6 @@ class Controller extends \Piwik\Plugin\Controller return $view->render(); } - public function getAvailableWidgets() - { - $this->checkTokenInUrl(); - - Json::sendHeaderJSON(); - return json_encode(WidgetsList::get()); - } - public function getDashboardLayout($checkToken = true) { if ($checkToken) { diff --git a/plugins/Dashboard/Dashboard.php b/plugins/Dashboard/Dashboard.php index 9ccbb822e4..5a0a7cc0ec 100644 --- a/plugins/Dashboard/Dashboard.php +++ b/plugins/Dashboard/Dashboard.php @@ -11,7 +11,8 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Common; use Piwik\Db; use Piwik\Piwik; -use Piwik\WidgetsList; +use Piwik\Category\Subcategory; +use Piwik\Widget\WidgetConfig; /** */ @@ -26,10 +27,43 @@ class Dashboard extends \Piwik\Plugin 'AssetManager.getJavaScriptFiles' => 'getJsFiles', 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles', 'UsersManager.deleteUser' => 'deleteDashboardLayout', - 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys' + 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', + 'Widget.addWidgetConfigs' => 'addWidgetConfigs', + 'Category.addSubcategories' => 'addSubcategories' ); } + public function addWidgetConfigs(&$widgets) + { + $dashboards = API::getInstance()->getDashboards(); + + foreach ($dashboards as $dashboard) { + $config = new WidgetConfig(); + $config->setIsNotWidgetizable(); + $config->setModule('Dashboard'); + $config->setAction('embeddedIndex'); + $config->setCategoryId('Dashboard_Dashboard'); + $config->setSubcategoryId($dashboard['id']); + $config->setParameters(array('idDashboard' => $dashboard['id'])); + $widgets[] = $config; + } + } + + public function addSubcategories(&$subcategories) + { + $dashboards = API::getInstance()->getDashboards(); + + $order = 0; + foreach ($dashboards as $dashboard) { + $subcategory = new Subcategory(); + $subcategory->setName($dashboard['name']); + $subcategory->setCategoryId('Dashboard_Dashboard'); + $subcategory->setId($dashboard['id']); + $subcategory->setOrder($order++); + $subcategories[] = $subcategory; + } + } + /** * Returns the layout in the DB for the given user, or false if the layout has not been set yet. * Parameters must be checked BEFORE this function call @@ -70,14 +104,14 @@ class Dashboard extends \Piwik\Plugin $defaultLayout = '[ [ - {"uniqueId":"widgetVisitsSummarygetEvolutionGraphcolumnsArray","parameters":{"module":"VisitsSummary","action":"getEvolutionGraph","columns":"nb_visits"}}, + {"uniqueId":"widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution","parameters":{"forceView":"1","viewDataTable":"graphEvolution","module":"VisitsSummary","action":"getEvolutionGraph"}}, {"uniqueId":"widgetLivewidget","parameters":{"module":"Live","action":"widget"}}, - {"uniqueId":"widgetVisitorInterestgetNumberOfVisitsPerVisitDuration","parameters":{"module":"VisitorInterest","action":"getNumberOfVisitsPerVisitDuration"}} + {"uniqueId":"widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud","parameters":{"viewDataTable":"cloud","module":"VisitorInterest","action":"getNumberOfVisitsPerVisitDuration"}} ], [ ' . $topWidget . ' {"uniqueId":"widgetReferrersgetWebsites","parameters":{"module":"Referrers","action":"getWebsites"}}, - {"uniqueId":"widgetVisitTimegetVisitInformationPerServerTime","parameters":{"module":"VisitTime","action":"getVisitInformationPerServerTime"}} + {"uniqueId":"widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar","parameters":{"viewDataTable": "graphVerticalBar","module":"VisitTime","action":"getVisitInformationPerServerTime"}} ], [ {"uniqueId":"widgetUserCountryMapvisitorMap","parameters":{"module":"UserCountryMap","action":"visitorMap"}}, @@ -160,24 +194,6 @@ class Dashboard extends \Piwik\Plugin ); } - foreach ($layoutObject->columns as &$row) { - if (!is_array($row)) { - $row = array(); - continue; - } - - foreach ($row as $widgetId => $widget) { - if (isset($widget->parameters->module)) { - $controllerName = $widget->parameters->module; - $controllerAction = $widget->parameters->action; - if (!WidgetsList::isDefined($controllerName, $controllerAction)) { - unset($row[$widgetId]); - } - } else { - unset($row[$widgetId]); - } - } - } $layout = $this->encodeLayout($layoutObject); return $layout; } @@ -202,11 +218,13 @@ class Dashboard extends \Piwik\Plugin public function getJsFiles(&$jsFiles) { + $jsFiles[] = "plugins/Dashboard/angularjs/common/services/dashboards-model.js"; $jsFiles[] = "plugins/Dashboard/javascripts/widgetMenu.js"; $jsFiles[] = "libs/javascript/json2.js"; $jsFiles[] = "plugins/Dashboard/javascripts/dashboardObject.js"; $jsFiles[] = "plugins/Dashboard/javascripts/dashboardWidget.js"; $jsFiles[] = "plugins/Dashboard/javascripts/dashboard.js"; + $jsFiles[] = "plugins/Dashboard/angularjs/dashboard/dashboard.directive.js"; } public function getStylesheetFiles(&$stylesheets) diff --git a/plugins/Dashboard/Menu.php b/plugins/Dashboard/Menu.php index f90c117e10..7967635f97 100644 --- a/plugins/Dashboard/Menu.php +++ b/plugins/Dashboard/Menu.php @@ -9,7 +9,6 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Db; -use Piwik\Menu\MenuReporting; use Piwik\Menu\MenuTop; use Piwik\Piwik; use Piwik\Plugins\UsersManager\UserPreferences; @@ -19,24 +18,6 @@ use Piwik\Site; */ class Menu extends \Piwik\Plugin\Menu { - public function configureReportingMenu(MenuReporting $menu) - { - $menu->addItem('Dashboard_Dashboard', '', $this->urlForAction('embeddedIndex', array('idDashboard' => 1)), 5); - - if (!Piwik::isUserIsAnonymous()) { - $login = Piwik::getCurrentUserLogin(); - - $dashboard = new Dashboard(); - $dashboards = $dashboard->getAllDashboards($login); - - $pos = 0; - foreach ($dashboards as $dashboard) { - $menu->addItem('Dashboard_Dashboard', $dashboard['name'], $this->urlForAction('embeddedIndex', array('idDashboard' => $dashboard['iddashboard'])), $pos); - $pos++; - } - } - } - public function configureTopMenu(MenuTop $menu) { $userPreferences = new UserPreferences(); diff --git a/plugins/Dashboard/Model.php b/plugins/Dashboard/Model.php index 790076c1a9..0ef02aeea9 100644 --- a/plugins/Dashboard/Model.php +++ b/plugins/Dashboard/Model.php @@ -10,7 +10,7 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Common; use Piwik\Db; use Piwik\DbHelper; -use Piwik\WidgetsList; +use Piwik\Widget\WidgetsList; class Model { @@ -189,7 +189,11 @@ class Model if ($widget->uniqueId == $oldWidgetId) { - $newWidgetId = WidgetsList::getWidgetUniqueId($newWidget['module'], $newWidget['action'], $newWidget['params']); + if (!empty($newWidget['uniqueId'])) { + $newWidgetId = $newWidget['uniqueId']; + } else { + $newWidgetId = WidgetsList::getWidgetUniqueId($newWidget['module'], $newWidget['action'], $newWidget['params']); + } // is new widget already is on dashboard just remove the old one if (self::layoutContainsWidget($dashboardLayout, $newWidgetId)) { diff --git a/plugins/Dashboard/angularjs/common/services/dashboards-model.js b/plugins/Dashboard/angularjs/common/services/dashboards-model.js new file mode 100644 index 0000000000..e0d861c2ba --- /dev/null +++ b/plugins/Dashboard/angularjs/common/services/dashboards-model.js @@ -0,0 +1,68 @@ +/*! + * 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('dashboardsModel', dashboardsModel); + + dashboardsModel.$inject = ['piwikApi']; + + function dashboardsModel (piwikApi) { + + var dashboardsPromise = null; + + var model = { + dashboards: [], + getAllDashboards: getAllDashboards, + reloadAllDashboards: reloadAllDashboards, + getDashboard: getDashboard, + getDashboardLayout: getDashboardLayout + }; + + return model; + + function getDashboard(dashboardId) + { + return getAllDashboards().then(function (dashboards) { + var dashboard = null; + angular.forEach(dashboards, function (board) { + if (parseInt(board.id, 10) === parseInt(dashboardId, 10)) { + dashboard = board; + } + }); + return dashboard; + }); + } + + function getDashboardLayout(dashboardId) + { + return piwikApi.fetch({module: 'Dashboard', action: 'getDashboardLayout', idDashboard: dashboardId}); + } + + function reloadAllDashboards() + { + if (dashboardsPromise) { + dashboardsPromise = null; + } + + return getAllDashboards(); + } + + function getAllDashboards() + { + if (!dashboardsPromise) { + dashboardsPromise = piwikApi.fetch({method: 'Dashboard.getDashboards'}).then(function (response) { + if (response) { + model.dashboards = response; + } + + return response; + }); + } + + return dashboardsPromise; + } + } +})();
\ No newline at end of file diff --git a/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js b/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js new file mode 100644 index 0000000000..578737940c --- /dev/null +++ b/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js @@ -0,0 +1,103 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * <div piwik-dashboard dashboardId="5" layout="10"></div> + */ +(function () { + angular.module('piwikApp').directive('piwikDashboard', piwikDashboard); + + piwikDashboard.$inject = ['dashboardsModel', '$rootScope', '$q']; + + function piwikDashboard(dashboardsModel, $rootScope, $q) { + + function renderDashboard(dashboardId, dashboard, layout) + { + $('.dashboardSettings').show(); + initTopControls(); + + // Embed dashboard + if (!$('#topBars').length) { + $('.dashboardSettings').after($('#Dashboard')); + $('#Dashboard_embeddedIndex_' + dashboardId).addClass('sfHover'); + } + + widgetsHelper.getAvailableWidgets(); + + $('#dashboardWidgetsArea') + .on('dashboardempty', showEmptyDashboardNotification) + .dashboard({ + idDashboard: dashboardId, + layout: layout, + name: dashboard ? dashboard.name : '' + }); + + $('#columnPreview').find('>div').each(function () { + var width = []; + $('div', this).each(function () { + width.push(this.className.replace(/width-/, '')); + }); + $(this).attr('layout', width.join('-')); + }); + + $('#columnPreview').find('>div').on('click', function () { + $('#columnPreview').find('>div').removeClass('choosen'); + $(this).addClass('choosen'); + }); + } + + function fetchDashboard(dashboardId) { + $('#dashboardWidgetsArea').innerHTML =''; + + var getDashboard = dashboardsModel.getDashboard(dashboardId); + var getLayout = dashboardsModel.getDashboardLayout(dashboardId); + + $q.all([getDashboard, getLayout]).then(function (response) { + var dashboard = response[0]; + var layout = response[1]; + + $(function() { + renderDashboard(dashboardId, dashboard, layout); + }); + }); + } + + function clearDashboard () { + $('.top_controls .dashboard-manager').hide(); + $('#dashboardWidgetsArea').dashboard('destroy'); + } + + return { + restrict: 'A', + scope: { + dashboardid: '=', + layout: '=' + }, + link: function (scope, element, attrs) { + + scope.$parent.fetchDashboard = function (dashboardId) { + scope.dashboardId = dashboardId; + fetchDashboard(dashboardId) + }; + + fetchDashboard(scope.dashboardid); + + function onLocationChange(event, url1, url2) + { + if (url1 !== url2) { + clearDashboard(); + } + } + + // should be rather handled in route or so. + var unbind = $rootScope.$on('$locationChangeSuccess', onLocationChange); + scope.$on('$destroy', onLocationChange); + scope.$on('$destroy', unbind); + } + }; + } +})();
\ No newline at end of file diff --git a/plugins/Dashboard/javascripts/dashboard.js b/plugins/Dashboard/javascripts/dashboard.js index 238aca5197..f78814cdbb 100644 --- a/plugins/Dashboard/javascripts/dashboard.js +++ b/plugins/Dashboard/javascripts/dashboard.js @@ -5,45 +5,12 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ -function initDashboard(dashboardId, dashboardLayout) { - - $('.dashboardSettings').show(); - initTopControls(); - - // Embed dashboard - if (!$('#topBars').length) { - $('.dashboardSettings').after($('#Dashboard')); - $('#Dashboard_embeddedIndex_' + dashboardId).addClass('sfHover'); - } - - widgetsHelper.getAvailableWidgets(); - - $('#dashboardWidgetsArea') - .on('dashboardempty', showEmptyDashboardNotification) - .dashboard({ - idDashboard: dashboardId, - layout: dashboardLayout - }); - - $('#columnPreview').find('>div').each(function () { - var width = []; - $('div', this).each(function () { - width.push(this.className.replace(/width-/, '')); - }); - $(this).attr('layout', width.join('-')); - }); - - $('#columnPreview').find('>div').on('click', function () { - $('#columnPreview').find('>div').removeClass('choosen'); - $(this).addClass('choosen'); - }); -} - function createDashboard() { - $('#createDashboardName').val(''); - piwikHelper.modalConfirm('#createDashboardConfirm', {yes: function () { - var dashboardName = $('#createDashboardName').val(); - var type = ($('#dashboard_type_empty:checked').length > 0) ? 'empty' : 'default'; + $(makeSelectorLastId('createDashboardName')).val(''); + + piwikHelper.modalConfirm(makeSelectorLastId('createDashboardConfirm'), {yes: function () { + var dashboardName = $(makeSelectorLastId('createDashboardName')).val(); + var type = ($('[id=dashboard_type_empty]:last:checked').length > 0) ? 'empty' : 'default'; var ajaxRequest = new ajaxHelper(); ajaxRequest.setLoadingElement(); @@ -57,50 +24,74 @@ function createDashboard() { }, 'post'); ajaxRequest.setCallback( function (id) { - $('#dashboardWidgetsArea').dashboard('loadDashboard', id); + angular.element(document).injector().invoke(function ($location, reportingMenuModel, dashboardsModel) { + dashboardsModel.reloadAllDashboards().then(function () { + $('#dashboardWidgetsArea').dashboard('loadDashboard', id); + $('#dashboardWidgetsArea').dashboard('rebuildMenu'); + }); + }); } ); ajaxRequest.send(true); }}); } +function makeSelectorLastId(domElementId) +{ + // there can be many elements with this id, we prefer the last one + return '[id=' + domElementId + ']:last'; +} + function resetDashboard() { - piwikHelper.modalConfirm('#resetDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); }}); + piwikHelper.modalConfirm(makeSelectorLastId('resetDashboardConfirm'), {yes: + function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); + }}); } function renameDashboard() { - $('#newDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName')); - piwikHelper.modalConfirm('#renameDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('setDashboardName', $('#newDashboardName').val()); }}); + $(makeSelectorLastId('newDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName')); + + piwikHelper.modalConfirm(makeSelectorLastId('renameDashboardConfirm'), {yes: function () { + var newDashboardName = $(makeSelectorLastId('newDashboardName')).val(); + $('#dashboardWidgetsArea').dashboard('setDashboardName', newDashboardName); + }}); } function removeDashboard() { - $('#removeDashboardConfirm').find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName')); - piwikHelper.modalConfirm('#removeDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('removeDashboard'); }}); + $(makeSelectorLastId('removeDashboardConfirm')).find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName')); + + piwikHelper.modalConfirm(makeSelectorLastId('removeDashboardConfirm'), {yes: function () { + $('#dashboardWidgetsArea').dashboard('removeDashboard'); + }}); } function showChangeDashboardLayoutDialog() { $('#columnPreview').find('>div').removeClass('choosen'); $('#columnPreview').find('>div[layout=' + $('#dashboardWidgetsArea').dashboard('getColumnLayout') + ']').addClass('choosen'); - piwikHelper.modalConfirm('#changeDashboardLayout', {yes: function () { - $('#dashboardWidgetsArea').dashboard('setColumnLayout', $('#changeDashboardLayout').find('.choosen').attr('layout')); + + var id = makeSelectorLastId('changeDashboardLayout'); + piwikHelper.modalConfirm(id, {yes: function () { + $('#dashboardWidgetsArea').dashboard('setColumnLayout', $(id).find('.choosen').attr('layout')); }}); } function showEmptyDashboardNotification() { - piwikHelper.modalConfirm('#dashboardEmptyNotification', { + piwikHelper.modalConfirm(makeSelectorLastId('dashboardEmptyNotification'), { resetDashboard: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); }, addWidget: function () { $('.dashboardSettings').trigger('click'); } }); } function setAsDefaultWidgets() { - piwikHelper.modalConfirm('#setAsDefaultWidgetsConfirm', { - yes: function () { $('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout'); } + piwikHelper.modalConfirm(makeSelectorLastId('setAsDefaultWidgetsConfirm'), { + yes: function () { + $('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout'); + } }); } function copyDashboardToUser() { - $('#copyDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName')); + $(makeSelectorLastId('copyDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName')); var ajaxRequest = new ajaxHelper(); ajaxRequest.addParams({ module: 'API', @@ -109,13 +100,13 @@ function copyDashboardToUser() { }, 'get'); ajaxRequest.setCallback( function (availableUsers) { - $('#copyDashboardUser').empty(); - $('#copyDashboardUser').append( + $(makeSelectorLastId('copyDashboardUser')).empty(); + $(makeSelectorLastId('copyDashboardUser')).append( $('<option></option>').val(piwik.userLogin).text(piwik.userLogin) ); $.each(availableUsers, function (index, user) { if (user.login != 'anonymous' && user.login != piwik.userLogin) { - $('#copyDashboardUser').append( + $(makeSelectorLastId('copyDashboardUser')).append( $('<option></option>').val(user.login).text(user.login + ' (' + user.alias + ')') ); } @@ -124,10 +115,10 @@ function copyDashboardToUser() { ); ajaxRequest.send(true); - piwikHelper.modalConfirm('#copyDashboardToUserConfirm', { + piwikHelper.modalConfirm(makeSelectorLastId('copyDashboardToUserConfirm'), { yes: function () { - var copyDashboardName = $('#copyDashboardName').val(); - var copyDashboardUser = $('#copyDashboardUser').val(); + var copyDashboardName = $(makeSelectorLastId('copyDashboardName')).val(); + var copyDashboardUser = $(makeSelectorLastId('copyDashboardUser')).val(); var ajaxRequest = new ajaxHelper(); ajaxRequest.addParams({ @@ -291,7 +282,7 @@ function copyDashboardToUser() { }, isWidgetAvailable: function (widgetUniqueId) { - return !$('#dashboardWidgetsArea').find('[widgetId=' + widgetUniqueId + ']').length; + return !$('#dashboardWidgetsArea').find('[widgetId="' + widgetUniqueId + '"]').length; }, widgetSelected: function (widget) { @@ -301,6 +292,7 @@ function copyDashboardToUser() { DashboardManagerControl.initElements = function () { UIControl.initElements(this, '.dashboard-manager'); + $('.top_controls .dashboard-manager').hide(); // initially hide the manager }; exports.DashboardManagerControl = DashboardManagerControl; diff --git a/plugins/Dashboard/javascripts/dashboardObject.js b/plugins/Dashboard/javascripts/dashboardObject.js index 7808d22c11..08bb36dd79 100644 --- a/plugins/Dashboard/javascripts/dashboardObject.js +++ b/plugins/Dashboard/javascripts/dashboardObject.js @@ -57,9 +57,6 @@ if (options.layout) { generateLayout(options.layout); - buildMenu(); - } else { - methods.loadDashboard.apply(this, [dashboardId]); } return this; @@ -89,11 +86,11 @@ dashboardName = ''; dashboardLayout = null; dashboardId = dashboardIdToLoad; - piwikHelper.showAjaxLoading(); - broadcast.updateHashOnly = true; - broadcast.propagateAjax('?idDashboard=' + dashboardIdToLoad); - fetchLayout(generateLayout); - buildMenu(); + + var element = $('[piwik-dashboard]'); + var scope = angular.element(element).scope(); + scope.fetchDashboard(dashboardIdToLoad); + return this; }, @@ -179,6 +176,8 @@ ajaxRequest.send(true); }, + rebuildMenu: rebuildMenu, + /** * Removes the current dashboard */ @@ -201,6 +200,39 @@ } }; + function removeNonExistingWidgets(availableWidgets, layout) + { + var existingModuleAction = {}; + $.each(availableWidgets, function (category, widgets) { + $.each(widgets, function (index, widget) { + existingModuleAction[widget.module + '.' + widget.action] = true; + }); + }); + + var columns = []; + $.each(layout.columns, function (i, column) { + var widgets = []; + + $.each(column, function (j, widget) { + if (!widget.parameters || !widget.parameters.module) { + return; + } + + var method = widget.parameters.module + '.' + widget.parameters.action + if (existingModuleAction[method]) { + widgets.push(widget); + } + + }); + + columns[i] = widgets; + }); + + layout.columns = columns; + + return layout; + } + /** * Generates the dashboard out of the given layout * @@ -209,46 +241,33 @@ function generateLayout(layout) { dashboardLayout = parseLayout(layout); - piwikHelper.hideAjaxLoading(); - adjustDashboardColumns(dashboardLayout.config.layout); - - var dashboardContainsWidgets = false; - for (var column = 0; column < dashboardLayout.columns.length; column++) { - for (var i in dashboardLayout.columns[column]) { - if (typeof dashboardLayout.columns[column][i] != 'object') { - // Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function. - // If we would continue with i="indexOf", an invalid widget would be created. - continue; + + widgetsHelper.getAvailableWidgets(function (availableWidgets) { + dashboardLayout = removeNonExistingWidgets(availableWidgets, dashboardLayout); + + piwikHelper.hideAjaxLoading(); + adjustDashboardColumns(dashboardLayout.config.layout); + + var dashboardContainsWidgets = false; + for (var column = 0; column < dashboardLayout.columns.length; column++) { + for (var i in dashboardLayout.columns[column]) { + if (typeof dashboardLayout.columns[column][i] != 'object') { + // Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function. + // If we would continue with i="indexOf", an invalid widget would be created. + continue; + } + var widget = dashboardLayout.columns[column][i]; + dashboardContainsWidgets = true; + addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden) } - var widget = dashboardLayout.columns[column][i]; - dashboardContainsWidgets = true; - addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden) } - } - - if (!dashboardContainsWidgets) { - $(dashboardElement).trigger('dashboardempty'); - } - makeWidgetsSortable(); - } + if (!dashboardContainsWidgets) { + $(dashboardElement).trigger('dashboardempty'); + } - /** - * Fetches the layout for the currently set dashboard id - * and passes the response to given callback function - * - * @param {function} callback - */ - function fetchLayout(callback) { - globalAjaxQueue.abort(); - var ajaxRequest = new ajaxHelper(); - ajaxRequest.addParams({ - module: 'Dashboard', - action: 'getDashboardLayout', - idDashboard: dashboardId - }, 'get'); - ajaxRequest.setCallback(callback); - ajaxRequest.send(false); + makeWidgetsSortable(); + }); } /** @@ -388,7 +407,7 @@ * @param {String} uniqueId */ function reloadWidget(uniqueId) { - $('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget('reload', false, true); + $('[widgetId="' + uniqueId + '"]', dashboardElement).dashboardWidget('reload', false, true); } /** @@ -417,7 +436,7 @@ $('.col:nth-child(' + columnNumber + ')', dashboardElement).append(widgetContent); } - $('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget({ + $('[widgetId="' + uniqueId + '"]', dashboardElement).dashboardWidget({ uniqueId: uniqueId, widgetParameters: widgetParameters, onChange: function () { @@ -468,7 +487,19 @@ /** * Handle clicks for menu items for choosing between available dashboards */ - function buildMenu() { + function rebuildMenu() { + + if ($('[piwik-reporting-menu]').length) { + // dashboard in reporting page (regular Piwik UI) + angular.element(document).injector().invoke(function (reportingMenuModel) { + reportingMenuModel.reloadMenuItems(); + }); + return; + } + + var _self = this; + + // widgetized var success = function (dashboards) { var dashboardMenuList = $('#Dashboard').find('> ul'); var dashboardMenuListItems = dashboardMenuList.find('>li'); @@ -484,7 +515,7 @@ for (var i = 0; i < dashboards.length; i++) { var $link = $('<a/>').attr('data-idDashboard', dashboards[i].iddashboard).text(dashboards[i].name); var $li = $('<li/>').attr('id', 'Dashboard_embeddedIndex_' + dashboards[i].iddashboard) - .addClass('dashboardMenuItem').append($link); + .addClass('dashboardMenuItem').append($link); items.push($li); if (dashboards[i].iddashboard == dashboardId) { @@ -502,15 +533,10 @@ var idDashboard = $(this).attr('data-idDashboard'); - if (typeof piwikMenu != 'undefined') { - piwikMenu.activateMenu('Dashboard', 'embeddedIndex'); - } $('#Dashboard ul li').removeClass('sfHover'); - if ($(dashboardElement).length) { - $(dashboardElement).dashboard('loadDashboard', idDashboard); - } else { - broadcast.propagateAjax('module=Dashboard&action=embeddedIndex&idDashboard=' + idDashboard); - } + + methods.loadDashboard.apply(_self, [idDashboard]); + $(this).closest('li').addClass('sfHover'); }); }; @@ -521,7 +547,7 @@ action: 'getAllDashboards' }, 'get'); ajaxRequest.setCallback(success); - ajaxRequest.send(false); + ajaxRequest.send(); } /** @@ -568,7 +594,7 @@ function () { if (dashboardChanged) { dashboardChanged = false; - buildMenu(); + rebuildMenu(); } } ); @@ -594,6 +620,7 @@ }, 'get'); ajaxRequest.setCallback( function () { + rebuildMenu(); methods.loadDashboard.apply(this, [1]); } ); diff --git a/plugins/Dashboard/javascripts/dashboardWidget.js b/plugins/Dashboard/javascripts/dashboardWidget.js index accd0aa2c2..969ed9db28 100755 --- a/plugins/Dashboard/javascripts/dashboardWidget.js +++ b/plugins/Dashboard/javascripts/dashboardWidget.js @@ -70,7 +70,7 @@ */ destroy: function () { if (this.isMaximised) { - $('[widgetId=' + this.uniqueId + ']').dialog('destroy'); + $('[widgetId="' + this.uniqueId + '"]').dialog('destroy'); } $('*', this.element).off('.dashboardWidget'); // unbind all events $('.widgetContent', this.element).trigger('widget:destroy'); @@ -197,7 +197,7 @@ var emptyWidgetContent = require('piwik/UI/Dashboard').WidgetFactory.make(uniqueId, title); this.element.html(emptyWidgetContent); - var widgetElement = $('#' + uniqueId, this.element); + var widgetElement = $('[id="' + uniqueId + '"]', this.element); var self = this; widgetElement .on('mouseenter.dashboardWidget', function () { @@ -312,7 +312,7 @@ } $('body').off('.dashboardWidget'); $(this).dialog("destroy"); - $('#' + self.uniqueId + '-placeholder').replaceWith(this); + $('[id="' + self.uniqueId + '-placeholder"]').replaceWith(this); $(this).removeAttr('style'); self.options.onChange(); $(this).find('div.piwik-graph').trigger('resizeGraph'); @@ -339,6 +339,9 @@ */ detachWidget: function () { this.element.before('<div id="' + this.uniqueId + '-placeholder" class="widgetPlaceholder widget"> </div>'); + var placeholder = $('[id="' + self.uniqueId + '-placeholder"]') + + $('#' + this.uniqueId + '-placeholder').height(this.element.height()); $('#' + this.uniqueId + '-placeholder').width(this.element.width() - 16); diff --git a/plugins/Dashboard/javascripts/widgetMenu.js b/plugins/Dashboard/javascripts/widgetMenu.js index 6d58415cb9..169768eb03 100644 --- a/plugins/Dashboard/javascripts/widgetMenu.js +++ b/plugins/Dashboard/javascripts/widgetMenu.js @@ -13,21 +13,82 @@ function widgetsHelper() { * * @return {object} object containing available widgets */ -widgetsHelper.getAvailableWidgets = function () { +widgetsHelper.getAvailableWidgets = function (callback) { + + function mergeCategoriesAndSubCategories(availableWidgets) + { + var categorized = {}; + + $.each(availableWidgets, function (index, widget) { + var category = widget.category.name; + + if (!categorized[category]) { + categorized[category] = {'-': []}; + } + + var subcategory = '-'; + if (widget.subcategory && widget.subcategory.name) { + subcategory = widget.subcategory.name; + } + + if (!categorized[category][subcategory]) { + categorized[category][subcategory] = []; + } + + categorized[category][subcategory].push(widget); + }); + + var moved = {}; + + $.each(categorized, function (category, widgets) { + $.each(widgets, function (subcategory, subwidgets) { + + var categoryToUse = category; + if (subwidgets.length >= 3 && subcategory !== '-') { + categoryToUse = category + ' - ' + subcategory; + } + + if (!moved[categoryToUse]) { + moved[categoryToUse] = []; + } + + $.each(subwidgets, function (index, widget) { + moved[categoryToUse].push(widget); + }); + }); + }); + + return moved; + } + if (!widgetsHelper.availableWidgets) { var ajaxRequest = new ajaxHelper(); + ajaxRequest._mixinDefaultGetParams = function (params) { + return params; + }; ajaxRequest.addParams({ - module: 'Dashboard', - action: 'getAvailableWidgets' + module: 'API', + method: 'API.getWidgetMetadata', + format: 'JSON', + deep: '1', + idSite: piwik.idSite || broadcast.getValueFromUrl('idSite') }, 'get'); ajaxRequest.setCallback( function (data) { - widgetsHelper.availableWidgets = data; + widgetsHelper.availableWidgets = mergeCategoriesAndSubCategories(data); + + if (callback) { + callback(widgetsHelper.availableWidgets); + } } ); ajaxRequest.send(true); } + if (callback) { + callback(widgetsHelper.availableWidgets); + } + return widgetsHelper.availableWidgets; }; @@ -191,6 +252,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid * @return {$} category list element */ function createWidgetCategoryList(widgetPreview, availableWidgets) { + var settings = widgetPreview.settings; if (!$('.' + settings.categorylistClass, widgetPreview).length) { @@ -200,7 +262,6 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid } for (var widgetCategory in availableWidgets) { - $('.' + settings.categorylistClass, widgetPreview).append('<li>' + widgetCategory + '</li>'); } @@ -257,6 +318,8 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid widgetClass += ' ' + settings.unavailableClass; } + widgetName = piwikHelper.escape(piwikHelper.htmlEntities(widgetName)); + widgetList.append('<li class="' + widgetClass + '" uniqueid="' + widgetUniqueId + '">' + widgetName + '</li>'); } @@ -278,7 +341,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid clearTimeout(widgetPreview); }); - $('li:not(.' + settings.unavailableClass + ')', widgetList).on('click', function () { + $('li', widgetList).on('click', function () { if (!$('.widgetLoading', widgetPreview).length) { settings.onSelect($(this).attr('uniqueid')); if (settings.resetOnSelect) { @@ -317,7 +380,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid */ function showPreview(widgetUniqueId, widgetPreview) { // do not reload id widget already displayed - if ($('#' + widgetUniqueId, widgetPreview).length) return; + if ($('[id="' + widgetUniqueId + '"]', widgetPreview).length) return; var settings = widgetPreview.settings; @@ -335,7 +398,8 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid previewElement.html(emptyWidgetHtml); var onWidgetLoadedCallback = function (response) { - var widgetElement = $('#' + widgetUniqueId); + var widgetElement = $(document.getElementById(widgetUniqueId)); + // document.getElementById needed for widgets with uniqueid like widgetOpens+Contact+Form $('.widgetContent', widgetElement).html($(response)); $('.widgetContent', widgetElement).trigger('widget:create'); settings.onPreviewLoaded(widgetUniqueId, widgetElement); @@ -398,19 +462,21 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid this.onPreviewLoaded = this.settings.onPreviewLoaded; } - availableWidgets = widgetsHelper.getAvailableWidgets(); + var self = this; + widgetsHelper.getAvailableWidgets(function (availableWidgets) { - var categoryList = createWidgetCategoryList(this, availableWidgets); + var categoryList = createWidgetCategoryList(self, availableWidgets); - var self = this; - $('li', categoryList).on('mouseover', function () { - var category = $(this).text(); - var widgets = availableWidgets[category]; - $('li', categoryList).removeClass(self.settings.choosenClass); - $(this).addClass(self.settings.choosenClass); - showWidgetList(widgets, self); - createPreviewElement(self); // empty preview + $('li', categoryList).on('mouseover', function () { + var category = $(this).text(); + var widgets = availableWidgets[category]; + $('li', categoryList).removeClass(self.settings.choosenClass); + $(this).addClass(self.settings.choosenClass); + showWidgetList(widgets, self); + createPreviewElement(self); // empty preview + }); }); + }; } }); diff --git a/plugins/Dashboard/templates/embeddedIndex.twig b/plugins/Dashboard/templates/embeddedIndex.twig index af1dbeb887..a7633ca193 100644 --- a/plugins/Dashboard/templates/embeddedIndex.twig +++ b/plugins/Dashboard/templates/embeddedIndex.twig @@ -1,10 +1,4 @@ -<script type="text/javascript"> - widgetsHelper.availableWidgets = {{ availableWidgets|raw }}; - $(function() { - initDashboard({{ dashboardId }}, {{ dashboardLayout|raw }}); - }); -</script> -<div id="dashboard"> +<div id="dashboard" piwik-dashboard dashboardid="{{ dashboardId }}"> <div class="ui-confirm" id="confirm"> <h2>{{ 'Dashboard_DeleteWidgetConfirm'|translate }}</h2> <input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/> |