// Effect parameters var slideshowIsRunning = false; // Indicated whether the slideshow is running (some actions depend on this) var cancelInitialSlideshowStart = false; // var currentPendingAction = null; // Used to store the currently delayed function (called by the slideshow to keep scrolling between pictures) var fadeInDuration = 0.75; var fadeOutDuration = 0.75; var nbAdjacentFrames = 5; // Global variable that stores the currently called frame // This variable ensures that, when several frames are being loaded simultaneously, only the last one called is displayed (because resources may arrive in a different order than the one they were called) var currentIndex; // Trim function String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); } // Move to a frame // This method is called by the user clicks var toFrame = function(index) { // Update the current index currentIndex = index; // Get the frame information var resourceIdentifier = '#resource' + index; // var resourceId = $$(resourceIdentifier + ' .resource_id')[0].innerHTML; var type = $$(resourceIdentifier + ' .type')[0].innerHTML; var number = $$(resourceIdentifier + ' .number')[0].innerHTML; var title = $$(resourceIdentifier + ' .title')[0].innerHTML; var previousIndex = $$(resourceIdentifier + ' .previous_index')[0].innerHTML.trim(); var nextIndex = $$(resourceIdentifier + ' .next_index')[0].innerHTML.trim(); var resourceStatusElement = $$(resourceIdentifier + ' .loading_status')[0]; var resourceStatus = resourceStatusElement.innerHTML.trim(); // 1 - Modify the previous and next links so that the user can keep navigating even if the frame is not loaded yet // Update the current frame number $('current_frame_number').update(index); // Update the previous and next links as well as the previous and next indexes if (previousIndex.length > 0) { $('previous_index').update(previousIndex); $('link_previous').update('
'); var linkPrevious = $$('#link_previous a'); linkPrevious[0].stopObserving('click'); linkPrevious[0].observe('click', function() {stopZoom(); stopSlideshow(); javascript:toFrame(previousIndex);}); } else { $('previous_index').update(''); $('link_previous').update('
'); } if (nextIndex.length > 0) { $('next_index').update(nextIndex); $('link_next').update('
'); var linkNext = $$('#link_next a'); linkNext[0].stopObserving('click'); linkNext[0].observe('click', function() {stopZoom(); stopSlideshow(); javascript:toFrame(nextIndex);}); } else { $('next_index').update(''); $('link_next').update('
'); } // 2 - Show the title of the new frame so that the user can follow where he is var newTitle = ''; if (type == 'image') { newTitle = number + '/' + $('nb_images').innerHTML.trim() + ' - '; } newTitle = newTitle + title; $('detail_title').update(newTitle); // Write the new title // 3 - Update the HTML document title document.title = title; // 4 - Display the frame according to its current status // If already loaded, display it and preload the adjacent frames if (resourceStatus == 2) { displayFrame(index); loadAdjacentFrames(index, nbAdjacentFrames); // Otherwise, load it and display it when it is loaded via a custom observer, with one condition: by the time it is loaded, it must still be the frame that matches the current index. Along with displaying it, preload the adjacent frames } else { $('loading').show(); resourceStatusElement.observe('status:change', function() { if ((resourceStatusElement.innerHTML == 2) && (index == currentIndex)) { displayFrame(index); loadAdjacentFrames(index, nbAdjacentFrames); } }); loadFrame(index); } } // Load a specified number of adjacent frames var loadAdjacentFrames = function(index, number) { // if (number == 0) { return; } // Do nothing if the frame is not defined if (!$('resource' + index)) { return; } loadNextFrames(index, number); loadPreviousFrames(index, number); } // Load a specified number of previous frames var loadPreviousFrames = function(index, number) { // if (number == 0) { return; } // Do nothing if the frame is not defined if (!$('resource' + index)) { return; } // Get the frame information var resourceIdentifier = '#resource' + index; var previousIndex = $$(resourceIdentifier + ' .previous_index')[0].innerHTML.trim(); loadFrame(previousIndex); loadPreviousFrames(previousIndex, number - 1); } // Load a specified number of next frames var loadNextFrames = function(index, number) { // if (number == 0) { return; } // Do nothing if the frame is not defined if (!$('resource' + index)) { return; } // Get the frame information var resourceIdentifier = '#resource' + index; var nextIndex = $$(resourceIdentifier + ' .next_index')[0].innerHTML.trim(); loadFrame(nextIndex); loadNextFrames(nextIndex, number - 1); } // Load a frame var loadFrame = function(index) { // Do nothing if the frame is not defined if (!$('resource' + index)) { return; } // Get the frame information var resourceIdentifier = '#resource' + index; var resourceId = $$(resourceIdentifier + ' .resource_id')[0].innerHTML; var resourceStatusElement = $$(resourceIdentifier + ' .loading_status')[0]; var resourceStatus = resourceStatusElement.innerHTML; var language = $('language').innerHTML; // Do nothing if the resource is already loading or loaded if (resourceStatus != 0) { return; } // Set the status as "loading" resourceStatusElement.update(1); // Load the next resource through an Ajax request new Ajax.Request(configApplicationPath + 'resource.php', { method: 'get', parameters: 'language=' + language + '&resource_id=' + resourceId, onSuccess: function(response) { // Insert the new frame into the document, only if it has not been done yet (this test should be unnecessary) if (!$('resource_contents' + resourceId)) { $('frame_contents').insert({'bottom': response.responseText}); } // In the case of an image, it is not considered loaded until the image itself is completely loaded var image = $('resource_contents' + resourceId).down('img'); if (image) { image.observe('load', function() { image.stopObserving('load'); resourceStatusElement.update(2); resourceStatusElement.fire('status:change'); }); // Workaround for Opera: the load event is never fired on Opera if the observer has not been declared before the image source is modified. To solve this problem, after the contents have been retrieved by the ajax call, the observer is declared and then the image source is emptied and reset to its original value, to simulate a modification in the source, therefore properly triggering the load event. This is only useful for Opera, as the other browsers do not have this issue. imageSrcBackup = image.readAttribute('src'); image.writeAttribute('src', ''); image.writeAttribute('src', imageSrcBackup); // In the case of a text, it is immediately loaded } else { resourceStatusElement.update(2); resourceStatusElement.fire('status:change'); } } }); }; // Switch the display to a specified frame var displayFrame = function(index) { // Cancel all running effects var scope = Effect.Queues.get('detail'); scope.each(function(effect) {effect.cancel();}); // Hide the loading indicator $('loading').hide(); // Get the frame information var resourceIdentifier = '#resource' + index; var resourceId = $$(resourceIdentifier + ' .resource_id')[0].innerHTML; var type = $$(resourceIdentifier + ' .type')[0].innerHTML; var orientation = $$(resourceIdentifier + ' .orientation')[0].innerHTML; var src = $$(resourceIdentifier + ' .src')[0].innerHTML; var img = $$(resourceIdentifier + ' .img')[0].innerHTML; var contents = $$(resourceIdentifier + ' .contents')[0].innerHTML; var number = $$(resourceIdentifier + ' .number')[0].innerHTML; var title = $$(resourceIdentifier + ' .title')[0].innerHTML; //var zoomLink = $$(resourceIdentifier + ' .zoom_link')[0].innerHTML; var resourceStatusElement = $$(resourceIdentifier + ' .loading_status')[0]; var resourceStatus = resourceStatusElement.innerHTML; // Hide the image frame new Effect.Morph('detail', { queue: {scope: 'detail'}, style: 'background-color: #2e2e2e;', duration: fadeOutDuration }); new Effect.Morph('frame', { queue: {scope: 'detail'}, style: 'background-color: #2e2e2e;', duration: fadeOutDuration }); // Hide the contents zone first new Effect.Fade('frame_contents', { queue: {scope: 'detail'}, duration: 1.0, afterFinish: function(effect) { /* // Stop the effects if the current frame is not the one with the specified index if (index != currentIndex) { return; } */ // Update the contents according to the resource type if (type == 'image') { // For an image, the class depends on the orientation $('detail').className = 'image_detail_' + orientation; // Mask every resource container $$('#frame_contents div').each(function(element) {element.hide();}); // Then redisplay only the appropriate one $('resource_contents' + resourceId).show(); // Redisplay the frame new Effect.Morph('detail', { queue: {scope: 'detail'}, style: 'background-color: #000000;', duration: 1.0 }); new Effect.Morph('frame', { queue: {scope: 'detail'}, style: 'background-color: #ffffff;', duration: fadeInDuration }); } else { // For a text, the class name is fixed $('detail').className = 'text_detail'; // Mask every resource container $$('#frame_contents div').each(function(element) {element.hide();}); // Then redisplay only the appropriate one $('resource_contents' + resourceId).show(); // Redisplay the frame new Effect.Morph('detail', { queue: {scope: 'detail'}, style: 'background-color: #ffffff;', duration: fadeInDuration }); new Effect.Morph('frame', { queue: {scope: 'detail'}, style: 'background-color: #ffffff;', duration: fadeInDuration }); } // Redisplay the contents zone new Effect.Appear('frame_contents'); } }); } // Display the next frame - this method is automatically called, not triggered by the user, therefore its instructions are executed only if the slideshow is running var displayNextFrame = function() { if (slideshowIsRunning) { var linkNext = $$('#link_next a'); var nextIndex = $('next_index').innerHTML; if (linkNext[0]) { // Display the next frame toFrame(nextIndex); } else { // Unless it is already the final frame, in which case return to the first one toFrame(1); } // Clear the potentially pending action and reschedule the next call // Without this process, toggling several times in succession the slideshow would cause several slideshow timelines to coexist and therefore several pictures being scrolled at the same time window.clearTimeout(currentPendingAction); currentPendingAction = displayNextFrame.delay($('display_period').innerHTML); } } // Start the slideshow var startSlideshow = function() { stopZoom(); // Stop the zoom action if necessary if (!slideshowIsRunning) { slideshowIsRunning = true; displayNextFrame(); // Update the slideshow link to show the stop message $('detail_slideshow').update('
' + $('slideshow_stop_label').innerHTML + '
'); //$('detail_slideshow').update('
' + $('slideshow_stop_label').innerHTML + '
'); new Control.Slider('slider_handler', 'slider_track', { range: $R(7, 3), values: [7, 6, 5, 4, 3], sliderValue: $('display_period').innerHTML, // Reuse the last value set by the user onSlide: function(value) {$('display_period').innerHTML = value;}, onChange: function(value) {$('display_period').innerHTML = value;} }); } cancelInitialSlideshowStart = true; }; // Stop the slideshow var stopSlideshow = function() { if (slideshowIsRunning) { slideshowIsRunning = false; // Update the slideshow link to show the slider and stop message $('detail_slideshow').update('' + $('slideshow_start_label').innerHTML + ''); } cancelInitialSlideshowStart = true; } // Start the slideshow - Initial start var startSlideshowInitial = function() { if (!zoomerIsRunning && !cancelInitialSlideshowStart) { startSlideshow(); } }; //Initial DOM manipulation document.observe('dom:loaded', function() { // Initialize the previous and next links if they exist var linkPrevious = $$('#link_previous a'); var previousIndex = $('previous_index').innerHTML; if (linkPrevious[0]) { linkPrevious[0].href = '#'; linkPrevious[0].observe('click', function() {javascript:stopZoom(); javascript:stopSlideshow(); toFrame(previousIndex);}); } var linkNext = $$('#link_next a'); var nextIndex = $('next_index').innerHTML; if (linkNext[0]) { linkNext[0].href='#'; linkNext[0].observe('click', function() {javascript:stopZoom(); javascript:stopSlideshow(); toFrame(nextIndex);}); } // Automatically start the slideshow 3 seconds after the initial image is loaded /* var image = $('frame_contents').down('img'); image.observe('load', function() { image.stopObserving('load'); startSlideshowInitial.delay(3); }); */ // Preload the adjacent frames loadAdjacentFrames($('current_frame_number').innerHTML, nbAdjacentFrames); // Initialize the slideshow link $('detail_slideshow').update('' + $('slideshow_start_label').innerHTML + ''); // Automatically start the slideshow startSlideshowInitial.delay(3); });