diff --git a/src/Umbraco.Web.UI.Client/gulpfile.js b/src/Umbraco.Web.UI.Client/gulpfile.js index b773025e7c..0dd816ae16 100644 --- a/src/Umbraco.Web.UI.Client/gulpfile.js +++ b/src/Umbraco.Web.UI.Client/gulpfile.js @@ -349,6 +349,14 @@ gulp.task('dependencies', function () { "src": ["./node_modules/ng-file-upload/dist/ng-file-upload.min.js"], "base": "./node_modules/ng-file-upload/dist" }, + { + "name": "nouislider", + "src": [ + "./node_modules/nouislider/distribute/nouislider.min.js", + "./node_modules/nouislider/distribute/nouislider.min.css" + ], + "base": "./node_modules/nouislider/distribute" + }, { "name": "signalr", "src": ["./node_modules/signalr/jquery.signalR.js"], diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 69c046624f..d847e14e59 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -33,6 +33,7 @@ "lazyload-js": "1.0.0", "moment": "2.10.6", "ng-file-upload": "12.2.13", + "nouislider": "12.1.0", "npm": "^6.4.1", "signalr": "2.3.0", "tinymce": "4.7.13", diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbrangeslider.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbrangeslider.directive.js new file mode 100644 index 0000000000..c8a22693e3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbrangeslider.directive.js @@ -0,0 +1,148 @@ +(function() { + 'use strict'; + + var umbRangeSlider = { + template: '
', + controller: UmbRangeSliderController, + bindings: { + ngModel: '<', + options: '<', + onSetup: '&?', + onUpdate: '&?', + onSlide: '&?', + onSet: '&?', + onChange: '&?', + onStart: '&?', + onEnd: '&?' + } + }; + + function UmbRangeSliderController($element, $timeout, $scope, assetsService) { + + const ctrl = this; + let sliderInstance = null; + + ctrl.$onInit = function() { + + // load css file for the date picker + assetsService.loadCss('lib/nouislider/nouislider.min.css', $scope); + + // load the js file for the date picker + assetsService.loadJs('lib/nouislider/nouislider.min.js', $scope).then(function () { + // init date picker + grabElementAndRun(); + }); + + }; + + function grabElementAndRun() { + $timeout(function() { + const element = $element.find('.umb-range-slider')[0]; + setSlider(element); + }, 0, true); + } + + function setSlider(element) { + + sliderInstance = element; + + const defaultOptions = { + "start": [0], + "step": 1, + "range": { + "min": [0], + "max": [100] + } + }; + const options = ctrl.options ? ctrl.options : defaultOptions; + + // create new slider + noUiSlider.create(sliderInstance, options); + + if (ctrl.onSetup) { + ctrl.onSetup({ + slider: sliderInstance + }); + } + + // If has ngModel set the date + if (ctrl.ngModel) { + sliderInstance.noUiSlider.set(ctrl.ngModel); + } + + // destroy the flatpickr instance when the dom element is removed + angular.element(element).on('$destroy', function() { + sliderInstance.noUiSlider.off(); + }); + + setUpCallbacks(); + + // Refresh the scope + $scope.$applyAsync(); + } + + function setUpCallbacks() { + if(sliderInstance) { + + // bind hook for update + if(ctrl.onUpdate) { + sliderInstance.noUiSlider.on('update', function (values, handle, unencoded, tap, positions) { + $timeout(function() { + ctrl.onUpdate({values: values, handle: handle, unencoded: unencoded, tap: tap, positions: positions}); + }); + }); + } + + // bind hook for slide + if(ctrl.onSlide) { + sliderInstance.noUiSlider.on('slide', function (values, handle, unencoded, tap, positions) { + $timeout(function() { + ctrl.onSlide({values: values, handle: handle, unencoded: unencoded, tap: tap, positions: positions}); + }); + }); + } + + // bind hook for set + if(ctrl.onSet) { + sliderInstance.noUiSlider.on('set', function (values, handle, unencoded, tap, positions) { + $timeout(function() { + ctrl.onSet({values: values, handle: handle, unencoded: unencoded, tap: tap, positions: positions}); + }); + }); + } + + // bind hook for change + if(ctrl.onChange) { + sliderInstance.noUiSlider.on('change', function (values, handle, unencoded, tap, positions) { + $timeout(function() { + ctrl.onChange({values: values, handle: handle, unencoded: unencoded, tap: tap, positions: positions}); + }); + }); + } + + // bind hook for start + if(ctrl.onStart) { + sliderInstance.noUiSlider.on('start', function (values, handle, unencoded, tap, positions) { + $timeout(function() { + ctrl.onStart({values: values, handle: handle, unencoded: unencoded, tap: tap, positions: positions}); + }); + }); + } + + // bind hook for end + if(ctrl.onEnd) { + sliderInstance.noUiSlider.on('end', function (values, handle, unencoded, tap, positions) { + $timeout(function() { + ctrl.onEnd({values: values, handle: handle, unencoded: unencoded, tap: tap, positions: positions}); + }); + }); + } + + } + } + + } + + angular.module('umbraco.directives').component('umbRangeSlider', umbRangeSlider); + +})(); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.controller.js index 588e2d2b03..f991700dd7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.controller.js @@ -1,50 +1,18 @@ function sliderController($scope, $log, $element, assetsService, angularHelper) { - var sliderRef = null; + let sliderRef = null; /** configure some defaults on init */ function configureDefaults() { - - if (!$scope.model.config.orientation) { - $scope.model.config.orientation = "horizontal"; - } - if (!$scope.model.config.enableRange) { - $scope.model.config.enableRange = false; - } - else { - $scope.model.config.enableRange = Object.toBoolean($scope.model.config.enableRange); - } - if (!$scope.model.config.initVal1) { - $scope.model.config.initVal1 = 0; - } - else { - $scope.model.config.initVal1 = parseFloat($scope.model.config.initVal1); - } - if (!$scope.model.config.initVal2) { - $scope.model.config.initVal2 = 0; - } - else { - $scope.model.config.initVal2 = parseFloat($scope.model.config.initVal2); - } - if (!$scope.model.config.minVal) { - $scope.model.config.minVal = 0; - } - else { - $scope.model.config.minVal = parseFloat($scope.model.config.minVal); - } - if (!$scope.model.config.maxVal) { - $scope.model.config.maxVal = 100; - } - else { - $scope.model.config.maxVal = parseFloat($scope.model.config.maxVal); - } - if (!$scope.model.config.step) { - $scope.model.config.step = 1; - } - else { - $scope.model.config.step = parseFloat($scope.model.config.step); - } + $scope.model.config.orientation = $scope.model.config.orientation ? $scope.model.config.orientation : "horizontal"; + $scope.model.config.enableRange = $scope.model.config.enableRange ? Object.toBoolean($scope.model.config.enableRange) : false; + $scope.model.config.initVal1 = $scope.model.config.initVal1 ? parseFloat($scope.model.config.initVal1) : 0; + $scope.model.config.initVal2 = $scope.model.config.initVal2 ? parseFloat($scope.model.config.initVal2) : 0; + $scope.model.config.minVal = $scope.model.config.minVal ? parseFloat($scope.model.config.minVal) : 0; + $scope.model.config.maxVal = $scope.model.config.maxVal ? parseFloat($scope.model.config.maxVal) : 100; + $scope.model.config.step = $scope.model.config.step ? parseFloat($scope.model.config.step) : 1; + if (!$scope.model.config.handle) { $scope.model.config.handle = "round"; @@ -209,10 +177,40 @@ } } + function setModelValue(values) { + $scope.model.value = values.toString(); + } + + $scope.setup = function(slider) { + sliderRef = slider; + }; + + $scope.update = function(values) { + setModelValue(values); + }; + function init() { configureDefaults(); + // format config to fit slider plugin + const start = $scope.model.config.enableRange ? [$scope.model.config.initVal1, $scope.model.config.initVal2] : [$scope.model.config.initVal1]; + const step = $scope.model.config.step; + const tooltips = $scope.model.config.enableRange ? [true, true] : [true]; + const min = $scope.model.config.minVal ? [$scope.model.config.minVal] : [$scope.model.config.minVal]; + const max = $scope.model.config.maxVal ? [$scope.model.config.maxVal] : [$scope.model.config.maxVal]; + + // setup default + $scope.sliderOptions = { + "start": start, + "step": step, + "tooltips": tooltips, + "range": { + "min": min, + "max": max + } + }; + //tell the assetsService to load the bootstrap slider //libs from the plugin folder assetsService diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.html index 638ecead4b..4bbe6448ba 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/slider.html @@ -1,5 +1,19 @@ 
+ +
+ + +
+ +
Value
+ {{model.value}} +
config
+
{{model.config | json}}