9a57ac21846cf7d47c22e5be62fee6e84506ffb7
[Portfolio.git] / skins / photo_lightbox_viewer.js
1 /*
2 * 2008-2014 Benoit Pin - MINES ParisTech
3 * http://plinn.org
4 * Licence Creative Commons http://creativecommons.org/licenses/by-nc/2.0/
5 */
6
7
8 var Lightbox;
9
10 (function(){
11
12 var reSelected = /.*selected.*/;
13
14 Lightbox = function(grid, toolbar) {
15 var self = this;
16 this.grid = grid;
17 this.lastSlide = this.grid.children[this.grid.children.length-1];
18 this.toolbar = toolbar;
19 if (toolbar) {
20 this.toolbarFixed = false;
21 addListener(window, 'scroll', function(evt){self.windowScrollHandler(evt);});
22 }
23 this.lastCBChecked = undefined;
24 this.form = undefined;
25 var parent = this.grid.parentNode;
26 while(parent) {
27 parent = parent.parentNode;
28 if (parent.tagName === 'FORM') {
29 this.form = parent;
30 break;
31 }
32 else if (parent.tagName === 'BODY') {
33 break;
34 }
35 }
36 addListener(this.grid, 'click', function(evt){self.mouseClickHandler(evt);});
37 if (this.form) {
38 var fm = this.fm = new FormManager(this.form);
39 addListener(this.form, 'change', function(evt){self.onChangeHandler(evt);});
40 fm.onBeforeSubmit = function(fm_, evt) {return self.onBeforeSubmit(fm_, evt);};
41 fm.onResponseLoad = function(req) {return self.onResponseLoad(req);};
42 }
43 };
44
45 Lightbox.prototype.windowScrollHandler = function(evt) {
46 if (this.toolbar.offsetTop < window.scrollY && !this.toolbarFixed) {
47 this.toolbarFixed = true;
48 this.backThreshold = this.toolbar.offsetTop;
49 this.switchToolBarPositioning(true);
50 }
51 else if (this.toolbarFixed && window.scrollY < this.backThreshold) {
52 this.toolbarFixed = false;
53 this.switchToolBarPositioning(false);
54 }
55 if (window.scrollY > this.lastSlide.firstElementChild.offsetTop - getWindowHeight()) {
56 this.fetchTail();
57 }
58 };
59
60 Lightbox.prototype.mouseClickHandler = function(evt) {
61 var target = getTargetedObject(evt);
62 if (target.tagName === 'IMG') {
63 var img = target;
64 var link = target.parentNode;
65 var button = link.parentNode;
66 var slide = button.parentNode;
67 var req, url;
68 if (link.tagName === 'A') {
69 switch(link.getAttribute('name')) {
70 case 'add_to_selection':
71 disableDefault(evt);
72 link.blur();
73 req = new XMLHttpRequest();
74 url = link.href;
75 req.open("POST", url, true);
76 req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
77 req.send("ajax=1");
78
79 slide.className = 'selected';
80
81 link.setAttribute('name', 'remove_to_selection');
82 link.href = url.replace(/(.*\/)add_to_selection$/, '$1remove_to_selection');
83 link.title = img.alt = 'Retirer de la sélection';
84 button.className = "button slide-deselect";
85 break;
86
87 case 'remove_to_selection':
88 disableDefault(evt);
89 link.blur();
90 req = new XMLHttpRequest();
91 url = link.href;
92 req.open("POST", url, true);
93 req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
94 req.send("ajax=1");
95 slide.className = null;
96 link.setAttribute('name', 'add_to_selection');
97 link.href = url.replace(/(.*\/)remove_to_selection$/, '$1add_to_selection');
98 link.title = img.alt = 'Ajouter à la sélection';
99 button.className = "button slide-select";
100 break;
101
102 case 'add_to_cart' :
103 disableDefault(evt);
104 slide.widget = new CartWidget(slide, link.href);
105 break;
106
107 case 'hide_for_anonymous':
108 disableDefault(evt);
109 link.blur();
110 req = new XMLHttpRequest();
111 url = link.href;
112 req.open("POST", url, true);
113 req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
114 req.send(null);
115 slide.className = 'hidden-slide';
116 link.setAttribute('name', 'show_for_anonymous');
117 link.href = url.replace(/(.*\/)hideForAnonymous$/, '$1resetHide');
118 link.title = img.alt = 'Montrer au anonymes';
119 button.className = "button slide-show";
120 break;
121
122 case 'show_for_anonymous':
123 disableDefault(evt);
124 link.blur();
125 req = new XMLHttpRequest();
126 url = link.href;
127 req.open("POST", url, true);
128 req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
129 req.send(null);
130 slide.className = null;
131 link.setAttribute('name', 'hide_for_anonymous');
132 link.href = url.replace(/(.*\/)resetHide$/, '$1hideForAnonymous');
133 link.title = img.alt = 'Masquer pour les anonymes';
134 button.className = "button slide-hide";
135 break;
136 }
137 }
138 } else if(target.tagName === 'INPUT' && target.type === 'checkbox') {
139 var cb = target;
140 if (cb.checked) {
141 cb.setAttribute('checked', 'checked');
142 }
143 else {
144 cb.removeAttribute('checked');
145 }
146 this.selectCBRange(evt);
147 }
148 };
149
150 Lightbox.prototype.onChangeHandler = function(evt) {
151 var target = getTargetedObject(evt);
152 if (target.name === 'sort_on') {
153 this.fm.submitButton = {'name' : 'set_sorting', 'value' : 'ok'};
154 this.fm.submit(evt);
155 }
156 };
157
158 Lightbox.prototype.onBeforeSubmit = function(fm, evt) {
159 switch(fm.submitButton.name) {
160 case 'delete' :
161 this.hideSelection();
162 break;
163 }
164 };
165
166 Lightbox.prototype.onResponseLoad = function(req) {
167 switch(req.responseXML.documentElement.nodeName) {
168 case 'deleted' :
169 this.deleteSelection();
170 break;
171 case 'error' :
172 this.showSelection();
173 break;
174 case 'sorted' :
175 this.fm.submitButton = undefined;
176 this.refreshGrid();
177 break;
178 }
179 };
180
181 Lightbox.prototype.switchToolBarPositioning = function(fixed) {
182 var tbs = this.toolbar.style;
183 if (fixed) {
184 this.toolbar.defaultCssText = this.toolbar.style.cssText;
185 tbs.width = String(this.toolbar.offsetWidth) + 'px';
186 tbs.height = String(this.toolbar.offsetHeight) + 'px';
187 tbs.position = 'fixed';
188 tbs.top = '0';
189 this.toolbarPlaceholder = document.createElement('div');
190 var phs = this.toolbarPlaceholder.style;
191 phs.cssText = tbs.cssText;
192 phs.position = 'relative';
193 this.toolbar.parentNode.insertBefore(this.toolbarPlaceholder, this.toolbar);
194 }
195 else {
196 this.toolbarPlaceholder.parentNode.removeChild(this.toolbarPlaceholder);
197 tbs.cssText = this.toolbar.defaultCssText;
198 }
199 };
200
201
202 Lightbox.prototype.hideSelection = function() {
203 var i, e, slide;
204 for (i=0 ; i<this.form.elements.length ; i++) {
205 e = this.form.elements[i];
206 if (e.type === 'checkbox' && e.checked) {
207 slide = e.parentNode.parentNode;
208 slide.classList.add('zero_opacity');
209 }
210 }
211 };
212
213 Lightbox.prototype.showSelection = function() {
214 var i, e, slide;
215 for (i=0 ; i<this.form.elements.length ; i++) {
216 e = this.form.elements[i];
217 if (e.type === 'checkbox' && e.checked) {
218 slide = e.parentNode.parentNode;
219 slide.classList.remove('zero_opacity');
220 }
221 }
222 };
223
224 Lightbox.prototype.deleteSelection = function() {
225 var i, e, slide;
226 for (i=0 ; i<this.form.elements.length ; i++) {
227 e = this.form.elements[i];
228 if (e.type === 'checkbox' && e.checked) {
229 slide = e.parentNode.parentNode;
230 slide.classList.add('zero_width');
231 }
232 }
233 var self = this;
234 // if you change this, delay you should also change this css rule :
235 // .lightbox span { transition: width 1s
236 setTimeout(function(){self._removeSelection();}, 1000);
237 };
238
239 Lightbox.prototype._removeSelection = function() {
240 var i, e, slide;
241 var toRemove = [];
242 for (i=0 ; i<this.form.elements.length ; i++) {
243 e = this.form.elements[i];
244 if (e.type === 'checkbox' && e.checked) {
245 toRemove.push(e.parentNode.parentNode);
246 }
247 }
248 for (i=0 ; i<toRemove.length ; i++) {
249 slide = toRemove[i];
250 slide.parentNode.removeChild(slide);
251 }
252 this.cbIndex = undefined;
253 };
254
255 Lightbox.prototype.getCBIndex = function(cb) {
256 if (!this.cbIndex) {
257 // build checkbox index
258 this.cbIndex = [];
259 var i, node, c;
260 var nodes = this.grid.childNodes;
261 for (i=0 ; i<nodes.length ; i++) {
262 node = nodes[i];
263 if (node.nodeName === 'SPAN') {
264 c = node.getElementsByTagName('input')[0];
265 c.index = this.cbIndex.length;
266 this.cbIndex[this.cbIndex.length] = c;
267 }
268 }
269 }
270 return cb.index;
271 };
272
273 Lightbox.prototype.selectCBRange = function(evt) {
274 var target = getTargetedObject(evt);
275 evt = getEventObject(evt);
276 var shift = evt.shiftKey;
277 if (shift && this.lastCBChecked) {
278 var from = this.getCBIndex(this.lastCBChecked);
279 var to = this.getCBIndex(target);
280 var start = Math.min(from, to);
281 var stop = Math.max(from, to);
282 var i;
283 for (i=start ; i<stop ; i++ ) {
284 this.cbIndex[i].setAttribute('checked', 'checked');
285 }
286 }
287 else if (target.checked) {
288 this.lastCBChecked = target;
289 }
290 else {
291 this.lastCBChecked = undefined;
292 }
293 };
294
295 Lightbox.prototype.refreshGrid = function() {
296 var req = new XMLHttpRequest();
297 self = this;
298 req.onreadystatechange = function() {
299 switch (req.readyState) {
300 case 1 :
301 showProgressImage();
302 break;
303 case 4 :
304 hideProgressImage();
305 if (req.status === 200) {
306 self._refreshGrid(req)
307 }
308 break;
309 }
310 };
311
312 var url = absolute_url() +
313 '/portfolio_thumbnails_tail?start:int=0&size:int=' +
314 this.grid.children.length;
315 req.open('GET', url, true);
316 req.send();
317 };
318
319 Lightbox.prototype._refreshGrid = function(req) {
320 var doc = req.responseXML.documentElement;
321 var i;
322 var slides = this.grid.children;
323 for (i=0 ; i<doc.children.length ; i++) {
324 this.grid.replaceChild(getCopyOfNode(doc.children[i]), slides[i]);
325 }
326 };
327
328 Lightbox.prototype.fetchTail = function() {
329 var req = new XMLHttpRequest();
330 self = this;
331 req.onreadystatechange = function() {
332 switch (req.readyState) {
333 case 1 :
334 showProgressImage();
335 break;
336 case 4 :
337 hideProgressImage();
338 if (req.status === 200) {
339 self._appendTail(req)
340 }
341 break;
342 }
343 };
344
345 var url = absolute_url() +
346 '/portfolio_thumbnails_tail?start:int=' +
347 String(this.grid.children.length + 1 ) +
348 '&size:int=10';
349 req.open('GET', url, true);
350 req.send();
351 };
352
353 Lightbox.prototype._appendTail = function(req) {
354 var doc = req.responseXML.documentElement;
355 var i;
356 var slides = this.grid.children;
357 for (i=0 ; i<doc.children.length ; i++) {
358 this.grid.replaceChild(getCopyOfNode(doc.children[i]), slides[i]);
359 }
360 };
361
362
363 var _outlineSelectedSlide;
364 if (browser.isGecko) {
365 _outlineSelectedSlide = function(slide) {
366 slide.className = 'selected';
367 };
368 }
369 else {
370 _outlineSelectedSlide = function(slide) {
371 if (slide.className &&
372 !reSelected.test(slide.className)) {
373 slide.className = slide.className + ' selected';
374 }
375 };
376 }
377
378 }());