/*! WPMU Dev code library - v3.0.1
* http://premium.wpmudev.org/
* Copyright (c) 2016; * Licensed GPLv2+ */
/*!
* WPMU Dev UI library
* (Philipp Stracker for WPMU Dev)
*
* This library provides a Javascript API via the global wpmUi object.
*
* @version 1.0.0
* @author Philipp Stracker for WPMU Dev
* @link http://appendto.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/
* @requires jQuery
*/
/*global jQuery:false */
/*global window:false */
/*global document:false */
/*global XMLHttpRequest:false */
(function( wpmUi ) {
/**
* The document element.
*
* @type jQuery object
* @since 1.0.0
* @private
*/
var _doc = null;
/**
* The html element.
*
* @type jQuery object
* @since 1.0.0
* @private
*/
var _html = null;
/**
* The body element.
*
* @type jQuery object
* @since 1.0.0
* @private
*/
var _body = null;
/**
* Modal overlay, created by this object.
*
* @type jQuery object
* @since 1.0.0
* @private
*/
var _modal_overlay = null;
// ==========
// == Public UI functions ==================================================
// ==========
/**
* Creates a new popup window.
*
* @since 1.0.0
* @param string template Optional. The HTML template of the popup.
* Note: The template should contain an element ".popup"
* @param string css CSS styles to attach to the popup.
* @return WpmUiWindow A new popup window.
*/
wpmUi.popup = function popup( template, css ) {
_init();
return new wpmUi.WpmUiWindow( template, css );
};
/**
* Creates a new progress bar element.
*
* @since 2.0.2
* @return WpmUiProgress A new progress bar element.
*/
wpmUi.progressbar = function progressbar() {
_init();
return new wpmUi.WpmUiProgress();
};
/**
* Creates a new formdata object.
* With this object we can load or submit data via ajax.
*
* @since 1.0.0
* @param string ajaxurl URL to the ajax handler.
* @param string default_action The action to use when an ajax function
* does not specify an action.
* @return WpmUiAjaxData A new formdata object.
*/
wpmUi.ajax = function ajax( ajaxurl, default_action ) {
_init();
return new wpmUi.WpmUiAjaxData( ajaxurl, default_action );
};
/**
* Upgrades normal multiselect fields to chosen-input fields.
*
* This function is a bottle-neck in Firefox -> el.chosen() takes quite long
*
* @since 1.0.0
* @param jQuery|string base All children of this base element will be
* checked. If empty then the body element is used.
*/
wpmUi.upgrade_multiselect = function upgrade_multiselect( base ) {
_init();
base = jQuery( base || _body );
var items = base.find( 'select[multiple]' ),
ajax_items = base.find( 'input[data-select-ajax]' );
// When an DOM container is *cloned* it may contain markup for a select2
// listbox that is not attached to any event handler. Clean this up.
var clean_ghosts = function clean_ghosts( el ) {
var id = el.attr( 'id' ),
s2id = '#s2id_' + id,
ghosts = el.parent().find( s2id );
ghosts.remove();
};
// Initialize normal select or multiselect list.
var upgrade_item = function upgrade_item() {
var el = jQuery( this ),
options = {
'closeOnSelect': false,
'width': '100%'
};
// Prevent double initialization (i.e. conflict with other plugins)
if ( typeof el.data( 'select2' ) === 'object' ) { return; }
if ( typeof el.data( 'chosen' ) === 'object' ) { return; }
if ( el.filter( '[class*=acf-]' ).length ) { return; }
// Prevent double initialization (with other WPMU LIB plugin)
if ( el.data( 'wpmui-select' ) === '1' ) { return; }
// Prevent auto-initialization when manually disabled.
if ( el.closest( '.no-auto-init', base[0] ).length ) { return; }
el.data( 'wpmui-select', '1' );
clean_ghosts( el );
// Prevent lags during page load by making this asynchronous.
window.setTimeout( function() {
el.wpmuiSelect(options);
}, 1);
};
// Initialize select list with ajax source.
var upgrade_ajax = function upgrade_ajax() {
var format_item = function format_item( item ) {
return item.val;
};
var get_id = function get_id( item ) {
return item.key;
};
var init_selection = function init_selection( me, callback ) {
var vals = me.val(),
data = [],
plain = [];
jQuery( vals.split(',') ).each(function () {
var item = this.split('::');
plain.push( item[0] );
data.push( { key: item[0], val: item[1] } );
});
me.val( plain.join(',') );
callback( data );
};
var el = jQuery( this ),
options = {
'closeOnSelect': false,
'width': '100%',
'multiple': true,
'minimumInputLength': 1,
'ajax': {
url: el.attr( 'data-select-ajax' ),
dataType: 'json',
quietMillis: 100,
cache: true,
data: function(term, page) {
return {
q: term,
};
},
results: function(data, page) {
return {
results: data.items
};
}
},
'id': get_id,
'formatResult': format_item,
'formatSelection': format_item,
'initSelection': init_selection
};
// Prevent double initialization (i.e. conflict with other plugins)
if ( typeof el.data( 'select2' ) === 'object' ) { return; }
if ( typeof el.data( 'chosen' ) === 'object' ) { return; }
if ( el.filter( '[class*=acf-]' ).length ) { return; }
// Prevent double initialization (with other WPMU LIB plugin)
if ( el.data( 'wpmui-select' ) === '1' ) { return; }
// Prevent auto-initialization when manually disabled
if ( el.closest( '.no-auto-init', base[0] ).length ) { return; }
el.data( 'wpmui-select', '1' );
clean_ghosts( el );
// Prevent lags during page load by making this asynchronous.
window.setTimeout( function() {
el.wpmuiSelect(options);
}, 1);
};
if ( 'function' === typeof jQuery.fn.each2 ) {
items.each2( upgrade_item );
ajax_items.each2( upgrade_ajax );
} else {
items.each( upgrade_item );
ajax_items.each( upgrade_ajax );
}
};
/**
* Displays a WordPress-like message to the user.
*
* @since 1.0.0
* @param string|object args Message options object or message-text.
* args: {
* 'message': '...'
* 'type': 'ok|err' // Style
* 'close': true // Show close button?
* 'parent': '.wrap' // Element that displays the message
* 'insert_after': 'h2' // Inside the parent the message
* // will be displayed after the
* // first element of this type.
* // Set to false to insert at top.
* 'id': 'msg-ok' // When set to a string value then the
* // the first call to "message()" will
* // insert a new message and the next
* // call will update the existing element.
* 'class': 'msg1' // Additional CSS class.
* 'details': obj // Details for error-type message.
* }
*/
wpmUi.message = function message( args ) {
var parent, msg_box, btn_close, need_insert, debug;
_init();
// Hides the message again, e.g. when user clicks the close icon.
var hide_message = function hide_message( ev ) {
ev.preventDefault();
msg_box.remove();
return false;
};
// Toggle the error-details
var toggle_debug = function toggle_debug( ev ) {
var me = jQuery( this ).closest( '.wpmui-msg' );
me.find( '.debug' ).toggle();
};
if ( 'undefined' === typeof args ) { return false; }
if ( 'string' === typeof args || args instanceof Array ) {
args = { 'message': args };
}
if ( args['message'] instanceof Array ) {
args['message'] = args['message'].join( '
' );
}
if ( ! args['message'] ) { return false; }
args['type'] = undefined === args['type'] ? 'ok' : args['type'].toString().toLowerCase();
args['close'] = undefined === args['close'] ? true : args['close'];
args['parent'] = undefined === args['parent'] ? '.wrap' : args['parent'];
args['insert_after'] = undefined === args['insert_after'] ? 'h2' : args['insert_after'];
args['id'] = undefined === args['id'] ? '' : args['id'].toString().toLowerCase();
args['class'] = undefined === args['class'] ? '' : args['class'].toString().toLowerCase();
args['details'] = undefined === args['details'] ? false : args['details'];
if ( args['type'] === 'error' || args['type'] === 'red' ) { args['type'] = 'err'; }
if ( args['type'] === 'success' || args['type'] === 'green' ) { args['type'] = 'ok'; }
parent = jQuery( args['parent'] ).first();
if ( ! parent.length ) { return false; }
if ( args['id'] && jQuery( '.wpmui-msg[data-id="' + args['id'] + '"]' ).length ) {
msg_box = jQuery( '.wpmui-msg[data-id="' + args['id'] + '"]' ).first();
need_insert = false;
} else {
msg_box = jQuery( '
' );
if ( args['id'] ) { msg_box.attr( 'data-id', args['id'] ); }
need_insert = true;
}
msg_box.find( 'p' ).html( args['message'] );
if ( args['type'] === 'err' && args['details'] && window.JSON ) {
jQuery( '' )
.appendTo( msg_box )
.text( JSON.stringify( args['details'] ) );
jQuery( '' )
.prependTo( msg_box.find( 'p:first' ) )
.click( toggle_debug )
.after( ' ' );
}
msg_box.removeClass().addClass( 'updated wpmui-msg ' + args['class'] );
if ( 'err' === args['type'] ) {
msg_box.addClass( 'error' );
}
if ( need_insert ) {
if ( args['close'] ) {
btn_close = jQuery( '' );
btn_close.prependTo( msg_box );
btn_close.click( hide_message );
}
if ( args['insert_after'] && parent.find( args['insert_after'] ).length ) {
parent = parent.find( args['insert_after'] ).first();
parent.after( msg_box );
} else {
parent.prepend( msg_box );
}
}
return true;
};
/**
* Displays confirmation box to the user.
*
* The layer is displayed in the upper half of the parent element and is by
* default modal.
* Note that the confirmation is asynchronous and the functions return value
* only indicates if the confirmation message was created, and not the users
* response!
*
* Also this is a "disponsable" function which does not create DOM elements
* that can be re-used. All elements are temporary and are removed when the
* confirmation is closed. Only 1 confirmation should be displayed at a time.
*
* @since 1.0.14
* @param object args {
* Confirmation options.
*
* string message
* bool modal
* string layout 'fixed' or 'absolute'
* jQuery parent A jQuery object or selector
* array buttons Default is ['OK']
* function(key) callback Receives array-index of the pressed button
* }
* @return bool True if the confirmation is created correctly.
*/
wpmUi.confirm = function confirm( args ) {
var parent, modal, container, el_msg, el_btn, ind, item, primary_button;
if ( ! args instanceof Object ) { return false; }
if ( undefined === args['message'] ) { return false; }
args['modal'] = undefined === args['modal'] ? true : args['modal'];
args['layout'] = undefined === args['layout'] ? 'fixed' : args['layout'];
args['parent'] = undefined === args['parent'] ? _body : args['parent'];
args['buttons'] = undefined === args['buttons'] ? ['OK'] : args['buttons'];
args['callback'] = undefined === args['callback'] ? false : args['callback'];
parent = jQuery( args['parent'] );
function handle_close() {
var me = jQuery( this ),
key = parseInt( me.data( 'key' ) );
if ( args['modal'] ) {
if ( args['layout'] === 'fixed' ) {
wpmUi._close_modal();
} else {
modal.remove();
}
}
container.remove();
if ( 'function' === typeof args['callback'] ) {
args['callback']( key );
}
}
if ( args['modal'] ) {
if ( args['layout'] === 'fixed' ) {
wpmUi._make_modal( 'wpmui-confirm-modal' );
} else {
modal = jQuery( '' )
.css( { 'position': args['layout'] } )
.appendTo( parent );
}
}
container = jQuery( '' )
.css( { 'position': args['layout'] } )
.appendTo( parent );
el_msg = jQuery( '' )
.html( args['message'] );
el_btn = jQuery( '' );
primary_button = true;
for ( ind = 0; ind < args['buttons'].length; ind += 1 ) {
item = jQuery( '' )
.html( args['buttons'][ind] )
.addClass( primary_button ? 'button-primary' : 'button-secondary' )
.data( 'key', ind )
.click( handle_close )
.prependTo( el_btn );
primary_button = false;
}
el_msg.appendTo( container );
el_btn.appendTo( container )
.find( '.button-primary' )
.focus();
return true;
};
/**
* Attaches a tooltip to the specified element.
*
* @since 1.0.0
* @param jQuery el The host element that receives the tooltip.
* @param object|string args The tooltip options. Either a string containing
* the toolip message (HTML code) or an object with details:
* - content
* - trigger [hover|click]
* - pos [top|bottom|left|right]
* - class
*/
wpmUi.tooltip = function tooltip( el, args ) {
var tip, parent;
_init();
// Positions the tooltip according to the function args.
var position_tip = function position_tip( tip ) {
var tip_width = tip.outerWidth(),
tip_height = tip.outerHeight(),
tip_padding = 5,
el_width = el.outerWidth(),
el_height = el.outerHeight(),
pos = {};
pos['left'] = (el_width - tip_width) / 2;
pos['top'] = (el_height - tip_height) / 2;
pos[ args['pos'] ] = 'auto';
switch ( args['pos'] ) {
case 'top': pos['bottom'] = el_height + tip_padding; break;
case 'bottom': pos['top'] = el_height + tip_padding; break;
case 'left': pos['right'] = el_width + tip_padding; break;
case 'right': pos['left'] = el_width + tip_padding; break;
}
tip.css(pos);
};
// Make the tooltip visible.
var show_tip = function show_tip( ev ) {
var tip = jQuery( this )
.closest( '.wpmui-tip-box' )
.find( '.wpmui-tip' );
tip.addClass( 'wpmui-visible' );
tip.show();
position_tip( tip );
window.setTimeout( function() { position_tip( tip ); }, 35 );
};
// Hide the tooltip.
var hide_tip = function hide_tip( ev ) {
var tip = jQuery( this )
.closest( '.wpmui-tip-box' )
.find( '.wpmui-tip' );
tip.removeClass( 'wpmui-visible' );
tip.hide();
};
// Toggle the tooltip state.
var toggle_tip = function toggle_tip( ev ) {
if ( tip.hasClass( 'wpmui-visible' ) ) {
hide_tip.call(this, ev);
} else {
show_tip.call(this, ev);
}
};
if ( 'string' === typeof args ) {
args = { 'content': args };
}
if ( undefined === args['content'] ) {
return false;
}
el = jQuery( el );
if ( ! el.length ) {
return false;
}
args['trigger'] = undefined === args['trigger'] ? 'hover' : args['trigger'].toString().toLowerCase();
args['pos'] = undefined === args['pos'] ? 'top' : args['pos'].toString().toLowerCase();
args['class'] = undefined === args['class'] ? '' : args['class'].toString().toLowerCase();
parent = el.parent();
if ( ! parent.hasClass( 'wpmui-tip-box' ) ) {
parent = el
.wrap( '' )
.parent()
.addClass( args['class'] + '-box' );
}
tip = parent.find( '> .wpmui-tip' );
el.off();
if ( ! tip.length ) {
tip = jQuery( '' );
tip
.addClass( args['class'] )
.addClass( args['pos'] )
.appendTo( el.parent() )
.hide();
if ( ! isNaN( args['width'] ) ) {
tip.width( args['width'] );
}
}
if ( 'hover' === args['trigger'] ) {
el.on( 'mouseenter', show_tip ).on( 'mouseleave', hide_tip );
} else if ( 'click' === args['trigger'] ) {
el.on( 'click', toggle_tip );
}
tip.html( args['content'] );
return true;
};
/**
* Checks the DOM and creates tooltips for the DOM Elements that specify
* tooltip details.
*
* Function can be called repeatedly and will refresh the tooltip contents
* if they changed since last call.
*
* @since 1.0.8
*/
wpmUi.upgrade_tooltips = function upgrade_tooltips() {
var el = jQuery( '[data-wpmui-tooltip]' );
el.each(function() {
var me = jQuery( this ),
args = {
'content': me.attr( 'data-wpmui-tooltip' ),
'pos': me.attr( 'data-pos' ),
'trigger': me.attr( 'data-trigger' ),
'class': me.attr( 'data-class' ),
'width': me.attr( 'data-width' )
};
wpmUi.tooltip( me, args );
});
};
/*
* Converts any value to an object.
* Typically used to convert an array to an object.
*
* @since 1.0.6
* @param mixed value This value is converted to an JS-object.
* @return object
*/
wpmUi.obj = function( value ) {
var obj = {};
if ( value instanceof Object ) {
obj = value;
}
else if ( value instanceof Array ) {
if ( typeof value.reduce === 'function' ) {
obj = value.reduce(function(o, v, i) {
o[i] = v;
return o;
}, {});
} else {
for ( var i = value.length - 1; i > 0; i -= 1 ) {
if ( value[i] !== undefined ) {
obj[i] = value[i];
}
}
}
}
else if ( typeof value === 'string' ) {
obj.scalar = value;
}
else if ( typeof value === 'number' ) {
obj.scalar = value;
}
else if ( typeof value === 'boolean' ) {
obj.scalar = value;
}
return obj;
};
// ==========
// == Private helper functions =============================================
// ==========
/**
* Initialize the object
*
* @since 1.0.0
* @private
*/
function _init() {
if ( null !== _html ) { return; }
_doc = jQuery( document );
_html = jQuery( 'html' );
_body = jQuery( 'body' );
_init_boxes();
_init_tabs();
if ( ! _body.hasClass( 'no-auto-init' ) ) {
/**
* Do the auto-initialization stuff after a short delay, so other
* scripts can run first.
*/
window.setTimeout(function() {
wpmUi.upgrade_multiselect();
wpmUi.upgrade_tooltips();
}, 20);
}
wpmUi.binary = new wpmUi.WpmUiBinary();
}
/**
* Returns the modal overlay object
*
* @since 1.1.0
* @private
*/
wpmUi._modal_overlay = function() {
if ( null === _modal_overlay ) {
_modal_overlay = jQuery( '' )
.addClass( 'wpmui-overlay' )
.appendTo( _body );
}
return _modal_overlay;
};
/**
* Shows a modal background layer
*
* @since 1.0.0
* @param string the_class CSS class added to the overlay.
* @param string html_classes Additional CSS classes added to the HTML tag.
* @private
*/
wpmUi._make_modal = function( the_class, html_classes ) {
var overlay = wpmUi._modal_overlay();
overlay.removeClass().addClass( 'wpmui-overlay' );
if ( the_class ) {
overlay.addClass( the_class );
}
_body.addClass( 'wpmui-has-overlay' );
_html.addClass( 'wpmui-no-scroll' );
if ( html_classes ) {
_html.addClass( html_classes );
}
return overlay;
};
/**
* Closes the modal background layer again.
*
* @since 1.0.0
* @param string html_classes Additional CSS classes to remove from HTML tag.
* @private
*/
wpmUi._close_modal = function( html_classes ) {
_body.removeClass( 'wpmui-has-overlay' );
_html.removeClass( 'wpmui-no-scroll' );
if ( html_classes) {
_html.removeClass( html_classes );
}
};
/**
* Initialize the WordPress-ish accordeon boxes:
* Open or close boxes when user clicks the toggle icon.
*
* @since 1.0.0
*/
function _init_boxes() {
// Toggle the box state (open/closed)
var toggle_box = function toggle_box( ev ) {
var box = jQuery( this ).closest( '.wpmui-box' );
ev.preventDefault();
// Don't toggle the box if it is static.
if ( box.hasClass( 'static' ) ) { return false; }
box.toggleClass( 'closed' );
return false;
};
_body.on( 'click', '.wpmui-box > h3', toggle_box );
_body.on( 'click', '.wpmui-box > h3 > .toggle', toggle_box );
}
/**
* Initialize the WordPress-ish tab navigation:
* Change the tab on click.
*
* @since 1.0.0
*/
function _init_tabs() {
// Toggle the box state (open/closed)
var activate_tab = function activate_tab( ev ) {
var tab = jQuery( this ),
all_tabs = tab.closest( '.wpmui-tabs' ),
content = all_tabs.next( '.wpmui-tab-contents' ),
active = all_tabs.find( '.active.tab' ),
sel_tab = tab.attr( 'href' ),
sel_active = active.attr( 'href' ),
content_tab = content.find( sel_tab ),
content_active = content.find( sel_active );
// Close previous tab.
if ( ! tab.hasClass( 'active' ) ) {
active.removeClass( 'active' );
content_active.removeClass( 'active' );
}
// Open selected tab.
tab.addClass( 'active' );
content_tab.addClass( 'active' );
ev.preventDefault();
return false;
};
_body.on( 'click', '.wpmui-tabs .tab', activate_tab );
}
// Initialize the object.
jQuery(function() {
_init();
});
}( window.wpmUi = window.wpmUi || {} ));
/*!
* WPMU Dev UI library
* (Philipp Stracker for WPMU Dev)
*
* This module provides the WpmUiWindow object which is a smart and easy to use
* Pop-up.
*
* @version 3.0.0
* @author Philipp Stracker for WPMU Dev
* @requires jQuery
*/
/*global jQuery:false */
/*global window:false */
(function( wpmUi ) {
/*============================*\
================================
== ==
== WINDOW ==
== ==
================================
\*============================*/
/**
* The next popup ID to use
*
* @type int
* @since 1.1.0
* @internal
*/
var _next_id = 1;
/**
* A list of all popups
*
* @type array
* @since 1.1.0
* @internal
*/
var _all_popups = {};
/**
* Returns a list with all currently open popups.
*
* When a popup is created it is added to the list.
* When it is closed (not hidden!) it is removed.
*
* @since 1.1.0
* @return WpmUiWindow[]
*/
wpmUi.popups = function() {
return _all_popups;
};
/**
* Popup window.
*
* @type WpmUiWindow
* @since 1.0.0
*/
wpmUi.WpmUiWindow = function( _template, _css ) {
/**
* Backreference to the WpmUiWindow object.
*
* @since 1.0.0
* @internal
*/
var _me = this;
/**
* Stores the state of the window.
*
* @since 1.0.0
* @internal
*/
var _visible = false;
/**
* Defines if a modal background should be visible.
*
* @since 1.0.0
* @internal
*/
var _modal = false;
/**
* Defines if the dialog title should contain a close button.
*
* @since 1.1.2
* @internal
*/
var _title_close = true;
/**
* Defines if clicking in the modal background closes the dialog.
*
* @since 1.1.2
* @internal
*/
var _background_close = true;
/**
* Size of the window.
*
* @since 1.0.0
* @internal
*/
var _width = 740;
/**
* Size of the window.
*
* @since 1.0.0
* @internal
*/
var _height = 400;
/**
* Title of the window.
*
* @since 1.0.0
* @internal
*/
var _title = 'Window';
/**
* Content of the window. Either a jQuery selector/object or HTML code.
*
* @since 1.0.0
* @internal
*/
var _content = '';
/**
* Class names to add to the popup window
*
* @since 1.0.14
* @internal
*/
var _classes = '';
/**
* Opening animation - triggered when .show() is called.
*
* @since 3.0.0
* @internal
*/
var _animation_in = '';
/**
* Closing animation - triggered when .hide() or .close() is called.
*
* @since 3.0.0
* @internal
*/
var _animation_out = '';
/**
* Is set to true when new content is assigned to the window.
*
* @since 1.0.0
* @internal
*/
var _content_changed = false;
/**
* Flag is set to true when the window size was changed.
* After the window was updated we will additionally check if it is
* visible in the current viewport.
*
* @since 1.0.0
* @internal
*/
var _need_check_size = false;
/**
* Position of the popup, can contain one or more of these flags:
* 'none', 'left', 'right', 'top', 'bottom'
*
* @since 2.0.0
* @internal
*/
var _snap = { top: false, left: false, right: false, bottom: false };
/**
* Define closing-behavior of the popup to be a slide-in:
* 'none', 'up', 'down'
*
* @since 2.0.0
* @internal
*/
var _slidein = 'none';
/**
* Called after the window is made visible.
*
* @type Callback function.
* @since 1.0.0
* @internal
*/
var _onshow = null;
/**
* Called after the window was hidden.
*
* @type Callback function.
* @since 1.0.0
* @internal
*/
var _onhide = null;
/**
* Called after the window was hidden + destroyed.
*
* @type Callback function.
* @since 1.0.0
* @internal
*/
var _onclose = null;
/**
* Custom resize handler.
*
* @type Callback function.
* @since 1.0.0
* @internal
*/
var _onresize = null;
/**
* The popup container element. This is the outermost DOM element of the
* popup. The _wnd element might contain additional data, such as a
* CSS ' ).prependTo( _wnd );
}
// Add default selector class to the base element if the class is missing.
if ( ! _wnd.filter( '.popup' ).length && ! _wnd.find( '.popup' ).length ) {
_wnd.addClass( 'popup' );
}
// See comments in top section for difference between _wnd and _popup.
if ( _wnd.hasClass( 'popup' ) ) {
_popup = _wnd;
} else {
_popup = _wnd.find( '.popup' ).first();
}
// Add supported content modification methods.
if ( ! _popup.find( '.popup-title' ).length ) {
_me.title = function() { return _me; };
}
if ( ! _popup.find( '.popup-content' ).length ) {
_me.content = function() { return _me; };
}
if ( ! _popup.find( '.slidein-toggle' ).length ) {
if ( _popup.find( '.popup-title .popup-close' ).length ) {
_popup.find( '.popup-title .popup-close' ).addClass( 'slidein-toggle' );
} else if ( _popup.find( '.popup-title' ).length ) {
_popup.find( '.popup-title' ).addClass( 'slidein-toggle' );
} else {
_popup.prepend( '' );
}
}
_visible = false;
}
/**
* Add event listeners.
*
* @since 1.0.0
* @internal
*/
function _hook() {
if ( _popup && ! _popup.data( 'hooked' ) ) {
_popup.data( 'hooked', true );
_popup.on( 'click', '.popup-close', _click_close );
_popup.on( 'click', '.popup-title', _click_title );
_popup.on( 'click', '.close', _me.hide );
_popup.on( 'click', '.destroy', _me.destroy );
_popup.on( 'click', 'thead .check-column :checkbox', _toggle_checkboxes );
_popup.on( 'click', 'tfoot .check-column :checkbox', _toggle_checkboxes );
_popup.on( 'click', 'tbody .check-column :checkbox', _check_checkboxes );
jQuery( window ).on( 'resize', _resize_and_move );
if ( jQuery().draggable !== undefined ) {
_popup.draggable({
containment: jQuery( 'body' ),
scroll: false,
handle: '.popup-title'
});
}
}
}
/**
* Remove all event listeners.
*
* @since 1.0.0
* @internal
*/
function _unhook() {
if ( _popup && _popup.data( 'hooked' ) ) {
_popup.data( 'hooked', false );
_popup.off( 'click', '.popup-close', _click_close );
_popup.off( 'click', '.popup-title', _click_title );
_popup.off( 'click', '.close', _me.hide );
_popup.off( 'click', '.check-column :checkbox', _toggle_checkboxes );
jQuery( window ).off( 'resize', _resize_and_move );
}
}
/**
* Updates the size and position of the window.
*
* @since 1.0.0
* @internal
*/
function _update_window() {
if ( ! _wnd ) { return false; }
if ( ! _popup ) { return false; }
var _overlay = wpmUi._modal_overlay(),
_el_title = _popup.find( '.popup-title' ),
_el_content = _popup.find( '.popup-content' ),
_title_span = _el_title.find( '.the-title' );
// Window title.
if ( _template && ! _title_span.length ) {
_title_span = _el_title;
}
_title_span.html( _title );
if ( _title_close ) {
_popup.removeClass( 'no-close' );
} else {
_popup.addClass( 'no-close' );
}
// Display a copy of the specified content.
if ( _content_changed ) {
// Remove the current button bar.
_wnd.find( '.buttons' ).remove();
_popup.addClass( 'no-buttons' );
// Update the content.
if ( _content instanceof jQuery ) {
// _content is a jQuery element.
_el_content.empty().append( _content );
} else {
// _content is a HTML string.
_el_content.html( _content );
}
// Move the buttons out of the content area.
var buttons = _el_content.find( '.buttons' );
if ( buttons.length ) {
buttons.appendTo( _popup );
_popup.removeClass( 'no-buttons' );
}
// Add custom class to the popup.
_popup.addClass( _classes );
_content_changed = false;
}
if ( _overlay instanceof jQuery ) {
_overlay.off( 'click', _modal_close );
}
// Show or hide the window and modal background.
if ( _visible ) {
_show_the_popup();
if ( _modal ) {
wpmUi._make_modal( '', 'has-popup' );
}
if ( _background_close ) {
_overlay.on( 'click', _modal_close );
}
if ( _need_check_size ) {
_need_check_size = false;
_resize_and_move();
}
// Allow the browser to display + render the title first.
window.setTimeout(function() {
if ( 'down' === _slidein ) {
_el_content.css({ bottom: _el_title.height() + 1 });
} else {
_el_content.css({ top: _el_title.height() + 1 });
}
if ( ! _height ) {
window.setTimeout(_resize_and_move, 5);
}
}, 5);
} else {
_hide_the_popup();
var wnd, remove_modal = true;
for ( wnd in _all_popups ) {
if ( _all_popups[wnd] === _me ) { continue; }
if ( ! _all_popups[wnd].is_visible() ) { continue; }
if ( _all_popups[wnd].is_modal() ) {
remove_modal = false;
break;
}
}
if ( remove_modal ) {
wpmUi._close_modal( 'has-popup no-scroll can-scroll' );
}
}
// Adjust the close-icon according to slide-in state.
var icon = _popup.find('.popup-close .dashicons');
if ( icon.length ) {
if ( 'none' === _slidein ) {
icon.removeClass().addClass('dashicons dashicons-no-alt');
} else {
if ( 'collapsed' === _slidein_status ) {
icon.removeClass().addClass('dashicons').addClass(_icon_collapse);
} else if ( 'expanded' === _slidein_status ) {
icon.removeClass().addClass('dashicons').addClass(_icon_expand);
}
}
}
// Remove all "slidein-..." classes from the popup.
_popup[0].className = _popup[0].className.replace(/\sslidein-.+?\b/g, '');
if ( 'none' === _slidein ) {
_popup.removeClass( 'slidein' );
_popup.removeClass( 'wdev-slidein' );
_popup.addClass( 'wdev-window' );
} else {
_popup.addClass( 'slidein' );
_popup.addClass( 'slidein-' + _slidein );
_popup.addClass( 'slidein-' + _slidein_status );
_popup.addClass( 'wdev-slidein' );
_popup.removeClass( 'wdev-window' );
}
if ( _snap.top ) { _popup.addClass('snap-top'); }
if ( _snap.left ) { _popup.addClass('snap-left'); }
if ( _snap.right ) { _popup.addClass('snap-right'); }
if ( _snap.bottom ) { _popup.addClass('snap-bottom'); }
}
/**
* Displays the popup while considering the slidein option
*
* @since 2.0.0
*/
function _show_the_popup() {
_popup.show();
// We have a collapsed slide-in. Animate it.
var have_slidein = 'none' !== _slidein,
can_expand = ('collapsed' === _slidein_status);
if ( have_slidein ) {
// First time the slide in is opened? Animate it.
if ( ! can_expand && 'none' === _slidein_status ) {
var styles = {};
_slidein_status = 'collapsed';
styles = _get_popup_size( styles );
styles = _get_popup_pos( styles );
_popup.css(styles);
can_expand = true;
}
if ( can_expand ) {
_slidein_status = 'expanding';
_resize_and_move( _slidein_speed );
_need_check_size = false;
window.setTimeout(function() {
_slidein_status = 'expanded';
_update_window();
window.setTimeout( _resize_and_move, 10 );
}, _slidein_speed);
}
}
}
/**
* Hides the popup while considering the slidein option to either
* completely hide the popup or to keep the title visible.
*
* @since 2.0.0
*/
function _hide_the_popup() {
switch ( _slidein ) {
case 'up':
case 'down':
var can_collapse = ('expanded' === _slidein_status);
if ( can_collapse ) {
var wnd = jQuery( window ),
window_height = wnd.innerHeight(),
popup_pos = _popup.position(),
styles = {};
// First position the popup using the `top` property only.
styles['margin-top'] = 0;
styles['margin-bottom'] = 0;
styles['bottom'] = 'auto';
styles['top'] = popup_pos.top;
_popup.css( styles );
// Calculate the destination position of the popup and animate.
_slidein_status = 'collapsing';
styles = _get_popup_pos();
_popup.animate(styles, _slidein_speed, function() {
_slidein_status = 'collapsed';
_update_window();
window.setTimeout( _resize_and_move, 10 );
});
}
break;
default:
_popup.hide();
break;
}
}
/**
* When the popup has slide-in behavior then the close button acts as
* a toggle-visiblity button.
*
* @since 1.0.0
*/
function _click_close( ev ) {
if ( 'none' === _slidein ) {
_me.hide();
} else {
if ( _visible ) {
_me.hide();
} else {
_me.show();
}
}
ev.stopPropagation();
}
/**
* Slide-ins also react when the user clicks the title.
*
* @since 1.0.0
*/
function _click_title( ev ) {
if ( 'none' !== _slidein ) {
if ( _visible ) {
_me.hide();
} else {
_me.show();
}
ev.stopPropagation();
}
}
/**
* Closes the window when user clicks on the modal overlay
*
* @since 1.0.0
* @internal
*/
function _modal_close() {
var _overlay = wpmUi._modal_overlay();
if ( ! _wnd ) { return false; }
if ( ! _overlay instanceof jQuery ) { return false; }
_overlay.off( 'click', _modal_close );
_me.hide();
}
/**
* Makes sure that the popup window is not bigger than the viewport.
*
* @since 1.0.0
* @internal
*/
function _resize_and_move(duration) {
if ( ! _popup ) { return false; }
if ( typeof _onresize === 'function' ) {
_onresize.apply( _me, [ _me.$() ] );
} else {
var styles = {};
styles = _get_popup_size( styles );
styles = _get_popup_pos( styles );
// Size and position.
if ( ! isNaN( duration ) && duration > 0 ) {
_popup.animate(styles, duration);
} else {
_popup.css(styles);
}
}
}
/**
* A helper function for the resize/slidein functions that returns the
* actual size (width and height) of the popup.
*
* @since 1.0.0
* @return object
*/
function _get_popup_size( size ) {
var wnd = jQuery( window ),
window_width = wnd.innerWidth(),
window_height = wnd.innerHeight(),
border_x = parseInt( _popup.css('border-left-width') ) +
parseInt( _popup.css('border-right-width') ),
border_y = parseInt( _popup.css('border-top-width') ) +
parseInt( _popup.css('border-bottom-width') ),
real_width = _width + border_x,
real_height = _height + border_y;
if ( 'object' !== typeof size ) { size = {}; }
// Calculate the width and height ------------------------------
if ( ! _height || ! _width ) {
var get_width = ! _width,
get_height = ! _height,
new_width = 0, new_height = 0;
_popup.find('*').each(function() {
var el = jQuery( this ),
pos = el.position(),
el_width = el.outerWidth() + pos.left,
el_height = el.outerHeight() + pos.top;
if ( get_width && new_width < el_width ) {
new_width = el_width;
}
if ( get_height && new_height < el_height ) {
new_height = el_height;
}
});
if ( get_width ) { real_width = new_width + border_x; }
if ( get_height ) { real_height = new_height + border_y; }
}
if ( _snap.left && _snap.right ) {
// Snap to 2 sides: full width.
size['width'] = window_width - border_x;
} else {
if ( window_width < real_width ) {
real_width = window_width;
}
size['width'] = real_width - border_x;
}
if ( _snap.top && _snap.bottom ) {
// Snap to 2 sides: full height.
size['height'] = window_height - border_y;
} else {
if ( window_height < real_height ) {
real_height = window_height;
}
size['height'] = real_height - border_y;
}
return size;
}
/**
* Helper function used for positioning the popup, it will return the
* x/y positioning styles.
*
* @since 1.0.0
* @return object
*/
function _get_popup_pos( styles ) {
var wnd = jQuery( window ),
el_toggle = _popup.find( '.slidein-toggle' ),
window_width = wnd.innerWidth(),
window_height = wnd.innerHeight(),
border_x = parseInt( _popup.css('border-left-width') ) +
parseInt( _popup.css('border-right-width') ),
border_y = parseInt( _popup.css('border-top-width') ) +
parseInt( _popup.css('border-bottom-width') );
if ( 'object' !== typeof styles ) { styles = {}; }
if ( undefined === styles['width'] || undefined === styles['height'] ) {
styles = _get_popup_size( styles );
}
// Position X: (empty) / left / right / left + right
if ( ! _snap.left && ! _snap.right ) {
// Center X.
styles['left'] = (window_width - styles['width']) / 2;
} else if ( _snap.left && _snap.right ) {
// Snap to 2 sides.
styles['left'] = 0;
} else {
// Snap to one side.
if ( _snap.left ) {
styles['left'] = 0;
}
if ( _snap.right ) {
styles['left'] = window_width - styles['width'] - border_x;
}
}
if ( 'none' !== _slidein && ('collapsed' === _slidein_status || 'collapsing' === _slidein_status) ) {
// We have a collapsed slide-in. Y-position is fixed.
if ( 'down' === _slidein ) {
styles['top'] = el_toggle.outerHeight() - styles['height'];
} else {
styles['top'] = window_height - el_toggle.outerHeight();
}
} else {
// Position Y: (empty) / top / bottom / top + bottom
if ( ! _snap.top && ! _snap.bottom ) {
// Center Y.
styles['top'] = (window_height - styles['height']) / 2;
} else if ( _snap.top && _snap.bottom ) {
// Snap to 2 sides.
styles['top'] = 0;
} else {
// Snap to one side.
if ( _snap.top ) {
styles['top'] = 0;
}
if ( _snap.bottom ) {
styles['top'] = window_height - styles['height'] - border_y;
}
}
}
styles['margin-top'] = 0;
styles['margin-bottom'] = 0;
styles['bottom'] = 'auto';
styles['right'] = 'auto';
if ( undefined === styles['top'] ) { styles['top'] = 'auto'; }
if ( undefined === styles['left'] ) { styles['left'] = 'auto'; }
return styles;
}
/**
* Toggle all checkboxes in a WordPress-ish table when the user clicks
* the check-all checkbox in the header or footer.
*
* @since 1.0.0
* @internal
*/
function _toggle_checkboxes( ev ) {
var chk = jQuery( this ),
c = chk.prop( 'checked' ),
toggle = (ev.shiftKey);
// Toggle checkboxes inside the table body
chk
.closest( 'table' )
.children( 'tbody, thead, tfoot' )
.filter( ':visible' )
.children()
.children( '.check-column' )
.find( ':checkbox' )
.prop( 'checked', c);
}
/**
* Toggle the check-all checkexbox in the header/footer in a
* WordPress-ish table when a single checkbox in the body is changed.
*
* @since 1.0.0
*/
function _check_checkboxes( ev ) {
var chk = jQuery( this ),
unchecked = chk
.closest( 'tbody' )
.find( ':checkbox' )
.filter( ':visible' )
.not( ':checked' );
chk
.closest( 'table' )
.children( 'thead, tfoot' )
.find( ':checkbox' )
.prop( 'checked', ( 0 === unchecked.length ) );
return true;
}
// Initialize the popup window.
_me = this;
_init();
}; /* ** End: WpmUiWindow ** */
}( window.wpmUi = window.wpmUi || {} ));
/*!
* WPMU Dev UI library
* (Philipp Stracker for WPMU Dev)
*
* This module provides the WpmUiProgress object which is a smart and easy to use
* Pop-up.
*
* @version 2.0.2
* @author Philipp Stracker for WPMU Dev
* @requires jQuery
*/
/*global jQuery:false */
/*global window:false */
/*global document:false */
/*global XMLHttpRequest:false */
(function( wpmUi ) {
/*==============================*\
==================================
== ==
== PROGRESS ==
== ==
==================================
\*==============================*/
/**
* The progress bar element.
*
* @type WpmUiProgress
* @since 2.0.2
*/
wpmUi.WpmUiProgress = function() {
/**
* Backreference to the WpmUiWindow object.
*
* @since 2.0.2
* @internal
*/
var _me = this;
/**
* Current value of the progress bar.
*
* @since 2.0.2
* @internal
*/
var _current = 0;
/**
* Max value of the progress bar.
*
* @since 2.0.2
* @internal
*/
var _max = 100;
/**
* The label text
*
* @since 2.0.2
* @internal
*/
var _label = '';
/**
* The wrapper around the progress bar elements.
*
* @since 2.0.2
* @internal
*/
var _el = null;
/**
* The progress bar.
*
* @since 2.0.2
* @internal
*/
var _el_bar = null;
/**
* The progress bar full width indicator.
*
* @since 2.0.2
* @internal
*/
var _el_full = null;
/**
* The progress bar title.
*
* @since 2.0.2
* @internal
*/
var _el_label = null;
/**
* Label that displays the current progress percent value.
*
* @since 2.0.2
* @internal
*/
var _el_percent = null;
/**
* Change the value of the progress bar.
*
* @since 2.0.2
* @api
*/
this.value = function value( val ) {
if ( ! isNaN( val ) ) {
_current = parseInt( val );
_update();
}
return _me;
};
/**
* Set the max value of the progess bar.
*
* @since 2.0.2
* @api
*/
this.max = function max( val ) {
if ( ! isNaN( val ) ) {
_max = parseInt( val );
_update();
}
return _me;
};
/**
* Set the contents of the label.
*
* @since 2.0.2
* @api
*/
this.label = function label( val ) {
_label = val;
_update();
return _me;
};
/**
* Adds an event handler to the element.
*
* @since 2.0.1
*/
this.on = function on( event, selector, callback ) {
_el.on( event, selector, callback );
return _me;
};
/**
* Removes an event handler from the element.
*
* @since 2.0.1
*/
this.off = function off( event, selector, callback ) {
_el.off( event, selector, callback );
return _me;
};
/**
* Returns the jQuery object of the main element
*
* @since 1.0.0
*/
this.$ = function $() {
return _el;
};
// ==============================
// == Private functions =========
/**
* Create the DOM elements for the window.
*
* @since 2.0.2
* @internal
*/
function _init() {
_max = 100;
_current = 0;
_el = jQuery( '' );
_el_full = jQuery( '' );
_el_bar = jQuery( '' );
_el_label = jQuery( '' );
_el_percent = jQuery( '' );
// Attach the window to the current page.
_el_bar.appendTo( _el_full );
_el_percent.appendTo( _el_full );
_el_full.appendTo( _el );
_el_label.appendTo( _el );
_update();
}
/**
* Updates the progress bar
*
* @since 2.0.2
*/
function _update() {
var percent = _current / _max * 100;
if ( percent < 0 ) { percent = 0; }
if ( percent > 100 ) { percent = 100; }
_el_bar.width( percent + '%' );
_el_percent.text( parseInt( percent ) + ' %' );
if ( _label && _label.length ) {
_el_label.html( _label );
_el_label.show();
} else {
_el_label.hide();
}
}
// Initialize the progress bar.
_me = this;
_init();
}; /* ** End: WpmUiProgress ** */
}( window.wpmUi = window.wpmUi || {} ));
/*!
* WPMU Dev UI library
* (Rheinard Korf, Philipp Stracker for WPMU Dev)
*
* This module adds a WordPress-like hook system in javascript that makes it
* easier to expose actions/filters to other developers.
*
* ----------------------------------------------------------------------------
* @file A WordPress-like hook system for JavaScript.
*
* This file demonstrates a simple hook system for JavaScript based on the hook
* system in WordPress. The purpose of this is to make your code extensible and
* allowing other developers to hook into your code with their own callbacks.
*
* There are other ways to do this, but this will feel right at home for
* WordPress developers.
*
* @author Rheinard Korf
* @license GPL2 (https://www.gnu.org/licenses/gpl-2.0.html)
*
* @requires underscore.js (http://underscorejs.org/)
* ----------------------------------------------------------------------------
*
* @version 3.0.0
* @author Philipp Stracker for WPMU Dev
* @requires jQuery
*/
/*global jQuery:false */
/*global window:false */
/*global document:false */
(function( wpmUi ) {
if (wpmUi.add_action) { return; }
/*===========================*\
===============================
== ==
== HOOKS ==
== ==
===============================
\*===========================*/
/**
* All actions/filters are stored in the filters object.
*
* In WordPress actions and filters are synonyms - only difference is, that
* a filter will return a value, while an action does not return a value.
*/
wpmUi.filters = wpmUi.filters || {};
/**
* Add a new Action callback to wpmUi.filters
*
* This function is an alias to wpmUi.add_filter
*
* @param tag The tag specified by do_action()
* @param callback The callback function to call when do_action() is called
* @param priority The order in which to call the callbacks. Default: 10 (like WordPress)
*/
wpmUi.add_action = function( tag, callback, priority ) {
wpmUi.add_filter( tag, callback, priority );
};
/**
* Add a new Filter callback to wpmUi.filters
*
* @param tag The tag specified by apply_filters()
* @param callback The callback function to call when apply_filters() is called
* @param priority Priority of filter to apply. Default: 10 (like WordPress)
*/
wpmUi.add_filter = function( tag, callback, priority ) {
if( undefined === callback ) {
return;
}
if( undefined === priority ) {
priority = 10;
}
// If the tag doesn't exist, create it.
wpmUi.filters[ tag ] = wpmUi.filters[ tag ] || [];
wpmUi.filters[ tag ].push( { priority: priority, callback: callback } );
};
/**
* Remove an Action callback from wpmUi.filters
*
* This function is an Alias to wpmUi.remove_filter
*
* Must be the exact same callback signature.
* Warning: Anonymous functions can not be removed.
* @param tag The tag specified by do_action()
* @param callback The callback function to remove
*/
wpmUi.remove_action = function( tag, callback ) {
wpmUi.remove_filter( tag, callback );
};
/**
* Remove a Filter callback from wpmUi.filters
*
* Must be the exact same callback signature.
* Warning: Anonymous functions can not be removed.
* @param tag The tag specified by apply_filters()
* @param callback The callback function to remove
*/
wpmUi.remove_filter = function( tag, callback ) {
wpmUi.filters[ tag ] = wpmUi.filters[ tag ] || [];
wpmUi.filters[ tag ].forEach( function( filter, i ) {
if( filter.callback === callback ) {
wpmUi.filters[ tag ].splice(i, 1);
}
} );
};
/**
* Remove all Action callbacks for the specified tag.
*
* This function is an Alias to wpmUi.remove_all_filters
*
* @param tag The tag specified by do_action()
* @param priority Only remove actions with the specified priority
*/
wpmUi.remove_all_actions = function( tag, priority ) {
wpmUi.remove_all_filters( tag, priority );
};
/**
* Remove all Filter callbacks for the specified tag
*
* @param tag The tag specified by do_action()
* @param priority Only remove actions with the specified priority
*/
wpmUi.remove_all_filters = function( tag, priority ) {
wpmUi.filters[ tag ] = wpmUi.filters[ tag ] || [];
if ( undefined === priority ) {
wpmUi.filters[ tag ] = [];
} else {
wpmUi.filters[ tag ].forEach( function( filter, i ) {
if( filter.priority === priority ) {
wpmUi.filters[ tag ].splice(i, 1);
}
} );
}
};
/**
* Calls actions that are stored in wpmUi.actions for a specific tag or nothing
* if there are no actions to call.
*
* @param tag A registered tag in Hook.actions
* @options Optional JavaScript object to pass to the callbacks
*/
wpmUi.do_action = function( tag, options ) {
var actions = [];
if( undefined !== wpmUi.filters[ tag ] && wpmUi.filters[ tag ].length > 0 ) {
wpmUi.filters[ tag ].forEach( function( hook ) {
actions[ hook.priority ] = actions[ hook.priority ] || [];
actions[ hook.priority ].push( hook.callback );
} );
actions.forEach( function( hooks ) {
hooks.forEach( function( callback ) {
callback( options );
} );
} );
}
};
/**
* Calls filters that are stored in wpmUi.filters for a specific tag or return
* original value if no filters exist.
*
* @param tag A registered tag in Hook.filters
* @options Optional JavaScript object to pass to the callbacks
*/
wpmUi.apply_filters = function( tag, value, options ) {
var filters = [];
if( undefined !== wpmUi.filters[ tag ] && wpmUi.filters[ tag ].length > 0 ) {
wpmUi.filters[ tag ].forEach( function( hook ) {
filters[ hook.priority ] = filters[ hook.priority ] || [];
filters[ hook.priority ].push( hook.callback );
} );
filters.forEach( function( hooks ) {
hooks.forEach( function( callback ) {
value = callback( value, options );
} );
} );
}
return value;
};
/* ** End: Hooks integration in wpmUi ** */
}( window.wpmUi = window.wpmUi || {} ));
/*!
* WPMU Dev UI library
* (Philipp Stracker for WPMU Dev)
*
* This module provides the WpmUiAjaxData object that is used to serialize whole
* forms and submit then via Ajax. Even file uploads are possibly with this
* object.
*
* @version 1.0.0
* @author Philipp Stracker for WPMU Dev
* @requires jQuery
*/
/*global jQuery:false */
/*global window:false */
/*global document:false */
/*global XMLHttpRequest:false */
(function( wpmUi ) {
/*===============================*\
===================================
== ==
== AJAX-DATA ==
== ==
===================================
\*===============================*/
/**
* Form Data object that is used to load or submit data via ajax.
*
* @type WpmUiAjaxData
* @since 1.0.0
*/
wpmUi.WpmUiAjaxData = function( _ajaxurl, _default_action ) {
/**
* Backreference to the WpmUiAjaxData object.
*
* @since 1.0.0
* @private
*/
var _me = this;
/**
* An invisible iframe with name "wpmui_void", created by this object.
*
* @type jQuery object
* @since 1.0.0
* @private
*/
var _void_frame = null;
/**
* Data that is sent to the server.
*
* @type Object
* @since 1.0.0
* @private
*/
var _data = {};
/**
* Progress handler during upload/download.
* Signature function( progress )
* - progress .. Percentage complete or "-1" for "unknown"
*
* @type Callback function.
* @since 1.0.0
* @private
*/
var _onprogress = null;
/**
* Receives the server response after ajax call is finished.
* Signature: function( response, okay, xhr )
* - response .. Data received from the server.
* - okay .. bool; false means an error occured.
* - xhr .. XMLHttpRequest object.
*
* @type Callback function.
* @since 1.0.0
* @private
*/
var _ondone = null;
/**
* Feature detection: HTML5 upload/download progress events.
*
* @type bool
* @since 1.0.0
* @private
*/
var _support_progress = false;
/**
* Feature detection: HTML5 file API.
*
* @type bool
* @since 1.0.0
* @private
*/
var _support_file_api = false;
/**
* Feature detection: HTML5 FormData object.
*
* @type bool
* @since 1.0.0
* @private
*/
var _support_form_data = false;
// ==============================
// == Public functions ==========
/**
* Define the data that is sent to the server.
*
* @since 1.0.0
* @param mixed Data that is sent to the server. Either:
* - Normal javascript object interpreted as key/value pairs.
* - A jQuery object of the whole form element
* - An URL-encoded string ("key=val&key2=val2")
*/
this.data = function data( obj ) {
_data = obj;
return _me;
};
/**
* Returns an ajax-compatible version of the data object passed in.
* This data object can be any of the values that is recognized by the
* data() method above.
*
* @since 1.0.7
* @param mixed obj
* @return Object
*/
this.extract_data = function extract_data( obj ) {
_data = obj;
return _get_data( undefined, false );
};
/**
* Define the upload/download progress callback.
*
* @since 1.0.0
* @param function callback Progress handler.
*/
this.onprogress = function onprogress( callback ) {
_onprogress = callback;
return _me;
};
/**
* Callback that receives the server response of the ajax request.
*
* @since 1.0.0
* @param function callback
*/
this.ondone = function ondone( callback ) {
_ondone = callback;
return _me;
};
/**
* Reset all configurations.
*
* @since 1.0.0
*/
this.reset = function reset() {
_data = {};
_onprogress = null;
_ondone = null;
return _me;
};
/**
* Submit the specified data to the ajaxurl and pass the response to a
* callback function. Server response can be any string.
*
* @since 1.0.0
* @param action string The ajax action to execute.
*/
this.load_text = function load_text( action ) {
action = action || _default_action;
_load( action, 'text' );
return _me;
};
/**
* Submit the specified data to the ajaxurl and pass the response to a
* callback function. Server response must be a valid JSON string!
*
* @since 1.0.0
* @param action string The ajax action to execute.
*/
this.load_json = function load_json( action ) {
action = action || _default_action;
_load( action, 'json' );
return _me;
};
/**
* Submit the specified data to the ajaxurl and let the browser process
* the response.
* Use this function for example when the server returns a file that
* should be downloaded.
*
* @since 1.0.0
* @param string target Optional. The frame to target.
* @param string action Optional. The ajax action to execute.
*/
this.load_http = function load_http( target, action ) {
target = target || 'wpmui_void';
action = action || _default_action;
_form_submit( action, target );
return _me;
};
// ==============================
// == Private functions =========
/**
* Initialize the formdata object
*
* @since 1.0.0
* @private
*/
function _init() {
// Initialize missing Ajax-URL: Use WordPress ajaxurl if possible.
if ( ! _ajaxurl && typeof window.ajaxurl === 'string') {
_ajaxurl = window.ajaxurl;
}
// Initialize an invisible iframe for file downloads.
_void_frame = jQuery( 'body' ).find( '#wpmui_void' );
if ( ! _void_frame.length ) {
/**
* Create the invisible iframe.
* Usage:
*/
_void_frame = jQuery('')
.attr( 'name', 'wpmui_void' )
.attr( 'id', 'wpmui_void' )
.css({
'width': 1,
'height': 1,
'display': 'none',
'visibility': 'hidden',
'position': 'absolute',
'left': -1000,
'top': -1000
})
.hide()
.appendTo( jQuery( 'body' ) );
}
// Find out what HTML5 feature we can use.
_what_is_supported();
// Reset all configurations.
_me.reset();
}
/**
* Feature detection
*
* @since 1.0.0
* @private
* @return bool
*/
function _what_is_supported() {
var inp = document.createElement( 'INPUT' );
var xhr = new XMLHttpRequest();
// HTML 5 files API
inp.type = 'file';
_support_file_api = 'files' in inp;
// HTML5 ajax upload "progress" events
_support_progress = !! (xhr && ( 'upload' in xhr ) && ( 'onprogress' in xhr.upload ));
// HTML5 FormData object
_support_form_data = !! window.FormData;
}
/**
* Creates the XMLHttpReqest object used for the jQuery ajax calls.
*
* @since 1.0.0
* @private
* @return XMLHttpRequest
*/
function _create_xhr() {
var xhr = new window.XMLHttpRequest();
if ( _support_progress ) {
// Upload progress
xhr.upload.addEventListener( "progress", function( evt ) {
if ( evt.lengthComputable ) {
var percentComplete = evt.loaded / evt.total;
_call_progress( percentComplete );
} else {
_call_progress( -1 );
}
}, false );
// Download progress
xhr.addEventListener( "progress", function( evt ) {
if ( evt.lengthComputable ) {
var percentComplete = evt.loaded / evt.total;
_call_progress( percentComplete );
} else {
_call_progress( -1 );
}
}, false );
}
return xhr;
}
/**
* Calls the "onprogress" callback
*
* @since 1.0.0
* @private
* @param float value Percentage complete / -1 for "unknown"
*/
function _call_progress( value ) {
if ( _support_progress && typeof _onprogress === 'function' ) {
_onprogress( value );
}
}
/**
* Calls the "onprogress" callback
*
* @since 1.0.0
* @private
* @param response mixed The parsed server response.
* @param okay bool False means there was an error.
* @param xhr XMLHttpRequest
*/
function _call_done( response, okay, xhr ) {
_call_progress( 100 );
if ( typeof _ondone === 'function' ) {
_ondone( response, okay, xhr );
}
}
/**
* Returns data object containing the data to submit.
* The data object is either a plain javascript object or a FormData
* object; this depends on the parameter "use_formdata" and browser-
* support for FormData.
*
* @since 1.0.0
* @private
* @param string action
* @param boolean use_formdata If set to true then we return FormData
* when the browser supports it. If support is missing or
* use_formdata is not true then the response is an object.
* @return Object or FormData
*/
function _get_data( action, use_formdata ) {
var data = {};
use_formdata = use_formdata && _support_form_data;
if ( _data instanceof jQuery ) {
// ===== CONVERT ' ),
ajax_action = '';
// Append all data fields to the form.
for ( var name in data ) {
if ( data.hasOwnProperty( name ) ) {
if ( name === ':files' ) {
for ( var file in data[name] ) {
var inp = data[name][file];
form.append( inp );
}
} else if ( name === 'action') {
ajax_action = name + '=' + data[name].toString();
} else {
jQuery('')
.attr( 'name', name )
.attr( 'value', data[name] )
.appendTo( form );
}
}
}
if ( _ajaxurl.indexOf( '?' ) === -1 ) {
ajax_action = '?' + ajax_action;
} else {
ajax_action = '&' + ajax_action;
}
// Set correct form properties.
form.attr( 'action', _ajaxurl + ajax_action )
.attr( 'method', 'POST' )
.attr( 'enctype', 'multipart/form-data' )
.attr( 'target', target )
.hide()
.appendTo( jQuery( 'body' ) );
// Submit the form.
form.submit();
}
// Initialize the formdata object
_me = this;
_init();
}; /* ** End: WpmUiAjaxData ** */
}( window.wpmUi = window.wpmUi || {} ));
/*!
* WPMU Dev UI library
* (Philipp Stracker for WPMU Dev)
*
* This module provides the WpmUiBinary object that is used to
* serialize/deserialize data in base64.
*
* @version 1.0.0
* @author Philipp Stracker for WPMU Dev
* @requires jQuery
*/
/*global jQuery:false */
/*global window:false */
/*global document:false */
/*global XMLHttpRequest:false */
(function( wpmUi ) {
/*===============================*\
===================================
== ==
== UTF8-DATA ==
== ==
===================================
\*===============================*/
/**
* Handles conversions of binary <-> text.
*
* @type WpmUiBinary
* @since 1.0.0
*/
wpmUi.WpmUiBinary = function() {
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
wpmUi.WpmUiBinary.utf8_encode = function utf8_encode( string ) {
if ( typeof string !== 'string' ) {
return string;
} else {
string = string.replace(/\r\n/g, "\n");
}
var output = '', i = 0, charCode;
for ( i; i < string.length; i++ ) {
charCode = string.charCodeAt(i);
if ( charCode < 128 ) {
output += String.fromCharCode( charCode );
} else if ( (charCode > 127) && (charCode < 2048) ) {
output += String.fromCharCode( (charCode >> 6) | 192 );
output += String.fromCharCode( (charCode & 63) | 128 );
} else {
output += String.fromCharCode( (charCode >> 12) | 224 );
output += String.fromCharCode( ((charCode >> 6) & 63) | 128 );
output += String.fromCharCode( (charCode & 63) | 128 );
}
}
return output;
};
wpmUi.WpmUiBinary.utf8_decode = function utf8_decode( string ) {
if ( typeof string !== 'string' ) {
return string;
}
var output = '', i = 0, charCode = 0;
while ( i < string.length ) {
charCode = string.charCodeAt(i);
if ( charCode < 128 ) {
output += String.fromCharCode( charCode );
i += 1;
} else if ( (charCode > 191) && (charCode < 224) ) {
output += String.fromCharCode(((charCode & 31) << 6) | (string.charCodeAt(i + 1) & 63));
i += 2;
} else {
output += String.fromCharCode(((charCode & 15) << 12) | ((string.charCodeAt(i + 1) & 63) << 6) | (string.charCodeAt(i + 2) & 63));
i += 3;
}
}
return output;
};
/**
* Converts a utf-8 string into an base64 encoded string
*
* @since 1.0.15
* @param string input A string with any encoding.
* @return string
*/
wpmUi.WpmUiBinary.base64_encode = function base64_encode( input ) {
if ( typeof input !== 'string' ) {
return input;
} else {
input = wpmUi.WpmUiBinary.utf8_encode( input );
}
var output = '', a, b, c, d, e, f, g, i = 0;
while ( i < input.length ) {
a = input.charCodeAt(i++);
b = input.charCodeAt(i++);
c = input.charCodeAt(i++);
d = a >> 2;
e = ((a & 3) << 4) | (b >> 4);
f = ((b & 15) << 2) | (c >> 6);
g = c & 63;
if ( isNaN( b ) ) {
f = g = 64;
} else if ( isNaN( c ) ) {
g = 64;
}
output += map.charAt( d ) + map.charAt( e ) + map.charAt( f ) + map.charAt( g );
}
return output;
};
/**
* Converts a base64 string into the original (binary) data
*
* @since 1.0.15
* @param string input Base 64 encoded text
* @return string
*/
wpmUi.WpmUiBinary.base64_decode = function base64_decode( input ) {
if ( typeof input !== 'string' ) {
return input;
} else {
input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
}
var output = '', a, b, c, d, e, f, g, i = 0;
while ( i < input.length ) {
d = map.indexOf( input.charAt( i++ ) );
e = map.indexOf( input.charAt( i++ ) );
f = map.indexOf( input.charAt( i++ ) );
g = map.indexOf( input.charAt( i++ ) );
a = (d << 2) | (e >> 4);
b = ((e & 15) << 4) | (f >> 2);
c = ((f & 3) << 6) | g;
output += String.fromCharCode( a );
if ( f !== 64 ) {
output += String.fromCharCode( b );
}
if ( g !== 64 ) {
output += String.fromCharCode( c );
}
}
return wpmUi.WpmUiBinary.utf8_decode( output );
};
}; /* ** End: WpmUiBinary ** */
}( window.wpmUi = window.wpmUi || {} ));