5a920362 |
1 | |
2 | /* - dragdropreorder.js - */ |
3 | /* |
4 | Drag and drop reordering of folder contents. |
5 | |
6 | Provides global ploneDnDReorder |
7 | */ |
8 | |
9 | |
10 | /*jslint nomen:false */ |
11 | |
12 | var ploneDnDReorder = {}; |
13 | |
14 | ploneDnDReorder.dragging = null; |
15 | ploneDnDReorder.table = null; |
16 | ploneDnDReorder.rows = null; |
17 | ploneDnDReorder.locked = false; |
18 | |
19 | (function($) { |
20 | |
21 | ploneDnDReorder.doDown = function(e) { |
22 | var dragging = ploneDnDReorder.dragging, |
23 | body; |
24 | // Waiting for a server operation to complete or following an error |
25 | if (ploneDnDReorder.locked) {return;} |
26 | // already dragging, probably catching up a lost drag. |
27 | if (dragging) { |
28 | if ($(this).attr('id') !== dragging.attr('id')) { |
29 | ploneDnDReorder.locked = true; |
30 | dragging.removeClass('dragging').addClass('error'); |
31 | } |
32 | return; |
33 | } |
34 | dragging = $(this).parents('.draggable:first'); |
35 | if (!dragging.length) {return;} |
36 | ploneDnDReorder.rows.mousemove(ploneDnDReorder.doDrag); |
37 | body = $('body'); |
38 | body.mouseup(ploneDnDReorder.doUp); |
39 | body.mouseleave(ploneDnDReorder.doCancel); |
40 | |
41 | ploneDnDReorder.dragging = dragging; |
42 | dragging.data('ploneDnDReorder.startPosition', ploneDnDReorder.getPos(dragging)); |
43 | dragging.addClass("dragging"); |
44 | $(this).parents('tr').addClass('dragindicator'); |
45 | // Find the original subset ids. This must be in the current order. |
46 | dragging.data('ploneDnDReorder.subset_ids', $.map( |
47 | ploneDnDReorder.table.find('tr.draggable'), |
48 | function(elem) { |
49 | return $(elem).attr('id').substr('folder-contents-item-'.length); |
50 | })); |
51 | |
52 | return false; |
53 | }; |
54 | |
55 | ploneDnDReorder.getPos = function(node) { |
56 | var pos = node.parent().children('.draggable').index(node[0]); |
57 | return pos === -1 ? null : pos; |
58 | }; |
59 | |
60 | ploneDnDReorder.doDrag = function(e) { |
61 | var dragging = ploneDnDReorder.dragging, |
62 | target = this; |
63 | |
64 | if (!dragging) {return;} |
65 | if (!target) {return;} |
66 | |
67 | if ($(target).attr('id') !== dragging.attr('id')) { |
68 | ploneDnDReorder.swapElements($(target), dragging); |
69 | } |
70 | return false; |
71 | }; |
72 | |
73 | ploneDnDReorder.swapElements = function(child1, child2) { |
74 | var parent = child1.parent(), |
75 | items = parent.children('[id]'), |
76 | t; |
77 | |
78 | // Only adjacent elements may be swapped. |
79 | if (Math.abs(ploneDnDReorder.getPos(child1) - ploneDnDReorder.getPos(child2)) !== 1) { |
80 | return; |
81 | } |
82 | |
83 | items.removeClass('even').removeClass('odd'); |
84 | if (child1[0].swapNode) { |
85 | // IE proprietary method |
86 | child1[0].swapNode(child2[0]); |
87 | } else { |
88 | // swap the two elements, using a textnode as a position marker |
89 | t = parent[0].insertBefore(document.createTextNode(''), |
90 | child1[0]); |
91 | child1.insertBefore(child2); |
92 | child2.insertBefore(t); |
93 | $(t).remove(); |
94 | } |
95 | // odd and even are 0-based, so we want them the other way around |
96 | parent.children('[id]:odd').addClass('even'); |
97 | parent.children('[id]:even').addClass('odd'); |
98 | }; |
99 | |
100 | ploneDnDReorder.doUp = function(e) { |
101 | var dragging = ploneDnDReorder.dragging, |
102 | body = $('body'); |
103 | if (!dragging) {return;} |
104 | |
105 | ploneDnDReorder.updatePositionOnServer(); |
106 | dragging.removeData('ploneDnDReorder.startPosition'); |
107 | dragging.removeData('ploneDnDReorder.subset_ids'); |
108 | ploneDnDReorder.rows.unbind('mousemove', ploneDnDReorder.doDrag); |
109 | body.unbind('mouseup', ploneDnDReorder.doUp); |
110 | body.unbind('mouseleave', ploneDnDReorder.doCancel); |
111 | |
112 | $(this).parents('tr').removeClass('dragindicator'); |
113 | return false; |
114 | }; |
115 | |
116 | ploneDnDReorder.doCancel = function(e) { |
117 | var dragging = ploneDnDReorder.dragging, |
118 | body = $('body'); |
119 | if (!dragging) {return;} |
120 | |
121 | dragging.removeClass("dragging") |
122 | if (ploneDnDReorder.getPos(dragging) - dragging.data('ploneDnDReorder.startPosition')) { |
123 | // position has changed, error out |
124 | ploneDnDReorder.locked = true; |
125 | dragging.addClass("error"); |
126 | } |
127 | ploneDnDReorder.rows.unbind('mousemove', ploneDnDReorder.doDrag); |
128 | body.unbind('mouseup', ploneDnDReorder.doCancel); |
129 | body.unbind('mouseleave', ploneDnDReorder.doCancel); |
130 | ploneDnDReorder.dragging = null; |
131 | return false; |
132 | }; |
133 | |
134 | ploneDnDReorder.updatePositionOnServer = function() { |
135 | var dragging = ploneDnDReorder.dragging, |
136 | delta, |
137 | args, |
138 | encoded; |
139 | |
140 | if (!dragging) {return;} |
141 | |
142 | delta = ploneDnDReorder.getPos(dragging) - dragging.data('ploneDnDReorder.startPosition'); |
143 | |
144 | if (delta === 0) { |
145 | // nothing changed |
146 | return; |
147 | } |
148 | // Strip off id prefix |
149 | args = { |
150 | item_id: dragging.attr('id').substr('folder-contents-item-'.length), |
151 | subset_ids: dragging.data('ploneDnDReorder.subset_ids') |
152 | }; |
153 | args['delta:int'] = delta; |
154 | // Convert jQuery's name[]=1&name[]=2 to Zope's name:list=1&name:list=2 |
155 | encoded = $.param(args).replace(/%5B%5D=/g, '%3Alist='); |
156 | $.ajax({ |
157 | type: 'POST', |
158 | url: 'folder_moveitem', |
159 | data: encoded, |
160 | complete: ploneDnDReorder.complete |
161 | }); |
162 | ploneDnDReorder.locked = true; |
163 | }; |
164 | |
165 | ploneDnDReorder.complete = function(xhr, textStatus) { |
166 | var dragging = ploneDnDReorder.dragging; |
167 | dragging.removeClass("dragging"); |
168 | if (textStatus === "success" || textStatus === "notmodified") { |
169 | ploneDnDReorder.locked = false; |
170 | } else { |
171 | dragging.addClass("error"); |
172 | } |
173 | ploneDnDReorder.dragging = null; |
174 | }; |
175 | |
176 | |
177 | }(jQuery)); |
178 | |