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