2 * © 2008 Benoît Pin – Centre de recherche en informatique – École des mines de Paris
4 * Licence Creative Commons http://creativecommons.org/licenses/by-nc/2.0/
13 var keyLeft
= 37, keyRight
= 39;
14 var isTextMime
= /^text\/.+/i;
15 var isAddToSelection
= /.*\/add_to_selection$/;
16 var imgRequestedSize
= /size=(\d+)/;
17 var DEFAULT_IMAGE_SIZES
= [500, 600, 800];
19 FilmSlider = function(filmBar
, slider
, ctxInfos
, image
, toolbar
, breadcrumbs
) {
20 var thisSlider
= this;
21 this.filmBar
= filmBar
;
22 var film
= filmBar
.firstChild
;
23 if (film
.nodeType
== 3)
24 film
= film
.nextSibling
;
27 this.rail
= slider
.parentNode
;
28 this.sliderSpeedRatio
= undefined;
29 this.sliderRatio
= undefined;
30 this.selectedSlide
= undefined;
31 this.selectedSlideInSelection
= undefined;
32 this.cartSlide
= document
.getElementById('cart_slide');
34 this.stretchable
= image
.parentNode
;
35 this.viewMode
= 'medium';
37 this.buttons
= new Array();
38 this.toolbar
= toolbar
;
39 var bcElements
= breadcrumbs
.getElementsByTagName('a');
40 this.lastBCElement
= bcElements
[bcElements
.length
-1];
41 var imgSrcParts
= image
.src
.split('/');
42 this.lastBCElement
.innerHTML
= imgSrcParts
[imgSrcParts
.length
-2];
44 var buttons
= toolbar
.getElementsByTagName('img');
46 for (var i
=0 ; i
<buttons
.length
; i
++) {
48 name
= b
.getAttribute('name');
50 this.buttons
[name
] = b
;
53 this.pendingImage
= new Image();
54 this.pendingImage
.onload = function() {
55 thisSlider
.refreshImage();
57 this.initialized
= false;
59 with(this.slider
.style
) {
63 with(this.film
.style
) {
68 this.filmLength
= ctxInfos
.filmLength
;
69 this.center
= ctxInfos
.center
;
70 this.slideSize
= ctxInfos
.slideSize
;
71 this.ctxUrlTranslation
= ctxInfos
.ctxUrlTranslation
;
73 this.ddHandlers
= {'down' : function(evt
){thisSlider
.mouseDownHandler(evt
);},
74 'move' : function(evt
){thisSlider
.mouseMoveHandler(evt
);},
75 'up' : function(evt
){thisSlider
.mouseUpHandler(evt
);},
76 'out' : function(evt
){thisSlider
.mouseOutHandler(evt
);}
80 this.addEventListeners()
84 FilmSlider
.prototype.resizeSlider = function(evt
) {
85 var filmBarWidth
= getObjectWidth(this.filmBar
);
87 var thisSlider
= this;
88 addListener(window
, 'load', function(evt
){thisSlider
.resizeSlider(evt
);});
92 var filmWidth
= this.slideSize
* this.filmLength
;
93 var sliderRatio
= this.sliderRatio
= filmBarWidth
/ filmWidth
;
94 var sliderWidth
= filmBarWidth
* sliderRatio
;
95 this.rail
.style
.width
= filmBarWidth
+ 'px';
96 this.rail
.style
.display
= 'block';
97 this.rail
.style
.visibility
= 'visible';
98 if (sliderRatio
< 1) {
99 this.slider
.style
.width
= Math
.round(sliderWidth
) + 'px';
100 this.slider
.style
.visibility
= 'visible';
103 this.slider
.style
.visibility
= 'hidden';
106 this.winSize
= {'width' : getWindowWidth(),
107 'height' : getWindowHeight()};
108 this.maxRightPosition
= filmBarWidth
- sliderWidth
109 this.sliderSpeedRatio
= - (filmBarWidth
- sliderWidth
) / (filmWidth
- filmBarWidth
);
110 if (!this.initialized
) {
111 this.centerSlide(this.center
);
112 this.selectedSlide
= this.filmBar
.getElementsByTagName('img')[this.center
].parentNode
;
113 this.initialized
= true;
117 FilmSlider
.prototype.fitToScreen = function(evt
) {
119 var thisSlider
= this;
120 addListener(window
, 'resize', function(evt
){thisSlider
._fitToScreen();});
123 FilmSlider
.prototype._fitToScreen = function(evt
) {
124 var wh
= getWindowHeight();
125 var rb
= getObjectTop(this.rail
) + getObjectHeight(this.rail
); // rail bottom
127 var sh
= getObjectHeight(this.stretchable
);
128 var newSize
= sh
+ delta
;
129 this.stretchable
.style
.height
= newSize
+ 'px';
131 var ratio
= this.image
.height
/ this.image
.width
;
132 var bestFitSize
= this.getBestFitSize(ratio
);
133 var currentSize
= parseInt(imgRequestedSize
.exec(this.image
.src
)[1]);
134 if (currentSize
!= bestFitSize
) {
135 var src
= this.image
.src
.replace(imgRequestedSize
, 'size=' + bestFitSize
);
136 this.pendingImage
.src
= src
;
140 FilmSlider
.prototype.getBestFitSize = function(ratio
) {
141 var fw
= getObjectWidth(this.stretchable
) - 1;
142 var fh
= getObjectHeight(this.stretchable
) - 1;
146 for (i
=DEFAULT_IMAGE_SIZES
.length
-1 ; i
>0 ; i
--) {
147 irw
= DEFAULT_IMAGE_SIZES
[i
];
149 if (irw
<= fw
&& irh
<= fh
)
154 for (i
=DEFAULT_IMAGE_SIZES
.length
-1 ; i
>0 ; i
--) {
155 irh
= DEFAULT_IMAGE_SIZES
[i
];
157 if (irw
<= fw
&& irh
<= fh
)
161 return DEFAULT_IMAGE_SIZES
[i
];
164 FilmSlider
.prototype.centerSlide = function(slideIndex
) {
165 if (this.sliderRatio
> 1)
167 var filmBarWidth
= getObjectWidth(this.filmBar
);
168 var x
= slideIndex
* this.slideSize
169 x
= x
- (filmBarWidth
- this.slideSize
) / 2.0;
170 x
= x
* this.sliderSpeedRatio
;
171 var p
= new Point( -x
, 0 )
172 this.setSliderPosition(p
);
175 FilmSlider
.prototype.setSliderPosition = function(point
) {
178 if (point
.x
> this.maxRightPosition
)
179 point
.x
= this.maxRightPosition
;
180 this.slider
.style
.left
= point
.x
+ 'px';
181 this.setFilmPosition(point
);
184 FilmSlider
.prototype.setFilmPosition = function(point
) {
185 this.film
.style
.left
= point
.x
/ this.sliderSpeedRatio
+ 'px';
188 FilmSlider
.prototype.getSliderPosition = function() {
189 var x
= parseInt(this.slider
.style
.left
);
190 var y
= parseInt(this.slider
.style
.top
);
191 var p
= new Point(x
, y
);
195 FilmSlider
.prototype.getFilmPosition = function() {
196 var x
= parseInt(this.film
.style
.left
);
197 var y
= parseInt(this.film
.style
.top
);
198 var p
= new Point(x
, y
);
202 FilmSlider
.prototype.loadSibling = function(previous
) {
205 slide
= this.selectedSlide
.parentNode
.previousSibling
;
206 if (slide
&& slide
.nodeType
==3)
207 slide
= slide
.previousSibling
;
210 slide
= this.selectedSlide
.parentNode
.nextSibling
;
211 if (slide
&& slide
.nodeType
==3)
212 slide
= slide
.nextSibling
;
218 var target
= slide
.getElementsByTagName('a')[0];
219 raiseMouseEvent(target
, 'click');
220 var index
= parseInt(target
.getAttribute('portfolio:position'));
221 this.centerSlide(index
);
225 FilmSlider
.prototype.addEventListeners = function() {
226 var thisSlider
= this;
227 addListener(window
, 'resize', function(evt
){thisSlider
.resizeSlider(evt
);});
228 addListener(this.filmBar
, 'click', function(evt
){thisSlider
.thumbnailClickHandler(evt
);});
229 addListener(this.toolbar
, 'click', function(evt
){thisSlider
.toolbarClickHandler(evt
);});
230 addListener(window
, 'load', function(evt
){thisSlider
.fitToScreen(evt
);});
233 addListener(this.slider
, 'mousedown', this.ddHandlers
['down']);
234 if(browser
.isDOM2Event
){
235 if (browser
.isAppleWebKit
) {
236 this.filmBar
.addEventListener('mousewheel', function(evt
){thisSlider
.mouseWheelHandler(evt
);}, false);
239 addListener(this.filmBar
, 'DOMMouseScroll', function(evt
){thisSlider
.mouseWheelHandler(evt
);});
242 else if (browser
.isIE6up
) {
243 addListener(this.filmBar
, 'mousewheel', function(evt
){thisSlider
.mouseWheelHandler(evt
);});
246 addListener(document
, 'keydown', function(evt
){thisSlider
.keyDownHandler(evt
);});
247 addListener(document
, 'keypress', function(evt
){thisSlider
.keyPressHandler(evt
);});
251 FilmSlider
.prototype.mouseDownHandler = function(evt
) {
252 this.initialClickPoint
= new Point(evt
.clientX
, evt
.clientY
);
253 this.initialPosition
= this.getSliderPosition();
254 this.dragInProgress
= true;
255 addListener(document
, 'mousemove', this.ddHandlers
['move']);
256 addListener(document
, 'mouseup', this.ddHandlers
['up']);
257 addListener(document
.body
, 'mouseout', this.ddHandlers
['out'])
262 FilmSlider
.prototype.mouseMoveHandler = function(evt
) {
263 if(!this.dragInProgress
)
267 evt
= getEventObject(evt
);
268 var currentPoint
= new Point(evt
.clientX
, evt
.clientY
);
269 var displacement
= currentPoint
.diff(this.initialClickPoint
);
270 this.setSliderPosition(this.initialPosition
.add(displacement
));
273 FilmSlider
.prototype.mouseUpHandler = function(evt
) {
274 this.dragInProgress
= false;
275 evt
= getEventObject(evt
);
276 this.mouseMoveHandler(evt
);
280 FilmSlider
.prototype.mouseOutHandler = function(evt
) {
281 evt
= getEventObject(evt
);
285 x
> this.winSize
['width'] ||
287 y
> this.winSize
['height']
289 this.mouseUpHandler(evt
);
293 FilmSlider
.prototype.thumbnailClickHandler = function(evt
) {
294 var target
= getTargetedObject(evt
);
295 while (target
.tagName
!= 'A' && target
!= this.filmBar
)
296 target
= target
.parentNode
;
297 if (target
.tagName
!= 'A')
300 if (this.viewMode
== 'full') {
301 this.mosaique
.unload();
302 this.mosaique
= null;
303 this.viewMode
= 'medium';
306 disablePropagation(evt
);
308 history
.pushState(target
.href
, '', target
.href
);
310 var imgBaseUrl
= target
.href
;
312 if (this.ctxUrlTranslation
[0])
313 canonicalImgUrl
= imgBaseUrl
.replace(this.ctxUrlTranslation
[0],
314 this.ctxUrlTranslation
[1]);
316 canonicalImgUrl
= imgBaseUrl
;
318 var ajaxUrl
= imgBaseUrl
+ '/photo_view_ajax';
321 //this.pendingImage.src = canonicalImgUrl + '/getResizedImage?size=600';
322 var thumbnail
= target
.getElementsByTagName('IMG')[0];
323 var bestFitSize
= this.getBestFitSize(thumbnail
.height
/thumbnail
.width
);
324 this.pendingImage
.src
= canonicalImgUrl
+ '/getResizedImage?size=' + bestFitSize
;
327 var fullScreenLink
= this.buttons
['full_screen'].parentNode
;
328 fullScreenLink
.href
= canonicalImgUrl
+ '/zoom_view';
330 var toggleSelectionBtn
= this.buttons
['toggle_selection'];
331 var toggleSelectionLink
= toggleSelectionBtn
.parentNode
;
332 this.selectedSlideInSelection
= (target
.className
=='selected');
333 if (this.selectedSlideInSelection
) {
334 toggleSelectionBtn
.src
= portal_url() + '/unselect_flag_btn.gif';
335 toggleSelectionBtn
.alt
= toggleSelectionLink
.title
= 'Retirer de la sélection';
336 toggleSelectionLink
.href
= canonicalImgUrl
+ '/remove_to_selection';
339 toggleSelectionBtn
.src
= portal_url() + '/select_flag_btn.gif';
340 toggleSelectionBtn
.alt
= toggleSelectionLink
.title
= 'Ajouter à la sélection';
341 toggleSelectionLink
.href
= canonicalImgUrl
+ '/add_to_selection';
344 var showBuyableButtonLink
= this.buttons
['show_buyable'].parentNode
;
345 showBuyableButtonLink
.href
= canonicalImgUrl
+ '/get_slide_buyable_items';
346 this.cartSlide
.innerHTML
= '';
347 this.cartSlide
.style
.visibility
='hidden';
350 var metadataButton
= this.buttons
['edit_metadata']
351 if (metadataButton
) {
352 var metadataEditLink
= metadataButton
.parentNode
;
353 metadataEditLink
.href
= canonicalImgUrl
+ '/photo_edit_form'
357 var req
= new XMLHttpRequest();
358 req
.onreadystatechange = function() {
359 switch (req
.readyState
) {
365 if (! isTextMime
.exec(req
.getResponseHeader('Content-Type'))) {
366 req
.onreadystatechange
= null;
369 window
.location
.href
= thisFS
._fallBackUrl
;
376 if (req
.status
== '200')
377 thisFS
.populateViewer(req
);
379 //window.location.href = target.href;
380 console
.error(ajaxUrl
);
385 req
.open("GET", ajaxUrl
, true);
388 // update old displayed slide className
389 var className
= this.selectedSlide
.className
;
390 var classes
= className
.split(' ');
391 var newClasses
= new Array();
396 if (name
== 'displayed')
399 newClasses
.push(name
);
402 this.selectedSlide
.className
= newClasses
.join(' ')
404 // hightlight new displayed slide
405 this.selectedSlide
= target
;
406 className
= this.selectedSlide
.className
;
407 classes
= className
.split(' ');
408 classes
.push('displayed');
409 this.selectedSlide
.className
= classes
.join(' ');
413 FilmSlider
.prototype.toolbarClickHandler = function(evt
) {
414 var target
= getTargetedObject(evt
);
415 if(target
.tagName
== 'IMG' && target
.getAttribute('name')){
416 switch(target
.getAttribute('name')) {
419 disablePropagation(evt
);
421 var link
= button
.parentNode
;
423 this.loadSibling(true);
427 disablePropagation(evt
);
429 var link
= button
.parentNode
;
431 this.loadSibling(false);
435 disablePropagation(evt
);
436 target
.parentNode
.blur();
437 if (this.viewMode
== 'full') {
438 this.mosaique
.unload();
439 this.mosaique
= null;
440 this.viewMode
= 'medium';
443 var main
= document
.getElementById('photo_viewer');
444 var url
= target
.parentNode
.href
;
445 url
= url
.substring(0, url
.length
- '/zoom_view'.length
);
446 var margins
= {'top':0, 'right':-1, 'bottom':0, 'left':0};
447 this.mosaique
= new Mosaique(main
, url
, margins
);
448 this.viewMode
= 'full';
451 case 'toggle_selection':
453 disablePropagation(evt
);
455 var link
= button
.parentNode
;
458 var req
= new XMLHttpRequest();
460 req
.open("POST", url
, true);
461 req
.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
465 var parts
= url
.split('/');
466 var canonicalImgUrl
= parts
.slice(0, parts
.length
-1).join('/');
468 if (isAddToSelection
.test(url
)) {
469 button
.src
= portal_url() + '/unselect_flag_btn.gif';
470 button
.alt
= link
.title
= 'Retirer de la sélection';
471 link
.href
= canonicalImgUrl
+ '/remove_to_selection';
472 this.selectedSlide
.className
= 'selected displayed';
473 this.image
.parentNode
.className
= 'selected';
474 this.selectedSlideInSelection
= true;
477 button
.src
= portal_url() + '/select_flag_btn.gif';
478 button
.alt
= link
.title
= 'Ajouter à la sélection';
479 link
.href
= canonicalImgUrl
+ '/add_to_selection';
480 this.selectedSlide
.className
= 'displayed';
481 this.image
.parentNode
.className
= '';
482 this.selectedSlideInSelection
= false;
488 disablePropagation(evt
);
490 var link
= button
.parentNode
;
492 var slide
= this.cartSlide
;
493 slide
.innerHTML
= '';
494 slide
.style
.visibility
= 'visible';
495 var cw
= new CartWidget(slide
, link
.href
);
496 cw
.onCancel = function() {
497 CartWidget
.prototype.onCancel
.apply(this);
498 slide
.style
.visibility
= 'hidden';
500 cw
.onAfterConfirm = function() {
501 slide
.style
.visibility
= 'hidden';
509 case 'edit_metadata' :
511 disablePropagation(evt);
513 if (this.viewMode == 'full') {
514 this.mosaique.unload();
515 this.mosaique = null;
516 this.viewMode = 'medium';
519 var fi = new FragmentImporter(absolute_url());
520 fi.useMacro('metadata_edit_form_macros', 'iptc', 'image_metadata');
528 if(browser
.isDOM2Event
){
529 if (browser
.isAppleWebKit
) {
530 FilmSlider
.prototype.mouseWheelHandler = function(evt
) {
532 var pos
= this.getSliderPosition();
533 pos
.x
-= evt
.wheelDelta
/ 40;
534 this.setSliderPosition(pos
);
538 FilmSlider
.prototype.mouseWheelHandler = function(evt
) {
540 var pos
= this.getSliderPosition();
541 pos
.x
+= evt
.detail
* 3;
542 this.setSliderPosition(pos
);
546 else if (browser
.isIE6up
) {
547 FilmSlider
.prototype.mouseWheelHandler = function() {
548 var evt
= window
.event
;
549 evt
.returnValue
= false;
550 var pos
= this.getSliderPosition();
551 pos
.x
-= evt
.wheelDelta
/ 40;
552 this.setSliderPosition(pos
);
556 FilmSlider
.prototype.keyDownHandler = function(evt
) {
557 var evt
= getEventObject(evt
);
558 switch (evt
.keyCode
) {
560 this.loadSibling(true);
563 this.loadSibling(false);
571 FilmSlider
.prototype.keyPressHandler = function(evt
) {
572 var target
= getTargetedObject(evt
);
573 if (target
.tagName
== 'INPUT' || target
.tagName
== 'TEXTAREA')
575 var evt
= getEventObject(evt
);
576 var charPress
= String
.fromCharCode((evt
.keyCode
) ? evt
.keyCode
: evt
.which
);
580 raiseMouseEvent(this.buttons
['full_screen'], 'click');
585 FilmSlider
.prototype.populateViewer = function(req
) {
586 var elements
= req
.responseXML
.documentElement
.childNodes
;
587 for(var i
=0 ; i
< elements
.length
; i
++ ) {
588 element
= elements
[i
];
589 switch (element
.nodeName
) {
591 var dest
= document
.getElementById(element
.getAttribute('id'));
592 dest
.innerHTML
= element
.firstChild
.nodeValue
;
594 case 'imageattributes' :
595 var link
= this.buttons
['back_to_portfolio'].parentNode
;
596 link
.href
= element
.getAttribute('backToContextUrl');
597 link
= this.buttons
['show_buyable'].parentNode
;
598 var buyable
= element
.getAttribute('buyable');
599 if(buyable
== 'True')
600 link
.className
= null;
601 else if(buyable
== 'False')
602 link
.className
= 'hidden';
603 this.image
.alt
= element
.getAttribute('alt');
604 this.lastBCElement
.href
= element
.getAttribute('lastBcUrl');
605 this.lastBCElement
.innerHTML
= element
.getAttribute('img_id');
611 FilmSlider
.prototype.refreshImage = function() {
612 this.image
.style
.visibility
= 'hidden';
613 this.image
.src
= this.pendingImage
.src
;
614 this.image
.width
= this.pendingImage
.width
;
615 this.image
.height
= this.pendingImage
.height
;
616 this.image
.style
.visibility
= 'visible';
617 if (this.selectedSlideInSelection
)
618 this.image
.parentNode
.className
= 'selected';
620 this.image
.parentNode
.className
= '';
623 FilmSlider
.prototype.startSlideShow = function() {
624 this.slideShowSlide
= this.pendingSlideShowSlide
= this.selectedSlide
;
625 return this.slideShowSlide
.href
;
628 FilmSlider
.prototype.slideShowNext = function() {
629 var nextSlide
= this.slideShowSlide
.parentNode
.nextSibling
;
630 if (nextSlide
&& nextSlide
.nodeType
==3)
631 nextSlide
= nextSlide
.nextSibling
;
634 nextSlide
= nextSlide
.getElementsByTagName('a')[0];
635 this.pendingSlideShowSlide
= nextSlide
;
636 return this.pendingSlideShowSlide
.href
;
639 var row
= this.slideShowSlide
.parentNode
.parentNode
;
640 var first
= row
.firstChild
;
641 if (first
.nodeType
==3)
642 first
= first
.nextSibling
;
643 this.pendingSlideShowSlide
= first
.getElementsByTagName('a')[0];
644 return this.pendingSlideShowSlide
.href
;
648 FilmSlider
.prototype.slideShowPrevious = function() {
649 var previousSlide
= this.slideShowSlide
.parentNode
.previousSibling
;
650 if (previousSlide
&& previousSlide
.nodeType
==3)
651 previousSlide
= previousSlide
.previousSibling
;
654 previousSlide
= previousSlide
.getElementsByTagName('a')[0];
655 this.pendingSlideShowSlide
= previousSlide
;
656 return this.pendingSlideShowSlide
.href
;
659 var row
= this.slideShowSlide
.parentNode
.parentNode
;
660 var last
= row
.lastChild
;
661 if (last
.nodeType
==3)
662 last
= last
.previousSibling
;
663 this.pendingSlideShowSlide
= last
.getElementsByTagName('a')[0];
664 return this.pendingSlideShowSlide
.href
;
668 FilmSlider
.prototype.slideShowImageLoaded = function() {
669 this.slideShowSlide
= this.pendingSlideShowSlide
;
672 FilmSlider
.prototype.stopSlideShow = function() {
673 raiseMouseEvent(this.slideShowSlide
, 'click');
674 var index
= parseInt(this.selectedSlide
.getAttribute('portfolio:position'));
675 this.centerSlide(index
);
680 function Point(x
, y
) {
681 this.x
= Math
.round(x
);
682 this.y
= Math
.round(y
);
684 Point
.prototype.diff = function(point
) { return new Point(this.x
- point
.x
, this.y
- point
.y
); };
685 Point
.prototype.add = function(point
) { return new Point(this.x
+ point
.x
, this.y
+ point
.y
); };
686 Point
.prototype.mul = function(k
) { return new Point(this.x
* k
, this.y
*k
)};
687 Point
.prototype.toString = function() { return "(" + String(this.x
) + ", " + String(this.y
) + ")"; };