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