From 6435f2f03442e4ed8a57fc0d0dbca15a3e1a01f0 Mon Sep 17 00:00:00 2001
From: diosmosis <benakamoorthi@fastmail.fm>
Date: Mon, 10 Feb 2014 17:28:20 +0000
Subject: [PATCH] Rewrote top control code to move elements that are not in the
 top bar, change name of css class js-autoLeftPanel, make segment selector
 more generic, make dashboard settings widget reusable.

---
 plugins/CoreHome/javascripts/broadcast.js     |   4 +-
 plugins/CoreHome/javascripts/top_controls.js  |  26 ++--
 plugins/CoreHome/javascripts/uiControl.js     |   4 +
 plugins/CoreHome/templates/_periodSelect.twig |   2 +-
 plugins/Dashboard/DashboardManagerControl.php |   2 +-
 .../DashboardSettingsControlBase.php          |   2 +-
 plugins/Dashboard/javascripts/dashboard.js    | 115 ++++++++++++------
 plugins/Dashboard/templates/index.twig        |   2 +-
 .../SegmentEditor/SegmentSelectorControl.php  |   2 +-
 .../SegmentEditor/javascripts/Segmentation.js |  16 +--
 10 files changed, 112 insertions(+), 63 deletions(-)

diff --git a/plugins/CoreHome/javascripts/broadcast.js b/plugins/CoreHome/javascripts/broadcast.js
index b18f53319a..b48ad77e10 100644
--- a/plugins/CoreHome/javascripts/broadcast.js
+++ b/plugins/CoreHome/javascripts/broadcast.js
@@ -128,7 +128,7 @@ var broadcast = {
                     broadcast.loadAjaxContent(hashUrl);
 
                     // make sure the "Widgets & Dashboard" is deleted on reload
-                    $('.top_controls .dashboardSettings').hide();
+                    $('.top_controls .dashboard-manager').hide();
                     $('#dashboardWidgetsArea').dashboard('destroy');
 
                     // remove unused controls
@@ -423,6 +423,8 @@ var broadcast = {
                 piwikHelper.hideAjaxLoading();
                 broadcast.lastUrlRequested = null;
             }
+
+            initTopControls();
         }
 
         var ajax = new ajaxHelper();
diff --git a/plugins/CoreHome/javascripts/top_controls.js b/plugins/CoreHome/javascripts/top_controls.js
index 93e9c6993d..c2089648d0 100644
--- a/plugins/CoreHome/javascripts/top_controls.js
+++ b/plugins/CoreHome/javascripts/top_controls.js
@@ -5,14 +5,20 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  */
 function initTopControls() {
-    if ($('#periodString').length) {
-        var left=0;
-        $('.top_controls').children('.js-autoLeftPanel').each(function(i, el){
-            var control = $(el);
-            if (left) {
-                control.css({left: left});
-            }
-            left+=control.outerWidth(true);
-        });
-    }
+    var $topControlsContainer = $('.top_controls'),
+        left = 0;
+    $('.piwikTopControl').each(function () {
+        var $control = $(this);
+        if ($control.css('display') == 'none') {
+            return;
+        }
+
+        $control.css('left', left);
+
+        if (!$.contains($topControlsContainer[0], this)) {
+            $control.detach().appendTo($topControlsContainer);
+        }
+
+        left += $control.outerWidth(true);
+    });
 }
\ No newline at end of file
diff --git a/plugins/CoreHome/javascripts/uiControl.js b/plugins/CoreHome/javascripts/uiControl.js
index 7c92d26a01..1c3c8aaf19 100644
--- a/plugins/CoreHome/javascripts/uiControl.js
+++ b/plugins/CoreHome/javascripts/uiControl.js
@@ -18,6 +18,10 @@
      * @param {Element} element The root element of the control.
      */
     var UIControl = function (element) {
+        if (!element) {
+            throw new Error("no element passed to UIControl constructor");
+        }
+
         this._controlId = UIControl._controls.length;
         UIControl._controls.push(this);
 
diff --git a/plugins/CoreHome/templates/_periodSelect.twig b/plugins/CoreHome/templates/_periodSelect.twig
index b0f853c506..6373adfd1b 100644
--- a/plugins/CoreHome/templates/_periodSelect.twig
+++ b/plugins/CoreHome/templates/_periodSelect.twig
@@ -1,4 +1,4 @@
-<div id="periodString" class="js-autoLeftPanel">
+<div id="periodString" class="piwikTopControl">
     <div id="date">{{ 'General_DateRange'|translate }} <strong>{{ prettyDate }}</strong></div>
     <div class="calendar-icon"></div>
     <div id="periodMore">
diff --git a/plugins/Dashboard/DashboardManagerControl.php b/plugins/Dashboard/DashboardManagerControl.php
index 71727d61d1..af6303d2b0 100644
--- a/plugins/Dashboard/DashboardManagerControl.php
+++ b/plugins/Dashboard/DashboardManagerControl.php
@@ -22,7 +22,7 @@ class DashboardManagerControl extends DashboardSettingsControlBase
         parent::__construct();
         
         $this->jsClass = "DashboardManagerControl";
-        $this->cssIdentifier = "dashboardSettings";
+        $this->cssIdentifier = "dashboard-manager";
 
         $this->addDashboardActions();
         $this->addGeneralActions();
diff --git a/plugins/Dashboard/DashboardSettingsControlBase.php b/plugins/Dashboard/DashboardSettingsControlBase.php
index e78b086b20..d546d33b79 100644
--- a/plugins/Dashboard/DashboardSettingsControlBase.php
+++ b/plugins/Dashboard/DashboardSettingsControlBase.php
@@ -23,7 +23,7 @@ abstract class DashboardSettingsControlBase extends UIControl
     {
         parent::__construct();
         
-        $this->cssClass = "js-autoLeftPanel";
+        $this->cssClass = "piwikTopControl dashboardSettings";
         $this->dashboardActions = array();
         $this->generalActions = array();
     }
diff --git a/plugins/Dashboard/javascripts/dashboard.js b/plugins/Dashboard/javascripts/dashboard.js
index 3afdaff096..7b1b2a2538 100644
--- a/plugins/Dashboard/javascripts/dashboard.js
+++ b/plugins/Dashboard/javascripts/dashboard.js
@@ -8,7 +8,6 @@
 function initDashboard(dashboardId, dashboardLayout) {
 
     $('.dashboardSettings').show();
-    initTopControls();
 
     // Embed dashboard
     if (!$('#topBars').length) {
@@ -16,25 +15,6 @@ function initDashboard(dashboardId, dashboardLayout) {
         $('#Dashboard_embeddedIndex_' + dashboardId).addClass('sfHover');
     }
 
-    $('.dashboardSettings').on('click', function (e) {
-        if ($(e.target).is('.dashboardSettings') || $(e.target).is('.dashboardSettings>span')) {
-            $('.dashboardSettings').toggleClass('visible');
-            if ($('#dashboardWidgetsArea').dashboard('isDefaultDashboard')) {
-                $('.removeDashboardLink').hide();
-            } else {
-                $('.removeDashboardLink').show();
-            }
-            // fix position
-            $('.dashboardSettings').find('.widgetpreview-widgetlist').css('paddingTop', $('.dashboardSettings').find('.widgetpreview-categorylist').parent('li').position().top);
-        }
-    });
-    $('body').on('mouseup', function (e) {
-        if (!$(e.target).parents('.dashboardSettings').length && !$(e.target).is('.dashboardSettings')) {
-            $('.dashboardSettings').widgetPreview('reset');
-            $('.dashboardSettings').removeClass('visible');
-        }
-    });
-
     widgetsHelper.getAvailableWidgets();
 
     $('#dashboardWidgetsArea')
@@ -44,18 +24,6 @@ function initDashboard(dashboardId, dashboardLayout) {
             layout: dashboardLayout
         });
 
-    $('.dashboardSettings').widgetPreview({
-        isWidgetAvailable: function (widgetUniqueId) {
-            return !$('#dashboardWidgetsArea').find('[widgetId=' + widgetUniqueId + ']').length;
-        },
-        onSelect: function (widgetUniqueId) {
-            var widget = widgetsHelper.getWidgetObjectFromUniqueId(widgetUniqueId);
-            $('#dashboardWidgetsArea').dashboard('addWidget', widget.uniqueId, 1, widget.parameters, true, false);
-            $('.dashboardSettings').removeClass('visible');
-        },
-        resetOnSelect: true
-    });
-
     $('#columnPreview').find('>div').each(function () {
         var width = [];
         $('div', this).each(function () {
@@ -68,13 +36,6 @@ function initDashboard(dashboardId, dashboardLayout) {
         $('#columnPreview').find('>div').removeClass('choosen');
         $(this).addClass('choosen');
     });
-
-    $('.submenu > li').on('mouseenter', function (event) {
-        if (!$('.widgetpreview-categorylist', event.target).length) {
-            $('.dashboardSettings').widgetPreview('reset');
-        }
-    });
-
 }
 
 function createDashboard() {
@@ -203,12 +164,68 @@ function copyDashboardToUser() {
     var DashboardSettingsControlBase = function (element) {
         UIControl.call(this, element);
 
+        // on menu item click, trigger action event on this
         var self = this;
         this.$element.on('click', 'ul.submenu li[data-action]', function (e) {
             $(self).trigger($(this).attr('data-action'));
         });
+
+        // open manager on open
+        this.$element.on('click', function (e) {
+            if ($(e.target).is('.dashboardSettings,.dashboardSettings>span')) {
+                self.$element.toggleClass('visible');
+
+                // fix position
+                self.$element
+                    .find('.widgetpreview-widgetlist')
+                    .css('paddingTop', self.$element.find('.widgetpreview-categorylist').parent('li').position().top);
+
+                self.onOpen();
+            }
+        });
+
+        // handle manager close
+        this.onBodyMouseUp = function (e) {
+            if (!$(e.target).closest('.dashboardSettings').length
+                && !$(e.target).is('.dashboardSettings')
+            ) {
+                self.$element.widgetPreview('reset');
+                self.$element.removeClass('visible');
+            }
+        };
+
+        $('body').on('mouseup', this.onBodyMouseUp);
+
+        // setup widgetPreview
+        this.$element.widgetPreview({
+            isWidgetAvailable: function (widgetUniqueId) {
+                return self.isWidgetAvailable(widgetUniqueId);
+            },
+            onSelect: function (widgetUniqueId) {
+                var widget = widgetsHelper.getWidgetObjectFromUniqueId(widgetUniqueId);
+                self.$element.removeClass('visible');
+
+                self.widgetSelected(widget);
+            },
+            resetOnSelect: true
+        });
+
+        // on enter widget list category, reset widget preview
+        this.$element.on('mouseenter', '.submenu > li', function (event) {
+            if (!$('.widgetpreview-categorylist', event.target).length) {
+                self.$element.widgetPreview('reset');
+            }
+        });
     };
 
+    $.extend(DashboardSettingsControlBase.prototype, UIControl.prototype, {
+        _destroy: function () {
+            UIControl.prototype.call(this);
+
+            $('body')[0].removeEventListener(this.onBodyMouseUp);
+        }
+    });
+
     exports.DashboardSettingsControlBase = DashboardSettingsControlBase;
 
     /**
@@ -250,8 +267,26 @@ function copyDashboardToUser() {
         });
     };
 
+    $.extend(DashboardManagerControl.prototype, DashboardSettingsControlBase.prototype, {
+        onOpen: function () {
+            if ($('#dashboardWidgetsArea').dashboard('isDefaultDashboard')) { 
+                $('.removeDashboardLink', this.$element).hide();
+            } else {
+                $('.removeDashboardLink', this.$element).show();
+            }
+        },
+
+        isWidgetAvailable: function (widgetUniqueId) {
+            return !$('#dashboardWidgetsArea').find('[widgetId=' + widgetUniqueId + ']').length;
+        },
+
+        widgetSelected: function (widget) {
+            $('#dashboardWidgetsArea').dashboard('addWidget', widget.uniqueId, 1, widget.parameters, true, false);
+        }
+    });
+
     DashboardManagerControl.initElements = function () {
-        UIControl.initElements(this, '.dashboardSettings');
+        UIControl.initElements(this, '.dashboard-manager');
     };
 
     exports.DashboardManagerControl = DashboardManagerControl;
diff --git a/plugins/Dashboard/templates/index.twig b/plugins/Dashboard/templates/index.twig
index 5d34202044..0a8831fe3f 100644
--- a/plugins/Dashboard/templates/index.twig
+++ b/plugins/Dashboard/templates/index.twig
@@ -3,7 +3,7 @@
     {% include "@CoreHome/_periodSelect.twig" %}
     {{ postEvent("Template.nextToCalendar") }}
     {% render dashboardSettingsControl %}
-    <div id="Dashboard" class="js-autoLeftPanel">
+    <div id="Dashboard" class="piwikTopControl">
         <ul>
             {% for dashboard in dashboards %}
                 <li class="dashboardMenuItem" id="Dashboard_embeddedIndex_{{ dashboard.iddashboard }}">
diff --git a/plugins/SegmentEditor/SegmentSelectorControl.php b/plugins/SegmentEditor/SegmentSelectorControl.php
index bacc057e29..747bb6fdf5 100644
--- a/plugins/SegmentEditor/SegmentSelectorControl.php
+++ b/plugins/SegmentEditor/SegmentSelectorControl.php
@@ -30,7 +30,7 @@ class SegmentSelectorControl extends UIControl
 
         $this->jsClass = "SegmentSelectorControl";
         $this->cssIdentifier = "segmentEditorPanel";
-        $this->cssClass = "js-autoLeftPanel";
+        $this->cssClass = "piwikTopControl";
 
         $this->idSite = Common::getRequestVar('idSite', false, 'int');
 
diff --git a/plugins/SegmentEditor/javascripts/Segmentation.js b/plugins/SegmentEditor/javascripts/Segmentation.js
index f8c1d64718..195318c679 100644
--- a/plugins/SegmentEditor/javascripts/Segmentation.js
+++ b/plugins/SegmentEditor/javascripts/Segmentation.js
@@ -17,12 +17,13 @@ Segmentation = (function($) {
         self.currentSegmentStr = "";
         self.segmentAccess = "read";
         self.availableSegments = [];
-        self.editorTemplate = $('.SegmentEditor', self.target).detach();
 
         for (var item in config) {
             self[item] = config[item];
         }
 
+        self.editorTemplate = self.editorTemplate.detach();
+
         self.timer = ""; // variable for further use in timing events
         self.searchAllowed = true;
 
@@ -967,7 +968,6 @@ Segmentation = (function($) {
                 self.target.append(html);
                 self.content = self.target.find(".segmentationContainer");
             }
-            initTopControls();
 
             // assign content to object attribute to make it easil accesible through all widget methods
             bindListEvents();
@@ -1005,7 +1005,7 @@ $(document).ready(function() {
         }
 
         var self = this;
-        var changeSegment = function(segmentDefinition){
+        this.changeSegment = function(segmentDefinition) {
             self.$element.find('a.close').click();
             segmentDefinition = cleanupSegmentDefinition(segmentDefinition);
             segmentDefinition = encodeURIComponent(segmentDefinition);
@@ -1034,7 +1034,7 @@ $(document).ready(function() {
                 if (response && response.result == 'error') {
                     alert(response.message);
                 } else {
-                    changeSegment(params.definition);
+                    self.changeSegment(params.definition);
                 }
             });
             ajaxHandler.send(true);
@@ -1056,7 +1056,7 @@ $(document).ready(function() {
                 if (response && response.result == 'error') {
                     alert(response.message);
                 } else {
-                    changeSegment(params.definition);
+                    self.changeSegment(params.definition);
                 }
             });
             ajaxHandler.send(true);
@@ -1079,7 +1079,8 @@ $(document).ready(function() {
                 if (response && response.result == 'error') {
                     alert(response.message);
                 } else {
-                    return broadcast.propagateNewPage('segment=');
+                    self.changeSegment('');
+                    $('.ui-dialog-content').dialog('close');
                 }
             });
 
@@ -1095,12 +1096,13 @@ $(document).ready(function() {
         
         this.impl = new Segmentation({
             "target"   : this.$element.find(".segmentListContainer"),
+            "editorTemplate": $('.SegmentEditor', self.$element),
             "segmentAccess" : "write",
             "availableSegments" : this.props.availableSegments,
             "addMethod": addSegment,
             "updateMethod": updateSegment,
             "deleteMethod": deleteSegment,
-            "segmentSelectMethod": changeSegment,
+            "segmentSelectMethod": function () { self.changeSegment.apply(this, arguments); },
             "currentSegmentStr": segmentFromRequest,
             "translations": this.props.segmentTranslations
         });
-- 
GitLab