piggybak_rails_admin_nestable 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module RailsAdminNestable
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,469 @@
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
+ dragItem.replaceWith(this.placeEl).appendTo(this.dragEl);
261
+ $(document.body).append(this.dragEl);
262
+ this.dragEl.css({
263
+ 'left' : e.pageX - mouse.offsetX,
264
+ 'top' : e.pageY - mouse.offsetY
265
+ });
266
+ // total depth of dragging item
267
+ var i, depth,
268
+ items = this.dragEl.find(this.options.itemNodeName);
269
+ for (i = 0; i < items.length; i++) {
270
+ depth = $(items[i]).parents(this.options.listNodeName).length;
271
+ if (depth > this.dragDepth) {
272
+ this.dragDepth = depth;
273
+ }
274
+ }
275
+ },
276
+
277
+ dragStop: function(e)
278
+ {
279
+ this.placeEl.replaceWith(this.dragEl.html());
280
+ this.dragEl.remove();
281
+ this.el.trigger('change');
282
+ if (this.hasNewRoot) {
283
+ this.dragRootEl.trigger('change');
284
+ }
285
+ this.reset();
286
+ },
287
+
288
+ dragMove: function(e)
289
+ {
290
+ var list, parent, prev, next, depth,
291
+ opt = this.options,
292
+ mouse = this.mouse;
293
+
294
+ this.dragEl.css({
295
+ 'left' : e.pageX - mouse.offsetX,
296
+ 'top' : e.pageY - mouse.offsetY
297
+ });
298
+
299
+ // mouse position last events
300
+ mouse.lastX = mouse.nowX;
301
+ mouse.lastY = mouse.nowY;
302
+ // mouse position this events
303
+ mouse.nowX = e.pageX;
304
+ mouse.nowY = e.pageY;
305
+ // distance mouse moved between events
306
+ mouse.distX = mouse.nowX - mouse.lastX;
307
+ mouse.distY = mouse.nowY - mouse.lastY;
308
+ // direction mouse was moving
309
+ mouse.lastDirX = mouse.dirX;
310
+ mouse.lastDirY = mouse.dirY;
311
+ // direction mouse is now moving (on both axis)
312
+ mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1;
313
+ mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1;
314
+ // axis mouse is now moving on
315
+ var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0;
316
+
317
+ // do nothing on first move
318
+ if (!mouse.moving) {
319
+ mouse.dirAx = newAx;
320
+ mouse.moving = true;
321
+ return;
322
+ }
323
+
324
+ // calc distance moved on this axis (and direction)
325
+ if (mouse.dirAx !== newAx) {
326
+ mouse.distAxX = 0;
327
+ mouse.distAxY = 0;
328
+ } else {
329
+ mouse.distAxX += Math.abs(mouse.distX);
330
+ if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) {
331
+ mouse.distAxX = 0;
332
+ }
333
+ mouse.distAxY += Math.abs(mouse.distY);
334
+ if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) {
335
+ mouse.distAxY = 0;
336
+ }
337
+ }
338
+ mouse.dirAx = newAx;
339
+
340
+ /**
341
+ * move horizontal
342
+ */
343
+ if (mouse.dirAx && mouse.distAxX >= opt.threshold) {
344
+ // reset move distance on x-axis for new phase
345
+ mouse.distAxX = 0;
346
+ prev = this.placeEl.prev(opt.itemNodeName);
347
+ // increase horizontal level if previous sibling exists and is not collapsed
348
+ if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) {
349
+ // cannot increase level when item above is collapsed
350
+ list = prev.find(opt.listNodeName + ':last');
351
+ // check if depth limit has reached
352
+ depth = this.placeEl.parents(opt.listNodeName).length;
353
+ if (depth + this.dragDepth <= opt.maxDepth) {
354
+ // create new sub-level if one doesn't exist
355
+ if (!list.length) {
356
+ list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass);
357
+ list.append(this.placeEl);
358
+ prev.append(list);
359
+ this.setParent(prev);
360
+ } else {
361
+ // else append to next level up
362
+ list = prev.children(opt.listNodeName + ':last');
363
+ list.append(this.placeEl);
364
+ }
365
+ }
366
+ }
367
+ // decrease horizontal level
368
+ if (mouse.distX < 0) {
369
+ // we can't decrease a level if an item preceeds the current one
370
+ next = this.placeEl.next(opt.itemNodeName);
371
+ if (!next.length) {
372
+ parent = this.placeEl.parent();
373
+ this.placeEl.parents(opt.itemNodeName + ':first').after(this.placeEl);
374
+ if (!parent.children().length) {
375
+ this.unsetParent(parent.parent());
376
+ }
377
+ }
378
+ }
379
+ }
380
+
381
+ var isEmpty = false;
382
+
383
+ // find list item under cursor
384
+ if (!hasPointerEvents) {
385
+ this.dragEl[0].style.visibility = 'hidden';
386
+ }
387
+ this.pointEl = $(document.elementFromPoint(e.pageX - this.w.scrollLeft(), e.pageY - this.w.scrollTop()));
388
+ if (!hasPointerEvents) {
389
+ this.dragEl[0].style.visibility = 'visible';
390
+ }
391
+ if (this.pointEl.hasClass(opt.handleClass)) {
392
+ this.pointEl = this.pointEl.parent(opt.itemNodeName);
393
+ }
394
+ if (this.pointEl.hasClass(opt.emptyClass)) {
395
+ isEmpty = true;
396
+ }
397
+ else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) {
398
+ return;
399
+ }
400
+
401
+ // find parent list of item under cursor
402
+ var pointElRoot = this.pointEl.parents('.' + opt.rootClass + ':first'),
403
+ isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id');
404
+
405
+ /**
406
+ * move vertical
407
+ */
408
+ if (!mouse.dirAx || isNewRoot || isEmpty) {
409
+ // check if groups match if dragging over new root
410
+ if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) {
411
+ return;
412
+ }
413
+ // check depth limit
414
+ depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length;
415
+ if (depth > opt.maxDepth) {
416
+ return;
417
+ }
418
+ var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2);
419
+ parent = this.placeEl.parent();
420
+ // if empty create new list to replace empty placeholder
421
+ if (isEmpty) {
422
+ list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass);
423
+ list.append(this.placeEl);
424
+ this.pointEl.replaceWith(list);
425
+ }
426
+ else if (before) {
427
+ this.pointEl.before(this.placeEl);
428
+ }
429
+ else {
430
+ this.pointEl.after(this.placeEl);
431
+ }
432
+ if (!parent.children().length) {
433
+ this.unsetParent(parent.parent());
434
+ }
435
+ if (!this.dragRootEl.find(opt.itemNodeName).length) {
436
+ this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>');
437
+ }
438
+ // parent root list has changed
439
+ if (isNewRoot) {
440
+ this.hasNewRoot = true;
441
+ this.dragRootEl = pointElRoot;
442
+ }
443
+ }
444
+ }
445
+
446
+ };
447
+
448
+ $.fn.nestable = function(params)
449
+ {
450
+ var lists = this,
451
+ retval = this;
452
+
453
+ lists.each(function()
454
+ {
455
+ var plugin = $.data(this, 'nestable');
456
+ if (!plugin) {
457
+ $.data(this, 'nestable', new Plugin(this, params));
458
+ $.data(this, 'nestable-id', new Date().getTime());
459
+ } else {
460
+ if (typeof params === 'string' && typeof plugin[params] === 'function') {
461
+ retval = plugin[params]();
462
+ }
463
+ }
464
+ });
465
+
466
+ return retval || lists;
467
+ };
468
+
469
+ })(jQuery, window, document);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: piggybak_rails_admin_nestable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -63,6 +63,7 @@ files:
63
63
  - lib/rails_admin_nestable/version.rb
64
64
  - lib/rails_admin_nestable/model.rb
65
65
  - lib/rails_admin_nestable.rb
66
+ - vendor/assets/javascripts/jquery.nestable.js
66
67
  - MIT-LICENSE
67
68
  - Rakefile
68
69
  - README.md
@@ -80,7 +81,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
80
81
  version: '0'
81
82
  segments:
82
83
  - 0
83
- hash: 958472697506243010
84
+ hash: 482415928317324562
84
85
  required_rubygems_version: !ruby/object:Gem::Requirement
85
86
  none: false
86
87
  requirements:
@@ -89,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
90
  version: '0'
90
91
  segments:
91
92
  - 0
92
- hash: 958472697506243010
93
+ hash: 482415928317324562
93
94
  requirements: []
94
95
  rubyforge_project:
95
96
  rubygems_version: 1.8.23