diff --git a/NEWS b/NEWS index 47b1f034e..793b8bcbc 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ New features Enhancements - [core] now possible to {un}subscribe to folders using sogo-tool - [web] AngularJS optimizations in Mail module + - [web] AngularJS optimization of color picker - [web] improve display of tasks status Bug fixes diff --git a/UI/WebServerResources/js/Common/sgColorPicker.directive.js b/UI/WebServerResources/js/Common/sgColorPicker.directive.js index a855bc092..f5bc50d06 100644 --- a/UI/WebServerResources/js/Common/sgColorPicker.directive.js +++ b/UI/WebServerResources/js/Common/sgColorPicker.directive.js @@ -7,71 +7,127 @@ /* * sgColorPicker - Color picker widget * @restrict element - * @param {function} sgOnSelect - the function to call when clicking on a color. - * One variable is available: color. * @ngInject * @example: - + */ function sgColorPicker() { return { restrict: 'E', require: 'ngModel', template: [ - '', ' ', - ' color_lens', - ' ', - ' ', - ' ', - ' ', - ' check_box', - ' ', - ' ', - ' ', - '' + ' ng-click="$ctrl.showPicker($event)">', + ' format_color_fill', + ' ' ].join(''), - replace: true, controller: sgColorPickerController, - link: link + controllerAs: '$ctrl' }; - - function link(scope, iElement, iAttr, ngModelController) { - // Expose ng-model value to scope - ngModelController.$render = function() { - scope.sgColor = ngModelController.$viewValue; - scope.sgIconColor = contrast(ngModelController.$viewValue); - }; - } } - + /** * @ngInject */ - sgColorPickerController.$inject = ['$scope', '$element', 'sgColors']; - function sgColorPickerController($scope, $element, sgColors) { - var ngModelController = $element.controller('ngModel'); + sgColorPickerController.$inject = ['$scope', '$element', '$mdPanel', 'sgColors']; + function sgColorPickerController($scope, $element, $mdPanel, sgColors) { + var $ctrl, ngModelController, color; - $scope.sgColors = sgColors.selection; - $scope.setColor = function(event, color) { - if (event) { - _.forEach(event.currentTarget.parentElement.children, function(tile) { - tile.classList.remove('selected'); - }); - event.currentTarget.classList.add('selected'); + this.$onInit = function() { + $ctrl = this; + ngModelController = $element.controller('ngModel'); + }; + + this.$postLink = function() { + this.buttonIcon = $element.find('md-icon'); + ngModelController.$render = function() { + updateColor(ngModelController.$viewValue); + }; + }; + + function updateColor(newColor) { + color = newColor; + $ctrl.buttonIcon.css('color', color); + } + + this.showPicker = function($event) { + var panelPosition = $mdPanel.newPanelPosition() + .relativeTo($ctrl.buttonIcon) + .addPanelPosition( + $mdPanel.xPosition.ALIGN_START, + $mdPanel.yPosition.ALIGN_TOPS + ); + + var panelAnimation = $mdPanel.newPanelAnimation() + .openFrom($ctrl.buttonIcon) + .duration(100) + .withAnimation($mdPanel.animation.FADE); + + // Build grid with 7 colors per row + var columns = []; + var column = ''; + for (var i = 0; i < sgColors.selection.length; i++) { + var currentColor = sgColors.selection[i]; + var currentContrastColor = contrast(currentColor); + var selected = (currentColor == color); + if (i % 7 === 0) { + if (column.length) columns.push(column); + column = ''; + } + column += ''; + if (selected) + column += ''; + column += ''; + } + + var config = { + attachTo: angular.element(document.body), + bindToController: true, + controller: MenuController, + controllerAs: '$menuCtrl', + position: panelPosition, + animation: panelAnimation, + targetEvent: $event, + template: [ + '
', + '
' + columns.join('
') + '
', + '
' + ].join(''), + trapFocus: true, + clickOutsideToClose: true, + escapeToClose: true, + focusOnOpen: true + }; + + $mdPanel.open(config) + .then(function(panelRef) { + // Automatically close panel when clicking inside of it + panelRef.panelEl.one('click', function() { + panelRef.close(); + }); + }); + + MenuController.$inject = ['mdPanelRef', '$state', '$mdDialog', 'User']; + function MenuController(mdPanelRef, $state, $mdDialog, User) { + var $menuCtrl = this; + + this.setColor = function(event, color) { + if (event) { + _.forEach(event.currentTarget.parentElement.children, function(tile) { + tile.classList.remove('selected'); + }); + event.currentTarget.classList.add('selected'); + } + // Update scope value and ng-model + updateColor(color); + ngModelController.$setViewValue(color); + }; } - // Update scope value and ng-model - $scope.sgColor = color; - $scope.sgIconColor = contrast(color); - ngModelController.$setViewValue(color); }; } diff --git a/UI/WebServerResources/scss/components/colorpicker/colorpicker.scss b/UI/WebServerResources/scss/components/colorpicker/colorpicker.scss new file mode 100644 index 000000000..b55b0f8cc --- /dev/null +++ b/UI/WebServerResources/scss/components/colorpicker/colorpicker.scss @@ -0,0 +1,30 @@ +/// colorpicker.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*- + +$colorpicker-size: 25px; + +.sg-color-picker-panel { + + div { + line-height: 0; + cursor: pointer; + } + + span { + display: inline-block; + height: $colorpicker-size; + transition: transform .2s; + width: $colorpicker-size; + z-index: $z-index-menu; + + &:not(.selected):hover { + outline: 0; + transform: scale(1.3, 1.3); + z-index: $z-index-menu + 1; + } + + md-icon { + float: left; + } + } + +} diff --git a/UI/WebServerResources/scss/styles.scss b/UI/WebServerResources/scss/styles.scss index a05dada96..0d2533c51 100755 --- a/UI/WebServerResources/scss/styles.scss +++ b/UI/WebServerResources/scss/styles.scss @@ -65,6 +65,7 @@ // Inverse components @import 'components/avatarImage/avatarImage'; +@import 'components/colorpicker/colorpicker'; @import 'components/draggable-droppable/draggable'; @import 'components/draggable-droppable/droppable'; @import 'components/hotkeys/hotkeys';