Skip to content

Commit 27d85e2

Browse files
author
Dean Sofer
committed
Initial structure of ui-sortable
1 parent a8dc1cd commit 27d85e2

11 files changed

+362
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
components/
2+
node_modules/

.travis.yml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
language: node_js
2+
node_js:
3+
- "0.8"
4+
5+
before_install:
6+
- export DISPLAY=:99.0
7+
- sh -e /etc/init.d/xvfb start
8+
- npm install -g bower grunt-cli
9+
- npm install
10+
- bower install
11+
12+
script: "grunt"

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License
2+
3+
Copyright (c) 2012 the AngularUI Team, http://angular-ui.github.com
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all 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,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# ui-sortable directive
2+
3+
This directive allows you to sort array with drag & drop.
4+
5+
## Requirements
6+
7+
- JQuery
8+
- JQueryUI
9+
10+
## Usage
11+
12+
Load the script file: sortable.js in your application:
13+
14+
```html
15+
<script type="text/javascript" src="modules/directives/sortable/src/sortable.js"></script>
16+
```
17+
18+
Add the sortable module as a dependency to your application module:
19+
20+
```js
21+
var myAppModule = angular.module('MyApp', ['ui.directives.sortable'])
22+
```
23+
24+
Apply the directive to your form elements:
25+
26+
```html
27+
<ul ui-sortable ng-model="items">
28+
<li ng-repeat="item in items">{{ item }}</li>
29+
</ul>
30+
```
31+
32+
### Options
33+
34+
All the jQueryUI Sortable options can be passed through the directive.
35+
36+
37+
```js
38+
myAppModule.controller('MyController', function($scope) {
39+
$scope.items = ["One", "Two", "Three"];
40+
41+
$scope.sortableOptions = {
42+
update: function(e, ui) { ... },
43+
axis: 'x'
44+
};
45+
});
46+
```
47+
48+
```html
49+
<ul ui-sortable="sortableOptions" ng-model="items">
50+
<li ng-repeat="item in items">{{ item }}</li>
51+
</ul>
52+
```
53+
54+

component.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "angular-ui-sortable",
3+
"version": "0.0.1",
4+
"description": "This directive allows you to jQueryUI Sortable.",
5+
"author": "https://github.com/angular-ui/ui-sortable/graphs/contributors",
6+
"license": "MIT",
7+
"homepage": "http://angular-ui.github.com",
8+
"main": "./src/sortable.js",
9+
"ignore": [
10+
"**/.*",
11+
"node_modules",
12+
"components",
13+
"test*",
14+
"demo*",
15+
"gruntFile.js",
16+
"package.json"
17+
],
18+
"dependencies": {
19+
"angular": "~1.x",
20+
"jquery-ui": ">= 1.9"
21+
},
22+
"devDependencies": {
23+
"angular-mocks": "~1.x"
24+
}
25+
}

demo/demo.html

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!DOCTYPE html>
2+
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
3+
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
4+
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
5+
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
6+
<head>
7+
<meta charset="utf-8">
8+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
9+
<title>AngularUI - Date Picker Demo</title>
10+
<base href=".."></base>
11+
<link rel="stylesheet" href="components/jquery-ui/themes/smoothness/jquery-ui.css">
12+
<script type="text/javascript" src="components/jquery/jquery.js"></script>
13+
<script type="text/javascript" src="components/jquery-ui/ui/jquery-ui.custom.js"></script>
14+
<script type="text/javascript" src="components/angular/angular.js"></script>
15+
<script type="text/javascript" src="src/date.js"></script>
16+
</head>
17+
<body ng-app="ui.date">
18+
<label>Select Date: <input type="text" ui-date ng-model="aDate"></label>
19+
<div>{{aDate}}</div>
20+
</body>
21+
</html>

gruntFile.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module.exports = function (grunt) {
2+
3+
grunt.loadNpmTasks('grunt-testacular');
4+
grunt.loadNpmTasks('grunt-contrib-jshint');
5+
6+
// Default task.
7+
grunt.registerTask('default', ['jshint', 'testacular']);
8+
9+
var testacularConfig = function(configFile, customOptions) {
10+
var options = { configFile: configFile, keepalive: true };
11+
var travisOptions = process.env.TRAVIS && { browsers: ['Firefox'], reporters: 'dots' };
12+
return grunt.util._.extend(options, customOptions, travisOptions);
13+
};
14+
15+
// Project configuration.
16+
grunt.initConfig({
17+
testacular: {
18+
unit: {
19+
options: testacularConfig('test/test.conf.js')
20+
}
21+
},
22+
jshint:{
23+
files:['src/**/*.js', 'test/**/*.js', 'demo/**/*.js'],
24+
options:{
25+
curly:true,
26+
eqeqeq:true,
27+
immed:true,
28+
latedef:true,
29+
newcap:true,
30+
noarg:true,
31+
sub:true,
32+
boss:true,
33+
eqnull:true,
34+
globals:{}
35+
}
36+
}
37+
});
38+
39+
};

package.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "angular-ui-date",
3+
"version": "0.0.2",
4+
"description": "This directive allows you to add a date-picker to your form elements.",
5+
"author": "https://github.com/angular-ui/ui-date/graphs/contributors",
6+
"license": "MIT",
7+
"homepage": "http://angular-ui.github.com",
8+
"main": "src/date.js",
9+
"dependencies": {},
10+
"devDependencies": {
11+
"grunt": "~0.4.1",
12+
"grunt-testacular": "~0.3.0",
13+
"grunt-contrib-jshint": "~0.2.0"
14+
},
15+
"scripts": {},
16+
"repository": {
17+
"type": "git",
18+
"url": "git://github.com/angular-ui/ui-date.git"
19+
}
20+
}

src/sortable.js

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
jQuery UI Sortable plugin wrapper
3+
4+
@param [ui-sortable] {object} Options to pass to $.fn.sortable() merged onto ui.config
5+
*/
6+
angular.module('ui.sortable', []).value('uiSortableConfig',{}).directive('uiSortable', [
7+
'uiSortableConfig', function(uiSortableConfig) {
8+
return {
9+
require: '?ngModel',
10+
link: function(scope, element, attrs, ngModel) {
11+
var onReceive, onRemove, onStart, onUpdate, opts;
12+
13+
opts = angular.extend({}, uiSortableConfig, scope.$eval(attrs.uiSortable));
14+
15+
if (ngModel) {
16+
17+
ngModel.$render = function() {
18+
element.sortable( "refresh" );
19+
};
20+
21+
onStart = function(e, ui) {
22+
// Save position of dragged item
23+
ui.item.sortable = { index: ui.item.index() };
24+
};
25+
26+
onUpdate = function(e, ui) {
27+
// For some reason the reference to ngModel in stop() is wrong
28+
ui.item.sortable.resort = ngModel;
29+
};
30+
31+
onReceive = function(e, ui) {
32+
ui.item.sortable.relocate = true;
33+
// added item to array into correct position and set up flag
34+
ngModel.$modelValue.splice(ui.item.index(), 0, ui.item.sortable.moved);
35+
};
36+
37+
onRemove = function(e, ui) {
38+
// copy data into item
39+
if (ngModel.$modelValue.length === 1) {
40+
ui.item.sortable.moved = ngModel.$modelValue.splice(0, 1)[0];
41+
} else {
42+
ui.item.sortable.moved = ngModel.$modelValue.splice(ui.item.sortable.index, 1)[0];
43+
}
44+
};
45+
46+
onStop = function(e, ui) {
47+
// digest all prepared changes
48+
if (ui.item.sortable.resort && !ui.item.sortable.relocate) {
49+
50+
// Fetch saved and current position of dropped element
51+
var end, start;
52+
start = ui.item.sortable.index;
53+
end = ui.item.index();
54+
55+
// Reorder array and apply change to scope
56+
ui.item.sortable.resort.$modelValue.splice(end, 0, ui.item.sortable.resort.$modelValue.splice(start, 1)[0]);
57+
58+
}
59+
if (ui.item.sortable.resort || ui.item.sortable.relocate) {
60+
scope.$apply();
61+
}
62+
};
63+
64+
// If user provided 'start' callback compose it with onStart function
65+
opts.start = (function(_start){
66+
return function(e, ui) {
67+
onStart(e, ui);
68+
if (typeof _start === "function")
69+
_start(e, ui);
70+
}
71+
})(opts.start);
72+
73+
// If user provided 'start' callback compose it with onStart function
74+
opts.stop = (function(_stop){
75+
return function(e, ui) {
76+
onStop(e, ui);
77+
if (typeof _stop === "function")
78+
_stop(e, ui);
79+
}
80+
})(opts.stop);
81+
82+
// If user provided 'update' callback compose it with onUpdate function
83+
opts.update = (function(_update){
84+
return function(e, ui) {
85+
onUpdate(e, ui);
86+
if (typeof _update === "function")
87+
_update(e, ui);
88+
}
89+
})(opts.update);
90+
91+
// If user provided 'receive' callback compose it with onReceive function
92+
opts.receive = (function(_receive){
93+
return function(e, ui) {
94+
onReceive(e, ui);
95+
if (typeof _receive === "function")
96+
_receive(e, ui);
97+
}
98+
})(opts.receive);
99+
100+
// If user provided 'remove' callback compose it with onRemove function
101+
opts.remove = (function(_remove){
102+
return function(e, ui) {
103+
onRemove(e, ui);
104+
if (typeof _remove === "function")
105+
_remove(e, ui);
106+
};
107+
})(opts.remove);
108+
}
109+
110+
// Create sortable
111+
element.sortable(opts);
112+
}
113+
};
114+
}
115+
]);

test/sortableSpec.js

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
describe('uiSortable', function() {
2+
3+
// Ensure the sortable angular module is loaded
4+
beforeEach(module('ui.sortable'));
5+
6+
describe('simple use', function() {
7+
8+
it('should have a ui-sortable class', function() {
9+
inject(function($compile, $rootScope) {
10+
var element;
11+
element = $compile("<ul ui-sortable></ul>")($rootScope);
12+
expect(element.hasClass("ui-sortable")).toBeTruthy();
13+
});
14+
});
15+
16+
it('should update model when order changes', function() {
17+
inject(function($compile, $rootScope) {
18+
var element;
19+
element = $compile('<ul ui-sortable ng-model="items"><li ng-repeat="item in items" id="s-{{$index}}">{{ item }}</li></ul>')($rootScope);
20+
$rootScope.$apply(function() {
21+
return $rootScope.items = ["One", "Two", "Three"];
22+
});
23+
24+
element.find('li:eq(1)').insertAfter(element.find('li:eq(2)'));
25+
26+
// None of this work, one way is to use .bind("sortupdate")
27+
// and then use .trigger("sortupdate", e, ui) but I have no idea how to
28+
// construct ui object
29+
30+
// element.sortable('refresh')
31+
// element.sortable('refreshPositions')
32+
// element.trigger('sortupdate')
33+
34+
// expect($rootScope.items).toEqual(["One", "Three", "Two"])
35+
});
36+
});
37+
38+
});
39+
40+
});

test/test.conf.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
basePath = '..';
2+
files = [
3+
JASMINE,
4+
JASMINE_ADAPTER,
5+
'components/jquery/jquery.js',
6+
'components/jquery-ui/ui/jquery-ui.custom.js',
7+
'components/angular/angular.js',
8+
'components/angular-mocks/angular-mocks.js',
9+
'src/sortable.js',
10+
'test/*.spec.js'
11+
];
12+
singleRun = true;
13+
browsers = [ 'Chrome' ];

0 commit comments

Comments
 (0)