/** * IPS Social Suite 4 * (c) 2013 Invision Power Services - http://www.invisionpower.com * * ips.browse.list.js - Gallery browse list controller * * Author: Rikki Tissier */ ;( function($, _, undefined){ "use strict"; ips.controller.register('gallery.front.browse.list', { initialize: function () { this.on( 'change', '[data-role="moderation"]', this.selectImage ); this.on( 'tableRowsUpdated', this.rowsUpdated ); }, /** * Refreshes the patchwork when table rows are updated * * @returns {void} */ rowsUpdated: function () { var patchwork = ips.ui.photoLayout.getObj( this.scope ); if( patchwork ){ patchwork.refresh(); } }, /** * Toggles classes when the moderation checkbox is checked * * @param {event} e Event object * @returns {void} */ selectImage: function (e) { // e.stopPropagation(); // Can't do that or the moderator floating menu never shows up var row = $( e.currentTarget ).closest('.cGalleryImageItem'); row.toggleClass( 'cGalleryImageItem_selected', $( e.currentTarget ).is(':checked') ); //return false; } }); }(jQuery, _)); /** * IPS Social Suite 4 * (c) 2013 Invision Power Services - http://www.invisionpower.com * * ips.submit.existingAlbums.js - Allows user to select an existing gallery album * * Author: Rikki Tissier */ ;( function($, _, undefined){ "use strict"; ips.controller.register('gallery.front.submit.existingAlbums', { initialize: function () { this.on( 'click', '[data-action="chooseAlbum"]', this.chooseAlbum ); }, chooseAlbum: function (e) { e.preventDefault(); // Submit the request via ajax and see what we get back var link = $( e.currentTarget ); var url = link.attr('href'); ips.getAjax()( url ) .done( function (response) { link.trigger( 'closeDialog' ); $( document ).trigger( 'albumSelected', response ); }); } }); }(jQuery, _)); 1){ e.preventDefault(); ips.ui.alert.show( { type: 'confirm', icon: 'warn', message: ips.getString('images_without_data', { count: ips.pluralize( ips.getString( 'count_image' ), unsavedCount ) }), subText: ips.getString('images_without_data_desc'), callbacks: { ok: function () { window.location = $( e.currentTarget ).attr('href'); } } }); } }, deleteImage: function (e) { e.preventDefault(); var link = $( e.currentTarget ); var self = this; ips.getAjax()( link.attr('href') ) .done( function (response) { var carousel = self.scope.find('.cDownloadsCarousel'); var numberOfItems = 0; // Update the excess count if necessary if( self.scope.find('.cGallerySubmit_excess').length ){ numberOfItems = carousel.find('.ipsCarousel_item:not( .cGallerySubmit_excess )').length; } // Remove the one we deleted carousel.find('.cGallerySubmit_current').remove(); self._replaceForm( response.nextForm ); self._selectItem( response.nextType, response.nextID ); self._setFormLoading( false ); if( numberOfItems ){ carousel.find('.ipsCarousel_item').slice( 0, numberOfItems ).removeClass('cGallerySubmit_excess'); } }); }, /** * Called when an album has been created in a dialog * * @param {event} e Event object * @param {object} data Event data * @returns {void} */ createAlbum: function (e, data) { this._changeAlbumInfo( 'new_album', data.response.maxImages || null, data.response.name ); }, /** * Called when an existing album has been chosen by the user * * @param {event} e Event object * @param {object} data Event data * @returns {void} */ albumSelected: function (e, data) { this._changeAlbumInfo( 'existing_album', data.maxImages || null, data.name ); }, /** * Updates the album row after the user adds/chooses an album * * @param {string} lang Language string to use * @param {number} maxImages The maximum number of images that will be saved * @param {string} albumName Event object * @returns {void} */ _changeAlbumInfo: function (lang, maxImages, albumName) { var self = this; var images = this.scope.find('.cDownloadsCarousel > li'); var count = images.length; var words = ips.getString( lang, { count: ips.pluralize( ips.getString( 'count_images' ), ( maxImages > 0 && count > maxImages ) ? maxImages : count ), album: albumName }); this.scope.find('[data-role="albumChosen"]').show().find('[data-role="text"]').html( words ).show(); this.scope.find('[data-role="albumChoice"]').hide(); setTimeout( function () { ips.utils.anim.go( 'pulseOnce', self.scope.find('[data-role="albumChosen"]') ); }, 500) // Do we need to mark any images as 'excess'? if( maxImages > 0 && count > maxImages ){ var excess = images.slice( maxImages ); excess.addClass('cGallerySubmit_excess'); } }, /** * User clicks the 'change' link to edit the album being saved to * * @param {event} e Event object * @returns {void} */ changeAlbum: function (e) { e.preventDefault(); this.scope.find('[data-role="albumChosen"]').hide(); this.scope.find('[data-role="albumChoice"]').show(); this.scope.find('.cDownloadsCarousel .cGallerySubmit_excess').removeClass('cGallerySubmit_excess'); ips.getAjax()( ips.getSetting('baseURL') + 'index.php?app=gallery&module=gallery&controller=submit&do=clearAlbum' ); }, /** * User has clicked a specific image to edit * * @param {event} e Event object * @returns {void} */ switchImage: function (e) { e.preventDefault(); var self = this; var link = $( e.currentTarget ); var item = link.closest('.ipsCarousel_item'); var type = item.attr('data-type'); var id = item.attr('data-index'); var doSwitchImage = function () { self._setFormLoading( true ); ips.getAjax()( link.attr('href') ) .done( function (response) { self._replaceForm( response ); self._selectItem( type, id ); self._setFormLoading( false ); }); }; // Warn user about unsaved data if( this._changedForm ){ ips.ui.alert.show( { type: 'confirm', icon: 'warn', message: ips.getString('unsaved_image_data'), subText: ips.getString('unsaved_image_data_desc'), callbacks: { ok: function () { doSwitchImage(); } } }); } else { doSwitchImage(); } }, /** * Event handler for submitting a form * * @param {event} e Event object * @returns {void} */ submitImageForm: function (e) { e.preventDefault(); var self = this; var form = $( e.currentTarget ); form.find('button[type="submit"]').prop( 'disabled', true ).text( ips.getString('saving') ); this._setFormLoading( true ); ips.getAjax()( form.action, { data: form.serialize(), dataType: 'json', method: form.attr('method') }) .done( function (response) { console.log('-------'); console.log(response); console.log('-------'); if( response.done ){ window.location = self.scope.find('[data-action="finish"]').attr('href'); } else { self._replaceForm( response.nextForm ); self._selectItem( response.nextType, response.nextID, true ); } }) .fail( function (jqXHR, textStatus, errorThrown) { self._replaceForm( jqXHR.responseText ); }) .always( function () { self._setFormLoading( false ); }); }, /** * Replaces the current edit form with the new content * * @param {string} contents New form contents * @returns {void} */ _replaceForm: function (contents) { // This method doesn't check this flag, it just resets it this._changedForm = false; // Replace the form with the new form var editArea = this.scope.find('[data-role="editForm"]'); editArea.css({ height: editArea.height() + 'px' }); editArea.html( contents ); ips.utils.anim.go( 'fadeIn fast', editArea ); $( document ).trigger('contentChange', [ editArea ]); $('html, body').animate( { scrollTop: this.scope.find('#elImageInfo').offset().top } ); }, /** * Sets the loading status of the form * * @param {boolean} state Show as loading? * @returns {void} */ _setFormLoading: function (state) { var form = this.scope.find('[data-role="editForm"]'); if( state ){ form.animate( { opacity: 0.6 }, 'fast' ); var dims = ips.utils.position.getElemDims( form ); var position = ips.utils.position.getElemPosition( form ); this.scope.append( $('
').addClass('ipsLoading').attr('data-role', 'loading').css({ left: position.viewportOffset.left + 'px', top: position.viewportOffset.top + 'px', width: dims.width + 'px', height: dims.height + 'px', position: 'absolute', zIndex: ips.ui.zIndex() }) ); } else { form.animate( { opacity: 1 }, 'fast' ); this.scope.find('[data-role="loading"]').remove(); } }, /** * Highlights an item in the image slider * * @param {string} type The type of item being highlighted (images or movies) * @param {string} id Index of the item being highlighted * @param {boolean} markCurrentAsDone Show the current item as 'done' before switching? * @returns {void} */ _selectItem: function (type, id, markCurrentAsDone) { var allImages = this.scope.find('[data-role="uploadedImages"]'); var currentItem = allImages.find('.cGallerySubmit_current'); // Make the new item active in the slider currentItem .removeClass('cGallerySubmit_current') .toggleClass( 'cGallerySubmit_done', ( markCurrentAsDone === true || currentItem.hasClass('cGallerySubmit_done') ) ? true : false ); allImages .find('[data-type="' + type + '"][data-index="' + id + '"]') .addClass('cGallerySubmit_current'); } }); }(jQuery, _));]]> = 0; i-- ){ var id = $( collectionItems[ i ] ).attr('data-imageID'); if( !_.isUndefined( id ) ){ newPrevID = id; } else { break; } } if( newPrevID ){ this._loadAndReplace( newPrevID, 'prev', newPrevItems.length, newPrevItems ) .done( function (response) { self._updateNavButton( 'prev', response.moreResults ); }); } } // Add any images we need to load at the END of the slider if( collectionItems.length < ( index + 4 ) ){ newNextItems = this._addPlaceholders( 'end', ( index + 4 ) - collectionItems.length ); collectionItems = collection.find('li'); // Work out the index for( var i = index; i < collectionItems.length; i++ ){ var id = $( collectionItems[ i ] ).attr('data-imageID'); if( !_.isUndefined( id ) ){ newNextID = id; } else { break; } } if( newNextID ){ this._loadAndReplace( newNextID, 'next', 10, newNextItems ) .done( function (response) { self._updateNavButton( 'next', response.moreResults ); }); } } // Get the position of the middle image var newLeftPos = item.position().left; var leftPos = parseInt( collection.css('left') ) * -1; var leftIdx = ( ( leftPos ) / 50 ); var middleLI = collectionItems.slice( leftIdx + 3, leftIdx + 4 ); var middleLeftPos = middleLI.position().left; var difference = newLeftPos - middleLeftPos; collection.animate({ left: "-=" + difference + 'px' }); collectionItems.removeClass('cGalleryAlbumSlider_active'); item.addClass('cGalleryAlbumSlider_active'); }, /** * Paginates to the previous screen of thumbs in the slider * * @param {event} e Event object * @returns {void} */ prevCollection: function (e) { e.preventDefault(); var self = this; var collection = this.scope.find('[data-role="collection"]'); var collectionItems = collection.find('li'); var toLoad = 0; var newItems = []; // Get the first image shown var leftPos = parseInt( collection.css('left') ) * -1; var leftIdx = ( ( leftPos ) / 50 ); var leftMostLI = collectionItems.slice( leftIdx, leftIdx + 1 ); var leftMostID = leftMostLI.attr('data-imageID'); // Make sure we have enough elements before this one if( leftIdx < 6 ){ toLoad = 6 - leftIdx; } var newLeftPos = leftPos * -1; if( toLoad > 0 ){ // Add spacers for the incoming images newItems = this._addPlaceholders( 'start', toLoad ); // We need to change the left of the slider to compensate for the new items newLeftPos = ( leftPos + ( newItems.length * 50 ) ) * -1; collection.css({ left: newLeftPos + 'px' }); } collection.animate({ left: ( newLeftPos + 300 ) + 'px' }); // Now load any images we need if( toLoad > 0 ){ this._loadAndReplace( leftMostID, 'prev', 6, newItems ) .done( function (response) { self._updateNavButton( 'prev', response.moreResults ); self._updateNavButton( 'next', true ); }); } else { self._updateNavButton( 'next', true ); } }, /** * Paginates to the next screen of images in the slider * * @param {event} e Event object * @returns {void} */ nextCollection: function (e) { e.preventDefault(); var self = this; var collection = this.scope.find('[data-role="collection"]'); var collectionItems = collection.find('li'); var toLoad = 0; var newItems = []; // Figure out the right-most image var leftPos = parseInt( collection.css('left') ) * 1; var leftIdx = ( ( 350 - leftPos ) / 50 ) - 1; // Get the left position var rightMostLI = collectionItems.slice( leftIdx, leftIdx + 1 ); var rightMostID = rightMostLI.attr('data-imageID'); var rightPos = rightMostLI.position(); // Make sure we have enough elements after this one if( collectionItems.length < ( leftIdx + 6 ) ){ toLoad = ( collectionItems.length + 5 ) - leftIdx; } // If we are loading any new images, create a holder and append it to our list if( toLoad > 0 ){ // Add spacers for the incoming images newItems = this._addPlaceholders( 'end', toLoad ); } collection.animate({ left: ( rightPos.left * -1 ) + 'px' }); // Now load any images we need if( toLoad > 0 ){ this._loadAndReplace( rightMostID, 'next', 6, newItems ) .done( function (response) { self._updateNavButton( 'next', response.moreResults ); self._updateNavButton( 'prev', true ); }); } else { self._updateNavButton( 'prev', true ); } }, /** * Adds placeholder images to the slider in the location specified * * @param {string} location 'start' or 'end' * @param {number} count Number to add * @returns {array} Array of placeholder elements created */ _addPlaceholders: function (location, count) { var collection = this.scope.find('[data-role="collection"]'); var newItems = []; for( var i = 0; i < count; i++ ){ var item = $('
  • ').addClass('cGalleryTrimmedImage ipsAreaBackground ipsLoading_tiny'); newItems.push( item ); if( location == 'end' ){ collection.append( item ); } else { collection.prepend( item ); } } return newItems; }, /** * Loads more slider images * * @param {string} direction Which direction we're updating * @param {boolean} moreResults Are there more results to see? * @returns {void} */ _updateNavButton: function (direction, moreResults) { var elem = this.scope.find('[data-role="collectionNav"] [data-action="' + direction + '"]'); if( moreResults ){ elem.removeAttr('data-disabled'); } else { elem.attr( 'data-disabled', true ); } }, /** * Loads more slider images * * @param {number} fromID The ID to fetch from * @param {string} direction next or prev * @param {number} count Number of items to get * @param {array} itemsArray Array of placeholders that will be replaced with the loaded images * @returns {void} */ _loadAndReplace: function (fromID, direction, count, itemsArray) { var deferred = $.Deferred(); this.scope.find('[data-role="collectionNav"] [data-action]').attr( 'data-disabled', true ); ips.getAjax()( ips.getSetting('baseURL') + 'index.php?app=gallery&module=gallery&controller=browse&do=getImages&image=' + fromID + '&direction=' + direction + '&count=' + ( count + 1 ) ) .done( function (response) { // Now replace each of the placeholders for( var i = 0; i < itemsArray.length; i++ ){ if( response[ i ] ){ itemsArray[ i ].replaceWith( response[i] ); } } deferred.resolve({ moreResults: !( response.length <= count ) }); }); return deferred.promise(); }, /** * Navigates the page to the next image * * @param {event} e Event object * @returns {void} */ nextImage: function (e) { e.preventDefault(); var url = $( e.currentTarget ).attr('href'); var id = $( e.currentTarget ).attr('data-imageID'); var title = $( e.currentTarget ).attr('title'); History.pushState( { controller: 'gallery.front.view.image', imageID: id }, title, url ); }, /** * Navigates the page to the previous image * * @param {event} e Event object * @returns {void} */ prevImage: function (e) { e.preventDefault(); var url = $( e.currentTarget ).attr('href'); var id = $( e.currentTarget ).attr('data-imageID'); var title = $( e.currentTarget ).attr('title'); History.pushState( { controller: 'gallery.front.view.image', imageID: id }, title, url ); }, /** * Sets the current image as the user's profile picture * * @param {event} e Event object * @returns {void} */ setAsProfile: function (e) { e.preventDefault(); var url = $( e.currentTarget ).attr('href'); ips.ui.alert.show( { type: 'confirm', icon: 'question', message: ips.getString('set_as_photo_confirm'), callbacks: { ok: function () { ips.getAjax()( url, { showLoading: true } ) .done( function (response) { ips.ui.flashMsg.show( response.message ); }) .fail( function () { window.location = url; }); } } }); }, /** * Sets the image as a cover photo * * @param {event} e Event object * @returns {void} */ setAsCover: function (e) { e.preventDefault(); var url = $( e.currentTarget ).attr('href'); ips.getAjax()( url, { showLoading: true } ) .done( function (response) { ips.ui.flashMsg.show( response.message ); }) .fail( function () { window.location = url; }); }, /** * Event handler for window resizing * * @returns {void} */ windowResize: function () { this._setUpSizing(); }, /** * Loads the specified URL to fetch a new image * * @param {string} url URL of new image to fetch * @returns {void} */ _loadURL: function (url) { var self = this; this._setImageLoading( true ); // Cancel any request running if( this._ajaxObj && _.isFunction( this._ajaxObj.abort ) ){ this._ajaxObj.abort(); } this._ajaxObj = ips.getAjax(); this._ajaxObj( url, { dataType: 'json' } ) .done( function (response) { self._updateImage( response ); }) .fail( function( jqXHR, textStatus, errorThrown ) { if( Debug.isEnabled() ){ Debug.error( errorThrown ); } else { window.location = url; } }); }, /** * Handles a response from the server with new image info * * @param {object} response Server response json * @returns {void} */ _updateImage: function (response) { this.cleanContents(); this.scope.find('[data-role="imageInfo"]').html( response.info ); this.scope.find('[data-role="imageFrame"]').replaceWith( response.image ); if( response.slider ) { this.scope.find('#elGalleryNav > ul').html( response.slider ); } if( response.image.match( /
  • \ "); ips.templates.set('gallery.notes.delete', " \ ×\ "); ips.templates.set('gallery.notes.edit', " \ \ \ ");]]>
    templates common/ui common/utils common controllers underscore jquery mustache jstz Debug.js app.js jquery.js jquery.history.js jquery.transform.js xregexp-all.js xregexp-lookbehind.js