├── HEAD ├── .jshintignore ├── config ├── description ├── docs ├── favicon.ico ├── src │ ├── examples │ │ ├── exampleBasic │ │ │ ├── exampleBasic.css │ │ │ ├── exampleBasic.js │ │ │ └── exampleBasic.html │ │ ├── partials │ │ │ ├── partial-contribute.html │ │ │ ├── partial-docs.html │ │ │ ├── partial-home.html │ │ │ └── autogenerated │ │ │ │ └── contribute.html │ │ ├── exampleNestedRepeatsWithCustomDirective │ │ │ ├── exampleNestedRepeatsWithCustomDirective.css │ │ │ ├── exampleNestedRepeatsWithCustomDirective.html │ │ │ └── exampleNestedRepeatsWithCustomDirective.js │ │ ├── exampleCopy │ │ │ ├── exampleCopy.js │ │ │ └── exampleCopy.html │ │ ├── exampleDirective │ │ │ ├── exampleDirective.js │ │ │ └── exampleDirective.html │ │ ├── exampleRemoveOnSpill │ │ │ ├── exampleRemoveOnSpill.js │ │ │ └── exampleRemoveOnSpill.html │ │ ├── exampleRevertOnSpill │ │ │ ├── exampleRevertOnSpill.js │ │ │ └── exampleRevertOnSpill.html │ │ ├── exampleBoundingBox │ │ │ ├── exampleBoundingBox.js │ │ │ └── exampleBoundingBox.html │ │ ├── exampleCustomClasses │ │ │ ├── exampleCustomClasses.js │ │ │ └── exampleCustomClasses.html │ │ ├── exampleHandle │ │ │ ├── exampleHandle.js │ │ │ └── exampleHandle.html │ │ ├── exampleBoundingBoxLockX │ │ │ ├── exampleBoundingBoxLockX.js │ │ │ └── exampleBoundingBoxLockX.html │ │ ├── exampleBoundingBoxLockY │ │ │ ├── exampleBoundingBoxLockY.js │ │ │ └── exampleBoundingBoxLockY.html │ │ ├── exampleDragOverEvents │ │ │ ├── exampleDragOverEvents.css │ │ │ ├── exampleDragOverEvents.js │ │ │ └── exampleDragOverEvents.html │ │ ├── exampleScrollingDrag │ │ │ ├── exampleScrollingDrag.css │ │ │ ├── exampleScrollingDrag.js │ │ │ └── exampleScrollingDrag.html │ │ ├── exampleNameSpaces │ │ │ ├── exampleNameSpaces.js │ │ │ └── exampleNameSpaces.html │ │ ├── docsInstall │ │ │ └── docsInstall.html │ │ ├── exampleDirectiveWithModel │ │ │ ├── exampleDirectiveWithModel.js │ │ │ └── exampleDirectiveWithModel.html │ │ ├── exampleCopyWithModel │ │ │ ├── exampleCopyWithModel.js │ │ │ └── exampleCopyWithModel.html │ │ ├── exampleNgRepeat │ │ │ ├── exampleNgRepeat.js │ │ │ └── exampleNgRepeat.html │ │ ├── exampleNgRepeatWithModel │ │ │ ├── exampleNgRepeatWithModel.js │ │ │ └── exampleNgRepeatWithModel.html │ │ ├── exampleRemoveOnSpillWithModel │ │ │ ├── exampleRemoveOnSpillWithModel.js │ │ │ └── exampleRemoveOnSpillWithModel.html │ │ ├── exampleIsContainerWithModel │ │ │ ├── exampleIsContainerWithModel.js │ │ │ └── exampleIsContainerWithModel.html │ │ ├── examplesRouter.js │ │ ├── exampleNestedNgRepeat │ │ │ ├── exampleNestedNgRepeat.js │ │ │ └── exampleNestedNgRepeat.html │ │ ├── exampleDifferentOptionsWithModel │ │ │ ├── exampleDifferentOptionsWithModel.js │ │ │ └── exampleDifferentOptionsWithModel.html │ │ ├── exampleBasicWithModel │ │ │ ├── exampleBasicWithModel.js │ │ │ └── exampleBasicWithModel.html │ │ ├── exampleEvents │ │ │ ├── exampleEvents.js │ │ │ └── exampleEvents.html │ │ ├── exampleNgRepeatFilteredWithModel │ │ │ ├── exampleNgRepeatFilteredWithModel.js │ │ │ └── exampleNgRepeatFilteredWithModel.html │ │ ├── exampleNestedNgRepeatWithModel │ │ │ ├── exampleNestedNgRepeatWithModel.js │ │ │ └── exampleNestedNgRepeatWithModel.html │ │ ├── examplesApp.css │ │ └── examplesApp.js │ └── vendor │ │ ├── highlight.github.css │ │ └── highlight.pack.js └── index.html ├── resources ├── demo.png └── eyes.png ├── .gitignore ├── .csslintrc ├── .editorconfig ├── dist ├── dragular.min.css ├── dragular.css └── dragular.min.js ├── src ├── dragularSource.css ├── dragularModule.js └── dragularDirective.js ├── .jshintrc ├── .codeclimate.yml ├── bower.json ├── license ├── CODE_OF_CONDUCT.md ├── package.json ├── CONTRIBUTING.md ├── .eslintrc ├── .vscode └── tasks.json ├── gulpfile.js └── CHANGELOG.md /HEAD: -------------------------------------------------------------------------------- 1 | ref: refs/heads/master 2 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | dist 4 | highlight.pack.js -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | [core] 2 | repositoryformatversion = 0 3 | filemode = true 4 | bare = true 5 | -------------------------------------------------------------------------------- /description: -------------------------------------------------------------------------------- 1 | Unnamed repository; edit this file 'description' to name the repository. 2 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luckylooke/dragular/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /resources/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luckylooke/dragular/HEAD/resources/demo.png -------------------------------------------------------------------------------- /resources/eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luckylooke/dragular/HEAD/resources/eyes.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | Thumbs.db 5 | .publish 6 | .idea 7 | bower_components 8 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBasic/exampleBasic.css: -------------------------------------------------------------------------------- 1 | .clickedClass { 2 | background-color: orange !important; 3 | } 4 | -------------------------------------------------------------------------------- /.csslintrc: -------------------------------------------------------------------------------- 1 | --exclude-exts=.min.css 2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes 3 | -------------------------------------------------------------------------------- /docs/src/examples/partials/partial-contribute.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /dist/dragular.min.css: -------------------------------------------------------------------------------- 1 | .gu-mirror{position:fixed!important;margin:0!important;z-index:9999!important;opacity:.8}.gu-hide{display:none!important}.gu-unselectable{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.gu-transit{opacity:.2} -------------------------------------------------------------------------------- /docs/src/examples/exampleBasic/exampleBasic.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BasicCtrl = function ($element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService('.container-vertical'); 6 | }; 7 | 8 | BasicCtrl.$inject = ['$element', 'dragularService']; 9 | 10 | module.exports = BasicCtrl; 11 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNestedRepeatsWithCustomDirective/exampleNestedRepeatsWithCustomDirective.css: -------------------------------------------------------------------------------- 1 | 2 | .app div { 3 | min-width: 200px; 4 | padding: 10px 5 | } 6 | 7 | .can-be-empty { 8 | min-height: 50px; 9 | min-width: 200px; 10 | } 11 | 12 | .item, 13 | .subitem{ 14 | border: 1px solid blue; 15 | } -------------------------------------------------------------------------------- /docs/src/examples/exampleCopy/exampleCopy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var CopyCtrl = function ($element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService($element.children(), { 6 | copy: true 7 | }); 8 | }; 9 | 10 | CopyCtrl.$inject = ['$element', 'dragularService']; 11 | 12 | module.exports = CopyCtrl; 13 | -------------------------------------------------------------------------------- /src/dragularSource.css: -------------------------------------------------------------------------------- 1 | .gu-mirror { 2 | position: fixed !important; 3 | margin: 0 !important; 4 | z-index: 9999 !important; 5 | opacity: 0.8; 6 | } 7 | 8 | .gu-hide { 9 | display: none !important; 10 | } 11 | 12 | .gu-unselectable { 13 | user-select: none !important; 14 | } 15 | 16 | .gu-transit { 17 | opacity: 0.2; 18 | } 19 | -------------------------------------------------------------------------------- /docs/src/examples/exampleDirective/exampleDirective.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var DirectiveCtrl = function ($scope) { 4 | $scope.dragularOptions = { 5 | classes: { 6 | mirror: 'custom-green-mirror' 7 | }, 8 | nameSpace: 'same' // just connecting left and right container 9 | }; 10 | }; 11 | 12 | DirectiveCtrl.$inject = ['$scope']; 13 | 14 | module.exports = DirectiveCtrl; 15 | -------------------------------------------------------------------------------- /docs/src/examples/exampleRemoveOnSpill/exampleRemoveOnSpill.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var RemoveOnSpillCtrl = function ($element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService($element.children(), { 6 | removeOnSpill: true 7 | }); 8 | }; 9 | 10 | RemoveOnSpillCtrl.$inject = ['$element', 'dragularService']; 11 | 12 | module.exports = RemoveOnSpillCtrl; 13 | -------------------------------------------------------------------------------- /docs/src/examples/exampleRevertOnSpill/exampleRevertOnSpill.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var RevertOnSpillCtrl = function ($element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService($element.children(), { 6 | revertOnSpill: true 7 | }); 8 | }; 9 | 10 | RevertOnSpillCtrl.$inject = ['$element', 'dragularService']; 11 | 12 | module.exports = RevertOnSpillCtrl; 13 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBoundingBox/exampleBoundingBox.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BoundingBoxCtrl = function ($element, dragularService) { 4 | var boundingBox = $element[0]; 5 | dragularService.cleanEnviroment(); 6 | 7 | dragularService($element.children(), { 8 | boundingBox: boundingBox 9 | }); 10 | }; 11 | 12 | BoundingBoxCtrl.$inject = ['$element', 'dragularService']; 13 | 14 | module.exports = BoundingBoxCtrl; 15 | -------------------------------------------------------------------------------- /docs/src/examples/exampleCustomClasses/exampleCustomClasses.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var CustomClassesCtrl = function ($element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService($element.children(), { 6 | classes: { 7 | mirror: 'custom-green-mirror' 8 | } 9 | }); 10 | }; 11 | 12 | CustomClassesCtrl.$inject = ['$element', 'dragularService']; 13 | 14 | module.exports = CustomClassesCtrl; 15 | -------------------------------------------------------------------------------- /docs/src/examples/exampleHandle/exampleHandle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var HandleCtrl = function ($element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService($element.children(), { 6 | moves: function(el, container, handle) { 7 | return handle.classList.contains('handle'); 8 | } 9 | }); 10 | }; 11 | 12 | HandleCtrl.$inject = ['$element', 'dragularService']; 13 | 14 | module.exports = HandleCtrl; 15 | -------------------------------------------------------------------------------- /dist/dragular.css: -------------------------------------------------------------------------------- 1 | .gu-mirror { 2 | position: fixed !important; 3 | margin: 0 !important; 4 | z-index: 9999 !important; 5 | opacity: 0.8; 6 | } 7 | 8 | .gu-hide { 9 | display: none !important; 10 | } 11 | 12 | .gu-unselectable { 13 | -webkit-user-select: none !important; 14 | -moz-user-select: none !important; 15 | -ms-user-select: none !important; 16 | user-select: none !important; 17 | } 18 | 19 | .gu-transit { 20 | opacity: 0.2; 21 | } 22 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "newcap": true, 5 | "noarg": true, 6 | "noempty": true, 7 | "nonew": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "trailing": true, 12 | "boss": true, 13 | "eqnull": true, 14 | "strict": true, 15 | "immed": true, 16 | "expr": true, 17 | "latedef": "nofunc", 18 | "quotmark": "single", 19 | "validthis": true, 20 | "indent": 2, 21 | "node": true, 22 | "browser": true 23 | } 24 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBoundingBoxLockX/exampleBoundingBoxLockX.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BoundingBoxLockXCtrl = function ($element, dragularService) { 4 | var boundingBox = $element.children().children()[0]; 5 | dragularService.cleanEnviroment(); 6 | dragularService(boundingBox, { 7 | boundingBox: boundingBox, 8 | lockX: true 9 | }); 10 | }; 11 | 12 | BoundingBoxLockXCtrl.$inject = ['$element', 'dragularService']; 13 | 14 | module.exports = BoundingBoxLockXCtrl; 15 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBoundingBoxLockY/exampleBoundingBoxLockY.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var BoundingBoxLockYCtrl = function ($element, dragularService) { 4 | var boundingBox = $element.children().children()[0]; 5 | dragularService.cleanEnviroment(); 6 | dragularService(boundingBox, { 7 | boundingBox: boundingBox, 8 | lockY: true 9 | }); 10 | }; 11 | 12 | BoundingBoxLockYCtrl.$inject = ['$element', 'dragularService']; 13 | 14 | module.exports = BoundingBoxLockYCtrl; 15 | -------------------------------------------------------------------------------- /docs/src/examples/exampleDragOverEvents/exampleDragOverEvents.css: -------------------------------------------------------------------------------- 1 | .notContainer { 2 | width: 100%; 3 | padding: 1em; 4 | margin-top: 1em; 5 | margin-bottom: 1em; 6 | text-align: center; 7 | background-color: rgba(0, 0, 0, 0.2); 8 | } 9 | 10 | .notContainer.gu-over { 11 | background-color: yellow; 12 | } 13 | 14 | .container-vertical.gu-over-accept { 15 | background-color: green; 16 | } 17 | 18 | .container-vertical.gu-over-decline { 19 | background-color: red; 20 | } 21 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | csslint: 4 | enabled: true 5 | duplication: 6 | enabled: true 7 | config: 8 | languages: 9 | - ruby 10 | - javascript 11 | - python 12 | - php 13 | eslint: 14 | enabled: true 15 | fixme: 16 | enabled: true 17 | ratings: 18 | paths: 19 | - "**.css" 20 | - "**.inc" 21 | - "**.js" 22 | - "**.jsx" 23 | - "**.module" 24 | - "**.php" 25 | - "**.py" 26 | - "**.rb" 27 | exclude_paths: 28 | - /docs/src/vendor 29 | -------------------------------------------------------------------------------- /src/dragularModule.js: -------------------------------------------------------------------------------- 1 | /* global angular */ 2 | 'use strict'; 3 | var dragularDirective = require( './dragularDirective' ); 4 | var dragularService = require( './dragularService' ); 5 | 6 | /** 7 | * Dragular 4.6.0 by Luckylooke https://github.com/luckylooke/dragular 8 | * Angular version of dragula https://github.com/bevacqua/dragula 9 | */ 10 | module.exports = 'dragularModule'; 11 | 12 | angular 13 | .module( 'dragularModule', [] ) 14 | .factory( 'dragularService', dragularService ) 15 | .directive( 'dragular', dragularDirective ); 16 | -------------------------------------------------------------------------------- /docs/src/examples/exampleScrollingDrag/exampleScrollingDrag.css: -------------------------------------------------------------------------------- 1 | .scrollingDrag { 2 | width: 45%; 3 | display: inline-block; 4 | } 5 | 6 | .scrollingDragInner { 7 | max-height: 200px; 8 | overflow-y: auto; 9 | } 10 | 11 | #rightTopBar, 12 | #rightBottomBar { 13 | background: transparent; 14 | position: relative; 15 | height: 20px; 16 | } 17 | 18 | #rightTopBar { 19 | top: 10px; 20 | } 21 | 22 | #rightBottomBar { 23 | bottom: 10px; 24 | } 25 | 26 | div.scrollBar { 27 | background: yellow; 28 | text-align: center; 29 | padding: 1px; 30 | } 31 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNameSpaces/exampleNameSpaces.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var NameSpacesCtrl = function ($element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService([$element.children()[0], $element.children()[2]], { 6 | nameSpace: 'apples' 7 | }); 8 | dragularService($element.children()[1], { 9 | nameSpace: 'oranges' 10 | }); 11 | dragularService($element.children()[3], { // mixed 12 | nameSpace: ['oranges', 'apples'] 13 | }); 14 | }; 15 | 16 | NameSpacesCtrl.$inject = ['$element', 'dragularService']; 17 | 18 | module.exports = NameSpacesCtrl; 19 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNestedRepeatsWithCustomDirective/exampleNestedRepeatsWithCustomDirective.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{item.order}}: ({{item.name}} + {{item.age}}) 5 |
6 | 7 | 8 |
9 |
10 |
11 |
12 | 13 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dragular", 3 | "version": "4.6.0", 4 | "description": "Angular drag and drop library based on dragula, but full featured. For light-weight angular wrap of dragula look for angular-dragula", 5 | "main": [ 6 | "dist/dragular.js", 7 | "dist/dragular.css" 8 | ], 9 | "dependencies": { 10 | "angular": "1.x" 11 | }, 12 | "ignore": [ 13 | "node_modules", 14 | "bower_components", 15 | ".publish" 16 | ], 17 | "homepage": "http://luckylooke.github.io/dragular/", 18 | "authors": [ 19 | "Ctibor Laky " 20 | ], 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /docs/src/examples/exampleHandle/exampleHandle.html: -------------------------------------------------------------------------------- 1 |
2 |

Handle

3 | 4 |
5 |
6 |
+Move me, but you can use the plus sign to drag me around.
7 |
8 |
9 |
10 |
11 |
12 |         
13 |   dragularService([document.getElementById(left), document.getElementById(right)], {
14 |     moves: function (el, container, handle) {
15 |       return handle.className === 'handle';
16 |     }
17 |   });
18 |         
19 |       
20 |
21 | -------------------------------------------------------------------------------- /docs/src/examples/docsInstall/docsInstall.html: -------------------------------------------------------------------------------- 1 |

Install

2 |

download dragular.js and dragular.css from dist folder

3 |

OR clone git

4 |

 5 | git clone http://github.com/luckylooke/dragular.git
 6 | 
7 |

OR use npm

8 |

 9 | [sudo] npm install dragular
10 | 
11 |

OR use bower

12 |

13 | bower install dragular
14 | 
15 |

AND include files into your project

16 |

17 | <link href="styles/dragular.css" rel="stylesheet" type="text/css" />
18 | <script src="scripts/dragular.js"></script>
19 | 
20 |

AND put dragularModule into dependency array

21 |

22 | var app = angular.module("myApp", ["dragularModule", "otherDependencies"]);
23 | 
24 |

DONE :)

25 | -------------------------------------------------------------------------------- /docs/src/examples/partials/partial-docs.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 8 | 9 |
10 |

11 | 12 |

13 | 14 |
15 |
16 | 17 |
18 | 19 |
20 | -------------------------------------------------------------------------------- /docs/src/examples/exampleDirectiveWithModel/exampleDirectiveWithModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var DirectiveModelCtrl = function ($scope) { 4 | $scope.items1 = [{ 5 | content: 'Move me, and make copy on drop.' 6 | }, { 7 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.' 8 | }, { 9 | content: 'Item 3' 10 | }, { 11 | content: 'Item 4' 12 | }]; 13 | $scope.items2 = [{ 14 | content: 'Item 5' 15 | }, { 16 | content: 'Item 6' 17 | }, { 18 | content: 'Item 7' 19 | }, { 20 | content: 'Item 8' 21 | }]; 22 | $scope.dragularOptions = { 23 | containersModel: $scope.items1, 24 | classes: { 25 | mirror: 'custom-green-mirror' 26 | }, 27 | nameSpace: 'common' // just connecting left and right container 28 | }; 29 | }; 30 | 31 | DirectiveModelCtrl.$inject = ['$scope']; 32 | 33 | module.exports = DirectiveModelCtrl; 34 | -------------------------------------------------------------------------------- /docs/src/examples/exampleCopyWithModel/exampleCopyWithModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var CopyModelCtrl = function ($scope, $element, dragularService) { 4 | $scope.items1 = [{ 5 | content: 'Move me, and make copy on drop.' 6 | }, { 7 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.' 8 | }, { 9 | content: 'Item 3' 10 | }, { 11 | content: 'Item 4' 12 | }]; 13 | $scope.items2 = [{ 14 | content: 'Item 5' 15 | }, { 16 | content: 'Item 6' 17 | }, { 18 | content: 'Item 7' 19 | }, { 20 | content: 'Item 8' 21 | }]; 22 | var containers = $element.children().eq(0).children(); 23 | dragularService.cleanEnviroment(); 24 | dragularService([containers[0],containers[1]],{ 25 | containersModel: [$scope.items1, $scope.items2], 26 | copy: true 27 | }); 28 | }; 29 | 30 | CopyModelCtrl.$inject = ['$scope', '$element', 'dragularService']; 31 | 32 | module.exports = CopyModelCtrl; 33 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNgRepeat/exampleNgRepeat.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var NgRepeatCtrl = function ($scope, $element, dragularService) { 4 | dragularService.cleanEnviroment(); 5 | dragularService($element.children()); 6 | $scope.items = [{ 7 | content: 'Try to add or remove some elements (click on +- buttons), you will see that it is not problem for dragular.' 8 | }, { 9 | content: 'Item 2' 10 | }, { 11 | content: 'Item 3' 12 | }, { 13 | content: 'Item 4' 14 | }]; 15 | $scope.addItem = function addItem() { 16 | var index = $scope.items.indexOf(this.item) + 1; 17 | $scope.items.splice(index, 0, { 18 | content: this.item.content + '-copy' 19 | }); 20 | }; 21 | $scope.removeItem = function removeItem() { 22 | var index = $scope.items.indexOf(this.item); 23 | $scope.items.splice(index, 1); 24 | }; 25 | }; 26 | 27 | NgRepeatCtrl.$inject = ['$scope', '$element', 'dragularService']; 28 | 29 | module.exports = NgRepeatCtrl; 30 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNgRepeatWithModel/exampleNgRepeatWithModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var NgRepeatWithModelCtrl = function ($scope, $element, dragularService) { 4 | $scope.items = [{ 5 | content: 'Try to add or remove some elements (click on +- buttons), you will see that it is not problem for dragular.' 6 | }, { 7 | content: 'Item 2' 8 | }, { 9 | content: 'Item 3' 10 | }, { 11 | content: 'Item 4' 12 | }]; 13 | dragularService.cleanEnviroment(); 14 | dragularService($element.children().eq(0).children(), {containersModel: $scope.items}); 15 | $scope.addItem = function addItem() { 16 | var index = $scope.items.indexOf(this.item) + 1; 17 | $scope.items.splice(index, 0, { 18 | content: this.item.content + '-copy' 19 | }); 20 | }; 21 | $scope.removeItem = function removeItem() { 22 | var index = $scope.items.indexOf(this.item); 23 | $scope.items.splice(index, 1); 24 | }; 25 | }; 26 | 27 | NgRepeatWithModelCtrl.$inject = ['$scope', '$element', 'dragularService']; 28 | 29 | module.exports = NgRepeatWithModelCtrl; 30 | -------------------------------------------------------------------------------- /docs/src/examples/exampleRemoveOnSpillWithModel/exampleRemoveOnSpillWithModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var RemoveOnSpillWithModelCtrl = function ($scope, $element, dragularService) { 4 | $scope.items1 = [{ 5 | content: 'Move me, but you can only drop me in containers.' 6 | }, { 7 | content: 'If you try to drop me somewhere other than containers, I\'ll die a fiery death.' 8 | }, { 9 | content: 'Item 3' 10 | }, { 11 | content: 'Item 4' 12 | }]; 13 | $scope.items2 = [{ 14 | content: 'You can drop me in the left container.' 15 | }, { 16 | content: 'Item 6' 17 | }, { 18 | content: 'Item 7' 19 | }, { 20 | content: 'Item 8' 21 | }]; 22 | var containers = $element.children().eq(0).children(); 23 | dragularService.cleanEnviroment(); 24 | dragularService([containers[0], containers[1]], { 25 | containersModel: [$scope.items1, $scope.items2], 26 | removeOnSpill: true 27 | }); 28 | }; 29 | 30 | RemoveOnSpillWithModelCtrl.$inject = ['$scope', '$element', 'dragularService']; 31 | 32 | module.exports = RemoveOnSpillWithModelCtrl; 33 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBoundingBox/exampleBoundingBox.html: -------------------------------------------------------------------------------- 1 |
2 |

BoundingBox

3 | 4 |
5 |
6 |
This items cannot cross its example element, just try it your selves.
7 |
Item 2.
8 |
Item 3.
9 |
Item 6.
10 |
11 |
12 |
This items cannot cross its example element, just try it your selves.
13 |
Item 4.
14 |
Item 5.
15 |
16 |
17 |
18 |         
19 |   dragularService([$element.children(), {
20 |     boundingBox: $element
21 |   });
22 |         
23 |       
24 |
-------------------------------------------------------------------------------- /docs/src/examples/exampleBoundingBoxLockX/exampleBoundingBoxLockX.html: -------------------------------------------------------------------------------- 1 |
2 |

BoundingBox and lockX

3 | 4 |
5 |
6 |
7 |
Items are locked in X axis movement and cannot cross its closest parent div.boundingBox, just try it your selves.
8 |
item 2
9 |
item 3
10 |
item 4
11 |
12 |
13 |
14 |
15 |         
16 |   dragularService([$element.children()[0].children(), {
17 |     boundingBox: $element.children()[0],
18 |     lockX: true
19 |   });
20 |         
21 |       
22 |
23 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNgRepeat/exampleNgRepeat.html: -------------------------------------------------------------------------------- 1 |
2 |

ngRepeat

3 | 4 |
5 |
6 |
7 | {{item.content}} 8 |
9 |
10 |
11 |
12 |         
13 |   // HTML:
14 |   <div class="container-vertical">
15 |     <div ng-repeat="item in items">
16 |       {{item.content}}
17 |     </div>
18 |   </div>
19 | 
20 |   // JS:
21 |   dragularService($element.children());
22 |   $scope.items = [{
23 |     content: 'Try to add or remove some elements (click on +- buttons), you will see that it is not problem for dragular.'
24 |   },{
25 |     content: 'Item 2'
26 |   },{
27 |     content: 'Item 3'
28 |   },{
29 |     content: 'Item 4'
30 |   }];
31 |         
32 |       
33 |
34 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2015 Ctibor Laky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBoundingBoxLockY/exampleBoundingBoxLockY.html: -------------------------------------------------------------------------------- 1 |
2 |

BoundingBox and LockY

3 | 4 |
5 |
6 |
7 |
Items are locked in Y axis movement and cannot cross its closest parent div.boundingBox, just try it your selves.
8 |
item 2
9 |
item 3
10 |
item 4
11 |
item 5
12 |
item 6
13 |
14 |
15 |
16 |
17 |         
18 |   dragularService([$element.children()[0].children(), {
19 |     boundingBox: $element.children()[0],
20 |     lockY: true
21 |   });
22 |         
23 |       
24 |
-------------------------------------------------------------------------------- /docs/src/examples/exampleRemoveOnSpill/exampleRemoveOnSpill.html: -------------------------------------------------------------------------------- 1 |
2 |

Remove on spill

3 | 4 |
5 |
6 |
Move me, but you can only drop me in containers.
7 |
If you try to drop me somewhere other than containers, I'll die a fiery death.
8 |
Item 3.
9 |
Item 6.
10 |
Item 4.
11 |
Item 5.
12 |
13 | 18 |
19 |
20 |         
21 |   dragularService([document.getElementById(single)], { removeOnSpill: true });
22 |         
23 |       
24 |
25 | -------------------------------------------------------------------------------- /docs/src/examples/exampleIsContainerWithModel/exampleIsContainerWithModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var IsContainerModelCtrl = function ($scope, $element, dragularService) { 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: 'Item 3' 10 | }, { 11 | content: 'Item 4' 12 | }]; 13 | $scope.cartModel = []; 14 | 15 | var containerLeft = document.querySelector('#containerLeft'); 16 | 17 | dragularService.cleanEnviroment(); 18 | dragularService([containerLeft], { 19 | containersModel: [$scope.items1], 20 | copy: true, 21 | isContainer: function isContainer (el) { 22 | return el.id === 'cart'; 23 | }, 24 | isContainerModel: function getModel (){ 25 | return $scope.cartModel; 26 | } 27 | }); 28 | 29 | $scope.removeItem = function removeItem() { 30 | var index = $scope.cartModel.indexOf(this.item); 31 | $scope.cartModel.splice(index, 1); 32 | }; 33 | }; 34 | 35 | IsContainerModelCtrl.$inject = ['$scope', '$element', 'dragularService']; 36 | 37 | module.exports = IsContainerModelCtrl; 38 | -------------------------------------------------------------------------------- /src/dragularDirective.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * dragular Directive by Luckylooke https://github.com/luckylooke/dragular 5 | * Angular version of dragula https://github.com/bevacqua/dragula 6 | */ 7 | 8 | var dragular = function ( dragularService ) { 9 | return { 10 | restrict: 'A', 11 | link: function ( $scope, iElm, iAttrs ) { 12 | 13 | var options = $scope.$eval( iAttrs.dragular ) || tryJson( iAttrs.dragular ) || {}; 14 | 15 | function tryJson( json ) { 16 | try { // I dont like try catch solutions but I havent find sattisfying way of chcecking json validity. 17 | return JSON.parse( json ); 18 | } catch ( e ) { 19 | return undefined; 20 | } 21 | } 22 | 23 | if ( iAttrs.dragularModel ) { 24 | options.containersModel = iAttrs.dragularModel; 25 | if ( !options.scope ){ 26 | options.scope = $scope; 27 | } 28 | } 29 | 30 | if ( iAttrs.dragularNameSpace ) { 31 | options.nameSpace = iAttrs.dragularNameSpace.split( ' ' ); 32 | } 33 | 34 | if ( iAttrs.dragularOnInit ) { 35 | options.onInit = $scope.$eval( iAttrs.dragularOnInit ); 36 | } 37 | 38 | dragularService( iElm[ 0 ], options ); 39 | } 40 | }; 41 | }; 42 | 43 | dragular.$inject = [ 'dragularService' ]; 44 | 45 | module.exports = dragular; 46 | -------------------------------------------------------------------------------- /docs/src/examples/exampleRevertOnSpill/exampleRevertOnSpill.html: -------------------------------------------------------------------------------- 1 |
2 |

Revert on spill

3 | 4 |
5 |
6 |
Move me, but you can only drop me in one of these containers.
7 |
If you try to drop me somewhere other than these containers, I'll just come back.
8 |
Item 3.
9 |
Item 6.
10 |
11 |
12 |
You can drop me in the left container, otherwise I'll stay here.
13 |
Item 4.
14 |
Item 5.
15 |
16 |
17 |
18 |         
19 |   dragularService([document.getElementById(left), document.getElementById(right)], { revertOnSpill: true });
20 |         
21 |       
22 |
23 | -------------------------------------------------------------------------------- /docs/src/examples/exampleCustomClasses/exampleCustomClasses.html: -------------------------------------------------------------------------------- 1 |
2 |

Custom classes

3 | 4 |
5 |
6 |
Move me, but you can only drop me in one of these containers.
7 |
If you try to drop me somewhere other than these containers, I'll just come back.
8 |
Item 3.
9 |
Item 6.
10 |
11 |
12 |
You can drop me in the left container, otherwise I'll stay here.
13 |
Item 4.
14 |
Item 5.
15 |
16 |
17 |
18 |         
19 |   dragularService([document.getElementById(left), document.getElementById(right)], { classes: {
20 |     mirror: 'custom-green-mirror'
21 |   } });
22 | 
23 |   // Default classes are:
24 |   option.classes = {
25 |     mirror: 'gu-mirror',
26 |     hide: 'gu-hide',
27 |     unselectable: 'gu-unselectable',
28 |     transit: 'gu-transit',
29 |     overActive: 'gu-over-active',
30 |     overAccepts: 'gu-over-accept',
31 |     overDeclines: 'gu-over-decline'
32 |   };
33 |         
34 |       
35 |
36 | -------------------------------------------------------------------------------- /docs/src/examples/examplesRouter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var examplesRouter = function ($stateProvider, $urlRouterProvider) { 4 | $urlRouterProvider.otherwise('/home'); 5 | 6 | var timer, 7 | ctrl = function routerCtrl($state, $stateParams, $timeout) { 8 | // go to install notes by default 9 | if (!$stateParams.link) { 10 | timer = $timeout(function timer() { 11 | $state.go('docs.detail', { 12 | link: 'docsInstall' 13 | }); 14 | },0); 15 | }else{ 16 | $timeout.cancel(timer); 17 | } 18 | }; 19 | 20 | ctrl.$inject = ['$state', '$stateParams', '$timeout']; 21 | 22 | $stateProvider 23 | .state('home', { 24 | url: '/home', 25 | templateUrl: '/partials/partial-home.html' 26 | }) 27 | .state('docs', { 28 | url: '/docs', 29 | templateUrl: '/partials/partial-docs.html', 30 | controller: ctrl 31 | }) 32 | .state('docs.detail', { 33 | url: '/:link', 34 | templateUrl: function($stateParams) { 35 | return '/' + $stateParams.link + '/' + $stateParams.link + '.html'; 36 | }, 37 | controller: ctrl 38 | }) 39 | .state('contribute', { 40 | url: '/contribute', 41 | templateUrl: '/partials/partial-contribute.html' 42 | }); 43 | }; 44 | 45 | examplesRouter.$inject = ['$stateProvider', '$urlRouterProvider']; 46 | 47 | module.exports = examplesRouter; 48 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) 14 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNestedNgRepeat/exampleNestedNgRepeat.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var NestedNgRepeatCtrl = function ($timeout, $scope, $element, dragularService) { 4 | $timeout(function() { // timeount due to ngRepeat to be ready 5 | dragularService.cleanEnviroment(); 6 | dragularService($element, { 7 | nameSpace: 'rows', 8 | moves: function rowOnly (el, container, handle) { 9 | return handle.classList.contains('row-handle'); 10 | } 11 | }); 12 | 13 | dragularService($element.children(), { 14 | nameSpace: 'cells', 15 | moves: function excludeHandle (el, container, handle) { 16 | return !handle.classList.contains('row-handle'); 17 | } 18 | }); 19 | }, 0); 20 | $scope.items = [{ 21 | items: [{ 22 | content: 'Item a1' 23 | }, { 24 | content: 'Item a2' 25 | }, { 26 | content: 'Item a3' 27 | }, { 28 | content: 'Item a4' 29 | }] 30 | }, { 31 | items: [{ 32 | content: 'Item b1' 33 | }, { 34 | content: 'Item b2' 35 | }, { 36 | content: 'Item b3' 37 | }, { 38 | content: 'Item b4' 39 | }] 40 | }, { 41 | items: [{ 42 | content: 'Item c1' 43 | }, { 44 | content: 'Item c2' 45 | }, { 46 | content: 'Item c3' 47 | }, { 48 | content: 'Item c4' 49 | }] 50 | }]; 51 | }; 52 | 53 | NestedNgRepeatCtrl.$inject = ['$timeout', '$scope', '$element', 'dragularService']; 54 | 55 | module.exports = NestedNgRepeatCtrl; 56 | -------------------------------------------------------------------------------- /docs/src/examples/exampleCopy/exampleCopy.html: -------------------------------------------------------------------------------- 1 |
2 |

Copy

3 | 4 |
5 |
6 |
Move me, and make copy on drop.
7 |
If you try to drop me somewhere other than these containers, I'll just come back.
8 |
9 |
10 |
You can drop me in the left container, otherwise I'll stay here.
11 |
12 |
13 |
14 |         
15 | // JS
16 |   controller("Copy", ["$element", "dragularService", function TodoCtrl($element, dragularService) {
17 |     dragularService($element.children(), {
18 |       copy: true
19 |     });
20 |   }])
21 |         
22 |         
23 | <!-- HTML -->
24 | <div class="wrapper" ng-controller="Copy" ng-hide="globals.showModelExamples">
25 |     <div id="left2" class="container-vertical">
26 |       <div>Move me, and make copy on drop.</div>
27 |       <div>If you try to drop me somewhere other than these containers, I'll just come back.</div>
28 |     </div>
29 |     <div id="right2" class="container-vertical">
30 |       <div>You can drop me in the left container, otherwise I'll stay here.</div>
31 |     </div>
32 |   </div>
33 |         
34 |       
35 |
36 | -------------------------------------------------------------------------------- /docs/src/examples/exampleScrollingDrag/exampleScrollingDrag.js: -------------------------------------------------------------------------------- 1 | /* global angular */ 2 | 'use strict'; 3 | 4 | var ScrollingDragCtrl = function ($interval, $element, dragularService) { 5 | var timer, 6 | leftScrollContainer = document.getElementById('leftScroll'), 7 | rightScrollContainer = document.getElementById('rightScroll'), 8 | leftTopBar = document.getElementById('leftTopBar'), 9 | leftBottomBar = document.getElementById('leftBottomBar'), 10 | rightTopBar = document.getElementById('rightTopBar'), 11 | rightBottomBar = document.getElementById('rightBottomBar'); 12 | 13 | dragularService.cleanEnviroment(); 14 | dragularService([leftScrollContainer, rightScrollContainer]); 15 | 16 | registerEvents(leftTopBar, leftScrollContainer, -5); 17 | registerEvents(leftBottomBar, leftScrollContainer, 5); 18 | registerEvents(rightTopBar, rightScrollContainer, -5); 19 | registerEvents(rightBottomBar, rightScrollContainer, 5); 20 | 21 | function registerEvents(bar, container, inc, speed) { 22 | if (!speed) { 23 | speed = 20; 24 | } 25 | angular.element(bar).on('dragularenter', function() { 26 | container.scrollTop += inc; 27 | timer = $interval(function moveScroll() { 28 | container.scrollTop += inc; 29 | }, speed); 30 | }); 31 | angular.element(bar).on('dragularleave dragularrelease', function() { 32 | $interval.cancel(timer); 33 | }); 34 | } 35 | }; 36 | 37 | ScrollingDragCtrl.$inject = ['$interval', '$element', 'dragularService']; 38 | 39 | module.exports = ScrollingDragCtrl; 40 | -------------------------------------------------------------------------------- /docs/src/examples/exampleDifferentOptionsWithModel/exampleDifferentOptionsWithModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var DifferentOptionsModelCtrl = function ($scope, $element, dragularService) { 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: 'Item 3' 10 | }, { 11 | content: 'Item 4' 12 | }]; 13 | $scope.items2 = [{ 14 | content: 'Item 5' 15 | }, { 16 | content: 'Item 6' 17 | }, { 18 | content: 'Item 7' 19 | }, { 20 | content: 'Item 8' 21 | }]; 22 | 23 | var containerLeft = document.querySelector('#containerLeft'), 24 | containerRight = document.querySelector('#containerRight'); 25 | 26 | function accepts(el, target, source) { 27 | // left->right || in same container 28 | if (source === containerLeft || source === target) { 29 | return true; 30 | } 31 | } 32 | 33 | dragularService.cleanEnviroment(); 34 | dragularService([containerLeft], { 35 | containersModel: [$scope.items1], 36 | copy: true, 37 | copySortSource: true, 38 | //move only from left to right 39 | accepts: accepts 40 | }); 41 | 42 | dragularService([containerRight], { 43 | containersModel: [$scope.items2], 44 | removeOnSpill: true, 45 | //move only from left to right 46 | accepts: accepts 47 | }); 48 | 49 | }; 50 | 51 | DifferentOptionsModelCtrl.$inject = ['$scope', '$element', 'dragularService']; 52 | 53 | module.exports = DifferentOptionsModelCtrl; 54 | -------------------------------------------------------------------------------- /docs/src/examples/exampleDragOverEvents/exampleDragOverEvents.js: -------------------------------------------------------------------------------- 1 | /* global angular */ 2 | 'use strict'; 3 | 4 | var DragOverEventsCtrl = function ($element, dragularService) { 5 | dragularService.cleanEnviroment(); 6 | dragularService([$element.children()[0], $element.children()[2]], { 7 | nameSpace: 'apples' 8 | }); 9 | dragularService([$element.children()[1], $element.children()[3]], { 10 | nameSpace: 'oranges' 11 | }); 12 | 13 | // containers events handling 14 | function registerEvents(el) { 15 | el.on('dragularenter', function(e) { 16 | if (el[0] === e.target) { // filter bubbled 17 | el.addClass(dragularService.shared.extra ? 'gu-over-accept' : 'gu-over-decline'); 18 | } 19 | }); 20 | el.on('dragularleave dragularrelease', function(e) { 21 | if ((el[0] === e.target && // filter bubbled 22 | dragularService.shared.extra && // extra on dragleave contains element the drag is leaving to 23 | dragularService.shared.extra.parentElement !== e.target) || // is that element child of this container? 24 | e.type === 'dragularrelease') { 25 | el.removeClass('gu-over-accept'); 26 | el.removeClass('gu-over-decline'); 27 | } 28 | }); 29 | } 30 | 31 | angular.forEach($element.children(), function forEachChild(el) { 32 | registerEvents(angular.element(el)); 33 | }); 34 | 35 | // notContainer events handling 36 | var notContainer = angular.element(document.getElementsByClassName('notContainer')); 37 | notContainer.on('dragularenter', function() { 38 | notContainer.addClass('gu-over'); 39 | }); 40 | notContainer.on('dragularleave dragularrelease', function() { 41 | notContainer.removeClass('gu-over'); 42 | }); 43 | }; 44 | 45 | DragOverEventsCtrl.$inject = ['$element', 'dragularService']; 46 | 47 | module.exports = DragOverEventsCtrl; 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dragular", 3 | "version": "4.6.0", 4 | "description": "Angular drag and drop based on dragula", 5 | "keywords": [ 6 | "drag", 7 | "drop", 8 | "drag&drop", 9 | "drag & drop", 10 | "drag and drop", 11 | "angular", 12 | "angularjs" 13 | ], 14 | "main": "./dist/dragular.js", 15 | "scripts": { 16 | "start": "gulp dev:docs", 17 | "build": "gulp build" 18 | }, 19 | "jspm": { 20 | "format": "global", 21 | "shim": { 22 | "dist/dragular": { 23 | "deps": [ 24 | "./dragular.css!" 25 | ] 26 | } 27 | } 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "http://github.com/luckylooke/dragular.git" 32 | }, 33 | "author": { 34 | "name": "Ctibor Laky", 35 | "email": "luckylooke@gmail.com", 36 | "url": "http://github.com/luckylooke" 37 | }, 38 | "license": "MIT", 39 | "bugs": { 40 | "url": "http://github.com/luckylooke/dragular/issues" 41 | }, 42 | "homepage": "http://luckylooke.github.io/dragular/", 43 | "dependencies": { 44 | "angular": "^1.6.5" 45 | }, 46 | "devDependencies": { 47 | "browser-sync": "^2.26.3", 48 | "gulp": "^4.0.0", 49 | "gulp-angular-templatecache": "^1.7.0", 50 | "gulp-autoprefixer": "^2.3.1", 51 | "gulp-concat": "^2.6.0", 52 | "gulp-gh-pages": "^0.5.2", 53 | "gulp-if": "^2.0.2", 54 | "gulp-jshint": "^2.1.0", 55 | "gulp-markdown": "^1.2.0", 56 | "gulp-minify-css": "^1.2.0", 57 | "gulp-rename": "^1.2.2", 58 | "gulp-size": "^1.2.3", 59 | "gulp-sourcemaps": "^1.12.0", 60 | "gulp-uglify": "^1.2.0", 61 | "gulp-util": "^3.0.6", 62 | "jshint": "^2.9.7", 63 | "jshint-stylish": "^2.1.0", 64 | "run-sequence": "^1.1.2", 65 | "webpack-stream": "^3.1.0" 66 | }, 67 | "maintainers": [ 68 | { 69 | "name": "luckylooke", 70 | "email": "luckylooke@gmail.com" 71 | } 72 | ], 73 | "readme": "ERROR: No README data found!" 74 | } 75 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBasicWithModel/exampleBasicWithModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var BasicModelCtrl = function ($scope, $element, dragularService) { 3 | $scope.items1 = [{ 4 | content: 'Move me, but you can only drop me in one of these containers.' 5 | }, { 6 | content: 'If you try to drop me somewhere other than these containers, I\'ll just come back.' 7 | }, { 8 | content: 'Item 3' 9 | }, { 10 | content: 'Item 4' 11 | }]; 12 | $scope.items2 = [{ 13 | content: 'Item 5' 14 | }, { 15 | content: 'Item 6' 16 | }, { 17 | content: 'Item 7' 18 | }, { 19 | content: 'Item 8' 20 | }]; 21 | var containers = $element.children().eq(0).children(); 22 | dragularService.cleanEnviroment(); 23 | // var drake = dragularService([containers[0],containers[1]],{ 24 | // dragularService([containers[0]],{ 25 | dragularService([containers[0], containers[1]],{ 26 | containersModel: [$scope.items1, $scope.items2], 27 | // canBeAccepted: function () { 28 | // return false; 29 | // }, 30 | // accepts: function () { 31 | // return false; 32 | // }, 33 | // isContainer: function (el) { 34 | // return el.id == 'test'; 35 | // }, 36 | // isContainerModel: function () { 37 | // return $scope.items2; 38 | // } 39 | // scope: $scope 40 | }); 41 | 42 | // $scope.$on('dragularcloned', myFn('cloned')); 43 | // $scope.$on('dragulardrag', myFn('drag')); 44 | // $scope.$on('dragularcancel', myFn('cancel')); 45 | // $scope.$on('dragulardrop', myFn('drop')); 46 | // $scope.$on('dragularremove', myFn('remove')); 47 | // $scope.$on('dragulardragend', myFn('dragend')); 48 | // $scope.$on('dragularshadow', myFn('shadow')); 49 | // 50 | // function myFn(eventName) { 51 | // return function() { 52 | // console.log(eventName, arguments, drake); 53 | // }; 54 | // } 55 | 56 | }; 57 | 58 | BasicModelCtrl.$inject = ['$scope', '$element', 'dragularService']; 59 | 60 | module.exports = BasicModelCtrl; 61 | -------------------------------------------------------------------------------- /docs/src/examples/exampleBasic/exampleBasic.html: -------------------------------------------------------------------------------- 1 |
2 |

Basic

3 | 4 |
5 |
6 |
Move me, but you can only drop me in one of these containers.
7 |
If you try to drop me somewhere other than these containers, I'll just come back.
8 |
Item 3.
9 |
Item 6.
10 |
11 |
12 |
You can drop me in the left container, otherwise I'll stay here.
13 |
Try to click me, dragular distinguish drag from click
14 |
Item 5.
15 |
16 |
17 |
18 |         
19 | // JS
20 |   controller('Basic', ['$element', 'dragularService', function TodoCtrl($element, dragularService) {
21 |     dragularService('.container-vertical');
22 |   }])
23 |         
24 |         
25 | // CSS
26 | .clickedClass {
27 |   background-color: orange !important;
28 | }
29 |         
30 |         
31 | <!-- HTML -->
32 |   <div class="wrapper" ng-controller="Basic">
33 |     <div class="container-vertical">
34 |         <div>Move me, but you can only drop me in one of these containers.</div>
35 |         <div>If you try to drop me somewhere other than these containers, I'll just come back.</div>
36 |         <div>Item 3.</div>
37 |         <div>Item 6.</div>
38 |     </div>
39 |     <div class="container-vertical">
40 |         <div>You can drop me in the left container, otherwise I'll stay here.</div>
41 |         <div ng-click="clicked = !clicked" ng-class="clicked && 'clickedClass'">Try to click me, dragular distinguish drag from click</div>
42 |         <div>Item 5.</div>
43 |     </div>
44 | </div>
45 |         
46 |       
47 |
48 | -------------------------------------------------------------------------------- /docs/src/examples/exampleDirective/exampleDirective.html: -------------------------------------------------------------------------------- 1 |
2 |

Directive

3 | 4 |
5 |
6 |
Move me, but you can only drop me in one of these containers.
7 |
If you try to drop me somewhere other than these containers, I'll just come back.
8 |
Item 3.
9 |
Item 6.
10 |
11 |
12 |
You can drop me in the left container, otherwise I'll stay here.
13 |
Item 4.
14 |
Item 5.
15 |
16 |
17 |
18 |         
19 | // JS
20 |   controller('Directive', ['$scope', 'dragularService', function TodoCtrl($scope) {
21 |     $scope.dragularOptions = {
22 |       classes: {
23 |         mirror: 'custom-green-mirror'
24 |       },
25 |       nameSpace: 'common' // just connecting left and right container
26 |     };
27 |   }])
28 |         
29 |         
30 | <!-- HTML -->
31 | <div class="wrapper" ng-controller="Directive">
32 |     <div class="container-vertical" dragular="dragularOptions">
33 |       <div>Move me, but you can only drop me in one of these containers.</div>
34 |       <div>If you try to drop me somewhere other than these containers, I'll just come back.</div>
35 |       <div>Item 3.</div>
36 |       <div>Item 6.</div>
37 |     </div>
38 |     <div class="container-vertical" dragular='{"classes":{"mirror":"custom-green-mirror"},"nameSpace":"same"}'>
39 |       <div>You can drop me in the left container, otherwise I'll stay here.</div>
40 |       <div>Item 4.</div>
41 |       <div>Item 5.</div>
42 |     </div>
43 |   </div>
44 |         
45 |       
46 |
47 | -------------------------------------------------------------------------------- /docs/src/examples/exampleNameSpaces/exampleNameSpaces.html: -------------------------------------------------------------------------------- 1 |
2 |

NameSpaces

3 | 4 |
5 |
6 |
try to mix oranges and apples
7 |
apple 2
8 |
apple 3
9 |
apple 4
10 |
11 |
12 |
orange 1
13 |
orange 2
14 |
orange 3
15 |
orange 4
16 |
17 |
18 |
apple 5
19 |
apple 6
20 |
apple 7
21 |
apple 8
22 |
23 |
24 |
mixed 1
25 |
mixed 2
26 |
mixed 3
27 |
mixed 4
28 |
29 |
30 |
31 |       
32 | dragularService([$element.children()[0], $element.children()[2]], {
33 |   nameSpace: 'apples'
34 | });
35 | dragularService($element.children()[1], {
36 |   nameSpace: 'oranges'
37 | });
38 | dragularService($element.children()[3], { // mixed
39 |   nameSpace: ['oranges', 'apples']
40 | });
41 |       
42 |     
43 |
-------------------------------------------------------------------------------- /docs/src/vendor/highlight.github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 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 | 4 |
5 |
6 |
7 |
8 | {{item.content}} 9 | 10 | 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 | 4 |
5 |
6 |
7 |
{{item.content}}
8 |
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 | 4 |
5 |
6 |
7 |
{{item.content}}
8 |
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 | 4 |
5 |
6 |
7 |
{{item.content}}
8 |
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 | 4 |
5 |
6 |
7 |
{{item.content}}
8 |
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 | 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 |
6 |

DRAGULAR

7 |

Angular drag&drop based on dragula.

8 |

Live examples in docs

9 |
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 |
    34 |
  • improve docs
  • 35 |
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 | 4 |
5 |
6 |
7 |
{{item.content}}
8 |
9 |
10 |
{{item.content}} 11 |
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 | 4 |
5 |
6 |
7 |
{{item.content}}
8 |
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 |

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 | 48 | 49 | 50 | Fork me on GitHub 51 | 52 | 53 |
54 |
55 |
56 |

Dragular 2015 | Coded with and keyboard by Luckylooke

57 |
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 | 5 |
6 |
7 |
up
8 |
9 |
Item 1.
10 |
Item 2.
11 |
Item 3.
12 |
Item 4.
13 |
Item 5.
14 |
Item 6.
15 |
Item 7.
16 |
Item 9.
17 |
Item 10.
18 |
Item 11.
19 |
Item 12.
20 |
Item 13.
21 |
22 |
down
23 |
24 |
25 |
26 |
27 |
Item 1.
28 |
Item 2.
29 |
Item 3.
30 |
Item 4.
31 |
Item 5.
32 |
Item 6.
33 |
Item 7.
34 |
Item 9.
35 |
Item 10.
36 |
Item 11.
37 |
Item 12.
38 |
Item 13.
39 |
40 |
41 |
42 |
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 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
dragularService.shared.itemitem beeing dragged (it is copy of item if copy is enabled via options)
dragularService.shared.sourcesource container item is dragged from
dragularService.shared.sourceModelsource container model representation if model was porvided
dragularService.shared.initialIndexoriginal index of item, can be used to get item model from sourceModel
dragularService.shared.extracontains accepting information (boolean) on dragenter, element drag is leaving to on dragleave and element behind the cursor on dragrelease
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 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
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 | 25 |

Linting

26 | 29 |

Making a pull request

30 |

Once that is ready, make your changes and submit a Pull Request:

31 | 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 | 8 |
9 |
10 |
11 |
12 |
Row {{::$index}}
13 |
14 |
{{item.content}}
15 |
16 |
17 | 18 | 19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | 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 `
")),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:/\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:/]+/}]}]}]};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:"|$)",e:">",k:{title:"style"},c:[c],starts:{e:"",rE:!0,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[c],starts:{e:"",rE:!0,sL:""}},s,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",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 | --------------------------------------------------------------------------------