4 |
5 | */
6 |
7 | .hljs {
8 | display: block;
9 | overflow-x: auto;
10 | padding: 0.5em;
11 | color: #333;
12 | background: #f8f8f8;
13 | -webkit-text-size-adjust: none;
14 | }
15 |
16 | .hljs-comment,
17 | .diff .hljs-header {
18 | color: #998;
19 | font-style: italic;
20 | }
21 |
22 | .hljs-keyword,
23 | .css .rule .hljs-keyword,
24 | .hljs-winutils,
25 | .nginx .hljs-title,
26 | .hljs-subst,
27 | .hljs-request,
28 | .hljs-status {
29 | color: #333;
30 | font-weight: bold;
31 | }
32 |
33 | .hljs-number,
34 | .hljs-hexcolor,
35 | .ruby .hljs-constant {
36 | color: #008080;
37 | }
38 |
39 | .hljs-string,
40 | .hljs-tag .hljs-value,
41 | .hljs-doctag,
42 | .tex .hljs-formula {
43 | color: #d14;
44 | }
45 |
46 | .hljs-title,
47 | .hljs-id,
48 | .scss .hljs-preprocessor {
49 | color: #900;
50 | font-weight: bold;
51 | }
52 |
53 | .hljs-list .hljs-keyword,
54 | .hljs-subst {
55 | font-weight: normal;
56 | }
57 |
58 | .hljs-class .hljs-title,
59 | .hljs-type,
60 | .vhdl .hljs-literal,
61 | .tex .hljs-command {
62 | color: #458;
63 | font-weight: bold;
64 | }
65 |
66 | .hljs-tag,
67 | .hljs-tag .hljs-title,
68 | .hljs-rule .hljs-property,
69 | .django .hljs-tag .hljs-keyword {
70 | color: #000080;
71 | font-weight: normal;
72 | }
73 |
74 | .hljs-attribute,
75 | .hljs-variable,
76 | .lisp .hljs-body,
77 | .hljs-name {
78 | color: #008080;
79 | }
80 |
81 | .hljs-regexp {
82 | color: #009926;
83 | }
84 |
85 | .hljs-symbol,
86 | .ruby .hljs-symbol .hljs-string,
87 | .lisp .hljs-keyword,
88 | .clojure .hljs-keyword,
89 | .scheme .hljs-keyword,
90 | .tex .hljs-special,
91 | .hljs-prompt {
92 | color: #990073;
93 | }
94 |
95 | .hljs-built_in {
96 | color: #0086b3;
97 | }
98 |
99 | .hljs-preprocessor,
100 | .hljs-pragma,
101 | .hljs-pi,
102 | .hljs-doctype,
103 | .hljs-shebang,
104 | .hljs-cdata {
105 | color: #999;
106 | font-weight: bold;
107 | }
108 |
109 | .hljs-deletion {
110 | background: #fdd;
111 | }
112 |
113 | .hljs-addition {
114 | background: #dfd;
115 | }
116 |
117 | .diff .hljs-change {
118 | background: #0086b3;
119 | }
120 |
121 | .hljs-chunk {
122 | color: #aaa;
123 | }
124 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleNgRepeatWithModel/exampleNgRepeatWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
ngRepeat - with model
3 |
Example of using ng-repeat with dragular and adding/removing items dynamicaly.
4 |
5 |
6 |
7 |
8 | {{item.content}}
9 | +
10 | x
11 |
12 |
13 |
14 |
15 |
16 |
Items:
17 | {{items | json}}
18 |
19 |
20 |
21 |
22 |
23 | // HTML:
24 | <div class="wrapper" ng-controller="NgRepeatWithModel">
25 | <div class="container-vertical">
26 | <div ng-repeat="item in items">
27 | {{item.content}}
28 | <button class="cursor-default" ng-click="addItem()">+</button>
29 | <button class="cursor-default" ng-click="removeItem()">x</button>
30 | </div>
31 | </div>
32 | </div>
33 |
34 |
35 |
36 |
37 | // JS:
38 | controller('NgRepeatWithModel', ['$scope', '$element', 'dragularService', function TodoCtrl($scope, $element, dragularService) {
39 | $scope.items = [{
40 | content: 'Try to add or remove some elements (click on +- buttons), you will see that it is not problem for dragular.'
41 | }, {
42 | content: 'Item 2'
43 | }, {
44 | content: 'Item 3'
45 | }, {
46 | content: 'Item 4'
47 | }];
48 | dragularService($element.children().eq(0).children(), {containersModel: $scope.items});
49 | $scope.addItem = function addItem() {
50 | var index = $scope.items.indexOf(this.item) + 1;
51 | $scope.items.splice(index, 0, {
52 | content: this.item.content + '-copy'
53 | });
54 | };
55 | $scope.removeItem = function removeItem() {
56 | var index = $scope.items.indexOf(this.item);
57 | $scope.items.splice(index, 1);
58 | };
59 | }])
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleEvents/exampleEvents.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var EventsCtrl = function ($scope, $element, dragularService, $timeout) {
4 | dragularService.cleanEnviroment();
5 |
6 | var drake = dragularService($element.children(), {
7 | scope: $scope
8 | });
9 | $scope.$on('dragulardrag', function(e, el) {
10 | e.stopPropagation();
11 | el.className = el.className.replace(' ex-moved', '');
12 | });
13 | $scope.$on('dragulardrop', function(e, el) {
14 | e.stopPropagation();
15 | $timeout(function() {
16 | el.className += ' ex-moved';
17 | }, 0);
18 | });
19 |
20 | $scope.$on('dragularcloned', myFn('cloned in EventsCtrl'));
21 | $scope.$on('dragulardrag', myFn('drag in EventsCtrl'));
22 | $scope.$on('dragularcancel', myFn('cancel in EventsCtrl'));
23 | $scope.$on('dragulardrop', myFn('drop in EventsCtrl'));
24 | $scope.$on('dragularremove', myFn('remove in EventsCtrl'));
25 | $scope.$on('dragulardragend', myFn('dragend in EventsCtrl'));
26 | $scope.$on('dragularshadow', myFn('shadow in EventsCtrl'));
27 |
28 | function myFn(eventName) {
29 | return function() {
30 | console.log(eventName, arguments, drake);
31 | };
32 | }
33 | };
34 |
35 | var Events2Ctrl = function ($scope, $element, dragularService, $timeout) {
36 | var drake = dragularService($element.children(), {
37 | scope: $scope
38 | });
39 | $scope.$on('dragulardrag', function(e, el) {
40 | e.stopPropagation();
41 | el.className = el.className.replace(' ex-moved', '');
42 | });
43 | $scope.$on('dragulardrop', function(e, el) {
44 | e.stopPropagation();
45 | $timeout(function() {
46 | el.className += ' ex-moved';
47 | }, 0);
48 | });
49 |
50 | $scope.$on('dragularcloned', myFn('cloned in Events2Ctrl'));
51 | $scope.$on('dragulardrag', myFn('drag in Events2Ctrl'));
52 | $scope.$on('dragularcancel', myFn('cancel in Events2Ctrl'));
53 | $scope.$on('dragulardrop', myFn('drop in Events2Ctrl'));
54 | $scope.$on('dragularremove', myFn('remove in Events2Ctrl'));
55 | $scope.$on('dragulardragend', myFn('dragend in Events2Ctrl'));
56 | $scope.$on('dragularshadow', myFn('shadow in Events2Ctrl'));
57 |
58 | function myFn(eventName) {
59 | return function() {
60 | console.log(eventName, arguments, drake);
61 | };
62 | }
63 | };
64 |
65 | EventsCtrl.$inject = ['$scope', '$element', 'dragularService', '$timeout'];
66 | Events2Ctrl.$inject = ['$scope', '$element', 'dragularService', '$timeout'];
67 |
68 | module.exports = [EventsCtrl, Events2Ctrl];
69 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleDirectiveWithModel/exampleDirectiveWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
Directive - with model
3 |
Same as custom classes example, but showing use of directive.
4 |
5 |
6 |
9 |
10 |
{{item.content}}
11 |
12 |
13 |
14 |
15 |
Items1:
16 | {{items1 | json}}
17 |
18 |
19 |
Items2:
20 | {{items2 | json}}
21 |
22 |
23 |
24 |
25 |
26 |
27 | // JS
28 | controller('DirectiveModel', ['$scope', function TodoCtrl($scope) {
29 | $scope.items1 = [{
30 | content: 'Move me, and make copy on drop.'
31 | }, {
32 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.'
33 | }, {
34 | content: 'Item 3'
35 | }, {
36 | content: 'Item 4'
37 | }];
38 | $scope.items2 = [{
39 | content: 'Item 5'
40 | }, {
41 | content: 'Item 6'
42 | }, {
43 | content: 'Item 7'
44 | }, {
45 | content: 'Item 8'
46 | }];
47 | $scope.dragularOptions = {
48 | containersModel: $scope.items1,
49 | classes: {
50 | mirror: 'custom-green-mirror'
51 | },
52 | nameSpace: 'common' // just connecting left and right container
53 | };
54 | }])
55 |
56 |
57 | <!-- HTML -->
58 | <div class="wrapper" ng-controller="DirectiveModel">
59 | <div class="container-vertical" dragular="dragularOptions">
60 | <div ng-repeat="item in items1">{{item.content}}</div>
61 | </div>
62 | <div class="container-vertical" dragular='{"containersModel":"items2","classes":{"mirror":"custom-green-mirror"},"nameSpace":"common"}'>
63 | <div ng-repeat="item in items2">{{item.content}}</div>
64 | </div>
65 | </div>
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleBasicWithModel/exampleBasicWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
Basic - with model
3 |
Move stuff between these two containers. Note how the stuff gets inserted near the mouse pointer? Great stuff.
4 |
5 |
6 |
9 |
10 |
{{item.content}}
11 |
12 |
13 |
14 |
15 |
Items1:
16 | {{items1 | json}}
17 |
18 |
19 |
Items2:
20 | {{items2 | json}}
21 |
22 |
23 |
24 |
25 |
26 | // JS
27 | controller('BasicModel', ['$scope', '$element', 'dragularService', function TodoCtrl($scope, $element, dragularService) {
28 | $scope.items1 = [{
29 | content: 'Move me, but you can only drop me in one of these containers.'
30 | }, {
31 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.'
32 | }, {
33 | content: 'Item 3'
34 | }, {
35 | content: 'Item 4'
36 | }];
37 | $scope.items2 = [{
38 | content: 'Item 5'
39 | }, {
40 | content: 'Item 6'
41 | }, {
42 | content: 'Item 7'
43 | }, {
44 | content: 'Item 8'
45 | }];
46 | var containers = $element.children().children();
47 | dragularService([containers[0],containers[1]],{
48 | containersModel: [$scope.items1, $scope.items2]
49 | });
50 | }])
51 |
52 |
53 | <!-- HTML -->
54 | <div class="wrapper" ng-controller="Basic">
55 | <div class="table-row">
56 | <div class="container-vertical">
57 | <div ng-repeat="item in items1">{{item.content}}</div>
58 | </div>
59 | <div class="container-vertical">
60 | <div ng-repeat="item in items2">{{item.content}}</div>
61 | </div>
62 | </div>
63 | <div class="table-row">
64 | <div class="container">
65 | <div>Items1:
66 | <br/>{{items1 | json}}</div>
67 | </div>
68 | <div class="container">
69 | <div>Items2:
70 | <br/>{{items2 | json}}</div>
71 | </div>
72 | </div>
73 | </div>
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleCopyWithModel/exampleCopyWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
Copy - with model
3 |
Copying stuff is great too.
4 |
5 |
6 |
9 |
10 |
{{item.content}}
11 |
12 |
13 |
14 |
15 |
Items1:
16 |
17 | {{ items1 | json }}
18 |
19 |
20 |
21 |
22 |
Items2:
23 |
24 | {{ items2 | json }}
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | // JS
33 | controller('CopyModel', ['$scope', '$element', 'dragularService', function TodoCtrl($scope, $element, dragularService) {
34 | $scope.items1 = [{
35 | content: 'Move me, and make copy on drop.'
36 | }, {
37 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.'
38 | }, {
39 | content: 'Item 3'
40 | }, {
41 | content: 'Item 4'
42 | }];
43 | $scope.items2 = [{
44 | content: 'Item 5'
45 | }, {
46 | content: 'Item 6'
47 | }, {
48 | content: 'Item 7'
49 | }, {
50 | content: 'Item 8'
51 | }];
52 | var containers = $element.children().children();
53 | dragularService([containers[0],containers[1]],{
54 | containersModel: [$scope.items1, $scope.items2],
55 | copy: true
56 | });
57 | }])
58 |
59 |
60 | <!-- HTML -->
61 | <div class="wrapper" ng-controller="CopyModel" ng-show="globals.showModelExamples">
62 | <div class="table-row">
63 | <div class="container-vertical">
64 | <div ng-repeat="item in items1">{{item.content}}</div>
65 | </div>
66 | <div class="container-vertical">
67 | <div ng-repeat="item in items2">{{item.content}}</div>
68 | </div>
69 | </div>
70 | <div class="table-row">
71 | <div class="container">
72 | <div>Items1:
73 | <br/>{{items1 | json}}</div>
74 | </div>
75 | <div class="container">
76 | <div>Items2:
77 | <br/>{{items2 | json}}</div>
78 | </div>
79 | </div>
80 | </div>
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleNgRepeatFilteredWithModel/exampleNgRepeatFilteredWithModel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var NgRepeatFilteredWithModelCtrl = function ($scope, $element, dragularService, $filter) {
4 | $scope.items1 = [{
5 | content: 'Move me, but you can only drop me in one of these containers.'
6 | }, {
7 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.'
8 | }, {
9 | content: 'Apple 3'
10 | }, {
11 | content: 'Orange 4'
12 | }, {
13 | content: 'Orange 5'
14 | }, {
15 | content: 'Apple 6'
16 | }, {
17 | content: 'Apple 7'
18 | }, {
19 | content: 'Apple 8'
20 | }];
21 | $scope.items2 = [{
22 | content: 'Apple 9'
23 | }, {
24 | content: 'Orange 10'
25 | }, {
26 | content: 'Orange 11'
27 | }, {
28 | content: 'Apple 12'
29 | }, {
30 | content: 'Orange 13'
31 | }, {
32 | content: 'Apple 14'
33 | }];
34 | $scope.filter1query = 'Orange';
35 | $scope.filter2query = 'Orange';
36 | $scope.filteredModel1 = [];
37 | $scope.filteredModel2 = [];
38 | $scope.getFilteredModel = function (filteredModel, items, filterQuery) {
39 | filteredModel.length = 0;
40 | /*
41 | * Following one-liner is same like:
42 | * var filteredModelTemp = $filter('filter')(items, filterQuery);
43 | * angular.forEach(filteredModelTemp, function(item){
44 | * filteredModel.push(item);
45 | * });
46 | * Or like:
47 | * var filteredModelTemp = $filter('filter')(items, filterQuery);
48 | * for(var i; i < filteredModelTemp.length; i++){
49 | * filteredModel.push(filteredModelTemp[i]);
50 | * }
51 | *
52 | * You cannot just assign filtered array to filteredModel like this:
53 | * filteredModel = $filter('filter')(items, filterQuery);
54 | * Because you would replace the array object you provide to dragular with new one.
55 | * So dragular will continue to use the one it was provided on init.
56 | * Hopefully I make it clear. :)
57 | */
58 | [].push.apply(filteredModel, $filter('filter')(items, filterQuery));
59 |
60 | // Example with orderBy filter:
61 | // var tmp = [];
62 | // [].push.apply(tmp, $filter('filter')(items, filterQuery));
63 | // [].push.apply(filteredModel, $filter('orderBy')(tmp, '+content'));
64 |
65 | return filteredModel;
66 | };
67 | var containers = $element.children().eq(1).children();
68 | dragularService.cleanEnviroment();
69 | dragularService([containers[0],containers[1]],{
70 | containersModel: [$scope.items1, $scope.items2],
71 | containersFilteredModel: [$scope.filteredModel1, $scope.filteredModel2]
72 | });
73 | };
74 |
75 | NgRepeatFilteredWithModelCtrl.$inject = ['$scope', '$element', 'dragularService', '$filter'];
76 |
77 | module.exports = NgRepeatFilteredWithModelCtrl;
78 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleRemoveOnSpillWithModel/exampleRemoveOnSpillWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
Remove on spill - with model
3 |
Need to be able to quickly delete stuff when it spills out of the chosen containers?
4 |
5 |
6 |
9 |
10 |
{{item.content}}
11 |
12 |
13 |
14 |
15 |
Items1:
16 | {{items1 | json}}
17 |
18 |
19 |
Items2:
20 | {{items2 | json}}
21 |
22 |
23 |
24 |
25 |
26 | // JS
27 | .controller('RemoveOnSpillWithModel', ['$scope', '$element', 'dragularService', function TodoCtrl($scope, $element, dragularService) {
28 | $scope.items1 = [{
29 | content: 'Move me, but you can only drop me in containers.'
30 | }, {
31 | content: 'If you try to drop me somewhere other than containers, I\'ll die a fiery death.'
32 | }, {
33 | content: 'Item 3'
34 | }, {
35 | content: 'Item 4'
36 | }];
37 | $scope.items2 = [{
38 | content: 'You can drop me in the left container.'
39 | }, {
40 | content: 'Item 6'
41 | }, {
42 | content: 'Item 7'
43 | }, {
44 | content: 'Item 8'
45 | }];
46 | var containers = $element.children().eq(0).children();
47 | dragularService.cleanEnviroment();
48 | dragularService([containers[0],containers[1]],{
49 | containersModel: [$scope.items1, $scope.items2],
50 | removeOnSpill: true
51 | });
52 | }])
53 |
54 |
55 | <!-- HTML -->
56 | <div class="wrapper" ng-controller="Basic">
57 | <div class="table-row">
58 | <div class="container-vertical">
59 | <div ng-repeat="item in items1">{{item.content}}</div>
60 | </div>
61 | <div class="container-vertical">
62 | <div ng-repeat="item in items2">{{item.content}}</div>
63 | </div>
64 | </div>
65 | <div class="table-row">
66 | <div class="container">
67 | <div>Items1:
68 | <br/>{{items1 | json}}</div>
69 | </div>
70 | <div class="container">
71 | <div>Items2:
72 | <br/>{{items2 | json}}</div>
73 | </div>
74 | </div>
75 | </div>
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleNestedNgRepeat/exampleNestedNgRepeat.html:
--------------------------------------------------------------------------------
1 |
2 |
Nested ngRepeat
3 |
You can move whole rows by grabing row title, all items it selves. Try it out!
4 |
5 | Old IE doesnt support Flexible Box Layout so it can look weird. But in modern browsers it is awsome! Dragular will be working well also in old IE but you have to use different css for layout.
6 |
7 |
8 |
9 |
10 |
Row {{$index}}
11 |
{{item.content}}
12 |
13 |
14 |
15 |
16 | // HTML
17 |
18 | <div ng-controller="Example15">
19 | <div ng-repeat="item in items" class="example-row">
20 | <div class="row-handle">Row {{$index}}</div>
21 | <div ng-repeat="item in item.items" class="example-cell">{{item.content}}</div>
22 | </div>
23 | </div>
24 |
25 |
26 |
27 |
28 | // CSS
29 |
30 | .example-row {
31 | display: flex;
32 | flex-direction: row;
33 | }
34 |
35 | .example-cell {
36 | flex-grow: 1;
37 | }
38 |
39 | .example-row,
40 | .example-cell {
41 | margin: 10px;
42 | padding: 10px;
43 | background-color: rgba(0, 0, 0, 0.2);
44 | cursor: move;
45 | cursor: grab;
46 | cursor: -moz-grab;
47 | cursor: -webkit-grab;
48 | }
49 |
50 |
51 |
52 |
53 | // JS
54 |
55 | .controller('NestedNgRepeat', ['$timeout', '$scope', '$element', 'dragularService', function NestedNgRepeatCtrl($timeout, $scope, $element, dragularService) {
56 | $timeout(function() { // timeount due to ngRepeat to be ready
57 | dragularService($element, {
58 | nameSpace: 'rows',
59 | moves: function rowOnly (el, container, handle) {
60 | return handle.classList.contains('row-handle');
61 | }
62 | });
63 | dragularService($element.children(), {
64 | nameSpace: 'cells',
65 | moves: function excludeHandle (el, container, handle) {
66 | return !handle.classList.contains('row-handle');
67 | }
68 | });
69 | }, 0);
70 | $scope.items = [{
71 | items: [{
72 | content: 'Item a1'
73 | }, {
74 | content: 'Item a2'
75 | }, {
76 | content: 'Item a3'
77 | }, {
78 | content: 'Item a4'
79 | }]
80 | }, {
81 | items: [{
82 | content: 'Item b1'
83 | }, {
84 | content: 'Item b2'
85 | }, {
86 | content: 'Item b3'
87 | }, {
88 | content: 'Item b4'
89 | }]
90 | }, {
91 | items: [{
92 | content: 'Item c1'
93 | }, {
94 | content: 'Item c2'
95 | }, {
96 | content: 'Item c3'
97 | }, {
98 | content: 'Item c4'
99 | }]
100 | }];
101 | }])
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/docs/src/examples/partials/partial-home.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
Browser support includes every sane browser and **IE7+**. _(Granted you polyfill the functional `Array` methods in ES5)_
13 |
Inspiration
14 |
I am working on huge angular project and I am using several drag&drop libraries in it, one for UI, one for lists, etc.. I want to use one full-featured drag&drop library for whole project. As I could not find any suitable, I decided to create one. I have choosen great library dragula by Nicolas Bevacqua as my starting point, make it more angular and started to put features in it! If you wish light-weight angular version of dragula, there is official angular version of dragula .
15 |
Actual version 4.6.0 is based on dragula 3.6.3 and tested with angular 1.5.5.
16 |
Differences of dragular (against dragula)
17 |
18 | replaced dragula crossvent with angulars event binding
19 | replaced dragula contra.emitter with $scope.$emit if scope provided in options (options.scope)
20 | provided as service or directive dragular where options can be passed via atribute dragular
21 | automatic direction if not provided in options, instead of default vertical
22 | accepting arraylike objects as containers array (jQuery, jQlite collections etc..)
23 | accepting custom classes via option.classes
24 | namespaced containers groups available via option.nameSpace (containers in same nameSpace cooperate)
25 | boundingBox (dragging element can me moved only in specific area)
26 | lockX/Y (dragging element can me moved only in specific direction)
27 | DOM can be synced with scope model
28 | support css selectors to define containers
29 | added syntax highlighter to example codes
30 | etc..
31 |
32 |
Todo
33 |
36 |
Features
37 |
38 | provided as service and also as directive
39 | Super easy to set up
40 | No bloated dependencies
41 | Figures out sort order on its own
42 | A shadow where the item would be dropped offers visual feedback
43 | Touch events!
44 |
45 |
For installation, usage and examples go to docs
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleNestedNgRepeatWithModel/exampleNestedNgRepeatWithModel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var NestedNgRepeatWithModelCtrl = function ($timeout, $scope, $element, dragularService) {
4 | $timeout(function() { // timeount due to nested ngRepeat to be ready
5 | var rowsContainer = $element[0].querySelector('.container-vertical'),
6 | cellsContainers = getCellsContainers();
7 |
8 | dragularService.cleanEnviroment();
9 | dragularService(rowsContainer, {
10 | moves: function(el, container, handle) {
11 | return handle.classList.contains('row-handle');
12 | },
13 | containersModel: $scope.rows,
14 | nameSpace: 'rows'
15 | });
16 |
17 | var cellsContainersDrake = dragularService(cellsContainers, {
18 | moves: function(el, container, handle) {
19 | return handle.classList.contains('example-cell');
20 | },
21 | containersModel: getcellsContainersModel(),
22 | nameSpace: 'cells'
23 | });
24 |
25 | $scope.addItem = function(row) {
26 | var item = {
27 | content: 'Item x' + Math.round( Math.random() * 1000 )
28 | }
29 | row.items.push( item );
30 | }
31 |
32 | $scope.removeItem = function(row, item) {
33 | row.items.splice( row.items.indexOf( item ), 1);
34 | }
35 |
36 | $scope.addRow = function() {
37 | var row = { items: [] };
38 | $scope.rows.push( row );
39 | // wait for angular to create element for added row
40 | $scope.$evalAsync(function() {
41 | // $evalAsync is probably not enough to get after the DOM creation, so timeouted :/
42 | $timeout(function() {
43 | // you can provide all containers, dragular will add just new containers
44 | cellsContainersDrake.addContainers( getCellsContainers(), getcellsContainersModel());
45 | }, 500);
46 | });
47 | }
48 |
49 | $scope.removeRow = function( row, e ) {
50 | var cellsContainerElm = e.target.parentElement.parentElement.querySelectorAll('.container-nested')[0];
51 | cellsContainersDrake.removeContainers( cellsContainerElm );
52 | $scope.rows.splice( $scope.rows.indexOf( row ), 1 );
53 | }
54 |
55 | function getCellsContainers() {
56 | return $element[0].querySelectorAll('.container-nested');
57 | }
58 |
59 | function getcellsContainersModel(){
60 | var parent = $scope.rows,
61 | containersModel = [];
62 | for (var i = 0; i < parent.length; i++) {
63 | containersModel.push(parent[i].items);
64 | }
65 | return containersModel;
66 | }
67 |
68 | }, 0);
69 |
70 | $scope.rows = [{
71 | items: [{
72 | content: 'Item a1'
73 | }, {
74 | content: 'Item a2'
75 | }, {
76 | content: 'Item a3'
77 | }, {
78 | content: 'Item a4'
79 | }]
80 | }, {
81 | items: [{
82 | content: 'Item b1'
83 | }, {
84 | content: 'Item b2'
85 | }, {
86 | content: 'Item b3'
87 | }, {
88 | content: 'Item b4'
89 | }]
90 | }, {
91 | items: [{
92 | content: 'Item c1'
93 | }, {
94 | content: 'Item c2'
95 | }, {
96 | content: 'Item c3'
97 | }, {
98 | content: 'Item c4'
99 | }]
100 | }];
101 | };
102 |
103 | NestedNgRepeatWithModelCtrl.$inject = ['$timeout', '$scope', '$element', 'dragularService'];
104 |
105 | module.exports = NestedNgRepeatWithModelCtrl;
106 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleIsContainerWithModel/exampleIsContainerWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
isContainer - with model
3 |
Possible use case of options.isContainer combined with model. When you provide function isContainer and in case it returns true and you are providing models (options.containersModel ), dragular check for model by calling options.isContainerModel(el) function. If not provided, model is discarted.
4 |
5 |
6 |
9 |
10 |
{{item.content}}
11 | x
12 |
13 |
14 |
15 |
16 |
Items1:
17 | {{items1 | json}}
18 |
19 |
20 |
Cart:
21 | {{cartModel | json}}
22 |
23 |
24 |
25 |
26 |
27 | // JS
28 | .controller('IsContainerModel', ['$scope', '$element', 'dragularService', function TodoCtrl($scope, $element, dragularService) {
29 | $scope.items1 = [{
30 | content: 'Move me, but you can only drop me in one of these containers.'
31 | }, {
32 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.'
33 | }, {
34 | content: 'Item 3'
35 | }, {
36 | content: 'Item 4'
37 | }];
38 | $scope.cartModel = [];
39 |
40 | var containerLeft = document.querySelector('#containerLeft');
41 |
42 | dragularService.cleanEnviroment();
43 | dragularService([containerLeft], {
44 | containersModel: [$scope.items1],
45 | copy: true,
46 | isContainer: function isContainer (el) {
47 | return el.id === 'cart';
48 | },
49 | isContainerModel: function getModel (){
50 | return $scope.cartModel;
51 | }
52 | });
53 |
54 | $scope.removeItem = function removeItem() {
55 | var index = $scope.cartModel.indexOf(this.item);
56 | $scope.cartModel.splice(index, 1);
57 | };
58 |
59 | }])
60 |
61 |
62 | <!-- HTML -->
63 | <div class="wrapper" ng-controller="IsContainerModel">
64 | <div class="table-row">
65 | <div id="containerLeft" class="container-vertical">
66 | <div ng-repeat="item in items1">{{item.content}}</div>
67 | </div>
68 | <div id="cart" class="container-vertical">
69 | <div class="cursor-default" ng-repeat="item in cartModel">{{item.content}}
70 | <button class="cursor-default" ng-click="removeItem()">x</button></div>
71 | </div>
72 | </div>
73 | <div class="table-row">
74 | <div class="container-vertical">
75 | <pre>Items1:
76 | <br/>{{items1 | json}}</pre>
77 | </div>
78 | <div class="container-vertical">
79 | <pre>Cart:
80 | <br/>{{cartModel | json}}</pre>
81 | </div>
82 | </div>
83 | </div>
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleDifferentOptionsWithModel/exampleDifferentOptionsWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
Different options - with model
3 |
You may need to setup different options (rules) for each container. For such setup you need to initialize each container separately. Do not initialize same container twice! In example bellow you can copy from left to right, but not otherwise. And from right container items can be removed on spill.
4 |
5 |
6 |
9 |
10 |
{{item.content}}
11 |
12 |
13 |
14 |
15 |
Items1:
16 | {{items1 | json}}
17 |
18 |
19 |
Items2:
20 | {{items2 | json}}
21 |
22 |
23 |
24 |
25 |
26 | // JS
27 | .controller('DifferentOptionsModel', ['$scope', '$element', 'dragularService', function TodoCtrl($scope, $element, dragularService) {
28 | $scope.items1 = [{
29 | content: 'Move me, but you can only drop me in one of these containers.'
30 | }, {
31 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.'
32 | }, {
33 | content: 'Item 3'
34 | }, {
35 | content: 'Item 4'
36 | }];
37 | $scope.items2 = [{
38 | content: 'Item 5'
39 | }, {
40 | content: 'Item 6'
41 | }, {
42 | content: 'Item 7'
43 | }, {
44 | content: 'Item 8'
45 | }];
46 |
47 | var containerLeft = document.querySelector('#containerLeft'),
48 | containerRight = document.querySelector('#containerRight');
49 |
50 | function accepts(el, target, source) {
51 | if (source === containerLeft || source === target) {
52 | return true;
53 | }
54 | }
55 |
56 | dragularService([containerLeft], {
57 | containersModel: [$scope.items1],
58 | copy: true,
59 | //move only from left to right
60 | accepts: accepts
61 | });
62 |
63 | dragularService([containerRight], {
64 | containersModel: [$scope.items2],
65 | removeOnSpill: true,
66 | //move only from left to right
67 | accepts: accepts
68 | });
69 |
70 | }])
71 |
72 |
73 | <!-- HTML -->
74 | <div class="wrapper" ng-controller="DifferentOptionsModel">
75 | <div class="table-row">
76 | <div id="containerLeft" class="container-vertical">
77 | <div ng-repeat="item in items1">{{item.content}}</div>
78 | </div>
79 | <div id="containerRight" class="container-vertical">
80 | <div ng-repeat="item in items2">{{item.content}}</div>
81 | </div>
82 | </div>
83 | <div class="table-row">
84 | <div class="container-vertical">
85 | <pre>Items1:
86 | <br/>{{items1 | json}}</pre>
87 | </div>
88 | <div class="container-vertical">
89 | <pre>Items2:
90 | <br/>{{items2 | json}}</pre>
91 | </div>
92 | </div>
93 | </div>
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleEvents/exampleEvents.html:
--------------------------------------------------------------------------------
1 |
2 |
Events
3 |
Add some fantastic events! Events affecting more than on cotrollers are emitted on both scopes if provided.
4 |
EventsCtrl
5 |
6 |
7 |
Move me, but you can only drop me in one of these containers.
8 |
If you try to drop me somewhere other than these containers, I'll just come back.
9 |
Item 3.
10 |
Item 6.
11 |
12 |
13 |
You can drop me in the left container, otherwise I'll stay here.
14 |
Item 4.
15 |
Item 5.
16 |
17 |
18 |
19 |
Events2Ctrl
20 |
21 |
22 |
Move me, but you can only drop me in one of these containers.
23 |
If you try to drop me somewhere other than these containers, I'll just come back.
24 |
Item 3.
25 |
Item 6.
26 |
27 |
28 |
You can drop me in the left container, otherwise I'll stay here.
29 |
Item 4.
30 |
Item 5.
31 |
32 |
33 |
34 |
35 | var EventsCtrl = function ($scope, $element, dragularService, $timeout) {
36 |
37 | var drake = dragularService($element.children(), {
38 | scope: $scope
39 | });
40 | $scope.$on('dragulardrag', function(e, el) {
41 | e.stopPropagation();
42 | el.className = el.className.replace(' ex-moved', '');
43 | });
44 | $scope.$on('dragulardrop', function(e, el) {
45 | e.stopPropagation();
46 | $timeout(function() {
47 | el.className += ' ex-moved';
48 | }, 0);
49 | });
50 |
51 | $scope.$on('dragularcloned', myFn('cloned in EventsCtrl'));
52 | $scope.$on('dragulardrag', myFn('drag in EventsCtrl'));
53 | $scope.$on('dragularcancel', myFn('cancel in EventsCtrl'));
54 | $scope.$on('dragulardrop', myFn('drop in EventsCtrl'));
55 | $scope.$on('dragularremove', myFn('remove in EventsCtrl'));
56 | $scope.$on('dragulardragend', myFn('dragend in EventsCtrl'));
57 | $scope.$on('dragularshadow', myFn('shadow in EventsCtrl'));
58 |
59 | function myFn(eventName) {
60 | return function() {
61 | console.log(eventName, arguments, drake);
62 | };
63 | }
64 | };
65 |
66 | var Events2Ctrl = function ($scope, $element, dragularService, $timeout) {
67 | var drake = dragularService($element.children(), {
68 | scope: $scope
69 | });
70 | $scope.$on('dragulardrag', function(e, el) {
71 | e.stopPropagation();
72 | el.className = el.className.replace(' ex-moved', '');
73 | });
74 | $scope.$on('dragulardrop', function(e, el) {
75 | e.stopPropagation();
76 | $timeout(function() {
77 | el.className += ' ex-moved';
78 | }, 0);
79 | });
80 |
81 | $scope.$on('dragularcloned', myFn('cloned in Events2Ctrl'));
82 | $scope.$on('dragulardrag', myFn('drag in Events2Ctrl'));
83 | $scope.$on('dragularcancel', myFn('cancel in Events2Ctrl'));
84 | $scope.$on('dragulardrop', myFn('drop in Events2Ctrl'));
85 | $scope.$on('dragularremove', myFn('remove in Events2Ctrl'));
86 | $scope.$on('dragulardragend', myFn('dragend in Events2Ctrl'));
87 | $scope.$on('dragularshadow', myFn('shadow in Events2Ctrl'));
88 |
89 | function myFn(eventName) {
90 | return function() {
91 | console.log(eventName, arguments, drake);
92 | };
93 | }
94 | };
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleNestedRepeatsWithCustomDirective/exampleNestedRepeatsWithCustomDirective.js:
--------------------------------------------------------------------------------
1 | /* global angular */
2 | 'use strict';
3 |
4 | NestedRepeatsWithCustomDirective.$inject = ['dragularService', '$element', '$scope', '$timeout'];
5 |
6 | angular.module('examplesApp')
7 | .directive('questionDirective', QuestionsDirective)
8 | .controller('QuestionsController', QuestionsController);
9 |
10 | module.exports = NestedRepeatsWithCustomDirective;
11 |
12 |
13 |
14 | function NestedRepeatsWithCustomDirective( dragularService, $element, $scope, $timeout) {
15 |
16 | dragularService.cleanEnviroment();
17 |
18 | $scope.items = [
19 | {
20 | questions:[
21 | {
22 | text: 'text1',
23 | points: 1
24 | },
25 | {
26 | text: 'text2',
27 | points: 2
28 | },
29 | {
30 | text: 'text3',
31 | points: 3
32 | }
33 | ],
34 | order: 1,
35 | name: 'x',
36 | age: '1'
37 | },
38 | {
39 | questions:[
40 | {
41 | text: 'text1',
42 | points: 1
43 | },
44 | {
45 | text: 'text2',
46 | points: 2
47 | },
48 | {
49 | text: 'text3',
50 | points: 3
51 | }
52 | ],
53 | order: 2,
54 | name: 'y',
55 | age: '2'
56 | }, {
57 | questions:[
58 | {
59 | text: 'text1',
60 | points: 1
61 | },
62 | {
63 | text: 'text2',
64 | points: 2
65 | },
66 | {
67 | text: 'text3',
68 | points: 3
69 | }
70 | ],
71 | order: 3,
72 | name: 'z',
73 | age: '3'
74 | },
75 | {
76 | questions:[
77 | {
78 | text: 'text1',
79 | points: 1
80 | },
81 | {
82 | text: 'text2',
83 | points: 2
84 | },
85 | {
86 | text: 'text3',
87 | points: 3
88 | }
89 | ],
90 | order: 1,
91 | name: 'x',
92 | age: '4'
93 | }, {
94 | questions:[
95 | {
96 | text: 'text1',
97 | points: 1
98 | },
99 | {
100 | text: 'text2',
101 | points: 2
102 | },
103 | {
104 | text: 'text3',
105 | points: 3
106 | }
107 | ],
108 | order: 2,
109 | name: 'y',
110 | age: '5'
111 | }, {
112 | questions:[
113 | {
114 | text: 'text1',
115 | points: 1
116 | },
117 | {
118 | text: 'text2',
119 | points: 2
120 | },
121 | {
122 | text: 'text3',
123 | points: 3
124 | }
125 | ],
126 | order: 3,
127 | name: 'z',
128 | age: '6'
129 | }];
130 |
131 | // timeout due to document not ready, jsfiddle settings issue?
132 | $timeout(function() {
133 |
134 | dragularService('#items', {
135 | containersModel: 'items',
136 | scope: $scope,
137 | moves: function itemsOnly (el, container, handle) {
138 | return handle.classList.contains('item');
139 | },
140 | nameSpace:'items'
141 | });
142 |
143 | $scope.$on('dragulardrop', function(){
144 | $scope.items.forEach(function(item, index){
145 | item.order = index + 1;
146 | });
147 | });
148 |
149 | });
150 |
151 | }
152 |
153 | function QuestionsDirective() {
154 | return {
155 | restrict : 'E',
156 | template : '{{subitem.points}}. {{subitem.text}}
',
157 | controller : 'QuestionsController',
158 | scope : {
159 | question: '='
160 | }
161 | };
162 | }
163 |
164 | function QuestionsController($scope, dragularService, $element) {
165 |
166 | dragularService( $element.children('.all-data'), {
167 | containersModel: 'question',
168 | scope: $scope,
169 | nameSpace: 'subitem',
170 | moves: function subItemsOnly (el, container, handle) {
171 | return handle.classList.contains('subitem');
172 | }
173 | });
174 |
175 | $scope.$on('dragulardrop', function(){
176 | $scope.question.forEach(function(item, index){
177 | item.points = index + 1;
178 | });
179 | });
180 | }
181 |
182 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | dragular-api
18 |
19 |
23 |
24 |
25 |
26 |
27 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
78 |
79 |
--------------------------------------------------------------------------------
/docs/src/examples/examplesApp.css:
--------------------------------------------------------------------------------
1 | .gh-fork {
2 | position: fixed;
3 | top: 0;
4 | right: 0;
5 | border: 0;
6 | z-index: 10000;
7 | }
8 |
9 |
10 | /* dragular-specific example page styles */
11 |
12 | .wrapper {
13 | display: table;
14 | table-layout: fixed;
15 | width: 100%;
16 | }
17 |
18 | .container-vertical {
19 | display: table-cell;
20 | background-color: rgba(255, 255, 255, 0.2);
21 | width: 50%;
22 | }
23 |
24 | .container-horizontal {
25 | display: table-row;
26 | background-color: rgba(255, 255, 255, 0.2);
27 | }
28 |
29 | .container-horizontal div {
30 | border-spacing: 5px;
31 | display: table-cell;
32 | margin: 10px;
33 | padding: 10px;
34 | background-color: rgba(0, 0, 0, 0.2);
35 | transition: opacity 0.4s ease-in-out;
36 | cursor: move;
37 | cursor: grab;
38 | cursor: -moz-grab;
39 | cursor: -webkit-grab;
40 | }
41 |
42 | .width25 {
43 | width: 25%;
44 | }
45 |
46 | .container-vertical:nth-child(odd) {
47 | background-color: rgba(0, 0, 0, 0.2);
48 | }
49 |
50 | .container-vertical:nth-child(even) {
51 | background-color: rgba(0, 0, 0, 0.4);
52 | }
53 |
54 | .container-vertical pre {
55 | border: 0;
56 | background-color: transparent;
57 | }
58 |
59 | label b{
60 | color: darkorange;
61 | }
62 |
63 | /*
64 | * note that styling gu-mirror directly is a bad practice because it's too generic.
65 | * you're better off giving the draggable elements a unique class and styling that directly!
66 | */
67 |
68 | .container-vertical div,
69 | .gu-mirror {
70 | margin: 10px;
71 | padding: 10px;
72 | background-color: rgba(0, 0, 0, 0.2);
73 | transition: opacity 0.4s ease-in-out;
74 | cursor: move;
75 | cursor: grab;
76 | cursor: -moz-grab;
77 | cursor: -webkit-grab;
78 | }
79 |
80 | .gu-unselectable {
81 | cursor: grabbing;
82 | cursor: -moz-grabbing;
83 | cursor: -webkit-grabbing;
84 | }
85 |
86 | .container-vertical .ex-moved {
87 | background-color: #e74c3c;
88 | }
89 |
90 | .handle {
91 | padding: 0 5px;
92 | margin-right: 5px;
93 | background-color: rgba(0, 0, 0, 0.4);
94 | cursor: move;
95 | }
96 |
97 | .custom-green-mirror {
98 | background-color: #56AB1C;
99 | margin: 10px;
100 | padding: 10px;
101 | cursor: move;
102 | cursor: grab;
103 | cursor: -moz-grab;
104 | cursor: -webkit-grab;
105 | opacity: 0.8;
106 | position: fixed !important;
107 | margin: 0 !important;
108 | z-index: 9999 !important;
109 | }
110 |
111 | .container-vertical.width25.gu-over-active.gu-over-accept {
112 | background-color: green !important;
113 | }
114 |
115 | .container-vertical.width25.gu-over-active.gu-over-decline {
116 | background-color: red !important;
117 | }
118 |
119 | pre.gu-over-active.gu-over-decline {
120 | background-color: yellow !important;
121 | }
122 |
123 | div.limit-box {
124 | margin: 0;
125 | padding: 0;
126 | background: transparent;
127 | }
128 |
129 | .cursor-default {
130 | cursor: default !important;
131 | }
132 |
133 | .example-row {
134 | display: flex;
135 | flex-direction: row;
136 | }
137 |
138 | .example-cell {
139 | flex-grow: 1;
140 | }
141 |
142 | .example-row,
143 | .example-cell {
144 | margin: 10px;
145 | padding: 10px;
146 | background-color: rgba(0, 0, 0, 0.2);
147 | cursor: move;
148 | cursor: grab;
149 | cursor: -moz-grab;
150 | cursor: -webkit-grab;
151 | }
152 |
153 | .table-row {
154 | display: table-row;
155 | }
156 |
157 |
158 | /* OFF CANVAS TEMPLATE CSS */
159 |
160 |
161 | /*
162 | * Style tweaks
163 | * --------------------------------------------------
164 | */
165 |
166 | html,
167 | body {
168 | overflow-x: hidden;
169 | /* Prevent scroll on narrow devices */
170 | }
171 |
172 | body {
173 | padding-top: 70px;
174 | }
175 |
176 | footer {
177 | padding: 30px 0;
178 | text-align: center;
179 | }
180 |
181 | .jumbotron {
182 | text-align: center;
183 | }
184 |
185 |
186 | /*
187 | * Off Canvas
188 | * --------------------------------------------------
189 | */
190 |
191 | @media screen and (max-width: 767px) {
192 | .gh-fork {
193 | top: 50px !important;
194 | z-index: auto;
195 | }
196 | .row-offcanvas {
197 | position: relative;
198 | -webkit-transition: all .25s ease-out;
199 | -o-transition: all .25s ease-out;
200 | transition: all .25s ease-out;
201 | }
202 | .row-offcanvas-right {
203 | right: 0;
204 | }
205 | .row-offcanvas-left {
206 | left: 0;
207 | }
208 | .row-offcanvas-right .sidebar-offcanvas {
209 | right: -50%;
210 | /* 6 columns */
211 | }
212 | .row-offcanvas-left .sidebar-offcanvas {
213 | left: -50%;
214 | /* 6 columns */
215 | }
216 | .row-offcanvas-right.active {
217 | right: 50%;
218 | /* 6 columns */
219 | }
220 | .row-offcanvas-left.active {
221 | left: 50%;
222 | /* 6 columns */
223 | }
224 | .sidebar-offcanvas {
225 | position: absolute !important;
226 | top: 0;
227 | width: 50%;
228 | /* 6 columns */
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleScrollingDrag/exampleScrollingDrag.html:
--------------------------------------------------------------------------------
1 |
2 |
Scrolling drag
3 |
Containers can be scrolled by hovering up/down bar near containers. Bars on right side are transparent and moved a bit over containers. It can be scrolled also by mouse wheel.
4 |
5 |
43 |
44 |
45 | // JS
46 | controller('ScrollingDrag', ['$interval', '$element', 'dragularService', function TodoCtrl($interval, $element, dragularService) {
47 |
48 |
49 | var timer,
50 | leftScrollContainer = document.getElementById('leftScroll'),
51 | rightScrollContainer = document.getElementById('rightScroll'),
52 | leftTopBar = document.getElementById('leftTopBar'),
53 | leftBottomBar = document.getElementById('leftBottomBar'),
54 | rightTopBar = document.getElementById('rightTopBar'),
55 | rightBottomBar = document.getElementById('rightBottomBar');
56 |
57 | dragularService.cleanEnviroment();
58 | dragularService([leftScrollContainer, rightScrollContainer]);
59 |
60 | registerEvents(leftTopBar, leftScrollContainer, -5);
61 | registerEvents(leftBottomBar, leftScrollContainer, 5);
62 | registerEvents(rightTopBar, rightScrollContainer, -5);
63 | registerEvents(rightBottomBar, rightScrollContainer, 5);
64 |
65 | function registerEvents(bar, container, inc, speed) {
66 | if (!speed) {
67 | speed = 20;
68 | }
69 | angular.element(bar).on('dragularenter', function() {
70 | container.scrollTop += inc;
71 | timer = $interval(function moveScroll() {
72 | container.scrollTop += inc;
73 | }, speed);
74 | });
75 | angular.element(bar).on('dragularleave dragularrelease', function() {
76 | $interval.cancel(timer);
77 | });
78 | }
79 | }])
80 |
81 |
82 |
83 |
84 | <!-- HTML -->
85 | <div ng-controller="ScrollingDrag">
86 | <div class="container-vertical scrollingDrag">
87 | <div class="scrollBar" id="leftTopBar">up</div>
88 | <div id="leftScroll" class="scrollingDragInner">
89 | <div>Item 1</div>
90 | <div>Item 2</div>
91 | ...
92 | </div>
93 | <div class="scrollBar" id="leftBottomBar">down</div>
94 | </div>
95 | <div class="container-vertical scrollingDrag">
96 | <div class="scrollBar" id="rightTopBar">up</div>
97 | <div id="rightScroll" class="scrollingDragInner">
98 | <div>Item 1</div>
99 | <div>Item 2</div>
100 | ...
101 | </div>
102 | <div class="scrollBar" id="rightBottomBar">down</div>
103 | </div>
104 | </div>
105 |
106 |
107 |
108 |
109 | // CSS
110 | .scrollingDrag {
111 | width: 45%;
112 | display: inline-block;
113 | }
114 |
115 | .scrollingDragInner {
116 | max-height: 200px;
117 | overflow-y: auto;
118 | }
119 |
120 | #rightTopBar,
121 | #rightBottomBar {
122 | background: transparent;
123 | position: relative;
124 | height: 20px;
125 | }
126 |
127 | #rightTopBar {
128 | top: 10px;
129 | }
130 |
131 | #rightBottomBar {
132 | bottom: 10px;
133 | }
134 |
135 | div.scrollBar {
136 | background: yellow;
137 | text-align: center;
138 | padding: 1px;
139 | }
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | It's important to us that you feel you can contribute towards the evolution of Dragular. This can take many forms: from helping to fix bugs or improve the docs, to adding in new features to the source. This guide should help you in making that process as smooth as possible.
4 |
5 | Before contributing, please read the [code of conduct](https://github.com/luckylooke/dragular/blob/master/CODE_OF_CONDUCT.md).
6 |
7 | ## Reporting issues
8 |
9 | [GitHub Issues][0] is the place to report bugs you may have found in either the core library or any of the examples that are part of the repository. When submitting a bug please do the following:
10 |
11 | **1. Search for existing issues.** Your bug may have already been fixed or addressed in a development branch version of Dragular, so be sure to search the issues first before putting in a duplicate issue.
12 |
13 | **2. Not sure if it's a bug?.** Then please ask via issues and tag it [question].
14 |
15 | **3. Create an isolated and reproducible test case.** If you are reporting a bug, make sure you also have a minimal, runnable, code example that reproduces the problem you have.
16 |
17 | **4. Include a live example.** After narrowing your code down to only the problem areas, make use of [Codepen][1], [jsBin][2], or a link to your live site so that we can view a live example of the problem. (you can start by forking [this codepen](https://codepen.io/luckylooke/pen/pPmeWY))
18 |
19 | **5. Share as much information as possible.** Include browser version affected, your OS, version of the library, steps to reproduce, etc. "X isn't working!!!1!" will probably just be closed.
20 |
21 | ## Dev vs. Master
22 |
23 | The dev branch of Dragular is our 'current working' version. It is always ahead of the master branch in terms of features and fixes. However it's also bleeding-edge and experimental and we cannot and do not guarantee it will compile or work for you. Very often we have to break things for a few days while we rebuild and patch. So by all means please export the dev branch and contribute towards it, indeed that is where all Pull Requests should be sent, but do so understanding the API may change beneath you.
24 |
25 |
26 | ## Making Changes
27 |
28 | To take advantage of our npm build script and jshint config it will be easiest for you if you have node.js installed locally.
29 |
30 | You can download node.js from [nodejs.org][3].
31 |
32 | After that you can clone the repository and run `npm i` inside the cloned folder. This will install dependencies necessary for building the project. For development workflow automation dragular uses `gulp >= 3.9.0`. Before starting development, make sure that `gulp` is installed on your machine globally: `npm i -g gulp`.
33 |
34 | ### Developing
35 |
36 | There are several gulp tasks that are used for generating different builds:
37 |
38 | - `gulp dev` - Serves files with BrowserSync server, watches & automatically refreshes connected browsers on changes, generates non-minified but concatenated styles & scripts from the dragular source.
39 | - `gulp dev:docs` - Does exactly the same as `gulp dev`, except it works with the documentation source.
40 | - `gulp build` - Concatenates and minifies dragular source files.
41 | - `gulp build:docs` - Concatenates and minifies documentation source files.
42 |
43 | ### Linting
44 |
45 | - `gulp lint` & `gulp lint:docs` - Lint JavaScript files.
46 |
47 | ### Making a pull request
48 |
49 | Once that is ready, make your changes and submit a Pull Request:
50 |
51 | - **Send Pull Requests to the `dev` branch.** All Pull Requests must be sent to the `dev` branch, `master` is the latest release and PRs to that branch will be closed.
52 |
53 | - **Ensure changes are jshint validated.** Our JSHint configuration file is provided in the repository and you should check against it before submitting.
54 |
55 | - **Only commit relevant changes.** Don't include changes that are not directly relevant to the fix you are making. The more focused a PR is, the faster it will get attention and be merged. Extra files changing only whitespace or trash files will likely get your PR closed.
56 |
57 |
58 | Dependencies for building from source and running tests:
59 |
60 |
61 | ## Coding style preferences are not contributions
62 |
63 | If your PR is doing little more than changing the Dragular source code into a format / coding style that you prefer then we will automatically close it. All PRs must adhere to the coding style already set-out across the lines of code in Dragular. Your personal preferences for how things should "look" or be structured do not apply here, sorry. PRs should fix bugs, fix documentation or add features. No changes for the sake of change.
64 |
65 |
66 | ## I don't really like git / node.js, but I can fix this bug
67 |
68 | That is fine too. While Pull Requests are the best thing in the world for us, they are not the only way to help. You're welcome to post fixes to our forum or even just email them to us. All we ask is that you still adhere to the guidelines presented here re: JSHint, etc.
69 |
70 |
71 | [0]: https://github.com/luckylooke/dragular/issues
72 | [1]: http://codepen.io
73 | [2]: http://jsbin.com/
74 | [3]: http://nodejs.org
75 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | ecmaFeatures: {}
2 | rules:
3 | no-alert: 0
4 | no-array-constructor: 0
5 | no-bitwise: 0
6 | no-caller: 0
7 | no-catch-shadow: 0
8 | no-class-assign: 0
9 | no-cond-assign: 2
10 | no-console: 2
11 | no-const-assign: 0
12 | no-constant-condition: 2
13 | no-continue: 0
14 | no-control-regex: 2
15 | no-debugger: 2
16 | no-delete-var: 2
17 | no-div-regex: 0
18 | no-dupe-keys: 2
19 | no-dupe-args: 2
20 | no-duplicate-case: 2
21 | no-else-return: 0
22 | no-empty: 2
23 | no-empty-character-class: 2
24 | no-empty-label: 0
25 | no-eq-null: 0
26 | no-eval: 0
27 | no-ex-assign: 2
28 | no-extend-native: 0
29 | no-extra-bind: 0
30 | no-extra-boolean-cast: 2
31 | no-extra-parens: 0
32 | no-extra-semi: 2
33 | no-fallthrough: 2
34 | no-floating-decimal: 0
35 | no-func-assign: 2
36 | no-implicit-coercion: 0
37 | no-implied-eval: 0
38 | no-inline-comments: 0
39 | no-inner-declarations:
40 | - 2
41 | - functions
42 | no-invalid-regexp: 2
43 | no-invalid-this: 0
44 | no-irregular-whitespace: 2
45 | no-iterator: 0
46 | no-label-var: 0
47 | no-labels: 0
48 | no-lone-blocks: 0
49 | no-lonely-if: 0
50 | no-loop-func: 0
51 | no-mixed-requires:
52 | - 0
53 | - false
54 | no-mixed-spaces-and-tabs:
55 | - 2
56 | - false
57 | linebreak-style:
58 | - 0
59 | - unix
60 | no-multi-spaces: 0
61 | no-multi-str: 0
62 | no-multiple-empty-lines:
63 | - 0
64 | - max: 2
65 | no-native-reassign: 0
66 | no-negated-in-lhs: 2
67 | no-nested-ternary: 0
68 | no-new: 0
69 | no-new-func: 0
70 | no-new-object: 0
71 | no-new-require: 0
72 | no-new-wrappers: 0
73 | no-obj-calls: 2
74 | no-octal: 2
75 | no-octal-escape: 0
76 | no-param-reassign: 0
77 | no-path-concat: 0
78 | no-plusplus: 0
79 | no-process-env: 0
80 | no-process-exit: 0
81 | no-proto: 0
82 | no-redeclare: 2
83 | no-regex-spaces: 2
84 | no-reserved-keys: 0
85 | no-restricted-modules: 0
86 | no-return-assign: 0
87 | no-script-url: 0
88 | no-self-compare: 0
89 | no-sequences: 0
90 | no-shadow: 0
91 | no-shadow-restricted-names: 0
92 | no-spaced-func: 0
93 | no-sparse-arrays: 2
94 | no-sync: 0
95 | no-ternary: 0
96 | no-trailing-spaces: 0
97 | no-this-before-super: 0
98 | no-throw-literal: 0
99 | no-undef: 2
100 | no-undef-init: 0
101 | no-undefined: 0
102 | no-unexpected-multiline: 0
103 | no-underscore-dangle: 0
104 | no-unneeded-ternary: 0
105 | no-unreachable: 2
106 | no-unused-expressions: 0
107 | no-unused-vars:
108 | - 2
109 | - vars: all
110 | args: after-used
111 | no-use-before-define: 0
112 | no-useless-call: 0
113 | no-void: 0
114 | no-var: 0
115 | no-warning-comments:
116 | - 0
117 | - terms:
118 | - todo
119 | - fixme
120 | - xxx
121 | location: start
122 | no-with: 0
123 | array-bracket-spacing:
124 | - 0
125 | - never
126 | arrow-parens: 0
127 | arrow-spacing: 0
128 | accessor-pairs: 0
129 | block-scoped-var: 0
130 | brace-style:
131 | - 0
132 | - 1tbs
133 | callback-return: 0
134 | camelcase: 0
135 | comma-dangle:
136 | - 2
137 | - never
138 | comma-spacing: 0
139 | comma-style: 0
140 | complexity:
141 | - 2
142 | - 11
143 | computed-property-spacing:
144 | - 0
145 | - never
146 | consistent-return: 0
147 | consistent-this:
148 | - 0
149 | - that
150 | constructor-super: 0
151 | curly:
152 | - 0
153 | - all
154 | default-case: 0
155 | dot-location: 0
156 | dot-notation:
157 | - 0
158 | - allowKeywords: true
159 | eol-last: 0
160 | eqeqeq: 0
161 | func-names: 0
162 | func-style:
163 | - 0
164 | - declaration
165 | generator-star-spacing: 0
166 | guard-for-in: 0
167 | handle-callback-err: 0
168 | indent: 0
169 | init-declarations: 0
170 | key-spacing:
171 | - 0
172 | - beforeColon: false
173 | afterColon: true
174 | lines-around-comment: 0
175 | max-depth:
176 | - 0
177 | - 4
178 | max-len:
179 | - 0
180 | - 80
181 | - 4
182 | max-nested-callbacks:
183 | - 0
184 | - 2
185 | max-params:
186 | - 0
187 | - 3
188 | max-statements:
189 | - 0
190 | - 10
191 | new-cap: 0
192 | new-parens: 0
193 | newline-after-var: 0
194 | object-curly-spacing:
195 | - 0
196 | - never
197 | object-shorthand: 0
198 | one-var: 0
199 | operator-assignment:
200 | - 0
201 | - always
202 | operator-linebreak: 0
203 | padded-blocks: 0
204 | prefer-const: 0
205 | prefer-spread: 0
206 | prefer-reflect: 0
207 | quote-props: 0
208 | quotes:
209 | - 0
210 | - double
211 | radix: 0
212 | require-yield: 0
213 | semi: 0
214 | semi-spacing:
215 | - 0
216 | - before: false
217 | after: true
218 | sort-vars: 0
219 | space-after-keywords:
220 | - 0
221 | - always
222 | space-before-blocks:
223 | - 0
224 | - always
225 | space-before-function-paren:
226 | - 0
227 | - always
228 | space-in-parens:
229 | - 0
230 | - never
231 | space-infix-ops: 0
232 | space-return-throw-case: 0
233 | space-unary-ops:
234 | - 0
235 | - words: true
236 | nonwords: false
237 | spaced-comment: 0
238 | strict: 0
239 | use-isnan: 2
240 | valid-jsdoc: 0
241 | valid-typeof: 2
242 | vars-on-top: 0
243 | wrap-iife: 0
244 | wrap-regex: 0
245 | yoda:
246 | - 0
247 | - never
248 | env:
249 | browser: true
250 | node: true
251 | jquery: true
252 | amd: true
253 | commonjs: true
254 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleDragOverEvents/exampleDragOverEvents.html:
--------------------------------------------------------------------------------
1 |
2 |
Drag-over events
3 |
You can interact with dragging element by litening to dragOver events. Usually you want to containers show wheather they accepts element or not, but you can use it anywhere. DragOver events are: dragenter, dragleave and dragrelease. On dragOver events dragularService reveals several useful properties.
4 |
5 |
6 |
7 |
8 | dragularService.shared.item
9 | item beeing dragged (it is copy of item if copy is enabled via options)
10 |
11 |
12 | dragularService.shared.source
13 | source container item is dragged from
14 |
15 |
16 | dragularService.shared.sourceModel
17 | source container model representation if model was porvided
18 |
19 |
20 | dragularService.shared.initialIndex
21 | original index of item, can be used to get item model from sourceModel
22 |
23 |
24 | dragularService.shared.extra
25 | contains accepting information (boolean) on dragenter, element drag is leaving to on dragleave and element behind the cursor on dragrelease
26 |
27 |
28 |
29 |
30 |
Try to drag over the not-container too.
31 |
32 |
33 |
apples and oranges cannot be mixed
34 |
apple 2
35 |
apple 3
36 |
apple 4
37 |
38 |
39 |
orange 1
40 |
orange 2
41 |
orange 3
42 |
orange 4
43 |
44 |
45 |
apple 5
46 |
apple 6
47 |
apple 7
48 |
apple 8
49 |
50 |
51 |
orange 5
52 |
orange 6
53 |
orange 7
54 |
orange 8
55 |
56 |
57 |
Test active class on NOT container.
58 |
59 |
60 |
61 | <!-- HTML -->
62 | <div class="wrapper" ng-controller="DragOverEvents">
63 | <div class="container width25">
64 | <div>apples and oranges cannot be mixed</div>
65 | <div>apple 2</div>
66 | ...
67 | </div>
68 | <div class="container width25">
69 | <div>orange 1</div>
70 | <div>orange 2</div>
71 | ...
72 | </div>
73 | <div class="container width25">
74 | <div>apple 5</div>
75 | <div>apple 6</div>
76 | ...
77 | </div>
78 | <div class="container width25">
79 | <div>orange 5</div>
80 | <div>orange 6</div>
81 | ...
82 | </div>
83 | </div>
84 | <div class="notContainer"> Test active class on NOT container.</div>
85 |
86 |
87 |
88 |
89 |
90 | // CSS
91 |
92 | .notContainer.gu-over {
93 | background-color: yellow;
94 | }
95 |
96 | .container-vertical.gu-over-accept {
97 | background-color: green;
98 | }
99 |
100 | .container-vertical.gu-over-decline {
101 | background-color: red;
102 | }
103 |
104 |
105 |
106 |
107 |
108 | // JS
109 | controller('DragOverEvents', ['$element', 'dragularService', function TodoCtrl($element, dragularService) {
110 | dragularService.cleanEnviroment();
111 | dragularService([$element.children()[0], $element.children()[2]], {
112 | nameSpace: 'apples'
113 | });
114 | dragularService([$element.children()[1], $element.children()[3]], {
115 | nameSpace: 'oranges'
116 | });
117 |
118 | // containers events handling
119 | function registerEvents(el) {
120 | el.on('dragularenter', function(e) {
121 | if (el[0] === e.target) { // filter bubbled
122 | el.addClass(dragularService.shared.extra ? 'gu-over-accept' : 'gu-over-decline');
123 | }
124 | });
125 | el.on('dragularleave dragularrelease', function(e) {
126 | if ((el[0] === e.target && // filter bubbled
127 | dragularService.shared.extra && // extra on dragleave contains element the drag is leaving to
128 | dragularService.shared.extra.parentElement !== e.target) // is that element child of this container?
129 | || e.type === 'dragularrelease') {
130 | el.removeClass('gu-over-accept');
131 | el.removeClass('gu-over-decline');
132 | }
133 | });
134 | }
135 |
136 | angular.forEach($element.children(), function forEachChild(el) {
137 | registerEvents(angular.element(el));
138 | });
139 |
140 | // notContainer events handling
141 | var notContainer = angular.element(document.getElementsByClassName('notContainer'));
142 | notContainer.on('dragularenter', function() {
143 | notContainer.addClass('gu-over');
144 | });
145 | notContainer.on('dragularleave dragularrelease', function() {
146 | notContainer.removeClass('gu-over');
147 | });
148 | }])
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/docs/src/examples/exampleNgRepeatFilteredWithModel/exampleNgRepeatFilteredWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
Filtered ngRepeat - with model
3 |
Move stuff between these two filtered containers. You can play with filter inputs to see that everything goes right.
4 |
5 | Please notify the getFilteredModel function, it is necessery for not replacing the initial array object with new filtered one!
6 |
7 |
15 |
16 |
17 |
{{item.content}}
18 |
19 |
20 |
{{item.content}}
21 |
22 |
23 |
24 |
25 |
Items1:
26 | {{items1 | json}}
27 |
28 |
29 |
Items2:
30 | {{items2 | json}}
31 |
32 |
33 |
34 |
35 |
36 | // JS
37 | .controller('NgRepeatFilteredWithModel', ['$scope', '$element', 'dragularService', '$filter', function TodoCtrl($scope, $element, dragularService, $filter) {
38 | $scope.items1 = [{
39 | content: 'Move me, but you can only drop me in one of these containers.'
40 | }, {
41 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.'
42 | }, {
43 | content: 'Apple 3'
44 | }, {
45 | content: 'Orange 4'
46 | }, {
47 | content: 'Orange 5'
48 | }, {
49 | content: 'Apple 6'
50 | }, {
51 | content: 'Apple 7'
52 | }, {
53 | content: 'Apple 8'
54 | }];
55 | $scope.items2 = [{
56 | content: 'Apple 9'
57 | }, {
58 | content: 'Orange 10'
59 | }, {
60 | content: 'Orange 11'
61 | }, {
62 | content: 'Apple 12'
63 | }, {
64 | content: 'Orange 13'
65 | }, {
66 | content: 'Apple 14'
67 | }];
68 | $scope.filter1query = 'Orange';
69 | $scope.filter2query = 'Orange';
70 | $scope.filteredModel1 = [];
71 | $scope.filteredModel2 = [];
72 | $scope.getFilteredModel = function (filteredModel, items, filterQuery) {
73 | filteredModel.length = 0;
74 | /*
75 | * Following one-liner is same like:
76 | * var filteredModelTemp = $filter('filter')(items, filterQuery);
77 | * angular.forEach(filteredModelTemp, function(item){
78 | * filteredModel.push(item);
79 | * });
80 | * Or like:
81 | * var filteredModelTemp = $filter('filter')(items, filterQuery);
82 | * for(var i; i < filteredModelTemp.length; i++){
83 | * filteredModel.push(filteredModelTemp[i]);
84 | * }
85 | *
86 | * You cannot just assign filtered array to filteredModel like this:
87 | * filteredModel = $filter('filter')(items, filterQuery);
88 | * Because you would replace the array object you provide to dragular with new one.
89 | * So dragular will continue to use the one it was provided on init.
90 | * Hopefully I make it clear. :)
91 | */
92 | [].push.apply(filteredModel, $filter('filter')(items, filterQuery));
93 | return filteredModel;
94 | };
95 | var containers = $element.children().eq(1).children();
96 | dragularService.cleanEnviroment();
97 | dragularService([containers[0],containers[1]],{
98 | containersModel: [$scope.items1, $scope.items2],
99 | containersFilteredModel: [$scope.filteredModel1, $scope.filteredModel2]
100 | });
101 | }]);
102 |
103 |
104 |
105 | <!-- HTML -->
106 | <div class="wrapper" ng-controller="NgRepeatFilteredWithModel">
107 | <div class="table-row">
108 | <div class="container-vertical">
109 | <input ng-model="filter1query" style="margin:10px 10px">
110 | </div>
111 | <div class="container-vertical">
112 | <input ng-model="filter2query" style="margin:10px 10px">
113 | </div>
114 | </div>
115 | <div class="table-row">
116 | <div class="container-vertical">
117 | <div ng-repeat="item in getFilteredModel(filteredModel1, items1, filter1query)">{{item.content}}</div>
118 | </div>
119 | <div class="container-vertical">
120 | <div ng-repeat="item in getFilteredModel(filteredModel2, items2, filter2query)">{{item.content}}</div>
121 | </div>
122 | </div>
123 | <div class="table-row">
124 | <div class="container-vertical">
125 | <pre>Items1:
126 | <br/>{{items1 | json}}</pre>
127 | </div>
128 | <div class="container-vertical">
129 | <pre>Items2:
130 | <br/>{{items2 | json}}</pre>
131 | </div>
132 | </div>
133 | </div>
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/docs/src/examples/partials/autogenerated/contribute.html:
--------------------------------------------------------------------------------
1 | How to contribute
2 | It's important to us that you feel you can contribute towards the evolution of Dragular. This can take many forms: from helping to fix bugs or improve the docs, to adding in new features to the source. This guide should help you in making that process as smooth as possible.
3 | Before contributing, please read the code of conduct .
4 | Reporting issues
5 | GitHub Issues is the place to report bugs you may have found in either the core library or any of the examples that are part of the repository. When submitting a bug please do the following:
6 | 1. Search for existing issues. Your bug may have already been fixed or addressed in a development branch version of Dragular, so be sure to search the issues first before putting in a duplicate issue.
7 | 2. Not sure if it's a bug?. Then please ask via issues and tag it [question].
8 | 3. Create an isolated and reproducible test case. If you are reporting a bug, make sure you also have a minimal, runnable, code example that reproduces the problem you have.
9 | 4. Include a live example. After narrowing your code down to only the problem areas, make use of Codepen , jsBin , or a link to your live site so that we can view a live example of the problem. (you can start by forking this codepen )
10 | 5. Share as much information as possible. Include browser version affected, your OS, version of the library, steps to reproduce, etc. "X isn't working!!!1!" will probably just be closed.
11 | Dev vs. Master
12 | The dev branch of Dragular is our 'current working' version. It is always ahead of the master branch in terms of features and fixes. However it's also bleeding-edge and experimental and we cannot and do not guarantee it will compile or work for you. Very often we have to break things for a few days while we rebuild and patch. So by all means please export the dev branch and contribute towards it, indeed that is where all Pull Requests should be sent, but do so understanding the API may change beneath you.
13 | Making Changes
14 | To take advantage of our npm build script and jshint config it will be easiest for you if you have node.js installed locally.
15 | You can download node.js from nodejs.org .
16 | After that you can clone the repository and run npm i inside the cloned folder. This will install dependencies necessary for building the project. For development workflow automation dragular uses gulp >= 3.9.0. Before starting development, make sure that gulp is installed on your machine globally: npm i -g gulp.
17 | Developing
18 | There are several gulp tasks that are used for generating different builds:
19 |
20 | gulp dev - Serves files with BrowserSync server, watches & automatically refreshes connected browsers on changes, generates non-minified but concatenated styles & scripts from the dragular source.
21 | gulp dev:docs - Does exactly the same as gulp dev, except it works with the documentation source.
22 | gulp build - Concatenates and minifies dragular source files.
23 | gulp build:docs - Concatenates and minifies documentation source files.
24 |
25 | Linting
26 |
27 | gulp lint & gulp lint:docs - Lint JavaScript files.
28 |
29 | Making a pull request
30 | Once that is ready, make your changes and submit a Pull Request:
31 |
32 | Send Pull Requests to the dev branch. All Pull Requests must be sent to the dev branch, master is the latest release and PRs to that branch will be closed.
33 |
34 | Ensure changes are jshint validated. Our JSHint configuration file is provided in the repository and you should check against it before submitting.
35 |
36 | Only commit relevant changes. Don't include changes that are not directly relevant to the fix you are making. The more focused a PR is, the faster it will get attention and be merged. Extra files changing only whitespace or trash files will likely get your PR closed.
37 |
38 |
39 | Dependencies for building from source and running tests:
40 | Coding style preferences are not contributions
41 | If your PR is doing little more than changing the Dragular source code into a format / coding style that you prefer then we will automatically close it. All PRs must adhere to the coding style already set-out across the lines of code in Dragular. Your personal preferences for how things should "look" or be structured do not apply here, sorry. PRs should fix bugs, fix documentation or add features. No changes for the sake of change.
42 | I don't really like git / node.js, but I can fix this bug
43 | That is fine too. While Pull Requests are the best thing in the world for us, they are not the only way to help. You're welcome to post fixes to our forum or even just email them to us. All we ask is that you still adhere to the guidelines presented here re: JSHint, etc.
44 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // Available variables which can be used inside of strings.
2 | // ${workspaceRoot}: the root folder of the team
3 | // ${file}: the current opened file
4 | // ${fileBasename}: the current opened file's basename
5 | // ${fileDirname}: the current opened file's dirname
6 | // ${fileExtname}: the current opened file's extension
7 | // ${cwd}: the current working directory of the spawned process
8 |
9 | // A task runner that calls the Typescript compiler (tsc) and
10 | // // Compiles a HelloWorld.ts program
11 | // {
12 | // "version": "0.1.0",
13 |
14 | // // The command is tsc. Assumes that tsc has been installed using npm install -g typescript
15 | // "command": "npm",
16 |
17 | // // The command is a shell script
18 | // "isShellCommand": true,
19 |
20 | // // Show the output window only if unrecognized errors occur.
21 | // "showOutput": "always",
22 |
23 | // // args is the HelloWorld program to compile.
24 | // "args": ["run"],
25 |
26 | // "isWatching": false,
27 | // "tasks": [
28 | // // { "taskName": "start" },
29 | // { "taskName": "clean:start" },
30 | // { "taskName": "build" },
31 | // { "taskName": "build:dev" },
32 | // { "taskName": "build:prod" }
33 | // ]
34 | // }
35 |
36 | // A task runner that calls the Typescript compiler (tsc) and
37 | // compiles based on a tsconfig.json file that is present in
38 | // the root of the folder open in VSCode
39 | /*
40 | {
41 | "version": "0.1.0",
42 |
43 | // The command is tsc. Assumes that tsc has been installed using npm install -g typescript
44 | "command": "tsc",
45 |
46 | // The command is a shell script
47 | "isShellCommand": true,
48 |
49 | // Show the output window only if unrecognized errors occur.
50 | "showOutput": "silent",
51 |
52 | // Tell the tsc compiler to use the tsconfig.json from the open folder.
53 | "args": ["-p", "."],
54 |
55 | // use the standard tsc problem matcher to find compile problems
56 | // in the output.
57 | "problemMatcher": "$tsc"
58 | }
59 | */
60 |
61 | // A task runner configuration for gulp. Gulp provides a less task
62 | // which compiles less to css.
63 |
64 | {
65 | "version": "0.1.0",
66 | "command": "gulp",
67 | "isShellCommand": true,
68 | "tasks": [
69 | {
70 | "taskName": "build",
71 | // Make this the default build command.
72 | "isBuildCommand": true,
73 | // Show the output window only if unrecognized errors occur.
74 | "showOutput": "always",
75 | "problemMatcher": ["$tsc"]
76 | },
77 | {
78 | "taskName": "dev:docs",
79 | // Show the output window only if unrecognized errors occur.
80 | "showOutput": "always",
81 | "problemMatcher": ["$tsc"],
82 | "isWatching": true
83 | }
84 | ]
85 | }
86 |
87 |
88 | // Uncomment the following section to use jake to build a workspace
89 | // cloned from https://github.com/Microsoft/TypeScript.git
90 | /*
91 | {
92 | "version": "0.1.0",
93 | // Task runner is jake
94 | "command": "jake",
95 | // Need to be executed in shell / cmd
96 | "isShellCommand": true,
97 | "showOutput": "silent",
98 | "tasks": [
99 | {
100 | // TS build command is local.
101 | "taskName": "local",
102 | // Make this the default build command.
103 | "isBuildCommand": true,
104 | // Show the output window only if unrecognized errors occur.
105 | "showOutput": "silent",
106 | // Use the redefined Typescript output problem matcher.
107 | "problemMatcher": [
108 | "$tsc"
109 | ]
110 | }
111 | ]
112 | }
113 | */
114 |
115 | // Uncomment the section below to use msbuild and generate problems
116 | // for csc, cpp, tsc and vb. The configuration assumes that msbuild
117 | // is available on the path and a solution file exists in the
118 | // workspace folder root.
119 | /*
120 | {
121 | "version": "0.1.0",
122 | "command": "msbuild",
123 | "args": [
124 | // Ask msbuild to generate full paths for file names.
125 | "/property:GenerateFullPaths=true"
126 | ],
127 | "taskSelector": "/t:",
128 | "showOutput": "silent",
129 | "tasks": [
130 | {
131 | "taskName": "build",
132 | // Show the output window only if unrecognized errors occur.
133 | "showOutput": "silent",
134 | // Use the standard MS compiler pattern to detect errors, warnings
135 | // and infos in the output.
136 | "problemMatcher": "$msCompile"
137 | }
138 | ]
139 | }
140 | */
141 |
142 | // Uncomment the following section to use msbuild which compiles Typescript
143 | // and less files.
144 | /*
145 | {
146 | "version": "0.1.0",
147 | "command": "msbuild",
148 | "args": [
149 | // Ask msbuild to generate full paths for file names.
150 | "/property:GenerateFullPaths=true"
151 | ],
152 | "taskSelector": "/t:",
153 | "showOutput": "silent",
154 | "tasks": [
155 | {
156 | "taskName": "build",
157 | // Show the output window only if unrecognized errors occur.
158 | "showOutput": "silent",
159 | // Use the standard MS compiler pattern to detect errors, warnings
160 | // and infos in the output.
161 | "problemMatcher": [
162 | "$msCompile",
163 | "$lessCompile"
164 | ]
165 | }
166 | ]
167 | }
168 | */
169 | // A task runner example that defines a problemMatcher inline instead of using
170 | // a predefined one.
171 | /*
172 | {
173 | "version": "0.1.0",
174 | "command": "tsc",
175 | "isShellCommand": true,
176 | "args": ["HelloWorld.ts"],
177 | "showOutput": "silent",
178 | "problemMatcher": {
179 | // The problem is owned by the typescript language service. Ensure that the problems
180 | // are merged with problems produced by Visual Studio's language service.
181 | "owner": "typescript",
182 | // The file name for reported problems is relative to the current working directory.
183 | "fileLocation": ["relative", "${cwd}"],
184 | // The actual pattern to match problems in the output.
185 | "pattern": {
186 | // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'.
187 | "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$",
188 | // The match group that denotes the file containing the problem.
189 | "file": 1,
190 | // The match group that denotes the problem location.
191 | "location": 2,
192 | // The match group that denotes the problem's severity. Can be omitted.
193 | "severity": 3,
194 | // The match group that denotes the problem code. Can be omitted.
195 | "code": 4,
196 | // The match group that denotes the problem's message.
197 | "message": 5
198 | }
199 | }
200 | }
201 | */
--------------------------------------------------------------------------------
/docs/src/examples/exampleNestedNgRepeatWithModel/exampleNestedNgRepeatWithModel.html:
--------------------------------------------------------------------------------
1 |
2 |
Nested ngRepeat - with model
3 |
You can move whole rows by grabing row title, all items it selves. Try it out!
4 |
5 | Old IE doesnt support Flexible Box Layout so it can look weird. But in modern browsers it is awsome! Dragular will be working well also in old IE but you have to use different css for layout.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Row {{::$index}}
13 |
14 |
{{item.content}} x
15 |
16 |
17 | +
18 | X
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | add row
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Rows:
35 | {{rows | json}}
36 |
37 |
38 |
39 |
40 |
41 |
42 | <!-- HTML -->
43 | <div ng-controller="NestedNgRepeatWithModel">
44 | <div class="table-row">
45 | <div class="container-vertical">
46 | <div ng-repeat="row in rows" class="example-row">
47 | <div class="row-handle">Row {{::$index}}</div>
48 | <div class="example-row container-nested">
49 | <div ng-repeat="item in row.items" class="example-cell">{{item.content}} <button class="cursor-default" ng-click="removeItem(row, item)">x</button></div>
50 | </div>
51 | <div>
52 | <button class="cursor-default" ng-click="addItem(row)">+</button>
53 | <button class="cursor-default" ng-click="removeRow(row, $event)">X</button>
54 | </div>
55 | </div>
56 | </div>
57 | </div>
58 | <div class="table-row">
59 | <div class="container-vertical">
60 | <div>
61 | <button class="cursor-default" ng-click="addRow()">add row</button>
62 | </div>
63 | </div>
64 | </div>
65 |
66 |
67 |
68 |
69 | // CSS
70 |
71 | .example-row {
72 | display: flex;
73 | flex-direction: row;
74 | }
75 |
76 | .example-row,
77 | .example-cell {
78 | flex-grow: 1;
79 | margin: 10px;
80 | padding: 10px;
81 | background-color: rgba(0, 0, 0, 0.2);
82 | cursor: move;
83 | cursor: grab;
84 | cursor: -moz-grab;
85 | cursor: -webkit-grab;
86 | }
87 |
88 |
89 |
90 |
91 | // JS
92 | .controller('NestedNgRepeatWithModel', ['$timeout', '$scope', '$element', 'dragularService', function NestedNgRepeatWithModelCtrl($timeout, $scope, $element, dragularService) {
93 | $timeout(function() { // timeount due to nested ngRepeat to be ready
94 | var rowsContainer = $element[0].querySelector('.container-vertical'),
95 | cellsContainers = getCellsContainers();
96 |
97 | dragularService.cleanEnviroment();
98 | dragularService(rowsContainer, {
99 | moves: function(el, container, handle) {
100 | return handle.classList.contains('row-handle');
101 | },
102 | containersModel: $scope.rows,
103 | nameSpace: 'rows'
104 | });
105 |
106 | var cellsContainersDrake = dragularService(cellsContainers, {
107 | moves: function(el, container, handle) {
108 | return handle.classList.contains('example-cell');
109 | },
110 | containersModel: getcellsContainersModel(),
111 | nameSpace: 'cells'
112 | });
113 |
114 | $scope.addItem = function(row) {
115 | var item = {
116 | content: 'Item x' + Math.round( Math.random() * 1000 )
117 | }
118 | row.items.push( item );
119 | }
120 |
121 | $scope.removeItem = function(row, item) {
122 | row.items.splice( row.items.indexOf( item ), 1);
123 | }
124 |
125 | $scope.addRow = function() {
126 | var row = { items: [] };
127 | $scope.rows.push( row );
128 | // wait for angular to create element for added row
129 | $scope.$evalAsync(function() {
130 | // $evalAsync is probably not enough to get after the DOM creation, so timeouted :/
131 | $timeout(function() {
132 | // you can provide all containers, dragular will add just new containers
133 | cellsContainersDrake.addContainers( getCellsContainers(), getcellsContainersModel());
134 | }, 500);
135 | });
136 | }
137 |
138 | $scope.removeRow = function( row, e ) {
139 | var cellsContainerElm = e.target.parentElement.parentElement.querySelectorAll('.container-nested')[0];
140 | cellsContainersDrake.removeContainers( cellsContainerElm );
141 | $scope.rows.splice( $scope.rows.indexOf( row ), 1 );
142 | }
143 |
144 | function getCellsContainers() {
145 | return $element[0].querySelectorAll('.container-nested');
146 | }
147 |
148 | function getcellsContainersModel(){
149 | var parent = $scope.rows,
150 | containersModel = [];
151 | for (var i = 0; i < parent.length; i++) {
152 | containersModel.push(parent[i].items);
153 | }
154 | return containersModel;
155 | }
156 |
157 | }, 0);
158 |
159 | $scope.rows = [{
160 | items: [{
161 | content: 'Item a1'
162 | }, {
163 | content: 'Item a2'
164 | }, {
165 | content: 'Item a3'
166 | }, {
167 | content: 'Item a4'
168 | }]
169 | }, {
170 | items: [{
171 | content: 'Item b1'
172 | }, {
173 | content: 'Item b2'
174 | }, {
175 | content: 'Item b3'
176 | }, {
177 | content: 'Item b4'
178 | }]
179 | }, {
180 | items: [{
181 | content: 'Item c1'
182 | }, {
183 | content: 'Item c2'
184 | }, {
185 | content: 'Item c3'
186 | }, {
187 | content: 'Item c4'
188 | }]
189 | }];
190 | });
191 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /* global process */
2 | 'use strict';
3 | const gulp = require('gulp');
4 | const gutil = require('gulp-util');
5 | const gulpif = require('gulp-if');
6 | const webpack = require('webpack-stream');
7 | const size = require('gulp-size');
8 | const uglify = require('gulp-uglify');
9 | const rename = require('gulp-rename');
10 | const minifyCss = require('gulp-minify-css');
11 | const autoprefixer = require('gulp-autoprefixer');
12 | const browserSync = require('browser-sync');
13 | const jshint = require('gulp-jshint');
14 | const concat = require('gulp-concat');
15 | const templateCache = require('gulp-angular-templatecache');
16 | const ghPages = require('gulp-gh-pages');
17 | const sourcemaps = require('gulp-sourcemaps');
18 | const markdown = require('gulp-markdown');
19 |
20 | const config = {
21 | dragular: {
22 | scripts: './src/*.js',
23 | styles: './src/*.css',
24 | dest: './dist'
25 | },
26 | docs: {
27 | src: './docs/src/examples',
28 | index: './docs/index.html',
29 | scripts: './docs/src/examples/**/*.js',
30 | styles: './docs/src/**/*.css',
31 | templates: './docs/src/examples/**/*.html',
32 | dest: './docs/dist'
33 | },
34 | browserSync: {
35 | port: '3000',
36 | server: './docs'
37 | },
38 | // Predefined scripts & styles configs to keep tasks DRY
39 | scripts: {
40 | libraryTarget: 'umd',
41 | dragular: {
42 | type: 'dragular',
43 | entryPoint: './src/dragularModule.js',
44 | bundleName: 'dragular.js',
45 | dest: './dist'
46 | },
47 | docs: {
48 | type: 'docs',
49 | entryPoint: './docs/src/examples/examplesApp.js',
50 | bundleName: 'examples.js',
51 | dest: './docs/dist'
52 | }
53 | },
54 | styles: {
55 | dragular: {
56 | entryPoint: './src/*.css',
57 | bundleName: 'dragular.css',
58 | dest: './dist'
59 | },
60 | docs: {
61 | entryPoint: [
62 | './src/*.css',
63 | './docs/src/**/*.css'
64 | ],
65 | bundleName: 'examples.css',
66 | dest: './docs/dist'
67 | }
68 | },
69 | // A flag attribute to switch modes
70 | isProd: false
71 | };
72 |
73 | const tasks = {};
74 |
75 | /*
76 | * selectedConfigs stores temporary scripts & styles settings (like entry point or
77 | * output directory). This metadata is used to configure the webpack compilation
78 | * process.
79 | */
80 | let selectedConfigs = {
81 | scripts: config.scripts.dragular,
82 | styles: config.styles.dragular
83 | }
84 |
85 | function handleErrors(err) {
86 | gutil.log(err.toString());
87 | this.emit('end');
88 | }
89 |
90 | tasks.lint = gulp.series(function lint() {
91 | return gulp.src([config.dragular.scripts])
92 | .pipe(jshint())
93 | .pipe(jshint.reporter('jshint-stylish'));
94 | });
95 |
96 | tasks.lint_docs = gulp.series(function lintDocs() {
97 | return gulp.src([config.docs.scripts, '!./docs/src/examples/templates.js'])
98 | .pipe(jshint())
99 | .pipe(jshint.reporter('jshint-stylish'));
100 | });
101 |
102 | tasks.scripts = gulp.series(selectedConfigs.scripts.type === 'dragular' ? tasks.lint : tasks.lint_docs, function scriptsTask(done) {
103 | console.log('selected configs: ', selectedConfigs);
104 | return gulp.src(selectedConfigs.scripts.entryPoint)
105 | .on('error', handleErrors)
106 | .pipe(webpack({
107 | watch: config.isProd ? false : true,
108 | output: {
109 | libraryTarget: config.scripts.libraryTarget,
110 | filename: selectedConfigs.scripts.bundleName
111 | }
112 | }, null, function(err, stats) {
113 | if ( err ) {
114 | throw err;
115 | }
116 | console.log('webpack build finished in ', stats.endTime - stats.startTime, 'ms');
117 | done();
118 | }))
119 | .pipe(gulpif(config.isProd, gulp.dest(selectedConfigs.scripts.dest)))
120 | .pipe(gulpif(config.isProd, size({
121 | title: 'Non-minified scripts: '
122 | })))
123 | .pipe(gulpif(config.isProd, sourcemaps.init({loadMaps: true})))
124 | .pipe(gulpif(config.isProd, uglify({
125 | compress: { drop_console: true }
126 | })))
127 | .pipe(gulpif(config.isProd, rename({
128 | suffix: '.min'
129 | })))
130 | .pipe(size({
131 | title: 'Scripts: '
132 | }))
133 | .pipe(gulpif(config.isProd, sourcemaps.write('./')))
134 | .pipe(gulp.dest(selectedConfigs.scripts.dest))
135 | .pipe(gulpif(browserSync.active, browserSync.stream()));
136 | }
137 | );
138 |
139 | tasks.styles = gulp.series(function stylesTask() {
140 | return gulp.src(selectedConfigs.styles.entryPoint)
141 | .pipe(autoprefixer({
142 | browsers: [ 'last 15 versions', '> 1%', 'ie 8', 'ie 7' ],
143 | cascade: false
144 | }))
145 | .pipe(concat(selectedConfigs.styles.bundleName))
146 | .pipe(gulpif(config.isProd, gulp.dest(selectedConfigs.styles.dest)))
147 | .pipe(gulpif(config.isProd, size({
148 | title: 'Non-minified styles: '
149 | })))
150 | .pipe(gulpif(config.isProd, minifyCss()))
151 | .pipe(gulpif(config.isProd, rename({
152 | suffix: '.min'
153 | })))
154 | .pipe(size({
155 | title: 'Styles: '
156 | }))
157 | .pipe(gulp.dest(selectedConfigs.styles.dest))
158 | .pipe(gulpif(browserSync.active, browserSync.stream()));
159 | }
160 | );
161 |
162 | tasks.serve = gulp.series(function serve(done) {
163 | browserSync({
164 | ui:{
165 | port: '8081'
166 | },
167 | port: (typeof process !== 'undefined' && process.env.PORT) || config.browserSync.port, // cloud9 improvement
168 | host: typeof process !== 'undefined' && process.env.IP, // cloud9 improvement
169 | server: {
170 | baseDir: config.browserSync.server
171 | },
172 | logConnections: true,
173 | logFileChanges: true,
174 | notify: true
175 | });
176 | done();
177 | });
178 |
179 | /*
180 | * Concatenate and register templates in the $templateCache. The resulting file
181 | * (templates.js) is placed inside the directory specified in config.docs.src.
182 | */
183 | tasks.templates_docs = gulp.series(function templatesDocs() {
184 | return gulp.src(config.docs.templates)
185 | .pipe(templateCache({
186 | moduleSystem: 'Browserify',
187 | standalone: true
188 | }))
189 | .pipe(gulp.dest(config.docs.src));
190 | });
191 |
192 | /*
193 | * Watch files for changes
194 | */
195 | tasks.watch = gulp.series(tasks.serve, function watch(done) {
196 | gulp.watch(config.dragular.styles, tasks.styles);
197 | gulp.watch(config.dragular.scripts, tasks.scripts);
198 | done();
199 | });
200 |
201 | tasks.watch_docs = gulp.series(tasks.serve, function watchDocs(done) {
202 | console.log('watching docs');
203 | gulp.watch(config.dragular.styles, tasks.styles);
204 | gulp.watch(config.dragular.scripts, tasks.scripts);
205 | gulp.watch(config.docs.styles, tasks.styles);
206 | gulp.watch(config.docs.scripts, tasks.scripts);
207 | gulp.watch(config.docs.templates, tasks.templates_docs);
208 | gulp.watch(config.docs.index, browserSync.reload);
209 | gulp.watch('./CONTRIBUTING.md', tasks.markdown);
210 | done();
211 | });
212 |
213 | /*
214 | * Launch browserSync server, watch & automatically refresh connected browsers
215 | * on changes, generate non-minified but concatenated output.
216 | */
217 | tasks.dev = gulp.series(function dev(done) {
218 | config.isProd = true;
219 | selectedConfigs = {
220 | scripts: config.scripts.dragular,
221 | styles: config.styles.dragular
222 | };
223 | done();
224 | }, gulp.parallel(tasks.scripts, tasks.styles), tasks.watch);
225 |
226 | /*
227 | * Compiles markdown to html.
228 | */
229 | tasks.markdown = gulp.series(function markdownTask() {
230 | return gulp.src('./CONTRIBUTING.md')
231 | .pipe(markdown())
232 | .pipe(gulpif('**/CONTRIBUTING.html', rename({basename: 'contribute'})))
233 | .pipe(gulp.dest(config.docs.src + '/partials/autogenerated'));
234 | });
235 |
236 | tasks.dev_docs = gulp.series(function devDocs(done) {
237 | config.isProd = false;
238 | selectedConfigs = {
239 | scripts: config.scripts.docs,
240 | styles: config.styles.docs
241 | };
242 | done();
243 | }, tasks.markdown, tasks.templates_docs, gulp.parallel(tasks.scripts, tasks.styles), tasks.watch_docs);
244 |
245 | tasks.build_docs = gulp.series(function buildDocs(done) {
246 | config.isProd = true;
247 | selectedConfigs = {
248 | scripts: config.scripts.docs,
249 | styles: config.styles.docs
250 | };
251 | done();
252 | }, tasks.markdown, tasks.templates_docs, gulp.parallel(tasks.scripts, tasks.styles));
253 |
254 | /*
255 | * Generate production ready minified and concantenated output.
256 | */
257 | tasks.build = gulp.series(function build(done) {
258 | config.isProd = true;
259 | selectedConfigs = {
260 | scripts: config.scripts.dragular,
261 | styles: config.styles.dragular
262 | };
263 | done();
264 | }, gulp.parallel(tasks.scripts, tasks.styles), tasks.build_docs);
265 |
266 | /*
267 | * Publish code to GitHub pages.
268 | */
269 | tasks.deploy_docs = gulp.series(function deployDocs() {
270 | return gulp.src('./docs/**/*')
271 | .pipe(ghPages());
272 | });
273 |
274 |
275 | exports.build = tasks.build;
276 | gulp.task('dev:docs', tasks.dev_docs);
277 | gulp.task('deploy:docs', tasks.deploy_docs);
278 |
--------------------------------------------------------------------------------
/docs/src/examples/examplesApp.js:
--------------------------------------------------------------------------------
1 | /* global angular, hljs */
2 | 'use strict';
3 |
4 | // var angular = require('angular');
5 |
6 | var dragular = require('../../../src/dragularModule');
7 |
8 | angular
9 | .module('examplesApp', [dragular, 'templates', 'ui.router']);
10 |
11 | var examplesRouter = require('./examplesRouter');
12 | var BasicCtrl = require('./exampleBasic/exampleBasic');
13 | var BasicModelCtrl = require('./exampleBasicWithModel/exampleBasicWithModel');
14 | var BoundingBoxCtrl = require('./exampleBoundingBox/exampleBoundingBox');
15 | var BoundingBoxLockXCtrl = require('./exampleBoundingBoxLockX/exampleBoundingBoxLockX');
16 | var BoundingBoxLockYCtrl = require('./exampleBoundingBoxLockY/exampleBoundingBoxLockY');
17 | var CopyCtrl = require('./exampleCopy/exampleCopy');
18 | var CopyModelCtrl = require('./exampleCopyWithModel/exampleCopyWithModel');
19 | var CustomClassesCtrl = require('./exampleCustomClasses/exampleCustomClasses');
20 | var DifferentOptionsModelCtrl = require('./exampleDifferentOptionsWithModel/exampleDifferentOptionsWithModel');
21 | var DirectiveCtrl = require('./exampleDirective/exampleDirective');
22 | var DirectiveModelCtrl = require('./exampleDirectiveWithModel/exampleDirectiveWithModel');
23 | var DragOverEventsCtrl = require('./exampleDragOverEvents/exampleDragOverEvents');
24 | var EventsCtrl = require('./exampleEvents/exampleEvents');
25 | var HandleCtrl = require('./exampleHandle/exampleHandle');
26 | var IsContainerModelCtrl = require('./exampleIsContainerWithModel/exampleIsContainerWithModel');
27 | var NameSpacesCtrl = require('./exampleNameSpaces/exampleNameSpaces');
28 | var NestedNgRepeatCtrl = require('./exampleNestedNgRepeat/exampleNestedNgRepeat');
29 | var NestedNgRepeatWithModelCtrl = require('./exampleNestedNgRepeatWithModel/exampleNestedNgRepeatWithModel');
30 | var NgRepeatCtrl = require('./exampleNgRepeat/exampleNgRepeat');
31 | var NgRepeatFilteredWithModelCtrl = require('./exampleNgRepeatFilteredWithModel/exampleNgRepeatFilteredWithModel');
32 | var NgRepeatWithModelCtrl = require('./exampleNgRepeatWithModel/exampleNgRepeatWithModel');
33 | var RemoveOnSpillCtrl = require('./exampleRemoveOnSpill/exampleRemoveOnSpill');
34 | var RemoveOnSpillWithModelCtrl = require('./exampleRemoveOnSpillWithModel/exampleRemoveOnSpillWithModel');
35 | var RevertOnSpillCtrl = require('./exampleRevertOnSpill/exampleRevertOnSpill.js');
36 | var ScrollingDragCtrl = require('./exampleScrollingDrag/exampleScrollingDrag.js');
37 | var NestedRepeatsWithCustomDirective = require('./exampleNestedRepeatsWithCustomDirective/exampleNestedRepeatsWithCustomDirective.js');
38 | require('./templates');
39 |
40 | /**
41 | * Module Example App
42 | *
43 | * DEMO app for dragular https://github.com/luckylooke/dragular
44 | */
45 |
46 | angular
47 | .module('examplesApp')
48 | .config(examplesRouter)
49 | .controller('Basic', BasicCtrl)
50 | .controller('BasicModel', BasicModelCtrl)
51 | .controller('BoundingBox', BoundingBoxCtrl)
52 | .controller('BoundingBoxLockX', BoundingBoxLockXCtrl)
53 | .controller('BoundingBoxLockY', BoundingBoxLockYCtrl)
54 | .controller('Copy', CopyCtrl)
55 | .controller('CopyModel', CopyModelCtrl)
56 | .controller('CustomClasses', CustomClassesCtrl)
57 | .controller('DifferentOptionsModel', DifferentOptionsModelCtrl)
58 | .controller('Directive', DirectiveCtrl)
59 | .controller('DirectiveModel', DirectiveModelCtrl)
60 | .controller('DragOverEvents', DragOverEventsCtrl)
61 | .controller('Events', EventsCtrl[0])
62 | .controller('Events2', EventsCtrl[1])
63 | .controller('Handle', HandleCtrl)
64 | .controller('IsContainerModel', IsContainerModelCtrl)
65 | .controller('NameSpaces', NameSpacesCtrl)
66 | .controller('NestedNgRepeat', NestedNgRepeatCtrl)
67 | .controller('NestedNgRepeatWithModel', NestedNgRepeatWithModelCtrl)
68 | .controller('NgRepeat', NgRepeatCtrl)
69 | .controller('NgRepeatFilteredWithModel', NgRepeatFilteredWithModelCtrl)
70 | .controller('NgRepeatWithModel', NgRepeatWithModelCtrl)
71 | .controller('RemoveOnSpill', RemoveOnSpillCtrl)
72 | .controller('RemoveOnSpillWithModel', RemoveOnSpillWithModelCtrl)
73 | .controller('RevertOnSpill', RevertOnSpillCtrl)
74 | .controller('ScrollingDrag', ScrollingDragCtrl)
75 | .controller('NestedRepeatsWithCustomDirective', NestedRepeatsWithCustomDirective)
76 | .controller('ExAppCtrl', ['$scope', function($scope) {
77 | $scope.examplesList = [{
78 | template: 'docsInstall/docsInstall.html',
79 | link: 'docsInstall',
80 | title: 'Installation'
81 | },{
82 | template: 'exampleBasic/exampleBasic.html',
83 | link: 'exampleBasic',
84 | title: 'Basic'
85 | },{
86 | template: 'exampleBasicWithModel/exampleBasicWithModel.html',
87 | link: 'exampleBasicWithModel',
88 | title: 'Basic - with model'
89 | },{
90 | template: 'exampleDifferentOptionsWithModel/exampleDifferentOptionsWithModel.html',
91 | link: 'exampleDifferentOptionsWithModel',
92 | title: 'Different options - with model'
93 | }, {
94 | template: 'exampleDirective/exampleDirective.html',
95 | link: 'exampleDirective',
96 | title: 'Directive'
97 | }, {
98 | template: 'exampleDirectiveWithModel/exampleDirectiveWithModel.html',
99 | link: 'exampleDirectiveWithModel',
100 | title: 'Directive - with model'
101 | }, {
102 | template: 'exampleEvents/exampleEvents.html',
103 | link: 'exampleEvents',
104 | title: 'Events'
105 | }, {
106 | template: 'exampleRemoveOnSpill/exampleRemoveOnSpill.html',
107 | link: 'exampleRemoveOnSpill',
108 | title: 'Remove on spill'
109 | }, {
110 | template: 'exampleRemoveOnSpillWithModel/exampleRemoveOnSpillWithModel.html',
111 | link: 'exampleRemoveOnSpillWithModel',
112 | title: 'Remove on spill - with model'
113 | }, {
114 | template: 'exampleRevertOnSpill/exampleRevertOnSpill.html',
115 | link: 'exampleRevertOnSpill',
116 | title: 'Revert on spill'
117 | }, {
118 | template: 'exampleCopy/exampleCopy.html',
119 | link: 'exampleCopy',
120 | title: 'Copy'
121 | }, {
122 | template: 'exampleCopyWithModel/exampleCopyWithModel.html',
123 | link: 'exampleCopyWithModel',
124 | title: 'Copy - with model'
125 | }, {
126 | template: 'exampleHandle/exampleHandle.html',
127 | link: 'exampleHandle',
128 | title: 'Handle'
129 | }, {
130 | template: 'exampleIsContainerWithModel/exampleIsContainerWithModel.html',
131 | link: 'exampleIsContainerWithModel',
132 | title: 'isContainer - with model'
133 | }, {
134 | template: 'exampleCustomClasses/exampleCustomClasses.html',
135 | link: 'exampleCustomClasses',
136 | title: 'Custom classes'
137 | }, {
138 | template: 'exampleNameSpaces/exampleNameSpaces.html',
139 | link: 'exampleNameSpaces',
140 | title: 'NameSpaces'
141 | }, {
142 | template: 'exampleDragOverEvents/exampleDragOverEvents.html',
143 | link: 'exampleDragOverEvents',
144 | title: 'Drag-over events'
145 | }, {
146 | template: 'exampleBoundingBox/exampleBoundingBox.html',
147 | link: 'exampleBoundingBox',
148 | title: 'BoundingBox'
149 | }, {
150 | template: 'exampleBoundingBoxLockX/exampleBoundingBoxLockX.html',
151 | link: 'exampleBoundingBoxLockX',
152 | title: 'BoundingBox + LockX'
153 | }, {
154 | template: 'exampleBoundingBoxLockY/exampleBoundingBoxLockY.html',
155 | link: 'exampleBoundingBoxLockY',
156 | title: 'BoundingBox + LockY'
157 | }, {
158 | template: 'exampleNgRepeat/exampleNgRepeat.html',
159 | link: 'exampleNgRepeat',
160 | title: 'ngRepeat'
161 | }, {
162 | template: 'exampleNgRepeatWithModel/exampleNgRepeatWithModel.html',
163 | link: 'exampleNgRepeatWithModel',
164 | title: 'ngRepeat - with model'
165 | }, {
166 | template: 'exampleNgRepeatFilteredWithModel/exampleNgRepeatFilteredWithModel.html',
167 | link: 'exampleNgRepeatFilteredWithModel',
168 | title: 'Filtered ngRepeat - with model'
169 | }, {
170 | template: 'exampleNestedNgRepeat/exampleNestedNgRepeat.html',
171 | link: 'exampleNestedNgRepeat',
172 | title: 'Nested ngRepead'
173 | }, {
174 | template: 'exampleNestedNgRepeatWithModel/exampleNestedNgRepeatWithModel.html',
175 | link: 'exampleNestedNgRepeatWithModel',
176 | title: 'Nested ngRepead - with model'
177 | }, {
178 | template: 'exampleScrollingDrag/exampleScrollingDrag.html',
179 | link: 'exampleScrollingDrag',
180 | title: 'Scrolling drag'
181 | }, {
182 | template: 'exampleSNestedRepeatsWithCustomDirective/exampleNestedRepeatsWithCustomDirective.html',
183 | link: 'exampleNestedRepeatsWithCustomDirective',
184 | title: 'Nested repeats with custom directive'
185 | }];
186 |
187 | $scope.highlightCode = function () {
188 | if(document.getElementsByTagName('code').length){
189 | var codeBlocks = document.getElementsByTagName('code');
190 | for (var i = codeBlocks.length - 1; i >= 0; i--) {
191 | hljs.highlightBlock(codeBlocks[i]);
192 | }
193 | }
194 | };
195 |
196 | var rowOffcanvas;
197 | $scope.toggleSidebar = function toggleSidebar () {
198 | if(!rowOffcanvas){
199 | rowOffcanvas = angular.element(document.getElementById('rowOffcanvas'));
200 | }
201 | rowOffcanvas.toggleClass('active');
202 | };
203 |
204 | }]);
205 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 4.6.0 Ghost busters
2 | - improved dynamic containers recognition
3 | - improved addContainers, removeContainers methods
4 | - improved example of nested containers
5 | - fixing gulp tasks
6 |
7 | # 4.5.1 Grinch
8 | - fixed npm audit vulnerabilities #173
9 |
10 | # 4.5.0 Wind River
11 | - with "copy:'events'" option dragular clone element including event handlers binded on element (request #165)
12 | - added helpers methods into drake for easier dynamic add/removal of containers of drake initialised earlier
13 |
14 | # 4.4.6 Ghost in the shell
15 | - isContainer docs augmentation
16 | - fixed bug in getTargetCtx
17 | - fixed #161 previous target context used if the last before drop was not accepted target
18 |
19 | # 4.4.5 Target
20 | - fixes #154 - both scopes should be notified about events (source and also target scope)
21 | - adding main gulp tasks to standard npm tasks, to get better orented quickly
22 | - renamed CHANGELOG and README to UPPERCASE so they can be more easily to find visually
23 |
24 | # 4.4.4 Don't Knock Twice
25 | - throwing error if trying same container to register twice
26 | - new example of nested ng-repeats combined with custom directive
27 |
28 | # 4.4.3 Spy Kids
29 | - fixed #148 - model not updated on spill
30 |
31 | # 4.4.2 The Model
32 | - fixed #138 - dynamic model via directive doesn't work properly
33 |
34 | # 4.4.1 Dark places
35 | - fixed #136 - Items can be moved to the end of container even if options.accepts returns false
36 |
37 | # 4.4.0 Accepted
38 | - isContainerAccepts - acceptation function for isContainer containers
39 | - some docs improvements
40 | - fixed #132 - not working isContainer with models
41 |
42 | # 4.3.4 Home alone
43 | - merged forgotten changes from master PRs
44 |
45 | # 4.3.3 The Gods Must Be Crazy
46 | - fixed #131 drags mixed with scrolling (caused by chrome update)
47 | - fixed #129 drag stucks on no-container release
48 | - fixed #128 canBeAccepted did not work in combination with isContainer
49 | - added options object as second argument to onInit (requested in #65)
50 |
51 | # 4.3.2 War of the Worlds
52 | - fixed #120 isContainer example not working
53 |
54 | # 4.3.1 Robin Hood
55 | - fixed dynamic (function) `options.containersModel` for target containers models
56 |
57 | # 4.3.0 Hitman
58 | - added new options for `options.containersModel`, it accepts also string from now
59 |
60 | # 4.2.5 Di-strict 9
61 | - fixing #108 - Webpack and strict mode
62 |
63 | # 4.2.4 Trolls
64 | - fixed #87 - problem in example "NestedNgRepeat", input field doesnt work
65 |
66 | # 4.2.3 The lost explorer
67 | - fixed #107 - IE dragging issue, drag did not start
68 |
69 | # 4.2.2 The Drop
70 | - fixed #104 - drop index undefined in dragulardrop event listeners
71 |
72 | # 4.2.1 Skyfall
73 | - fixed #102
74 | - transit class added after mirror rendering #101
75 | - original DOM events passed as new parameter to angular listeners #97
76 |
77 | # 4.2.0 Bad Moms
78 | - UMD compatible #79
79 | - options.onInit, on init callback function, closes #65
80 | - Fixed examples #83 (Filtered model in nested ng-repeat)
81 |
82 | # 4.1.0 Dora
83 | - IE bug fixes #68
84 | - compileItemOnDrop fixes #71
85 |
86 | # 4.0.1 John Whick
87 | - possibility to use it as a CommonJS module #62
88 | - jQuery enviroment fixes #63
89 |
90 | # 4.0.0 Uprising
91 |
92 | - **[Braking change!]** options object reference is now live, so can be changed on the fly with instant effect, this feature can be disabled by 'options.copyOptions = true' flag so dragular then make copy of options object. It also means than provided options object will be extended with default value where option property is undefined.
93 | - **[Braking change!]** flag 'options.ignoreInputTextSelection' default value is 'true'! Meaning that selecting text in input elements is not considered as drag, now by default!
94 | - all boolean type options can be functions returning boolean
95 | - options.containersModel can be function returning model
96 | - new directive attribute dragular-name-space for better readability of views
97 | - new options flag `options.dynamicModelAttribute`, if true dragular will react on model changes
98 | - new options flag `options.dontCopyModel`, dont make copy of model when coping item (#61)
99 |
100 | ### Changes merged from dragula 3.6.3
101 | - Fixed an issue that prevented `dragular` from execution early in the document load life-cycle
102 | - Fixed issues in touch-enabled browsers such as Windows Phone 10
103 |
104 | # 3.4.0 StarWars
105 | - support filtered ng-repeats
106 | - the 'shared' object is truly shared between service instances as it was originally intended
107 | - many code refactors for better readability (to be continued..)
108 | - event names can be now customized for each drake
109 |
110 | # 3.3.1 Dwarf
111 | - fix touches
112 |
113 | # 3.3.0 Xmas fever
114 | - some code refactors
115 | - introducing codeclimate
116 | - Sending target index on dragulardrop event
117 | - Fix css property typo
118 | - Fix for applyAsync typo and multiple executions of startBecauseMouseMoved
119 | - Touchstart and Touchend Support
120 |
121 | ### Changes merged from dragula 3.6.0
122 | - Introduced support for `contentEditable` DOM attribute
123 | - Switched from `.parentElement` to `.parentNode` avoiding bugs when hovering over `` elements
124 | - Fixed a bug where mobile devices wouldn't be able to drag elements
125 |
126 | # 3.2.0 Ladybugs
127 | - Fix for applyAsync typo and multiple executions of startBecauseMouseMoved #45
128 |
129 | ### Changes merged from dragula 3.5.2:
130 | - Fixed a bug where `` inputs couldn't be focused
131 | - Fixed a bug when determining the mouse button being pressed
132 | - Fixed a bug when determining the element behind the mouse cursor when `ignoreInputTextSelection` was enabled
133 | - Added a feature where users are able to select text ranges with their mouse in inputs within a dragular container
134 | - Fixed a bug where text in inputs inside containers assigned to `dragula` couldn't be selected
135 | - Fixed a bug where `out` would be emitted with an `undefined` container
136 | - Fixed a fringe bug [(#207)](https://github.com/bevacqua/dragula/pull/207) where the click handler wouldn't work
137 | - Fixed a bug where `drop` events would sometimes not receive the current sibling
138 |
139 | # 3.1.0 Brotherhood
140 |
141 | - added `dragular-model` atribute as new optional way of provideng model when using dragular directive
142 | - fixed gh-pages missed prefixes in Events example
143 |
144 | ### Changes merged from dragula 3.3.0:
145 | - You can now use `options.copySortSource` to enable sorting in `copy`-source containers
146 | - The `options.moves` callback now receives a fourth parameter, the `sibling` found after `el`
147 |
148 | # 3.0.2 fix
149 |
150 | - Fixed drop event firing before models updated
151 |
152 | # 3.0.1 fix
153 |
154 | - Fixed shared.item undefined in grab fn in some cases
155 |
156 | # 3.0.0 Interdragular
157 |
158 | - **[Braking change!]** scope events are renamed (drop => dragulardrop, shadow => dragularshadow, etc..)
159 | - **[Braking change!]** options.accepts is splited into two methods options.accepts applied with target container options and options.canBeAccepted applied with source container options
160 | - if options.isContainer is used model can be provided via function options.isContainerModel(containerElm)
161 | - **[Braking change!]** removed dragOverClasses (dragOver events can be used instead);
162 | - share containers between instances, so no need to nameSpace if containers are initialised separately (CAUTION: in case of nested containers you need to use nameSpace for each group/level_of_nesting)
163 | - example with containers which has different options each
164 | - **[Braking change!]** Now all non-nameSpaced continers are in same domain
165 | - **[Braking change!]** Models are not updated until drag ends
166 | - css selectors supportet in service `containers` parameter
167 | - removed npm workflow
168 |
169 | ### Changes merged from dragula 3.1.0:
170 | - You can now set `options.copy` to a method. It'll be invoked once per drag to ask whether the element being dragged should be treated as a copy or not
171 | - Fixed a bug where starting a drag programatically while an element was being dragged resulted in an exception
172 | - Fixed a bug where `mousedown` would be prevented and focusing draggable inputs wouldn't be possible
173 | - Fixed a historical bug, where click on anchors would be ignored within dragula containers in mobile
174 | - Fixed a bug where events wouldn't be gracefully removed if drake were destroyed during a drag event
175 | - Now emits dragend after out to preserve consistency (because drag is emitted before over)
176 | - Fixed another old bug where attempting to remove elements using removeOnSpill on mobile would fail
177 | - Fixed a bug in mobile, caused by 3.0.0, where scrolling would be impossible
178 | - Fixed a bug where dragging would cause text selection in IE8
179 | - **[Braking change!]** Removed addContainer method, which was previously deprecated
180 | - **[Braking change!]** Removed removeContainer method, which was previously deprecated
181 | - **[Braking change!]** Removed delay option in favor of using mousemove
182 | - Drag events now start on the first occurrence of a mousemove event
183 | - If mousemove never fires, then the drag machinery won't start, either
184 | - Changed default value for invalid, now always returns false by default
185 | - Added mirrorContainer option to determine where the mirror gets appended to (defaults to document.body)
186 |
187 | # 2.1.3 hotfix
188 |
189 | - fixing makeArray internal function which causes reversed arrays and so unexpected behaviour
190 |
191 | # 2.1.2 Damn
192 |
193 | - fixing release (unminidied files had still 2.1.0 version)
194 |
195 | # 2.1.1 patch
196 |
197 | - fixing drake.destroy()
198 |
199 | # 2.1.0 Elder Scrolls
200 |
201 | - fixed scrolling while drag #14
202 | - added new events fired on elements behind cursor while dragging (dragularenter, dragularleave), could be used to add/remove classes
203 | - added new scope event 'release' when mouse button is released whatever ending it has (drop, cancel, revert..)
204 |
205 | # 2.0.1 Lightning
206 |
207 | - fixed forgoten lint errors
208 |
209 | # 2.0.0 Aloha
210 |
211 | - ngRepeat can be synced with provided model
212 | - gulp workflow (thanks to @alferov)
213 | - gh-pages refactored
214 | - Fixed a bug where `shadow` would trigger multiple times while dragging an element over the same spot
215 | - Fixed a bug where adding and removing classes might've caused issues on elements that had foreign CSS classes
216 | - Added an argument to `cloned` event that specifies the kind of clone. Possible values include `mirror` and `copy` at the moment
217 | - Added `over` event that fires whenever an element is dragged over a container _(or whenever a drag event starts)_
218 | - Added `out` event that fires whenever an element is dragged out of a container _(or whenever a drag event ends)_
219 | - Fixed a bug caused in `2.0.6` where anything would be regarded as a `drake` container
220 | - Fixed a bug where `isContainer` would be called with a `el=null` in some situations
221 | - Set `gu-transit` after a drag event has fully started
222 | - Fixed a bug where using `.cancel` would throw an exception
223 | - Fixed a bug where dragging a copy back to origin after hovering over another container would still result in a copy being made if you never spilled the item
224 | - Deprecated addContainer method
225 | - Deprecated removeContainer method
226 | - Exposed dragula.containers collection
227 | - Introduced dynamic isContainer method
228 | - Can now omit containers argument to dragula(containers, options)
229 | - Can now pass containers as an option
230 | - Differentiate between drag and click using delay option
231 | - Ability to specify which event targets are invalid drag triggers
232 |
233 | # 1.3.2 Buggydown
234 |
235 | - mousedown handlers moved from document to containers, due to bugs in namespacing-multiple-instances enviroment
236 |
237 | # 1.3.1 Fix6
238 |
239 | - fixes #6
240 |
241 | # 1.3.0 Dragula203
242 |
243 | - changes of dragula 2.0.3 against 1.6.1 implemented
244 | - usage description augmented (#5)
245 |
246 | # 1.2.1 Damn build
247 |
248 | - forgot to build.. sorry
249 |
250 | # 1.2.0 Directive
251 |
252 | - feat(directive): accept options as JSON string
253 | - fix(directive): minify-safe syntax added to directive, closes #3
254 |
255 | # 1.1.0 tadaaa
256 |
257 | - started correctly using Semantic Versioning 2.0.0 http://semver.org/
258 | - avoiding angular.merge, so polyfill part was removed
259 | - boundingBox (dragging element can me moved only in specific area)
260 | - lockX/Y (dragging element can me moved only in specific direction)
261 | - readded feature: automatic direction
262 |
263 | # 1.0.3 nameSpaced containers
264 |
265 | - allowing share of containers groups
266 |
267 | # 1.0.2 customClasses
268 |
269 | - custom classes via option.classes;
270 |
271 | # 1.0.1 arraylike
272 |
273 | - accepting arraylike objects as containers array;
274 |
275 | # 1.0.0 IPO
276 |
277 | - Initial Public Release (dragula 1.6.1, angular 1.4.1);
278 |
--------------------------------------------------------------------------------
/docs/src/vendor/highlight.pack.js:
--------------------------------------------------------------------------------
1 | !function(e){"undefined"!=typeof exports?e(exports):(window.hljs=e({}),"function"==typeof define&&define.amd&&define("hljs",[],function(){return window.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&").replace(//gm,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){return/no-?highlight|plain|text/.test(e)}function i(e){var n,t,r,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=/\blang(?:uage)?-([\w-]+)\b/.exec(i))return E(t[1])?t[1]:"no-highlight";for(i=i.split(/\s+/),n=0,r=i.length;r>n;n++)if(E(i[n])||a(i[n]))return i[n]}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset"}function u(e){f+=""+t(e)+">"}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,f="",l=[];e.length||r.length;){var g=i();if(f+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){l.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);l.reverse().forEach(o)}else"start"==g[0].event?l.push(g[0].node):l.pop(),c(g.splice(0,1)[0])}return f+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\b\w+\b/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var f=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=f.length?t(f.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){for(var t=0;t";return i+=e+'">',i+n+o}function p(){if(!L.k)return n(B);var e="",t=0;L.lR.lastIndex=0;for(var r=L.lR.exec(B);r;){e+=n(B.substr(t,r.index-t));var a=g(L,r);a?(y+=a[1],e+=h(a[0],n(r[0]))):e+=n(r[0]),t=L.lR.lastIndex,r=L.lR.exec(B)}return e+n(B.substr(t))}function d(){if(L.sL&&!x[L.sL])return n(B);var e=L.sL?f(L.sL,B,!0,M[L.sL]):l(B);return L.r>0&&(y+=e.r),"continuous"==L.subLanguageMode&&(M[L.sL]=e.top),h(e.language,e.value,!1,!0)}function b(){return void 0!==L.sL?d():p()}function v(e,t){var r=e.cN?h(e.cN,"",!0):"";e.rB?(k+=r,B=""):e.eB?(k+=n(t)+r,B=""):(k+=r,B=t),L=Object.create(e,{parent:{value:L}})}function m(e,t){if(B+=e,void 0===t)return k+=b(),0;var r=o(t,L);if(r)return k+=b(),v(r,t),r.rB?0:t.length;var a=u(L,t);if(a){var i=L;i.rE||i.eE||(B+=t),k+=b();do L.cN&&(k+=""),y+=L.r,L=L.parent;while(L!=a.parent);return i.eE&&(k+=n(t)),B="",a.starts&&v(a.starts,""),i.rE?0:t.length}if(c(t,L))throw new Error('Illegal lexeme "'+t+'" for mode "'+(L.cN||"")+'"');return B+=t,t.length||1}var N=E(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,L=i||N,M={},k="";for(R=L;R!=N;R=R.parent)R.cN&&(k=h(R.cN,"",!0)+k);var B="",y=0;try{for(var C,j,I=0;;){if(L.t.lastIndex=I,C=L.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),R=L;R.parent;R=R.parent)R.cN&&(k+="");return{r:y,value:k,language:e,top:L}}catch(O){if(-1!=O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function l(e,t){t=t||w.languages||Object.keys(x);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(E(n)){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function g(e){return w.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,w.tabReplace)})),w.useBR&&(e=e.replace(/\n/g," ")),e}function h(e,n,t){var r=n?R[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n=i(e);if(!a(n)){var t;w.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/ /g,"\n")):t=e;var r=t.textContent,o=n?f(n,r,!0):l(r),s=u(t);if(s.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=o.value,o.value=c(s,u(p),r)}o.value=g(o.value),e.innerHTML=o.value,e.className=h(e.className,n,o.language),e.result={language:o.language,re:o.r},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.r})}}function d(e){w=o(w,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){R[e]=n})}function N(){return Object.keys(x)}function E(e){return x[e]||x[R[e]]}var w={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},x={},R={};return e.highlight=f,e.highlightAuto=l,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=E,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",bK:"TODO FIXME NOTE BUG XXX",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e});hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"pi",r:10,b:/^\s*['"]use (strict|asm)['"]/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/,e:/>\s*[);\]]/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{bK:"import",e:"[;$]",k:"import from as",c:[e.ASM,e.QSM]},{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]}]}});hljs.registerLanguage("http",function(t){return{aliases:["https"],i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:!0}}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",a={cN:"function",b:c+"\\(",rB:!0,eE:!0,e:"\\("},r={cN:"rule",b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{cN:"value",eW:!0,eE:!0,c:[a,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,r,{cN:"id",b:/\#[A-Za-z0-9_-]+/},{cN:"class",b:/\.[A-Za-z0-9_-]+/},{cN:"attr_selector",b:/\[/,e:/\]/,i:"$"},{cN:"pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"']+/},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[a,e.ASM,e.QSM,e.CSSNM]}]},{cN:"tag",b:c,r:0},{cN:"rules",b:"{",e:"}",i:/\S/,c:[e.CBCM,r]}]}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:"^\\[.+\\]:",rB:!0,c:[{cN:"link_reference",b:"\\[",e:"\\]:",eB:!0,eE:!0,starts:{cN:"link_url",e:"$"}}]}]}});hljs.registerLanguage("json",function(e){var t={literal:"true false null"},i=[e.QSM,e.CNM],l={cN:"value",e:",",eW:!0,eE:!0,c:i,k:t},c={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:!0,eE:!0,c:[e.BE],i:"\\n",starts:l}],i:"\\S"},n={b:"\\[",e:"\\]",c:[e.inherit(l,{cN:null})],i:"\\S"};return i.splice(i.length,0,c,n),{c:i,k:t,i:"\\S"}});hljs.registerLanguage("xml",function(t){var e="[A-Za-z0-9\\._:-]+",s={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"},c={eW:!0,i:/,r:0,c:[s,{cN:"attribute",b:e,r:0},{b:"=",r:0,c:[{cN:"value",c:[s],v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s\/>]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},t.C("",{r:10}),{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"",rE:!0,sL:"css"}},{cN:"tag",b:"",rE:!0,sL:""}},s,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"?",e:"/?>",c:[{cN:"title",b:/[^ \/><\n\t]+/,r:0},c]}]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,e.NM,s,a,t]}});hljs.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"chunk",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});
--------------------------------------------------------------------------------
/dist/dragular.min.js:
--------------------------------------------------------------------------------
1 | !function(e,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n();else if("function"==typeof define&&define.amd)define([],n);else{var t=n();for(var r in t)("object"==typeof exports?exports:e)[r]=t[r]}}(this,function(){return function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}var t={};return n.m=e,n.c=t,n.p="",n(0)}([function(e,n,t){"use strict";var r=t(1),o=t(2);e.exports="dragularModule",angular.module("dragularModule",[]).factory("dragularService",o).directive("dragular",r)},function(e,n){"use strict";var t=function(e){return{restrict:"A",link:function(n,t,r){function o(e){try{return JSON.parse(e)}catch(n){return}}var i=n.$eval(r.dragular)||o(r.dragular)||{};r.dragularModel&&(i.containersModel=r.dragularModel,i.scope||(i.scope=n)),r.dragularNameSpace&&(i.nameSpace=r.dragularNameSpace.split(" ")),r.dragularOnInit&&(i.onInit=n.$eval(r.dragularOnInit)),e(t[0],i)}}};t.$inject=["dragularService"],e.exports=t},function(e,n){"use strict";var t={classesCache:{},containersCtx:{},containers:{},mirror:null,source:null,item:null,copy:null,sourceItem:null,sourceModel:null,sourceFilteredModel:null,target:null,targetCtx:null,targetModel:null,lastDropTarget:null,offsetX:null,offsetY:null,moveX:null,moveY:null,offsetXr:null,offsetYb:null,clientX:null,clientY:null,mirrorWidth:null,mirrorHeight:null,initialSibling:null,currentSibling:null,initialIndex:null,currentIndex:null,tempModel:null,dragOverEvents:{},lastElementBehindCursor:null,grabbed:null},r=function(e,n){function r(r,d){function x(){"string"==typeof r?pe=document.querySelectorAll(r):1!==arguments.length||T(r)||angular.isElement(r)||r[0]||(ve=r||{},pe=[]),ge=ve.copyOptions?angular.copy(ve):ve}function M(){var e=angular.extend({},Ce,ge);angular.extend(ge,e),ge.classes&&(e=angular.extend({},xe,ge.classes),angular.extend(ge.classes,e)),ge.eventNames&&(e=angular.extend({},ye,ge.eventNames),angular.extend(ge.eventNames,e))}function I(){h(ge.boundingBox)||(ge.boundingBox=!1),ge.containers&&(pe=ge.containers),ge.containers=o(pe,!1,ge.scope),ge.containersModel=o(ge.containersModel,!0,ge.scope),T(ge.containersFilteredModel)?ge.containersFilteredModel=T(ge.containersFilteredModel[0])?ge.containersFilteredModel:[ge.containersFilteredModel]:ge.containersFilteredModel=[],ge.nameSpace||(ge.nameSpace=["dragularCommon"]),T(ge.nameSpace)||(ge.nameSpace=[ge.nameSpace]),ge.nameSpace.forEach(function(e){t.containers[e]||(t.containers[e]=[],t.containersCtx[e]=[]);for(var n,r=_(ge).length,o=0;oi.left+t.offsetX&&ri.top+t.offsetY&&ot)return o;if(!l&&i.top>r)return o}return null}function i(){var e=n.getBoundingClientRect();return a(l?t>e.left+f(e)/2:r>e.top+g(e)/2)}function a(e){return e?v(n):n}var l="horizontal"===ge.direction;return n!==e?i():o()}function V(e,n,t){var r,o=e||{},i=o.className;return o.className+=" "+ge.classes.hide,r=O.elementFromPoint(n,t),o.className=i,r}function Z(e){if(!e)return!1;if(_(ge).indexOf(e)>-1)return!0;for(var n=ge.nameSpace.length;n--;)if(t.containers[ge.nameSpace[n]].indexOf(e)!==-1)return!0;return ge.isContainer(e)?(t.tempModel=ge.isContainerModel(e),!0):(t.tempModel=null,!1)}function _(e){return te("containers",e)}function ee(e){return te("containersModel",e,!0)}function ne(e){return te("containersFilteredModel",e,!0)}function te(e,n,r){return B(n[e])?o(n[e](n===ge?Me:null,t),r,n.scope):n[e]}function re(e){if(Me.dragging){var n=arguments.length>0?e:he(ge.revertOnSpill),r=E(t.item),o=J(r);o||t.copy||!n||t.source.insertBefore(t.item,t.initialSibling),!t.sourceModel||t.copy||n?ge.scope&&(o||n)&&ge.scope.$emit(ge.eventNames.dragularcancel,t.item,t.source,t.sourceModel,t.initialIndex):ie(t.item,r),(!t.sourceModel||t.copy||n||o)&&le()}}function oe(e){if(W(),Me.dragging){e.originalEvent&&(e=e.originalEvent),t.clientX=b("clientX",e),t.clientY=b("clientY",e);var n=V(t.mirror,t.clientX,t.clientY),r=K(n,t.clientX,t.clientY);r&&(t.copy&&he(ge.copySortSource)||!t.copy||r!==t.source)?ie(t.item,r):he(ge.removeOnSpill)?ae():re(),t.target=null,t.lastElementBehindCursor&&X(t.lastElementBehindCursor,t.dragOverEvents.dragularrelease,n),ge.scope&&ge.scope.$emit(ge.eventNames.dragularrelease,t.item,t.source,e)}}function ie(r,o){function a(){function e(e){J(o)?e.$emit(ge.eventNames.dragularcancel,r,t.source,t.sourceModel,t.initialIndex):e.$emit(ge.eventNames.dragulardrop,r,o,t.source,t.sourceModel,t.initialIndex,t.targetModel,u)}if(_(ge).forEach(function(e){i(e,"off","mousedown",A),i(e,"on","mousedown",A)}),ge.compileItemOnDrop){var a=angular.element(o).scope?angular.element(o).scope():ge.scope;a&&a.$applyAsync(function(){var e=n(t.copy?l.cloneNode(!0):l)(a);r.parentNode===o&&o.removeChild(r),o.insertBefore(e[0],c),le()})}ge.scope&&e(ge.scope),t.targetCtx&&t.targetCtx.o.scope&&t.targetCtx.o.scope!==ge.scope&&e(t.targetCtx.o.scope),ge.compileItemOnDrop||le()}if(!r)return void le();var l=t.sourceItem,c=t.currentSibling,u=N(r,o);t.copy&&o===t.source&&E(r)&&he(ge.copySortSource)&&r.parentNode.removeChild(t.sourceItem),t.sourceModel&&!J(o)?(t.targetCtx&&t.targetCtx.fm&&(u=t.targetCtx.m.indexOf(t.targetCtx.fm[u])),t.sourceFilteredModel&&(t.initialIndex=t.sourceModel.indexOf(t.sourceFilteredModel[t.initialIndex])),e.$applyAsync(function(){t.sourceModel&&(o===t.source?t.sourceModel.splice(u,0,t.sourceModel.splice(t.initialIndex,1)[0]):(t.dropElmModel=t.copy&&!ge.dontCopyModel?angular.copy(t.sourceModel[t.initialIndex]):t.sourceModel[t.initialIndex],t.tempModel?t.targetModel=t.tempModel:t.targetModel=t.targetCtx&&t.targetCtx.m||t.sourceModel,r.parentNode.removeChild(r),t.copy||t.sourceModel.splice(t.initialIndex,1),t.targetModel&&t.targetModel.splice(u,0,t.dropElmModel)),E(r)&&r.parentNode.removeChild(r),a())})):a()}function ae(){if(Me.dragging){var n=E(t.item);n&&n.removeChild(t.item),t.sourceModel&&e.$applyAsync(function(){t.sourceModel.splice(t.initialIndex,1),le()}),ge.scope&&ge.scope.$emit(t.copy?ge.eventNames.dragularcancel:ge.eventNames.dragularremove,t.item,n,t.sourceModel,t.initialIndex),t.sourceModel||le()}}function le(){W(),me(),t.item&&C(t.item,ge.classes.transit),Me.dragging=!1,he(ge.removeOnSpill)===!0&&q(),ge.scope&&(t.lastDropTarget&&ge.scope.$emit(ge.eventNames.dragularout,t.item,t.lastDropTarget,t.source),ge.scope.$emit(ge.eventNames.dragulardragend,t.item)),t.source=t.item=t.sourceItem=t.initialSibling=t.currentSibling=t.sourceModel=null,t.initialIndex=t.currentIndex=t.lastDropTarget=t.tempModel=t.targetModel=null,t.dropElmModel=t.targetCtx=t.copy=t.moveX=t.moveY=null}function ce(){$(!0),se(ge.containers),oe({})}function ue(e,n,r){e&&(n=n||ee(ge)||{},r=r||ne(ge)||{},e=T(e)?e:c(e),e.forEach(function(e){angular.forEach(ge.nameSpace,function(o){if(!(t.containers[o].indexOf(e)>-1)){var a=t.containers[o].push(e)-1;t.containersCtx[o].push({o:ge,m:n[a],fm:r[a]}),i(e,"off","mousedown",A),i(e,"on","mousedown",A)}})}))}function se(n){e.$applyAsync(function(){n=T(n)?n:c(n),n.forEach(function(e){angular.forEach(ge.nameSpace,function(n){var r;r=t.containers[n].indexOf(e),t.containers[n].splice(r,1),t.containersCtx[n].splice(r,1)})})})}function de(e){if(t.target){e.originalEvent&&(e=e.originalEvent);var n=t.target.scrollTop;t.target.scrollTop+=e.deltaY,n!==t.target.scrollTop&&(e.stopPropagation(),e.preventDefault())}}function me(){t.mirror&&(C(O.body,ge.classes.unselectable),i(w,"off","mousemove",z),i(t.mirror,"off","wheel",de),E(t.mirror)&&t.mirror.parentNode.removeChild(t.mirror),t.mirror=null)}function fe(e){o(e,!0,ge.scope)}var ge,pe=r||[],ve=d||{},he=Y,xe={mirror:"gu-mirror",hide:"gu-hide",unselectable:"gu-unselectable",transit:"gu-transit"},ye={dragularenter:"dragularenter",dragularleave:"dragularleave",dragularrelease:"dragularrelease",dragularcloned:"dragularcloned",dragulardrag:"dragulardrag",dragularcancel:"dragularcancel",dragulardrop:"dragulardrop",dragularremove:"dragularremove",dragulardragend:"dragulardragend",dragularshadow:"dragularshadow",dragularover:"dragularover",dragularout:"dragularout"},Ce={copyOptions:!1,classes:xe,eventNames:ye,containers:!1,containersModel:!1,containersFilteredModel:!1,isContainer:a,isContainerModel:p,isContainerAccepts:l,moves:l,accepts:l,canBeAccepted:l,copy:!1,copySortSource:!1,dontCopyModel:!1,invalid:a,revertOnSpill:!1,removeOnSpill:!1,lockX:!1,lockY:!1,boundingBox:!1,mirrorContainer:O.body,ignoreInputTextSelection:!0,compileItemOnDrop:!1,onInit:!1},Me={containers:t.containers,containersCtx:t.containersCtx,sanitizeContainersModel:fe,sanitizeContainers:o,addContainers:ue,removeContainers:se,isContainer:Z,start:P,end:R,cancel:re,remove:ae,destroy:ce,dragging:!1};return x(),M(),I(),$(),ge.onInit&&ge.onInit(Me,ge),Me}function o(e,n,t){if(B(e))return e;if(T(e))return n?T(e[0])?e:[e]:e;if("string"==typeof e&&t){var r=t.$eval(e);return B(r)?r:function(){return t.$eval(e)}}return e?c(e):[]}function i(e,n,t,r){var o={mouseup:"touchend",mousedown:"touchstart",mousemove:"touchmove"},i={mouseup:"pointerup",mousedown:"pointerdown",mousemove:"pointermove"},a={mouseup:"MSPointerUp",mousedown:"MSPointerDown",mousemove:"MSPointerMove"},l=angular.element(e);if(e.addEventListener){var c={on:"addEventListener",off:"removeEventListener"};e[c[n]](t,r,{passive:!1}),e[c[n]](o[t],r,{passive:!1})}else"undefined"!=typeof navigator&&navigator.pointerEnabled&&i[t]?l[n](i[t],r):"undefined"!=typeof navigator&&navigator.msPointerEnabled&&a[t]?l[n](a[t],r):o[t]&&l[n](o[t],r),l[n](t,r)}function a(){return!1}function l(){return!0}function c(e,n){return T(e)?e:e.length?Array.prototype.slice.call(e,n):[e]}function u(e){if(e.touches)return e.touches.length;if(e.originalEvent&&e.originalEvent.touches)return e.originalEvent.touches.length;if(void 0!==e.which&&0!==e.which)return e.which;if(void 0!==e.buttons)return e.buttons;var n=e.button;return void 0!==n?1&n?1:2&n?3:4&n?2:0:void 0}function s(e){e.originalEvent&&(e=e.originalEvent),t.grabbed&&e.preventDefault()}function d(e,n){return"undefined"!=typeof window[n]?window[n]:w.clientHeight?w[e]:O.body[e]}function m(e){var n=e.getBoundingClientRect(),t=d("scrollTop","pageYOffset"),r=d("scrollLeft","pageXOffset");return{left:n.left+r,right:n.right+r,top:n.top+t,bottom:n.bottom+t}}function f(e){return e.width||e.right-e.left}function g(e){return e.height||e.bottom-e.top}function p(){return[]}function v(e){function n(){var n=e;do n=n.nextSibling;while(n&&1!==n.nodeType);return n}if(e)return e.nextElementSibling||n()}function h(e){return"object"==typeof HTMLElement?e instanceof HTMLElement:e&&"object"==typeof e&&null!==e&&1===e.nodeType&&"string"==typeof e.nodeName}function x(e){var n=t.classesCache[e];return n?n.lastIndex=0:t.classesCache[e]=n=new RegExp("(?:^|\\s)"+e+"(?:\\s|$)","g"),n}function y(e,n){var t=e.className;t.length?x(n).test(t)||(e.className+=" "+n):e.className=n}function C(e,n){e.className=e.className.replace(x(n)," ").trim()}function M(e){return e.targetTouches&&e.targetTouches.length?e.targetTouches[0]:e.changedTouches&&e.changedTouches.length?e.changedTouches[0]:e}function b(e,n){var t=M(n),r={pageX:"clientX",pageY:"clientY"};return e in r&&!(e in t)&&r[e]in t&&(e=r[e]),!t.type||t.type.indexOf("touch")<0?t[e]:t.type.indexOf("end")===-1&&t.originalEvent.touches[0][e.replace("client","page")]}function E(e){return e.parentNode===document?null:e.parentNode}function S(e){return"INPUT"===e.tagName||"TEXTAREA"===e.tagName||"SELECT"===e.tagName||I(e)}function I(e){return!!e&&("false"!==e.contentEditable&&("true"===e.contentEditable||I(E(e))))}function N(e,n){return Array.prototype.indexOf.call(angular.element(n).children(),e)}function X(e,n,r){e&&(t.extra=r,e.dispatchEvent?e.dispatchEvent(n):e.fireEvent("on"+n.eventType,n))}function Y(e,n,r){return B(e)?!!e.apply(r||this,n||t):!!e}var O=document,w=O.documentElement,T=Array.isArray,B=angular.isFunction;return r.cleanEnviroment=function(){t.classesCache={},t.containersCtx={},t.containers={},t.mirror=void 0},r.shared=t,r};r.$inject=["$rootScope","$compile"],e.exports=r}])});
2 | //# sourceMappingURL=dragular.min.js.map
3 |
--------------------------------------------------------------------------------