File: /var/www/lcc.kaunokolegija.lt/wp-content/plugins/envira-gallery-lite/assets/js/gallery-select.js
/* ==========================================================
* gallery-select.js
*
* Defines a Backbone Modal for Gallery or Album selection.
*
* To use:
* EnviraGalleryModalWindow.content( new EnviraGallerySelectionView( {
* action: 'gallery', // gallery|album
* multiple: true, // Support multiple Gallery / Album selection
* sidebar_view: 'envira-selection-sidebar' // WordPress media view to render into the sidebar
* modal_title: 'Insert Gallery', // Title for the Backbone Modal
* insert_button_label: 'Insert', // Label for the Insert Button
* onInsert: function() {}, // Callback function when the 'Insert' button in the modal is pressed.
* // You'll have access to this.selection, containing the chosen Galleries / Albums.
* } ).open();
*
* Only the 'action' and 'multiple' arguments are required; defaults will be appled for the other arguments if they're not specified.
*
* You can also attach a global event once the user has chosen Galleries / Albums, clicked the Insert button and the item(s)
* have been inserted:
* jQuery( document ).on( 'enviraGalleryModalData', function( e ) {
* console.log( e.action ); // 'gallery' or 'album'
* console.log( e.multiple ); // Whether the user could select multiple Galleries / Albums (true|false)
* console.log( e.items ); // An array of Galleries or Albums
* console.log( e.insert_options ); // An object of the Insert Options the user chose
* } );
*/
/**
* Controller: Modal Window
* - Used by most Envira Backbone views to display information e.g. bulk edit, edit single image etc.
*/
if ( typeof EnviraGalleryModalWindow == 'undefined' ) {
var EnviraGalleryModalWindow = new wp.media.view.Modal( {
controller: {
trigger: function() {
}
}
} );
}
/**
* View: Error
* - Renders a WordPress style error message when something goes wrong.
*
* @since 1.4.3.0
*/
wp.media.view.EnviraGalleryError = wp.Backbone.View.extend( {
// The outer tag and class name to use. The item is wrapped in this
tagName : 'div',
className : 'notice error envira-gallery-error',
render: function() {
// Load the template to render
// See includes/admin/media-views.php
this.template = wp.media.template( 'envira-gallery-error' );
// Define the HTML for the template
this.$el.html( this.template( this.model ) );
// Return the template
return this;
}
} );
/**
* View: Single Item (Gallery or Album)
* - Renders an <li> element within the "Choose your Gallery / Album" view
*
* @since 1.5.0
*/
var EnviraGallerySelectionItemView = wp.Backbone.View.extend( {
/**
* The Tag Name and Tag's Class(es)
*/
tagName: 'li',
className: 'attachment',
/**
* Template
* - The template to load inside the above tagName element
*/
template: wp.template( 'envira-selection-item' ),
/**
* Initialize
*
* @param object model EnviraGalleryImage Backbone Model
*/
initialize: function( args ) {
// Assign the model to this view
this.model = args.model;
},
/**
* Render
* - Binds the model to the view, so we populate the view's fields and data
*/
render: function() {
// Get HTML
this.$el.html( this.template( this.model.attributes ) );
return this;
}
} );
/**
* View: Sidebar
* - Renders the Helpful Tips when selecting a Gallery or Album for insertion into a Post.
*
* @since 1.5.0.3
*/
var EnviraGallerySelectionSidebarView = wp.Backbone.View.extend( {
/**
* The Tag Name and Tag's Class(es)
*/
tagName: 'div',
className: 'sidebar',
/**
* Initialize
*
* @param string view View to render
*/
initialize: function( view ) {
// Define the sidebar view to render
// This must be a WordPress media view using e.g. <script type="text/html" id="tmpl-my-sidebar-view-name">
this.view = ( ( typeof view == 'undefined' ) ? 'envira-selection-sidebar' : view );
},
/**
* Render the view
*/
render: function() {
// Get HTML
this.$el.html( wp.template( this.view ) );
return this;
}
} );
/**
* Gallery Selection View
*/
var EnviraGallerySelectionView = wp.Backbone.View.extend( {
/**
* The Tag Name and Tag's Class(es)
*/
tagName: 'div',
className: 'media-frame mode-select wp-core-ui hide-router hide-menu',
/**
* Template
* - The template to load inside the above tagName element
*/
template: wp.template( 'envira-selection' ),
/**
* Events
* - Functions to call when specific events occur
*/
events: {
// Clicked a gallery
'click .attachment': 'click',
// Used the search input
'keyup': 'search',
'search': 'search',
// Display Options
'change select': 'updateInsertOption',
// Insert Button
'click button.media-button-insert': 'insert',
},
/**
* Initialize
*
* @param object args:
* - action: gallery|album (required)
* - multiple: true|false (required)
* - sidebar_view: A custom WordPress media view to render into the sidebar (optional)
* - modal_title: The modal title (optional)
* - insert_button_label: The 'Insert' button label (optional)
* - prepend_ids: Optional array of Galleries or Albums to always prepend to the resultset
* - onInsert: function() {} (optional)
*/
initialize: function( args ) {
// Whether we're inserting galleries or albums
this.action = args.action;
// Whether multiple galleries or albums can be selected
this.multiple = args.multiple;
// Define the sidebar view to render into this Modal
// This must be a WordPress media view using e.g. <script type="text/html" id="tmpl-my-sidebar-view-name">
this.sidebar_view = ( ( typeof args.sidebar_view == 'undefined' ) ? 'envira-selection-sidebar' : args.sidebar_view );
// Store the onInsert function provided by the calling class
this.onInsert = args.onInsert;
// Whether we're prepending galleries / albums to the collection
this.prepend_ids = ( ( typeof args.prepend_ids == 'undefined' ) ? false : args.prepend_ids );
// Whether we're preselecting galleries / albums
this.select_ids = ( ( typeof args.select_ids == 'undefined' ) ? false : args.select_ids );
// Define a collection, which will store the Galleries
this.selection = new Backbone.Collection(); // The galleries / albums the user has selected
this.collection = new Backbone.Collection(); // The available galleries / albums
// Define a model to store Insert Options
this.insert_options = new Backbone.Model( {
'modal_title': ( ( typeof args.modal_title == 'undefined' ) ? envira_gallery_select.modal_title : args.modal_title ),
'title': 0,
'insert_button_label': ( ( typeof args.modal_title == 'undefined' ) ? envira_gallery_select.insert_button_label : args.insert_button_label )
} );
// Define some other flags.
this.is_loading = false;
this.search_timeout = false;
// Define loading and loaded events
this.on( 'loading', this.loading, this );
this.on( 'loaded', this.loaded, this );
// Get Galleries
this.getItems( false, '' );
},
/**
* Called when a Gallery is clicked
*
* @param object event Event
*/
click: function( event ) {
// Get the target element, whether it's a directory and its ID
var target = jQuery( event.currentTarget ),
id = jQuery( 'div.attachment-preview', target ).attr( 'data-id' );
// Add or remove item from the selection, depending on its current state
if ( target.hasClass( 'selected' ) ) {
// Remove
this.removeFromSelection( target, id );
} else {
// If multiple selection isn't supported, clear the selection first
if ( ! this.multiple ) {
this.clearSelection();
}
// Add
this.addToSelection( target, id );
}
},
/**
* Called when the search event is fired (the user types into the search field)
*
* @param object event Event
*/
search: function( event ) {
// If we're already loading something, bail
if ( this.is_loading ) {
return;
}
// Clear any existing timeout
clearTimeout( this.search_timeout );
// Check if a search term exists, and is at least 3 characters
var search = event.target.value;
// If search is empty, return the entire folder's contents
if ( search.length == 0 ) {
this.getItems( false, '' );
return;
}
// If search isn't empty but less than 3 characters, don't do anything
if ( search.length < 3 ) {
return;
}
// Set a small timeout before we perform the search. If the user keeps typing,
// this ensures we don't return the wrong results too early.
var that = this;
this.search_timeout = setTimeout( function() {
that.getItems( true, search );
}, 1000 );
},
/**
* Gets galleries by sending an AJAX request
*
* @param bool is_search Is a search request
* @param string search_terms Search Terms
*/
getItems: function( is_search, search_terms ) {
// If we're already loading something, bail
if ( this.is_loading ) {
return;
}
// Clear the existing collection
this.clearSelection();
this.$el.find( 'ul.attachments' ).empty();
this.$el.find( 'div.envira-gallery-error' ).remove();
// Update the loading flag
this.trigger( 'loading' );
// Determine whether we're going to retrieve Galleries or Albums.
var action = '';
switch ( this.action ) {
case 'gallery':
action = 'envira_gallery_editor_get_galleries';
break;
case 'album':
action = 'envira_albums_editor_get_albums';
break;
}
// Perform AJAX request to get Galleries or Albums.
wp.media.ajax( action, {
context: this,
data: {
nonce: envira_gallery_select.get_galleries_nonce,
search: is_search,
search_terms: search_terms,
prepend_ids: this.prepend_ids
},
success: function( items ) {
// Define a collection
var collection = new Backbone.Collection( items );
// Reset the collection
this.collection.reset();
// Add the collection's models (items) to this class' collection
this.collection.add( collection.models );
// Render each item in the collection
this.collection.each( function( model ) {
// Init with model
var child_view = new EnviraGallerySelectionItemView( {
model: model
} );
// Render view within our main view
this.$el.find( 'ul.attachments' ).append( child_view.render().el );
// If we're selecting specific item IDs, check now if this item should be selected
if ( this.select_ids !== false ) {
var select_model = jQuery.inArray( parseInt( model.get( 'id' ) ), this.select_ids );
if ( select_model > -1 ) {
// Select this item
this.addToSelection( jQuery( child_view.render().el ), model.get( 'id' ) );
}
}
}, this );
// Tell wp.media we've finished loading items
this.trigger( 'loaded' );
},
error: function( error_message ) {
// Tell wp.media we've finished loading items, and send the error message
// for output
this.trigger( 'loaded', error_message );
}
} );
},
/**
* Updates an Insert Option (displayed in the sidebar) when changed.
*/
updateInsertOption: function( event ) {
// Check if the target has a name. If not, it's not a model value we want to store
if ( event.target.name == '' ) {
return;
}
// Update the model's value, depending on the input type
if ( event.target.type == 'checkbox' ) {
value = ( event.target.checked ? 1 : 0 );
} else {
value = event.target.value;
}
// Update the model
this.insert_options.set( event.target.name, value );
},
/**
* Render
* - Binds the collection to the view, so we populate the view's attachments grid
*/
render: function() {
// Get HTML
this.$el.html( this.template( this.insert_options.attributes ) );
// Render the Sidebar View
var sidebar = new EnviraGallerySelectionSidebarView( this.sidebar_view );
this.$el.find( 'div.media-sidebar' ).append( sidebar.render().el );
// Return
return this;
},
/**
* Renders an error using
* wp.media.view.EnviraGalleryError
*/
renderError: function( error ) {
// Define model
var model = {};
model.error = error;
// Define view
var view = new wp.media.view.EnviraGalleryError( {
model: model
} );
// Return rendered view
return view.render().el;
},
/**
* Tells the view we're loading by displaying a spinner
*/
loading: function() {
// Set a flag so we know we're loading data
this.is_loading = true;
// Show the spinner
this.$el.find( '.spinner' ).css( 'visibility', 'visible' );
},
/**
* Hides the loading spinner
*/
loaded: function( response ) {
// Set a flag so we know we're not loading anything now
this.is_loading = false;
// Hide the spinner
this.$el.find( '.spinner' ).css( 'visibility', 'hidden' );
// Display the error message, if it's provided
if ( typeof response !== 'undefined' ) {
this.$el.find( 'ul.attachments' ).before( this.renderError( response ) );
}
},
/**
* Adds the given target to the selection
*
* @param object target Selected Element
* @param string id Unique Identifier (i.e. third party API item's UID)
*/
addToSelection: function( target, id ) {
// Trigger the loading event
this.trigger( 'loading' );
// Iterate through the current collection of models until we find the model
// that matches the ID we have
this.collection.each( function( model ) {
// If this model matches the model the user selected, add it to the selection
if ( model.get( 'id' ) == id ) {
this.selection.add( model );
}
}, this );
// Mark the item as selected in the media view
target.addClass( 'selected details' );
// If the selection is not empty, enable the Insert button
if ( this.selection.length > 0 ) {
this.$el.find( 'button.media-button-insert' ).attr( 'disabled', false );
}
// Trigger the loaded event
this.trigger( 'loaded' );
},
/**
* Removes the given target from the selection
*
* @param object target Deselected Element
* @param string id Unique Identifier (i.e. third party API item's UID)
*/
removeFromSelection: function( target, id ) {
// Trigger the loading event
this.trigger( 'loading' );
// Iterate through the current collection of selected models until we find the model
// that has a path matching the given path
this.selection.each( function( model ) {
// remove this model from the collection of selected models
this.selection.remove([{ cid: model.cid }]);
}, this );
// Mark the item as deselected in the media view
target.removeClass( 'selected details' );
// If the selection is empty, disable the Insert button
if ( this.selection.length == 0 ) {
this.$el.find( 'button.media-button-insert' ).attr( 'disabled', 'disabled' );
}
// Trigger the loaded event
this.trigger( 'loaded' );
},
/**
* Clears all selected items
*/
clearSelection: function() {
// Iterate through each item, removing the selected state from the UI
this.selection.each( function( model ) {
this.$el.find( 'div[data-id="' + model.get( 'id' ) + '"]' ).parent().removeClass( 'selected details' );
}, this );
// Disable the Insert button
this.$el.find( 'button.media-button-insert' ).attr( 'disabled', 'disabled' );
// Clear the selected models
this.selection.reset();
},
/**
* Inserts one or more Galleries or Albums into the Editor
*/
insert: function() {
// Tell the View we're loading
this.trigger( 'loading' );
// Run the onInsert() function from the calling class
// If no function given, run the default action, which is to insert
// into the Visual Editor
if ( typeof this.onInsert === 'undefined' ) {
// For each selected item, insert a shortcode into the editor
var items = [];
this.selection.forEach( function( item ) {
// Build array of items, and reset shortcode
items.push( item.attributes );
var shortcode = '';
// Prepend Title to Shortcode
if ( this.insert_options.get( 'title' ) != 0 ) {
shortcode = '<' + this.insert_options.get( 'title' ) + '>' + item.get( 'title' ) + '</' + this.insert_options.get( 'title' ) + '>';
}
// Shortcode
shortcode += '[envira-' + this.action + ' id="' + item.id + '"]';
// Insert into Editor
wp.media.editor.insert( shortcode );
}, this );
// Trigger the enviraGalleryModalData event, comprising of the chosen Galleries.
jQuery( document ).trigger( {
type: 'enviraGalleryModalData',
items: items, // array of galleries or albums
insert_options: this.insert_options,// Backbone Model comprising of Insert Options the user chose on screen
action: this.action // gallery or album
} );
var result = true;
} else {
var result = this.onInsert();
}
// Trigger the loaded event
this.trigger( 'loaded' );
// If the result was successful, close the modal window
if ( result ) {
EnviraGalleryModalWindow.close();
}
}
} );