/* global ogf_repeater */ jQuery( document ).ready( function() { const themeControls = jQuery( '#customize-theme-controls' ); /** * This adds a new box to repeater */ themeControls.on( 'click', '.customizer-repeater-new-field', function() { const parent = jQuery( this ).closest( '.customize-control' ); if ( typeof parent !== 'undefined' ) { /* Clone the first box*/ const field = parent.find( '.customizer-repeater-general-control-repeater-container:first' ).clone( true, true ); if ( typeof field !== 'undefined' ) { /*Show delete box button because it's not the first box*/ field.find( '#ogf-repeater-control-remove-field' ).show(); /*Remove value from text field*/ field.find( '.customizer-repeater-control' ).val( '' ); /*Append new box*/ parent.find( '.customizer-repeater-general-control-repeater-container:first' ).parent().append( field ); /*Refresh values*/ customizerRepeaterRefreshValues(); } } return false; } ); themeControls.on( 'click', '#ogf-repeater-control-remove-field', function() { const control = jQuery( this ).closest( '.customizer-repeater-general-control-repeater-container' ); if ( typeof control !== 'undefined' ) { control.hide( 250, function() { control.remove(); customizerRepeaterRefreshValues(); } ); } return false; } ); themeControls.on( 'keyup', '.customizer-repeater-control', function() { customizerRepeaterRefreshValues(); } ); /** * Save elements and refresh the customizer. */ themeControls.on( 'click', '.ogf_save_elements_button', function() { jQuery.when( wp.customize.previewer.save() ).done( function() { window.location.href = ogf_repeater.return_url; } ); } ); } ); function customizerRepeaterRefreshValues() { const entityMap = { '&': '&', '<': '<', '>': '>', '"': '"', '\'': ''', '/': '/', }; function escapeHtml( string ) { //noinspection JSUnresolvedFunction string = String( string ).replace( new RegExp( '\r?\n', 'g' ), '
' ); string = String( string ).replace( /\\/g, '\' ); return String( string ).replace( /[&<>"'\/]/g, function( s ) { return entityMap[ s ]; } ); } jQuery( '.customizer-repeater-general-control-repeater' ).each( function() { const values = []; jQuery( this ).find( '.customizer-repeater-general-control-repeater-container' ).each( function() { let label = jQuery( this ).find( '.customizer-repeater-label-control' ).val(); const description = jQuery( this ).find( '.customizer-repeater-description-control' ).val(); const selectors = jQuery( this ).find( '.customizer-repeater-selectors-control' ).val(); if ( label !== '' || description !== '' || selectors !== '' ) { label = ( label !== '' ? label : selectors ); values.push( { label: escapeHtml( label ), description: escapeHtml( description ), selectors: escapeHtml( selectors ), } ); } } ); jQuery( this ).find( '.customizer-repeater-collector' ).val( JSON.stringify( values ) ); jQuery( this ).find( '.customizer-repeater-collector' ).trigger( 'change' ); } ); } // Stores the database ID of // currently editing slider. var LS_sliderID = 0, // Store the indexes of currently // selected items on the interface. LS_activeSlideIndex = 0, LS_activeLayerIndexSet = [0], LS_activeLayerPageIndex = 0, LS_activeLayerTransitionTab = 0, LS_activeScreenType = 'desktop', // Stores all preview items using an object // to easily add and modify items. // // NOTE: it's not a jQuery collection, but a // collection of jQuery-enabled elements. LS_previewItems = [], // Object references, pointing to the currently selected // slide/layer data. These are not working copies, any // change made will affect the main data object. This makes // possible to avoid issues caused by inconsistent data. LS_activeSlideData = {}, LS_activeLayerDataSet = [], LS_activeStaticLayersDataSet = [], // These objects will be filled with the default slide/layer // properties when needed. They purpose as a caching mechanism // for bulk slide/layer creation. LS_defaultSliderData = {}, LS_defaultSlideData = {}, LS_defaultLayerData = {}, // Stores all previous editing sessions // to cache results and speed up operations. LS_editorSessions = [], // Flag for unsaved changes on site. // We use this to display a warning // for the user when leaving the page. LS_editorIsDirty = false, // Stores default UI settings of // editing sessions. LS_defaultEditorSession = { slideIndex: LS_activeSlideIndex, layerIndex: LS_activeLayerIndexSet, zoomSlider: 100, zoomAutoFit: true }, // Stores temporary data for all // copy & pate operations. LS_clipboard = {}, // Stores the main UI elements LS_previewZoom = 1, LS_previewArea, LS_previewHolder, LS_previewWrapper, LS_transformStyles = [ 'rotation', 'rotationX', 'rotationY', 'scaleX', 'scaleY', 'skewX', 'skewY' ]; var $lasso = jQuery(); // Utility functions to perform // commonly used tasks. var LS_Utils = { convertDateToUTC: function(date) { return new Date( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds() ); }, dataURItoBlob: function(dataURI) { var binary = atob(dataURI.split(',')[1]); var array = []; for(var i = 0; i < binary.length; i++) { array.push(binary.charCodeAt(i)); } return new Blob([new Uint8Array(array)], {type: 'image/png'}); }, moveArrayItem: function(array, from, to) { if( to === from ) return; var target = array[from]; var increment = to < from ? -1 : 1; for(var k = from; k != to; k += increment){ array[k] = array[k + increment]; } array[to] = target; }, toAbsoluteURL: function(url) { // Handle absolute URLs (with protocol-relative prefix) // Example: //domain.com/file.png if (url.search(/^\/\//) != -1) { return window.location.protocol + url; } // Handle absolute URLs (with explicit origin) // Example: http://domain.com/file.png if (url.search(/:\/\//) != -1) { return url; } // Handle absolute URLs (without explicit origin) // Example: /file.png if (url.search(/^\//) != -1) { return window.location.origin + url; } // Handle relative URLs // Example: file.png var base = window.location.href.match(/(.*\/)/)[0]; return base + url; }, // credits: http://phpjs.org/functions/strip_tags/ stripTags: function(input, allowed) { allowed = (((allowed || '') + '') .toLowerCase() .match(/<[a-z][a-z0-9]*>/g) || []) .join(''); var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, commentsAndPhpTags = /|<\?(?:php)?[\s\S]*?\?>/gi; return input.replace(commentsAndPhpTags, '') .replace(tags, function($0, $1) { return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''; }); }, // credits: http://phpjs.org/functions/nl2br/ nl2br: function(str, is_xhtml) { var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '
' : '
'; // Adjust comment to avoid issue on phpjs.org display return (str + '') .replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2'); }, // credits: http://stackoverflow.com/questions/3169786/clear-text-selection-with-javascript removeTextSelection: function() { var selection = window.getSelection ? window.getSelection() : document.selection ? document.selection : null; if(!!selection) selection.empty ? selection.empty() : selection.removeAllRanges(); }, // credits: http://locutus.io/php/stripslashes/ stripslashes: function(str) { return (str + '') .replace(/\\(.?)/g, function (s, n1) { switch (n1) { case '\\': return '\\' case '0': return '\u0000' case '': return '' default: return n1 } }); }, // credits: http://locutus.io/php/parse_url/ parse_url: function(str, component) { var query; var mode = (typeof require !== 'undefined' ? require('../info/ini_get')('locutus.parse_url.mode') : undefined) || 'php'; var key = [ 'source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment' ]; // For loose we added one optional slash to post-scheme to catch file:/// (should restrict this) var parser = { php: new RegExp([ '(?:([^:\\/?#]+):)?', '(?:\\/\\/()(?:(?:()(?:([^:@\\/]*):?([^:@\\/]*))?@)?([^:\\/?#]*)(?::(\\d*))?))?', '()', '(?:(()(?:(?:[^?#\\/]*\\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)' ].join('')), strict: new RegExp([ '(?:([^:\\/?#]+):)?', '(?:\\/\\/((?:(([^:@\\/]*):?([^:@\\/]*))?@)?([^:\\/?#]*)(?::(\\d*))?))?', '((((?:[^?#\\/]*\\/)*)([^?#]*))(?:\\?([^#]*))?(?:#(.*))?)' ].join('')), loose: new RegExp([ '(?:(?![^:@]+:[^:@\\/]*@)([^:\\/?#.]+):)?', '(?:\\/\\/\\/?)?', '((?:(([^:@\\/]*):?([^:@\\/]*))?@)?([^:\\/?#]*)(?::(\\d*))?)', '(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))', '(?:\\?([^#]*))?(?:#(.*))?)' ].join('')) }; var m = parser[mode].exec(str); var uri = {}; var i = 14; while (i--) { if (m[i]) { uri[key[i]] = m[i]; } } if (component) { return uri[component.replace('PHP_URL_', '').toLowerCase()]; } if (mode !== 'php') { var name = (typeof require !== 'undefined' ? require('../info/ini_get')('locutus.parse_url.queryKey') : undefined) || 'queryKey'; parser = /(?:^|&)([^&=]*)=?([^&]*)/g; uri[name] = {}; query = uri[key[12]] || ''; query.replace(parser, function ($0, $1, $2) { if ($1) { uri[name][$1] = $2; } }); } delete uri.source; return uri; } }; var LS_GUI = { updateImagePicker: function( $picker, image, updateProperties ) { updateProperties = updateProperties || {}; if( typeof $picker === 'string' ) { $picker = jQuery('input[name="'+$picker+'"]').next(); } if( image === 'useCurrent' ) { image = $picker.find('img').attr('src'); } if( image && image.indexOf('blank.gif') !== -1 ) { if( ! updateProperties.fromPost ) { image = false; } } $picker .removeClass('has-image not-set') .addClass( image ? 'has-image' : 'not-set' ) .find('img').attr('src', image || lsTrImgPath+'/blank.gif' ); } }; // Slide specific undo & redo operations. // Uses callbacks to run any code stored by // other methods. Supports custom parameters. var LS_UndoManager = { index: -1, stack: [], limit: 50, add: function(cmd, name, updateInfo) { // Invalidate items higher on the stack when // called from an undo-ed position this.stack.splice(this.index + 1, this.stack.length - this.index); this.index = this.stack.length - 1; // Maintain stack limit if(this.stack.length > this.limit) { this.stack.shift(); } // Verify 'history' object in slide if(!LS_activeSlideData.hasOwnProperty('history')) { LS_activeSlideData.history = []; } // Prepare updateInfo this.prepareUpdateInfo( updateInfo ); // Add item this.stack.push({ cmd: cmd, name: name, updateInfo: updateInfo }); // Maintain buttons and stack index this.index = this.stack.length - 1; this.maintainButtons(); // Mark unsaved changes on page LS_editorIsDirty = true; }, // Replace this.stack when switching slides // to support slide-specific history. update: function() { // Verify 'history' object in slide if(!LS_activeSlideData.hasOwnProperty('history')) { LS_activeSlideData.history = []; } this.stack = LS_activeSlideData.history; this.index = this.stack.length - 1; if( LS_activeSlideData.meta && LS_activeSlideData.meta.undoStackIndex ) { this.index = LS_activeSlideData.meta.undoStackIndex; } this.maintainButtons(); }, // Merges new changes into the last item in // the UndoManager stack. merge: function( cmd, name, updateInfo ) { var lastItem = this.stack[ this.stack.length - 1 ]; this.prepareUpdateInfo( updateInfo ); jQuery.extend(true, lastItem.updateInfo, updateInfo); }, // Empties the current slide's history and reset // every UndoManager-related properties empty: function() { LS_activeSlideData.history = []; if( LS_activeSlideData.meta && LS_activeSlideData.meta.undoStackIndex ) { LS_activeSlideData.meta.undoStackIndex = -1; } this.update(); }, undo: function() { if(this.stack[this.index]) { this.execute('undo', this.stack[this.index]); this.index--; this.maintainButtons(); } }, redo: function() { if(this.stack[this.index+1]) { this.index++; this.execute('redo', this.stack[this.index]); this.maintainButtons(); } }, prepareUpdateInfo: function( updateInfo ) { if( updateInfo && typeof updateInfo === 'object') { jQuery.each(updateInfo, function(key, val) { if( typeof val === 'object') { LS_UndoManager.prepareUpdateInfo( val ); return true; } if( val === null || typeof val === 'undefined') { updateInfo[key] = ''; } }); } }, maintainButtons: function(itemIndex) { var undoButton = jQuery('.ls-editor-undo'), redoButton = jQuery('.ls-editor-redo'); LS_activeSlideData.meta.undoStackIndex = this.index; if(this.index !== -1) { undoButton.removeClass('disabled'); } else { undoButton.addClass('disabled'); } if(this.index < this.stack.length-1) { redoButton.removeClass('disabled'); } else { redoButton.addClass('disabled'); } }, execute: function(action, item) { // Convert object to array to easily // handle multi-action steps. if( jQuery.type(item.updateInfo) === 'object' ) { item.updateInfo = [item.updateInfo]; } // Iterate through actions in step. for(var c = 0; c < item.updateInfo.length; c++) { this.executeItem( item.cmd, item.updateInfo[c].itemIndex, item.updateInfo[c][action], item.updateInfo[c] ); } }, executeItem: function(command, itemIndex, updateInfo, item) { switch(command) { case 'slide.general': this.updateOptions(LS_activeSlideData.properties, itemIndex, updateInfo, 'slide'); LayerSlider.updateSlideInterfaceItems(); LayerSlider.generatePreview(); break; case 'slide.layers': if(jQuery.isEmptyObject(updateInfo.data)) { LayerSlider.removeLayer(itemIndex, { histroyEvent: true, requireConfirmation: false }); } else { LayerSlider.addLayer(updateInfo.data, itemIndex, { histroyEvent: true }); LayerSlider.selectLayer( item.selectIndex ); } LS_DataSource.buildLayersList(); LayerSlider.generatePreview(); break; case 'layer.order': LS_Utils.moveArrayItem(LS_activeSlideData.sublayers, updateInfo.from, updateInfo.to); LS_DataSource.buildLayersList(); LayerSlider.generatePreview(); break; case 'layer.general': this.updateOptions(LS_activeSlideData.sublayers[itemIndex], itemIndex, updateInfo); LayerSlider.updateLayerInterfaceItems(itemIndex); LayerSlider.generatePreviewItem(itemIndex); LayerSlider.updatePreviewSelection(); break; case 'layer.transition': this.updateOptions(LS_activeSlideData.sublayers[itemIndex].transition, itemIndex, updateInfo); LayerSlider.generatePreviewItem(itemIndex); break; case 'layer.style': this.updateOptions(LS_activeSlideData.sublayers[itemIndex].styles, itemIndex, updateInfo); LayerSlider.generatePreviewItem(itemIndex); LayerSlider.updatePreviewSelection(); break; } }, // Iterates over the updateInfo object, // overrides the keys in the provided // data object. updateOptions: function( data, index, updateInfo, area ) { area = area || 'layers'; var parent = (area === 'slide') ? '.ls-slide-options' : '.ls-layers-table'; jQuery.each(updateInfo, function(key, val) { //if( data.hasOwnProperty(key) ) { if( typeof val === 'object' ) { LS_UndoManager.updateOptions( data[key], index, updateInfo[key], area); return true; } // Update data data[key] = val; // Handle UI if it's the active layer if( area === 'slide' || (LS_activeLayerIndexSet.length == 1 && index == LS_activeLayerIndexSet[0]) ) { var $target = jQuery(parent+' '+'[name="'+key+'"]'), eventType = 'input'; $target.val(val).trigger('input').trigger('keyup'); if($target.is(':checkbox')) { if(val) { $target.next().addClass('on').removeClass('off'); } else { $target.next().addClass('off').removeClass('on'); } return; } else if($target.is('select')) { eventType = 'change'; } var jqEvent = jQuery.Event(eventType, { target: $target[0], UndoManagerAction: true }); jQuery('#ls-layers').triggerHandler(jqEvent); } //} }); }, trackInputs: function( event, element ) { event = event || { type: 'change' }; if( event.UndoManagerAction ) { return false; } var $input = jQuery(element), cmd, name, index; if( event.type.toLowerCase() == 'click' && $input.is('input,textarea') ) { return; } if( event.type.toLowerCase() !== 'change' ) { $input.data('prevVal', $input.val() ); return; } // Skip colorpickers, as they rapidly send change events if( $input.hasClass('ls-colorpicker') ) { return; } if( $input.closest('.ls-sublayer-pages').length ) { cmd = 'layer.general'; name = LS_l10n.SBUndoLayer; index = LS_activeLayerIndexSet[0]; if($input.hasClass('sublayerprop')) { cmd = 'layer.transition'; } else if($input.hasClass('auto')) { cmd = 'layer.style'; } } else if( $input.closest('.ls-slide-options').length ) { cmd = 'slide.general'; name = LS_l10n.SBUndoSlide; index = LS_activeSlideIndex; } else { return true; } var optionName = $input.attr('name'), optionValue = $input.is(':checkbox') ? $input.prop('checked') : $input.val(), prevValue = $input.is(':checkbox') ? ! $input.prop('checked') : $input.data('prevVal'), action = $input.hasClass('undomanager-merge') ? 'merge': 'add'; if( ! optionName ) { return false; } var undo = {}, redo = {}; undo[ optionName ] = prevValue; redo[ optionName ] = optionValue; if( prevValue !== optionValue ) { LS_UndoManager[action](cmd, name, { itemIndex: index, undo: undo, redo: redo }); } } }; var LayerSlider = { uploadInput: null, dragIndex: 0, timeout: 0, mediaCheckTimeout: 0, isSlidePreviewActive: false, isLayerPreviewActive: false, selectableTimeout: 0, selectMainTab: function(el) { // Select new tab jQuery(el).addClass('active').siblings().removeClass('active'); // Show new tab contents jQuery('#ls-pages .ls-page').removeClass('active'); jQuery('#ls-pages .ls-page').eq( jQuery(el).index() ).addClass('active'); // Init CodeMirror if(jQuery(el).hasClass('callbacks')) { if(jQuery('.ls-callback-page .CodeMirror-code').length === 0) { LS_CodeMirror.init({ mode: 'javascript', autofocus : false, styleActiveLine : false }); jQuery(window).scrollTop(0); } } }, selectSettingsTab: function(li) { var index = jQuery(li).index(); jQuery(li).addClass('active').siblings().removeClass('active'); jQuery('div.ls-settings-contents tbody.active').removeClass('active'); jQuery('div.ls-settings-contents tbody').eq(index).addClass('active'); }, addSlide: function() { // Get default data objects for slides and layers var newSlideData = jQuery.extend(true, {}, LS_DataSource.getDefaultSlideData()), newLayerData = jQuery.extend(true, {}, LS_DataSource.getDefaultLayerData()); newLayerData.subtitle = LS_l10n.SBLayerTitle.replace('%d', '1'); // Add new slide data to data source window.lsSliderData.layers.push({ properties: newSlideData, sublayers: [newLayerData] }); // Add new slide tab var newIndex = window.lsSliderData.layers.length + 1, title = LS_l10n.SBSlideTitle.replace('%d', newIndex), tab = jQuery(''+title+'').insertBefore('#ls-add-layer'); // Name new slide properly LayerSlider.reindexSlides(); LayerSlider.addSlideSortables(); LS_activeLayerPageIndex = 0; // Show new slide, re-initialize // interactive features tab.click(); LayerSlider.addLayerSortables(); }, removeSlide: function(el) { if(confirm(LS_l10n.SBRemoveSlide)) { // Get tab and menu item index var index = LS_activeSlideIndex; var $tab = jQuery(el).parent(); var $newTab = null; // Open next or prev layer if($tab.next(':not(.unsortable)').length > 0) { $newTab = $tab.next(); } else if($tab.prev().length > 0) { $newTab = $tab.prev(); } // Remove tab and slide data window.lsSliderData.layers.splice(index, 1); $tab.remove(); // Create a new slide if the last one // was removed if(window.lsSliderData.layers < 1) { LayerSlider.addSlide(); return true; } // Select new slide. The .click() event will // maintain the active slide index and data. LayerSlider.reindexSlides(); $newTab.click(); } }, selectSlide: function(slideIndex, selectProperties) { // Set selectProperties to an empty object by default selectProperties = selectProperties || {}; // Bail out early if it's the currently active layer if( !selectProperties.forceSelect && LS_activeSlideIndex === slideIndex) { return false; } // Set active slide, highlight new tab jQuery('#ls-layer-tabs a') .eq(slideIndex) .addClass('active') .attr('data-help-disabled', '1') .siblings() .removeClass('active') .removeAttr('data-help-disabled'); // Stop live preview LayerSlider.stopSlidePreview(); LayerSlider.stopLayerPreview(); // Set new slide index & data LS_activeSlideIndex = slideIndex; LS_activeSlideData = window.lsSliderData.layers[ slideIndex ]; // Create the 'meta' object if not set if(!LS_activeSlideData.meta) { LS_activeSlideData.meta = {}; } // Make sure to include new slide options in all cases var defaults = jQuery.extend( true, {}, LS_DataSource.getDefaultSlideData() ); LS_activeSlideData.properties = jQuery.extend( true, defaults, LS_activeSlideData.properties ); // Set active layer index set LS_activeLayerIndexSet = LS_activeSlideData.meta.activeLayers || [0]; // Add static layers LS_activeStaticLayersDataSet = LayerSlider.staticLayersForSlide( slideIndex ); // Build slide LS_DataSource.buildSlide(); LayerSlider.generatePreview(); LayerSlider.selectLayer(LS_activeLayerIndexSet); LayerSlider.updatePreviewSelection(); LS_UndoManager.update(); }, renameSlide: function(el) { if( document.location.href.indexOf('ls-revisions') !== -1 ) { return; } var $el = jQuery(el); var name = jQuery('span:first-child', el).text(); if($el.hasClass('editing')) { return false; } // Add input $el.addClass('editing'); $input = jQuery('').appendTo($el).val(name); $input.focus().select(); // Save changes on Enter $input.on('keydown', function(e) { if(e.which == 13) { LayerSlider.renameSlideEnd(el); } }); // Save changes by clicking away jQuery('body').one('click', ':not(#ls-layer-tabs a input)', function() { LayerSlider.renameSlideEnd(el); }); }, renameSlideEnd: function(el) { var $el = jQuery(el), $input = jQuery('input', el), index = $el.index(); if($el.hasClass('editing')) { window.lsSliderData.layers[ index ].properties.title = $input.val(); jQuery('span', $el).first().text( $input.val()); $input.remove(); $el.removeClass('editing'); } }, duplicateSlide: function(el) { // Duplicate slide by using jQuery.extend() // to make sure it's a copy instead of an // object reference. var newSlideData = jQuery.extend(true, {}, LS_activeSlideData); // Assign new UUID newSlideData.properties.uuid = LS_DataSource.generateUUID(); // Rename slide if(!!newSlideData.properties.title) { newSlideData.properties.title += ' copy'; } else { newSlideData.properties.title = LS_l10n.SBSlideCopyTitle.replace('%d', LS_activeSlideIndex+1); } // Duplicate slide by using jQuery.extend() // to make sure it's a copy instead of an // object reference. window.lsSliderData.layers.splice( LS_activeSlideIndex + 1, 0, newSlideData ); // Insert the duplicate slide tab after the original var tab = jQuery(''+newSlideData.properties.title+'').insertAfter('#ls-layer-tabs a.active'); LayerSlider.reindexSlides(); LayerSlider.reindexStaticLayers(); // Select new slide tab.click(); }, toggleAdvancedSlideOptions: function( el ) { var $el = jQuery(el), $target = jQuery('.ls-slide-options tr.ls-advanced'); if( $el.hasClass('ls-opened') ) { $el.removeClass('ls-opened'); $target.addClass('ls-hidden'); } else { $el.addClass('ls-opened'); $target.removeClass('ls-hidden'); } }, setPreviewZoom: function( value ) { LS_previewZoom = value; jQuery('.ls-editor-slider-val').text(''+Math.round(value * 100)+'%'); jQuery( '.ls-preview-transform' ).css({ transform: 'scale('+value+')' }).parent().trigger('zoom'); var sliderProps = window.lsSliderData.properties, width = parseInt(sliderProps.sublayercontainer) || sliderProps.width || 1280, height = sliderProps.height || 720; jQuery( '.ls-preview-size' ).css({ width: parseInt(width)* value, height: parseInt(height) * value }); LayerSlider.updatePreviewSelection(); }, addPreviewSlider: function(target, value) { jQuery(target).slider({ value: value, min: 0.5, max: 1.5, step: 0.01, range: 'min', orientation: 'horizontal', slide: function(event, ui) { // Disable auto-fit when resizing manually if( jQuery('#zoom-fit').prop('checked') ){ jQuery('#zoom-fit').next().click(); } LayerSlider.setPreviewZoom(ui.value); // Restart previews (if any) if( LayerSlider.isSlidePreviewActive ) { LayerSlider.stopSlidePreview( ); } if( LayerSlider.isLayerPreviewActive ) { LayerSlider.stopLayerPreview( true ); } }, change: function(event, ui) { LS_previewZoom = ui.value; LayerSlider.updatePreviewSelection(); } }); // Resize preview on page load if( jQuery('#zoom-fit').prop('checked') ) { LayerSlider.autoFitPreview(target); // Slide value on page load } else if(typeof value != "undefined" && value != 1 ) { jQuery(target).slider('value', parseInt(value)); LayerSlider.setPreviewZoom(value); } jQuery(document).on('click','#zoom-fit',function(){ if( jQuery(this).prop('checked') ){ LayerSlider.autoFitPreview(target, 0.75); } }); jQuery(window).resize(function( event ){ if( event.target === window ) { LayerSlider.autoFitPreview(target); } }); jQuery('#collapse-menu').click(function() { LayerSlider.autoFitPreview(target); }); }, autoFitPreview: function(target, duration){ if( jQuery('#zoom-fit').prop('checked') ){ var sliderProps = window.lsSliderData.properties, width = parseInt(sliderProps.sublayercontainer) || parseInt(sliderProps.width) || 1280, height = parseInt(sliderProps.height) || 720, // 905(px) is the minimum width to keep the slider settings table organized smallestRatio = 916 / width > 0.5 ? 916 / width : 0.5, padding = (document.location.href.indexOf('ls-revisions') !== -1) ? 0 : 32, ratio = ( jQuery('.wrap').eq(0).outerWidth() - padding ) / width; if( ratio < smallestRatio ){ ratio = smallestRatio; } else if( ratio > 1 ){ ratio = 1; } jQuery(target).slider('value', ratio ); LayerSlider.setPreviewZoom( ratio ); // jQuery('.ls-editor-slider-val').text(ratio+'%'); // if( duration ){ // TweenLite.to( // jQuery('#ls-preview-layers')[0], // duration, // { // parseTransform: true, // scale: ratio/100, // ease: 'Quint.easeInOut', // onUpdate: function() { // jQuery('.ls-preview-td').trigger('zoom'); // LayerSlider.updatePreviewSelection(); // } // } // ); // TweenLite.to( // [LS_previewHolder, LS_previewWrapper], // duration, // { // width: width * ratio / 100, // height: height * ratio / 100, // ease: 'Quint.easeInOut' // } // ); // }else{ // LayerSlider.setPreviewZoom( ratio ); // } } }, addLayer: function(layerDataSet, atIndexSet, addProperties) { var c, len, selectIndexSet = [], updateInfo = [], emptyData, emptyIndex; // Set removeProperties to an empty object by default addProperties = addProperties || { selectLayer: true }; // Get default layer data if not provided emptyData = !layerDataSet; layerDataSet = layerDataSet || jQuery.extend(true, {}, LS_DataSource.getDefaultLayerData() ); layerDataSet = jQuery.makeArray( layerDataSet ); c = layerDataSet.length; // Add layer to the top if // not specified otherwise. emptyIndex = ! atIndexSet; atIndexSet = ! emptyIndex ? atIndexSet : [].fill(0, c); atIndexSet = jQuery.makeArray( atIndexSet ); // Iterate backwards to keep indexes consistent throughout // the sequence. Don't use .revert() on data sets reference, // as it will change the original set as well. while(c--) { // Add new layer data to data source LS_activeSlideData.sublayers.splice(atIndexSet[c], 0, layerDataSet[c]); // Offsetting indexes to follow data storage // changes in case of multiple additions. selectIndexSet.push( atIndexSet[c] + c ); // UndoManager updateInfo.push({ itemIndex: atIndexSet[c], selectIndex: selectIndexSet[c], undo: { data: {} }, redo: { data: layerDataSet[c] } }); } // Maintain undoManager if( ! addProperties.histroyEvent) { LS_UndoManager.add( 'slide.layers', updateInfo.length > 1 ? LS_l10n.SBUndoNewLayers : LS_l10n.SBUndoNewLayer, updateInfo ); } // Update layers list and preview LS_DataSource.buildLayersList(); LayerSlider.generatePreview(); // Select new layers if( addProperties.selectLayer ) { if( addProperties.hasOwnProperty('selectPage') ) { LS_activeLayerPageIndex = addProperties.selectPage; } LayerSlider.selectLayer( selectIndexSet ); if( emptyData && updateInfo.length === 1 ) { jQuery('.ls-sublayers li.active .ls-sublayer-title').focus().select(); } } }, selectLayer: function(layerIndexSet, selectProperties) { // Bail out early if the current slide has no layers if( ! LS_activeSlideData.sublayers.length) { jQuery('.ls-timeline-switch, .ls-sublayer-nav').hide(); jQuery('.ls-sublayer-pages').empty(); return false; } else { jQuery('.ls-timeline-switch, .ls-sublayer-nav').show(); } // Bail out early if there's no active layer selection if( ! layerIndexSet || ! layerIndexSet.length) { return false; } // Bail out early if the current selection is the same // if( layerIndexSet.length == LS_activeLayerIndexSet.length ) { // if( layerIndexSet.every(function(v,i) { return v === LS_activeLayerIndexSet[i];}) ) { // return false; // } // } // Set removeProperties to an empty object by default selectProperties = selectProperties || {}; // Bail out early if it's already a selected layer // if( !selectProperties.forceSelect && // LS_activeLayerIndexSet.indexOf(layerIndex) !== -1 ) { // return false; // } var $layersList = jQuery('.ls-sublayers li'), $layerOptions = jQuery('.ls-sublayer-pages-wrapper'); // Stop layer preview session (if any) LayerSlider.stopLayerPreview(); // Update stored data & preview based on // the passed selection index set. LS_activeLayerIndexSet = []; LS_activeLayerDataSet = []; $layersList.removeClass('active'); jQuery('#ls-preview-layers > *').removeClass('ui-selected'); jQuery.each(layerIndexSet, function(idx, layerIndex) { LS_activeLayerIndexSet.push(layerIndex); LS_activeLayerDataSet.push( LS_activeSlideData.sublayers[layerIndex] ); LS_previewItems[layerIndex].addClass('ui-selected'); $layersList.eq(layerIndex).addClass('active'); }); if(!LS_activeLayerDataSet[0].meta) { LS_activeLayerDataSet[0].meta = {}; } // Show/Hide layer options depending on // the number of selected layers if(LS_activeLayerIndexSet.length > 1) { $layerOptions.hide().prev().removeClass('ls-hidden'); } else { $layerOptions.show().prev().addClass('ls-hidden'); } // Build new layer ... if(LS_activeLayerIndexSet.length === 1) { LS_DataSource.buildLayer(); } // Store selection LS_Utils.removeTextSelection(); LayerSlider.updatePreviewSelection(); LS_activeSlideData.meta.activeLayers = LS_activeLayerIndexSet; jQuery('.ls-timeline-switch, .ls-sublayer-nav').show(); // Create layer transition preview animations layerTransitionPreview.create(); }, selectLayerPage: function(pageIndex) { // Select new tab jQuery('.ls-sublayer-nav a').removeClass('active') .eq(pageIndex).addClass('active'); // Show the corresponding page jQuery('#ls-layers .ls-sublayer-page').removeClass('active') .eq( pageIndex ).addClass('active'); // Store lastly selected layer page LS_activeLayerPageIndex = pageIndex; // SET: styles kmUI.smartResize.set(); }, selectTransitionPage: function( td ) { var $td = jQuery(td), index = ($td.index() - 1) / 2, $target = jQuery('#ls-layer-transitions').children().eq(index); $target.addClass('active').siblings().removeClass('active'); $td.addClass('selected').siblings().removeClass('selected'); jQuery( '#ls-transition-selector' ).val( index ); LS_activeLayerTransitionTab = index; $target.removeClass('disabled'); if( ! $target.find('.ls-h-button input').prop('checked') ) { $target.addClass('disabled'); } }, enableTransitionPage: function( input ) { LayerSlider.reorderTransitionProperties( jQuery( input ).closest('section').index() ); LayerSlider.checkForOpeningTransition(); }, checkForOpeningTransition: function() { $table = jQuery('#ls-transition-selector-table'); $transitions = jQuery('.ls-opening-transition.active', $table); $warning = jQuery('#ls-transition-warning'); $warning[ $transitions.length ? 'removeClass' : 'addClass' ]('visible'); }, reorderTransitionProperties: function( sectionIndex ) { var media = LS_activeLayerDataSet[0].media || '', index, $sections = jQuery('#ls-layer-transitions').children(), $section, $input, $td; if( sectionIndex ) { $sections = $sections.eq( sectionIndex ); } $sections.each(function() { $section = jQuery(this); index = $section.index(); $input = $section.find('input.toggle').eq(0); $td = jQuery('#ls-transition-selector-table td:not(.ls-padding)').eq( index ); // Disabled if( ! $input.prop('checked') ) { $td.removeClass('active'); $section.addClass('disabled'); $section.find(':input').each(function() { var $this = jQuery(this), name = $this.attr('name'), value = $this.is(':checkbox') ? $this.prop('checked') : $this.val(); if( name && ! $this.is('.toggle') ) { $this.data('value', value ); delete LS_activeLayerDataSet[0].transition[ name ]; } }); // Active } else { $td.addClass('active'); $section.removeClass('disabled'); $section.find(':input').each(function() { var $this = jQuery(this), name = $this.attr('name'), value = $this.data('value'); if( name && ! $this.is('.toggle') ) { LS_activeLayerDataSet[0].transition[ name ] = value; } }); } }); }, removeLayer: function(layerIndexSet, removeProperties) { // Set removeProperties to an empty object by default removeProperties = removeProperties || { requireConfirmation: true }; // Require confirmation from user // if it's not a history event. if( removeProperties.requireConfirmation ) { if( !confirm( LS_l10n.SBRemoveLayer ) ) { return false; } } // Get active layers if no index was provided if( ! layerIndexSet && layerIndexSet !== 0 ) { layerIndexSet = LS_activeLayerIndexSet; // Convert a single index to an index set } else if( typeof layerIndexSet === 'number') { layerIndexSet = [layerIndexSet]; } // Get layer(s) var c = layerIndexSet.length, $layers = jQuery('.ls-sublayers li'), updateInfo = [], $layer, $newLayer, layerIndex, layerData; // Iterate backwards to keep indexes consistent throughout the sequence. // Don't use .revert() on a LS_activeLayerIndexSet reference, as it will // change the original set as well. while(c--) { layerIndex = layerIndexSet[c]; $layer = $layers.eq(layerIndex); layerData = jQuery.extend(true, {}, LS_activeSlideData.sublayers[layerIndex]); // Get the next or prev layer if($layer.next().length > 0) { $newLayer = $layer.next(); } else if($layer.prev().length > 0) { $newLayer = $layer.prev(); } // Setup UndoManager updateInfo object updateInfo.push({ itemIndex: layerIndex, undo: { data: layerData }, redo: { data: {} } }); // Remove layer from data source and UI LS_activeSlideData.sublayers.splice(layerIndex, 1); $layer.remove(); } // Empty slide, hide UI items if(!LS_activeSlideData.sublayers.length) { jQuery('.ls-timeline-switch, .ls-sublayer-nav').hide(); jQuery('.ls-sublayer-pages').empty(); // Update UI otherwise // Select new layer. The .click() event will // maintain the active layer index and data. } else if($newLayer) { $newLayer.click(); LayerSlider.reindexLayers(); } // Update preview LayerSlider.generatePreview(); LayerSlider.updatePreviewSelection(); // Maintain undoManager only if // it wasn't a history action if( !removeProperties.histroyEvent && updateInfo.length) { LS_UndoManager.add('slide.layers', LS_l10n.SBUndoRemoveLayer, updateInfo); } }, hideLayer: function(el) { // Get layer index var layerIndex = jQuery(el).closest('li').index(); var layerData = LS_activeSlideData.sublayers[layerIndex]; // Maintain history LS_UndoManager.add('layer.general', LS_l10n.SBUndoHideLayer, { itemIndex: layerIndex, undo: { skip: !!layerData.skip }, redo: { skip: !layerData.skip } }); // Hide/show layer layerData.skip = !layerData.skip; if(layerData.skip) { jQuery(el).addClass('disabled'); } else { jQuery(el).removeClass('disabled'); } // Update preview LayerSlider.generatePreviewItem(layerIndex); }, lockLayer: function(el) { // Get layer index var layerIndex = jQuery(el).closest('li').index(), layerData = LS_activeSlideData.sublayers[layerIndex], $previewItem = LayerSlider.previewItemAtIndex(layerIndex); // Maintain history LS_UndoManager.add('layer.general', LS_l10n.SBUndoLockLayer, { itemIndex: layerIndex, undo: { locked: !!layerData.locked }, redo: { locked: !layerData.locked } }); // Lock layer layerData.locked = !layerData.locked; if(layerData.locked) { jQuery(el).removeClass('disabled'); $previewItem.addClass('disabled'); $lasso.hide(); // Unlock layer } else { jQuery(el).addClass('disabled'); $previewItem.removeClass('disabled'); } }, setLayerMedia: function(mediaType, $mediaEl, layerData) { switch(mediaType) { case 'img': var src = layerData.imageThumb || pluginPath+'admin/img/blank.gif', classes = layerData.imageThumb ? '' : ' dashicons dashicons-format-image'; $mediaEl.attr('class', 'ls-sublayer-thumb'+classes).html(''); break; case 'html': $mediaEl.addClass('dashicons dashicons-editor-code'); break; case 'media': $mediaEl.addClass('dashicons dashicons-video-alt3'); break; case 'post': $mediaEl.addClass('dashicons dashicons-admin-post'); break; default: $mediaEl.addClass('dashicons dashicons-editor-textcolor'); break; } }, setLayerAttributes: function( event, element ) { if( event.type === 'change' && ! jQuery(element).is(':checkbox') ) { return; } var $tr = jQuery(element).closest('tr'), $inputs = jQuery('input', $tr ), innerAttrs = LS_activeLayerDataSet[0].innerAttributes = {}, outerAttrs = LS_activeLayerDataSet[0].outerAttributes = {}; if( ! $inputs.eq(0).val() && ! $inputs.eq(1).val() ) { $tr.remove(); return; } jQuery('.ls-sublayer-custom-attributes tr:not(:last-child)').each(function() { var $key = jQuery('td.first input', this), $val = jQuery('td.second input', this), $chb = jQuery('td.third input', this), key = $key.val(), val = $val.val(); if( key && /^[a-zA-Z]([a-zA-Z0-9_-]+)$/.test( key ) ) { $key.removeClass('error'); if( $chb.prop('checked') ) { outerAttrs[ key ] = val; } else { innerAttrs[ key ] = val; } } else { $key.addClass('error'); } }); }, updateLayerAttributes: function( layerData ) { // Make sure to have objects for data layerData.innerAttributes = layerData.innerAttributes || {}; layerData.outerAttributes = layerData.outerAttributes || {}; var customAttrs = jQuery.extend( {}, layerData.innerAttributes, layerData.outerAttributes), $customAttributes = jQuery('.ls-sublayer-custom-attributes'); // Sort keys Object.keys(customAttrs).sort().forEach(function(key) { var value = customAttrs[key]; delete customAttrs[key]; customAttrs[key] = value; }); jQuery.each(customAttrs, function(key, val) { jQuery('tr:last-child input:eq(2)', $customAttributes).prop('checked', key in layerData.outerAttributes ); jQuery('tr:last-child input:eq(1)', $customAttributes).val( val ); jQuery('tr:last-child input:eq(0)', $customAttributes).val( key ).trigger('keyup'); }); }, updateLayerBorderPadding: function(el) { var $input = jQuery(el), value = parseInt( $input.val() ), type = ($input.parent().index() === 1) ? 'border' : 'padding', edge = $input.closest('tr').data('edge'); sel = '.ls-'+type+'-'+edge+'-value'; jQuery(sel).text( value || '–' ); }, // Iterate through all slides and their layers to // find the ones appearing on the target slide. staticLayersForSlide: function( targetSlideIndex ) { var staticLayers = []; jQuery.each(window.lsSliderData.layers, function(slideIndex, slideData) { jQuery.each(slideData.sublayers, function(layerIndex, layerData) { if( layerData.transition.static ) { var staticOut = layerData.transition.static; if( ( staticOut > targetSlideIndex || staticOut === 'forever' ) && slideIndex < targetSlideIndex ) { staticLayers.push({ slideIndex: slideIndex, slideData: slideData, layerIndex: layerIndex, layerData: layerData }); } } }); }); return staticLayers; }, reindexStaticLayers: function() { jQuery.each(window.lsSliderData.layers, function(slideIndex, slideData) { jQuery.each(slideData.sublayers, function(layerIndex, layerData) { if( layerData.transition.staticUUID ) { var staticOut = LS_DataSource.slideForUUID( layerData.transition.staticUUID ); if( staticOut ) { layerData.transition.static = staticOut + 1; } } }); }); }, setupStaticLayersChooser: function( select ) { var $select = jQuery(select); // Remove previously added options $select.children(':gt(1)').remove(); // Gather slide data var sliderData = window.lsSliderData, slideCount = sliderData.layers ? sliderData.layers.length : 0, markup = '', slideName; // Generate markup for( var s = 0; s < slideCount; s++) { slideName = sliderData.layers[s].properties.title; slideName = slideName ? ' ('+slideName+')' : ''; markup += ''; } // Append select options $select.append(markup); var staticVal = parseInt( LS_activeLayerDataSet[0].transition.static ); if( staticVal ) { $select.children('[value="'+staticVal+'"]').prop('selected', true) .siblings().prop('selected', false); } }, revealStaticLayer: function( el ) { var $target = jQuery(el).closest('li'), index = $target.index(), data = LS_activeStaticLayersDataSet[ index ]; LayerSlider.selectSlide( data.slideIndex ); LayerSlider.selectLayer( [data.layerIndex] ); }, addColorPicker: function(el) { jQuery(el).minicolors({ opacity: true, changeDelay: 100, position: 'bottom right', change: function(hex, opacity) { //LayerSlider.willGeneratePreview(); } }).blur(function( event ) { event.stopImmediatePropagation(); jQuery(this) .removeClass('ls-colorpicker') .trigger('change') .addClass('ls-colorpicker'); }); }, duplicateLayer: function() { this.pasteLayer( this.copyLayer(false).layers ); }, copyLayer: function(useStorage, layerDataSet, layerIndexSet, copyProperties) { // Defaults useStorage = useStorage || true; layerDataSet = layerDataSet || LS_activeLayerDataSet; layerIndexSet = layerIndexSet || LS_activeLayerIndexSet; copyProperties = copyProperties || { shiftLayers: true }; // Iterate over the data set, clone objects and // make some visual adjustments on items var clipboardData = []; jQuery.each(layerDataSet, function(key, item) { // Copy layer data object var copy = jQuery.extend(true, {}, item); copy.subtitle += ' copy'; if( copyProperties.shiftLayers ) { // copy.styles.top = (copy.styles.top.indexOf('%') == -1) ? parseInt(copy.styles.top) + 10 + 'px' : parseInt(copy.styles.top) + 1 + '%'; // copy.styles.left = (copy.styles.left.indexOf('%') == -1) ? parseInt(copy.styles.left) + 10 + 'px' : parseInt(copy.styles.left) + 1 + '%'; } // Add copy to the new set clipboardData.push(copy); }); // Build clipboard data clipboardData = { layers: clipboardData, sliderID: copyProperties.sliderID || LS_sliderID, slideIndex: copyProperties.slideIndex || LS_activeSlideIndex, layerIndexSet: layerIndexSet }; // Save to storage and return copies useStorage && localStorage.setObject('ls-layer-clipboard', clipboardData); return clipboardData; }, pasteLayer: function(layerDataSet, layerIndexSet, pasteProperties) { // Check for provided data, fetch from clipboard if not var isDataProvided = layerDataSet ? true : false, clipboardData = localStorage.getObject('ls-layer-clipboard'), addIndexSet; if( ! clipboardData ) { alert(LS_l10n.SBPasteLayerError); return; } layerDataSet = layerDataSet || clipboardData.layers; layerIndexSet = layerIndexSet || clipboardData.layerIndexSet; // Warn users when there's nothing on the clipboard // and halt execution. if( ! layerDataSet ) { alert(LS_l10n.SBPasteLayerError); return; } // Set pasteProperties to an empty object by default pasteProperties = pasteProperties || {}; // If the layer is from the same slide, then // find the uppermost selected layer index // and insert everything into that position. // Otherwise insert at the beginning of the layers list. // - // Trying to insert layers before their parents // individually is complex, and it will fragment // dupe selection. if(clipboardData.sliderID !== LS_sliderID || clipboardData.slideIndex !== LS_activeSlideIndex) { addIndexSet = [].fill( 0, layerIndexSet.length); } else { addIndexSet = [].fill( Math.min.apply(Math, layerIndexSet), layerIndexSet.length); } // Insert new layers LayerSlider.addLayer(layerDataSet, addIndexSet, { selectLayer: true } ); // Copy pasted layer to make a new reference // and update settings like position and name if( ! isDataProvided) { this.copyLayer(true, layerDataSet, layerIndexSet, { sliderID: clipboardData.sliderID, slideIndex: clipboardData.slideIndex }); } }, selectMediaType: function(el, layerIndex) { // Gather layer data layerIndex = layerIndex ? layerIndex : LS_activeLayerIndexSet; layerIndex = (typeof layerIndex === 'object') ? layerIndex[0] : layerIndex; var layerData = LS_activeSlideData.sublayers[layerIndex], layer = jQuery(el).closest('.ls-sublayer-page'), $layerItem = jQuery('.ls-sublayers li').eq(layerIndex), section = jQuery(el).data('section'), placeholder = jQuery(el).data('placeholder'), sections = jQuery('.ls-layer-sections', layer).children(); // Set active class jQuery(el).attr('class', 'active').siblings().removeAttr('class'); // Store selection if( section ) { layerData.media = section; } // Show the corresponding sections sections.hide().removeClass('ls-hidden'); jQuery('.ls-sublayer-element', layer).hide().removeClass('ls-hidden'); jQuery('.ls-html-code .ls-options, .ls-html-code .ls-insert-media', layer).addClass('ls-hidden'); switch(section) { case 'img': sections.eq(0).show(); var src = layerData.imageThumb || pluginPath+'admin/img/blank.gif', classes = layerData.imageThumb ? '' : ' dashicons dashicons-format-image'; jQuery('.ls-sublayer-thumb', $layerItem).attr('class', 'ls-sublayer-thumb'+classes).html(''); break; case 'text': sections.eq(1).show(); layer.find('.ls-sublayer-element').show(); jQuery('.ls-html-code textarea').attr('placeholder', placeholder ); jQuery('.ls-sublayer-thumb', $layerItem).attr('class', 'ls-sublayer-thumb dashicons dashicons-editor-textcolor').html(''); break; case 'html': sections.eq(1).show(); jQuery('.ls-html-code .ls-options, .ls-html-code .ls-insert-media', layer).addClass('ls-hidden'); jQuery('.ls-html-code textarea').attr('placeholder', placeholder ); jQuery('.ls-sublayer-thumb', $layerItem).attr('class', 'ls-sublayer-thumb dashicons dashicons-editor-code').html(''); break; case 'media': sections.eq(1).show(); jQuery('.ls-html-code .ls-options, .ls-html-code .ls-insert-media', layer).removeClass('ls-hidden'); jQuery('.ls-html-code textarea').attr('placeholder', placeholder ); jQuery('.ls-sublayer-thumb', $layerItem).attr('class', 'ls-sublayer-thumb dashicons dashicons-video-alt3').html(''); break; case 'post': sections.eq(1).show(); sections.eq(2).show(); jQuery('.ls-html-code textarea').attr('placeholder', placeholder ); jQuery('.ls-sublayer-thumb', $layerItem).attr('class', 'ls-sublayer-thumb dashicons dashicons-admin-post').html(''); break; } if( section === 'img' || section === 'media' ) { jQuery('#ls-layer-transitions .ls-text-transition .ls-checkbox.toggle.on').click(); } jQuery('.ls-sublayer-pages-wrapper').attr('class', 'ls-sublayer-pages-wrapper ls-layer-type-' + layerData.media); }, selectElementType: function(el, layerIndex) { // Layer and properties layerIndex = layerIndex ? layerIndex : LS_activeLayerIndexSet; layerIndex = (typeof layerIndex === 'object') ? layerIndex[0] : layerIndex; var layerData = LS_activeSlideData.sublayers[layerIndex], layer = jQuery(el).closest('.ls-sublayer-page'), element = jQuery(el).data('element'); // Set active class jQuery(el).siblings().removeClass('active'); jQuery(el).addClass('active'); // Store selection if( element ) { layerData.type = element; } }, copyLayerSettings: function(el) { var $el = jQuery(el), $wrapper = $el.closest('[data-storage]'), storage = $wrapper.attr('data-storage'), data = { styles: {}, transition: {} }; // Iterate over options, store values $wrapper.find(':input').each(function() { if(this.name) { var $item = jQuery(this), area = $item.hasClass('sublayerprop') ? 'transition' : 'styles'; data[area][this.name] = $item.is(':checkbox') ? $item.prop('checked') : $item.val(); } }); // Add data to clipboard var LS_clipboard = localStorage.getObject('ls-options-clipboard') || {}; LS_clipboard[ storage ] = { timestamp: Math.floor(Date.now() / 1000), data: data }; localStorage.setObject('ls-options-clipboard', LS_clipboard); // Send feedback to users $el.css('color', '#fcd116'); setTimeout(function() { $el.css('color', '#00a0d2'); }, 1000); }, pasteLayerSettings: function(el) { var $el = jQuery(el), $wrapper = $el.closest('[data-storage]'), storage = $wrapper.attr('data-storage'), undoObj = {}, redoObj = {}, undoArea; // Don't allow pasting options when the corresponding // transition sections is disabled if( $wrapper.closest('#ls-layer-transitions').length ) { if( ! $wrapper.find('.ls-h-button input').prop('checked') ) { $wrapper.find('.overlay').click(); return; } } // Get clipboard data var LS_clipboard = localStorage.getObject('ls-options-clipboard') || {}, clipboard = LS_clipboard[storage], timestamp = Math.floor(Date.now() / 1000); // Validate clipboard data if( ! clipboard || jQuery.isEmptyObject(clipboard.data) || clipboard.timestamp < timestamp - 60 * 60 * 3 ) { alert(LS_l10n.SBPasteError); return false; } // Iterate over options, set new values $wrapper.find(':input').each(function() { if(this.name && this.name != 'top' && this.name != 'left') { // !!! don't paste left & top style var $this = jQuery(this), area = $this.hasClass('sublayerprop') ? 'transition' : 'styles', curVal = $this.is(':checkbox') ? $this.prop('checked') : $this.val(), newVal = clipboard.data[area][this.name]; if( curVal != newVal ) { if($this.is(':checkbox')) { $this.next().click(); } else { $this.val( newVal ).trigger('input').trigger('keyup'); } if( ! undoObj[ area ] ) { undoObj[ area ] = {}; } if( ! redoObj[ area ] ) { redoObj[ area ] = {}; } undoObj[ area ][ this.name ] = curVal; redoObj[ area ][ this.name ] = newVal; } // Handle custom CSS field separately if( this.name === 'style' ) { LS_activeLayerDataSet[0]['style'] = newVal; } else { LS_activeLayerDataSet[0][area][ this.name ] = newVal; } } }); // Add UndoManager action LS_UndoManager.add('layer.general', LS_l10n.SBUndoPasteSettings, { itemIndex: LS_activeLayerIndexSet[0], undo: undoObj, redo: redoObj }); $el.css('color', '#90ca77'); setTimeout(function() { $el.css('color', '#00a0d2'); }, 1000); if( undoArea === 'style' ) { LayerSlider.generatePreviewItem( LS_activeLayerIndexSet[0] ); } }, updateSlideInterfaceItems: function() { var slideData = LS_activeSlideData.properties, imgSrc = slideData.backgroundThumb ? slideData.backgroundThumb : slideData.background; LS_GUI.updateImagePicker( 'background', imgSrc ); }, updateLayerInterfaceItems: function(layerIndex) { var $layer = jQuery('.ls-sublayer-pages'), $layerItem = jQuery('.ls-sublayers li').eq(layerIndex), layerData = LS_activeSlideData.sublayers[layerIndex]; if( ! layerData ) { return; } // Image layer preview var imgSrc = layerData.imageThumb ? layerData.imageThumb : layerData.image; LS_GUI.updateImagePicker( 'image', imgSrc ); // Video poster preview imgSrc = layerData.posterThumb ? layerData.posterThumb : layerData.poster; LS_GUI.updateImagePicker( 'poster', imgSrc ); // Select layer and media type if(typeof layerData.media == 'undefined') { switch(layerData.type) { case 'img': layerData.media = 'img'; break; case 'div': layerData.media = 'html'; break; default: layerData.media = 'text'; } } LayerSlider.selectMediaType( $layer.find('.ls-layer-kind li[data-section="'+layerData.media+'"]'), layerIndex ); LayerSlider.selectElementType( $layer.find('.ls-sublayer-element > li[data-element="'+layerData.type+'"]'), layerIndex ); // Skip if(layerData.skip) { jQuery('.ls-icon-eye', $layerItem).addClass('disabled'); } else { jQuery('.ls-icon-eye', $layerItem).removeClass('disabled'); } if(layerData.locked) { jQuery('.ls-icon-lock', $layerItem).removeClass('disabled'); } else { jQuery('.ls-icon-lock', $layerItem).addClass('disabled'); } }, changeLayerScreenType: function( $button, updateLayer ) { jQuery('.ls-set-screen-types button').each(function() { var layerData = LS_activeLayerDataSet[0], $item = jQuery(this), type = $item.data('type'); if( $button && $button.is( $item ) ) { layerData['hide_on_'+type] = ! layerData['hide_on_'+type]; } $item[ layerData['hide_on_'+type] ? 'removeClass' : 'addClass' ]('playing'); }); if( updateLayer ) { LayerSlider.generatePreviewItem( LS_activeLayerIndexSet[0] ); setTimeout(function() { LS_DataSource.buildLayersListItem( LS_activeLayerIndexSet[0] ); }, 200); } }, changeVideoType: function() { var $input = jQuery('.ls-sublayer-basic input.bgvideo'), $options = jQuery('.ls-sublayer-basic .ls-media-options'); $overlays = jQuery('.ls-sublayer-basic .ls-bgvideo-options'); if( $input.prop('checked') ) { $options.hide(); $overlays.show(); LS_activeLayerDataSet[0].locked = true; } else { $options.show(); $overlays.hide(); LS_activeLayerDataSet[0].locked = false; } }, validateCustomCSS: function( $textarea ) { var keys = ['mix-blend-mode', 'filter']; for(var c = 0; c < keys.length; c++) { if( $textarea.val().indexOf(keys[c]) !== -1 ) { $textarea.val( $textarea.val().replace( new RegExp(keys[c], 'gi'), '') ); TweenMax.to( jQuery('.ls-sublayer-style :input[name="'+keys[c]+'"]')[0], 0.15, { yoyo: true, repeat: 3, ease: Quad.easeInOut, scale: 1.2, backgroundColor: 'rgba(255, 0, 0, 0.2)' }); } } }, willGeneratePreview: function() { clearTimeout(LayerSlider.timeout); LayerSlider.timeout = setTimeout(function() { LayerSlider.generatePreview(); }, 1000); }, generatePreview: function() { // ––––––––––––––––––––––––––––––––––––––––––––– // READ-ONLY BLOCK // // Group DOM read/access operations together, // so the browser can cache and apply them in a // in a single pass, triggering only one reflow. // ———————————————————————————–––––––––––––––––– // Slider data sets var sliderProps = window.lsSliderData.properties, slideIndex = LS_activeSlideIndex, slideData = LS_activeSlideData, slideProps = slideData.properties, layers = slideData.sublayers, $settings = jQuery('.ls-settings'), // Preview data width = parseInt( sliderProps.sublayercontainer) || parseInt(sliderProps.width) || 1280, height = parseInt(sliderProps.height) || 720, bgColor = sliderProps.backgroundcolor, bgImage = sliderProps.backgroundimage, yourLogo = sliderProps.yourlogo, yourLogoStyle = sliderProps.yourlogostyle, posts = window.lsPostsJSON, postOffset = slideProps.post_offset, slideBG = slideProps.background, slideBGSize = slideProps.bgsize, slideBGPos = slideProps.bgposition, post; // --- Adjust default values --- height = (height.indexOf('%') !== -1) ? 400 : parseInt(height); postOffset = (postOffset == -1) ? slideIndex : postOffset; post = posts[ postOffset ] || {}; // ––––––––––––––––––––––––––––––––––––––––––––– // WRITE-ONLY BLOCK // // Use only DOM write operations after this comment, // so the browser can cache and apply them in a // in a single pass, triggering only one reflow. // ———————————————————————————–––––––––––––––––– // --- Set preview canvas size --- LS_previewArea.css({ width : width, height : height }).empty(); jQuery('.ls-preview-size').css({ width : width * LS_previewZoom, height : height * LS_previewZoom }); // Make sure to follow preview area size changes jQuery('.ls-ruler').trigger('resize'); LayerSlider.autoFitPreview(); // --- Set global background --- LS_previewHolder.css({ backgroundColor : bgColor || 'transparent', backgroundImage : bgImage ? 'url('+bgImage+')' : 'none', backgroundRepeat: sliderProps.globalBGRepeat, backgroundAttachment: sliderProps.globalBGAttachment, backgroundPosition: sliderProps.globalBGPosition, backgroundSize: sliderProps.globalBGSize }); // Empty preview items list, so we don't include beyond // array bounds objects from previous slide in case of // slide change. LS_previewItems = []; // Handle post content if(slideBG == '[image-url]') { slideBG = post['image-url']; LS_GUI.updateImagePicker( 'background', post['image-url'], { fromPost: true }); } // -- Set slide background && empty previous content --- if( ! slideBGSize || slideBGSize === 'inherit') { slideBGSize = sliderProps.slideBGSize; } if( ! slideBGPos || slideBGPos === 'inherit') { slideBGPos = sliderProps.slideBGPosition; } LS_previewArea.css({ backgroundImage: slideBG ? 'url('+slideBG+')' : 'none', backgroundSize: slideBGSize || 'auto', backgroundPosition: slideBGPos || 'center center', backgroundColor: slideProps.bgcolor || 'transparent', backgroundRepeat: 'no-repeat' }); // -- Set background on slide tab slideBG = slideBG || pluginPath+'admin/img/blank.gif'; jQuery('#ls-layer-tabs a').eq(slideIndex).data('help', ""); // --- Setup yourLogo --- LS_previewHolder.parent().find('.yourlogo').remove(); if( yourLogo ) { var logo = jQuery('').prependTo( LS_previewHolder ); logo.attr('style', yourLogoStyle); var oL, oR, oT, oB, logoLeft, logoRight, logoTop, logoBottom; oL = oR = oT = oB = 'auto'; if( logo.css('left') != 'auto' ){ logoLeft = logo[0].style.left; } if( logo.css('right') != 'auto' ){ logoRight = logo[0].style.right; } if( logo.css('top') != 'auto' ){ logoTop = logo[0].style.top; } if( logo.css('bottom') != 'auto' ){ logoBottom = logo[0].style.bottom; } if( logoLeft && logoLeft.indexOf('%') != -1 ){ oL = width / 100 * parseInt( logoLeft ) - logo.width() / 2; }else{ oL = parseInt( logoLeft ); } if( logoRight && logoRight.indexOf('%') != -1 ){ oR = width / 100 * parseInt( logoRight ) - logo.width() / 2; }else{ oR = parseInt( logoRight ); } if( logoTop && logoTop.indexOf('%') != -1 ){ oT = height / 100 * parseInt( logoTop ) - logo.height() / 2; }else{ oT = parseInt( logoTop ); } if( logoBottom && logoBottom.indexOf('%') != -1 ){ oB = height / 100 * parseInt( logoBottom ) - logo.height() / 2; }else{ oB = parseInt( logoBottom ); } logo.css({ left : oL, right : oR, top : oT, bottom : oB }); } // --- Setup layers --- for(var c = 0, len = layers.length; c < len; c++) { LayerSlider.generatePreviewItem( c, post); } // --- Setup static layers --- LayerSlider.generateStaticPreview(); }, generateStaticPreview: function() { LS_previewArea.children('.ls-static-layer').remove(); jQuery.each(LS_activeStaticLayersDataSet, function(idx, data) { LayerSlider.generatePreviewItem( idx, false, { $targetArea: LS_previewArea, $layerItem: LS_previewArea.children('.ls-static-layer').eq(idx), layerData: data.layerData, isStatic: true }); }); }, willGeneratePreviewItem: function(layerIndex) { clearTimeout(LayerSlider.timeout); LayerSlider.timeout = setTimeout(function() { LayerSlider.generatePreviewItem(layerIndex); }, 150); }, generatePreviewItem: function(layerIndex, post, generateProperties) { if( jQuery.type( layerIndex ) === 'array' ) { layerIndex = layerIndex[0]; } generateProperties = generateProperties || {}; generateProperties = jQuery.extend({}, { $targetArea: LS_previewArea, $layerItem: LS_previewItems[layerIndex], layerData: LS_activeSlideData.sublayers[layerIndex], isStatic: false }, generateProperties); // Don't update the editor while live previews are active if( LayerSlider.isLayerPreviewActive ) { return false; } // Remove affected item to replace with an updated one if( generateProperties.$layerItem ) { generateProperties.$layerItem.remove(); } // Get layer data sets var layerData = generateProperties.layerData, layerCount = LS_activeSlideData.sublayers ? LS_activeSlideData.sublayers.length : 0, // Get layer attributes item, type = layerData.type, html = layerData.html, id = layerData.id, // Get style settings top = layerData.styles.top, left = layerData.styles.left, innerAttrs = layerData.innerAttributes || {}, outerAttrs = layerData.outerAttributes || {}; if( generateProperties.isStatic ) { layerIndex = layerCount + layerIndex; } switch( layerData.media ) { case 'img': type = 'img'; break; case 'media': case 'html': type = 'div'; break; case 'post': type = 'post'; break; } // Get post content if not passed if( ! post ) { var posts = window.lsPostsJSON, postOffset = LS_activeSlideData.properties.post_offset; if( postOffset == -1 ) { postOffset = LS_activeSlideIndex; } post = posts[postOffset] || {}; } // Hidden layer if(layerData.skip || layerData['hide_on_'+LS_activeScreenType] ) { item = jQuery('
').appendToWithIndex(generateProperties.$targetArea, layerIndex).hide(); if( ! generateProperties.isStatic ) { LS_previewItems[layerIndex] = item; } return true; } // Append element if(type == 'img') { var url = layerData.image; if(url == '[image-url]') { url = post['image-url'] || ''; LS_GUI.updateImagePicker( 'image', post['image-url'], { fromPost: true } ); } var tmpContent = url ? '' : '
'; item = jQuery(tmpContent).hide().appendToWithIndex(generateProperties.$targetArea, layerIndex); } else if(type == 'post') { var textlength = layerData.post_text_length; for(var key in post) { if(html.indexOf('['+key+']') !== -1) { var postVal = post[key]; if( (key == 'title' || key == 'content' || key == 'excerpt') && textlength > 0) { postVal = LS_Utils.stripTags(postVal).substr(0, textlength); postVal = LS_Utils.nl2br(postVal); } html = html.replace('['+key+']', postVal); } } // Test for html wrapper html = jQuery.trim(html); var first = html.substr(0, 1), last = html.substr(html.length-1, 1); if(first == '<' && last == '>') { html = html.replace(/(\r\n|\n|\r)/gm,""); item = jQuery(html).appendToWithIndex(generateProperties.$targetArea, layerIndex); } else { item = jQuery('
').html(html).appendToWithIndex(generateProperties.$targetArea, layerIndex); } } else { item = jQuery('<'+type+'>').appendToWithIndex(generateProperties.$targetArea, layerIndex); if(html !== '') { item.html(html); } } // Restore selection if( ! generateProperties.isStatic ) { LS_previewItems[layerIndex] = item; if(LS_activeLayerIndexSet.indexOf(layerIndex) !== -1) { item.addClass('ui-selected'); } else { item.removeClass('ui-selected'); } } // Add ls-l or static layer classes item.addClass( generateProperties.isStatic ? 'disabled ls-static-layer' : 'ls-l' ); // Sublayer properties var transforms = {}, trKey, trVal, defVal; for( trKey in layerData.transition) { if( LS_transformStyles.indexOf( trKey ) !== -1) { trVal = layerData.transition[trKey]; if( ! trVal && trVal !== 0 ) { continue; } trVal = trVal.toString(); defVal = ( trKey.indexOf('scale') !== -1 ) ? 1 : 0; if( parseInt(trVal) !== defVal ) { transforms[ trKey ] = parseFloat( trVal ); } } } // Styles var styles = { 'z-index': (100 + layerCount) - layerIndex }; for(var sKey in layerData.styles) { var cssVal = layerData.styles[sKey]; if( ! cssVal && cssVal !== 0 ) { continue; } cssVal = cssVal.toString(); if( cssVal.slice(-1) == ';' ) { cssVal = cssVal.substring(0, cssVal.length - 1); } styles[sKey] = isNumber(cssVal) ? cssVal + 'px' : cssVal; if( ['z-index', 'font-weight', 'opacity'].indexOf( sKey ) !== -1 ) { styles[sKey] = cssVal; } } // Locked layer layerData.hasTransforms = ! jQuery.isEmptyObject( transforms ); if( layerData.locked ) { item.addClass('disabled'); } if( layerData.hasTransforms ) { item.addClass('transformed'); } if( document.location.href.indexOf('ls-revisions') !== -1 ) { item.addClass('disabled'); } // Apply style settings and attributes item.attr( jQuery.extend({}, innerAttrs, outerAttrs) ).attr({ id: id, style: layerData.style, }).css(styles).css({ whiteSpace: !layerData.styles.wordwrap ? 'nowrap' : 'normal', }).addClass(layerData['class']); // Iframes & media embeds var $iframe = item.children('iframe,video').eq(0); if( $iframe.length ) { if( layerData.transition.backgroundvideo ) { item.addClass('disabled bgvideo').css({ pointerEvents: 'none' }); if( layerData.transition.overlay ) { if( layerData.transition.overlayer !== 'disabled' ) { jQuery('
', { 'class': 'video-overlay', 'style': 'background-image: url('+layerData.transition.overlay+')' }).appendTo( item ); } } // Exit script LayerSlider.updatePreviewSelection(); return; } else { var width = parseInt( $iframe.attr('width') ) || $iframe.width(), height = parseInt( $iframe.attr('height') ) || $iframe.height(); if( ! layerData.styles.width ) { item.width( width ); } if( ! layerData.styles.height ) { item.height( height ); } } } if( item.is('img') ) { item.on( 'load', function(){ LayerSlider.setPositions(item, top, left); LayerSlider.updatePreviewSelection(); clearTimeout(LayerSlider.selectableTimeout); LayerSlider.selectableTimeout = setTimeout(function() { LayerSlider.updatePreviewSelection(); }, 100); }).attr('src',item.attr('src') ); }else{ LayerSlider.setPositions(item, top, left); LayerSlider.updatePreviewSelection(); } // DO TRANSFORMS transforms.transformPerspective = 500; transforms.transformOrigin = layerData.transition.transformoriginin || '50% 50% 0'; if( transforms.transformOrigin.indexOf( 'slider') !== -1 ){ var sliderWidth = parseInt( window.lsSliderData.properties.sublayercontainer ) || parseInt( window.lsSliderData.properties.width ) || 1280, sliderHeight = parseInt( window.lsSliderData.properties.height ) || 720, itemLeft = parseFloat( item[0].style.left ), itemTop = parseFloat( item[0].style.top ), itemWidth = item.outerWidth(), itemHeight = item.outerHeight(); transforms.transformOrigin = transforms.transformOrigin .replace( 'sliderleft', -itemLeft + 'px' ) .replace( 'sliderright', sliderWidth - itemLeft + 'px' ) .replace( 'slidercenter', sliderWidth / 2 - itemLeft + 'px' ) .replace( 'slidermiddle', sliderHeight / 2 - itemTop + 'px' ) .replace( 'slidertop', -itemTop + 'px' ) .replace( 'sliderbottom', sliderHeight - itemTop + 'px' ); } TweenMax.set( item[0], transforms ); // Add draggable LayerSlider.addDraggable(); }, setPositions: function(item, top, left, returnOnly) { item.show(); var cssTop = top ? parseInt(top) : 0, cssLeft = left ? parseInt(left) : 0, style = item[0].style, marginLeft = parseInt( style.marginLeft ) || 0, marginTop = parseInt( style.marginTop ) || 0; // Position the element if( top && top.indexOf('%') !== -1 ) { if( cssTop === 0 ) { cssTop = 0 + marginTop; } else if( cssTop === 100 ) { cssTop = LS_previewArea.height() - item.outerHeight() + marginTop; } else { cssTop = LS_previewArea.height() / 100 * cssTop - item.outerHeight() / 2 + marginTop; } } else if( LS_activeLayerIndexSet.length === 1 ) { cssLeft += marginLeft; } if( left && left.indexOf('%') !== -1 ) { if( cssLeft === 0 ) { cssLeft = 0 + marginLeft; } else if( cssLeft === 100 ) { cssLeft = LS_previewArea.width() - item.outerWidth() + marginLeft; } else { cssLeft = LS_previewArea.width() / 100 * cssLeft - item.outerWidth() / 2 + marginLeft; } } else if( LS_activeLayerIndexSet.length === 1 ) { cssTop += marginTop; } if( returnOnly ) { return { top: cssTop, left: cssLeft }; } item.css({ top: cssTop, left: cssLeft }); }, previewItemAtIndex: function(index) { return LS_previewArea.children('.ls-l').eq(index); }, updatePreviewSelection: function() { // Hide lasso and stop execution // if there's no selected layers if( ! LS_activeLayerIndexSet.length || ! LS_activeSlideData.sublayers.length || jQuery('.ls-editing').length) { $lasso.hide(); return; } if( LS_activeLayerIndexSet.length === 1 ) { var layerData = LS_activeLayerDataSet[0]; if ( layerData && ( layerData.hasTransforms ||layerData.locked ) ) { $lasso.hide(); return; } } var a = { left: Infinity, top: Infinity }, b = { left: -Infinity, top: -Infinity }; jQuery.each(LS_activeLayerIndexSet, function(idx, layerIndex) { var $item = LS_previewItems[layerIndex]; if($item) { var p = $item.position(), q = { top: p.top + $item.outerHeight() * LS_previewZoom, left: p.left + $item.outerWidth() * LS_previewZoom }; if( p.left < a.left ){ a.left = p.left; } if( p.top < a.top ){ a.top = p.top; } if( q.left > b.left ){ b.left = q.left; } if( q.top > b.top ){ b.top = q.top; } } }); a.width = b.left - a.left; a.height = b.top - a.top; $lasso.css(a).show(); if( ! $lasso.hasClass('ls-resizable-disabled') ) { $lasso.removeClass('ui-resizable-disabled').css(a).show(); } // Mark the position of 0x0 px selection if( ! a.width || ! a.height ) { $lasso.addClass('ui-resizable-disabled'); } }, hidePreviewSelection: function() { jQuery('.ls-preview-wrapper').addClass('hide-selection'); }, showPreviewSelection: function() { jQuery('.ls-preview-wrapper').removeClass('hide-selection'); }, openMediaLibrary: function() { jQuery(document).on('click', '.ls-upload', function(e) { e.preventDefault(); uploadInput = this; // Get library type var type = jQuery(this).hasClass('ls-insert-media') ? 'video,audio' : 'image'; var multiple = jQuery(this).hasClass('ls-bulk-upload'); // Media Library params var frame = wp.media({ title : LS_l10n.SBMediaLibraryImage, multiple : multiple, library : { type : type }, button : { text : 'Insert' } }); // Runs on select frame.on('select',function() { // Get attachment(s) data var attachment = frame.state().get('selection').first().toJSON(), attachments = frame.state().get('selection').toJSON(), updateInfo = [], previewImg, newLayerData; // Slide image upload // ------------------------------------- if(jQuery(uploadInput).hasClass('ls-slide-image') ) { // Set image chooser preview previewImg = !typeof attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.sizes.full.url; LS_GUI.updateImagePicker( jQuery(uploadInput), previewImg); // Add action to UndoManager LS_UndoManager.add('slide.general', LS_l10n.SBUndoSlideImage, { itemIndex: LS_activeSlideIndex, undo: { background: LS_activeSlideData.properties.background, backgroundId: LS_activeSlideData.properties.backgroundId, backgroundThumb: LS_activeSlideData.properties.backgroundThumb }, redo: { background: attachment.url, backgroundId: attachment.id, backgroundThumb: previewImg } }); // Set current layer image LS_activeSlideData.properties.background = attachment.url; LS_activeSlideData.properties.backgroundId = attachment.id; LS_activeSlideData.properties.backgroundThumb = previewImg; // Set other images for(c = 1; c < attachments.length; c++) { // Get preview image url previewImg = !typeof attachments[c].sizes.thumbnail ? attachments[c].sizes.thumbnail.url : attachments[c].sizes.full.url; // Build new slide var newSlideData = jQuery.extend(true, {}, LS_DataSource.getDefaultSlideData()); newSlideData.background = attachments[c].url; newSlideData.backgroundId = attachments[c].id; newSlideData.backgroundThumb = previewImg; // Add a layer newLayerData = jQuery.extend(true, {}, LS_DataSource.getDefaultLayerData()); newLayerData.subtitle = LS_l10n.SBLayerTitle.replace('%d', '1'); // Add new layer window.lsSliderData.layers.push({ properties: newSlideData, sublayers: [newLayerData] }); // Add new slide tab var newIndex = window.lsSliderData.layers.length + 1, title = LS_l10n.SBSlideTitle.replace('%d', newIndex), tab = jQuery(''+title+'').insertBefore('#ls-add-layer'); } // Name new slide properly LayerSlider.reindexSlides(); // Slide thumbnail upload // ------------------------------------- } else if(jQuery(uploadInput).hasClass('ls-slide-thumbnail') ) { // Set image chooser preview previewImg = !typeof attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.sizes.full.url; LS_GUI.updateImagePicker( jQuery(uploadInput), previewImg); // Set current layer image LS_activeSlideData.properties.thumbnail = attachment.url; LS_activeSlideData.properties.thumbnailId = attachment.id; LS_activeSlideData.properties.thumbnailThumb = previewImg; // Layer image upload // ------------------------------------- } else if(jQuery(uploadInput).hasClass('ls-layer-image') ) { // Set image chooser preview previewImg = !typeof attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.sizes.full.url; LS_GUI.updateImagePicker( jQuery(uploadInput), previewImg); // Add action to UndoManager LS_UndoManager.add('layer.general', LS_l10n.SBUndoLayerImage, { itemIndex: LS_activeLayerIndexSet[0], undo: { image: LS_activeLayerDataSet[0].image, imageId: LS_activeLayerDataSet[0].imageId, imageThumb: LS_activeLayerDataSet[0].imageThumb }, redo: { image: attachment.url, imageId: attachment.id, imageThumb: previewImg } }); // Set current layer image LS_activeLayerDataSet[0].image = attachment.url; LS_activeLayerDataSet[0].imageId = attachment.id; LS_activeLayerDataSet[0].imageThumb = previewImg; // Set other images for(c = 1; c < attachments.length; c++) { // Get preview image url previewImg = !typeof attachments[c].sizes.thumbnail ? attachments[c].sizes.thumbnail.url : attachments[c].sizes.full.url; // Build new layer newLayerData = jQuery.extend(true, {}, LS_DataSource.getDefaultLayerData()); newLayerData.image = attachments[c].url; newLayerData.imageId = attachments[c].id; newLayerData.imageThumb = previewImg; newLayerData.styles.top = (10*c)+'px'; newLayerData.styles.left = (10*c)+'px'; // Add new layer LS_activeSlideData.sublayers.unshift(newLayerData); updateInfo.push({ itemIndex: 0, undo: { data: {} }, redo: { data: newLayerData } }); } // Rebuild layers list LS_DataSource.buildLayersList(); // Maintain UndoManager if(updateInfo.length) { LS_UndoManager.add('slide.layers', LS_l10n.SBUndoNewLayers, updateInfo); } // Media (video/audio) image upload // ------------------------------------- } else if( jQuery(uploadInput).hasClass('ls-media-image') ) { // Set image chooser preview previewImg = !typeof attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.sizes.full.url; LS_GUI.updateImagePicker( jQuery(uploadInput), previewImg); // Add action to UndoManager LS_UndoManager.add('layer.general', LS_l10n.SBUndoVideoPoster, { itemIndex: LS_activeLayerIndexSet[0], undo: { poster: LS_activeLayerDataSet[0].poster, posterId: LS_activeLayerDataSet[0].posterId, posterThumb: LS_activeLayerDataSet[0].posterThumb }, redo: { poster: attachment.url, posterId: attachment.id, posterThumb: previewImg } }); // Set current layer poster LS_activeLayerDataSet[0].poster = attachment.url; LS_activeLayerDataSet[0].posterId = attachment.id; LS_activeLayerDataSet[0].posterThumb = previewImg; // Global slider background // ------------------------------------- } else if( jQuery(uploadInput).hasClass('ls-global-background') ) { // Set image chooser preview previewImg = !typeof attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.sizes.full.url; LS_GUI.updateImagePicker( jQuery(uploadInput), previewImg); // Store changes and update the preview window.lsSliderData.properties.backgroundimage = attachment.url; window.lsSliderData.properties.backgroundimageId = attachment.id; // YourLogo // ------------------------------------- } else if( jQuery(uploadInput).hasClass('ls-yourlogo-upload') ) { // Set image chooser preview previewImg = !typeof attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.sizes.full.url; LS_GUI.updateImagePicker( jQuery(uploadInput), previewImg); // Store changes and update the preview window.lsSliderData.properties.yourlogo = attachment.url; window.lsSliderData.properties.yourlogoId = attachment.id; // Slider Preview // ------------------------------------- } else if( jQuery(uploadInput).hasClass('ls-slider-preview') ) { // Set image chooser preview previewImg = !typeof attachment.sizes.thumbnail ? attachment.sizes.thumbnail.url : attachment.sizes.full.url; LS_GUI.updateImagePicker( jQuery(uploadInput), previewImg); // Make sure that the meta object exits if( ! window.lsSliderData.meta ) { window.lsSliderData.meta = {}; } // Store changes and update the preview window.lsSliderData.meta.preview = attachment.url; window.lsSliderData.meta.previewId = attachment.id; // Multimedia HTML } else if( jQuery(uploadInput).hasClass('ls-insert-media')) { var hasVideo = false, hasAudio = false, videos = [], audios = [], url = '', mediaHTML = ''; // Iterate over selected items for(c = 0; c < attachments.length; c++) { url = '/' + attachments[c].url.split('/').slice(3).join('/'); if(attachments[c].type === 'video') { hasVideo = true; videos.push({ url: url, mime: attachment.mime }); } else if(attachments[c].type === 'audio') { hasAudio = true; audios.push({ url: url, mime: attachment.mime }); } } // Insert multimedia if(hasVideo) { mediaHTML += ''; } if(hasAudio) { if(hasVideo) { mediaHTML += '\r\n\r\n'; } mediaHTML += ''; } LS_activeLayerDataSet[0].html = mediaHTML; jQuery(uploadInput).prev().val(mediaHTML); // Image with input field } else { jQuery(uploadInput).val( attachment.url ); if(jQuery(uploadInput).is('input[name="image"]')) { jQuery(uploadInput).prev().attr('src', attachment.url); } } // Generate preview LayerSlider.generatePreview(); }); // Open ML frame.open(); }); }, handleDroppedImages: function(event) { var oe = event.originalEvent, files = oe.dataTransfer.files, p = LS_previewArea.offset(), x = (jQuery(window).scrollLeft() + oe.clientX - p.left) / LS_previewZoom, y = (jQuery(window).scrollTop() + oe.clientY - p.top) / LS_previewZoom, updateInfo = [], layerDataSet = [], layerIndexSet = [], counter = 1; // Iterate over the dropped files jQuery.each(files, function(index, file) { LayerSlider.uploadImageToMediaLibrary(file, function(data) { // Build new layer var layerData = jQuery.extend(true, {}, LS_DataSource.getDefaultLayerData()); layerData.image = data.url; layerData.imageId = data.id; layerData.imageThumb = data.sizes.thumbnail ? data.sizes.thumbnail.url : data.url; layerData.subtitle = file.name; layerData.styles.left = x+'px'; layerData.styles.top = y+'px'; layerIndexSet.push(0); layerDataSet.push(layerData); // Increase next layer offsets x += 20; y += 20; // Add new layers when every image // has been uploaded if(counter++ === files.length) { LayerSlider.addLayer( layerDataSet, layerIndexSet ); } }); }); }, uploadImageToMediaLibrary: function(file, callback) { if(file.type.indexOf('image') === 0) { // Build FormData object var formData = new FormData(); formData.append('action', 'upload-attachment'); formData.append('async-upload', file, file.name); formData.append('name', file.name); formData.append('_wpnonce', _wpPluploadSettings.defaults.multipart_params._wpnonce); jQuery.ajax({ url: ajaxurl.replace('admin-ajax', 'async-upload'), method: 'POST', data: formData, dataType: 'json', processData: false, contentType: false, error: function(jqXHR, textStatus, errorThrown) { alert( LS_l10n.SBUploadErrorMessage.replace('%s', errorThrown) ); }, success: function(resp) { if(!resp || !resp.success) { alert(LS_l10n.SBUploadError); return; } if(typeof callback != "undefined") { callback(resp.data); } } }); } }, addLayerSortables: function() { // Bind sortable function jQuery('.ls-sublayer-sortable').sortable({ handle : 'span.ls-sublayer-sortable-handle', containment : 'parent', tolerance : 'pointer', axis : 'y', start: function() { LayerSlider.dragIndex = jQuery('.ui-sortable-placeholder').index() - 1; }, change: function() { jQuery('.ui-sortable-helper').addClass('moving'); }, stop: function(event, ui) { // Get indexes var oldIndex = LayerSlider.dragIndex; var index = jQuery('.moving').removeClass('moving').index(); LS_UndoManager.add('layer.order', LS_l10n.SBUndoSortLayers, { itemIndex: null, undo: { from: index, to: oldIndex }, redo: { from: oldIndex, to: index } }); if( index > -1 ){ LS_Utils.moveArrayItem(LS_activeSlideData.sublayers, oldIndex, index); } // Update active layer index LS_activeLayerIndexSet = []; jQuery('.ls-sublayers li.active').each(function() { LS_activeLayerIndexSet.push( jQuery(this).index() ); }); // Reindex layers LayerSlider.reindexLayers(); LayerSlider.generatePreview(); } }); }, addSlideSortables: function() { jQuery('#ls-layer-tabs').sortable({ containment: 'parent', tolerance: 'pointer', items: 'a:not(.unsortable)', start: function() { LayerSlider.dragIndex = jQuery('.ui-sortable-placeholder').index() - 1; }, change: function() { jQuery('.ui-sortable-helper').addClass('moving'); }, stop: function(event, ui) { // Get indexes var oldIndex = LayerSlider.dragIndex, index = jQuery('.moving').removeClass('moving').index(); if( index > -1 ){ LS_Utils.moveArrayItem(window.lsSliderData.layers, oldIndex, index); } // Update active slide index LS_activeSlideIndex = jQuery('#ls-layer-tabs a.active').index(); // Add static layers LS_activeStaticLayersDataSet = LayerSlider.staticLayersForSlide( LS_activeSlideIndex ); // Reindex slides LayerSlider.reindexSlides(); LayerSlider.reindexStaticLayers(); LayerSlider.generateStaticPreview(); LS_DataSource.buildLayersList(); } }); }, addDraggable: function() { // Add dragables and update settings // while and after dragging LS_previewArea.children('.ls-l').draggable({ snap: true, snapTolerance: 10, cancel: '.disabled,.transformed', start: function(e, ui) { // Fix for deselect if( !ui.helper.hasClass('ui-selected') ){ ui.helper.addClass('ui-selected').trigger('selectablestop.ls'); } // Store selected layers & lasso originalPosition $lasso.data('originalPosition', $lasso.position()); jQuery('.ls-preview .ui-selected').each(function() { var pos = jQuery(this).position(); jQuery(this).data('originalPosition', { 'top': pos.top / LS_previewZoom, 'left': pos.left / LS_previewZoom, }); }); }, drag: function(event, ui) { LayerSlider.dragging(ui); }, stop: function(event, ui) { var updateInfo = []; LayerSlider.dragging(ui); jQuery('.ls-preview .ui-selected').each(function() { var $layer = jQuery(this), index = $layer.index(), position = $layer.position(), newTop = Math.round( position.top / LS_previewZoom ) +'px', newLeft = Math.round( position.left / LS_previewZoom ) +'px', origPosition = $layer.data('originalPosition'); // Maintain changes in data source LS_activeSlideData.sublayers[index].styles.top = newTop; LS_activeSlideData.sublayers[index].styles.left = newLeft; // Gather changes for undoing updateInfo.push({ itemIndex: index, undo: { left: origPosition.left+'px', top: origPosition.top+'px' }, redo: { left: newLeft, top: newTop } }); }); // Add changes to undoManager LS_UndoManager.add('layer.style', LS_l10n.SBUndoLayerPosition, updateInfo.reverse()); } }); }, dragging: function(ui) { // Fix positions when zoomed ui.position.top = Math.round(ui.position.top / LS_previewZoom ); ui.position.left = Math.round(ui.position.left / LS_previewZoom ); var index = ui.helper.index(), top = Math.round( ui.position.top ), left = Math.round( ui.position.left ); // Update input field values if it's visible if(LS_activeLayerIndexSet.length === 1) { // Update input fields jQuery('.ls-sublayer-style input[name="top"]').val( ui.helper.position().top / LS_previewZoom + 'px'); jQuery('.ls-sublayer-style input[name="left"]').val( ui.helper.position().left / LS_previewZoom + 'px'); } }, resizing: function(e, ui) { var rh = ui.size.height / ui.originalSize.height, rw = ui.size.width / ui.originalSize.width, uiRatio = ui.originalSize.width / ui.originalSize.height, tagNames = [], layer, $layer, layerIndex, layerData, width, height, op, os, r; if( !$lasso.data( 'dragDirection') ){ $lasso.data( 'dragDirection', rh === 1 ? 'horizontal' : 'vertical' ); } // Update layer data jQuery('.ls-preview .ui-selected').each(function() { layer = this; $layer = jQuery(this); layerIndex = $layer.index(); layerData = LS_activeSlideData.sublayers[layerIndex]; tagNames.push( layer.tagName.toLowerCase() ); op = $layer.data('originalPosition'); os = $layer.data('originalSize'); layerData.styles.top = layer.style.top = Math.round( (op.top - Math.round( ui.originalPosition.top / LS_previewZoom ) ) * rh + Math.round( ui.position.top / LS_previewZoom ) ) + 'px'; layerData.styles.left = layer.style.left = Math.round( (op.left - Math.round( ui.originalPosition.left / LS_previewZoom ) ) * rw + Math.round( ui.position.left / LS_previewZoom ) ) + 'px'; width = Math.round(os.width * rw) + 'px'; height = Math.round(os.height * rh) + 'px'; if( layerData.styles.width || $layer.is('img,div') ) { layerData.styles.width = width; } if( layerData.styles.height || $layer.is('img,div') ) { layerData.styles.height = height; } $layer.outerWidth(width); $layer.outerHeight(height); // Font-size only if( ! $layer.is( 'img, iframe, video, audio' ) ) { r = ui.size.width / ui.originalSize.width; layerData.styles['font-size'] = layer.style.fontSize = Math.round( r * os.fontSize ) +'px'; if( os.lineHeight ) { layerData.styles['line-height'] = layer.style.lineHeight = Math.round( r * os.lineHeight ) +'px'; } } if(LS_activeLayerIndexSet.length === 1) { if( layerData.styles.width || $layer.is('img,div') ) { jQuery('.ls-sublayer-style input[name="width"]').val( layer.style.width); } if( layerData.styles.height || $layer.is('img,div') ) { jQuery('.ls-sublayer-style input[name="height"]').val( layer.style.height); } jQuery('.ls-sublayer-style input[name="top"]').val( layer.style.top); jQuery('.ls-sublayer-style input[name="left"]').val( layer.style.left); jQuery('.ls-sublayer-style input[name="font-size"]').val(layerData.styles['font-size']); if( os.lineHeight ) { jQuery('.ls-sublayer-style input[name="line-height"]').val( layerData.styles['line-height']+'px' ); } } }); if( tagNames.indexOf('img') === -1 && tagNames.indexOf('div') === -1 ) { switch( $lasso.data( 'dragDirection') ){ case 'horizontal': ui.size.height = ui.size.width / uiRatio; break; case 'vertical': ui.size.width = ui.size.height * uiRatio; break; } } // Update lasso size info $lasso.attr({ 'data-info-0': 'w: ' + Math.round(ui.size.width) + 'px', 'data-info-1': 'h: ' + Math.round(ui.size.height) + 'px' }); }, listPreviewItems: function(e) { // Bail out if preview is active or when using Revisions if( LayerSlider.isSlidePreviewActive || LayerSlider.isLayerPreviewActive || document.location.href.indexOf('ls-revisions') !== -1 ) { return; } // Vars to hold overlapping elements // and mouse position var items = [], mt = e.pageY; ml = e.pageX; // Loop through layers list LS_previewArea.children('.ls-l').each(function(layerIndex) { // Get layer item and data var $layer = jQuery(this), layerData = LS_activeSlideData.sublayers[ $layer.index() ], // Get layer positions and dimensions t = LS_previewArea.offset().top + $layer.position().top, l = LS_previewArea.offset().left + $layer.position().left, w = $layer.outerWidth() * LS_previewZoom, h = $layer.outerHeight() * LS_previewZoom; if( (mt > t && mt < t+h) && (ml > l && ml < l+w) ) { items.push({ index: layerIndex, data: layerData }); } }); // Create list holder if(items.length > 1) { // Remove previous list (if any) jQuery('.ls-preview-item-list').remove(); // Create list var $list = jQuery('
    ').prependTo('body'); $list.hide().css({ top: mt, left: ml }).fadeIn(100); // Close event jQuery('body').one('click', function() { jQuery('.ls-preview-item-list').animate({ opacity: 0 }, 200, function() { jQuery(this).remove(); }); }); // Loop through intersecting elements (if any) jQuery.each(items, function(idx, data) { var layerIndex = data.index, layerData = data.data, $li = jQuery('
  • '+layerData.subtitle+'
  • ').appendTo($list); $li.data('layerIndex', layerIndex); LayerSlider.setLayerMedia( layerData.media, jQuery('div', $li), layerData ); }); } }, highlightPreviewItem: function(el) { // Get layer related data var layerIndex = jQuery(el).data('layerIndex'); var $previewItem = LS_previewArea.children('.ls-l').eq(layerIndex); // Highlight item $previewItem.addClass('highlighted').siblings().addClass('lowlighted'); }, selectPreviewItem: function(el) { // Select layer var layerIndex = jQuery(el).data('layerIndex'); jQuery('.ls-sublayers li').eq(layerIndex).click(); // Remove layer highlights (if any) LS_previewArea.children().removeClass('highlighted lowlighted'); }, editLayerToggle: function() { if(LS_activeLayerIndexSet.length === 1) { var $editing = jQuery('.ls-editing'), $layer = LS_previewItems[ LS_activeLayerIndexSet[0] ]; if(!$editing.length) { this.editLayerStart($layer); } else { this.editLayerEnd($editing); } } }, editLayerStart: function( $layer ) { // Bail out earily if it's an image layer if( $layer.is('img') ) { return false; } LayerSlider.selectLayer( [$layer.index() ] ); // Get layer data var layerData = LS_activeLayerDataSet[0]; // Bail out early if it's a locked layer if( $layer.hasClass('disabled') || layerData.locked) { return false; } // Enable editing $layer.addClass('disabled ls-editing') .prop('contenteditable', true) .focus(); // Hide selectable/resizable $lasso.addClass('ui-resizable-disabled').hide(); // Save current value for undoManager jQuery('.ls-html-code textarea').data('prevVal',layerData.html); // Select all text document.execCommand('selectAll'); // End editing when clicking away jQuery(document).on('click.ls-editing', function(event) { if(!jQuery(event.target).hasClass('ls-editing')) { LayerSlider.editLayerEnd( jQuery('.ls-editing') ); } }); }, editLayer: function(e) { if((e.metaKey || e.ctrlKey || e.altKey) && e.which === 13) { e.preventDefault(); document.execCommand('insertHTML', false, '\r\n '); } }, editLayerUpdate: function(layer) { var content = layer.textContent, $textarea = jQuery('.ls-html-code textarea'), styles = LS_activeLayerDataSet[0].styles; $textarea.val(content); LS_activeLayerDataSet[0].html = content; LayerSlider.setPositions( jQuery(layer), styles.top, styles.left); }, editLayerPaste: function(event) { event.preventDefault(); document.execCommand('insertHTML', false, event.originalEvent.clipboardData.getData('text/plain') ); }, editLayerEnd: function($layer) { jQuery(document).off('click.ls-editing'); $layer.prop('contenteditable', false).removeClass('disabled ls-editing'); jQuery('.ls-html-code textarea').trigger('change'); LayerSlider.updatePreviewSelection(); }, reindexLayers: function(el) { var layerCount = LS_activeSlideData.sublayers.length; layerCount = layerCount ? layerCount : 0; // Reindex default layers' title jQuery('#ls-layers .ls-sublayers > li').each(function(index) { var layerTitle = jQuery(this).find('.ls-sublayer-title').val(), pattern = LS_l10n.SBLayerTitle.substring(0, LS_l10n.SBLayerTitle.length-2); if( layerTitle.indexOf(pattern) != -1 && layerTitle.indexOf('copy') == -1) { jQuery(this).find('.ls-sublayer-title').val( LS_l10n.SBLayerTitle.replace('%d', (layerCount-index) ) ); } }); }, reindexSlides: function() { jQuery('#ls-layer-tabs a:not(.unsortable)').each(function(index) { var title = jQuery('span:first-child', this).text(), slideData = window.lsSliderData.layers[ index ], src = slideData.properties.backgroundThumb || pluginPath+'admin/img/blank.gif'; if( title.indexOf('copy') === -1 && title.indexOf('Slide #') !== -1 ) { title = 'Slide #' + (index + 1); } jQuery(this) .attr({ 'data-help': "
    ", 'data-help-class': 'ls-slide-preview-tooltip popover-light', 'data-help-delay': 1, 'data-help-transition': false }).html(''+title+''); }); }, rebuildSlides: function() { // Remove tabs jQuery('#ls-layer-tabs a:not(.unsortable)').remove(); jQuery.each(window.lsSliderData.layers, function(slideKey, slideData) { var title = slideData.properties.title || LS_l10n.SBSlideTitle.replace('%d', slideKey+1), src = slideData.properties.backgroundThumb || pluginPath+'admin/img/blank.gif'; if( title.indexOf('copy') === -1 && title.indexOf('Slide #') !== -1 ) { title = 'Slide #' + (slideKey + 1); } $tab = jQuery('
    ').insertBefore('#ls-layer-tabs .unsortable:first'); $tab.attr({ 'href': '#', 'data-help': "
    ", 'data-help-class': 'ls-slide-preview-tooltip popover-light', 'data-help-delay': 1, 'data-help-transition': false }).html(''+title+''); }); jQuery('#ls-layer-tabs a').eq( LS_activeSlideIndex ).addClass('active'); }, checkMediaAutoPlay: function( $textarea, prop, val ) { clearTimeout(LayerSlider.mediaCheckTimeout); LayerSlider.mediaCheckTimeout = setTimeout(function() { if( val.indexOf('autoplay') !== -1 ) { var $media = jQuery(val).filter('iframe'), autoplayDetected = false; if( $media.is('iframe') ) { var URL = $media.attr('src').split('?'), targetIndex = -1; if( URL[1] ) { params = URL[1].split('&'); jQuery.each(params, function(index, item) { if( item.indexOf('autoplay') !== -1 ) { autoplayDetected = true; targetIndex = index; } }); if( targetIndex > -1 ) { params.splice(targetIndex, 1); } } if( typeof params !== 'undefined' ) { $media.attr('src', URL[0]+'?'+params.join('&') ); } } else if( $media.is('video') || $media.is('audio') ) { autoplayDetected = true; $media.removeAttr('autoplay'); } if( autoplayDetected ) { $textarea.val( $media[0].outerHTML ); $autoplay = jQuery('select[name="autoplay"]'); jQuery('option', $autoplay) .prop('selected', false) .eq(1).prop('selected', true); TweenLite.to($autoplay[0], 0.2, { css: { scale: 1.3 }, onComplete: function() { TweenLite.to($autoplay[0], 0.2, { css: { scale: 1 } }); } }); } } }, 100, $textarea, prop, val); }, startSlidePreview: function( sliderOptions ) { // Stop **layer** preview if it's currently running // to prevent simultaneous instances this.stopLayerPreview(true); // Stop slide preview if it's currently running if(this.isSlidePreviewActive) { LayerSlider.stopSlidePreview(); return true; } this.isSlidePreviewActive = true; sliderOptions = sliderOptions || {}; // Get slider settings and preview container var sliderProps = window.lsSliderData.properties, // Slider settings width = sliderProps.width, height = sliderProps.height, posts = window.lsPostsJSON, callbacks = window.lsSliderData.callbacks, plugins = []; // Switch between preview and editor var $slider = jQuery('#ls-layers .ls-real-time-preview').show(); $slider = jQuery('
    ').appendTo( $slider ); jQuery('#ls-layers .ls-preview').hide(); jQuery('#ls-layers .ls-preview-button').html('Stop').addClass('playing'); LayerSlider.hidePreviewSelection(); // Empty the preview area to avoid ID collisions LS_previewArea.empty(); // Iterate over the slides jQuery.each(window.lsSliderData.layers, function(slideIndex, slideData) { // Slide data var slideProps = slideData.properties, layers = slideData.sublayers.reverse(); // Get post content if any var postOffset = slideProps.post_offset; if(postOffset == -1) { postOffset = slideIndex; } var post = posts[postOffset]; // Slide attributes var properties = '', sKey, sVal; for( sKey in slideProps) { sVal = slideProps[ sKey ]; if( sVal !== '' && sVal !== 'null' ) { // Slide BG inheritance if( sKey === 'bgsize' && sVal === 'inherit' ) { sVal = sliderProps.slideBGSize; } else if( sKey === 'bgposition' && sVal === 'inherit' ) { sVal = sliderProps.slideBGPosition; } if( sKey === 'transitionorigami' && sVal ) { if(plugins.indexOf('origami') === -1) { plugins.push('origami'); } } properties += sKey+':'+sVal+';'; } } // Build the Slide var layer = jQuery('
    ') .attr('data-ls', properties) .appendTo( $slider ); // Get background var background = slideProps.background; if(background === '[image-url]') { background = post['image-url']; } // Add background if(background) { jQuery('').appendTo(layer); } // Get selected transitions var tr2d = slideProps['2d_transitions'], tr3d = slideProps['3d_transitions'], tr2dcustom = slideProps.custom_2d_transitions, tr3dcustom = slideProps.custom_3d_transitions; // Apply transitions if(tr2d) layer.attr('data-ls', layer.attr('data-ls') + ' transition2d: '+tr2d+'; '); if(tr3d) layer.attr('data-ls', layer.attr('data-ls') + ' transition3d: '+tr3d+'; '); if(tr2dcustom) layer.attr('data-ls', layer.attr('data-ls') + ' customtransition2d: '+tr2dcustom+'; '); if(tr3dcustom) layer.attr('data-ls', layer.attr('data-ls') + ' customtransition3d: '+tr3dcustom+'; '); // Iterate over layers jQuery.each(layers, function(layerKey, layerData) { LayerSlider.appendLivePreviewItem(layerKey, layerData, layer, post); }); // Revert back to original layer order, as the reversed // layers list is only a visual thing on the admin UI. slideData.sublayers.reverse(); }); // Get slider settings var autoPlayVideos = sliderProps.autoplayvideos; autoPlayVideos = autoPlayVideos ? true : false; // Callbacks if( callbacks ) { for( var key in callbacks ) { var callback = callbacks[ key ], startIndex = callback.indexOf('{') + 1, endIndex = callback.length - 1; body = callback.substring(startIndex, endIndex); $slider.on(key, new Function('event', 'slider', body)); } } // Handle plugins if( sliderOptions && sliderOptions.plugins ) { sliderOptions.plugins = jQuery.merge(sliderOptions.plugins, plugins); } // Init layerslider $slider.layerSlider( jQuery.extend( true, { type: 'responsive', width: width, height: height, skin: 'v6', skinsPath: pluginPath + 'layerslider/skins/', firstSlide: LS_activeSlideIndex + 1, autoStart: true, pauseOnHover: false, startInViewport: false, autoPlayVideos: autoPlayVideos, slideBGSize: sliderProps.slideBGSize, slideBGPosition: sliderProps.slideBGPosition, globalBGColor: sliderProps.backgroundcolor, globalBGImage: sliderProps.backgroundimage, globalBGAttachment: sliderProps.globalBGAttachment, globalBGRepeat: sliderProps.globalBGRepeat, globalBGPosition: sliderProps.globalBGPosition, globalBGSize: sliderProps.globalBGSize, parallaxScrollReverse: sliderProps.parallaxScrollReverse, playByScroll: sliderProps.playByScroll ? true : false, playByScrollStart: sliderProps.playByScrollStart ? true : false, playByScrollSpeed: sliderProps.playByScrollSpeed || 1, navButtons: false, navStartStop: false, allowRestartOnResize: sliderProps.allowRestartOnResize ? true : false, plugins: plugins }, sliderOptions )).on('slideTimelineDidComplete', function( event, slider ) { // if( jQuery('.ls-timeline-switch li').eq(0).hasClass('active') ) { // slider.api('replay'); // return false; // } }).on( 'slideTimelineDidCreate', function(){ jQuery( '.ls-slidebar-slider' ).attr({ 'data-help': LS_l10n.SBDragMe, 'data-km-ui-popover-once': 'true', 'data-km-ui-popover-theme': 'red', 'data-km-ui-popover-autoclose': 3, 'data-km-ui-popover-distance': 20 }).trigger( 'mouseenter' ); }); }, stopSlidePreview: function() { if( this.isSlidePreviewActive ) { this.isSlidePreviewActive = false; // Show the editor jQuery('#ls-layers .ls-preview').show(); // Stop LayerSlider and empty the preview contents var layersliders = jQuery('#ls-layers .ls-real-time-preview'); layersliders.find('.ls-container').layerSlider( 'destroy', true ); layersliders.hide(); // Rewrote the Preview button text var btnText = document.location.href.indexOf('ls-revisions') !== -1 ? LS_l10n.SBPreviewSlide : LS_l10n.slideNoun; jQuery('#ls-layers .ls-preview-button').text( btnText ).removeClass('playing'); LayerSlider.generatePreview(); LayerSlider.showPreviewSelection(); LayerSlider.updatePreviewSelection(); // Remove timeline jQuery('.ls-timeline-switch li:first-child').click(); // SET: layer editor size kmUI.smartResize.set(); } }, startLayerPreview: function(button, forceStop) { // Stop **slide** preview if it's currently running // to prevent simultaneous instances this.stopSlidePreview(); // Stop or restart current preview session (if any) if(this.isLayerPreviewActive){ LayerSlider.stopLayerPreview(forceStop); if( !!forceStop ){ return; } } // Change preview state this.isLayerPreviewActive = true; jQuery(button).addClass('playing').text( LS_l10n.stop ); // Hide other layers LayerSlider.hidePreviewSelection(); LS_previewArea.children().addClass('ls-transparent'); // Create container element var $wrapper = jQuery('
    ').addClass('ls-layer-preview-wrapper').appendTo('.ls-preview-wrapper'); // Slide properties var slideProps = LS_activeSlideData.properties, postOffset = slideProps.post_offset; if(postOffset == -1) { postOffset = LS_activeSlideIndex; } var post = window.lsPostsJSON[postOffset]; // Slide attributes var properties = '', sKey, sVal; for( sKey in slideProps) { sVal = slideProps[ sKey ]; // Don't allow empty values & force auto slide duration if( sVal !== '' && sVal !== 'null' && sKey !== 'slidedelay' ) { properties += sKey+':'+sVal+';'; } } // Add slide $s1 = jQuery('
    ').attr({ 'class': 'ls-slide', 'data-ls': properties }).appendTo($wrapper); // Get layer data var item = LS_activeLayerDataSet[0], layerData = jQuery.extend(true, {}, item); layerData.transition.delayin = 100; LayerSlider.appendLivePreviewItem(0, layerData, $s1, post); item.skip = true; LS_previewItems[ LS_activeLayerIndexSet[0] ].addClass('ls-invisible'); // Initialize slider $wrapper.layerSlider({ type: 'responsive', width: window.lsSliderData.properties.width, height: window.lsSliderData.properties.height, skin: 'v6', skinsPath: pluginPath + 'layerslider/skins/', pauseOnHover: false, autoPlayVideos: false, startInViewport: false, keybNav: false, navButtons: false, navStartStop: false, navPrevNext: false }).on('slideTimelineDidComplete', function( event, slider ) { if( jQuery('.ls-timeline-switch li').eq(0).hasClass('active') ) { slider.api('replay'); return false; } }); }, updateLayerPreview: function() { var $slider = jQuery('.ls-real-time-preview .ls-container'), $layer = jQuery('.ls-layer', $slider); $slider.layerSlider( 'updateLayerData', $layer, 'scalein: 2; rotatein: 360; scaleout: 2; rotateout: 360; rotate: -45;' ); }, stopLayerPreview: function(forceStop){ if(this.isLayerPreviewActive) { // Change preview state this.isLayerPreviewActive = false; LayerSlider.showPreviewSelection(); jQuery('.ls-layer-preview-button').removeClass('playing').text( LS_l10n.layer ); jQuery.each(LS_activeLayerDataSet, function(index, item) { item.skip = false; }); // Restore editing area // LS_activeLayerDataSet.skip = false; if( forceStop ){ jQuery.each(LS_activeLayerIndexSet, function(index, item) { LayerSlider.generatePreviewItem( item ); }); } jQuery('.ls-layer-preview-wrapper').layerSlider( 'destroy', true ); LS_previewArea.children().removeClass('ls-transparent'); } }, appendLivePreviewItem: function(layerKey, layerData, $slide, post) { // Skip sublayer? if( !!layerData.skip || layerData['hide_on_'+LS_activeScreenType] ) { return true; } // Gather sublayer data var type = layerData.type; switch( layerData.media ) { case 'img': type = 'img'; break; case 'html': case 'media': type = 'div'; break; case 'post': type = 'post'; break; } var image = layerData.image, html = layerData.html, style = layerData.style, top = layerData.styles.top, left = layerData.styles.left, skip = layerData.hasOwnProperty('skip'), url = layerData.url, id = layerData.id, classes = layerData['class'], innerAttrs = layerData.innerAttributes || {}, outerAttrs = layerData.outerAttributes || {}; // Sublayer properties var sublayerprops = '', trKey, trVal; for( trKey in layerData.transition) { trVal = layerData.transition[ trKey ]; if( trKey.indexOf('perspective') !== -1 && trVal.toString() === '500') { continue; } if( trKey === 'backgroundvideo' && ! trVal ) { continue; } if( trVal !== '' && trVal !== null && trVal !== 'null' && trVal !== 'inherit' ) { sublayerprops += trKey+':'+trVal+';'; } } // Styles var styles = {}, cssProp, cssVal; for( cssProp in layerData.styles ) { cssVal = layerData.styles[cssProp]; if( ! cssVal && cssVal !== 0 ) { continue; } cssVal = cssVal.toString(); if(cssVal.slice(-1) == ';' ) { cssVal = cssVal.substring(0, cssVal.length - 1); } if (cssVal) { // !! fix for unused styles don't override Custom CSS styles[cssProp] = isNumber(cssVal) ? cssVal + 'px' : cssVal; if( ['z-index', 'font-weight', 'opacity'].indexOf( cssProp ) !== -1 ) { styles[cssProp] = cssVal; } } } // Build the sublayer var sublayer; if(type == 'img') { if(!image) { return true; } if(image == '[image-url]') { image = post['image-url']; } sublayer = jQuery('').appendTo($slide); } else if(type == 'post') { // Parse post placeholders var textlength = layerData.post_text_length; for(var key in post) { if(html.indexOf('['+key+']') !== -1) { if( (key == 'title' || key == 'content' || key == 'excerpt') && textlength > 0) { post[key] = post[key].substr(0, textlength); } html = html.replace('['+key+']', post[key]); } } // Test html html = jQuery.trim(html); var first = html.substr(0, 1); var last = html.substr(html.length-1, 1); if(first == '<' && last == '>') { html = html.replace(/(\r\n|\n|\r)/gm,""); sublayer = jQuery(html).appendTo($slide).addClass('ls-l'); } else { sublayer = jQuery('
    ').appendTo($slide).html(html).addClass('ls-l'); } } else { sublayer = jQuery('<'+type+'>').appendTo($slide).html(html).addClass('ls-l'); // Rewrite Youtube/Vimeo iframe src to data-src var $video = sublayer.find('iframe[src*="youtube-nocookie.com"], iframe[src*="youtube.com"], iframe[src*="youtu.be"], iframe[src*="player.vimeo"]'); if( $video.length ) { $video.attr('data-src', $video.attr('src') ).removeAttr('src'); } } // Apply styles sublayer .attr({ 'id': id, 'style': style }) .css(styles) .css('white-space', !layerData.styles.wordwrap ? 'nowrap' : 'normal') .addClass(classes); // Apply attributes for( var iaKey in innerAttrs ) { if( iaKey.toLowerCase() === 'class' ) { sublayer.addClass( innerAttrs[iaKey] ); continue; } sublayer[0].setAttribute(iaKey, innerAttrs[iaKey]); } // Position the element if(top.indexOf('%') != -1) { sublayer.css({ top : top }); } else { sublayer.css({ top : parseInt(top) }); } if(left.indexOf('%') != -1) { sublayer.css({ left : left }); } else { sublayer.css({ left : parseInt(left) }); } if( url ) { var anchor = jQuery(''); anchor.attr( outerAttrs ); sublayer.wrap( anchor ); } else { // Apply attributes for( var oaKey in outerAttrs ) { if( oaKey.toLowerCase() === 'class' ) { sublayer.addClass( outerAttrs[oaKey] ); continue; } sublayer[0].setAttribute(oaKey, outerAttrs[oaKey]); } } sublayer.attr('data-ls', sublayerprops); }, openTransitionGallery: function() { kmUI.modal.open( '#tmpl-ls-transition-modal', { width: 900, height: 1500 } ); // Append transitions LayerSlider.appendTransition(0, '', '2d_transitions', layerSliderTransitions.t2d); LayerSlider.appendTransition(1, '', '3d_transitions', layerSliderTransitions.t3d); // Append custom transitions if(typeof layerSliderCustomTransitions != "undefined") { if(layerSliderCustomTransitions.t2d.length) { LayerSlider.appendTransition(2, '', 'custom_2d_transitions', layerSliderCustomTransitions.t2d); } if(layerSliderCustomTransitions.t3d.length) { LayerSlider.appendTransition(3, '', 'custom_3d_transitions', layerSliderCustomTransitions.t3d); } } jQuery('#ls-transition-window .ls-select-special-transition').each(function() { var $this = jQuery(this), name = $this.data('name'); $this.addClass( LS_activeSlideData.properties[ name ] ? 'on' : 'off' ); }); // Select proper tab jQuery('#ls-transition-window .filters li.active').click(); }, appendTransition: function(index, title, tbodyclass, transitions) { // Append new section var section = jQuery( '#ls-transitions-list section:eq('+index+') div' ).empty(); // Get checked transitions var checked = LS_activeSlideData.properties[tbodyclass]; checked = checked ? checked.split(',') : []; if( transitions && transitions.length ) { for( c = 0; c < transitions.length; c++ ){ var addClass = ''; if(checked.indexOf(''+(c+1)+'') != -1 || checked == 'all') { addClass = 'added'; } section.append( jQuery( '
    ' + ( c + 1 ) + '' + transitions[c].name + '
    ' ) ); } } }, selectAllTransition: function(index, check) { // Get checkbox and transition type var checkbox = jQuery('#ls-transition-window header i:last'), type = jQuery('#ls-transitions-list section').eq(index).data('tr-type'); if(check) { jQuery( '#ls-transitions-list section:eq('+index+')' ).find('.tr-item').addClass('added'); checkbox.attr('class', 'on').text( LS_l10n.deselectAll ); LS_activeSlideData.properties[ type ] = 'all'; } else { jQuery( '#ls-transitions-list section:eq('+index+')' ).find('.tr-item').removeClass('added'); checkbox.attr('class', 'off').text( LS_l10n.selectAll); LS_activeSlideData.properties[ type ] = ''; } }, toggleTransition: function(el) { var $item = jQuery(el), $section = $item.closest('section'), $trs = $section.find('.tr-item'), type = $section.data('tr-type'); // Toggle addded class $item.toggleClass('added'); // All selected if($trs.filter('.added').length == $trs.length) { LayerSlider.selectAllTransition( $section.index(), true ); return; // Uncheck select all } else { // Check the checkbox jQuery('#ls-transition-window header i:last').attr('class', 'off').text( LS_l10n.selectAll ); } // Gather checked selected transitions var checked = []; $trs.filter('.added').each(function() { checked.push( jQuery(this).data('key') ); }); // Set data LS_activeSlideData.properties[ type ] = checked.join(','); }, save: function( saveProperties ) { saveProperties = saveProperties || {}; // Bring all layers back in, // as it can mess with saving. this.stopLayerPreview(true); // Get the slider data var sliderData = jQuery.extend(true, {}, window.lsSliderData); // Temporary disable submit button jQuery('.ls-publish').addClass('saving').find('button').text( LS_l10n.saving ).attr('disabled', true); // Serialize slider settings to prevent jQuery form converting form data sliderData.properties = JSON.stringify(sliderData.properties); // 1. Iterate over the slides and encode them // to workaround PHP's array size limitation. // // 2. Iterate over the styles object of layers // to remove empty values added mistakenly. // // 3. Also check whether they use dynamic content. jQuery.each(sliderData.layers, function(slideIndex, slideData) { slideData.properties.post_content = false; jQuery.each(slideData.sublayers, function(layerIndex, layerData) { if( layerData.styles ) { jQuery.each(layerData.styles, function(cssIndex, cssVal) { if( cssVal === '' ) { delete layerData.styles[cssIndex]; } }); } layerData.transition = JSON.stringify(layerData.transition); layerData.styles = JSON.stringify(layerData.styles); if(slideData.properties.post_content === false && layerData.media == 'post') { slideData.properties.post_content = true; } }); // Reverse the list of layers, as it is only // a visual thing on the admin UI. slideData.sublayers.reverse(); sliderData.layers[slideIndex] = JSON.stringify(slideData); }); // Save slider jQuery.ajax({ type: 'POST', url: ajaxurl, dataType: 'text', data: { _wpnonce: jQuery('#ls-slider-form input[name="_wpnonce"]').val(), _wp_http_referer: jQuery('#ls-slider-form input[name="_wp_http_referer"]').val(), action: 'ls_save_slider', id: LS_sliderID, sliderData: sliderData }, error: function(jqXHR, textStatus, errorThrown) { jQuery('.ls-publish').removeClass('saving').addClass('failed').find('button').text( LS_l10n.error ); setTimeout(function() { alert( LS_l10n.SBSaveError.replace('%s', errorThrown ) ); }, 100); }, success: function(jqXHR, textStatus) { // Consider the editor as "clean", do not show // unsaved changes warning when leaving the page. LS_editorIsDirty = false; // Button feedback jQuery('.ls-publish').removeClass('saving').addClass('saved').find('button').text( LS_l10n.saved ); // Display on screen notification when save // was initiated by a keyboard shortcut. if( saveProperties.usedShortcut && typeof lsScreenOptions !== 'undefined' && lsScreenOptions.useNotifyOSD === 'true' ) { jQuery('.ls-notify-osd').addClass('visible'); } }, complete: function(data) { setTimeout(function() { jQuery('.ls-publish').removeClass('saved failed').find('button').text( LS_l10n.save ).attr('disabled', false); jQuery('.ls-notify-osd').removeClass('visible'); }, 2000); } }); }, }; var LS_PostOptions = { init: function() { jQuery('#ls-layers').on('click', '.ls-configure-posts', function(e) { e.preventDefault(); LS_PostOptions.open(this); }); jQuery('.ls-configure-posts-modal .header a').click(function(e) { e.preventDefault(); LS_PostOptions.close(); }); jQuery('#ls-post-options select:not(.ls-post-taxonomy, .post_offset)').change(function() { window.lsSliderData.properties[ jQuery(this).attr('name') ] = jQuery(this).val(); LS_PostOptions.change(this); }); jQuery('#ls-post-options select.offset').change(function() { LS_activeSlideData.properties.post_offset = jQuery(this).val(); LayerSlider.willGeneratePreview(); }); jQuery('#ls-post-options select.ls-post-taxonomy').change(function() { window.lsSliderData.properties.post_taxonomy = jQuery(this).val(); LS_PostOptions.getTaxonoies(this); }); jQuery('#ls-layers').on('click', '.ls-post-placeholders li', function() { LS_PostOptions.insertPlaceholder(this); }); }, open: function(el) { // Create overlay jQuery('body').prepend(jQuery('
    ', { 'class' : 'ls-overlay'})); // Get slide's post offset var offset = parseInt(LS_activeSlideData.properties.post_offset) + 1; // Show modal window var modal = jQuery('#ls-post-options').show(); modal.find('select.offset option').prop('selected', false).eq(offset).prop('selected', true); // Close event jQuery(document).one('click', '.ls-overlay', function() { LS_PostOptions.close(); }); // First open? if(modal.find('.ls-post-previews ul').children().length === 0) { LS_PostOptions.change( modal.find('select')[0] ); } }, getTaxonoies: function(select) { var target = jQuery(select).next().empty(); if(jQuery(select).val() == 0) { LS_PostOptions.change(select); } else { jQuery.post(ajaxurl, jQuery.param({ action : 'ls_get_taxonomies', taxonomy : jQuery(select).val() }), function(data) { data = jQuery.parseJSON(data); for(c = 0; c < data.length; c++) { target.append( jQuery('