rails_admin_nestable 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,481 @@
1
+ /*!
2
+ * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/
3
+ * Dual-licensed under the BSD or MIT licenses
4
+ */
5
+ ;(function($, window, document, undefined)
6
+ {
7
+ var hasTouch = 'ontouchstart' in window;
8
+
9
+ /**
10
+ * Detect CSS pointer-events property
11
+ * events are normally disabled on the dragging element to avoid conflicts
12
+ * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js
13
+ */
14
+ var hasPointerEvents = (function()
15
+ {
16
+ var el = document.createElement('div'),
17
+ docEl = document.documentElement;
18
+ if (!('pointerEvents' in el.style)) {
19
+ return false;
20
+ }
21
+ el.style.pointerEvents = 'auto';
22
+ el.style.pointerEvents = 'x';
23
+ docEl.appendChild(el);
24
+ var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto';
25
+ docEl.removeChild(el);
26
+ return !!supports;
27
+ })();
28
+
29
+ var eStart = hasTouch ? 'touchstart' : 'mousedown',
30
+ eMove = hasTouch ? 'touchmove' : 'mousemove',
31
+ eEnd = hasTouch ? 'touchend' : 'mouseup';
32
+ eCancel = hasTouch ? 'touchcancel' : 'mouseup';
33
+
34
+ var defaults = {
35
+ listNodeName : 'ol',
36
+ itemNodeName : 'li',
37
+ rootClass : 'dd',
38
+ listClass : 'dd-list',
39
+ itemClass : 'dd-item',
40
+ dragClass : 'dd-dragel',
41
+ handleClass : 'dd-handle',
42
+ collapsedClass : 'dd-collapsed',
43
+ placeClass : 'dd-placeholder',
44
+ emptyClass : 'dd-empty',
45
+ expandBtnHTML : '<button data-action="expand" type="button">Expand</button>',
46
+ collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>',
47
+ group : 0,
48
+ maxDepth : 5,
49
+ threshold : 20
50
+ };
51
+
52
+ function Plugin(element, options)
53
+ {
54
+ this.w = $(window);
55
+ this.el = $(element);
56
+ this.options = $.extend({}, defaults, options);
57
+ this.init();
58
+ }
59
+
60
+ Plugin.prototype = {
61
+
62
+ init: function()
63
+ {
64
+ var list = this;
65
+
66
+ list.reset();
67
+
68
+ list.el.data('nestable-group', this.options.group);
69
+
70
+ list.placeEl = $('<div class="' + list.options.placeClass + '"/>');
71
+
72
+ $.each(this.el.find(list.options.itemNodeName), function(k, el) {
73
+ list.setParent($(el));
74
+ });
75
+
76
+ list.el.on('click', 'button', function(e) {
77
+ if (list.dragEl || (!hasTouch && e.button !== 0)) {
78
+ return;
79
+ }
80
+ var target = $(e.currentTarget),
81
+ action = target.data('action'),
82
+ item = target.parent(list.options.itemNodeName);
83
+ if (action === 'collapse') {
84
+ list.collapseItem(item);
85
+ }
86
+ if (action === 'expand') {
87
+ list.expandItem(item);
88
+ }
89
+ });
90
+
91
+ var onStartEvent = function(e)
92
+ {
93
+ var handle = $(e.target);
94
+ if (!handle.hasClass(list.options.handleClass)) {
95
+ handle = handle.parents('.' + list.options.handleClass).first();
96
+ }
97
+ if (!handle.length || list.dragEl || (!hasTouch && e.button !== 0) || (hasTouch && e.touches.length !== 1)) {
98
+ return;
99
+ }
100
+ e.preventDefault();
101
+ list.dragStart(hasTouch ? e.touches[0] : e);
102
+ };
103
+
104
+ var onMoveEvent = function(e)
105
+ {
106
+ if (list.dragEl) {
107
+ e.preventDefault();
108
+ list.dragMove(hasTouch ? e.touches[0] : e);
109
+ }
110
+ };
111
+
112
+ var onEndEvent = function(e)
113
+ {
114
+ if (list.dragEl) {
115
+ e.preventDefault();
116
+ list.dragStop(hasTouch ? e.touches[0] : e);
117
+ }
118
+ };
119
+
120
+ if (hasTouch) {
121
+ list.el[0].addEventListener(eStart, onStartEvent, false);
122
+ window.addEventListener(eMove, onMoveEvent, false);
123
+ window.addEventListener(eEnd, onEndEvent, false);
124
+ window.addEventListener(eCancel, onEndEvent, false);
125
+ } else {
126
+ list.el.on(eStart, onStartEvent);
127
+ list.w.on(eMove, onMoveEvent);
128
+ list.w.on(eEnd, onEndEvent);
129
+ }
130
+
131
+ },
132
+
133
+ serialize: function()
134
+ {
135
+ var data,
136
+ depth = 0,
137
+ list = this;
138
+ step = function(level, depth)
139
+ {
140
+ var array = [ ],
141
+ items = level.children(list.options.itemNodeName);
142
+ items.each(function()
143
+ {
144
+ var li = $(this),
145
+ item = $.extend({}, li.data()),
146
+ sub = li.children(list.options.listNodeName);
147
+ if (sub.length) {
148
+ item.children = step(sub, depth + 1);
149
+ }
150
+ array.push(item);
151
+ });
152
+ return array;
153
+ };
154
+ data = step(list.el.find(list.options.listNodeName).first(), depth);
155
+ return data;
156
+ },
157
+
158
+ serialise: function()
159
+ {
160
+ return this.serialize();
161
+ },
162
+
163
+ reset: function()
164
+ {
165
+ this.mouse = {
166
+ offsetX : 0,
167
+ offsetY : 0,
168
+ startX : 0,
169
+ startY : 0,
170
+ lastX : 0,
171
+ lastY : 0,
172
+ nowX : 0,
173
+ nowY : 0,
174
+ distX : 0,
175
+ distY : 0,
176
+ dirAx : 0,
177
+ dirX : 0,
178
+ dirY : 0,
179
+ lastDirX : 0,
180
+ lastDirY : 0,
181
+ distAxX : 0,
182
+ distAxY : 0
183
+ };
184
+ this.moving = false;
185
+ this.dragEl = null;
186
+ this.dragRootEl = null;
187
+ this.dragDepth = 0;
188
+ this.hasNewRoot = false;
189
+ this.pointEl = null;
190
+ },
191
+
192
+ expandItem: function(li)
193
+ {
194
+ li.removeClass(this.options.collapsedClass);
195
+ li.children('[data-action="expand"]').hide();
196
+ li.children('[data-action="collapse"]').show();
197
+ li.children(this.options.listNodeName).show();
198
+ },
199
+
200
+ collapseItem: function(li)
201
+ {
202
+ var lists = li.children(this.options.listNodeName);
203
+ if (lists.length) {
204
+ li.addClass(this.options.collapsedClass);
205
+ li.children('[data-action="collapse"]').hide();
206
+ li.children('[data-action="expand"]').show();
207
+ li.children(this.options.listNodeName).hide();
208
+ }
209
+ },
210
+
211
+ expandAll: function()
212
+ {
213
+ var list = this;
214
+ list.el.find(list.options.itemNodeName).each(function() {
215
+ list.expandItem($(this));
216
+ });
217
+ },
218
+
219
+ collapseAll: function()
220
+ {
221
+ var list = this;
222
+ list.el.find(list.options.itemNodeName).each(function() {
223
+ list.collapseItem($(this));
224
+ });
225
+ },
226
+
227
+ setParent: function(li)
228
+ {
229
+ if (li.children(this.options.listNodeName).length) {
230
+ li.prepend($(this.options.expandBtnHTML));
231
+ li.prepend($(this.options.collapseBtnHTML));
232
+ }
233
+ li.children('[data-action="expand"]').hide();
234
+ },
235
+
236
+ unsetParent: function(li)
237
+ {
238
+ li.removeClass(this.options.collapsedClass);
239
+ li.children('[data-action]').remove();
240
+ li.children(this.options.listNodeName).remove();
241
+ },
242
+
243
+ dragStart: function(e)
244
+ {
245
+ var mouse = this.mouse,
246
+ target = $(e.target),
247
+ dragItem = target.parents(this.options.itemNodeName).first();
248
+
249
+ this.placeEl.css('height', dragItem.height());
250
+
251
+ mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left;
252
+ mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top;
253
+ mouse.startX = mouse.lastX = e.pageX;
254
+ mouse.startY = mouse.lastY = e.pageY;
255
+
256
+ this.dragRootEl = this.el;
257
+
258
+ this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass);
259
+ this.dragEl.css('width', dragItem.width());
260
+
261
+ // fix for zepto.js
262
+ //dragItem.after(this.placeEl).detach().appendTo(this.dragEl);
263
+ dragItem.after(this.placeEl);
264
+ dragItem[0].parentNode.removeChild(dragItem[0]);
265
+ dragItem.appendTo(this.dragEl);
266
+
267
+ $(document.body).append(this.dragEl);
268
+ this.dragEl.css({
269
+ 'left' : e.pageX - mouse.offsetX,
270
+ 'top' : e.pageY - mouse.offsetY
271
+ });
272
+ // total depth of dragging item
273
+ var i, depth,
274
+ items = this.dragEl.find(this.options.itemNodeName);
275
+ for (i = 0; i < items.length; i++) {
276
+ depth = $(items[i]).parents(this.options.listNodeName).length;
277
+ if (depth > this.dragDepth) {
278
+ this.dragDepth = depth;
279
+ }
280
+ }
281
+ },
282
+
283
+ dragStop: function(e)
284
+ {
285
+ // fix for zepto.js
286
+ //this.placeEl.replaceWith(this.dragEl.children(this.options.itemNodeName + ':first').detach());
287
+ var el = this.dragEl.children(this.options.itemNodeName).first();
288
+ el[0].parentNode.removeChild(el[0]);
289
+ this.placeEl.replaceWith(el);
290
+
291
+ this.dragEl.remove();
292
+ this.el.trigger('change');
293
+ if (this.hasNewRoot) {
294
+ this.dragRootEl.trigger('change');
295
+ }
296
+ this.reset();
297
+ },
298
+
299
+ dragMove: function(e)
300
+ {
301
+ var list, parent, prev, next, depth,
302
+ opt = this.options,
303
+ mouse = this.mouse;
304
+
305
+ this.dragEl.css({
306
+ 'left' : e.pageX - mouse.offsetX,
307
+ 'top' : e.pageY - mouse.offsetY
308
+ });
309
+
310
+ // mouse position last events
311
+ mouse.lastX = mouse.nowX;
312
+ mouse.lastY = mouse.nowY;
313
+ // mouse position this events
314
+ mouse.nowX = e.pageX;
315
+ mouse.nowY = e.pageY;
316
+ // distance mouse moved between events
317
+ mouse.distX = mouse.nowX - mouse.lastX;
318
+ mouse.distY = mouse.nowY - mouse.lastY;
319
+ // direction mouse was moving
320
+ mouse.lastDirX = mouse.dirX;
321
+ mouse.lastDirY = mouse.dirY;
322
+ // direction mouse is now moving (on both axis)
323
+ mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
324
+ mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
325
+ // axis mouse is now moving on
326
+ var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
327
+
328
+ // do nothing on first move
329
+ if (!mouse.moving) {
330
+ mouse.dirAx = newAx;
331
+ mouse.moving = true;
332
+ return;
333
+ }
334
+
335
+ // calc distance moved on this axis (and direction)
336
+ if (mouse.dirAx !== newAx) {
337
+ mouse.distAxX = 0;
338
+ mouse.distAxY = 0;
339
+ } else {
340
+ mouse.distAxX += Math.abs(mouse.distX);
341
+ if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
342
+ mouse.distAxX = 0;
343
+ }
344
+ mouse.distAxY += Math.abs(mouse.distY);
345
+ if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
346
+ mouse.distAxY = 0;
347
+ }
348
+ }
349
+ mouse.dirAx = newAx;
350
+
351
+ /**
352
+ * move horizontal
353
+ */
354
+ if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
355
+ // reset move distance on x-axis for new phase
356
+ mouse.distAxX = 0;
357
+ prev = this.placeEl.prev(opt.itemNodeName);
358
+ // increase horizontal level if previous sibling exists and is not collapsed
359
+ if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) {
360
+ // cannot increase level when item above is collapsed
361
+ list = prev.find(opt.listNodeName).last();
362
+ // check if depth limit has reached
363
+ depth = this.placeEl.parents(opt.listNodeName).length;
364
+ if (depth + this.dragDepth <= opt.maxDepth) {
365
+ // create new sub-level if one doesn't exist
366
+ if (!list.length) {
367
+ list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
368
+ list.append(this.placeEl);
369
+ prev.append(list);
370
+ this.setParent(prev);
371
+ } else {
372
+ // else append to next level up
373
+ list = prev.children(opt.listNodeName).last();
374
+ list.append(this.placeEl);
375
+ }
376
+ }
377
+ }
378
+ // decrease horizontal level
379
+ if (mouse.distX < 0) {
380
+ // we can't decrease a level if an item preceeds the current one
381
+ next = this.placeEl.next(opt.itemNodeName);
382
+ if (!next.length) {
383
+ parent = this.placeEl.parent();
384
+ this.placeEl.parents(opt.itemNodeName).first().after(this.placeEl);
385
+ if (!parent.children().length) {
386
+ this.unsetParent(parent.parent());
387
+ }
388
+ }
389
+ }
390
+ }
391
+
392
+ var isEmpty = false;
393
+
394
+ // find list item under cursor
395
+ if (!hasPointerEvents) {
396
+ this.dragEl[0].style.visibility = 'hidden';
397
+ }
398
+ this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - document.body.scrollTop));
399
+ if (!hasPointerEvents) {
400
+ this.dragEl[0].style.visibility = 'visible';
401
+ }
402
+ if (this.pointEl.hasClass(opt.handleClass)) {
403
+ this.pointEl = this.pointEl.parent(opt.itemNodeName);
404
+ }
405
+ if (this.pointEl.hasClass(opt.emptyClass)) {
406
+ isEmpty = true;
407
+ }
408
+ else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
409
+ return;
410
+ }
411
+
412
+ // find parent list of item under cursor
413
+ var pointElRoot = this.pointEl.parents('.' + opt.rootClass).first(),
414
+ isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
415
+
416
+ /**
417
+ * move vertical
418
+ */
419
+ if (!mouse.dirAx || isNewRoot || isEmpty) {
420
+ // check if groups match if dragging over new root
421
+ if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
422
+ return;
423
+ }
424
+ // check depth limit
425
+ depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
426
+ if (depth > opt.maxDepth) {
427
+ return;
428
+ }
429
+ var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
430
+ parent = this.placeEl.parent();
431
+ // if empty create new list to replace empty placeholder
432
+ if (isEmpty) {
433
+ list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
434
+ list.append(this.placeEl);
435
+ this.pointEl.replaceWith(list);
436
+ }
437
+ else if (before) {
438
+ this.pointEl.before(this.placeEl);
439
+ }
440
+ else {
441
+ this.pointEl.after(this.placeEl);
442
+ }
443
+ if (!parent.children().length) {
444
+ this.unsetParent(parent.parent());
445
+ }
446
+ if (!this.dragRootEl.find(opt.itemNodeName).length) {
447
+ this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>');
448
+ }
449
+ // parent root list has changed
450
+ if (isNewRoot) {
451
+ this.hasNewRoot = true;
452
+ this.dragRootEl = pointElRoot;
453
+ }
454
+ }
455
+ }
456
+
457
+ };
458
+
459
+ $.fn.nestable = function(params)
460
+ {
461
+ var lists = this,
462
+ retval = this;
463
+
464
+ lists.each(function()
465
+ {
466
+ var plugin = $(this).data("nestable");
467
+
468
+ if (!plugin) {
469
+ $(this).data("nestable", new Plugin(this, params));
470
+ $(this).data("nestable-id", new Date().getTime());
471
+ } else {
472
+ if (typeof params === 'string' && typeof plugin[params] === 'function') {
473
+ retval = plugin[params]();
474
+ }
475
+ }
476
+ });
477
+
478
+ return retval || lists;
479
+ };
480
+
481
+ })(window.jQuery || window.Zepto, window, document);
@@ -1,3 +1,3 @@
1
1
  module RailsAdminNestable
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_admin_nestable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-28 00:00:00.000000000 Z
12
+ date: 2012-12-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -50,6 +50,7 @@ executables: []
50
50
  extensions: []
51
51
  extra_rdoc_files: []
52
52
  files:
53
+ - app/assets/javascripts/rails_admin/jquery.nestable.js
53
54
  - app/assets/javascripts/rails_admin/rails_admin_nestable.js.coffee
54
55
  - app/assets/stylesheets/rails_admin/rails_admin_nestable.css
55
56
  - app/helpers/rails_admin/nestable_helper.rb