123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- /**
- * Angular nestable 0.0.1
- * Copyright (c) 2014 Kamil Pekala
- * https://github.com/kamilkp/ng-nestable
- */
- /**
- * Sample output HTML
- <div class="dd">
- <ol class="dd-list">
- <li class="dd-item" data-id="1">
- <!-- item element -->
- </li>
- <li class="dd-item" data-id="2">
- <!-- item element -->
- </li>
- <li class="dd-item" data-id="3">
- <!-- item element -->
- <ol class="dd-list">
- <li class="dd-item" data-id="4">
- <!-- item element -->
- </li>
- <li class="dd-item" data-id="5">
- <!-- item element -->
- </li>
- </ol>
- </li>
- </ol>
- </div>
- */
- /**
- * Sample model object
- [
- {
- item: {},
- children: []
- },
- {
- item: {},
- children: [
- {
- item: {},
- children: []
- }
- ]
- },
- {
- item: {},
- children: []
- }
- ]
- */
- ;(function(window, document, angular, undefined){
- angular.module('ng-nestable', [])
- .provider('$nestable', function(){
- var modelName = '$item';
- var defaultOptions = {};
- this.$get = function(){
- return {
- modelName: modelName,
- defaultOptions: defaultOptions
- };
- };
- /**
- * Method to set model variable for nestable elements
- * @param {[string]} value
- */
- this.modelName = function(value){
- modelName = value;
- };
- /**
- * Method to set default nestable options
- * @param {[object]} value
- * You can change the follow options:
- maxDepth : number of levels an item can be nested (default 5)
- group : group ID to allow dragging between lists (default 0)
-
- listNodeName : The HTML element to create for lists (default 'ol')
- itemNodeName : The HTML element to create for list items (default 'li')
- rootClass : The class of the root element .nestable() was used on (default 'dd')
- listClass : The class of all list elements (default 'dd-list')
- itemClass : The class of all list item elements (default 'dd-item')
- dragClass : The class applied to the list element that is being dragged (default 'dd-dragel')
- handleClass : The class of the content element inside each list item (default 'dd-handle')
- collapsedClass : The class applied to lists that have been collapsed (default 'dd-collapsed')
- placeClass : The class of the placeholder element (default 'dd-placeholder')
- emptyClass : The class used for empty list placeholder elements (default 'dd-empty')
- expandBtnHTML : The HTML text used to generate a list item expand button (default '<button data-action="expand">Expand></button>')
- collapseBtnHTML : The HTML text used to generate a list item collapse button (default '<button data-action="collapse">Collapse</button>')
- */
- this.defaultOptions = function(value){
- defaultOptions = value;
- };
- })
- .directive('ngNestable', ['$compile', '$nestable', function($compile, $nestable){
- return {
- restrict: 'A',
- require: 'ngModel',
- compile: function(element){
- var itemTemplate = element.html();
- element.empty();
- return function($scope, $element, $attrs, $ngModel){
- var options = $.extend(
- {},
- $nestable.defaultOptions,
- $scope.$eval($attrs.ngNestable)
- );
- $scope.$watchCollection(function(){
- return $ngModel.$modelValue;
- }, function(model){
- if(model){
- /**
- * we are running the formatters here instead of watching on $viewValue because our model is an Array
- * and angularjs ngModel watcher watches for "shallow" changes and otherwise the possible formatters wouldn't
- * get executed
- */
- model = runFormatters(model, $ngModel);
- // TODO: optimize as rebuilding is not necessary here
- var root = buildNestableHtml(model, itemTemplate);
- $element.empty().append(root);
- $compile(root)($scope);
- root.nestable(options);
- root.on('change', function(){
- $ngModel.$setViewValue(root.nestable('serialize'));
- $scope && $scope.$root && $scope.$root.$$phase || $scope.$apply();
- });
- }
- });
- };
- },
- controller: angular.noop
- };
- function buildNestableHtml(model, tpl){
- var root = $('<div class="dd"></div>');
- var rootList = $('<ol class="dd-list"></ol>').appendTo(root);
- model.forEach(function f(item){
- var list = Array.prototype.slice.call(arguments).slice(-1)[0];
- if(!(list instanceof $)) list = rootList;
- var listItem = $('<li class="dd-item"></li>');
- var listElement = $('<div ng-nestable-item class="dd-handle"></div>');
- listElement.append(tpl).appendTo(listItem);
- list.append(listItem);
- listItem.data('item', item.item);
- if(isArray(item.children) && item.children.length > 0){
- var subRoot = $('<ol class="dd-list"></ol>').appendTo(listItem);
- item.children.forEach(function(item){
- f.apply(this, Array.prototype.slice.call(arguments).concat([subRoot]));
- });
- }
- });
- return root;
- }
- function isArray(arr){
- return Object.prototype.toString.call(arr) === '[object Array]';
- }
- function runFormatters(value, ctrl){
- var formatters = ctrl.$formatters,
- idx = formatters.length;
- ctrl.$modelValue = value;
- while(idx--) {
- value = formatters[idx](value);
- }
- return value;
- }
- }])
- .directive('ngNestableItem', ['$nestable', function($nestable){
- return {
- scope: true,
- require: '^ngNestable',
- link: function($scope, $element){
- $scope[$nestable.modelName] = $element.parent().data('item');
- }
- };
- }]);
- })(window, document, window.angular);
|