initial commit

This commit is contained in:
2024-04-29 13:12:44 +05:45
commit 34887303c5
19300 changed files with 5268802 additions and 0 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,495 @@
var WP_Optimize_Cache = function () {
var $ = jQuery;
var send_command = wp_optimize.send_command;
var browser_cache_enable_btn = $('#wp_optimize_browser_cache_enable'),
purge_cache_btn = $('#wp-optimize-purge-cache'),
enable_page_caching_switch = $('#enable_page_caching'),
page_cache_length_value_inp = $('#page_cache_length_value');
/**
* Handle purge cache btn.
*/
purge_cache_btn.on('click', function() {
var btn = $(this),
spinner = btn.next(),
success_icon = spinner.next();
spinner.show();
send_command('purge_page_cache', {}, function(response) {
spinner.hide();
success_icon.show();
setTimeout(function() {
success_icon.fadeOut('slow', function() {
success_icon.hide();
});
run_update_cache_preload_status();
}, 5000);
update_cache_size_information(response);
});
});
/**
* Trigger purge cache button click if wpo_purge_cache event fired.
*/
$('body').on('wpo_purge_cache', function() {
purge_cache_btn.trigger('click');
});
/**
* Trigger click Browser cache button if user push Enter and form start submitting.
*/
browser_cache_enable_btn.closest('form').on(
'submit',
function(e) {
e.preventDefault();
browser_cache_enable_btn.trigger('click');
return false;
}
);
/**
* Disable or enable preload cache lifespan value
*/
page_cache_length_value_inp.on('change', function() {
var value = parseInt(page_cache_length_value_inp.val(), 10);
$('#preload_schedule_type option[value="wpo_use_cache_lifespan"]').prop('disabled', isNaN(value) || value <= 0);
});
/**
* Handle Enable Gzip compression button click.
*/
$('#wp_optimize_gzip_compression_enable').on('click', function() {
var button = $(this),
loader = button.next();
loader.show();
send_command('enable_gzip_compression', {enable: button.data('enable')}, function(response) {
var gzip_status_message = $('#wpo_gzip_compression_status');
if (response) {
if (response.enabled) {
button.text(wpoptimize.disable);
button.data('enable', '0');
gzip_status_message.removeClass('wpo-disabled').addClass('wpo-enabled');
} else {
button.text(wpoptimize.enable);
button.data('enable', '1');
gzip_status_message.addClass('wpo-disabled').removeClass('wpo-enabled');
}
if (response.message) {
$('#wpo_gzip_compression_error_message').text(response.message).show();
} else {
$('#wpo_gzip_compression_error_message').hide();
}
if (response.output) {
$('#wpo_gzip_compression_output').html(response.output).show();
} else {
$('#wpo_gzip_compression_output').hide();
}
} else {
alert(wpoptimize.error_unexpected_response);
}
loader.hide();
}).fail(function() {
alert(wpoptimize.error_unexpected_response);
loader.hide();
});
});
/**
* Manually check gzip status
*/
$('.wpo-refresh-gzip-status').on('click', function(e) {
e.preventDefault();
$link = $(this);
$link.addClass('loading');
send_command('get_gzip_compression_status', null, function(response) {
$link.removeClass('loading');
var gzip_status_message = $('#wpo_gzip_compression_status');
if (response.hasOwnProperty('status')) {
if (response.status) {
// gzip is enabled
gzip_status_message.removeClass('wpo-disabled').addClass('wpo-enabled');
} else {
// gzip is not enabled
gzip_status_message.addClass('wpo-disabled').removeClass('wpo-enabled');
}
} else if (response.hasOwnProperty('error')) {
alert(response.error);
console.log('Gzip status error code: ' + response.code);
console.log('Gzip status error message: ' + response.message);
}
});
});
/**
* Handle Enable browser cache button click.
*/
browser_cache_enable_btn.on('click', function() {
var browser_cache_expire_days_el = $('#wpo_browser_cache_expire_days'),
browser_cache_expire_hours_el = $('#wpo_browser_cache_expire_hours'),
browser_cache_expire_days = parseInt(browser_cache_expire_days_el.val(), 10),
browser_cache_expire_hours = parseInt(browser_cache_expire_hours_el.val(), 10),
button = $(this),
loader = button.next();
// check for invalid integer.
if (isNaN(browser_cache_expire_days)) browser_cache_expire_days = 0;
if (isNaN(browser_cache_expire_hours)) browser_cache_expire_hours = 0;
if (browser_cache_expire_days < 0 || browser_cache_expire_hours < 0) {
$('#wpo_browser_cache_error_message').text(wpoptimize.please_use_positive_integers).show();
return false;
} else if (browser_cache_expire_hours > 23) {
$('#wpo_browser_cache_error_message').text(wpoptimize.please_use_valid_values).show();
return false;
} else {
$('#wpo_browser_cache_error_message').hide();
}
// set parsed values into input fields.
browser_cache_expire_days_el.val(browser_cache_expire_days);
browser_cache_expire_hours_el.val(browser_cache_expire_hours);
loader.show();
send_command('enable_browser_cache', {browser_cache_expire_days: browser_cache_expire_days, browser_cache_expire_hours: browser_cache_expire_hours}, function(response) {
var cache_status_message = $('#wpo_browser_cache_status');
if (response) {
if (response.enabled) {
button.text(wpoptimize.update);
cache_status_message.removeClass('wpo-disabled').addClass('wpo-enabled');
} else {
button.text(wpoptimize.enable);
cache_status_message.addClass('wpo-disabled').removeClass('wpo-enabled');
}
if (response.message) {
$('#wpo_browser_cache_message').text(response.message).show();
} else {
$('#wpo_browser_cache_message').hide();
}
if (response.error_message) {
$('#wpo_browser_cache_error_message').text(response.error_message).show();
} else {
$('#wpo_browser_cache_error_message').hide();
}
if (response.output) {
$('#wpo_browser_cache_output').html(response.output).show();
} else {
$('#wpo_browser_cache_output').hide();
}
} else {
alert(wpoptimize.error_unexpected_response);
}
loader.hide();
}).fail(function() {
alert(wpoptimize.error_unexpected_response);
loader.hide();
});
});
/**
* Gather cache settings from forms and return it as an object.
*
* @return object
*/
function gather_cache_settings() {
var settings = {};
$('.cache-settings').each(function() {
var el = $(this),
name = el.attr('name');
if (el.is('input[type="checkbox"]')) {
settings[name] = el.is(':checked') ? 1 : 0;
} else if (el.is('textarea')) {
settings[name] = el.val().split("\n");
} else {
settings[name] = el.val();
}
});
$('.cache-settings-array').each(function() {
var el = $(this),
name = el.attr('name');
if (!settings.hasOwnProperty(name)) {
settings[name] = [];
}
if (el.is('input[type="checkbox"]')) {
if ('value' == el.data('saveas')) {
if (el.is(':checked')) settings[name].push(el.val());
} else {
settings[name].push(el.is(':checked') ? 1 : 0);
}
} else if (el.is('textarea')) {
settings[name].push(el.val().split("\n"));
} else {
settings[name].push(el.val());
}
});
return settings;
}
/**
* Handle click on the save settings button for cache.
*/
$('#wp-optimize-save-cache-settings, #wp-optimize-save-cache-advanced-rules, #wp-optimize-save-cache-preload-settings').on('click', function() {
var btn = $(this),
spinner = btn.next(),
success_icon = spinner.next();
spinner.show();
$.blockUI();
send_command('save_cache_settings', { 'cache-settings': gather_cache_settings() }, function(response) {
if (response.hasOwnProperty('js_trigger')) {
$(document).trigger(response.js_trigger, response);
}
if (response.hasOwnProperty('error')) {
// show error
console.log(response.error);
$('.wpo-error__enabling-cache').removeClass('wpo_hidden').find('p').text(response.error.message);
} else {
$('.wpo-error__enabling-cache').addClass('wpo_hidden').find('p').text('');
}
if (response.hasOwnProperty('warnings')) {
// show error
console.log(response.warnings);
$('.wpo-warnings__enabling-cache').removeClass('wpo_hidden')
.find('p').text(response.warnings_label);
var ul = $('.wpo-warnings__enabling-cache').find('ul').html('');
$.each(response.warnings, function(index, warning) {
ul.append('<li>'+warning+'</li>');
});
} else {
$('.wpo-warnings__enabling-cache').addClass('wpo_hidden').find('p').text('');
}
if (response.hasOwnProperty('advanced_cache_file_writing_error')) {
$('#wpo_advanced_cache_output')
.text(response.advanced_cache_file_content)
.show();
} else {
$('#wpo_advanced_cache_output').hide();
}
// update the toggle state depending on response.enabled
enable_page_caching_switch.prop('checked', response.enabled);
// cache is activated
if (enable_page_caching_switch.is(':checked')) {
// show purge button
$('.purge-cache').show();
// enable preload button
$('#wp_optimize_run_cache_preload').removeProp('disabled');
// disable minify preload
$('#wp_optimize_run_minify_preload').prop('disabled', true);
$('#minify-preload').show();
} else {
// hide purge button
$('.purge-cache').hide();
// disable preload button
$('#wp_optimize_run_cache_preload').prop('disabled', true);
// enable minify preload
$('#wp_optimize_run_minify_preload').prop('disabled', false);
$('#minify-preload').hide();
}
if (response.result) {
// If Result is true, show the success icon.
success_icon.show();
setTimeout(function() {
success_icon.fadeOut('slow', function() {
success_icon.hide();
});
}, 5000);
} else {
var tab_id = $('.wp-optimize-nav-tab-contents .notice:visible').closest('.wp-optimize-nav-tab-contents').attr('id'),
tab_name = 'cache';
if (/wpo_cache-(.+)-contents/.test(tab_id)) {
var match = /wpo_cache-(.+)-contents/.exec(tab_id);
tab_name = match[1];
}
// Navigate to the tab where the notice is shown
$('.wpo-page.active .nav-tab-wrapper a[data-tab="'+tab_name+'"]').trigger('click');
// If it's false, scroll to the top where the error is displayed.
var offset = $('.wpo-page.active').offset();
window.scroll(0, offset.top - 20);
}
}).always(function() {
$.unblockUI();
spinner.hide();
});
});
/**
* Toggle page cache
*/
enable_page_caching_switch.on('change', function() {
// hide errors
$('.wpo-error__enabling-cache').addClass('wpo_hidden');
$('.wpo-warnings__enabling-cache').addClass('wpo_hidden');
$('#wpo_advanced_cache_output').hide();
// Trigger the save action
$('#wp-optimize-save-cache-settings').trigger('click');
});
/**
* Cache Preloader functionality
*/
var run_cache_preload_btn = $('#wp_optimize_run_cache_preload'),
cache_preload_status_el = $('#wp_optimize_preload_cache_status'),
check_status_interval = null,
enable_schedule_preloading = $('#enable_schedule_preload'),
preloader_schedule_type_select = $('#preload_schedule_type');
enable_schedule_preloading.on('change', function() {
if (enable_schedule_preloading.prop('checked')) {
preloader_schedule_type_select.prop('disabled', false);
} else {
preloader_schedule_type_select.prop('disabled', true);
}
});
enable_schedule_preloading.trigger('change');
run_cache_preload_btn.on('click', function() {
var btn = $(this),
is_running = btn.data('running'),
status = cache_preload_status_el.text();
btn.prop('disabled', true);
if (is_running) {
btn.data('running', false);
clearInterval(check_status_interval);
check_status_interval = null;
send_command(
'cancel_cache_preload',
null,
function(response) {
if (response && response.hasOwnProperty('message')) {
cache_preload_status_el.text(response.message);
}
}
).always(function() {
btn.val(wpoptimize.run_now);
btn.prop('disabled', false);
});
} else {
cache_preload_status_el.text(wpoptimize.starting_preload);
btn.data('running', true);
send_command(
'run_cache_preload',
null,
null,
true,
{
timeout: 3000 // set a timeout in case the server doesn't support our close browser connection function.
}
).always(function(response) {
try {
var resp = wpo_parse_json(response);
} catch (e) {
}
if (resp && resp.error) {
var error_text = wpoptimize.error_unexpected_response;
if (typeof resp.error != 'function') {
error_text = resp.error;
} else if (resp.status) {
error_text = resp.status + ': ' + resp.statusText;
}
alert(error_text);
cache_preload_status_el.text(status);
btn.prop('disabled', false);
btn.data('running', false);
return;
}
cache_preload_status_el.text(wpoptimize.loading_urls);
btn.val(wpoptimize.cancel);
btn.prop('disabled', false);
run_update_cache_preload_status();
});
}
});
/**
* If already running then update status
*/
if (run_cache_preload_btn.data('running')) {
run_update_cache_preload_status();
}
/**
* Create interval action for update preloader status.
*
* @return void
*/
function run_update_cache_preload_status() {
if (check_status_interval) return;
check_status_interval = setInterval(function() {
update_cache_preload_status();
}, 5000);
}
/**
* Update cache preload status ajax action.
*
* @return void
*/
function update_cache_preload_status() {
send_command('get_cache_preload_status', null, function(response) {
if (response.done) {
run_cache_preload_btn.val(wpoptimize.run_now);
run_cache_preload_btn.data('running', false);
clearInterval(check_status_interval);
check_status_interval = null;
} else {
run_cache_preload_btn.val(wpoptimize.cancel);
run_cache_preload_btn.data('running', true);
}
cache_preload_status_el.text(response.message);
update_cache_size_information(response);
});
}
/**
* Run update information about cache size.
*
* @return void
*/
function update_cache_size_information(response) {
$('#wpo_current_cache_size_information').text(wpoptimize.current_cache_size + ' ' + response.size);
$('#wpo_current_cache_file_count').text(wpoptimize.number_of_files + ' ' + response.file_count);
}
};

View File

@@ -0,0 +1,19 @@
Copyright (C) 2011-2019 by Yehuda Katz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,623 @@
/*!
* jQuery blockUI plugin
* Version 2.71.0-2020.12.08
* Requires jQuery v1.12 or later
*
* Examples at: http://malsup.com/jquery/block/
* Copyright (c) 2007-2013 M. Alsup
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
*/
;(function() {
/*jshint eqeqeq:false curly:false latedef:false */
"use strict";
function setup($) {
var migrateDeduplicateWarnings = jQuery.migrateDeduplicateWarnings || false;
jQuery.migrateDeduplicateWarnings = false;
$.fn._fadeIn = $.fn.fadeIn;
var noOp = $.noop || function() {};
// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
// confusing userAgent strings on Vista)
var msie = /MSIE/.test(navigator.userAgent);
var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
var mode = document.documentMode || 0;
var setExpr = "function" === typeof document.createElement('div').style.setExpression;
// global $ methods for blocking/unblocking the entire page
$.blockUI = function(opts) { install(window, opts); };
$.unblockUI = function(opts) { remove(window, opts); };
// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
$.growlUI = function(title, message, timeout, onClose) {
var $m = $('<div class="growlUI"></div>');
if (title) $m.append('<h1>'+title+'</h1>');
if (message) $m.append('<h2>'+message+'</h2>');
if (timeout === undefined) timeout = 3000;
// Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
var callBlock = function(opts) {
opts = opts || {};
$.blockUI({
message: $m,
fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
centerY: false,
showOverlay: false,
onUnblock: onClose,
css: $.blockUI.defaults.growlCSS
});
};
callBlock();
var nonmousedOpacity = $m.css('opacity');
$m.on('mouseover', function() {
callBlock({
fadeIn: 0,
timeout: 30000
});
var displayBlock = $('.blockMsg');
displayBlock.stop(); // cancel fadeout if it has started
displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
}).on('mouseout', function() {
$('.blockMsg').fadeOut(1000);
});
// End konapun additions
};
// plugin method for blocking element content
$.fn.block = function(opts) {
if ( this[0] === window ) {
$.blockUI( opts );
return this;
}
var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
this.each(function() {
var $el = $(this);
if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
return;
$el.unblock({ fadeOut: 0 });
});
return this.each(function() {
if ($.css(this,'position') == 'static') {
this.style.position = 'relative';
$(this).data('blockUI.static', true);
}
this.style.zoom = 1; // force 'hasLayout' in ie
install(this, opts);
});
};
// plugin method for unblocking element content
$.fn.unblock = function(opts) {
if ( this[0] === window ) {
$.unblockUI( opts );
return this;
}
return this.each(function() {
remove(this, opts);
});
};
$.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
// override these in your code to change the default behavior and style
$.blockUI.defaults = {
// message displayed when blocking (use null for no message)
message: '<h1>Please wait...</h1>',
title: null, // title string; only used when theme == true
draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
theme: false, // set to true to use with jQuery UI themes
// styles for the message when blocking; if you wish to disable
// these and use an external stylesheet then do this in your code:
// $.blockUI.defaults.css = {};
css: {
padding: 0,
margin: 0,
width: '30%',
top: '40%',
left: '35%',
textAlign: 'center',
color: '#000',
border: '3px solid #aaa',
backgroundColor:'#fff',
cursor: 'wait'
},
// minimal style set used when themes are used
themedCSS: {
width: '30%',
top: '40%',
left: '35%'
},
// styles for the overlay
overlayCSS: {
backgroundColor: '#000',
opacity: 0.6,
cursor: 'wait'
},
// style to replace wait cursor before unblocking to correct issue
// of lingering wait cursor
cursorReset: 'default',
// styles applied when using $.growlUI
growlCSS: {
width: '350px',
top: '10px',
left: '',
right: '10px',
border: 'none',
padding: '5px',
opacity: 0.6,
cursor: 'default',
color: '#fff',
backgroundColor: '#000',
'-webkit-border-radius':'10px',
'-moz-border-radius': '10px',
'border-radius': '10px'
},
// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
// (hat tip to Jorge H. N. de Vasconcelos)
/*jshint scripturl:true */
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
// force usage of iframe in non-IE browsers (handy for blocking applets)
forceIframe: false,
// z-index for the blocking overlay
baseZ: 1000,
// set these to true to have the message automatically centered
centerX: true, // <-- only effects element blocking (page block controlled via css above)
centerY: true,
// allow body element to be stetched in ie6; this makes blocking look better
// on "short" pages. disable if you wish to prevent changes to the body height
allowBodyStretch: true,
// enable if you want key and mouse events to be disabled for content that is blocked
bindEvents: true,
// be default blockUI will supress tab navigation from leaving blocking content
// (if bindEvents is true)
constrainTabKey: true,
// fadeIn time in millis; set to 0 to disable fadeIn on block
fadeIn: 200,
// fadeOut time in millis; set to 0 to disable fadeOut on unblock
fadeOut: 400,
// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
timeout: 0,
// disable if you don't want to show the overlay
showOverlay: true,
// if true, focus will be placed in the first available input field when
// page blocking
focusInput: true,
// elements that can receive focus
focusableElements: ':input:enabled:visible',
// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
// no longer needed in 2012
// applyPlatformOpacityRules: true,
// callback method invoked when fadeIn has completed and blocking message is visible
onBlock: null,
// callback method invoked when unblocking has completed; the callback is
// passed the element that has been unblocked (which is the window object for page
// blocks) and the options that were passed to the unblock call:
// onUnblock(element, options)
onUnblock: null,
// callback method invoked when the overlay area is clicked.
// setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
onOverlayClick: null,
// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
quirksmodeOffsetHack: 4,
// class name of the message block
blockMsgClass: 'blockMsg',
// if it is already blocked, then ignore it (don't unblock and reblock)
ignoreIfBlocked: false
};
// private data and functions follow...
var pageBlock = null;
var pageBlockEls = [];
function install(el, opts) {
var css, themedCSS;
var full = (el == window);
var msg = (opts && opts.message !== undefined ? opts.message : undefined);
opts = $.extend({}, $.blockUI.defaults, opts || {});
if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
return;
opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
if (opts.onOverlayClick)
opts.overlayCSS.cursor = 'pointer';
themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
msg = msg === undefined ? opts.message : msg;
// remove the current block (if there is one)
if (full && pageBlock)
remove(window, {fadeOut:0});
// if an existing element is being used as the blocking content then we capture
// its current place in the DOM (and current display style) so we can restore
// it when we unblock
if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
var node = msg.jquery ? msg[0] : msg;
var data = {};
$(el).data('blockUI.history', data);
data.el = node;
data.parent = node.parentNode;
data.display = node.style.display;
data.position = node.style.position;
if (data.parent)
data.parent.removeChild(node);
}
$(el).data('blockUI.onUnblock', opts.onUnblock);
var z = opts.baseZ;
// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
// layer1 is the iframe layer which is used to supress bleed through of underlying content
// layer2 is the overlay layer which has opacity and a wait cursor (by default)
// layer3 is the message content that is displayed while blocking
var lyr1, lyr2, lyr3, s;
if (msie || opts.forceIframe)
lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
else
lyr1 = $('<div class="blockUI" style="display:none"></div>');
if (opts.theme)
lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
else
lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
if (opts.theme && full) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
if ( opts.title ) {
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
}
s += '<div class="ui-widget-content ui-dialog-content"></div>';
s += '</div>';
}
else if (opts.theme) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
if ( opts.title ) {
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
}
s += '<div class="ui-widget-content ui-dialog-content"></div>';
s += '</div>';
}
else if (full) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
}
else {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
}
lyr3 = $(s);
// if we have a message, style it
if (msg) {
if (opts.theme) {
lyr3.css(themedCSS);
lyr3.addClass('ui-widget-content');
}
else
lyr3.css(css);
}
// style the overlay
if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
lyr2.css(opts.overlayCSS);
lyr2.css('position', full ? 'fixed' : 'absolute');
// make iframe layer transparent in IE
if (msie || opts.forceIframe)
lyr1.css('opacity',0.0);
//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
$.each(layers, function() {
this.appendTo($par);
});
if (opts.theme && opts.draggable && $.fn.draggable) {
lyr3.draggable({
handle: '.ui-dialog-titlebar',
cancel: 'li'
});
}
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
var expr = setExpr && ( "CSS1Compat" !== document.compatMode || $('object,embed', full ? null : el).length > 0);
if (ie6 || expr) {
// give body 100% height
if (full && opts.allowBodyStretch && "CSS1Compat" === document.compatMode)
$('html,body').css('height','100%');
// fix ie6 issue when blocked element has a border width
if ((ie6 || "CSS1Compat" !== document.compatMode) && !full) {
var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
var fixT = t ? '(0 - '+t+')' : 0;
var fixL = l ? '(0 - '+l+')' : 0;
}
// simulate fixed position
$.each(layers, function(i,o) {
var s = o[0].style;
s.position = 'absolute';
if (i < 2) {
if (full)
s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - ("CSS1Compat" === document.compatMode?0:'+opts.quirksmodeOffsetHack+') + "px"');
else
s.setExpression('height','this.parentNode.offsetHeight + "px"');
if (full)
s.setExpression('width','"CSS1Compat" === document.compatMode && document.documentElement.clientWidth || document.body.clientWidth + "px"');
else
s.setExpression('width','this.parentNode.offsetWidth + "px"');
if (fixL) s.setExpression('left', fixL);
if (fixT) s.setExpression('top', fixT);
}
else if (opts.centerY) {
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
s.marginTop = 0;
}
else if (!opts.centerY && full) {
var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
s.setExpression('top',expression);
}
});
}
// show the message
if (msg) {
if (opts.theme)
lyr3.find('.ui-widget-content').append(msg);
else
lyr3.append(msg);
if (msg.jquery || msg.nodeType)
$(msg).show();
}
if ((msie || opts.forceIframe) && opts.showOverlay)
lyr1.show(); // opacity is zero
if (opts.fadeIn) {
var cb = opts.onBlock ? opts.onBlock : noOp;
var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
var cb2 = msg ? cb : noOp;
if (opts.showOverlay)
lyr2._fadeIn(opts.fadeIn, cb1);
if (msg)
lyr3._fadeIn(opts.fadeIn, cb2);
}
else {
if (opts.showOverlay)
lyr2.show();
if (msg)
lyr3.show();
if (opts.onBlock)
opts.onBlock.bind(lyr3)();
}
// bind key and mouse events
bind(1, el, opts);
if (full) {
pageBlock = lyr3[0];
pageBlockEls = $(opts.focusableElements,pageBlock);
if (opts.focusInput)
setTimeout(focus, 20);
}
else
center(lyr3[0], opts.centerX, opts.centerY);
if (opts.timeout) {
// auto-unblock
var to = setTimeout(function() {
if (full)
$.unblockUI(opts);
else
$(el).unblock(opts);
}, opts.timeout);
$(el).data('blockUI.timeout', to);
}
}
// remove the block
function remove(el, opts) {
var count;
var full = (el == window);
var $el = $(el);
var data = $el.data('blockUI.history');
var to = $el.data('blockUI.timeout');
if (to) {
clearTimeout(to);
$el.removeData('blockUI.timeout');
}
opts = $.extend({}, $.blockUI.defaults, opts || {});
bind(0, el, opts); // unbind events
if (opts.onUnblock === null) {
opts.onUnblock = $el.data('blockUI.onUnblock');
$el.removeData('blockUI.onUnblock');
}
var els;
if (full) // crazy selector to handle odd field errors in ie6/7
els = $('body').children().filter('.blockUI').add('body > .blockUI');
else
els = $el.find('>.blockUI');
// fix cursor issue
if ( opts.cursorReset ) {
if ( els.length > 1 )
els[1].style.cursor = opts.cursorReset;
if ( els.length > 2 )
els[2].style.cursor = opts.cursorReset;
}
if (full)
pageBlock = pageBlockEls = null;
if (opts.fadeOut) {
count = els.length;
els.stop().fadeOut(opts.fadeOut, function() {
if ( --count === 0)
reset(els,data,opts,el);
});
}
else
reset(els, data, opts, el);
}
// move blocking element back into the DOM where it started
function reset(els,data,opts,el) {
var $el = $(el);
if ( $el.data('blockUI.isBlocked') )
return;
els.each(function(i,o) {
// remove via DOM calls so we don't lose event handlers
if (this.parentNode)
this.parentNode.removeChild(this);
});
if (data && data.el) {
data.el.style.display = data.display;
data.el.style.position = data.position;
data.el.style.cursor = 'default'; // #59
if (data.parent)
data.parent.appendChild(data.el);
$el.removeData('blockUI.history');
}
if ($el.data('blockUI.static')) {
$el.css('position', 'static'); // #22
}
if (typeof opts.onUnblock == 'function')
opts.onUnblock(el,opts);
// fix issue in Safari 6 where block artifacts remain until reflow
var body = $(document.body), w = body.width(), cssW = body[0].style.width;
body.width(w-1).width(w);
body[0].style.width = cssW;
}
// bind/unbind the handler
function bind(b, el, opts) {
var full = el == window, $el = $(el);
// don't bother unbinding if there is nothing to unbind
if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
return;
$el.data('blockUI.isBlocked', b);
// don't bind events when overlay is not in use or if bindEvents is false
if (!full || !opts.bindEvents || (b && !opts.showOverlay))
return;
// bind anchors and inputs for mouse and key events
var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
if (b)
$(document).on(events, opts, handler);
else
$(document).off(events, handler);
// former impl...
// var $e = $('a,:input');
// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
}
// event handler to suppress keyboard/mouse events when blocking
function handler(e) {
// allow tab navigation (conditionally)
if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
if (pageBlock && e.data.constrainTabKey) {
var els = pageBlockEls;
var fwd = !e.shiftKey && e.target === els[els.length-1];
var back = e.shiftKey && e.target === els[0];
if (fwd || back) {
setTimeout(function(){focus(back);},10);
return false;
}
}
}
var opts = e.data;
var target = $(e.target);
if (target.hasClass('blockOverlay') && opts.onOverlayClick)
opts.onOverlayClick(e);
// allow events within the message content
if (target.parents('div.' + opts.blockMsgClass).length > 0)
return true;
// allow events for content that is not being blocked
return target.parents().children().filter('div.blockUI').length === 0;
}
function focus(back) {
if (!pageBlockEls)
return;
var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
if (e)
e.focus();
}
function center(el, x, y) {
var p = el.parentNode, s = el.style;
var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
if (x) s.left = l > 0 ? (l+'px') : '0';
if (y) s.top = t > 0 ? (t+'px') : '0';
}
function sz(el, p) {
return parseInt($.css(el,p),10)||0;
}
jQuery.migrateDeduplicateWarnings = migrateDeduplicateWarnings;
}
/*global define:true */
if (typeof define === 'function' && define.amd && define.amd.jQuery) {
define(['jquery'], setup);
} else {
setup(jQuery);
}
})();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
function loadAsync(e,t){var a,n=!1;a=document.createElement("script"),a.type="text/javascript",a.src=e,a.onreadystatechange=function(){n||this.readyState&&"complete"!=this.readyState||(n=!0,"function"==typeof t&&t())},a.onload=a.onreadystatechange,document.getElementsByTagName("head")[0].appendChild(a)}

View File

@@ -0,0 +1,23 @@
/**
* This function will work cross-browser for loading scripts asynchronously
*/
function loadAsync(src, callback) {
var scriptTag,
ready = false;
scriptTag = document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = src;
scriptTag.onreadystatechange = function() {
// console.log( this.readyState ); //uncomment this line to see which ready states are called.
if (!ready
&& (!this.readyState || this.readyState == 'complete')
) {
ready = true;
typeof callback === 'function' && callback();
}
};
scriptTag.onload = scriptTag.onreadystatechange
document.getElementsByTagName("head")[0].appendChild(scriptTag)
}

View File

@@ -0,0 +1 @@
!function(e){"use strict";var t=function(t,n,o,r){function i(e){return l.body?e():void setTimeout(function(){i(e)})}function d(){s.addEventListener&&s.removeEventListener("load",d),s.media=o||"all"}var a,l=e.document,s=l.createElement("link");if(n)a=n;else{var f=(l.body||l.getElementsByTagName("head")[0]).childNodes;a=f[f.length-1]}var u=l.styleSheets;if(r)for(var c in r)r.hasOwnProperty(c)&&s.setAttribute(c,r[c]);s.rel="stylesheet",s.href=t,s.media="only x",i(function(){a.parentNode.insertBefore(s,n?a:a.nextSibling)});var v=function(e){for(var t=s.href,n=u.length;n--;)if(u[n].href===t)return e();setTimeout(function(){v(e)})};return s.addEventListener&&s.addEventListener("load",d),s.onloadcssdefined=v,v(d),s};"undefined"!=typeof exports?exports.loadCSS=t:e.loadCSS=t}("undefined"!=typeof global?global:this);

View File

@@ -0,0 +1,89 @@
// phpcs:disable
/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
(function(w){
"use strict";
/* exported loadCSS */
var loadCSS = function( href, before, media, attributes ){
// Arguments explained:
// `href` [REQUIRED] is the URL for your CSS file.
// `before` [OPTIONAL] is the element the script should use as a reference for injecting our stylesheet <link> before
// By default, loadCSS attempts to inject the link after the last stylesheet or script in the DOM. However, you might desire a more specific location in your document.
// `media` [OPTIONAL] is the media type or query of the stylesheet. By default it will be 'all'
// `attributes` [OPTIONAL] is the Object of attribute name/attribute value pairs to set on the stylesheet's DOM Element.
var doc = w.document;
var ss = doc.createElement( "link" );
var ref;
if( before ){
ref = before;
}
else {
var refs = ( doc.body || doc.getElementsByTagName( "head" )[ 0 ] ).childNodes;
ref = refs[ refs.length - 1];
}
var sheets = doc.styleSheets;
// Set any of the provided attributes to the stylesheet DOM Element.
if( attributes ){
for( var attributeName in attributes ){
if( attributes.hasOwnProperty( attributeName ) ){
ss.setAttribute( attributeName, attributes[attributeName] );
}
}
}
ss.rel = "stylesheet";
ss.href = href;
// temporarily set media to something inapplicable to ensure it'll fetch without blocking render
ss.media = "only x";
// wait until body is defined before injecting link. This ensures a non-blocking load in IE11.
function ready( cb ){
if( doc.body ){
return cb();
}
setTimeout(function(){
ready( cb );
});
}
// Inject link
// Note: the ternary preserves the existing behavior of "before" argument, but we could choose to change the argument to "after" in a later release and standardize on ref.nextSibling for all refs
// Note: `insertBefore` is used instead of `appendChild`, for safety re: http://www.paulirish.com/2011/surefire-dom-element-insertion/
ready( function(){
ref.parentNode.insertBefore( ss, ( before ? ref : ref.nextSibling ) );
});
// A method (exposed on return object for external use) that mimics onload by polling document.styleSheets until it includes the new sheet.
var onloadcssdefined = function( cb ){
var resolvedHref = ss.href;
var i = sheets.length;
while( i-- ){
if( sheets[ i ].href === resolvedHref ){
return cb();
}
}
setTimeout(function() {
onloadcssdefined( cb );
});
};
function loadCB(){
if( ss.addEventListener ){
ss.removeEventListener( "load", loadCB );
}
ss.media = media || "all";
}
// once loaded, set link's media back to `all` so that the stylesheet applies once it loads
if( ss.addEventListener ){
ss.addEventListener( "load", loadCB);
}
ss.onloadcssdefined = onloadcssdefined;
onloadcssdefined( loadCB );
return ss;
};
// commonjs
if( typeof exports !== "undefined" ){
exports.loadCSS = loadCSS;
}
else {
w.loadCSS = loadCSS;
}
}( typeof global !== "undefined" ? global : this ));

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,595 @@
(function ($) {
var wp_optimize = window.wp_optimize || {};
var send_command = wp_optimize.send_command;
var refresh_frequency = wpoptimize.refresh_frequency || 30000;
if (!send_command) {
console.error('WP-Optimize Minify: wp_optimize.send_command is required.');
return;
}
var minify = {};
/**
* Initializing the minify feature and events
*/
minify.init = function () {
var minify = this;
this.enabled = false;
$(document).on('wp-optimize/minify/toggle-status', function(e, params) {
if (params.hasOwnProperty('enabled')) {
$('[data-whichpage="wpo_minify"]').toggleClass('is-enabled', params.enabled)
minify.enabled = params.enabled;
if (minify.enabled) minify.getFiles();
}
});
/**
* The standard handler for clearing the cache. Safe to use
*/
$('.purge_minify_cache').on('click', function(e) {
e.preventDefault();
$.blockUI();
send_command('purge_minify_cache', null, function(response) {
minify.updateFilesLists(response.files);
minify.updateStats(response.files);
}).always(function() {
$.unblockUI();
});
});
/**
* Removes the entire cache dir.
* Use with caution, as cached html may still reference those files.
*/
$('.purge_all_minify_cache').on('click', function() {
$.blockUI();
send_command('purge_all_minify_cache', null, function(response) {
minify.updateFilesLists(response.files);
minify.updateStats(response.files);
}).always(function() {
$.unblockUI();
});
});
/**
* Forces minifiy to create a new cache, safe to use
*/
$('.minify_increment_cache').on('click', function() {
$.blockUI();
send_command('minify_increment_cache', null, function(response) {
if (response.hasOwnProperty('files')) {
minify.updateFilesLists(response.files);
minify.updateStats(response.files);
}
}).always(function() {
$.unblockUI();
});
});
// ======= SLIDERS ========
// Generic slider save
$('#wp-optimize-nav-tab-wpo_minify-status-contents form :input, #wp-optimize-nav-tab-wpo_minify-js-contents form :input, #wp-optimize-nav-tab-wpo_minify-css-contents form :input, #wp-optimize-nav-tab-wpo_minify-font-contents form :input, #wp-optimize-nav-tab-wpo_minify-settings-contents form :input, #wp-optimize-nav-tab-wpo_minify-advanced-contents form :input').on('change', function() {
$(this).closest('form').data('need_saving', true);
});
$('input[type=checkbox].wpo-save-setting').on('change', function(e) {
var input = $(this),
val = input.prop('checked'),
name = input.prop('name'),
data = {};
data[name] = val;
$.blockUI();
send_command('save_minify_settings', data, function(response) {
if (response.success) {
input.trigger('wp-optimize/minify/saved_setting');
if (response.hasOwnProperty('files')) {
minify.updateFilesLists(response.files);
minify.updateStats(response.files);
}
} else {
console.log('Settings not saved', data)
}
}).always(function() {
$.unblockUI();
});
});
// Slider enable minify
$('#wpo_min_enable_minify').on('wp-optimize/minify/saved_setting', function() {
this.enabled = $(this).prop('checked');
$(document).trigger('wp-optimize/minify/toggle-status', {enabled: this.enabled});
});
// Toggle wpo-feature-is-disabled class
$('#wpo_min_enable_minify').on('wp-optimize/minify/saved_setting', function() {
$(this).closest('.wpo_section').toggleClass('wpo-feature-is-disabled', !$(this).is(':checked'));
});
// Toggle wpo-feature-is-disabled class
$('#wpo_min_enable_minify_css, #wpo_min_enable_minify_js')
// Set value on status change
.on('wp-optimize/minify/saved_setting', function() {
$('#wp-optimize-nav-tab-wrapper__wpo_minify a[data-tab="' + $(this).data('tabname') + '"] span.disabled').toggleClass('hidden', $(this).is(':checked'));
})
// Set value on page load
.each(function() {
$('#wp-optimize-nav-tab-wrapper__wpo_minify a[data-tab="' + $(this).data('tabname') + '"] span.disabled').toggleClass('hidden', $(this).is(':checked'));
});
// slider enable Debug mode
$('#wpo_min_enable_minify_debug').on('wp-optimize/minify/saved_setting', function() {
// Refresh the page as it's needed to show the extra options
$.blockUI({message: '<h1>'+wpoptimize.page_refresh+'</h1>'});
location.href = $('#wp-optimize-nav-tab-wpo_minify-advanced').prop('href');
});
// Edit default exclusions
$('#wpo_min_edit_default_exclutions').on('wp-optimize/minify/saved_setting', function() {
// Show exclusions section
$('.wpo-minify-default-exclusions').toggleClass('hidden', !$(this).prop('checked'));
});
// Save settings
$('.wp-optimize-save-minify-settings').on('click', function(e) {
e.preventDefault();
var btn = $(this),
spinner = btn.next(),
success_icon = spinner.next(),
$need_refresh_btn = null;
spinner.show();
$.blockUI();
var data = {};
var tabs = $('[data-whichpage="wpo_minify"] .wp-optimize-nav-tab-contents form');
tabs.each(function() {
var tab = $(this);
if (true === tab.data('need_saving')) {
data = Object.assign(data, gather_data(tab));
tab.data('need_saving', false);
}
});
/**
* Gather data from the given form
*
* @param {HTMLFormElement} form
*
* @returns {Array} Array of collected data from the form
*/
function gather_data(form) {
var data = $(form).serializeArray().reduce(form_serialize_reduce_cb, {});
$(form).find('input[type="checkbox"]').each(function (i) {
var name = $(this).prop("name");
if (name.includes('[]')) {
if (!$(this).is(':checked')) return;
var newName = name.replace('[]', '');
if (!data[newName]) data[newName] = [];
data[newName].push($(this).val());
} else {
data[name] = $(this).is(':checked') ? 'true' : 'false';
}
});
return data;
}
/**
* Reduces the form elements array into an object
*
* @param {Object} collection An empty object
* @param {*} item form input element as array element
*
* @returns {Object} collection An object of form data
*/
function form_serialize_reduce_cb(collection, item) {
// Ignore items containing [], which we expect to be returned as arrays
if (item.name.includes('[]')) return collection;
collection[item.name] = item.value;
return collection;
}
send_command('save_minify_settings', data, function(response) {
if (response.hasOwnProperty('error')) {
// show error
console.log(response.error);
$('.wpo-error__enabling-cache').removeClass('wpo_hidden').find('p').text(response.error.message);
} else {
$('.wpo-error__enabling-cache').addClass('wpo_hidden').find('p').text('');
}
if (response.hasOwnProperty('files')) {
minify.updateFilesLists(response.files);
minify.updateStats(response.files);
}
spinner.hide();
success_icon.show();
setTimeout(function() {
success_icon.fadeOut('slow', function() {
success_icon.hide();
});
}, 5000);
}).always(function() {
$.unblockUI();
});
})
// Dismiss information notice
$('.wp-optimize-minify-status-information-notice').on('click', '.notice-dismiss', function(e) {
e.preventDefault();
send_command('hide_minify_notice');
});
// Show logs
$('#wpo_min_jsprocessed, #wpo_min_cssprocessed').on('click', '.log', function(e) {
e.preventDefault();
$(this).nextAll('.wpo_min_log').slideToggle('fast');
});
// Handle js excludes
$('#wpo_min_jsprocessed').on('click', '.exclude', function(e) {
e.preventDefault();
var el = $(this);
var excluded_file = get_excluded_file(el);
add_excluded_js_file(excluded_file);
tab_need_saving('js');
highlight_excluded_item(el);
});
// Handle css excludes
$('#wpo_min_cssprocessed').on('click', '.exclude', function(e) {
e.preventDefault();
var el = $(this);
var excluded_file = get_excluded_file(el);
add_excluded_css_file(excluded_file);
tab_need_saving('css');
highlight_excluded_item(el);
});
/**
* Get excluded file url
*
* @param {HTMLElement} el
*
* @return {string}
*/
function get_excluded_file(el) {
return el.data('url');
}
/**
* Exclude js file
*
* @param {string} excluded_file File url
*/
function add_excluded_js_file(excluded_file) {
var $js_textarea = $('#exclude_js');
var list_of_excluded_files = $js_textarea.val();
list_of_excluded_files += excluded_file + '\n';
$js_textarea.val(list_of_excluded_files);
}
/**
* Exclude css file
*
* @param {string} excluded_file File url
*/
function add_excluded_css_file(excluded_file) {
var $css_textarea = $('#exclude_css');
var list_of_excluded_files = $css_textarea.val();
list_of_excluded_files += excluded_file + '\n';
$css_textarea.val(list_of_excluded_files);
}
// Handle defer
$('#wpo_min_jsprocessed').on('click', '.defer', function(e) {
e.preventDefault();
add_deferred_file($(this));
});
// Handle async loading
$('#wpo_min_cssprocessed').on('click', '.async', function(e) {
e.preventDefault();
add_async_file($(this));
});
/**
* Add deferred file
*
* @param {HTMLElement} el target element
*/
function add_deferred_file(el) {
var deferred_file = el.data('url');
var $async_js_textarea = $('#async_js');
var list_of_deferred_files = $async_js_textarea.val();
list_of_deferred_files += deferred_file + '\n';
$async_js_textarea.val(list_of_deferred_files);
tab_need_saving('js');
highlight_excluded_item(el);
}
/**
* Add asynchronously loading file
*
* @param {HTMLElement} el target element
*/
function add_async_file(el) {
var async_file = el.data('url');
var $async_css_textarea = $('#async_css');
var list_of_async_files = $async_css_textarea.val();
list_of_async_files += async_file + '\n';
$async_css_textarea.val(list_of_async_files);
tab_need_saving('css');
highlight_excluded_item(el);
}
/**
*
* @param {string} tab_name Name of the tab that need saving
*/
function tab_need_saving(tab_name) {
$('#wp-optimize-nav-tab-wpo_minify-' + tab_name + '-contents form').data('need_saving', true);
}
/**
* Update UI after excluding the file
*
* @param {HTMLElement} el Target element
*/
function highlight_excluded_item(el) {
el.closest('.wpo_min_log').prev().removeClass('hidden').addClass('updated').slideDown();
el.text(wpoptimize.added_to_list);
el.removeClass('exclude');
el.parent().addClass('disable-list-item');
el.replaceWith($('<span>' + el.text() + '</span>'));
}
$('#wp-optimize-minify-advanced').on('click', '.save-exclusions', function(e) {
e.preventDefault();
$('.wp-optimize-save-minify-settings').first().trigger('click');
});
// Set the initial `enabled` value
this.enabled = $('#wpo_min_enable_minify').prop('checked');
$(document).trigger('wp-optimize/minify/toggle-status', {enabled: this.enabled});
// When loading the page and minify is disabled, make sure that the status tab is active.
if (!this.enabled && !$('#wp-optimize-nav-tab-wrapper__wpo_minify a[data-tab="status"]').is('.nav-tab-active')) {
$('#wp-optimize-nav-tab-wrapper__wpo_minify a[data-tab="status"]').trigger('click');
}
// Enable / disable defer_jquery
function check_defer_status( e ) {
$('input[name="enable_defer_js"]').each(function(index, element) {
$(element).closest('fieldset').removeClass('selected').find('.defer-js-settings').slideUp('fast');
});
$('input[name="enable_defer_js"]:checked').closest('fieldset').addClass('selected').find('.defer-js-settings').slideDown('fast');
}
$('input[name="enable_defer_js"]').on('change', check_defer_status);
check_defer_status();
/**
* Minify Preloader functionality
*/
var run_minify_preload_btn = $('#wp_optimize_run_minify_preload'),
minify_preload_status_el = $('#wp_optimize_preload_minify_status'),
check_status_interval = null;
run_minify_preload_btn.on('click', function() {
var btn = $(this),
is_running = btn.data('running'),
status = minify_preload_status_el.text();
btn.prop('disabled', true);
if (is_running) {
btn.data('running', false);
clearInterval(check_status_interval);
check_status_interval = null;
send_command(
'cancel_minify_preload',
null,
function(response) {
if (response && response.hasOwnProperty('message')) {
minify_preload_status_el.text(response.message);
}
}
).always(function() {
btn.val(wpoptimize.run_now);
btn.prop('disabled', false);
});
} else {
minify_preload_status_el.text(wpoptimize.starting_preload);
btn.data('running', true);
send_command(
'run_minify_preload',
null,
null,
true,
{
timeout: 3000 // set a timeout in case the server doesn't support our close browser connection function.
}
).always(function(response) {
try {
var resp = wpo_parse_json(response);
} catch (e) {
}
if (resp && resp.error) {
var error_text = wpoptimize.error_unexpected_response;
if (typeof resp.error != 'function') {
error_text = resp.error;
} else if (resp.status) {
error_text = resp.status + ': ' + resp.statusText;
}
alert(error_text);
minify_preload_status_el.text(status);
btn.prop('disabled', false);
btn.data('running', false);
return;
}
minify_preload_status_el.text(wpoptimize.loading_urls);
btn.val(wpoptimize.cancel);
btn.prop('disabled', false);
run_update_minify_preload_status();
});
}
});
/**
* If already running then update status
*/
if (run_minify_preload_btn.data('running')) {
run_update_minify_preload_status();
}
/**
* Create interval action for update preloader status.
*
* @return void
*/
function run_update_minify_preload_status() {
if (check_status_interval) return;
check_status_interval = setInterval(function() {
update_minify_preload_status();
}, 5000);
}
/**
* Update minify preload status ajax action.
*
* @return void
*/
function update_minify_preload_status() {
send_command('get_minify_preload_status', null, function(response) {
if (response.done) {
run_minify_preload_btn.val(wpoptimize.run_now);
run_minify_preload_btn.data('running', false);
clearInterval(check_status_interval);
check_status_interval = null;
} else {
run_minify_preload_btn.val(wpoptimize.cancel);
run_minify_preload_btn.data('running', true);
}
minify_preload_status_el.text(response.message);
update_minify_size_information(response);
});
}
/**
* Run update information about minify size.
*
* @return void
*/
function update_minify_size_information(response) {
$('#wpo_min_cache_size').text(response.size);
$('#wpo_min_cache_total_size').text(response.total_size);
}
return this;
}
/**
* Get the list of files generated by Minify and update the markup.
*/
minify.getFiles = function() {
// Only run if the feature is enabled
if (!this.enabled) return;
var data = {
stamp: new Date().getTime()
};
send_command('get_minify_cached_files', data, function(response) {
minify.updateFilesLists(response);
minify.updateStats(response);
});
if (refresh_frequency) setTimeout(minify.getFiles.bind(this), refresh_frequency);
}
minify.updateFilesLists = function(data) {
// reset
var wpominarr = [];
// js
if (data.js.length > 0) {
$(data.js).each(function () {
wpominarr.push(this.uid);
if ($('#'+this.uid).length == 0) {
$('#wpo_min_jsprocessed ul.processed').append('\
<li id="'+this.uid+'">\
<span class="filename"><a href="'+this.file_url+'" target="_blank">'+this.filename+'</a> ('+this.fsize+')</span>\
<a href="#" class="log">' + wpoptimize.toggle_info + '</a>\
<div class="hidden save_notice">\
<p>' + wpoptimize.added_notice + '</p>\
<p><button class="button button-primary save-exclusions">' + wpoptimize.save_notice + '</button></p>\
</div>\
<div class="hidden wpo_min_log">'+this.log+'</div>\
</li>\
');
}
});
}
$('#wpo_min_jsprocessed ul.processed .no-files-yet').toggle(!data.js.length);
// css
if (data.css.length > 0) {
$(data.css).each(function () {
wpominarr.push(this.uid);
if ($('#'+this.uid).length == 0) {
$('#wpo_min_cssprocessed ul.processed').append('\
<li id="'+this.uid+'">\
<span class="filename"><a href="'+this.file_url+'" target="_blank">'+this.filename+'</a> ('+this.fsize+')</span>\
<a href="#" class="log">' + wpoptimize.toggle_info + '</a>\
<div class="hidden save_notice">\
<p>' + wpoptimize.added_to_list + '</p>\
<p><button class="button button-primary save-exclusions">' + wpoptimize.save_notice + '</button></p>\
</div>\
<div class="hidden wpo_min_log">'+this.log+'</div>\
</li>\
');
}
});
}
$('#wpo_min_cssprocessed ul.processed .no-files-yet').toggle(!data.css.length);
// Remove <li> if it's not in the files array
$('#wpo_min_jsprocessed ul.processed > li, #wpo_min_cssprocessed ul.processed > li').each(function () {
if (-1 == jQuery.inArray($(this).attr('id'), wpominarr)) {
if (!$(this).is('.no-files-yet')) {
$(this).remove();
}
}
});
};
minify.updateStats = function(data) {
if (data.cachesize.length > 0) {
$("#wpo_min_cache_size").html(this.enabled ? data.cachesize : wpoptimize.no_minified_assets);
$("#wpo_min_cache_total_size").html(this.enabled ? data.total_cache_size : wpoptimize.no_minified_assets);
$("#wpo_min_cache_time").html(this.enabled ? data.cacheTime : '-');
$("#wpo_min_cache_path").html(data.cachePath);
}
};
wp_optimize.minify = minify;
})(jQuery);

View File

@@ -0,0 +1 @@
var wp_optimize=window.wp_optimize||{};!function(e,t){"use strict";var i={};i.views={},i.views.modal=Backbone.View.extend({tagName:"div",template:t.template("wpo-modal"),preinitialize:function(){this.events=_.extend(this.events||{},{"click .wpo-modal--close":"close"}),this.className=this.className?"wpo-modal--container "+this.className:"wpo-modal--container "},render:function(){this.$el.append(this.template()),this.trigger("rendered")},initialize:function(){this.trigger("initialize"),this.render(),this.$content=this.$el.find(".wpo-modal--content"),"function"==typeof this.content&&this.$content.append(this.content())},close:function(){e("body").removeClass("wpo-modal-is-opened"),this.remove()}}),i.open=function(t){var o=_.extend(t||{},{}),n=i.views.modal.extend(o),s=new n;return s.$el.appendTo("body"),s.$(".wpo-modal").focus(),e("body").addClass("wpo-modal-is-opened"),s},wp_optimize.modal=i}(jQuery,window.wp);

View File

@@ -0,0 +1,69 @@
/*
How to use the modal
wp_optimize.modal.open({
className: 'a-class', // A class name, added to the main modal container
events: {}, // An object containing the events added to the modal. See Backbonejs View events syntax.
content: function() {
return ''; // the Content method returns html or jQuery objects which will be added to the content area of the modal
},
... // Other methods used by the custom events
})
*/
var wp_optimize = window.wp_optimize || {};
(function($, wp) {
'use strict';
var modal = {};
modal.views = {};
/**
* Main modal View
*/
modal.views.modal = Backbone.View.extend({
tagName: 'div',
template: wp.template('wpo-modal'),
/**
* Extend default values
*/
preinitialize: function() {
this.events = _.extend(this.events || {}, {
'click .wpo-modal--close': 'close'
});
this.className = this.className ? 'wpo-modal--container ' + this.className : 'wpo-modal--container ';
},
render: function() {
this.$el.append(this.template());
this.trigger('rendered');
},
initialize: function() {
this.trigger('initialize');
this.render();
this.$content = this.$el.find('.wpo-modal--content');
// Append the content area with the content provided by the child object
if ('function' === typeof this.content) {
this.$content.append(this.content());
}
},
close: function() {
$('body').removeClass('wpo-modal-is-opened');
this.remove();
}
});
/**
* Public method to create and open the modal
*/
modal.open = function(options) {
var view_options = _.extend(options || {}, {});
var modalView = modal.views.modal.extend(view_options);
var m = new modalView();
m.$el.appendTo('body');
m.$('.wpo-modal').focus();
$('body').addClass('wpo-modal-is-opened');
return m;
}
wp_optimize.modal = modal;
})(jQuery, window.wp);

View File

@@ -0,0 +1 @@
function Updraft_Queue(){var t=[],n=0,e=!1;this.get_length=function(){return t.length-n},this.is_empty=function(){return 0==t.length},this.enqueue=function(n){t.push(n)},this.is_locked=function(){return e},this.get_lock=function(){return!e&&(this.lock(),!0)},this.dequeue=function(){if(0!=t.length){var e=t[n];return 2*++n>=t.length&&(t=t.slice(n),n=0),e}},this.lock=function(){e=!0},this.unlock=function(){e=!1},this.peek=function(){return t.length>0?t[n]:void 0},this.replace_front=function(e){return!(t.length<1)&&(t[n]=e,!0)}}

View File

@@ -0,0 +1,142 @@
/**
Adapted and extended from the work of Stephen Morley - http://code.stephenmorley.org/javascript/queues/
Queue.js
A function to represent a queue
Created by Stephen Morley - http://code.stephenmorley.org/ - and released under
the terms of the CC0 1.0 Universal legal code:
http://creativecommons.org/publicdomain/zero/1.0/legalcode
*/
/**
* Creates a new queue. A queue is a first-in-first-out (FIFO) data structure -
* items are added to the end of the queue and removed from the front.
*
* @return {void}
*/
function Updraft_Queue() {
// Initialise the queue and offset.
var queue = [];
var offset = 0;
var locked = false;
/**
* Returns the length of the queue.
*
* @returns {number} - the length of the queue
*/
this.get_length = function () {
return (queue.length - offset);
}
/**
* Query whether the queue is empty or not
*
* @returns {boolean} - returns true if the queue is empty, and false otherwise.
*/
this.is_empty = function () {
return (queue.length == 0);
}
/**
* Enqueues the specified item. The parameter is:
*
* @param {*} item The item to enqueue
*
* @return {void}
*/
this.enqueue = function (item) {
queue.push(item);
}
/**
* Returns the queue lock status
*
* @returns {boolean} - whether the queue is locked or not
*/
this.is_locked = function () {
return locked;
}
/**
* Attempt to get the queue lock
*
* @returns {boolean} - whether the attempt succeeded or not
*/
this.get_lock = function () {
if (locked) { return false; }
this.lock();
return true;
}
/**
* Dequeues an item and returns it. If the queue is empty, the value
* 'undefined' is returned.
*
* @returns {*} - returns and removes the item at the front of the queue, or undefined if the queue is empty
*/
this.dequeue = function () {
// If the queue is empty, return immediately.
if (queue.length == 0) return undefined;
// Store the item at the front of the queue.
var item = queue[offset];
// Increment the offset and remove the free space if necessary.
if ((++offset * 2) >= queue.length) {
queue = queue.slice(offset);
offset = 0;
}
// Return the dequeued item.
return item;
}
/**
* Lock the queue
*
* @returns {void}
*/
this.lock = function () {
locked = true;
}
/**
* Unlock the queue
*
* @returns {void}
*/
this.unlock = function () {
locked = false;
}
/**
* Returns the item at the front of the queue (without dequeuing it). If the
* queue is empty then undefined is returned.
*
* @returns {*} - returns the item at the front of the queue, or undefined if the queue is empty
*/
this.peek = function () {
return (queue.length > 0 ? queue[offset] : undefined);
}
/**
* Replaces the item at the front of the queue (if any)
*
* @param {*} item The item to put at the front of the queue.
*
* @return {boolean} Whether or not the item was successfully replaced.
*/
this.replace_front = function (item) {
if (queue.length < 1) { return false; }
queue[offset] = item;
return true;
}
}

View File

@@ -0,0 +1 @@
var wp_optimize=window.wp_optimize||{};wp_optimize.send_command=function(e,o,i,t,r){t="undefined"==typeof t||t,o||(o={}),o.hasOwnProperty("include_ui_elements")||(o.include_ui_elements=!0);var n={action:"wp_optimize_ajax",subaction:e,nonce:wp_optimize_send_command_data.nonce,data:o},s={type:"post",data:n,success:function(e){if(t){try{var o=wpo_parse_json(e)}catch(r){return console.log(r),console.log(e),void alert(wpoptimize.error_unexpected_response)}if(!o.result&&o.hasOwnProperty("error_code")&&o.error_code)return void wp_optimize.notices.show_notice(o.error_code,o.error_message);"function"==typeof i&&i(o)}else{if(!e.result&&e.hasOwnProperty("error_code")&&e.error_code)return void wp_optimize.notices.show_notice(e.error_code,e.error_message);"function"==typeof i&&i(e)}}};return"object"==typeof r&&(r.hasOwnProperty("timeout")&&(s.timeout=r.timeout),r.hasOwnProperty("error")&&"function"==typeof r.error&&(s.error=r.error)),jQuery.ajax(ajaxurl,s)},wp_optimize.notices={errors:[],show_notice:function(e,o){jQuery("#wp-optimize-wrap").length?(this.notice||this.add_notice(),this.notice.show(),this.errors[e]||(this.errors[e]=jQuery("<p/>").html(o).appendTo(this.notice).data("error_code",e))):window.wp&&wp.hasOwnProperty("data")?wp.data.dispatch("core/notices").createNotice("error","WP-Optimize: "+o,{isDismissible:!0}):alert("WP-Optimize: "+o)},add_notice:function(){this.notice_container=jQuery('<div class="wpo-main-error-notice"></div>').prependTo("#wp-optimize-wrap"),this.notice=jQuery('<div class="notice notice-error wpo-notice is-dismissible"><button type="button" class="notice-dismiss"><span class="screen-reader-text">'+commonL10n.dismiss+"</span></button></div>"),this.notice.appendTo(this.notice_container),this.notice.on("click",".notice-dismiss",function(e){this.notice.hide().find("p").remove(),this.errors=[]}.bind(this))}};

View File

@@ -0,0 +1,106 @@
var wp_optimize = window.wp_optimize || {};
/**
* Send an action via admin-ajax.php.
*
* @param {string} action The action to send
* @param {[type]} data Data to send
* @param {Function} callback Will be called with the results
* @param {boolean} json_parse JSON parse the results
* @param {object} options Optional extra options; current properties supported are 'timeout' (in milliseconds)
*
* @return {JSON}
*/
wp_optimize.send_command = function (action, data, callback, json_parse, options) {
json_parse = ('undefined' === typeof json_parse) ? true : json_parse;
if (!data) data = {};
// If the command doesn't have the property, default to true
if (!data.hasOwnProperty('include_ui_elements')) {
data.include_ui_elements = true;
}
var ajax_data = {
action: 'wp_optimize_ajax',
subaction: action,
nonce: wp_optimize_send_command_data.nonce,
data: data
};
var args = {
type: 'post',
data: ajax_data,
success: function (response) {
if (json_parse) {
try {
var resp = wpo_parse_json(response);
} catch (e) {
console.log(e);
console.log(response);
alert(wpoptimize.error_unexpected_response);
return;
}
// If result == false and and error code is provided, show the error and return.
if (!resp.result && resp.hasOwnProperty('error_code') && resp.error_code) {
wp_optimize.notices.show_notice(resp.error_code, resp.error_message);
return;
}
if ('function' === typeof callback) callback(resp);
} else {
if (!response.result && response.hasOwnProperty('error_code') && response.error_code) {
wp_optimize.notices.show_notice(response.error_code, response.error_message);
return;
}
if ('function' === typeof callback) callback(response);
}
}
};
// Eventually merge options
if ('object' === typeof options) {
if (options.hasOwnProperty('timeout')) { args.timeout = options.timeout; }
if (options.hasOwnProperty('error') && 'function' === typeof options.error) { args.error = options.error; }
}
return jQuery.ajax(ajaxurl, args);
};
/**
* JS notices
*/
wp_optimize.notices = {
errors: [],
show_notice: function(error_code, error_message) {
// WPO main page
if (jQuery('#wp-optimize-wrap').length) {
if (!this.notice) this.add_notice();
this.notice.show();
if (!this.errors[error_code]) {
this.errors[error_code] = jQuery('<p/>').html(error_message).appendTo(this.notice).data('error_code', error_code);
}
// Post edit page
} else if (window.wp && wp.hasOwnProperty('data')) {
wp.data.dispatch('core/notices').createNotice(
'error',
'WP-Optimize: ' + error_message,
{
isDismissible: true
}
);
// Other locations
} else {
alert('WP-Optimize: ' + error_message);
}
},
add_notice: function() {
this.notice_container = jQuery('<div class="wpo-main-error-notice"></div>').prependTo('#wp-optimize-wrap');
this.notice = jQuery('<div class="notice notice-error wpo-notice is-dismissible"><button type="button" class="notice-dismiss"><span class="screen-reader-text">'+commonL10n.dismiss+'</span></button></div>');
this.notice.appendTo(this.notice_container);
this.notice.on('click', '.notice-dismiss', function(e) {
this.notice.hide().find('p').remove();
this.errors = [];
}.bind(this));
}
};

View File

@@ -0,0 +1,344 @@
/*!
SerializeJSON jQuery plugin.
https://github.com/marioizquierdo/jquery.serializeJSON
version 2.9.0 (Jan, 2018)
Copyright (c) 2012-2018 Mario Izquierdo
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*/
(function (factory) {
if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') { // Node/CommonJS
var jQuery = require('jquery');
module.exports = factory(jQuery);
} else { // Browser globals (zepto supported)
factory(window.jQuery || window.Zepto || window.$); // Zepto supported on browsers as well
}
}(function ($) {
"use strict";
// jQuery('form').serializeJSON()
$.fn.serializeJSON = function (options) {
var f, $form, opts, formAsArray, serializedObject, name, value, parsedValue, _obj, nameWithNoType, type, keys, skipFalsy;
f = $.serializeJSON;
$form = this; // NOTE: the set of matched elements is most likely a form, but it could also be a group of inputs
opts = f.setupOpts(options); // calculate values for options {parseNumbers, parseBoolens, parseNulls, ...} with defaults
// Use native `serializeArray` function to get an array of {name, value} objects.
formAsArray = $form.serializeArray();
f.readCheckboxUncheckedValues(formAsArray, opts, $form); // add objects to the array from unchecked checkboxes if needed
// Convert the formAsArray into a serializedObject with nested keys
serializedObject = {};
$.each(formAsArray, function (i, obj) {
name = obj.name; // original input name
value = obj.value; // input value
_obj = f.extractTypeAndNameWithNoType(name);
nameWithNoType = _obj.nameWithNoType; // input name with no type (i.e. "foo:string" => "foo")
type = _obj.type; // type defined from the input name in :type colon notation
if (!type) type = f.attrFromInputWithName($form, name, 'data-value-type');
f.validateType(name, type, opts); // make sure that the type is one of the valid types if defined
if (type !== 'skip') { // ignore inputs with type 'skip'
keys = f.splitInputNameIntoKeysArray(nameWithNoType);
parsedValue = f.parseValue(value, name, type, opts); // convert to string, number, boolean, null or customType
skipFalsy = !parsedValue && f.shouldSkipFalsy($form, name, nameWithNoType, type, opts); // ignore falsy inputs if specified
if (!skipFalsy) {
f.deepSet(serializedObject, keys, parsedValue, opts);
}
}
});
return serializedObject;
};
// Use $.serializeJSON as namespace for the auxiliar functions
// and to define defaults
$.serializeJSON = {
defaultOptions: {
checkboxUncheckedValue: undefined, // to include that value for unchecked checkboxes (instead of ignoring them)
parseNumbers: false, // convert values like "1", "-2.33" to 1, -2.33
parseBooleans: false, // convert "true", "false" to true, false
parseNulls: false, // convert "null" to null
parseAll: false, // all of the above
parseWithFunction: null, // to use custom parser, a function like: function(val){ return parsed_val; }
skipFalsyValuesForTypes: [], // skip serialization of falsy values for listed value types
skipFalsyValuesForFields: [], // skip serialization of falsy values for listed field names
customTypes: {}, // override defaultTypes
defaultTypes: {
"string": function(str) { return String(str); },
"number": function(str) { return Number(str); },
"boolean": function(str) { var falses = ["false", "null", "undefined", "", "0"]; return falses.indexOf(str) === -1; },
"null": function(str) { var falses = ["false", "null", "undefined", "", "0"]; return falses.indexOf(str) === -1 ? str : null; },
"array": function(str) { return JSON.parse(str); },
"object": function(str) { return JSON.parse(str); },
"auto": function(str) { return $.serializeJSON.parseValue(str, null, null, {parseNumbers: true, parseBooleans: true, parseNulls: true}); }, // try again with something like "parseAll"
"skip": null // skip is a special type that makes it easy to ignore elements
},
useIntKeysAsArrayIndex: false // name="foo[2]" value="v" => {foo: [null, null, "v"]}, instead of {foo: ["2": "v"]}
},
// Merge option defaults into the options
setupOpts: function(options) {
var opt, validOpts, defaultOptions, optWithDefault, parseAll, f;
f = $.serializeJSON;
if (options == null) { options = {}; } // options ||= {}
defaultOptions = f.defaultOptions || {}; // defaultOptions
// Make sure that the user didn't misspell an option
validOpts = ['checkboxUncheckedValue', 'parseNumbers', 'parseBooleans', 'parseNulls', 'parseAll', 'parseWithFunction', 'skipFalsyValuesForTypes', 'skipFalsyValuesForFields', 'customTypes', 'defaultTypes', 'useIntKeysAsArrayIndex']; // re-define because the user may override the defaultOptions
for (opt in options) {
if (validOpts.indexOf(opt) === -1) {
throw new Error("serializeJSON ERROR: invalid option '" + opt + "'. Please use one of " + validOpts.join(', '));
}
}
// Helper to get the default value for this option if none is specified by the user
optWithDefault = function(key) { return (options[key] !== false) && (options[key] !== '') && (options[key] || defaultOptions[key]); };
// Return computed options (opts to be used in the rest of the script)
parseAll = optWithDefault('parseAll');
return {
checkboxUncheckedValue: optWithDefault('checkboxUncheckedValue'),
parseNumbers: parseAll || optWithDefault('parseNumbers'),
parseBooleans: parseAll || optWithDefault('parseBooleans'),
parseNulls: parseAll || optWithDefault('parseNulls'),
parseWithFunction: optWithDefault('parseWithFunction'),
skipFalsyValuesForTypes: optWithDefault('skipFalsyValuesForTypes'),
skipFalsyValuesForFields: optWithDefault('skipFalsyValuesForFields'),
typeFunctions: $.extend({}, optWithDefault('defaultTypes'), optWithDefault('customTypes')),
useIntKeysAsArrayIndex: optWithDefault('useIntKeysAsArrayIndex')
};
},
// Given a string, apply the type or the relevant "parse" options, to return the parsed value
parseValue: function(valStr, inputName, type, opts) {
var f, parsedVal;
f = $.serializeJSON;
parsedVal = valStr; // if no parsing is needed, the returned value will be the same
if (opts.typeFunctions && type && opts.typeFunctions[type]) { // use a type if available
parsedVal = opts.typeFunctions[type](valStr);
} else if (opts.parseNumbers && f.isNumeric(valStr)) { // auto: number
parsedVal = Number(valStr);
} else if (opts.parseBooleans && (valStr === "true" || valStr === "false")) { // auto: boolean
parsedVal = (valStr === "true");
} else if (opts.parseNulls && valStr == "null") { // auto: null
parsedVal = null;
} else if (opts.typeFunctions && opts.typeFunctions["string"]) { // make sure to apply :string type if it was re-defined
parsedVal = opts.typeFunctions["string"](valStr);
}
// Custom parse function: apply after parsing options, unless there's an explicit type.
if (opts.parseWithFunction && !type) {
parsedVal = opts.parseWithFunction(parsedVal, inputName);
}
return parsedVal;
},
isObject: function(obj) { return obj === Object(obj); }, // is it an Object?
isUndefined: function(obj) { return obj === void 0; }, // safe check for undefined values
isValidArrayIndex: function(val) { return /^[0-9]+$/.test(String(val)); }, // 1,2,3,4 ... are valid array indexes
isNumeric: function(obj) { return obj - parseFloat(obj) >= 0; }, // taken from jQuery.isNumeric implementation. Not using jQuery.isNumeric to support old jQuery and Zepto versions
optionKeys: function(obj) { if (Object.keys) { return Object.keys(obj); } else { var key, keys = []; for(key in obj){ keys.push(key); } return keys;} }, // polyfill Object.keys to get option keys in IE<9
// Fill the formAsArray object with values for the unchecked checkbox inputs,
// using the same format as the jquery.serializeArray function.
// The value of the unchecked values is determined from the opts.checkboxUncheckedValue
// and/or the data-unchecked-value attribute of the inputs.
readCheckboxUncheckedValues: function (formAsArray, opts, $form) {
var selector, $uncheckedCheckboxes, $el, uncheckedValue, f, name;
if (opts == null) { opts = {}; }
f = $.serializeJSON;
selector = 'input[type=checkbox][name]:not(:checked):not([disabled])';
$uncheckedCheckboxes = $form.find(selector).add($form.filter(selector));
$uncheckedCheckboxes.each(function (i, el) {
// Check data attr first, then the option
$el = $(el);
uncheckedValue = $el.attr('data-unchecked-value');
if (uncheckedValue == null) {
uncheckedValue = opts.checkboxUncheckedValue;
}
// If there's an uncheckedValue, push it into the serialized formAsArray
if (uncheckedValue != null) {
if (el.name && el.name.indexOf("[][") !== -1) { // identify a non-supported
throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+el.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");
}
formAsArray.push({name: el.name, value: uncheckedValue});
}
});
},
// Returns and object with properties {name_without_type, type} from a given name.
// The type is null if none specified. Example:
// "foo" => {nameWithNoType: "foo", type: null}
// "foo:boolean" => {nameWithNoType: "foo", type: "boolean"}
// "foo[bar]:null" => {nameWithNoType: "foo[bar]", type: "null"}
extractTypeAndNameWithNoType: function(name) {
var match;
if (match = name.match(/(.*):([^:]+)$/)) {
return {nameWithNoType: match[1], type: match[2]};
} else {
return {nameWithNoType: name, type: null};
}
},
// Check if this input should be skipped when it has a falsy value,
// depending on the options to skip values by name or type, and the data-skip-falsy attribute.
shouldSkipFalsy: function($form, name, nameWithNoType, type, opts) {
var f = $.serializeJSON;
var skipFromDataAttr = f.attrFromInputWithName($form, name, 'data-skip-falsy');
if (skipFromDataAttr != null) {
return skipFromDataAttr !== 'false'; // any value is true, except if explicitly using 'false'
}
var optForFields = opts.skipFalsyValuesForFields;
if (optForFields && (optForFields.indexOf(nameWithNoType) !== -1 || optForFields.indexOf(name) !== -1)) {
return true;
}
var optForTypes = opts.skipFalsyValuesForTypes;
if (type == null) type = 'string'; // assume fields with no type are targeted as string
if (optForTypes && optForTypes.indexOf(type) !== -1) {
return true
}
return false;
},
// Finds the first input in $form with this name, and get the given attr from it.
// Returns undefined if no input or no attribute was found.
attrFromInputWithName: function($form, name, attrName) {
var escapedName, selector, $input, attrValue;
escapedName = name.replace(/(:|\.|\[|\]|\s)/g,'\\$1'); // every non-standard character need to be escaped by \\
selector = '[name="' + escapedName + '"]';
$input = $form.find(selector).add($form.filter(selector)); // NOTE: this returns only the first $input element if multiple are matched with the same name (i.e. an "array[]"). So, arrays with different element types specified through the data-value-type attr is not supported.
return $input.attr(attrName);
},
// Raise an error if the type is not recognized.
validateType: function(name, type, opts) {
var validTypes, f;
f = $.serializeJSON;
validTypes = f.optionKeys(opts ? opts.typeFunctions : f.defaultOptions.defaultTypes);
if (!type || validTypes.indexOf(type) !== -1) {
return true;
} else {
throw new Error("serializeJSON ERROR: Invalid type " + type + " found in input name '" + name + "', please use one of " + validTypes.join(', '));
}
},
// Split the input name in programatically readable keys.
// Examples:
// "foo" => ['foo']
// "[foo]" => ['foo']
// "foo[inn][bar]" => ['foo', 'inn', 'bar']
// "foo[inn[bar]]" => ['foo', 'inn', 'bar']
// "foo[inn][arr][0]" => ['foo', 'inn', 'arr', '0']
// "arr[][val]" => ['arr', '', 'val']
splitInputNameIntoKeysArray: function(nameWithNoType) {
var keys, f;
f = $.serializeJSON;
keys = nameWithNoType.split('['); // split string into array
keys = $.map(keys, function (key) { return key.replace(/\]/g, ''); }); // remove closing brackets
if (keys[0] === '') { keys.shift(); } // ensure no opening bracket ("[foo][inn]" should be same as "foo[inn]")
return keys;
},
// Set a value in an object or array, using multiple keys to set in a nested object or array:
//
// deepSet(obj, ['foo'], v) // obj['foo'] = v
// deepSet(obj, ['foo', 'inn'], v) // obj['foo']['inn'] = v // Create the inner obj['foo'] object, if needed
// deepSet(obj, ['foo', 'inn', '123'], v) // obj['foo']['arr']['123'] = v //
//
// deepSet(obj, ['0'], v) // obj['0'] = v
// deepSet(arr, ['0'], v, {useIntKeysAsArrayIndex: true}) // arr[0] = v
// deepSet(arr, [''], v) // arr.push(v)
// deepSet(obj, ['arr', ''], v) // obj['arr'].push(v)
//
// arr = [];
// deepSet(arr, ['', v] // arr => [v]
// deepSet(arr, ['', 'foo'], v) // arr => [v, {foo: v}]
// deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}]
// deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}, {bar: v}]
//
deepSet: function (o, keys, value, opts) {
var key, nextKey, tail, lastIdx, lastVal, f;
if (opts == null) { opts = {}; }
f = $.serializeJSON;
if (f.isUndefined(o)) { throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined"); }
if (!keys || keys.length === 0) { throw new Error("ArgumentError: param 'keys' expected to be an array with least one element"); }
key = keys[0];
// Only one key, then it's not a deepSet, just assign the value.
if (keys.length === 1) {
if (key === '') {
o.push(value); // '' is used to push values into the array (assume o is an array)
} else {
o[key] = value; // other keys can be used as object keys or array indexes
}
// With more keys is a deepSet. Apply recursively.
} else {
nextKey = keys[1];
// '' is used to push values into the array,
// with nextKey, set the value into the same object, in object[nextKey].
// Covers the case of ['', 'foo'] and ['', 'var'] to push the object {foo, var}, and the case of nested arrays.
if (key === '') {
lastIdx = o.length - 1; // asume o is array
lastVal = o[lastIdx];
if (f.isObject(lastVal) && (f.isUndefined(lastVal[nextKey]) || keys.length > 2)) { // if nextKey is not present in the last object element, or there are more keys to deep set
key = lastIdx; // then set the new value in the same object element
} else {
key = lastIdx + 1; // otherwise, point to set the next index in the array
}
}
// '' is used to push values into the array "array[]"
if (nextKey === '') {
if (f.isUndefined(o[key]) || !$.isArray(o[key])) {
o[key] = []; // define (or override) as array to push values
}
} else {
if (opts.useIntKeysAsArrayIndex && f.isValidArrayIndex(nextKey)) { // if 1, 2, 3 ... then use an array, where nextKey is the index
if (f.isUndefined(o[key]) || !$.isArray(o[key])) {
o[key] = []; // define (or override) as array, to insert values using int keys as array indexes
}
} else { // for anything else, use an object, where nextKey is going to be the attribute name
if (f.isUndefined(o[key]) || !f.isObject(o[key])) {
o[key] = {}; // define (or override) as object, to set nested properties
}
}
}
// Recursively set the inner object
tail = keys.slice(1);
f.deepSet(o[key], tail, value, opts);
}
}
};
}));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,540 @@
WP_Optimize_Images_View = function(settings) {
var $ = jQuery,
defaults = {
container: '',
image_container_class: 'wpo_unused_image',
image_container_custom_classes: 'wpo_unused_image_row',
image_container_blog_class_prefix: 'wpo_unused_image_site_',
view_image_btn_link_class: 'wpo_unused_image_view_link',
view_image_btn_text: wpoptimize.view_image_link_text,
row_selector: '.wpo_unused_image_row',
row_id_class: 'wpo_unused_images_row_id',
row_thumb_class: 'wpo_unused_images_row_thumb',
row_file_class: 'wpo_unused_images_row_file',
row_action_class: 'wpo_unused_images_row_action',
/**
* Array with buttons shown in the list view mode.
*
* [
* {
* 'class': 'button_class',
* 'title': 'Button title',
* 'hint': 'Tooltip text'
* },
* ...
* ]
*/
row_action_buttons: [],
label_class: 'wpo_unused_image_thumb_label',
loader_additional_html: '',
action_btn_text: 'Remove',
action_btn_class: 'button button-primary wpo_unused_images_remove_single',
checkbox_class: 'wpo_unused_image__input',
list_mode_class: 'wpo_unused_image_list_view',
no_images_found_message: 'No images found',
related_elements: [],
action_buttons: [],
hide_when_empty: [],
load_next_page_callback: null,
onclear: null
},
options = jQuery.extend({}, defaults, settings),
IMAGES_VIEW_MODE = {
GRID: 'grid',
LIST: 'list'
},
images_view_mode = IMAGES_VIEW_MODE.GRID,
images_view_container = options.container,
image_container_selector = '.' + options.image_container_class,
checkbox_selector = '.' + options.checkbox_class,
last_clicked_image_id = '',
images_loaded_count = {};
/**
* Handle scroll in the images container.
*/
images_view_container.on('scroll mousewheel', function() {
load_next_page_if_need();
update_loader_position();
});
/**
* Handle Shift key state.
*/
var ctrl_shift_on_image_held = false;
images_view_container.on('mousedown', options.row_selector, function (e) {
ctrl_shift_on_image_held = e.shiftKey || e.ctrlKey;
});
images_view_container.on('mouseup', options.row_selector, function (e) {
ctrl_shift_on_image_held = e.shiftKey || e.ctrlKey;
});
/**
* Handle checked status changed for single unused image.
*/
images_view_container.on('click' , '.'+options.image_container_class , function(e) {
var check_box = $(this).find('.'+options.checkbox_class);
var image_id = check_box.attr('id');
// Toggle class on image container
if (true === check_box.prop('checked')) {
$(this).addClass('selected');
} else {
$(this).removeClass('selected');
}
if (ctrl_shift_on_image_held) {
if (true === check_box.prop('checked')) {
$(this).removeClass('selected');
check_box.prop('checked',false);
} else {
$(this).addClass('selected');
check_box.prop('checked',true);
}
if (1 <= get_selected_images().length) {
if (true === $("#"+last_clicked_image_id).prop('checked')) {
select_images(last_clicked_image_id, image_id, true === check_box.prop('checked'));
}
}
}
last_clicked_image_id = image_id;
disable_action_buttons(0 == get_selected_images().length);
});
/**
* Select or deselect images from #first_id to #last_id in the lis of unused images
*
* @param {string} first_id - first image id in the list
* @param {string} last_id - last image id in the list
* @param {bool} checked - select or deselect images
*
* @return void
*/
function select_images(first_id, last_id, checked) {
var image_id = first_id,
index1,
index2,
current,
first,
last,
done = false;
// if set first and last ids then go through the list.
if (last_id && first_id) {
// get positions in then list.
index1 = $(checkbox_selector).index($('#' + first_id));
index2 = $(checkbox_selector).index($('#' + last_id));
// check if both item exists. (posibly one of them was deleted)
if (-1 == index1) index1 = index2;
if (-1 == index2) index2 = index1;
// get correct first and last item.
if (index1 < index2) {
current = $(checkbox_selector).eq(index1).closest(image_container_selector);
last_id = $(checkbox_selector).eq(index2).attr('id');
} else {
current = $(checkbox_selector).eq(index2).closest(image_container_selector);
last_id = $(checkbox_selector).eq(index1).attr('id');
}
// select images.
while (!done) {
if (checked) {
current.addClass('selected');
$(checkbox_selector, current).prop('checked', checked);
} else {
current.removeClass('selected');
$(checkbox_selector, current).prop('checked', checked);
}
if ($(checkbox_selector, current).attr('id') == last_id) done = true;
current = current.next();
}
} else {
// if just one the first id passed then change just the first element state.
if (checked) {
$('#' + image_id).closest(image_container_selector).addClass('selected');
} else {
$('#' + image_id).closest(image_container_selector).removeClass('selected');
}
}
disable_action_buttons(0 == get_selected_images().length);
}
/**
* Disable/enable controls.
*
* @param {boolean} disabled
*/
function disable_action_buttons(disabled) {
if (!options.action_buttons) return;
$.each(options.action_buttons, function(i, el) {
el.prop('disabled', disabled)
});
}
/**
* Update view in case when then images list is empty.
*/
function hide_when_empty_elements() {
if (options.hide_when_empty) {
var images_count = $(['.', options.image_container_class,':visible'].join(''), images_view_container).length;
if (0 === images_count) {
// show message - no images found.
if (0 == $('.wpo-images-view-empty', images_view_container).length) {
images_view_container.append($('<div class="wpo-images-view-empty wpo-fieldgroup" />').text(options.no_images_found_message));
}
$('.wpo-images-view-empty', images_view_container).show();
} else {
$('.wpo-images-view-empty', images_view_container).hide();
}
$.each(options.hide_when_empty, function(i, el) {
if (images_count > 0) {
el.show();
} else {
el.hide();
}
});
}
}
/**
* Update view when images are changed.
*/
function update_view() {
if (!is_visible()) return;
hide_when_empty_elements();
disable_action_buttons(0 == get_selected_images().length);
}
/**
* Load the next part images if images container scrolled to the bottom.
*/
function load_next_page_if_need() {
if (images_view_container.scrollTop() + images_view_container.height() + 100 > images_view_container[0].scrollHeight) {
if ('function' == typeof options.load_next_page_callback) {
options.load_next_page_callback();
}
}
}
/**
* Append an image to the list.
*
* @param {int} blog_id image blog id
* @param {string} value value that will returned if image selected
* @param {string} href url opened when image clicked
* @param {string} thumbnail_url url to the image thumbnail
* @param {string} title image title
* @param {string} row_file_text text for displaying near image in the list view mode
*/
function append_image(blog_id, value, href, thumbnail_url, title, row_file_text) {
var random_id = 'image_' + (((1+Math.random())*0x10000)|0).toString(16).substring(1),
row_actions_html = '',
i;
// build button
if (options.row_action_buttons) {
for (i in options.row_action_buttons) {
if (!options.row_action_buttons.hasOwnProperty(i)) continue;
row_actions_html += [
'<button href="javascript: ;" class="',(options.row_action_buttons[i].class ? options.row_action_buttons[i].class : ''),'"',
' title="',(options.row_action_buttons[i].hint ? options.row_action_buttons[i].hint : ''),'">',(options.row_action_buttons[i].title ? options.row_action_buttons[i].title : ''),'</button>'
].join('');
}
}
// count added image.
if (!images_loaded_count.hasOwnProperty(blog_id)) images_loaded_count[blog_id] = 0;
images_loaded_count[blog_id]++;
images_view_container.append(['\
<div class="',options.image_container_class,' ',options.image_container_custom_classes,' ',options.image_container_blog_class_prefix,blog_id,'">\
<a class="button ',options.view_image_btn_link_class,'" href="',href,'" target="_blank">',
options.view_image_btn_text,
'</a>',
'<div class="',options.row_id_class,'">\
<input id="',random_id,'" type="checkbox" class="',options.checkbox_class,'" value="',value,'">\
</div>\
<div class="',options.row_thumb_class,'">\
<a href="',href,'" target="_blank">\
<img class="lazyload" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="',thumbnail_url,'" title="',title,'" alt="',title,'">\
</a>\
</div>\
<div class="',options.row_file_class,'">\
<a href="',href,'" target="_blank">',row_file_text,'</a>\
</div>\
<div class="',options.row_action_class,'">',row_actions_html,'</div>\
<label for="',random_id,'" class="',options.label_class,'">\
<div class="thumbnail">\
<img class="lazyload" src="data:image/gif;base64,R0lGODdhAQABAPAAAMPDwwAAACwAAAAAAQABAAACAkQBADs=" data-src="',thumbnail_url,'" title="',title,'" alt="',title,'">\
</div>\
</label>\
</div>'
].join(''));
}
/**
* Show only images for the selected blog.
*
* @param {int} blog_id
*/
function filter_by_site(blog_id) {
$(image_container_selector, images_view_container).hide();
$(['.',options.image_container_blog_class_prefix, blog_id].join(''), images_view_container).show();
update_view();
}
/**
* Get count of loaded images for the selected blog.
*
* @param {int} blog_id
*
* @return {number}
*/
function get_images_count(blog_id) {
if (!images_loaded_count.hasOwnProperty(blog_id)) return 0;
return images_loaded_count[blog_id];
}
/**
* Get count of loaded images currently displayed in the view container.
*
* @param {int} blog_id
*/
function get_visible_images_count(blog_id) {
return $(['.',options.image_container_blog_class_prefix, blog_id].join(''), images_view_container).length;
}
/**
* Switch view mode grid/list.
*
* @param mode
*/
function switch_view_mode(mode) {
if (mode === images_view_mode) return;
images_view_mode = mode;
if (mode === IMAGES_VIEW_MODE.GRID) {
images_view_container.removeClass(options.list_mode_class);
}
if (mode === IMAGES_VIEW_MODE.LIST) {
images_view_container.addClass(options.list_mode_class);
}
}
/**
* Get list of selected images.
*
* @return {Array}
*/
function get_selected_images() {
var selected_images = [];
// if no any selected images then exit.
if (0 == $('input[type="checkbox"]', images_view_container).length) return selected_images;
// build list of visible selected images .
$(['.',options.image_container_class,':visible input:checked'].join(''), images_view_container).each(function() {
selected_images.push($(this).val());
});
return selected_images;
}
/**
* Remove selected images.
*/
function remove_selected_images() {
var image_container_selector = ['.',options.image_container_class].join('');
$([image_container_selector,':visible input:checked'].join(''), images_view_container).each(function() {
$(this).closest(image_container_selector).remove();
});
}
/**
* Show images container.
*/
function show() {
images_view_container.show();
$(options.related_elements).each(function() {
$(this).show();
});
update_view();
load_next_page_if_need();
}
/**
* Hide images container.
*/
function hide() {
images_view_container.hide();
$(options.related_elements).each(function() {
$(this).hide();
});
}
/**
* Check if images container element is visible.
*
* @return {boolean}
*/
function is_visible() {
return images_view_container.is(':visible');
}
/**
* Show loader.
*/
function show_loader() {
show_custom_loader(wpoptimize.loading_data, '', options.loader_additional_html);
}
/**
* Show loader with custom content.
*
* @param {string} title
* @param {string} message
* @param {string} custom_html
*/
function show_custom_loader(title, message, custom_html) {
message = message ? message : '';
custom_html = custom_html ? custom_html : '';
images_view_container.css({ 'min-height' : '220px' });
images_view_container.append([
'<div class="wpo_shade">',
'<div class="wpo_shade_inner">',
'<span class="dashicons dashicons-update-alt wpo-rotate"></span>',
'<h4>',title,'</h4>',
'<p class="wpo-shade-progress-message">',message,'</p>',
custom_html,
'</div>',
'</div>',
].join(''));
update_loader_position();
}
/**
* Hide loader.
*/
function hide_loader() {
images_view_container.css('min-height', 'initial');
$('.wpo_shade', images_view_container).remove();
}
/**
* Update top property for shade div with loader.
*/
function update_loader_position() {
$('.wpo_shade', images_view_container).css('top', images_view_container.scrollTop() + 'px');
}
/**
* Set message for under loader icon.
*
* @param {string} message
*/
function loader_message(message) {
$('.wpo-shade-progress-message', images_view_container).html(message);
}
/**
* Select all images.
*/
function select_all() {
$('.wpo_unused_image__input').each(function() {
if (!$(this).prop('checked')) {
$(this).closest('.wpo_unused_image').addClass('selected');
$(this).prop('checked', true);
last_clicked_image_id = null;
disable_action_buttons(0 == get_selected_images().length);
}
});
}
/**
* Deselect all images.
*/
function select_none() {
$('.wpo_unused_image__input').each(function() {
if ($(this).prop('checked')) {
$(this).closest('.wpo_unused_image').removeClass('selected');
$(this).prop('checked', false);
last_clicked_image_id = null;
disable_action_buttons(0 == get_selected_images().length);
}
});
}
/**
* Clear images container.
*/
function clear() {
$(['.', options.image_container_class].join(''), images_view_container).remove();
images_loaded_count = {};
disable_action_buttons(true);
// if defined on clear event then call it.
if ('function' === typeof options.onclear) {
options.onclear();
}
}
/**
* Reload view items.
*/
function reload() {
clear();
load_next_page_if_need();
}
return {
show: show,
hide: hide,
clear: clear,
reload: reload,
show_loader: show_loader,
show_custom_loader: show_custom_loader,
hide_loader: hide_loader,
loader_message: loader_message,
append_image: append_image,
get_selected_images: get_selected_images,
remove_selected_images: remove_selected_images,
get_images_count: get_images_count,
get_visible_images_count: get_visible_images_count,
load_next_page_if_need: load_next_page_if_need,
filter_by_site: filter_by_site,
switch_view_mode: switch_view_mode,
select_all: select_all,
select_none: select_none,
is_visible: is_visible,
update_view: update_view
}
};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff