1/** 2 * Angular nestable 0.0.1 3 * Copyright (c) 2014 Kamil Pekala 4 * https://github.com/kamilkp/ng-nestable 5 */ 6 7/** 8 * Sample output HTML 9 <div class="dd"> 10 <ol class="dd-list"> 11 <li class="dd-item" data-id="1"> 12 <!-- item element --> 13 </li> 14 <li class="dd-item" data-id="2"> 15 <!-- item element --> 16 </li> 17 <li class="dd-item" data-id="3"> 18 <!-- item element --> 19 <ol class="dd-list"> 20 <li class="dd-item" data-id="4"> 21 <!-- item element --> 22 </li> 23 <li class="dd-item" data-id="5"> 24 <!-- item element --> 25 </li> 26 </ol> 27 </li> 28 </ol> 29 </div> 30 */ 31 32/** 33 * Sample model object 34 [ 35 { 36 item: {}, 37 children: [] 38 }, 39 { 40 item: {}, 41 children: [ 42 { 43 item: {}, 44 children: [] 45 } 46 ] 47 }, 48 { 49 item: {}, 50 children: [] 51 } 52 ] 53 */ 54 55;(function(window, document, angular, undefined){ 56 angular.module('ng-nestable', []) 57 .provider('$nestable', function(){ 58 var modelName = '$item'; 59 var itemProperty = 'item'; 60 var childrenProperty = 'children'; 61 var collapseAllOnStart = false; 62 var defaultOptions = {}; 63 64 this.$get = function(){ 65 return { 66 modelName: modelName, 67 itemProperty: itemProperty, 68 childrenProperty: childrenProperty, 69 collapseAllOnStart: collapseAllOnStart, 70 defaultOptions: defaultOptions 71 }; 72 }; 73 74 /** 75 * Method to set model variable for nestable elements 76 * @param {[string]} value 77 */ 78 this.modelName = function(value){ 79 modelName = value; 80 }; 81 82 /** 83 * Method to set property which contains child elements 84 * @param {[string]} value 85 */ 86 this.childrenProperty = function(value){ 87 childrenProperty = value; 88 }; 89 90 /** 91 * Method to set property which contains item information 92 * @param {[string]} value 93 * 94 * Use 'null' to expose item properties to object on the same level as children array 95 * @example 96 * { 97 * title: 'Title', 98 * name: 'Name', 99 * prop1: '' 100 * ... 101 * children: [] 102 * }, 103 * 104 */ 105 this.itemProperty = function(value){ 106 itemProperty = value; 107 }; 108 109 /** 110 * Method to set option which responsible for collapsing all items on start 111 * @param {[boolean]} value 112 */ 113 this.collapseAllOnStart = function (value) { 114 collapseAllOnStart = value; 115 }; 116 /** 117 * Method to set default nestable options 118 * @param {[object]} value 119 * You can change the follow options: 120 121 maxDepth : number of levels an item can be nested (default 5) 122 group : group ID to allow dragging between lists (default 0) 123 124 listNodeName : The HTML element to create for lists (default 'ol') 125 itemNodeName : The HTML element to create for list items (default 'li') 126 rootClass : The class of the root element .nestable() was used on (default 'dd') 127 listClass : The class of all list elements (default 'dd-list') 128 itemClass : The class of all list item elements (default 'dd-item') 129 dragClass : The class applied to the list element that is being dragged (default 'dd-dragel') 130 handleClass : The class of the content element inside each list item (default 'dd-handle') 131 collapsedClass : The class applied to lists that have been collapsed (default 'dd-collapsed') 132 placeClass : The class of the placeholder element (default 'dd-placeholder') 133 emptyClass : The class used for empty list placeholder elements (default 'dd-empty') 134 expandBtnHTML : The HTML text used to generate a list item expand button (default '<button data-action="expand">Expand></button>') 135 collapseBtnHTML : The HTML text used to generate a list item collapse button (default '<button data-action="collapse">Collapse</button>') 136 137 138 */ 139 this.defaultOptions = function(value){ 140 defaultOptions = value; 141 }; 142 }) 143 .directive('ngNestable', ['$compile', '$nestable', function($compile, $nestable){ 144 return { 145 restrict: 'A', 146 require: 'ngModel', 147 compile: function(element){ 148 var itemTemplate = element.html(); 149 element.empty(); 150 return function($scope, $element, $attrs, $ngModel){ 151 var options = $.extend( 152 {}, 153 $nestable.defaultOptions, 154 $scope.$eval($attrs.ngNestable) 155 ); 156 $scope.$watchCollection(function(){ 157 return $ngModel.$modelValue; 158 }, function(model){ 159 if(model && element.is(':empty')){ 160 161 /** 162 * we are running the formatters here instead of watching on $viewValue because our model is an Array 163 * and angularjs ngModel watcher watches for "shallow" changes and otherwise the possible formatters wouldn't 164 * get executed 165 */ 166 model = runFormatters(model, $ngModel); 167 var root = buildNestableHtml(model, itemTemplate); 168 $element.empty().append(root); 169 $compile(root)($scope);
170 root.nestable(options); 171 if ($nestable.collapseAllOnStart) { 172 root.nestable('collapseAll'); 173 } 174 root.on('change', function(){ 175 $ngModel.$setViewValue(root.nestable('serialize')); 176 $scope && $scope.$root && $scope.$root.$$phase || $scope.$apply(); 177 }); 178 } 179 }); 180 }; 181 }, 182 controller: angular.noop 183 }; 184 185 function buildNestableHtml(model, tpl){ 186 var root = $('<div class="dd"></div>'); 187 var rootList = $('<ol class="dd-list"></ol>').appendTo(root); 188 model.forEach(function f(item){ 189 var list = Array.prototype.slice.call(arguments).slice(-1)[0]; 190 if(!(list instanceof $)) list = rootList; 191 192 var listItem = $('<li class="dd-item"></li>'); 193 var listElement = $('<div ng-nestable-item class="dd-handle"></div>'); 194 listElement.append(tpl).appendTo(listItem); 195 list.append(listItem); 196 var itemData = $nestable.itemProperty ? item[$nestable.itemProperty] : item; 197 listItem.data('item', itemData); 198 var children = item[$nestable.childrenProperty]; 199 if(isArray(children) && children.length > 0){ 200 var subRoot = $('<ol class="dd-list"></ol>').appendTo(listItem); 201 children.forEach(function(item){ 202 f.apply(this, Array.prototype.slice.call(arguments).concat([subRoot])); 203 }); 204 } 205 }); 206 207 return root; 208 } 209 210 function isArray(arr){ 211 return Object.prototype.toString.call(arr) === '[object Array]'; 212 } 213 214 function runFormatters(value, ctrl){ 215 var formatters = ctrl.$formatters, 216 idx = formatters.length; 217 218 ctrl.$modelValue = value; 219 while(idx--) { 220 value = formatters[idx](value); 221 } 222 223 return value; 224 } 225 }]) 226 .directive('ngNestableItem', ['$nestable', function($nestable){ 227 return { 228 scope: true, 229 require: '^ngNestable', 230 link: function($scope, $element){ 231 $scope[$nestable.modelName] = $element.parent().data('item'); 232 } 233 }; 234 }]); 235})(window, document, window.angular);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.