first
This commit is contained in:
243
wp-content/plugins/shortpixel-image-optimiser/res/js/debug.js
Normal file
243
wp-content/plugins/shortpixel-image-optimiser/res/js/debug.js
Normal file
@ -0,0 +1,243 @@
|
||||
'use strict';
|
||||
// This file contains debug screen for edit-media
|
||||
|
||||
var debugModal;
|
||||
jQuery(document).ready(function(jq) {
|
||||
$ = jq;
|
||||
|
||||
debugModal = function() {
|
||||
|
||||
}
|
||||
|
||||
debugModal.prototype = {
|
||||
currentModal: null,
|
||||
modals: [],
|
||||
parent: '#wpbody', // modal will be written to this element.
|
||||
multiple: false,
|
||||
windowHeight: false,
|
||||
windowWidth: false,
|
||||
setWidth: false,
|
||||
setHeight: false,
|
||||
target: false,
|
||||
}
|
||||
|
||||
debugModal.prototype.init = function()
|
||||
{
|
||||
this.windowHeight = $(window).height();
|
||||
this.windowWidth = $(window).width();
|
||||
|
||||
$(document).off('click', '.debugModal');
|
||||
$(document).on('click', '.debugModal', $.proxy(this.buildModal, this));
|
||||
$(window).on('resize', $.proxy(this.checkResize, this));
|
||||
|
||||
}
|
||||
|
||||
|
||||
debugModal.prototype.get = function()
|
||||
{
|
||||
return this.currentModal;
|
||||
}
|
||||
|
||||
debugModal.prototype.show = function()
|
||||
{
|
||||
|
||||
$('.debugModal_overlay').remove();
|
||||
$('body').removeClass('debug-modal-active');
|
||||
this.writeOverlay();
|
||||
this.currentModal.show();
|
||||
|
||||
if (this.setWidth)
|
||||
{
|
||||
this.currentModal.width(this.setWidth);
|
||||
}
|
||||
if (this.setHeight)
|
||||
{
|
||||
this.currentModal.height(this.setHeight);
|
||||
}
|
||||
|
||||
var $m = this.currentModal;
|
||||
|
||||
var headerHeight = $m.find('.modal_header').outerHeight();
|
||||
|
||||
var contentHeight = $m.find('.modal_content').outerHeight();
|
||||
var contentWidth = $m.find('.modal_content').width();
|
||||
|
||||
var modalHeight = headerHeight + contentHeight; //this.currentModal.height();
|
||||
var modalWidth = contentWidth; //this.currentModal.width();
|
||||
var top = (this.windowHeight - modalHeight) / 2;
|
||||
var left = (this.windowWidth - modalWidth) / 2;
|
||||
|
||||
if (top < 30)
|
||||
{
|
||||
top = 30; // top + admin bar
|
||||
}
|
||||
if (left < 0)
|
||||
{
|
||||
left: 0;
|
||||
}
|
||||
|
||||
if (modalHeight > this.windowHeight) // if height is higher than screen supports
|
||||
{
|
||||
var newHeight = this.windowHeight - top - 5;
|
||||
this.currentModal.height(newHeight);
|
||||
|
||||
var newContentH = newHeight - headerHeight;
|
||||
$m.find('.modal_content').height(newContentH);
|
||||
|
||||
}
|
||||
this.currentModal.css('left', left + 'px');
|
||||
this.currentModal.css('top', top + 'px');
|
||||
this.currentModal.css('height', modalHeight);
|
||||
|
||||
|
||||
$('.debugModal_overlay').show();
|
||||
$('body').addClass('shortpixel-modal-active');
|
||||
|
||||
$(document).off('keydown', $.proxy(this.keyPressHandler, this));
|
||||
$(document).on('keydown', $.proxy(this.keyPressHandler, this));
|
||||
|
||||
this.currentModal.trigger('focus');
|
||||
}
|
||||
|
||||
debugModal.prototype.keyPressHandler = function (e)
|
||||
{
|
||||
if (e.keyCode === 27)
|
||||
this.close();
|
||||
}
|
||||
|
||||
debugModal.prototype.checkResize = function ()
|
||||
{
|
||||
this.windowHeight = $(window).height();
|
||||
this.windowWidth = $(window).width();
|
||||
|
||||
if (this.currentModal === null)
|
||||
return;
|
||||
|
||||
this.currentModal.removeAttr('style');
|
||||
this.currentModal.find('.modal_content').removeAttr('style');
|
||||
this.currentModal.removeAttr('style');
|
||||
|
||||
// redo sizes, repaint.
|
||||
|
||||
this.show();
|
||||
}
|
||||
|
||||
debugModal.prototype.close = function()
|
||||
{
|
||||
this.currentModal.trigger('modal_close', [this]);
|
||||
this.currentModal.remove();
|
||||
this.currentModal = null;
|
||||
$('.debugModal_overlay').remove();
|
||||
$('body').removeClass('shortpixel-modal-active');
|
||||
$(document).off('keydown', $.proxy(this.keyPressHandler, this));
|
||||
|
||||
}
|
||||
|
||||
debugModal.prototype.fadeOut = function (timeOut)
|
||||
{
|
||||
if (typeof timeOut == undefined)
|
||||
timeOut = 600;
|
||||
|
||||
var self = this;
|
||||
this.currentModal.fadeOut(timeOut, function() { self.close(); } );
|
||||
|
||||
}
|
||||
/* Set the modal content
|
||||
|
||||
Sets the content of the modal. Do not run this function after adding controls.
|
||||
@param string HTML,text content of the modal
|
||||
*/
|
||||
debugModal.prototype.setContent = function(content)
|
||||
{
|
||||
this.currentModal.find('.modal_content').html(content);
|
||||
}
|
||||
|
||||
/* Builds modal from hidden data
|
||||
|
||||
Builds modal from an formatted data object in DOM. Triggered on Click
|
||||
|
||||
*/
|
||||
debugModal.prototype.buildModal = function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
|
||||
var target = $(e.target);
|
||||
if (typeof target.data('modal') == 'undefined')
|
||||
target = target.parents('.debugModal');
|
||||
|
||||
this.target = target;
|
||||
var id = target.data('modal');
|
||||
var data = $('#' + id);
|
||||
|
||||
// options
|
||||
if (typeof data.data('width') !== 'undefined')
|
||||
this.setWidth = data.data('width');
|
||||
else
|
||||
this.setWidth = false;
|
||||
|
||||
if (typeof data.data('height') !== 'undefined')
|
||||
this.setHeight = data.data('height');
|
||||
else
|
||||
this.setHeight = false;
|
||||
|
||||
// var title = $(data).find('.title').text();
|
||||
// var controls = $(data).find('.controls').html();
|
||||
var content = $(data).find('.content').html();
|
||||
|
||||
this.newModal(id);
|
||||
this.setContent(content);
|
||||
|
||||
// callback on init
|
||||
if (typeof $(data).data('load') !== 'undefined')
|
||||
{
|
||||
|
||||
// default call
|
||||
var funcName = data.data('load') + '(modal)';
|
||||
var callFunc = new Function ('modal', funcName);
|
||||
|
||||
}
|
||||
|
||||
this.show();
|
||||
}
|
||||
|
||||
debugModal.prototype.newModal = function(id)
|
||||
{
|
||||
if (this.currentModal !== null)
|
||||
this.close();
|
||||
|
||||
var modal = $('<div class="debug-modal ' + id + '" > \
|
||||
<div class="modal_header"> \
|
||||
<div class="modal_close dashicons dashicons-no"></div><h3 class="modal_title">Debug</h3> \
|
||||
</div> \
|
||||
<div class="inner modal_content"></div>\
|
||||
</div>');
|
||||
if ($(this.parent).length > 0)
|
||||
$(this.parent).append(modal);
|
||||
else
|
||||
$('body').append(modal); // fallback in case of interrupting page builders
|
||||
|
||||
$(modal).draggable({
|
||||
handle: '.modal_header'
|
||||
});
|
||||
|
||||
this.modals.push(modal);
|
||||
this.currentModal = modal;
|
||||
|
||||
|
||||
document.querySelector('.debug-modal .modal_close').addEventListener('click', this.close.bind(this), { once: true} );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
debugModal.prototype.writeOverlay = function()
|
||||
{
|
||||
|
||||
$(this.parent).append('<div class="debugModal_overlay"></div>');
|
||||
$('.debugModal_overlay').on('click', $.proxy(this.close, this));
|
||||
|
||||
}
|
||||
|
||||
var shortpixelDebug = new debugModal();
|
||||
shortpixelDebug.init();
|
||||
}); // jquery
|
@ -0,0 +1,805 @@
|
||||
/*!jQuery Knob*/
|
||||
/**
|
||||
* Downward compatible, touchable dial
|
||||
*
|
||||
* Version: 1.2.12
|
||||
* Requires: jQuery v1.7+
|
||||
*
|
||||
* Copyright (c) 2012 Anthony Terrien
|
||||
* Under MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
*
|
||||
* Thanks to vor, eskimoblood, spiffistan, FabrizioC
|
||||
*/
|
||||
(function (factory) {
|
||||
if (typeof exports === 'object') {
|
||||
// CommonJS
|
||||
module.exports = factory(require('jquery'));
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
|
||||
/**
|
||||
* Kontrol library
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Definition of globals and core
|
||||
*/
|
||||
var k = {}, // kontrol
|
||||
max = Math.max,
|
||||
min = Math.min;
|
||||
|
||||
k.c = {};
|
||||
k.c.d = $(document);
|
||||
k.c.t = function (e) {
|
||||
return e.originalEvent.touches.length - 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Kontrol Object
|
||||
*
|
||||
* Definition of an abstract UI control
|
||||
*
|
||||
* Each concrete component must call this one.
|
||||
* <code>
|
||||
* k.o.call(this);
|
||||
* </code>
|
||||
*/
|
||||
k.o = function () {
|
||||
var s = this;
|
||||
|
||||
this.o = null; // array of options
|
||||
this.$ = null; // jQuery wrapped element
|
||||
this.i = null; // mixed HTMLInputElement or array of HTMLInputElement
|
||||
this.g = null; // deprecated 2D graphics context for 'pre-rendering'
|
||||
this.v = null; // value ; mixed array or integer
|
||||
this.cv = null; // change value ; not commited value
|
||||
this.x = 0; // canvas x position
|
||||
this.y = 0; // canvas y position
|
||||
this.w = 0; // canvas width
|
||||
this.h = 0; // canvas height
|
||||
this.$c = null; // jQuery canvas element
|
||||
this.c = null; // rendered canvas context
|
||||
this.t = 0; // touches index
|
||||
this.isInit = false;
|
||||
this.fgColor = null; // main color
|
||||
this.pColor = null; // previous color
|
||||
this.dH = null; // draw hook
|
||||
this.cH = null; // change hook
|
||||
this.eH = null; // cancel hook
|
||||
this.rH = null; // release hook
|
||||
this.scale = 1; // scale factor
|
||||
this.relative = false;
|
||||
this.relativeWidth = false;
|
||||
this.relativeHeight = false;
|
||||
this.$div = null; // component div
|
||||
|
||||
this.run = function () {
|
||||
var cf = function (e, conf) {
|
||||
var k;
|
||||
for (k in conf) {
|
||||
s.o[k] = conf[k];
|
||||
}
|
||||
s._carve().init();
|
||||
s._configure()
|
||||
._draw();
|
||||
};
|
||||
|
||||
if (this.$.data('kontroled')) return;
|
||||
this.$.data('kontroled', true);
|
||||
|
||||
this.extend();
|
||||
this.o = $.extend({
|
||||
// Config
|
||||
min: this.$.data('min') !== undefined ? this.$.data('min') : 0,
|
||||
max: this.$.data('max') !== undefined ? this.$.data('max') : 100,
|
||||
stopper: true,
|
||||
readOnly: this.$.data('readonly') || (this.$.attr('readonly') === 'readonly'),
|
||||
|
||||
// UI
|
||||
cursor: this.$.data('cursor') === true && 30
|
||||
|| this.$.data('cursor') || 0,
|
||||
thickness: this.$.data('thickness')
|
||||
&& Math.max(Math.min(this.$.data('thickness'), 1), 0.01)
|
||||
|| 0.35,
|
||||
lineCap: this.$.data('linecap') || 'butt',
|
||||
width: this.$.data('width') || 200,
|
||||
height: this.$.data('height') || 200,
|
||||
displayInput: this.$.data('displayinput') == null || this.$.data('displayinput'),
|
||||
displayPrevious: this.$.data('displayprevious'),
|
||||
fgColor: this.$.data('fgcolor') || '#87CEEB',
|
||||
inputColor: this.$.data('inputcolor'),
|
||||
font: this.$.data('font') || 'Arial',
|
||||
fontWeight: this.$.data('font-weight') || 'bold',
|
||||
inline: false,
|
||||
step: this.$.data('step') || 1,
|
||||
rotation: this.$.data('rotation'),
|
||||
|
||||
// Hooks
|
||||
draw: null, // function () {}
|
||||
change: null, // function (value) {}
|
||||
cancel: null, // function () {}
|
||||
release: null, // function (value) {}
|
||||
|
||||
// Output formatting, allows to add unit: %, ms ...
|
||||
format: function(v) {
|
||||
return v;
|
||||
},
|
||||
parse: function (v) {
|
||||
return parseFloat(v);
|
||||
}
|
||||
}, this.o
|
||||
);
|
||||
|
||||
// finalize options
|
||||
this.o.flip = this.o.rotation === 'anticlockwise' || this.o.rotation === 'acw';
|
||||
if (!this.o.inputColor) {
|
||||
this.o.inputColor = this.o.fgColor;
|
||||
}
|
||||
|
||||
// routing value
|
||||
if (this.$.is('fieldset')) {
|
||||
|
||||
// fieldset = array of integer
|
||||
this.v = {};
|
||||
this.i = this.$.find('input');
|
||||
this.i.each(function(k) {
|
||||
var $this = $(this);
|
||||
s.i[k] = $this;
|
||||
s.v[k] = s.o.parse($this.val());
|
||||
|
||||
$this.bind(
|
||||
'change blur',
|
||||
function () {
|
||||
var val = {};
|
||||
val[k] = $this.val();
|
||||
s.val(s._validate(val));
|
||||
}
|
||||
);
|
||||
});
|
||||
this.$.find('legend').remove();
|
||||
} else {
|
||||
|
||||
// input = integer
|
||||
this.i = this.$;
|
||||
this.v = this.o.parse(this.$.val());
|
||||
this.v === '' && (this.v = this.o.min);
|
||||
this.$.bind(
|
||||
'change blur',
|
||||
function () {
|
||||
s.val(s._validate(s.o.parse(s.$.val())));
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
!this.o.displayInput && this.$.hide();
|
||||
|
||||
// adds needed DOM elements (canvas, div)
|
||||
this.$c = $(document.createElement('canvas')).attr({
|
||||
width: this.o.width,
|
||||
height: this.o.height
|
||||
});
|
||||
|
||||
// wraps all elements in a div
|
||||
// add to DOM before Canvas init is triggered
|
||||
this.$div = $('<div style="'
|
||||
+ (this.o.inline ? 'display:inline;' : '')
|
||||
+ 'width:' + this.o.width + 'px;height:' + this.o.height + 'px;'
|
||||
+ '"></div>');
|
||||
|
||||
this.$.wrap(this.$div).before(this.$c);
|
||||
this.$div = this.$.parent();
|
||||
|
||||
if (typeof G_vmlCanvasManager !== 'undefined') {
|
||||
G_vmlCanvasManager.initElement(this.$c[0]);
|
||||
}
|
||||
|
||||
this.c = this.$c[0].getContext ? this.$c[0].getContext('2d') : null;
|
||||
|
||||
if (!this.c) {
|
||||
throw {
|
||||
name: "CanvasNotSupportedException",
|
||||
message: "Canvas not supported. Please use excanvas on IE8.0.",
|
||||
toString: function(){return this.name + ": " + this.message}
|
||||
}
|
||||
}
|
||||
|
||||
// hdpi support
|
||||
this.scale = (window.devicePixelRatio || 1) / (
|
||||
this.c.webkitBackingStorePixelRatio ||
|
||||
this.c.mozBackingStorePixelRatio ||
|
||||
this.c.msBackingStorePixelRatio ||
|
||||
this.c.oBackingStorePixelRatio ||
|
||||
this.c.backingStorePixelRatio || 1
|
||||
);
|
||||
|
||||
// detects relative width / height
|
||||
this.relativeWidth = this.o.width % 1 !== 0
|
||||
&& this.o.width.indexOf('%');
|
||||
this.relativeHeight = this.o.height % 1 !== 0
|
||||
&& this.o.height.indexOf('%');
|
||||
this.relative = this.relativeWidth || this.relativeHeight;
|
||||
|
||||
// computes size and carves the component
|
||||
this._carve();
|
||||
|
||||
// prepares props for transaction
|
||||
if (this.v instanceof Object) {
|
||||
this.cv = {};
|
||||
this.copy(this.v, this.cv);
|
||||
} else {
|
||||
this.cv = this.v;
|
||||
}
|
||||
|
||||
// binds configure event
|
||||
this.$
|
||||
.bind("configure", cf)
|
||||
.parent()
|
||||
.bind("configure", cf);
|
||||
|
||||
// finalize init
|
||||
this._listen()
|
||||
._configure()
|
||||
._xy()
|
||||
.init();
|
||||
|
||||
this.isInit = true;
|
||||
|
||||
this.$.val(this.o.format(this.v));
|
||||
this._draw();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this._carve = function() {
|
||||
if (this.relative) {
|
||||
var w = this.relativeWidth ?
|
||||
this.$div.parent().width() *
|
||||
parseInt(this.o.width) / 100
|
||||
: this.$div.parent().width(),
|
||||
h = this.relativeHeight ?
|
||||
this.$div.parent().height() *
|
||||
parseInt(this.o.height) / 100
|
||||
: this.$div.parent().height();
|
||||
|
||||
// apply relative
|
||||
this.w = this.h = Math.min(w, h);
|
||||
} else {
|
||||
this.w = this.o.width;
|
||||
this.h = this.o.height;
|
||||
}
|
||||
|
||||
// finalize div
|
||||
this.$div.css({
|
||||
'width': this.w + 'px',
|
||||
'height': this.h + 'px'
|
||||
});
|
||||
|
||||
// finalize canvas with computed width
|
||||
this.$c.attr({
|
||||
width: this.w,
|
||||
height: this.h
|
||||
});
|
||||
|
||||
// scaling
|
||||
if (this.scale !== 1) {
|
||||
this.$c[0].width = this.$c[0].width * this.scale;
|
||||
this.$c[0].height = this.$c[0].height * this.scale;
|
||||
this.$c.width(this.w);
|
||||
this.$c.height(this.h);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this._draw = function () {
|
||||
|
||||
// canvas pre-rendering
|
||||
var d = true;
|
||||
|
||||
s.g = s.c;
|
||||
|
||||
s.clear();
|
||||
|
||||
s.dH && (d = s.dH());
|
||||
|
||||
d !== false && s.draw();
|
||||
};
|
||||
|
||||
this._touch = function (e) {
|
||||
var touchMove = function (e) {
|
||||
var v = s.xy2val(
|
||||
e.originalEvent.touches[s.t].pageX,
|
||||
e.originalEvent.touches[s.t].pageY
|
||||
);
|
||||
|
||||
if (v == s.cv) return;
|
||||
|
||||
if (s.cH && s.cH(v) === false) return;
|
||||
|
||||
s.change(s._validate(v));
|
||||
s._draw();
|
||||
};
|
||||
|
||||
// get touches index
|
||||
this.t = k.c.t(e);
|
||||
|
||||
// First touch
|
||||
touchMove(e);
|
||||
|
||||
// Touch events listeners
|
||||
k.c.d
|
||||
.bind("touchmove.k", touchMove)
|
||||
.bind(
|
||||
"touchend.k",
|
||||
function () {
|
||||
k.c.d.unbind('touchmove.k touchend.k');
|
||||
s.val(s.cv);
|
||||
}
|
||||
);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this._mouse = function (e) {
|
||||
var mouseMove = function (e) {
|
||||
var v = s.xy2val(e.pageX, e.pageY);
|
||||
|
||||
if (v == s.cv) return;
|
||||
|
||||
if (s.cH && (s.cH(v) === false)) return;
|
||||
|
||||
s.change(s._validate(v));
|
||||
s._draw();
|
||||
};
|
||||
|
||||
// First click
|
||||
mouseMove(e);
|
||||
|
||||
// Mouse events listeners
|
||||
k.c.d
|
||||
.bind("mousemove.k", mouseMove)
|
||||
.bind(
|
||||
// Escape key cancel current change
|
||||
"keyup.k",
|
||||
function (e) {
|
||||
if (e.keyCode === 27) {
|
||||
k.c.d.unbind("mouseup.k mousemove.k keyup.k");
|
||||
|
||||
if (s.eH && s.eH() === false)
|
||||
return;
|
||||
|
||||
s.cancel();
|
||||
}
|
||||
}
|
||||
)
|
||||
.bind(
|
||||
"mouseup.k",
|
||||
function (e) {
|
||||
k.c.d.unbind('mousemove.k mouseup.k keyup.k');
|
||||
s.val(s.cv);
|
||||
}
|
||||
);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this._xy = function () {
|
||||
var o = this.$c.offset();
|
||||
this.x = o.left;
|
||||
this.y = o.top;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this._listen = function () {
|
||||
if (!this.o.readOnly) {
|
||||
this.$c
|
||||
.bind(
|
||||
"mousedown",
|
||||
function (e) {
|
||||
e.preventDefault();
|
||||
s._xy()._mouse(e);
|
||||
}
|
||||
)
|
||||
.bind(
|
||||
"touchstart",
|
||||
function (e) {
|
||||
e.preventDefault();
|
||||
s._xy()._touch(e);
|
||||
}
|
||||
);
|
||||
|
||||
this.listen();
|
||||
} else {
|
||||
this.$.attr('readonly', 'readonly');
|
||||
}
|
||||
|
||||
if (this.relative) {
|
||||
$(window).resize(function() {
|
||||
s._carve().init();
|
||||
s._draw();
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this._configure = function () {
|
||||
|
||||
// Hooks
|
||||
if (this.o.draw) this.dH = this.o.draw;
|
||||
if (this.o.change) this.cH = this.o.change;
|
||||
if (this.o.cancel) this.eH = this.o.cancel;
|
||||
if (this.o.release) this.rH = this.o.release;
|
||||
|
||||
if (this.o.displayPrevious) {
|
||||
this.pColor = this.h2rgba(this.o.fgColor, "0.4");
|
||||
this.fgColor = this.h2rgba(this.o.fgColor, "0.6");
|
||||
} else {
|
||||
this.fgColor = this.o.fgColor;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this._clear = function () {
|
||||
this.$c[0].width = this.$c[0].width;
|
||||
};
|
||||
|
||||
this._validate = function (v) {
|
||||
var val = (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step;
|
||||
return Math.round(val * 100) / 100;
|
||||
};
|
||||
|
||||
// Abstract methods
|
||||
this.listen = function () {}; // on start, one time
|
||||
this.extend = function () {}; // each time configure triggered
|
||||
this.init = function () {}; // each time configure triggered
|
||||
this.change = function (v) {}; // on change
|
||||
this.val = function (v) {}; // on release
|
||||
this.xy2val = function (x, y) {}; //
|
||||
this.draw = function () {}; // on change / on release
|
||||
this.clear = function () { this._clear(); };
|
||||
|
||||
// Utils
|
||||
this.h2rgba = function (h, a) {
|
||||
var rgb;
|
||||
h = h.substring(1,7);
|
||||
rgb = [
|
||||
parseInt(h.substring(0,2), 16),
|
||||
parseInt(h.substring(2,4), 16),
|
||||
parseInt(h.substring(4,6), 16)
|
||||
];
|
||||
|
||||
return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")";
|
||||
};
|
||||
|
||||
this.copy = function (f, t) {
|
||||
for (var i in f) {
|
||||
t[i] = f[i];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* k.Dial
|
||||
*/
|
||||
k.Dial = function () {
|
||||
k.o.call(this);
|
||||
|
||||
this.startAngle = null;
|
||||
this.xy = null;
|
||||
this.radius = null;
|
||||
this.lineWidth = null;
|
||||
this.cursorExt = null;
|
||||
this.w2 = null;
|
||||
this.PI2 = 2*Math.PI;
|
||||
|
||||
this.extend = function () {
|
||||
this.o = $.extend({
|
||||
bgColor: this.$.data('bgcolor') || '#EEEEEE',
|
||||
angleOffset: this.$.data('angleoffset') || 0,
|
||||
angleArc: this.$.data('anglearc') || 360,
|
||||
inline: true
|
||||
}, this.o);
|
||||
};
|
||||
|
||||
this.val = function (v, triggerRelease) {
|
||||
if (null != v) {
|
||||
|
||||
// reverse format
|
||||
v = this.o.parse(v);
|
||||
|
||||
if (triggerRelease !== false
|
||||
&& v != this.v
|
||||
&& this.rH
|
||||
&& this.rH(v) === false) { return; }
|
||||
|
||||
this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;
|
||||
this.v = this.cv;
|
||||
this.$.val(this.o.format(this.v));
|
||||
this._draw();
|
||||
} else {
|
||||
return this.v;
|
||||
}
|
||||
};
|
||||
|
||||
this.xy2val = function (x, y) {
|
||||
var a, ret;
|
||||
|
||||
a = Math.atan2(
|
||||
x - (this.x + this.w2),
|
||||
- (y - this.y - this.w2)
|
||||
) - this.angleOffset;
|
||||
|
||||
if (this.o.flip) {
|
||||
a = this.angleArc - a - this.PI2;
|
||||
}
|
||||
|
||||
if (this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {
|
||||
|
||||
// if isset angleArc option, set to min if .5 under min
|
||||
a = 0;
|
||||
} else if (a < 0) {
|
||||
a += this.PI2;
|
||||
}
|
||||
|
||||
ret = (a * (this.o.max - this.o.min) / this.angleArc) + this.o.min;
|
||||
|
||||
this.o.stopper && (ret = max(min(ret, this.o.max), this.o.min));
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
this.listen = function () {
|
||||
|
||||
// bind MouseWheel
|
||||
var s = this, mwTimerStop,
|
||||
mwTimerRelease,
|
||||
mw = function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var ori = e.originalEvent,
|
||||
deltaX = ori.detail || ori.wheelDeltaX,
|
||||
deltaY = ori.detail || ori.wheelDeltaY,
|
||||
v = s._validate(s.o.parse(s.$.val()))
|
||||
+ (
|
||||
deltaX > 0 || deltaY > 0
|
||||
? s.o.step
|
||||
: deltaX < 0 || deltaY < 0 ? -s.o.step : 0
|
||||
);
|
||||
|
||||
v = max(min(v, s.o.max), s.o.min);
|
||||
|
||||
s.val(v, false);
|
||||
|
||||
if (s.rH) {
|
||||
// Handle mousewheel stop
|
||||
clearTimeout(mwTimerStop);
|
||||
mwTimerStop = setTimeout(function () {
|
||||
s.rH(v);
|
||||
mwTimerStop = null;
|
||||
}, 100);
|
||||
|
||||
// Handle mousewheel releases
|
||||
if (!mwTimerRelease) {
|
||||
mwTimerRelease = setTimeout(function () {
|
||||
if (mwTimerStop)
|
||||
s.rH(v);
|
||||
mwTimerRelease = null;
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
},
|
||||
kval,
|
||||
to,
|
||||
m = 1,
|
||||
kv = {
|
||||
37: -s.o.step,
|
||||
38: s.o.step,
|
||||
39: s.o.step,
|
||||
40: -s.o.step
|
||||
};
|
||||
|
||||
this.$
|
||||
.bind(
|
||||
"keydown",
|
||||
function (e) {
|
||||
var kc = e.keyCode;
|
||||
|
||||
// numpad support
|
||||
if (kc >= 96 && kc <= 105) {
|
||||
kc = e.keyCode = kc - 48;
|
||||
}
|
||||
|
||||
kval = parseInt(String.fromCharCode(kc));
|
||||
|
||||
if (isNaN(kval)) {
|
||||
(kc !== 13) // enter
|
||||
&& kc !== 8 // bs
|
||||
&& kc !== 9 // tab
|
||||
&& kc !== 189 // -
|
||||
&& (kc !== 190
|
||||
|| s.$.val().match(/\./)) // . allowed once
|
||||
&& e.preventDefault();
|
||||
|
||||
// arrows
|
||||
if ($.inArray(kc,[37,38,39,40]) > -1) {
|
||||
e.preventDefault();
|
||||
|
||||
var v = s.o.parse(s.$.val()) + kv[kc] * m;
|
||||
s.o.stopper && (v = max(min(v, s.o.max), s.o.min));
|
||||
|
||||
s.change(s._validate(v));
|
||||
s._draw();
|
||||
|
||||
// long time keydown speed-up
|
||||
to = window.setTimeout(function () {
|
||||
m *= 2;
|
||||
}, 30);
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.bind(
|
||||
"keyup",
|
||||
function (e) {
|
||||
if (isNaN(kval)) {
|
||||
if (to) {
|
||||
window.clearTimeout(to);
|
||||
to = null;
|
||||
m = 1;
|
||||
s.val(s.$.val());
|
||||
}
|
||||
} else {
|
||||
// kval postcond
|
||||
(s.$.val() > s.o.max && s.$.val(s.o.max))
|
||||
|| (s.$.val() < s.o.min && s.$.val(s.o.min));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.$c.bind("mousewheel DOMMouseScroll", mw);
|
||||
this.$.bind("mousewheel DOMMouseScroll", mw);
|
||||
};
|
||||
|
||||
this.init = function () {
|
||||
if (this.v < this.o.min
|
||||
|| this.v > this.o.max) { this.v = this.o.min; }
|
||||
|
||||
this.$.val(this.v);
|
||||
this.w2 = this.w / 2;
|
||||
this.cursorExt = this.o.cursor / 100;
|
||||
this.xy = this.w2 * this.scale;
|
||||
this.lineWidth = this.xy * this.o.thickness;
|
||||
this.lineCap = this.o.lineCap;
|
||||
this.radius = this.xy - this.lineWidth / 2;
|
||||
|
||||
this.o.angleOffset
|
||||
&& (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);
|
||||
|
||||
this.o.angleArc
|
||||
&& (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);
|
||||
|
||||
// deg to rad
|
||||
this.angleOffset = this.o.angleOffset * Math.PI / 180;
|
||||
this.angleArc = this.o.angleArc * Math.PI / 180;
|
||||
|
||||
// compute start and end angles
|
||||
this.startAngle = 1.5 * Math.PI + this.angleOffset;
|
||||
this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;
|
||||
|
||||
var s = max(
|
||||
String(Math.abs(this.o.max)).length,
|
||||
String(Math.abs(this.o.min)).length,
|
||||
2
|
||||
) + 2;
|
||||
|
||||
this.o.displayInput
|
||||
&& this.i.css({
|
||||
'width' : ((this.w / 2 + 4) >> 0) + 'px',
|
||||
'height' : ((this.w / 2) >> 0) + 'px',
|
||||
'position' : 'absolute',
|
||||
'vertical-align' : 'middle',
|
||||
'margin-top' : ((this.w / 4) >> 0) + 'px',
|
||||
'margin-left' : '-' + ((this.w * 3 / 4 + 2) >> 0) + 'px',
|
||||
'border' : 0,
|
||||
'background' : 'none',
|
||||
'font' : this.o.fontWeight + ' ' + ((this.w / s) >> 0) + 'px ' + this.o.font,
|
||||
'text-align' : 'center',
|
||||
'color' : this.o.inputColor || this.o.fgColor,
|
||||
'padding' : '0px',
|
||||
'-webkit-appearance': 'none'
|
||||
}) || this.i.css({
|
||||
'width': '0px',
|
||||
'visibility': 'hidden'
|
||||
});
|
||||
};
|
||||
|
||||
this.change = function (v) {
|
||||
this.cv = v;
|
||||
this.$.val(this.o.format(v));
|
||||
};
|
||||
|
||||
this.angle = function (v) {
|
||||
return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);
|
||||
};
|
||||
|
||||
this.arc = function (v) {
|
||||
var sa, ea;
|
||||
v = this.angle(v);
|
||||
if (this.o.flip) {
|
||||
sa = this.endAngle + 0.00001;
|
||||
ea = sa - v - 0.00001;
|
||||
} else {
|
||||
sa = this.startAngle - 0.00001;
|
||||
ea = sa + v + 0.00001;
|
||||
}
|
||||
this.o.cursor
|
||||
&& (sa = ea - this.cursorExt)
|
||||
&& (ea = ea + this.cursorExt);
|
||||
|
||||
return {
|
||||
s: sa,
|
||||
e: ea,
|
||||
d: this.o.flip && !this.o.cursor
|
||||
};
|
||||
};
|
||||
|
||||
this.draw = function () {
|
||||
var c = this.g, // context
|
||||
a = this.arc(this.cv), // Arc
|
||||
pa, // Previous arc
|
||||
r = 1;
|
||||
|
||||
c.lineWidth = this.lineWidth;
|
||||
c.lineCap = this.lineCap;
|
||||
|
||||
if (this.o.bgColor !== "none") {
|
||||
c.beginPath();
|
||||
c.strokeStyle = this.o.bgColor;
|
||||
c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
|
||||
c.stroke();
|
||||
}
|
||||
|
||||
if (this.o.displayPrevious) {
|
||||
pa = this.arc(this.v);
|
||||
c.beginPath();
|
||||
c.strokeStyle = this.pColor;
|
||||
c.arc(this.xy, this.xy, this.radius, pa.s, pa.e, pa.d);
|
||||
c.stroke();
|
||||
r = this.cv == this.v;
|
||||
}
|
||||
|
||||
c.beginPath();
|
||||
c.strokeStyle = r ? this.o.fgColor : this.fgColor ;
|
||||
c.arc(this.xy, this.xy, this.radius, a.s, a.e, a.d);
|
||||
c.stroke();
|
||||
};
|
||||
|
||||
this.cancel = function () {
|
||||
this.val(this.v);
|
||||
};
|
||||
};
|
||||
|
||||
$.fn.dial = $.fn.knob = function (o) {
|
||||
return this.each(
|
||||
function () {
|
||||
var d = new k.Dial();
|
||||
d.o = o;
|
||||
d.$ = $(this);
|
||||
d.run();
|
||||
}
|
||||
).parent();
|
||||
};
|
||||
|
||||
}));
|
2
wp-content/plugins/shortpixel-image-optimiser/res/js/jquery.knob.min.js
vendored
Normal file
2
wp-content/plugins/shortpixel-image-optimiser/res/js/jquery.knob.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,128 @@
|
||||
(function($){
|
||||
|
||||
$.fn.twentytwenty = function(options) {
|
||||
var options = $.extend({
|
||||
default_offset_pct: 0.5,
|
||||
orientation: 'horizontal',
|
||||
slider_move: "drag" //"drag" or "mousemove"
|
||||
}, options);
|
||||
return this.each(function() {
|
||||
|
||||
var sliderPct = options.default_offset_pct;
|
||||
var container = $(this);
|
||||
var sliderOrientation = options.orientation;
|
||||
var beforeDirection = (sliderOrientation === 'vertical') ? 'down' : 'left';
|
||||
var afterDirection = (sliderOrientation === 'vertical') ? 'up' : 'right';
|
||||
|
||||
|
||||
container.wrap("<div class='twentytwenty-wrapper twentytwenty-" + sliderOrientation + "'></div>");
|
||||
container.append("<div class='twentytwenty-overlay'></div>");
|
||||
var beforeImg = container.find("img:first");
|
||||
var afterImg = container.find("img:last");
|
||||
container.append("<div class='twentytwenty-handle'></div>");
|
||||
var slider = container.find(".twentytwenty-handle");
|
||||
slider.append("<span class='twentytwenty-" + beforeDirection + "-arrow'></span>");
|
||||
slider.append("<span class='twentytwenty-" + afterDirection + "-arrow'></span>");
|
||||
container.addClass("twentytwenty-container");
|
||||
beforeImg.addClass("twentytwenty-before");
|
||||
afterImg.addClass("twentytwenty-after");
|
||||
|
||||
var overlay = container.find(".twentytwenty-overlay");
|
||||
overlay.append("<div class='twentytwenty-before-label'></div>");
|
||||
overlay.append("<div class='twentytwenty-after-label'></div>");
|
||||
|
||||
var beforeLabel = container.find("div.twentytwenty-before-label");
|
||||
var afterLabel = container.find("div.twentytwenty-after-label");
|
||||
|
||||
var calcOffset = function(dimensionPct) {
|
||||
var w = beforeImg.width();
|
||||
var h = beforeImg.height();
|
||||
return {
|
||||
w: w+"px",
|
||||
h: h+"px",
|
||||
cw: (dimensionPct*w)+"px",
|
||||
ch: (dimensionPct*h)+"px",
|
||||
};
|
||||
};
|
||||
|
||||
var adjustContainer = function(offset) {
|
||||
if (sliderOrientation === 'vertical') {
|
||||
beforeImg.css("clip", "rect(0,"+offset.w+","+offset.ch+",0)");
|
||||
|
||||
}
|
||||
else {
|
||||
beforeImg.css("clip", "rect(0,"+offset.cw+","+offset.h+",0)");
|
||||
beforeLabel.css("clip", "rect(0,"+offset.cw+","+offset.h+",0)");
|
||||
afterLabel.css("clip", "rect(0,"+offset.w+","+offset.h+","+offset.cw+")"); //clip: rect(0px, 700px, 1000px, 600px);
|
||||
}
|
||||
container.css("height", offset.h);
|
||||
};
|
||||
|
||||
var adjustSlider = function(pct) {
|
||||
var offset = calcOffset(pct);
|
||||
slider.css((sliderOrientation==="vertical") ? "top" : "left", (sliderOrientation==="vertical") ? offset.ch : offset.cw);
|
||||
adjustContainer(offset);
|
||||
}
|
||||
|
||||
$(window).on("resize.twentytwenty", function(e) {
|
||||
adjustSlider(sliderPct);
|
||||
});
|
||||
|
||||
var offsetX = 0;
|
||||
var imgWidth = 0;
|
||||
|
||||
if(options.slider_move == "drag") {
|
||||
slider.on("movestart", function(e) {
|
||||
if (((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) && sliderOrientation !== 'vertical') {
|
||||
e.preventDefault();
|
||||
}
|
||||
else if (((e.distX < e.distY && e.distX < -e.distY) || (e.distX > e.distY && e.distX > -e.distY)) && sliderOrientation === 'vertical') {
|
||||
e.preventDefault();
|
||||
}
|
||||
container.addClass("active");
|
||||
offsetX = container.offset().left;
|
||||
offsetY = container.offset().top;
|
||||
imgWidth = beforeImg.width();
|
||||
imgHeight = beforeImg.height();
|
||||
});
|
||||
|
||||
slider.on("moveend", function(e) {
|
||||
container.removeClass("active");
|
||||
});
|
||||
|
||||
slider.on("move", function(e) {
|
||||
if (container.hasClass("active")) {
|
||||
sliderPct = (sliderOrientation === 'vertical') ? (e.pageY-offsetY)/imgHeight : (e.pageX-offsetX)/imgWidth;
|
||||
if (sliderPct < 0) {
|
||||
sliderPct = 0;
|
||||
}
|
||||
if (sliderPct > 1) {
|
||||
sliderPct = 1;
|
||||
}
|
||||
adjustSlider(sliderPct);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
container.mousemove(function(e) {
|
||||
sliderPct = (sliderOrientation === 'vertical')
|
||||
? (e.pageY-container.offset().top)/beforeImg.height()
|
||||
: (e.pageX-container.offset().left)/beforeImg.width();
|
||||
if (sliderPct < 0) {
|
||||
sliderPct = 0;
|
||||
}
|
||||
if (sliderPct > 1) {
|
||||
sliderPct = 1;
|
||||
}
|
||||
adjustSlider(sliderPct);
|
||||
});
|
||||
}
|
||||
|
||||
container.find("img").on("mousedown", function(event) {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
$(window).trigger("resize.twentytwenty");
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery);
|
1
wp-content/plugins/shortpixel-image-optimiser/res/js/jquery.twentytwenty.min.js
vendored
Normal file
1
wp-content/plugins/shortpixel-image-optimiser/res/js/jquery.twentytwenty.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(function(a){a.fn.twentytwenty=function(b){var b=a.extend({default_offset_pct:0.5,orientation:"horizontal",slider_move:"drag"},b);return this.each(function(){var h=b.default_offset_pct;var e=a(this);var c=b.orientation;var q=(c==="vertical")?"down":"left";var d=(c==="vertical")?"up":"right";e.wrap("<div class='twentytwenty-wrapper twentytwenty-"+c+"'></div>");e.append("<div class='twentytwenty-overlay'></div>");var r=e.find("img:first");var o=e.find("img:last");e.append("<div class='twentytwenty-handle'></div>");var f=e.find(".twentytwenty-handle");f.append("<span class='twentytwenty-"+q+"-arrow'></span>");f.append("<span class='twentytwenty-"+d+"-arrow'></span>");e.addClass("twentytwenty-container");r.addClass("twentytwenty-before");o.addClass("twentytwenty-after");var j=e.find(".twentytwenty-overlay");j.append("<div class='twentytwenty-before-label'></div>");j.append("<div class='twentytwenty-after-label'></div>");var l=e.find("div.twentytwenty-before-label");var k=e.find("div.twentytwenty-after-label");var i=function(t){var s=r.width();var u=r.height();return{w:s+"px",h:u+"px",cw:(t*s)+"px",ch:(t*u)+"px"}};var g=function(s){if(c==="vertical"){r.css("clip","rect(0,"+s.w+","+s.ch+",0)")}else{r.css("clip","rect(0,"+s.cw+","+s.h+",0)");l.css("clip","rect(0,"+s.cw+","+s.h+",0)");k.css("clip","rect(0,"+s.w+","+s.h+","+s.cw+")")}e.css("height",s.h)};var n=function(s){var t=i(s);f.css((c==="vertical")?"top":"left",(c==="vertical")?t.ch:t.cw);g(t)};a(window).on("resize.twentytwenty",function(s){n(h)});var m=0;var p=0;if(b.slider_move=="drag"){f.on("movestart",function(s){if(((s.distX>s.distY&&s.distX<-s.distY)||(s.distX<s.distY&&s.distX>-s.distY))&&c!=="vertical"){s.preventDefault()}else{if(((s.distX<s.distY&&s.distX<-s.distY)||(s.distX>s.distY&&s.distX>-s.distY))&&c==="vertical"){s.preventDefault()}}e.addClass("active");m=e.offset().left;offsetY=e.offset().top;p=r.width();imgHeight=r.height()});f.on("moveend",function(s){e.removeClass("active")});f.on("move",function(s){if(e.hasClass("active")){h=(c==="vertical")?(s.pageY-offsetY)/imgHeight:(s.pageX-m)/p;if(h<0){h=0}if(h>1){h=1}n(h)}})}else{e.mousemove(function(s){h=(c==="vertical")?(s.pageY-e.offset().top)/r.height():(s.pageX-e.offset().left)/r.width();if(h<0){h=0}if(h>1){h=1}n(h)})}e.find("img").on("mousedown",function(s){s.preventDefault()});a(window).trigger("resize.twentytwenty")})}})(jQuery);
|
449
wp-content/plugins/shortpixel-image-optimiser/res/js/punycode.js
Normal file
449
wp-content/plugins/shortpixel-image-optimiser/res/js/punycode.js
Normal file
@ -0,0 +1,449 @@
|
||||
'use strict';
|
||||
|
||||
/** ShortPixel: Changed punycode to sp_punycode in order to prevent possible conflicts with other WP plugins that use punycode
|
||||
* Also moved all the functions inside the sp_punycode const for the same reason and changed const's to let's */
|
||||
|
||||
// 5.0 Deprecated ** Let's see if the modern world works without this **/
|
||||
var sp_punycode = function(){
|
||||
|
||||
/** Highest positive signed 32-bit float value */
|
||||
var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
|
||||
|
||||
/** Bootstring parameters */
|
||||
var base = 36;
|
||||
var tMin = 1;
|
||||
var tMax = 26;
|
||||
var skew = 38;
|
||||
var damp = 700;
|
||||
var initialBias = 72;
|
||||
var initialN = 128; // 0x80
|
||||
var delimiter = '-'; // '\x2D'
|
||||
|
||||
/** Regular expressions */
|
||||
var regexPunycode = /^xn--/;
|
||||
var regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars
|
||||
var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
|
||||
|
||||
/** Error messages */
|
||||
var errors = {
|
||||
'overflow': 'Overflow: input needs wider integers to process',
|
||||
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
|
||||
'invalid-input': 'Invalid input'
|
||||
};
|
||||
|
||||
/** Convenience shortcuts */
|
||||
var baseMinusTMin = base - tMin;
|
||||
var floor = Math.floor;
|
||||
var stringFromCharCode = String.fromCharCode;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* A generic error utility function.
|
||||
* @private
|
||||
* @param {String} type The error type.
|
||||
* @returns {Error} Throws a `RangeError` with the applicable error message.
|
||||
*/
|
||||
function error(type) {
|
||||
throw new RangeError(errors[type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic `Array#map` utility function.
|
||||
* @private
|
||||
* @param {Array} array The array to iterate over.
|
||||
* @param {Function} callback The function that gets called for every array
|
||||
* item.
|
||||
* @returns {Array} A new array of values returned by the callback function.
|
||||
*/
|
||||
function map(array, fn) {
|
||||
var result = [];
|
||||
var length = array.length;
|
||||
while (length--) {
|
||||
result[length] = fn(array[length]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple `Array#map`-like wrapper to work with domain name strings or email
|
||||
* addresses.
|
||||
* @private
|
||||
* @param {String} domain The domain name or email address.
|
||||
* @param {Function} callback The function that gets called for every
|
||||
* character.
|
||||
* @returns {Array} A new string of characters returned by the callback
|
||||
* function.
|
||||
*/
|
||||
function mapDomain(string, fn) {
|
||||
var parts = string.split('@');
|
||||
var result = '';
|
||||
if (parts.length > 1) {
|
||||
// In email addresses, only the domain name should be punycoded. Leave
|
||||
// the local part (i.e. everything up to `@`) intact.
|
||||
result = parts[0] + '@';
|
||||
string = parts[1];
|
||||
}
|
||||
// Avoid `split(regex)` for IE8 compatibility. See #17.
|
||||
string = string.replace(regexSeparators, '\x2E');
|
||||
var labels = string.split('.');
|
||||
var encoded = map(labels, fn).join('.');
|
||||
return result + encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array containing the numeric code points of each Unicode
|
||||
* character in the string. While JavaScript uses UCS-2 internally,
|
||||
* this function will convert a pair of surrogate halves (each of which
|
||||
* UCS-2 exposes as separate characters) into a single code point,
|
||||
* matching UTF-16.
|
||||
* @see `punycode.ucs2.encode`
|
||||
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
||||
* @memberOf punycode.ucs2
|
||||
* @name decode
|
||||
* @param {String} string The Unicode input string (UCS-2).
|
||||
* @returns {Array} The new array of code points.
|
||||
*/
|
||||
function ucs2decode(string) {
|
||||
var output = [];
|
||||
var counter = 0;
|
||||
var length = string.length;
|
||||
while (counter < length) {
|
||||
var value = string.charCodeAt(counter++);
|
||||
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
|
||||
// It's a high surrogate, and there is a next character.
|
||||
var extra = string.charCodeAt(counter++);
|
||||
if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
|
||||
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
|
||||
} else {
|
||||
// It's an unmatched surrogate; only append this code unit, in case the
|
||||
// next code unit is the high surrogate of a surrogate pair.
|
||||
output.push(value);
|
||||
counter--;
|
||||
}
|
||||
} else {
|
||||
output.push(value);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string based on an array of numeric code points.
|
||||
* @see `punycode.ucs2.decode`
|
||||
* @memberOf punycode.ucs2
|
||||
* @name encode
|
||||
* @param {Array} codePoints The array of numeric code points.
|
||||
* @returns {String} The new Unicode string (UCS-2).
|
||||
*/
|
||||
//const ucs2encode = array => String.fromCodePoint(...array);
|
||||
var ucs2encode = array => String.fromCodePoint.prototype.apply(null, array);
|
||||
|
||||
/**
|
||||
* Converts a basic code point into a digit/integer.
|
||||
* @see `digitToBasic()`
|
||||
* @private
|
||||
* @param {Number} codePoint The basic numeric code point value.
|
||||
* @returns {Number} The numeric value of a basic code point (for use in
|
||||
* representing integers) in the range `0` to `base - 1`, or `base` if
|
||||
* the code point does not represent a value.
|
||||
*/
|
||||
var basicToDigit = function(codePoint) {
|
||||
if (codePoint - 0x30 < 0x0A) {
|
||||
return codePoint - 0x16;
|
||||
}
|
||||
if (codePoint - 0x41 < 0x1A) {
|
||||
return codePoint - 0x41;
|
||||
}
|
||||
if (codePoint - 0x61 < 0x1A) {
|
||||
return codePoint - 0x61;
|
||||
}
|
||||
return base;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a digit/integer into a basic code point.
|
||||
* @see `basicToDigit()`
|
||||
* @private
|
||||
* @param {Number} digit The numeric value of a basic code point.
|
||||
* @returns {Number} The basic code point whose value (when used for
|
||||
* representing integers) is `digit`, which needs to be in the range
|
||||
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
|
||||
* used; else, the lowercase form is used. The behavior is undefined
|
||||
* if `flag` is non-zero and `digit` has no uppercase form.
|
||||
*/
|
||||
var digitToBasic = function(digit, flag) {
|
||||
// 0..25 map to ASCII a..z or A..Z
|
||||
// 26..35 map to ASCII 0..9
|
||||
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
|
||||
};
|
||||
|
||||
/**
|
||||
* Bias adaptation function as per section 3.4 of RFC 3492.
|
||||
* https://tools.ietf.org/html/rfc3492#section-3.4
|
||||
* @private
|
||||
*/
|
||||
var adapt = function(delta, numPoints, firstTime) {
|
||||
var k = 0;
|
||||
delta = firstTime ? floor(delta / damp) : delta >> 1;
|
||||
delta += floor(delta / numPoints);
|
||||
for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
|
||||
delta = floor(delta / baseMinusTMin);
|
||||
}
|
||||
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
|
||||
* symbols.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The Punycode string of ASCII-only symbols.
|
||||
* @returns {String} The resulting string of Unicode symbols.
|
||||
*/
|
||||
var decode = function(input) {
|
||||
// Don't use UCS-2.
|
||||
var output = [];
|
||||
var inputLength = input.length;
|
||||
var i = 0;
|
||||
var n = initialN;
|
||||
var bias = initialBias;
|
||||
|
||||
// Handle the basic code points: let `basic` be the number of input code
|
||||
// points before the last delimiter, or `0` if there is none, then copy
|
||||
// the first basic code points to the output.
|
||||
|
||||
var basic = input.lastIndexOf(delimiter);
|
||||
if (basic < 0) {
|
||||
basic = 0;
|
||||
}
|
||||
|
||||
for (var j = 0; j < basic; ++j) {
|
||||
// if it's not a basic code point
|
||||
if (input.charCodeAt(j) >= 0x80) {
|
||||
error('not-basic');
|
||||
}
|
||||
output.push(input.charCodeAt(j));
|
||||
}
|
||||
|
||||
// Main decoding loop: start just after the last delimiter if any basic code
|
||||
// points were copied; start at the beginning otherwise.
|
||||
|
||||
for (var index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
|
||||
|
||||
// `index` is the index of the next character to be consumed.
|
||||
// Decode a generalized variable-length integer into `delta`,
|
||||
// which gets added to `i`. The overflow checking is easier
|
||||
// if we increase `i` as we go, then subtract off its starting
|
||||
// value at the end to obtain `delta`.
|
||||
var oldi = i;
|
||||
for (var w = 1, k = base; /* no condition */; k += base) {
|
||||
|
||||
if (index >= inputLength) {
|
||||
error('invalid-input');
|
||||
}
|
||||
|
||||
var digit = basicToDigit(input.charCodeAt(index++));
|
||||
|
||||
if (digit >= base || digit > floor((maxInt - i) / w)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
i += digit * w;
|
||||
var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
||||
|
||||
if (digit < t) {
|
||||
break;
|
||||
}
|
||||
|
||||
var baseMinusT = base - t;
|
||||
if (w > floor(maxInt / baseMinusT)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
w *= baseMinusT;
|
||||
|
||||
}
|
||||
|
||||
var out = output.length + 1;
|
||||
bias = adapt(i - oldi, out, oldi == 0);
|
||||
|
||||
// `i` was supposed to wrap around from `out` to `0`,
|
||||
// incrementing `n` each time, so we'll fix that now:
|
||||
if (floor(i / out) > maxInt - n) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
n += floor(i / out);
|
||||
i %= out;
|
||||
|
||||
// Insert `n` at position `i` of the output.
|
||||
output.splice(i++, 0, n);
|
||||
|
||||
}
|
||||
|
||||
//return String.fromCodePoint(...output);
|
||||
return String.fromCodePoint.prototype.apply(null, output);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a string of Unicode symbols (e.g. a domain name label) to a
|
||||
* Punycode string of ASCII-only symbols.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The string of Unicode symbols.
|
||||
* @returns {String} The resulting Punycode string of ASCII-only symbols.
|
||||
*/
|
||||
var encode = function(input) {
|
||||
var output = [];
|
||||
|
||||
// Convert the input in UCS-2 to an array of Unicode code points.
|
||||
input = ucs2decode(input);
|
||||
|
||||
// Cache the length.
|
||||
var inputLength = input.length;
|
||||
|
||||
// Initialize the state.
|
||||
var n = initialN;
|
||||
var delta = 0;
|
||||
var bias = initialBias;
|
||||
|
||||
// Handle the basic code points.
|
||||
for (var currentValue of input) {
|
||||
if (currentValue < 0x80) {
|
||||
output.push(stringFromCharCode(currentValue));
|
||||
}
|
||||
}
|
||||
|
||||
var basicLength = output.length;
|
||||
var handledCPCount = basicLength;
|
||||
|
||||
// `handledCPCount` is the number of code points that have been handled;
|
||||
// `basicLength` is the number of basic code points.
|
||||
|
||||
// Finish the basic string with a delimiter unless it's empty.
|
||||
if (basicLength) {
|
||||
output.push(delimiter);
|
||||
}
|
||||
|
||||
// Main encoding loop:
|
||||
while (handledCPCount < inputLength) {
|
||||
|
||||
// All non-basic code points < n have been handled already. Find the next
|
||||
// larger one:
|
||||
var m = maxInt;
|
||||
for (var currentValue of input) {
|
||||
if (currentValue >= n && currentValue < m) {
|
||||
m = currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
|
||||
// but guard against overflow.
|
||||
var handledCPCountPlusOne = handledCPCount + 1;
|
||||
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
delta += (m - n) * handledCPCountPlusOne;
|
||||
n = m;
|
||||
|
||||
for (var currentValue of input) {
|
||||
if (currentValue < n && ++delta > maxInt) {
|
||||
error('overflow');
|
||||
}
|
||||
if (currentValue == n) {
|
||||
// Represent delta as a generalized variable-length integer.
|
||||
var q = delta;
|
||||
for (var k = base; /* no condition */; k += base) {
|
||||
var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
||||
if (q < t) {
|
||||
break;
|
||||
}
|
||||
var qMinusT = q - t;
|
||||
var baseMinusT = base - t;
|
||||
output.push(
|
||||
stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
|
||||
);
|
||||
q = floor(qMinusT / baseMinusT);
|
||||
}
|
||||
|
||||
output.push(stringFromCharCode(digitToBasic(q, 0)));
|
||||
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
|
||||
delta = 0;
|
||||
++handledCPCount;
|
||||
}
|
||||
}
|
||||
|
||||
++delta;
|
||||
++n;
|
||||
|
||||
}
|
||||
return output.join('');
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Punycode string representing a domain name or an email address
|
||||
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
|
||||
* it doesn't matter if you call it on a string that has already been
|
||||
* converted to Unicode.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The Punycoded domain name or email address to
|
||||
* convert to Unicode.
|
||||
* @returns {String} The Unicode representation of the given Punycode
|
||||
* string.
|
||||
*/
|
||||
var toUnicode = function(input) {
|
||||
return mapDomain(input, function(string) {
|
||||
return regexPunycode.test(string)
|
||||
? decode(string.slice(4).toLowerCase())
|
||||
: string;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a Unicode string representing a domain name or an email address to
|
||||
* Punycode. Only the non-ASCII parts of the domain name will be converted,
|
||||
* i.e. it doesn't matter if you call it with a domain that's already in
|
||||
* ASCII.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The domain name or email address to convert, as a
|
||||
* Unicode string.
|
||||
* @returns {String} The Punycode representation of the given domain name or
|
||||
* email address.
|
||||
*/
|
||||
var toASCII = function(input) {
|
||||
return mapDomain(input, function(string) {
|
||||
return regexNonASCII.test(string)
|
||||
? 'xn--' + encode(string)
|
||||
: string;
|
||||
});
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/** Define the public API */
|
||||
return {
|
||||
/**
|
||||
* A string representing the current Punycode.js version number.
|
||||
* @memberOf punycode
|
||||
* @type String
|
||||
*/
|
||||
version: '2.1.0',
|
||||
/**
|
||||
* An object of methods to convert from JavaScript's internal character
|
||||
* representation (UCS-2) to Unicode code points, and back.
|
||||
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
||||
* @memberOf punycode
|
||||
* @type Object
|
||||
*/
|
||||
ucs2: {
|
||||
'decode': ucs2decode,
|
||||
'encode': ucs2encode
|
||||
},
|
||||
decode: decode,
|
||||
encode: encode,
|
||||
toASCII: toASCII,
|
||||
toUnicode: toUnicode
|
||||
}
|
||||
}();
|
||||
|
||||
//module.exports = sp_punycode;
|
1
wp-content/plugins/shortpixel-image-optimiser/res/js/punycode.min.js
vendored
Normal file
1
wp-content/plugins/shortpixel-image-optimiser/res/js/punycode.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
'use strict';var sp_punycode=function(){function a(K){throw new RangeError(y[K])}function b(K,L){for(var M=[],N=K.length;N--;)M[N]=L(K[N]);return M}function c(K,L){var M=K.split('@'),N='';1<M.length&&(N=M[0]+'@',K=M[1]),K=K.replace(x,'.');var O=K.split('.'),P=b(O,L).join('.');return N+P}function d(K){for(var O,L=[],M=0,N=K.length;M<N;)if(O=K.charCodeAt(M++),55296<=O&&56319>=O&&M<N){var P=K.charCodeAt(M++);56320==(64512&P)?L.push(((1023&O)<<10)+(1023&P)+65536):(L.push(O),M--)}else L.push(O);return L}var e=2147483647,f=36,g=1,h=26,p=72,r=128,s='-',u=/^xn--/,v=/[^\0-\x7E]/,x=/[\x2E\u3002\uFF0E\uFF61]/g,y={overflow:'Overflow: input needs wider integers to process','not-basic':'Illegal input >= 0x80 (not a basic code point)','invalid-input':'Invalid input'},z=f-g,A=Math.floor,B=String.fromCharCode,D=function(K){return 10>K-48?K-22:26>K-65?K-65:26>K-97?K-97:f},E=function(K,L){return K+22+75*(26>K)-((0!=L)<<5)},F=function(K,L,M){var N=0;for(K=M?A(K/700):K>>1,K+=A(K/L);K>z*h>>1;N+=f)K=A(K/z);return A(N+(z+1)*K/(K+38))},G=function(K){var L=[],M=K.length,N=0,O=r,P=p,Q=K.lastIndexOf(s);0>Q&&(Q=0);for(var R=0;R<Q;++R)128<=K.charCodeAt(R)&&a('not-basic'),L.push(K.charCodeAt(R));for(var T,S=0<Q?Q+1:0;S<M;){T=N;for(var U=1,V=f;;V+=f){S>=M&&a('invalid-input');var W=D(K.charCodeAt(S++));(W>=f||W>A((e-N)/U))&&a('overflow'),N+=W*U;var X=V<=P?g:V>=P+h?h:V-P;if(W<X)break;var Y=f-X;U>A(e/Y)&&a('overflow'),U*=Y}var Z=L.length+1;P=F(N-T,Z,0==T),A(N/Z)>e-O&&a('overflow'),O+=A(N/Z),N%=Z,L.splice(N++,0,O)}return String.fromCodePoint.prototype.apply(null,L)};var H=function(K){var L=[];K=d(K);var M=K.length,N=r,O=0,P=p;for(var Q of K)128>Q&&L.push(B(Q));var R=L.length,S=R;for(R&&L.push(s);S<M;){var T=e;for(var Q of K)Q>=N&&Q<T&&(T=Q);var U=S+1;T-N>A((e-O)/U)&&a('overflow'),O+=(T-N)*U,N=T;for(var Q of K)if(Q<N&&++O>e&&a('overflow'),Q==N){for(var X,V=O,W=f;;W+=f){if(X=W<=P?g:W>=P+h?h:W-P,V<X)break;var Y=V-X,Z=f-X;L.push(B(E(X+Y%Z,0))),V=A(Y/Z)}L.push(B(E(V,0))),P=F(O,U,S==R),O=0,++S}++O,++N}return L.join('')};return{version:'2.1.0',ucs2:{decode:d,encode:K=>String.fromCodePoint.prototype.apply(null,K)},decode:G,encode:H,toASCII:function(K){return c(K,function(L){return v.test(L)?'xn--'+H(L):L})},toUnicode:function(K){return c(K,function(L){return u.test(L)?G(L.slice(4).toLowerCase()):L})}}}();
|
@ -0,0 +1,179 @@
|
||||
'use strict';
|
||||
|
||||
class ShortPixelScreenBase
|
||||
{
|
||||
isCustom = true;
|
||||
isMedia = true;
|
||||
processor;
|
||||
strings = [];
|
||||
|
||||
constructor(MainScreen, processor)
|
||||
{
|
||||
this.processor = processor;
|
||||
this.strings = spio_screenStrings;
|
||||
}
|
||||
|
||||
// Function for subclasses to add more init. Seperated because of screens that need to call Process functions when starting.
|
||||
Init()
|
||||
{
|
||||
}
|
||||
|
||||
// var message = {status: false, http_status: response.status, http_text: text, status_text: response.statusText };
|
||||
HandleError(data)
|
||||
{
|
||||
if (this.processor.debugIsActive == 'false')
|
||||
return; // stay silent when debug is not active.
|
||||
|
||||
var text = String(data.http_text);
|
||||
var title = this.strings.fatalError;
|
||||
var notice = this.GetErrorNotice(title, text);
|
||||
|
||||
var el = this.GetErrorPosition();
|
||||
if (el === null)
|
||||
{
|
||||
console.error('Cannot display error - no position found!');
|
||||
return;
|
||||
}
|
||||
el.prepend(notice);
|
||||
}
|
||||
|
||||
// No actions at the base.
|
||||
HandleItemError(result)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HandleErrorStop()
|
||||
{
|
||||
if (this.processor.debugIsActive == 'false')
|
||||
return; // stay silent when debug is not active.
|
||||
|
||||
var title = this.strings.fatalErrorStop;
|
||||
var text = this.strings.fatalErrorStopText;
|
||||
|
||||
var notice = this.GetErrorNotice(title, text);
|
||||
var el = this.GetErrorPosition();
|
||||
if (el === null)
|
||||
{
|
||||
console.error('Cannot display error - no position found!');
|
||||
return;
|
||||
}
|
||||
el.prepend(notice);
|
||||
}
|
||||
|
||||
|
||||
GetErrorNotice(title, text)
|
||||
{
|
||||
var notice = document.createElement('div');
|
||||
|
||||
var button = document.createElement('button'); // '<button type="button" class="notice-dismiss"></button>';
|
||||
button.classList.add('notice-dismiss');
|
||||
button.type = 'button';
|
||||
button.addEventListener('click', this.EventCloseErrorNotice);
|
||||
|
||||
notice.classList.add('notice', 'notice-error', 'is-dismissible');
|
||||
|
||||
notice.innerHTML += '<p><strong>' + title + '</strong></p>';
|
||||
notice.innerHTML += '<div class="error-details">' + text + '</div>';
|
||||
|
||||
notice.append(button);
|
||||
|
||||
return notice;
|
||||
}
|
||||
|
||||
EventCloseErrorNotice(event)
|
||||
{
|
||||
event.target.parentElement.remove();
|
||||
}
|
||||
|
||||
// Search for where to insert the notice before ( ala WP system )
|
||||
GetErrorPosition()
|
||||
{
|
||||
var el = document.querySelector('.is-shortpixel-settings-page');
|
||||
if (el !== null) // we are on settings page .
|
||||
{
|
||||
return el;
|
||||
}
|
||||
|
||||
var el = document.querySelector('.wrap');
|
||||
if (el !== null)
|
||||
return el;
|
||||
|
||||
|
||||
var el = document.querySelector('#wpbody-content');
|
||||
if (el !== null)
|
||||
return el;
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
HandleImage(result, type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
UpdateStats()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
RenderItemView(e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// @todo Find a better home for this. Global screen class?
|
||||
ParseNumber(str)
|
||||
{
|
||||
str = str.replace(',','', str).replace('.','',str);
|
||||
return parseInt(str);
|
||||
}
|
||||
|
||||
|
||||
// ** FADE OUT FUNCTION **
|
||||
FadeOut(el) {
|
||||
el.style.opacity = 0;
|
||||
el.style.display = 'none';
|
||||
|
||||
/*
|
||||
el.style.opacity = 1;
|
||||
(function fade() {
|
||||
if ((el.style.opacity -= .1) < 0) {
|
||||
el.style.display = "none";
|
||||
el.style.opacity = 0;
|
||||
|
||||
} else {
|
||||
requestAnimationFrame(fade);
|
||||
}
|
||||
})(); */
|
||||
};
|
||||
|
||||
// ** FADE IN FUNCTION **
|
||||
FadeIn(el, display) {
|
||||
el.style.opacity = 1;
|
||||
el.style.display = "block";
|
||||
/*
|
||||
(function fade() {
|
||||
var val = parseFloat(el.style.opacity);
|
||||
if (!((val += .1) > 1)) {
|
||||
el.style.opacity = val;
|
||||
requestAnimationFrame(fade);
|
||||
}
|
||||
})(); */
|
||||
};
|
||||
|
||||
Show(el)
|
||||
{
|
||||
el.style.display = 'block';
|
||||
}
|
||||
|
||||
Hide(el)
|
||||
{
|
||||
el.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // class
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,544 @@
|
||||
'use strict';
|
||||
// MainScreen as an option for delegate functions
|
||||
class ShortPixelScreen extends ShortPixelScreenItemBase
|
||||
{
|
||||
isCustom = true;
|
||||
isMedia = true;
|
||||
type = 'custom';
|
||||
folderTree = null;
|
||||
currentSelectedPath = null;
|
||||
stopSignal = false;
|
||||
|
||||
Init()
|
||||
{
|
||||
super.Init();
|
||||
|
||||
this.InitFolderSelector();
|
||||
this.InitScanButtons();
|
||||
this.InitFileScreenAction();
|
||||
}
|
||||
|
||||
RenderItemView(e)
|
||||
{
|
||||
var data = e.detail;
|
||||
|
||||
if (data.custom)
|
||||
{
|
||||
var id = data.custom.id;
|
||||
var element = document.getElementById('sp-msg-' + id);
|
||||
element.outerHTML = data.custom.itemView;
|
||||
|
||||
var isOptimizable = data.custom.is_optimizable;
|
||||
var isRestorable = data.custom.is_restorable;
|
||||
|
||||
var inputSelect = document.querySelector('.item-' + id + ' input[name="select[]"]');
|
||||
|
||||
if (null === inputSelect)
|
||||
{
|
||||
console.warn('Checkbox not found ' + id);
|
||||
}
|
||||
|
||||
inputSelect.classList.remove('is-optimizable', 'is-restorable');
|
||||
if (true === isOptimizable)
|
||||
inputSelect.classList.add('is-optimizable');
|
||||
|
||||
if (true === isRestorable)
|
||||
inputSelect.classList.add('is-restorable');
|
||||
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the processor needs to start when items are being added / folders refreshed
|
||||
CheckProcessorStart()
|
||||
{
|
||||
// If automedia is active, see if something is to process.
|
||||
if (this.processor.IsAutoMediaActive())
|
||||
{
|
||||
this.processor.SetInterval(-1);
|
||||
this.processor.RunProcess();
|
||||
}
|
||||
}
|
||||
|
||||
RefreshFolder(id)
|
||||
{
|
||||
var data = {};
|
||||
data.id = id;
|
||||
data.type = 'folder';
|
||||
data.screen_action = 'refreshFolder';
|
||||
data.callback = 'shortpixel.folder.HandleFolderResult';
|
||||
|
||||
window.addEventListener('shortpixel.folder.HandleFolderResult', this.HandleFolderResult.bind(this), {'once':true});
|
||||
|
||||
// AjaxRequest should return result, which will go through Handleresponse, then LoaditemView.
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
StopMonitoringFolder(id)
|
||||
{
|
||||
|
||||
if (confirm('Are you sure you want to stop optimizing this folder? '))
|
||||
{
|
||||
var data = {};
|
||||
data.id = id;
|
||||
data.type = 'folder';
|
||||
data.screen_action = 'removeCustomFolder';
|
||||
data.callback = 'shortpixel.folder.HandleFolderResult';
|
||||
|
||||
window.addEventListener('shortpixel.folder.HandleFolderResult', this.HandleFolderResult.bind(this), {'once':true});
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
}
|
||||
|
||||
HandleFolderResult(e)
|
||||
{
|
||||
var data = e.detail;
|
||||
|
||||
if (data.folder)
|
||||
{
|
||||
var folder_id = data.folder.id;
|
||||
if (data.folder.message)
|
||||
{
|
||||
var el = document.querySelector('.shortpixel-other-media .item.item-' + folder_id + ' .status');
|
||||
if (null !== el)
|
||||
{
|
||||
el.innerHTML = data.folder.message;
|
||||
}
|
||||
else {
|
||||
console.error('Status Element not found for ' + folder_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.folder.fileCount)
|
||||
{
|
||||
var el = document.querySelector('.shortpixel-other-media .item.item-' + folder_id + ' .files-number');
|
||||
if (null !== el)
|
||||
{
|
||||
el.innerText = data.folder.fileCount;
|
||||
}
|
||||
else {
|
||||
console.error('FileCount Element not found for ' + folder_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.folder.action == 'remove')
|
||||
{
|
||||
if (true == data.folder.is_done)
|
||||
{
|
||||
var el = document.querySelector('.shortpixel-other-media .item.item-' + folder_id);
|
||||
if ( null !== el)
|
||||
{
|
||||
el.remove();
|
||||
}
|
||||
else {
|
||||
console.error('Row Element not found for ' + folder_id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.CheckProcessorStart();
|
||||
}
|
||||
|
||||
InitScanButtons()
|
||||
{
|
||||
var scanButtons = document.querySelectorAll('.scan-button');
|
||||
var self = this;
|
||||
|
||||
if (null !== scanButtons)
|
||||
{
|
||||
scanButtons.forEach(function (scanButton) {
|
||||
scanButton.addEventListener('click', self.StartFolderScanEvent.bind(self));
|
||||
});
|
||||
}
|
||||
|
||||
var stopButton = document.querySelector('.scan-actions .stop-button');
|
||||
if (null !== stopButton)
|
||||
{
|
||||
stopButton.addEventListener('click', this.StopScanEvent.bind(this));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InitFolderSelector()
|
||||
{
|
||||
var openModalButton = document.querySelector('.open-selectfolder-modal');
|
||||
if (null !== openModalButton)
|
||||
{
|
||||
openModalButton.addEventListener('click', this.OpenFolderModal.bind(this));
|
||||
}
|
||||
|
||||
var closeModalButtons = document.querySelectorAll('.shortpixel-modal input.select-folder-cancel, .sp-folder-picker-shade');
|
||||
|
||||
var self = this;
|
||||
closeModalButtons.forEach(function (button, index)
|
||||
{
|
||||
button.addEventListener('click', self.CloseFolderModal.bind(self));
|
||||
});
|
||||
|
||||
var addFolderButton = document.querySelector('.modal-folder-picker .select-folder')
|
||||
if (null !== addFolderButton)
|
||||
{
|
||||
addFolderButton.addEventListener('click', this.AddNewFolderEvent.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
InitFileScreenAction()
|
||||
{
|
||||
var selectAll = document.querySelector('input[name="select-all"]');
|
||||
if (null !== selectAll)
|
||||
selectAll.addEventListener('change', this.SelectAllItemsEvent.bind(this));
|
||||
|
||||
|
||||
var bulkAction = document.querySelector('button[name="doBulkAction"]');
|
||||
if (null !== bulkAction)
|
||||
bulkAction.addEventListener('click', this.BulkActionEvent.bind(this));
|
||||
|
||||
}
|
||||
|
||||
SelectAllItemsEvent(event)
|
||||
{
|
||||
var parent = event.target;
|
||||
var inputs = document.querySelectorAll('input[name="select[]"]');
|
||||
|
||||
var toggle = (true === parent.checked) ? true : false;
|
||||
|
||||
for(var i = 0; i < inputs.length; i++)
|
||||
{
|
||||
inputs[i].checked = toggle;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BulkActionEvent(event)
|
||||
{
|
||||
event.preventDefault();
|
||||
var target = event.target;
|
||||
|
||||
var items = document.querySelectorAll('input[name="select[]"]:checked');
|
||||
var selectBox = document.querySelector('select[name="bulk-actions"]');
|
||||
var selectedAction = selectBox.options[selectBox.selectedIndex];
|
||||
selectBox.selectedIndex = 0; // Return to default
|
||||
|
||||
var action = selectedAction.value;
|
||||
|
||||
|
||||
for (var i = 0; i < items.length; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
if (false == item.checked) // failsafe
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var item_id = item.value;
|
||||
|
||||
if ('optimize' === action)
|
||||
{
|
||||
if (item.classList.contains('is-optimizable'))
|
||||
{
|
||||
this.Optimize(item_id);
|
||||
}
|
||||
}
|
||||
else if ('restore' === action)
|
||||
{
|
||||
if (item.classList.contains('is-restorable'))
|
||||
{
|
||||
this.RestoreItem(item_id);
|
||||
}
|
||||
}
|
||||
else if ('mark-completed' === action)
|
||||
{
|
||||
if (item.classList.contains('is-optimizable'))
|
||||
{
|
||||
this.MarkCompleted(item_id);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
item.checked = false;
|
||||
}
|
||||
|
||||
var selectAll = document.querySelector('input[name="select-all"]');
|
||||
selectAll.checked = false;
|
||||
}
|
||||
|
||||
OpenFolderModal()
|
||||
{
|
||||
var shade = document.querySelector(".sp-folder-picker-shade");
|
||||
// this.FadeIn(shade, 500);
|
||||
this.Show(shade);
|
||||
|
||||
var picker = document.querySelector(".shortpixel-modal.modal-folder-picker");
|
||||
picker.classList.remove('shortpixel-hide');
|
||||
picker.style.display = 'block';
|
||||
|
||||
var picker = document.querySelector(".sp-folder-picker");
|
||||
|
||||
if (null === this.folderTree)
|
||||
{
|
||||
this.folderTree = new ShortPixelFolderTree(picker, this.processor);
|
||||
picker.addEventListener('shortpixel-folder.selected', this.HandleFolderSelectedEvent.bind(this));
|
||||
}
|
||||
|
||||
this.Show(picker);
|
||||
}
|
||||
|
||||
HandleFolderSelectedEvent(event)
|
||||
{
|
||||
var data = event.detail;
|
||||
var relpath = data.relpath;
|
||||
|
||||
var selectedField = document.querySelector('.sp-folder-picker-selected');
|
||||
selectedField.textContent = relpath;
|
||||
|
||||
this.currentSelectedPath = relpath;
|
||||
|
||||
if (null !== this.currentSelectedPath)
|
||||
{
|
||||
var addFolderButton = document.querySelector('.modal-folder-picker .select-folder');
|
||||
if (null !== addFolderButton)
|
||||
{
|
||||
addFolderButton.disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseFolderModal()
|
||||
{
|
||||
var shade = document.querySelector(".sp-folder-picker-shade");
|
||||
this.Hide(shade);
|
||||
|
||||
// @todo FadeOut function here
|
||||
var picker = document.querySelector('.shortpixel-modal.modal-folder-picker');
|
||||
this.Hide(picker);
|
||||
}
|
||||
|
||||
AddNewFolderEvent(event)
|
||||
{
|
||||
var data = {};
|
||||
data.relpath = this.currentSelectedPath;
|
||||
data.type = 'folder';
|
||||
data.screen_action = 'addCustomFolder';
|
||||
data.callback = 'shortpixel.folder.AddNewDirectory';
|
||||
|
||||
// @todo this message logic should prob. become part of the folder selector js proper.
|
||||
var messageEl = document.querySelector('.modal-folder-picker .folder-message');
|
||||
if (null !== messageEl)
|
||||
{
|
||||
if ( false == messageEl.classList.contains('hidden'))
|
||||
{
|
||||
messageEl.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('shortpixel.folder.AddNewDirectory', this.UpdateFolderViewEvent.bind(this), {'once':true});
|
||||
|
||||
this.processor.AjaxRequest(data);
|
||||
|
||||
|
||||
}
|
||||
|
||||
UpdateFolderViewEvent(event)
|
||||
{
|
||||
var data = event.detail;
|
||||
|
||||
// not for us.
|
||||
if (false === data.folder)
|
||||
return false;
|
||||
|
||||
if (data.folder.result && data.folder.result.itemView)
|
||||
{
|
||||
var element = document.querySelector('.list-overview .item');
|
||||
var elementHeading = document.querySelector('.list-overview .heading');
|
||||
|
||||
if (null !== element)
|
||||
{
|
||||
element.insertAdjacentHTML('beforebegin', data.folder.result.itemView);
|
||||
}
|
||||
else if (null !== elementHeading) // In case list is empty.
|
||||
{
|
||||
elementHeading.insertAdjacentHTML('afterend', data.folder.result.itemView);
|
||||
var noitems = document.querySelector('.list-overview .no-items');
|
||||
if (null !== noitems)
|
||||
noitems.remove();
|
||||
}
|
||||
|
||||
this.CloseFolderModal();
|
||||
this.CheckProcessorStart();
|
||||
|
||||
}
|
||||
else if (data.folder.is_error == true && data.folder.message)
|
||||
{
|
||||
var messageEl = document.querySelector('.modal-folder-picker .folder-message');
|
||||
if (null !== messageEl)
|
||||
{
|
||||
messageEl.textContent = data.folder.message;
|
||||
messageEl.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StartFolderScanEvent(event)
|
||||
{
|
||||
var element = event.target;
|
||||
this.stopSignal = false;
|
||||
this.ToggleScanInterface(true);
|
||||
|
||||
var force = false;
|
||||
if ('mode' in element.dataset)
|
||||
{
|
||||
var force = true;
|
||||
}
|
||||
|
||||
var reportElement = document.querySelector('.scan-area .result-table');
|
||||
while(reportElement.firstChild)
|
||||
{
|
||||
reportElement.firstChild.remove();
|
||||
}
|
||||
|
||||
var args = [];
|
||||
args.force = force;
|
||||
|
||||
if (true === force)
|
||||
{
|
||||
var data = {};
|
||||
data.type = 'folder';
|
||||
data.screen_action = 'resetScanFolderChecked';
|
||||
data.callback = 'shortpixel.folder.ScanFolder';
|
||||
|
||||
window.addEventListener('shortpixel.folder.ScanFolder', this.ScanFolder.bind(this, args), {'once':true});
|
||||
this.processor.AjaxRequest(data);
|
||||
|
||||
}
|
||||
else {
|
||||
this.ScanFolder(args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ScanFolder(args)
|
||||
{
|
||||
if (true === this.stopSignal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var data = {};
|
||||
data.type = 'folder';
|
||||
data.screen_action = 'scanNextFolder';
|
||||
data.callback = 'shortpixel.folder.ScannedDirectoryEvent';
|
||||
|
||||
if (true === args.force)
|
||||
{
|
||||
data.force = args.force;
|
||||
}
|
||||
|
||||
window.addEventListener('shortpixel.folder.ScannedDirectoryEvent', this.ScannedDirectoryEvent.bind(this, args), {'once':true});
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
ScannedDirectoryEvent(args, event)
|
||||
{
|
||||
var data = event.detail;
|
||||
data = data.folder;
|
||||
|
||||
var reportElement = document.querySelector('.scan-area .result-table');
|
||||
if ( null === reportElement)
|
||||
{
|
||||
console.error('Something wrong with reporting element');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.is_done === true)
|
||||
{
|
||||
// @todo Probably emit some done status here
|
||||
var div = document.createElement('div');
|
||||
div.classList.add('message');
|
||||
div.textContent = data.result.message;
|
||||
this.ToggleScanInterface(false);
|
||||
|
||||
reportElement.appendChild(div);
|
||||
}
|
||||
else if (data.result)
|
||||
{
|
||||
var div = document.createElement('div');
|
||||
var span_path = document.createElement('span');
|
||||
var span_filecount = document.createElement('span');
|
||||
var span_message = document.createElement('span');
|
||||
|
||||
span_path.textContent = data.result.path;
|
||||
span_filecount.textContent = data.result.new_count;
|
||||
span_message.textContent = data.result.message;
|
||||
|
||||
div.appendChild(span_path);
|
||||
div.appendChild(span_filecount);
|
||||
div.appendChild(span_message);
|
||||
reportElement.appendChild(div);
|
||||
|
||||
var self = this;
|
||||
setTimeout( function () { self.ScanFolder(args) }, 200);
|
||||
}
|
||||
}
|
||||
|
||||
StopScanEvent(event)
|
||||
{
|
||||
this.stopSignal = true;
|
||||
|
||||
var reportElement = document.querySelector('.scan-area .result-table');
|
||||
if ( null === reportElement)
|
||||
{
|
||||
console.error('Something wrong with reporting element');
|
||||
return false;
|
||||
}
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.classList.add('message');
|
||||
div.textContent = this.strings.stopActionMessage;
|
||||
|
||||
reportElement.appendChild(div);
|
||||
|
||||
this.ToggleScanInterface(false);
|
||||
|
||||
}
|
||||
|
||||
ToggleScanInterface(show)
|
||||
{
|
||||
if (typeof show === 'undefined')
|
||||
{
|
||||
var show = true;
|
||||
}
|
||||
|
||||
var divs = document.querySelectorAll('.scan-actions > div');
|
||||
|
||||
divs.forEach(function(div){
|
||||
if (div.classList.contains('action-scan') && true === show)
|
||||
{
|
||||
div.classList.add('not-visible');
|
||||
}
|
||||
else if (div.classList.contains('action-scan') && false === show) {
|
||||
div.classList.remove('not-visible');
|
||||
}
|
||||
else if ( div.classList.contains('action-stop') && true === show)
|
||||
{
|
||||
div.classList.remove('not-visible');
|
||||
}
|
||||
else {
|
||||
div.classList.add('not-visible');
|
||||
}
|
||||
});
|
||||
|
||||
var output = document.querySelector('.scan-area .output');
|
||||
if (null !== output && true === show)
|
||||
{
|
||||
output.classList.remove('not-visible');
|
||||
}
|
||||
}
|
||||
|
||||
} // class
|
@ -0,0 +1,278 @@
|
||||
'use strict';
|
||||
|
||||
class ShortPixelScreenItemBase extends ShortPixelScreenBase
|
||||
{
|
||||
|
||||
type; // media / custom
|
||||
currentMessage = '';
|
||||
|
||||
constructor(MainScreen, processor)
|
||||
{
|
||||
super(MainScreen, processor);
|
||||
}
|
||||
|
||||
Init()
|
||||
{
|
||||
super.Init();
|
||||
|
||||
window.addEventListener('shortpixel.' + this.type + '.resumeprocessing', this.processor.ResumeProcess.bind(this.processor));
|
||||
window.addEventListener('shortpixel.RenderItemView', this.RenderItemView.bind(this) );
|
||||
}
|
||||
|
||||
HandleImage(resultItem, type)
|
||||
{
|
||||
if (type != this.type ) // We don't eat that here.
|
||||
return false;
|
||||
|
||||
if (typeof resultItem.result !== 'undefined')
|
||||
{
|
||||
// This is final, not more messing with this. In results (multiple) defined one level higher than result object, if single, it's in result.
|
||||
var item_id = typeof resultItem.item_id !== 'undefined' ? resultItem.item_id : resultItem.result.item_id;
|
||||
var message = resultItem.result.message;
|
||||
|
||||
var element = document.getElementById('sp-msg-' + item_id); // empty result box while getting
|
||||
if (typeof message !== 'undefined')
|
||||
{
|
||||
var isError = false;
|
||||
if (resultItem.result.is_error == true)
|
||||
isError = true;
|
||||
this.UpdateMessage(item_id, message, isError);
|
||||
}
|
||||
if (element !== null)
|
||||
{
|
||||
element.innerHTML = '';
|
||||
// var event = new CustomEvent('shortpixel.loadItemView', {detail: {'type' : type, 'id': result.id }}); // send for new item view.
|
||||
var fileStatus = this.processor.fStatus[resultItem.fileStatus];
|
||||
|
||||
if (fileStatus == 'FILE_SUCCESS' || fileStatus == 'FILE_RESTORED' || resultItem.result.is_done == true)
|
||||
{
|
||||
this.processor.LoadItemView({id: item_id, type: type});
|
||||
}
|
||||
else if (fileStatus == 'FILE_PENDING')
|
||||
{
|
||||
element.style.display = 'none';
|
||||
}
|
||||
//window.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
console.error('handleImage without Result', resultItem);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateMessage(id, message, isError)
|
||||
{
|
||||
|
||||
var element = document.getElementById('sp-message-' + id);
|
||||
if (typeof isError === 'undefined')
|
||||
isError = false;
|
||||
|
||||
this.currentMessage = message;
|
||||
|
||||
if (element == null)
|
||||
{
|
||||
var parent = document.getElementById('sp-msg-' + id);
|
||||
if (parent !== null)
|
||||
{
|
||||
var element = document.createElement('div');
|
||||
element.classList.add('message');
|
||||
element.setAttribute('id', 'sp-message-' + id);
|
||||
parent.parentNode.insertBefore(element, parent.nextSibling);
|
||||
}
|
||||
}
|
||||
|
||||
if (element !== null)
|
||||
{
|
||||
if (element.classList.contains('error'))
|
||||
element.classList.remove('error');
|
||||
|
||||
element.innerHTML = message;
|
||||
|
||||
if (isError)
|
||||
element.classList.add('error');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.processor.Debug('Update Message Column not found - ' + id);
|
||||
}
|
||||
}
|
||||
|
||||
// Show a message that an action has started.
|
||||
SetMessageProcessing(id)
|
||||
{
|
||||
var message = this.strings.startAction;
|
||||
|
||||
var loading = document.createElement('img');
|
||||
loading.width = 20;
|
||||
loading.height = 20;
|
||||
loading.src = this.processor.GetPluginUrl() + '/res/img/bulk/loading-hourglass.svg';
|
||||
|
||||
message += loading.outerHTML;
|
||||
this.UpdateMessage(id, message);
|
||||
}
|
||||
|
||||
UpdateStats(stats, type)
|
||||
{
|
||||
// for now, since we process both, only update the totals in tooltip.
|
||||
if ( type !== 'total')
|
||||
return;
|
||||
|
||||
var waiting = stats.in_queue + stats.in_process;
|
||||
this.processor.tooltip.RefreshStats(waiting);
|
||||
}
|
||||
|
||||
GeneralResponses(responses)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if (responses.length == 0) // no responses.
|
||||
return;
|
||||
|
||||
var shownId = []; // prevent the same ID from creating multiple tooltips. There will be punishment for this.
|
||||
|
||||
responses.forEach(function (element, index)
|
||||
{
|
||||
|
||||
if (element.id)
|
||||
{
|
||||
if (shownId.indexOf(element.id) > -1)
|
||||
{
|
||||
return; // skip
|
||||
}
|
||||
else
|
||||
{
|
||||
shownId.push(element.id);
|
||||
}
|
||||
}
|
||||
|
||||
var message = element.message;
|
||||
if (element.filename)
|
||||
message += ' - ' + element.filename;
|
||||
|
||||
self.processor.tooltip.AddNotice(message);
|
||||
if (self.processor.rStatus[element.code] == 'RESPONSE_ERROR')
|
||||
{
|
||||
|
||||
if (element.id)
|
||||
{
|
||||
var message = self.currentMessage;
|
||||
self.UpdateMessage(element.id, message + '<br>' + element.message);
|
||||
self.currentMessage = message; // don't overwrite with this, to prevent echo.
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorBox = document.getElementById('shortpixel-errorbox');
|
||||
if (errorBox)
|
||||
{
|
||||
var error = document.createElement('div');
|
||||
error.classList.add('error');
|
||||
error.innerHTML = element.message;
|
||||
errorBox.append(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// HandleItemError is handling from results / result, not ResponseController. Check if it has negative effects it's kinda off now.
|
||||
HandleItemError(result)
|
||||
{
|
||||
if (result.message && result.item_id)
|
||||
{
|
||||
this.UpdateMessage(result.item_id, result.message, true);
|
||||
}
|
||||
|
||||
if (typeof result.item_id !== 'undefined')
|
||||
{
|
||||
this.processor.LoadItemView({id: result.item_id, type: 'media'});
|
||||
}
|
||||
}
|
||||
|
||||
RestoreItem(id)
|
||||
{
|
||||
var data = {};
|
||||
data.id = id;
|
||||
data.type = this.type;
|
||||
data.screen_action = 'restoreItem';
|
||||
// AjaxRequest should return result, which will go through Handleresponse, then LoaditemView.
|
||||
this.SetMessageProcessing(id);
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
CancelOptimizeItem(id)
|
||||
{
|
||||
var data = {};
|
||||
data.id = id;
|
||||
data.type = this.type;
|
||||
data.screen_action = 'cancelOptimize';
|
||||
// AjaxRequest should return result, which will go through Handleresponse, then LoaditemView.
|
||||
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
ReOptimize(id, compression, action)
|
||||
{
|
||||
var data = {
|
||||
id : id ,
|
||||
compressionType: compression,
|
||||
type: this.type,
|
||||
screen_action: 'reOptimizeItem'
|
||||
};
|
||||
|
||||
if (typeof action !== 'undefined')
|
||||
{
|
||||
data.actionType = action;
|
||||
}
|
||||
|
||||
if (! this.processor.CheckActive())
|
||||
data.callback = 'shortpixel.' + this.type + '.resumeprocessing';
|
||||
|
||||
this.SetMessageProcessing(id);
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
Optimize(id, force)
|
||||
{
|
||||
var data = {
|
||||
id: id,
|
||||
type: this.type,
|
||||
screen_action: 'optimizeItem'
|
||||
}
|
||||
|
||||
if (typeof force !== 'undefined' && true == force)
|
||||
{
|
||||
data.flags = 'force';
|
||||
}
|
||||
|
||||
if (! this.processor.CheckActive())
|
||||
data.callback = 'shortpixel.' + this.type + '.resumeprocessing';
|
||||
|
||||
this.SetMessageProcessing(id);
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
MarkCompleted(id)
|
||||
{
|
||||
var data = {};
|
||||
data.id = id;
|
||||
data.type = this.type;
|
||||
data.screen_action = 'markCompleted';
|
||||
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
UnMarkCompleted(id)
|
||||
{
|
||||
var data = {};
|
||||
data.id = id;
|
||||
data.type = this.type;
|
||||
data.screen_action = 'unMarkCompleted';
|
||||
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
} // class
|
@ -0,0 +1,256 @@
|
||||
'use strict';
|
||||
|
||||
// MainScreen as an option for delegate functions
|
||||
class ShortPixelScreen extends ShortPixelScreenItemBase //= function (MainScreen, processor)
|
||||
{
|
||||
isCustom = true;
|
||||
isMedia = true;
|
||||
type = 'media';
|
||||
|
||||
Init()
|
||||
{
|
||||
super.Init();
|
||||
this.ListenGallery();
|
||||
}
|
||||
|
||||
RenderItemView(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
var data = e.detail;
|
||||
if (data.media)
|
||||
{
|
||||
var id = data.media.id;
|
||||
|
||||
var element = document.getElementById('sp-msg-' + id);
|
||||
if (element !== null) // Could be other page / not visible / whatever.
|
||||
element.outerHTML = data.media.itemView;
|
||||
else {
|
||||
console.error('Render element not found');
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error('Data not found - RenderItemview on media screen');
|
||||
}
|
||||
return false; // callback shouldn't do more, see processor.
|
||||
}
|
||||
|
||||
HandleImage(resultItem, type)
|
||||
{
|
||||
var res = super.HandleImage(resultItem, type);
|
||||
var fileStatus = this.processor.fStatus[resultItem.fileStatus];
|
||||
|
||||
// If image editor is active and file is being restored because of this reason ( or otherwise ), remove the warning if this one exists.
|
||||
if (fileStatus == 'FILE_RESTORED')
|
||||
{
|
||||
var warning = document.getElementById('shortpixel-edit-image-warning');
|
||||
if (warning !== null)
|
||||
{
|
||||
warning.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RedoLegacy(id)
|
||||
{
|
||||
var data = {
|
||||
id: id,
|
||||
type: 'media',
|
||||
screen_action: 'redoLegacy',
|
||||
}
|
||||
data.callback = 'shortpixel.LoadItemView';
|
||||
|
||||
window.addEventListener('shortpixel.LoadItemView', function (e) {
|
||||
var itemData = { id: e.detail.media.id, type: 'media' };
|
||||
this.processor.timesEmpty = 0; // reset the defer on this.
|
||||
this.processor.LoadItemView(itemData);
|
||||
this.UpdateMessage(itemData.id, '');
|
||||
|
||||
}.bind(this), {'once': true} );
|
||||
|
||||
this.SetMessageProcessing(id);
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
ListenGallery()
|
||||
{
|
||||
var self = this;
|
||||
if (typeof wp.media === 'undefined')
|
||||
{
|
||||
this.ListenEditAttachment(); // Edit Media edit attachment screen
|
||||
return;
|
||||
}
|
||||
|
||||
// This taken from S3-offload / media.js / Grid media gallery
|
||||
if (typeof wp.media.view.Attachment.Details.TwoColumn !== 'undefined')
|
||||
{
|
||||
var detailsColumn = wp.media.view.Attachment.Details.TwoColumn;
|
||||
var twoCol = true;
|
||||
}
|
||||
else {
|
||||
var detailsColumn = wp.media.view.Attachment.Details;
|
||||
var twoCol = false;
|
||||
}
|
||||
|
||||
var extended = detailsColumn.extend ({
|
||||
render: function()
|
||||
{
|
||||
detailsColumn.prototype.render.apply( this );
|
||||
this.fetchSPIOData(this.model.get( 'id' ));
|
||||
|
||||
return this;
|
||||
},
|
||||
fetchSPIOData : function (id)
|
||||
{
|
||||
var data = {};
|
||||
data.id = id;
|
||||
data.type = self.type;
|
||||
data.action = 'getItemView';
|
||||
data.callback = 'shortpixel.MediaRenderView';
|
||||
|
||||
window.addEventListener('shortpixel.MediaRenderView', this.renderSPIOView.bind(this), {'once':true});
|
||||
self.processor.LoadItemView(data);
|
||||
},
|
||||
|
||||
renderSPIOView: function(e, timed)
|
||||
{
|
||||
if (! e.detail || ! e.detail.media || ! e.detail.media.itemView)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var $spSpace = this.$el.find('.attachment-info .details');
|
||||
if ($spSpace.length === 0 && (typeof timed === 'undefined' || timed < 5))
|
||||
{
|
||||
// It's possible the render is slow or blocked by other plugins. Added a delay and retry bit later to draw.
|
||||
if (typeof timed === 'undefined')
|
||||
{
|
||||
var timed = 0;
|
||||
}
|
||||
else {
|
||||
timed++;
|
||||
}
|
||||
setTimeout(function () { this.renderSPIOView(e, true) }.bind(this), 1000);
|
||||
}
|
||||
|
||||
var html = this.doSPIORow(e.detail.media.itemView);
|
||||
|
||||
$spSpace.after(html);
|
||||
},
|
||||
doSPIORow : function(dataHtml)
|
||||
{
|
||||
var html = '';
|
||||
html += '<div class="shortpixel-popup-info">';
|
||||
html += '<label class="name">ShortPixel</label>';
|
||||
html += dataHtml;
|
||||
html += '</div>';
|
||||
return html;
|
||||
},
|
||||
editAttachment: function(event)
|
||||
{
|
||||
event.preventDefault();
|
||||
self.AjaxOptimizeWarningFromUnderscore(this.model.get( 'id' ));
|
||||
detailsColumn.prototype.editAttachment.apply( this, [event]);
|
||||
}
|
||||
});
|
||||
|
||||
if (true === twoCol)
|
||||
{
|
||||
wp.media.view.Attachment.Details.TwoColumn = extended; //wpAttachmentDetailsTwoColumn;
|
||||
}
|
||||
else {
|
||||
wp.media.view.Attachment.Details = extended;
|
||||
}
|
||||
}
|
||||
|
||||
AjaxOptimizeWarningFromUnderscore(id)
|
||||
{
|
||||
var data = {
|
||||
id: id,
|
||||
type: 'media',
|
||||
screen_action: 'getItemEditWarning',
|
||||
callback: 'ShortPixelMedia.getItemEditWarning'
|
||||
};
|
||||
|
||||
window.addEventListener('ShortPixelMedia.getItemEditWarning', this.CheckOptimizeWarning.bind(this), {'once': true} );
|
||||
this.processor.AjaxRequest(data);
|
||||
}
|
||||
|
||||
CheckOptimizeWarning(event)
|
||||
{
|
||||
var data = event.detail;
|
||||
|
||||
var image_post_id = data.id;
|
||||
var is_restorable = data.is_restorable;
|
||||
var is_optimized = data.is_optimized;
|
||||
|
||||
if ('true' === is_restorable || 'true' === is_optimized)
|
||||
{
|
||||
this.ShowOptimizeWarning(image_post_id, is_restorable, is_optimized);
|
||||
}
|
||||
}
|
||||
|
||||
ShowOptimizeWarning(image_post_id, is_restorable, is_optimized)
|
||||
{
|
||||
var div = document.createElement('div');
|
||||
div.id = 'shortpixel-edit-image-warning';
|
||||
div.classList.add('shortpixel', 'shortpixel-notice', 'notice-warning');
|
||||
|
||||
|
||||
if ('true' == is_restorable)
|
||||
{
|
||||
var restore_link = spio_media.restore_link.replace('#post_id#', image_post_id);
|
||||
div.innerHTML = '<p>' + spio_media.optimized_text + ' <a href="' + restore_link + '">' + spio_media.restore_link_text + '</a></p>' ;
|
||||
}
|
||||
else {
|
||||
div.innerHTML = '<p>' + spio_media.optimized_text + ' ' + spio_media.restore_link_text_unrestorable + '</p>' ;
|
||||
|
||||
}
|
||||
// only if not existing.
|
||||
if (document.getElementById('shortpixel-edit-image-warning') == null)
|
||||
{
|
||||
var $menu = jQuery('.imgedit-menu');
|
||||
if ($menu.length > 0)
|
||||
{
|
||||
$menu.append(div);
|
||||
}
|
||||
else {
|
||||
jQuery(document).one('image-editor-ui-ready', function() // one!
|
||||
{
|
||||
jQuery('.imgedit-menu').append(div);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This should be the edit-attachment screen
|
||||
ListenEditAttachment()
|
||||
{
|
||||
var self = this;
|
||||
var imageEdit = window.imageEdit;
|
||||
|
||||
jQuery(document).on('image-editor-ui-ready', function()
|
||||
{
|
||||
var element = document.querySelector('input[name="post_ID"]');
|
||||
if (null === element)
|
||||
{
|
||||
console.error('Could not fetch post id on this screen');
|
||||
return;
|
||||
}
|
||||
|
||||
var post_id = element.value;
|
||||
|
||||
var data = {
|
||||
id: post_id,
|
||||
type: 'media',
|
||||
screen_action: 'getItemEditWarning',
|
||||
callback: 'ShortPixelMedia.getItemEditWarning'
|
||||
};
|
||||
|
||||
window.addEventListener('ShortPixelMedia.getItemEditWarning', self.CheckOptimizeWarning.bind(self), {'once': true} );
|
||||
window.ShortPixelProcessor.AjaxRequest(data);
|
||||
});
|
||||
}
|
||||
|
||||
} // class
|
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
// MainScreen as an option for delegate functions
|
||||
class ShortPixelScreen extends ShortPixelScreenBase
|
||||
{
|
||||
|
||||
Init()
|
||||
{
|
||||
super.Init();
|
||||
this.ListenPLUpload();
|
||||
}
|
||||
|
||||
|
||||
// Only listening on the nolist ( and more specific -> media addnew) , since the post editor classic/ gutenberg and others have this interface otherwise hidden.
|
||||
ListenPLUpload() {
|
||||
|
||||
// Most screen will not have uploader defined or ready.
|
||||
if (typeof uploader === 'undefined' || uploader === null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
uploader.bind('UploadComplete', function (up, file, response)
|
||||
{
|
||||
// Give processor a swoop when uploading is done, while respecting set boundaries.
|
||||
self.processor.RunProcess();
|
||||
});
|
||||
}
|
||||
|
||||
} // class
|
@ -0,0 +1,219 @@
|
||||
'use strict';
|
||||
|
||||
// Goals : Javascript plain folder/fileBrowser (filetree)
|
||||
// : Crawler to scan / refresh folders via ajax / JSON
|
||||
//
|
||||
|
||||
class ShortPixelFolderTree
|
||||
{
|
||||
strings = [];
|
||||
icons = [];
|
||||
didInit = false;
|
||||
parentElement;
|
||||
processor = null;
|
||||
|
||||
loadedFolders = [];
|
||||
|
||||
|
||||
|
||||
constructor(element, processor)
|
||||
{
|
||||
//this.processor = processor;
|
||||
this.parentElement = element;
|
||||
this.processor = processor;
|
||||
this.Init();
|
||||
}
|
||||
|
||||
Init()
|
||||
{
|
||||
if (true === this.didInit)
|
||||
return;
|
||||
|
||||
this.strings = spio_folderbrowser.strings;
|
||||
this.icons = spio_folderbrowser.icons;
|
||||
|
||||
this.ShowLoading();
|
||||
this.AjaxLoadFolders('');
|
||||
|
||||
this.didInit = true;
|
||||
}
|
||||
|
||||
BuildElement()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ShowLoading()
|
||||
{
|
||||
var loading = document.createElement('div');
|
||||
var h3 = document.createElement('h3');
|
||||
loading.classList.add('loading');
|
||||
|
||||
h3.textContent = this.strings.loading;
|
||||
|
||||
loading.appendChild(h3);
|
||||
this.parentElement.append(loading);
|
||||
}
|
||||
|
||||
RemoveLoading()
|
||||
{
|
||||
var elements = document.querySelectorAll('.sp-folder-picker .loading')
|
||||
elements.forEach(function(element) {
|
||||
element.remove();
|
||||
})
|
||||
}
|
||||
|
||||
LoadFolderEvent(e)
|
||||
{
|
||||
var data = e.detail;
|
||||
var folders = data.folder.folders;
|
||||
this.RemoveLoading();
|
||||
|
||||
if (data.folder.is_error == 'true') // error / emtpy result handlers.
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
var parent = this.parentElement;
|
||||
if (data.folder.relpath !== '')
|
||||
{
|
||||
|
||||
var child = document.querySelector('[data-relpath="' + data.folder.relpath + '"]');
|
||||
|
||||
if (child !== null)
|
||||
{
|
||||
parent = child;
|
||||
//child.classList.remove('closed');
|
||||
//child.classList.add('open');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var ul = document.createElement('ul');
|
||||
ul.classList.add('loaded', 'expanded');
|
||||
ul.dataset.loadpath = data.folder.relpath;
|
||||
|
||||
folders.forEach(function(element) {
|
||||
// console.log(element);
|
||||
var li = document.createElement('li');
|
||||
li.dataset.relpath = element.relpath;
|
||||
li.classList.add('folder','closed');
|
||||
|
||||
if ( element.is_active && true === element.is_active)
|
||||
{
|
||||
li.classList.add('is_active');
|
||||
}
|
||||
|
||||
var link = document.createElement('a');
|
||||
|
||||
var icon = document.createElement('i');
|
||||
icon.classList.add('icon');
|
||||
link.appendChild(icon);
|
||||
link.innerHTML += element.name;
|
||||
link.addEventListener('click', self.ToggleFolderContentsEvent.bind(self));
|
||||
|
||||
li.appendChild(link);
|
||||
|
||||
ul.appendChild(li);
|
||||
});
|
||||
|
||||
parent.appendChild(ul); // add the tree.
|
||||
}
|
||||
|
||||
// @Todo : find out how to keep track of previously selected items (and switch them out)
|
||||
// + Emit a singal (trigger event) to external when something is selected, so UX / hidden field can add them in custom.js
|
||||
ToggleFolderContentsEvent(e)
|
||||
{
|
||||
var anchor = e.target;
|
||||
var li = e.target.parentElement;
|
||||
if (li.tagName !== 'LI')
|
||||
{
|
||||
var li = li.parentElement;
|
||||
}
|
||||
|
||||
// Is classList is_active ( meaning already selected a custom folder ) do nothing with both selection and subfolders
|
||||
if (true === li.classList.contains('is_active'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all previous selected thingies.
|
||||
var openElements = this.parentElement.querySelectorAll('.folder.selected');
|
||||
openElements.forEach(function (element)
|
||||
{
|
||||
element.classList.remove('selected');
|
||||
//element.classList.add('closed');
|
||||
});
|
||||
|
||||
var relpath = li.dataset.relpath;
|
||||
var childTree = document.querySelector('[data-loadpath="' + relpath + '"]');
|
||||
|
||||
if (li.classList.contains('closed'))
|
||||
{
|
||||
if (null === childTree)
|
||||
{
|
||||
this.AjaxLoadFolders(relpath);
|
||||
}
|
||||
else {
|
||||
childTree.classList.add('expanded');
|
||||
childTree.classList.remove('collapsed');
|
||||
}
|
||||
|
||||
li.classList.remove('closed');
|
||||
li.classList.add('open');
|
||||
|
||||
// var img = li.querySelector('img');
|
||||
//img.src = this.icons.folder_open;
|
||||
|
||||
|
||||
}
|
||||
else if (li.classList.contains('open'))
|
||||
{
|
||||
if (null !== childTree)
|
||||
{
|
||||
childTree.classList.remove('expanded');
|
||||
childTree.classList.add('collapsed');
|
||||
}
|
||||
|
||||
li.classList.remove('open')
|
||||
li.classList.add('closed');
|
||||
// var img = li.querySelector('img');
|
||||
// img.src = this.icons.folder_closed;
|
||||
}
|
||||
|
||||
li.classList.add('selected');
|
||||
var selectEvent = new CustomEvent('shortpixel-folder.selected', { 'detail': {'relpath': relpath}});
|
||||
this.parentElement.dispatchEvent(selectEvent);
|
||||
|
||||
}
|
||||
|
||||
GetFolderIcon(name)
|
||||
{
|
||||
var svg = document.createElement('img');
|
||||
svg.src = this.icons.folder_closed;
|
||||
svg.style.width = '20px';
|
||||
svg.style.height = '20px';
|
||||
return svg;
|
||||
|
||||
}
|
||||
|
||||
AjaxLoadFolders(relpath)
|
||||
{
|
||||
var folderbase = this.folderbase;
|
||||
|
||||
var data = {
|
||||
type: 'folder',
|
||||
screen_action: 'browseFolders',
|
||||
relPath: relpath,
|
||||
callback: 'shortpixel.folder.LoadFolders',
|
||||
};
|
||||
|
||||
window.addEventListener('shortpixel.folder.LoadFolders', this.LoadFolderEvent.bind(this), {'once':true});
|
||||
|
||||
this.processor.AjaxRequest(data);
|
||||
|
||||
}
|
||||
|
||||
} // class
|
@ -0,0 +1,53 @@
|
||||
'use strict';
|
||||
|
||||
(function( $) {
|
||||
|
||||
if (typeof wp.media === 'undefined' || typeof wp.media.frame === 'undefined')
|
||||
{
|
||||
return;
|
||||
}
|
||||
var ShortPixelFilter = wp.media.view.AttachmentFilters.extend
|
||||
({
|
||||
id: 'shortpixel-media-filter',
|
||||
|
||||
createFilters: function() {
|
||||
var filters = {};
|
||||
var optimizedfilter = spio_media.mediafilters.optimized;
|
||||
|
||||
for (const [key,value] of Object.entries(optimizedfilter))
|
||||
{
|
||||
filters[key] = {
|
||||
text: value,
|
||||
props: { 'shortpixel_status': key },
|
||||
priority: 10,
|
||||
}
|
||||
};
|
||||
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
}); // ShortPixelFilter
|
||||
|
||||
var AttachmentsBrowser = wp.media.view.AttachmentsBrowser;
|
||||
|
||||
wp.media.view.AttachmentsBrowser = wp.media.view.AttachmentsBrowser.extend({
|
||||
createToolbar: function() {
|
||||
|
||||
// Make sure to load the original toolbar
|
||||
AttachmentsBrowser.prototype.createToolbar.call( this );
|
||||
|
||||
this.toolbar.set(
|
||||
'ShortPixelFilter',
|
||||
new ShortPixelFilter({
|
||||
controller: this.controller,
|
||||
model: this.collection.props,
|
||||
priority: -80
|
||||
})
|
||||
.render()
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
})( jQuery);
|
||||
|
||||
//}); // jquery - Attachmentfilters
|
@ -0,0 +1,678 @@
|
||||
|
||||
/*** ShortPixel Image Processor ***
|
||||
* The processor sends via a browser worker tasks in form of Ajax Request to the browser
|
||||
* Ajax returns from browser are processed and then delegated to the screens
|
||||
* Every function starts via capitals and camelcased i.e. LoadWorker
|
||||
* Normal variables are camel-cased.
|
||||
*
|
||||
* The remote secret is to prevent several browser clients on different computers but on same site to start processing.
|
||||
* This is to limit performance usages on sites with a large number of backend users.
|
||||
*
|
||||
* -- Screens --
|
||||
* A Screen is responsible for putting received values to UI
|
||||
* Required function of screen are : HandleImage HandleError UpdateStats
|
||||
* Optional functions : QueueStatus, GeneralResponses
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
window.ShortPixelProcessor =
|
||||
{
|
||||
// spp: {},
|
||||
isActive: false, // Is the processor active in this window - at all - . Transient
|
||||
defaultInterval: 3000, // @todo customize this from backend var, hook filter. default is onload interval
|
||||
interval: 3000, // is current interval. When nothing to be done increases
|
||||
deferInterval: 15000, // how long to wait between interval to check for new items.
|
||||
screen: null, // UI Object
|
||||
tooltip: null, // Tooltip object to show in WP admin bar
|
||||
isBulkPage: false, // Bypass secret check when bulking, because customer explicitly requests it.
|
||||
localSecret: null, // Local processorkey stored (or empty)
|
||||
remoteSecret: null, // Remote key indicating who has process right ( or null )
|
||||
isManualPaused: false, // tooltip pause :: do not set directly, but only through processor functions!
|
||||
autoMediaLibrary: false,
|
||||
worker: null, // HTTP worker to send requests ( worker.js )
|
||||
timer: null, // Timer to determine waiting time between actions
|
||||
timer_recheckactive: null,
|
||||
waitingForAction: false, // used if init yields results that should pause the processor.
|
||||
timesEmpty: 0, // number of times queue came up empty.
|
||||
nonce: [],
|
||||
debugIsActive : false, // indicating is SPIO is in debug mode. Don't report certain things if not.
|
||||
hasStartQuota: false, // if we start without quota, don't notice too much, don't run.
|
||||
workerErrors: 0, // times worker encoutered an error.
|
||||
qStatus: { // The Queue returns
|
||||
1: 'QUEUE_ITEMS',
|
||||
4: 'QUEUE_WAITING',
|
||||
10: 'QUEUE_EMPTY',
|
||||
2: 'PREPARING',
|
||||
3: 'PREPARING_DONE',
|
||||
11: 'PREPARING_RECOUNT',
|
||||
},
|
||||
fStatus: { // FileStatus of ImageModel
|
||||
'-1': 'FILE_ERROR',
|
||||
1: 'FILE_PENDING',
|
||||
2: 'FILE_DONE',
|
||||
3: 'FILE_RESTORED',
|
||||
},
|
||||
rStatus: { // ResponseController
|
||||
1: 'RESPONSE_ACTION', // when an action has been performed *not used*
|
||||
2: 'RESPONSE_SUCCESS', // not sure this one is needed *not used*
|
||||
10: 'RESPONSE_ERROR',
|
||||
11: 'RESPONSE_WARNING', // *not used*
|
||||
12: 'RESPONSE_ERROR_DELAY', // when an error is serious enough to delay things.*not used*
|
||||
},
|
||||
aStatusError: { // AjaxController / optimizeController - when an error occured
|
||||
'-1': 'PROCESSOR_ACTIVE', // active in another window
|
||||
'-2': 'NONCE_FAILED',
|
||||
'-3': 'NO_STATUS',
|
||||
'-4': 'APIKEY_FAILED',
|
||||
'-5': 'NOQUOTA',
|
||||
'-10': 'SERVER FAILURE',
|
||||
'-903': 'TIMEOUT', // SPIO shortQ retry limit reached.
|
||||
},
|
||||
|
||||
Load: function(hasQuota)
|
||||
{
|
||||
|
||||
window.addEventListener('error', this.ScriptError.bind(this));
|
||||
|
||||
this.isBulkPage = ShortPixelProcessorData.isBulkPage;
|
||||
this.localSecret = localStorage.getItem('bulkSecret');
|
||||
|
||||
this.remoteSecret = ShortPixelProcessorData.bulkSecret;
|
||||
this.debugIsActive = ShortPixelProcessorData.debugIsActive;
|
||||
|
||||
this.nonce['process'] = ShortPixelProcessorData.nonce_process;
|
||||
this.nonce['exit'] = ShortPixelProcessorData.nonce_exit;
|
||||
this.nonce['itemview'] = ShortPixelProcessorData.nonce_itemview;
|
||||
this.nonce['ajaxRequest'] = ShortPixelProcessorData.nonce_ajaxrequest;
|
||||
|
||||
this.autoMediaLibrary = (ShortPixelProcessorData.autoMediaLibrary == 'true') ? true : false;
|
||||
|
||||
if (hasQuota == 1)
|
||||
this.hasStartQuota = true;
|
||||
|
||||
if (ShortPixelProcessorData.interval && ShortPixelProcessorData.interval > 100)
|
||||
this.interval = ShortPixelProcessorData.interval;
|
||||
|
||||
if (ShortPixelProcessorData.interval && ShortPixelProcessorData.interval > 100)
|
||||
this.deferInterval = ShortPixelProcessorData.deferInterval;
|
||||
|
||||
console.log('Start Data from Server', ShortPixelProcessorData.startData, this.interval, this.deferInterval);
|
||||
console.log('remoteSecret ' + this.remoteSecret + ', localsecret: ' + this.localSecret);
|
||||
|
||||
|
||||
this.tooltip = new ShortPixelToolTip({}, this);
|
||||
|
||||
if (typeof ShortPixelScreen == 'undefined')
|
||||
{
|
||||
console.error('Missing Screen!');
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.screen = new ShortPixelScreen({}, this);
|
||||
this.screen.Init();
|
||||
}
|
||||
|
||||
// Load the Startup Data (needs screen)
|
||||
this.tooltip.InitStats();
|
||||
|
||||
// Always load worker, also used for UI actions.
|
||||
this.LoadWorker();
|
||||
|
||||
if (this.CheckActive())
|
||||
{
|
||||
if (this.hasStartQuota)
|
||||
this.RunProcess();
|
||||
}
|
||||
|
||||
},
|
||||
CheckActive: function()
|
||||
{
|
||||
|
||||
if (this.remoteSecret == false || this.remoteSecret == '' || this.isBulkPage) // if remoteSecret is false, we are the first process. Take it.
|
||||
{
|
||||
if (this.localSecret && this.localSecret.length > 0)
|
||||
{
|
||||
this.remoteSecret = this.localSecret;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.localSecret = Math.random().toString(36).substring(7);
|
||||
localStorage.setItem('bulkSecret',this.localSecret);
|
||||
// tell worker to use correct key.
|
||||
this.worker.postMessage({'action' : 'updateLocalSecret',
|
||||
'key': this.localSecret });
|
||||
}
|
||||
this.isActive = true;
|
||||
}
|
||||
else if (this.remoteSecret === this.localSecret) // There is a secret, we are the processor.
|
||||
{
|
||||
this.isActive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log('Check Active: Processor not active - ' + this.remoteSecret + ' - ' + this.localSecret);
|
||||
|
||||
this.tooltip.ProcessEnd();
|
||||
this.StopProcess();
|
||||
|
||||
if (null === this.timer_recheckactive)
|
||||
{
|
||||
var threemin = 180000; // TTL for a processorkey is 2 minutes now, so wait a broad 3 and check again
|
||||
this.timer_recheckactive = window.setTimeout(this.RecheckProcessor.bind(this), threemin );
|
||||
console.log('Waiting for recheckActive ', this.timer_recheckactive);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.isManualPaused)
|
||||
{
|
||||
this.isActive = false;
|
||||
console.debug('Check Active: Paused');
|
||||
}
|
||||
if (this.waitingForAction)
|
||||
{
|
||||
this.isActive = false;
|
||||
this.tooltip.ProcessEnd();
|
||||
console.debug('Check Active : Waiting for action');
|
||||
}
|
||||
return this.isActive;
|
||||
},
|
||||
|
||||
RecheckProcessor: function()
|
||||
{
|
||||
var data = {
|
||||
'screen_action': 'recheckActive',
|
||||
'callback': 'shortpixel.recheckActive',
|
||||
};
|
||||
|
||||
window.addEventListener('shortpixel.recheckActive', this.RecheckedActiveEvent.bind(this), {'once': true});
|
||||
this.AjaxRequest(data);
|
||||
|
||||
},
|
||||
RecheckedActiveEvent: function(event)
|
||||
{
|
||||
var data = event.detail;
|
||||
|
||||
// cleanse the timer;
|
||||
if (this.timer_recheckactive)
|
||||
{
|
||||
window.clearTimeout(this.timer_recheckactive);
|
||||
this.timer_recheckactive = null;
|
||||
}
|
||||
|
||||
if (true === data.status)
|
||||
{
|
||||
if (typeof data.processorKey !== 'undefined')
|
||||
{
|
||||
this.remoteSecret = data.processorKey;
|
||||
}
|
||||
else { // this happens when it's released, but client doens't have a localsecret, the remotesecret is not returned by request. Set to null and go probably should work in all cases.
|
||||
this.remoteSecret = null;
|
||||
}
|
||||
var bool = this.CheckActive();
|
||||
if (true === bool)
|
||||
{
|
||||
this.timesEmpty = 0; // reset the times empty to start fresh.
|
||||
this.RunProcess();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If key was not given, this should retrigger the next event.
|
||||
this.CheckActive();
|
||||
}
|
||||
|
||||
},
|
||||
LoadWorker: function()
|
||||
{
|
||||
if (window.Worker)
|
||||
{
|
||||
var ajaxURL = ShortPixel.AJAX_URL;
|
||||
var nonce = '';
|
||||
console.log('Starting Worker');
|
||||
|
||||
this.worker = new Worker(ShortPixelProcessorData.workerURL);
|
||||
|
||||
var isBulk = false;
|
||||
if (this.isBulkPage)
|
||||
isBulk = true;
|
||||
|
||||
this.worker.postMessage({'action' : 'setEnv',
|
||||
'data': {'isBulk' : isBulk, 'isMedia': this.screen.isMedia, 'isCustom': this.screen.isCustom, 'ajaxUrl' : ajaxURL, 'secret' : this.localSecret}
|
||||
});
|
||||
|
||||
/*this.worker.postMessage({'action': 'init', 'data' : [ajaxURL, this.localSecret], 'isBulk' : isBulk}); */
|
||||
this.worker.onmessage = this.CheckResponse.bind(this);
|
||||
window.addEventListener('beforeunload', this.ShutDownWorker.bind(this));
|
||||
|
||||
}
|
||||
},
|
||||
ShutDownWorker: function()
|
||||
{
|
||||
if (this.worker === null) // worker already shut / not loaded
|
||||
return false;
|
||||
|
||||
console.log('Shutting down Worker');
|
||||
this.worker.postMessage({'action' : 'shutdown', 'nonce': this.nonce['exit'] });
|
||||
this.worker = null;
|
||||
window.removeEventListener('beforeunload', this.ShutDownWorker.bind(this));
|
||||
window.removeEventListener('shortpixel.loadItemView', this.LoadItemView.bind(this));
|
||||
},
|
||||
Process: function()
|
||||
{
|
||||
if (this.worker === null)
|
||||
{
|
||||
this.LoadWorker(); // JIT worker loading
|
||||
}
|
||||
|
||||
this.worker.postMessage({action: 'process', 'nonce' : this.nonce['process']});
|
||||
},
|
||||
RunProcess: function()
|
||||
{
|
||||
if (this.timer)
|
||||
{
|
||||
window.clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
|
||||
if (! this.CheckActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.timer_recheckactive)
|
||||
{
|
||||
window.clearTimeout(this.timer_recheckactive);
|
||||
this.timer_recheckactive = null;
|
||||
}
|
||||
|
||||
console.log('Processor: Run Process in ' + this.interval);
|
||||
|
||||
this.timer = window.setTimeout(this.Process.bind(this), this.interval);
|
||||
},
|
||||
IsAutoMediaActive: function()
|
||||
{
|
||||
return this.autoMediaLibrary;
|
||||
},
|
||||
PauseProcess: function() // This is a manual intervention.
|
||||
{
|
||||
this.isManualPaused = true;
|
||||
var event = new CustomEvent('shortpixel.processor.paused', { detail : {paused: this.isManualPaused }});
|
||||
window.dispatchEvent(event);
|
||||
console.log('Processor: Process Paused');
|
||||
window.clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
|
||||
},
|
||||
StopProcess: function(args)
|
||||
{
|
||||
console.log('Stop Processing Signal #' + this.timer);
|
||||
|
||||
// @todo this can probably go? Why would StopProcess cancel Manual pauses?
|
||||
if (this.isManualPaused == true) /// processor ends on status paused.
|
||||
{
|
||||
this.isManualPaused = false;
|
||||
var event = new CustomEvent('shortpixel.processor.paused', { detail : {paused: this.isManualPaused}});
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
window.clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
|
||||
if (typeof args == 'object')
|
||||
{
|
||||
if (typeof args.defer !== 'undefined' && args.defer)
|
||||
{
|
||||
this.timesEmpty++;
|
||||
console.log('Stop, defer wait :' + (this.deferInterval * this.timesEmpty), this.timesEmpty);
|
||||
this.SetInterval( (this.deferInterval * this.timesEmpty) ); //set a long interval
|
||||
this.RunProcess(); // queue a run once
|
||||
this.SetInterval(-1); // restore interval
|
||||
}
|
||||
else if (typeof args.waiting !== 'undefined')
|
||||
{
|
||||
console.log('Stop Process: Waiting for action');
|
||||
this.waitingForAction = args.waiting;
|
||||
}
|
||||
}
|
||||
|
||||
this.tooltip.ProcessEnd();
|
||||
},
|
||||
ResumeProcess: function()
|
||||
{
|
||||
this.isManualPaused = false;
|
||||
this.waitingForAction = false;
|
||||
localStorage.setItem('tooltipPause','false'); // also remove the cookie so it doesn't keep hanging on page refresh.
|
||||
|
||||
var event = new CustomEvent('shortpixel.processor.paused', { detail : {paused: this.isManualPaused}});
|
||||
window.dispatchEvent(event);
|
||||
|
||||
this.Process(); // don't wait the interval to go on resume.
|
||||
},
|
||||
SetInterval: function(interval)
|
||||
{
|
||||
if (interval == -1)
|
||||
this.interval = this.defaultInterval;
|
||||
else
|
||||
this.interval = interval;
|
||||
|
||||
},
|
||||
CheckResponse: function(message)
|
||||
{
|
||||
var data = message.data;
|
||||
|
||||
if (data.status == true && data.response) // data status is from shortpixel worker, not the response object
|
||||
{
|
||||
var response = data.response;
|
||||
var handledError = false; // prevent passing to regular queueHandler is some action is taken.
|
||||
this.workerErrors = 0;
|
||||
|
||||
if ( response.callback)
|
||||
{
|
||||
console.log('Running callback : ' + response.callback);
|
||||
var event = new CustomEvent(response.callback, {detail: response, cancelable: true});
|
||||
var checkPrevent = window.dispatchEvent(event);
|
||||
|
||||
if (! checkPrevent) // if event is preventDefaulted, stop checking response
|
||||
return;
|
||||
}
|
||||
if ( response.status == false)
|
||||
{
|
||||
|
||||
// This is error status, or a usual shutdown, i.e. when process is in another browser.
|
||||
var error = this.aStatusError[response.error];
|
||||
if (error == 'PROCESSOR_ACTIVE')
|
||||
{
|
||||
this.Debug(response.message);
|
||||
handledError = true;
|
||||
this.StopProcess();
|
||||
}
|
||||
else if (error == 'NONCE_FAILED')
|
||||
{
|
||||
this.Debug('Nonce Failed', 'error');
|
||||
}
|
||||
else if (error == 'NOQUOTA')
|
||||
{
|
||||
if (this.hasStartQuota)
|
||||
this.tooltip.AddNotice(response.message);
|
||||
|
||||
this.screen.HandleError(response);
|
||||
this.Debug('No Quota - CheckResponse handler');
|
||||
this.PauseProcess();
|
||||
handledError = true;
|
||||
}
|
||||
else if (error == 'APIKEY_FAILED')
|
||||
{
|
||||
this.StopProcess();
|
||||
handledError = true;
|
||||
console.error('No API Key set for this site. See settings');
|
||||
}
|
||||
else if (response.error < 0) // something happened.
|
||||
{
|
||||
this.StopProcess();
|
||||
handledError = true;
|
||||
console.error('Some unknown error occured!', response.error, response);
|
||||
}
|
||||
|
||||
if (handledError == true)
|
||||
return;
|
||||
} // status false handler.
|
||||
|
||||
// Check the screen if we are custom or media ( or bulk ) . Check the responses for each of those.
|
||||
if (typeof response.custom == 'object' && response.custom !== null)
|
||||
{
|
||||
this.HandleResponse(response.custom, 'custom');
|
||||
}
|
||||
if (typeof response.media == 'object' && response.media !== null)
|
||||
{
|
||||
this.HandleResponse(response.media, 'media');
|
||||
}
|
||||
// Total is a response type for combined stats in the bulk.
|
||||
if (typeof response.total == 'object' && response.total !== null)
|
||||
{
|
||||
this.HandleResponse(response.total, 'total');
|
||||
}
|
||||
|
||||
this.HandleQueueStatus(response);
|
||||
|
||||
if (response.processorKey)
|
||||
{
|
||||
this.remoteSecret = response.processorKey;
|
||||
}
|
||||
|
||||
if (response.responses)
|
||||
{
|
||||
if (typeof this.screen.GeneralResponses == 'function')
|
||||
{
|
||||
this.screen.GeneralResponses(response.responses);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // This is a worker error / http / nonce / generail fail
|
||||
{
|
||||
this.workerErrors++;
|
||||
this.timesEmpty = 0; // don't drag it.
|
||||
|
||||
if (data.message)
|
||||
{
|
||||
this.screen.HandleError(data.message);
|
||||
|
||||
this.Debug(data.message, 'error');
|
||||
}
|
||||
|
||||
if (this.workerErrors >= 3)
|
||||
{
|
||||
this.screen.HandleErrorStop();
|
||||
console.log('Shutting down . Num errors: ' + this.workerErrors);
|
||||
this.StopProcess();
|
||||
this.ShutDownWorker();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.StopProcess({ defer: true });
|
||||
console.log('Stop / defer');
|
||||
}
|
||||
}
|
||||
|
||||
// Binded to bulk-screen js for checking data.
|
||||
var event = new CustomEvent('shortpixel.processor.responseHandled', { detail : {paused: this.isManualPaused}});
|
||||
window.dispatchEvent(event);
|
||||
},
|
||||
HandleResponse: function(response, type)
|
||||
{
|
||||
// Issue with the tooltip is when doing usual cycle of emptiness, a running icon is annoying to user. Once queries and yielded results, it might be said that the processor 'is running'
|
||||
if (response.stats)
|
||||
this.tooltip.DoingProcess();
|
||||
|
||||
if (response.has_error == true)
|
||||
{
|
||||
this.tooltip.AddNotice(response.message);
|
||||
}
|
||||
|
||||
if (! this.screen)
|
||||
{
|
||||
console.error('Missing screen - can\'t report results');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Perhaps if optimization, the new stats and actions should be generated server side?
|
||||
// If there are items, give them to the screen for display of optimization, waiting status etc.
|
||||
var imageHandled = false; // Only post one image per result-set to the ImageHandler (on bulk), to prevent flooding.
|
||||
|
||||
// @todo Make sure that .result and .results can be iterated the same.
|
||||
if (typeof response.results !== 'undefined' && response.results !== null)
|
||||
{
|
||||
for (var i = 0; i < response.results.length; i++)
|
||||
{
|
||||
var imageItem = response.results[i];
|
||||
if (imageItem == null || ! imageItem.result)
|
||||
{
|
||||
console.error('Expecting ImageItem Object with result ', imageItem);
|
||||
continue;
|
||||
}
|
||||
if (imageItem.result.is_error)
|
||||
{
|
||||
this.HandleItemError(imageItem, type);
|
||||
}
|
||||
|
||||
if (! imageHandled)
|
||||
{
|
||||
imageHandled = this.screen.HandleImage(imageItem, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof response.result !== 'undefined' && response.result !== null)
|
||||
{
|
||||
if (response.result.is_error)
|
||||
{
|
||||
this.HandleItemError(response.result, type);
|
||||
}
|
||||
else if (! imageHandled)
|
||||
{
|
||||
imageHandled = this.screen.HandleImage(response, type); // whole response here is single item. (final!)
|
||||
}
|
||||
}
|
||||
|
||||
// Queue status?
|
||||
if (response.stats)
|
||||
{
|
||||
this.tooltip.RefreshStats(response.stats, type);
|
||||
this.screen.UpdateStats(response.stats, type);
|
||||
}
|
||||
|
||||
},
|
||||
/// If both are reported back, both did tick, so both must be considered.
|
||||
HandleQueueStatus: function(data)
|
||||
{
|
||||
var mediaStatus = 100;
|
||||
var customStatus = 100;
|
||||
// If not statuses were returned, we are probably loading something via ajax, don't increase the defer / checks on the processing
|
||||
var anyQueueStatus = false;
|
||||
|
||||
if (typeof data.media !== 'undefined' && typeof data.media.qstatus !== 'undefined' )
|
||||
{
|
||||
anyQueueStatus = true;
|
||||
mediaStatus = data.media.qstatus;
|
||||
}
|
||||
if (typeof data.custom !== 'undefined' && typeof data.custom.qstatus !== 'undefined')
|
||||
{
|
||||
anyQueueStatus = true;
|
||||
customStatus = data.custom.qstatus;
|
||||
}
|
||||
|
||||
if (false === anyQueueStatus)
|
||||
{
|
||||
return false; // no further checks.
|
||||
}
|
||||
|
||||
// The lowest queue status (for now) equals earlier in process. Don't halt until both are done.
|
||||
if (mediaStatus <= customStatus)
|
||||
var combinedStatus = mediaStatus;
|
||||
else
|
||||
var combinedStatus = customStatus;
|
||||
|
||||
if (combinedStatus == 100)
|
||||
{
|
||||
this.StopProcess({ defer: true });
|
||||
return false; // no status in this request.
|
||||
}
|
||||
|
||||
if (typeof combinedStatus !== 'undefined')
|
||||
{
|
||||
var qstatus = this.qStatus[combinedStatus];
|
||||
if (qstatus == 'QUEUE_ITEMS' || qstatus == "PREPARING")
|
||||
{
|
||||
console.log('Qstatus Preparing or items returns');
|
||||
this.timesEmpty = 0;
|
||||
this.RunProcess();
|
||||
}
|
||||
if (qstatus == 'QUEUE_WAITING')
|
||||
{
|
||||
console.log('Item in Queue, but waiting');
|
||||
this.timesEmpty++;
|
||||
this.RunProcess(); // run another queue with timeout
|
||||
}
|
||||
else if (qstatus == 'QUEUE_EMPTY')
|
||||
{
|
||||
console.debug('Processor: Empty Queue');
|
||||
//this.tooltip.ProcessEnd();
|
||||
this.StopProcess({ defer: true });
|
||||
}
|
||||
else if (qstatus == "PREPARING_DONE")
|
||||
{
|
||||
console.log('Processor: Preparing is done');
|
||||
this.StopProcess();
|
||||
}
|
||||
|
||||
// React to status of the queue.
|
||||
if (typeof this.screen.QueueStatus == 'function')
|
||||
{
|
||||
this.screen.QueueStatus(qstatus, data);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
HandleItemError : function(result, type)
|
||||
{
|
||||
console.log('Handle Item Error', result, type);
|
||||
var error = this.aStatusError[result.error];
|
||||
|
||||
if (error == 'NOQUOTA' )
|
||||
{
|
||||
this.PauseProcess();
|
||||
}
|
||||
|
||||
this.screen.HandleItemError(result, type);
|
||||
|
||||
|
||||
},
|
||||
LoadItemView: function(data)
|
||||
{
|
||||
// var data = event.detail;
|
||||
var nonce = this.nonce['itemview'];
|
||||
if (this.worker !== null)
|
||||
{
|
||||
if (typeof data.callback === 'undefined')
|
||||
{
|
||||
data.callback = 'shortpixel.RenderItemView';
|
||||
}
|
||||
this.worker.postMessage({action: 'getItemView', 'nonce' : this.nonce['itemview'], 'data': { 'id' : data.id, 'type' : data.type, 'callback' : data.callback }});
|
||||
}
|
||||
},
|
||||
|
||||
AjaxRequest: function(data)
|
||||
{
|
||||
if (this.worker === null)
|
||||
{
|
||||
this.LoadWorker(); // JIT worker loading
|
||||
}
|
||||
|
||||
var localWorker = false;
|
||||
this.worker.postMessage({action: 'ajaxRequest', 'nonce' : this.nonce['ajaxRequest'], 'data': data });
|
||||
},
|
||||
GetPluginUrl: function()
|
||||
{
|
||||
return ShortPixelConstants[0].WP_PLUGIN_URL;
|
||||
},
|
||||
Debug: function (message, messageType)
|
||||
{
|
||||
if (typeof messageType == 'undefined')
|
||||
messageType = 'debug';
|
||||
|
||||
if (messageType == 'debug')
|
||||
{
|
||||
console.debug(message);
|
||||
}
|
||||
if (messageType == 'error')
|
||||
{
|
||||
console.error('Error: ', message);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
ScriptError: function(error)
|
||||
{
|
||||
console.trace('Script Error! ', error);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,728 @@
|
||||
'use strict'
|
||||
|
||||
// New Class for Settings Section.
|
||||
var ShortPixelSettings = function()
|
||||
{
|
||||
|
||||
this.Init = function()
|
||||
{
|
||||
this.InitActions();
|
||||
this.SaveOnKey();
|
||||
}
|
||||
|
||||
this.InitActions = function()
|
||||
{
|
||||
var toggles = document.querySelectorAll('[data-toggle]');
|
||||
var self = this;
|
||||
|
||||
toggles.forEach(function (toggle, index)
|
||||
{
|
||||
toggle.addEventListener('change', self.DoToggleAction.bind(self));
|
||||
|
||||
var evInit = new CustomEvent('change', {detail : { init: true }} );
|
||||
toggle.dispatchEvent(evInit);
|
||||
});
|
||||
|
||||
// Modals
|
||||
var modals = document.querySelectorAll('[data-action="open-modal"]');
|
||||
modals.forEach(function (modal, index)
|
||||
{
|
||||
modal.addEventListener('click', self.OpenModal.bind(self));
|
||||
});
|
||||
|
||||
// Events for the New Exclusion dialog
|
||||
var newExclusionInputs = document.querySelectorAll('.new-exclusion select, .new-exclusion input, .new-exclusion button, input[name="removeExclusion"], button[name="cancelEditExclusion"]');
|
||||
|
||||
newExclusionInputs.forEach(function (input)
|
||||
{
|
||||
switch (input.name)
|
||||
{
|
||||
case 'addExclusion':
|
||||
case 'removeExclusion':
|
||||
case 'cancelEditExclusion':
|
||||
case 'updateExclusion':
|
||||
var eventType = 'click';
|
||||
break;
|
||||
default:
|
||||
var eventType = 'change';
|
||||
break;
|
||||
}
|
||||
|
||||
input.addEventListener(eventType, self.NewExclusionUpdateEvent.bind(self));
|
||||
});
|
||||
|
||||
var exclusionItems = document.querySelectorAll('.exclude-list li');
|
||||
exclusionItems.forEach(function (input) {
|
||||
if (false == input.classList.contains('no-exclusion-item'))
|
||||
{
|
||||
input.addEventListener('click', self.NewExclusionShowInterfaceEvent.bind(self));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var addNewExclusionButton = document.querySelector('.new-exclusion-button');
|
||||
if (addNewExclusionButton !== null)
|
||||
{
|
||||
addNewExclusionButton.addEventListener('click', this.NewExclusionShowInterfaceEvent.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
this.DoToggleAction = function(event)
|
||||
{
|
||||
event.preventDefault();
|
||||
|
||||
var checkbox = event.target;
|
||||
var target = document.getElementById(checkbox.getAttribute('data-toggle'));
|
||||
|
||||
if (typeof checkbox.dataset.toggleReverse !== 'undefined')
|
||||
{
|
||||
var checked = ! checkbox.checked;
|
||||
}
|
||||
else {
|
||||
var checked = checkbox.checked;
|
||||
}
|
||||
|
||||
if (target === null)
|
||||
{
|
||||
console.error('Target element ID not found', checkbox);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checked)
|
||||
{
|
||||
// target.classList.add('is-visible');
|
||||
this.ShowElement(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.HideElement(target);
|
||||
// target.classList.remove('is-visible');
|
||||
}
|
||||
}
|
||||
|
||||
this.ShowElement = function (elem) {
|
||||
|
||||
// Get the natural height of the element
|
||||
var getHeight = function () {
|
||||
elem.style.display = 'block'; // Make it visible
|
||||
var height = elem.scrollHeight + 'px'; // Get it's height
|
||||
elem.style.display = ''; // Hide it again
|
||||
return height;
|
||||
};
|
||||
|
||||
var height = getHeight(); // Get the natural height
|
||||
elem.classList.add('is-visible'); // Make the element visible
|
||||
elem.style.height = height; // Update the max-height
|
||||
|
||||
// Once the transition is complete, remove the inline max-height so the content can scale responsively
|
||||
window.setTimeout(function () {
|
||||
elem.style.height = '';
|
||||
}, 350);
|
||||
|
||||
};
|
||||
|
||||
// Hide an element
|
||||
this.HideElement = function (elem) {
|
||||
|
||||
// Give the element a height to change from
|
||||
elem.style.height = elem.scrollHeight + 'px';
|
||||
|
||||
// Set the height back to 0
|
||||
window.setTimeout(function () {
|
||||
elem.style.height = '0';
|
||||
}, 1);
|
||||
|
||||
// When the transition is complete, hide it
|
||||
window.setTimeout(function () {
|
||||
elem.classList.remove('is-visible');
|
||||
}, 350);
|
||||
|
||||
};
|
||||
|
||||
|
||||
this.OpenModal = function(elem)
|
||||
{
|
||||
var target = elem.target;
|
||||
var targetElem = document.getElementById(target.dataset.target);
|
||||
if (! targetElem)
|
||||
return;
|
||||
|
||||
var shade = document.getElementById('spioSettingsModalShade');
|
||||
var modal = document.getElementById('spioSettingsModal');
|
||||
|
||||
shade.style.display = 'block';
|
||||
modal.classList.remove('spio-hide');
|
||||
|
||||
var body = modal.querySelector('.spio-modal-body');
|
||||
body.innerHTML = ('afterbegin', targetElem.innerHTML); //.cloneNode()
|
||||
body.style.background = '#fff';
|
||||
shade.addEventListener('click', this.CloseModal.bind(this), {'once': true} );
|
||||
|
||||
modal.querySelector('.spio-close-help-button').addEventListener('click', this.CloseModal.bind(this), {'once': true});
|
||||
|
||||
if (body.querySelector('[data-action="ajaxrequest"]') !== null)
|
||||
{
|
||||
body.querySelector('[data-action="ajaxrequest"]').addEventListener('click', this.SendModal.bind(this));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.CloseModal = function(elem)
|
||||
{
|
||||
var shade = document.getElementById('spioSettingsModalShade');
|
||||
var modal = document.getElementById('spioSettingsModal');
|
||||
|
||||
shade.style.display = 'none';
|
||||
modal.classList.add('spio-hide');
|
||||
|
||||
}
|
||||
|
||||
this.SendModal = function(elem)
|
||||
{
|
||||
var modal = document.getElementById('spioSettingsModal');
|
||||
var body = modal.querySelector('.spio-modal-body');
|
||||
var inputs = body.querySelectorAll('input');
|
||||
|
||||
var data = {};
|
||||
var validated = true;
|
||||
|
||||
for (var i = 0; i < inputs.length; i++)
|
||||
{
|
||||
data[inputs[i].name] = inputs[i].value;
|
||||
if (typeof inputs[i].dataset.required !== 'undefined')
|
||||
{
|
||||
if (inputs[i].value !== inputs[i].dataset.required)
|
||||
{
|
||||
inputs[i].style.border = '1px solid #ff0000';
|
||||
validated = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! validated)
|
||||
return false;
|
||||
|
||||
data.callback = 'shortpixelSettings.receiveModal'
|
||||
data.type = 'settings';
|
||||
|
||||
window.addEventListener('shortpixelSettings.receiveModal', this.ReceiveModal.bind(this), {'once': true} );
|
||||
|
||||
window.ShortPixelProcessor.AjaxRequest(data);
|
||||
|
||||
}
|
||||
|
||||
this.ReceiveModal = function(elem)
|
||||
{
|
||||
if (typeof elem.detail.settings.results !== 'undefined')
|
||||
{
|
||||
var modal = document.getElementById('spioSettingsModal');
|
||||
var body = modal.querySelector('.spio-modal-body');
|
||||
|
||||
body.innerHTML = elem.detail.settings.results;
|
||||
}
|
||||
|
||||
if (typeof elem.detail.settings.redirect !== 'undefined')
|
||||
{
|
||||
window.location.href = elem.detail.settings.redirect;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.SaveOnKey = function()
|
||||
{
|
||||
var saveForm = document.getElementById('wp_shortpixel_options');
|
||||
if (saveForm === null)
|
||||
return false; // no form no save.
|
||||
|
||||
window.addEventListener('keydown', function(event) {
|
||||
|
||||
if (! (event.key == 's' || event.key == 'S') || ! event.ctrlKey)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
document.getElementById('wp_shortpixel_options').submit();
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
this.NewExclusionShowInterfaceEvent = function (event)
|
||||
{
|
||||
this.ResetExclusionInputs();
|
||||
event.preventDefault();
|
||||
|
||||
var element = document.querySelector('.new-exclusion');
|
||||
element.classList.remove('not-visible', 'hidden');
|
||||
|
||||
var cancelButton = document.querySelector('.new-exclusion .button-actions button[name="cancelEditExclusion"]');
|
||||
cancelButton.classList.remove('not-visible', 'hidden');
|
||||
|
||||
var updateButton = document.querySelector('.new-exclusion .button-actions button[name="updateExclusion"]');
|
||||
|
||||
|
||||
if (event.target.name == 'addNewExclusion')
|
||||
{
|
||||
var mode = 'new';
|
||||
var id = 'new';
|
||||
var title = document.querySelector('.new-exclusion h3.new-title');
|
||||
var button = document.querySelector('.new-exclusion .button-actions button[name="addExclusion"]');
|
||||
|
||||
}
|
||||
else {
|
||||
var mode = 'edit';
|
||||
|
||||
if (event.target.id)
|
||||
{
|
||||
var id = event.target.id;
|
||||
var parent = event.target;
|
||||
}
|
||||
else {
|
||||
var id = event.target.parentElement.id;
|
||||
var parent = event.target.parentElement;
|
||||
}
|
||||
var title = document.querySelector('.new-exclusion h3.edit-title');
|
||||
var button = document.querySelector('.new-exclusion .button-actions button[name="removeExclusion"]');
|
||||
var input = document.querySelector('.new-exclusion input[name="edit-exclusion"]')
|
||||
|
||||
updateButton.classList.remove('not-visible', 'hidden');
|
||||
|
||||
input.value = id;
|
||||
var dataElement = parent.querySelector('input').value;
|
||||
var data = JSON.parse(dataElement);
|
||||
this.ReadWriteExclusionForm(data)
|
||||
|
||||
|
||||
}
|
||||
|
||||
title.classList.remove('not-visible', 'hidden');
|
||||
button.classList.remove('not-visible', 'hidden');
|
||||
|
||||
}
|
||||
|
||||
this.HideExclusionInterface = function()
|
||||
{
|
||||
var element = document.querySelector('.new-exclusion');
|
||||
element.classList.add('not-visible');
|
||||
|
||||
}
|
||||
|
||||
// EXCLUSIONS
|
||||
this.NewExclusionUpdateEvent = function(event)
|
||||
{
|
||||
var target = event.target;
|
||||
var inputName = event.target.name;
|
||||
switch(inputName)
|
||||
{
|
||||
case 'exclusion-type':
|
||||
this.NewExclusionUpdateType(target);
|
||||
break;
|
||||
case 'apply-select':
|
||||
this.NewExclusionUpdateThumbType(target);
|
||||
break;
|
||||
case 'addExclusion':
|
||||
this.NewExclusionButtonAdd(target);
|
||||
break;
|
||||
case 'exclusion-exactsize':
|
||||
this.NewExclusionToggleSizeOption(target);
|
||||
break;
|
||||
case 'removeExclusion':
|
||||
this.RemoveExclusion(target);
|
||||
break;
|
||||
case 'cancelEditExclusion':
|
||||
this.HideExclusionInterface();
|
||||
break;
|
||||
case 'updateExclusion':
|
||||
this.UpdateExclusion();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this.NewExclusionUpdateType = function(element)
|
||||
{
|
||||
var value = element.value;
|
||||
var selected = element.options[element.selectedIndex];
|
||||
var example = selected.dataset.example;
|
||||
if ( typeof example == 'undefined')
|
||||
{
|
||||
example = '';
|
||||
}
|
||||
|
||||
var valueOption = document.querySelector('.new-exclusion .value-option');
|
||||
var sizeOption = document.querySelector('.new-exclusion .size-option');
|
||||
var regexOption = document.querySelector('.regex-option');
|
||||
var switchExactOption = document.querySelector('.exact-option');
|
||||
|
||||
|
||||
if (value == 'size')
|
||||
{
|
||||
valueOption.classList.add('not-visible');
|
||||
sizeOption.classList.remove('not-visible');
|
||||
switchExactOption.classList.remove('not-visible');
|
||||
regexOption.classList.add('not-visible');
|
||||
}
|
||||
else {
|
||||
valueOption.classList.remove('not-visible');
|
||||
sizeOption.classList.add('not-visible');
|
||||
switchExactOption.classList.add('not-visible');
|
||||
regexOption.classList.remove('not-visible');
|
||||
}
|
||||
|
||||
var valueInput = document.querySelector('input[name="exclusion-value"]');
|
||||
if (null !== valueInput)
|
||||
{
|
||||
valueInput.placeholder = example;
|
||||
}
|
||||
}
|
||||
|
||||
this.NewExclusionUpdateThumbType = function(element)
|
||||
{
|
||||
var value = element.value;
|
||||
|
||||
var thumbSelect = document.querySelector('select[name="thumbnail-select"]');
|
||||
|
||||
if (value == 'selected-thumbs')
|
||||
{
|
||||
thumbSelect.classList.remove('not-visible');
|
||||
}
|
||||
else {
|
||||
thumbSelect.classList.add('not-visible');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.ReadWriteExclusionForm = function(setting)
|
||||
{
|
||||
// compile all inputs to a json encoded string to add to UX
|
||||
if (null === setting || typeof setting === 'undefined')
|
||||
{
|
||||
var setting = {
|
||||
'type' : '',
|
||||
'value' : '',
|
||||
'apply' : '',
|
||||
};
|
||||
|
||||
var mode = 'read';
|
||||
}
|
||||
else {
|
||||
var mode = 'write';
|
||||
}
|
||||
|
||||
var strings = {};
|
||||
|
||||
var typeOption = document.querySelector('.new-exclusion select[name="exclusion-type"]');
|
||||
var valueOption = document.querySelector('.new-exclusion input[name="exclusion-value"]');
|
||||
var applyOption = document.querySelector('.new-exclusion select[name="apply-select"]');
|
||||
var regexOption = document.querySelector('.new-exclusion input[name="exclusion-regex"]');
|
||||
|
||||
if ('read' === mode)
|
||||
{
|
||||
setting.type = typeOption.value;
|
||||
setting.value = valueOption.value;
|
||||
setting.apply = applyOption.value;
|
||||
|
||||
strings.type = typeOption.options[typeOption.selectedIndex].innerText;
|
||||
strings.apply = applyOption.options[applyOption.selectedIndex].innerText;
|
||||
}
|
||||
else {
|
||||
if (setting.type.indexOf('regex') != -1)
|
||||
{
|
||||
typeOption.value = setting.type.replace('regex-', '');
|
||||
}
|
||||
else {
|
||||
typeOption.value = setting.type;
|
||||
}
|
||||
valueOption.value = setting.value;
|
||||
applyOption.value = setting.apply;
|
||||
}
|
||||
|
||||
// When selected thumbnails option is selected, add the thumbnails to the list.
|
||||
if ('selected-thumbs' == applyOption.value)
|
||||
{
|
||||
var thumbOption = document.querySelector('.new-exclusion select[name="thumbnail-select"]');
|
||||
var thumblist = [];
|
||||
if ('read' === mode)
|
||||
{
|
||||
for(var i =0; i < thumbOption.selectedOptions.length; i++)
|
||||
{
|
||||
thumblist.push(thumbOption.selectedOptions[i].value);
|
||||
}
|
||||
setting.thumblist = thumblist;
|
||||
}
|
||||
else if ('write' === mode){
|
||||
for (var i = 0; i < thumbOption.options.length; i++)
|
||||
{
|
||||
if (setting.thumblist.indexOf(thumbOption[i].value) != -1)
|
||||
{
|
||||
thumbOption[i].selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.NewExclusionUpdateThumbType(applyOption);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for regular expression active on certain types
|
||||
if ('read' === mode && true === regexOption.checked && (typeOption.value == 'name' || typeOption.value == 'path'))
|
||||
{
|
||||
setting.type = 'regex-' + setting.type;
|
||||
}
|
||||
else if ('write' === mode)
|
||||
{
|
||||
if (setting.type.indexOf('regex') != -1)
|
||||
{
|
||||
regexOption.checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Options for size setting
|
||||
if ('size' === setting.type)
|
||||
{
|
||||
var exactOption = document.querySelector('.new-exclusion input[name="exclusion-exactsize"]');
|
||||
|
||||
var width = document.querySelector('.new-exclusion input[name="exclusion-width"]');
|
||||
var height = document.querySelector('.new-exclusion input[name="exclusion-height"]');
|
||||
|
||||
var minwidth = document.querySelector('.new-exclusion input[name="exclusion-minwidth"]');
|
||||
var maxwidth = document.querySelector('.new-exclusion input[name="exclusion-maxwidth"]');
|
||||
var minheight = document.querySelector('.new-exclusion input[name="exclusion-minheight"]');
|
||||
var maxheight = document.querySelector('.new-exclusion input[name="exclusion-maxheight"]');
|
||||
|
||||
|
||||
if ('read' === mode)
|
||||
{
|
||||
if (true === exactOption.checked)
|
||||
{
|
||||
setting.value = width.value + 'x' + height.value;
|
||||
}
|
||||
else {
|
||||
setting.value = minwidth.value + '-' + maxwidth.value + 'x' + minheight.value + '-' + maxheight.value;
|
||||
}
|
||||
}
|
||||
else if ('write' === mode)
|
||||
{
|
||||
var value = setting.value;
|
||||
var split = value.split(/(x|×|X)/);
|
||||
|
||||
if (value.indexOf('-') === -1)
|
||||
{
|
||||
exactOption.checked = true;
|
||||
width.value = split[0]; // in this split 1 is the X symbol
|
||||
height.value = split[2];
|
||||
}
|
||||
else {
|
||||
var widths = split[0].split('-'); // split the split for widths
|
||||
var heights = split[2].split('-');
|
||||
|
||||
minwidth.value = widths[0];
|
||||
maxwidth.value = widths[1];
|
||||
|
||||
minheight.value = heights[0];
|
||||
maxheight.value = heights[1];
|
||||
}
|
||||
|
||||
this.NewExclusionUpdateType(typeOption)
|
||||
this.NewExclusionToggleSizeOption(exactOption);
|
||||
}
|
||||
}
|
||||
if ('read' === mode)
|
||||
{
|
||||
return [setting, strings];
|
||||
}
|
||||
}
|
||||
|
||||
this.NewExclusionButtonAdd = function(element)
|
||||
{
|
||||
var result = this.ReadWriteExclusionForm(null);
|
||||
var setting = result[0];
|
||||
var strings = result[1];
|
||||
|
||||
var listElement = document.querySelector('.exclude-list');
|
||||
var newElement = document.createElement('li');
|
||||
var inputElement = document.createElement('input');
|
||||
|
||||
var newIndexInput = document.getElementById('new-exclusion-index');
|
||||
var newIndex = parseInt(newIndexInput.value) + 1;
|
||||
newIndexInput.value = newIndex;
|
||||
|
||||
newElement.id = 'exclude-' + newIndex;
|
||||
newElement.addEventListener('click', this.NewExclusionShowInterfaceEvent.bind(this));
|
||||
|
||||
inputElement.type = 'hidden';
|
||||
inputElement.name = 'exclusions[]';
|
||||
inputElement.value = JSON.stringify(setting);
|
||||
|
||||
|
||||
newElement.appendChild(inputElement);
|
||||
|
||||
var spans = [strings.type, setting.value, strings.apply];
|
||||
|
||||
for (var i = 0; i < spans.length; i++)
|
||||
{
|
||||
var spanElement = document.createElement('span');
|
||||
spanElement.textContent = spans[i];
|
||||
|
||||
newElement.appendChild(spanElement);
|
||||
}
|
||||
|
||||
listElement.appendChild(newElement);
|
||||
|
||||
var noItemsItem = document.querySelector('.exclude-list .no-exclusion-item');
|
||||
if (noItemsItem !== null)
|
||||
{
|
||||
noItemsItem.classList.add('not-visible');
|
||||
}
|
||||
|
||||
this.ResetExclusionInputs();
|
||||
this.HideExclusionInterface();
|
||||
this.ShowExclusionSaveWarning();
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.NewExclusionToggleSizeOption = function(target)
|
||||
{
|
||||
var sizeOptionRange = document.querySelector('.new-exclusion .size-option-range');
|
||||
var sizeOptionExact = document.querySelector('.new-exclusion .size-option-exact');
|
||||
|
||||
if (true === target.checked)
|
||||
{
|
||||
sizeOptionRange.classList.add('not-visible');
|
||||
sizeOptionExact.classList.remove('not-visible');
|
||||
}
|
||||
else {
|
||||
sizeOptionRange.classList.remove('not-visible');
|
||||
sizeOptionExact.classList.add('not-visible');
|
||||
}
|
||||
}
|
||||
|
||||
this.ResetExclusionInputs = function()
|
||||
{
|
||||
var typeOption = document.querySelector('.new-exclusion select[name="exclusion-type"]');
|
||||
var valueOption = document.querySelector('.new-exclusion input[name="exclusion-value"]');
|
||||
var applyOption = document.querySelector('.new-exclusion select[name="apply-select"]');
|
||||
|
||||
var inputs = document.querySelectorAll('.new-exclusion input, .new-exclusion select');
|
||||
for (var i = 0; i < inputs.length; i++)
|
||||
{
|
||||
var input = inputs[i];
|
||||
if (input.tagName == 'SELECT')
|
||||
{
|
||||
input.selectedIndex = 0;
|
||||
}
|
||||
else if (input.type == 'checkbox')
|
||||
{
|
||||
input.checked = false;
|
||||
}
|
||||
else {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var ev = new CustomEvent('change');
|
||||
typeOption.dispatchEvent(ev);
|
||||
applyOption.dispatchEvent(ev);
|
||||
|
||||
// reset title and buttons.
|
||||
var titles = document.querySelectorAll('.new-exclusion h3');
|
||||
var buttons = document.querySelectorAll('.new-exclusion .button-actions button');
|
||||
|
||||
for(var i = 0; i < titles.length; i++)
|
||||
{
|
||||
titles[i].classList.add('not-visible', 'hidden');
|
||||
|
||||
}
|
||||
|
||||
for (var i = 0; i < buttons.length; i++)
|
||||
{
|
||||
buttons[i].classList.add('not-visible', 'hidden');
|
||||
}
|
||||
|
||||
var exactOption = document.querySelector('.new-exclusion input[name="exclusion-exactsize"]');
|
||||
|
||||
exactOption.checked = false
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.UpdateExclusion = function()
|
||||
{
|
||||
var id = document.querySelector('.new-exclusion input[name="edit-exclusion"]');
|
||||
var result = this.ReadWriteExclusionForm();
|
||||
var setting = result[0];
|
||||
var strings = result[1];
|
||||
|
||||
if (id)
|
||||
{
|
||||
var element = document.querySelector('.exclude-list #' +id.value + ' input');
|
||||
var liElement = document.querySelector('.exclude-list #' +id.value);
|
||||
|
||||
var removeChildren = [];
|
||||
if (null !== element)
|
||||
{
|
||||
element.value = JSON.stringify(setting);
|
||||
|
||||
// Can't directly remove children, because it messes with the collection index.
|
||||
Array.from(liElement.children).forEach ( function (child, index){
|
||||
if (child.tagName == 'SPAN')
|
||||
{
|
||||
removeChildren.push(child)
|
||||
}
|
||||
});
|
||||
|
||||
for(var i = 0; i < removeChildren.length; i++ )
|
||||
{
|
||||
removeChildren[i].remove();
|
||||
}
|
||||
|
||||
var spans = [strings.type, setting.value, strings.apply];
|
||||
for (var j = 0; j < spans.length; j++)
|
||||
{
|
||||
var spanElement = document.createElement('span');
|
||||
spanElement.textContent = spans[j];
|
||||
liElement.appendChild(spanElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.HideExclusionInterface();
|
||||
this.ShowExclusionSaveWarning();
|
||||
|
||||
}
|
||||
|
||||
this.ShowExclusionSaveWarning = function()
|
||||
{
|
||||
var reminder = document.querySelector('.exclusion-save-reminder');
|
||||
if (reminder)
|
||||
{
|
||||
reminder.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
this.RemoveExclusion = function()
|
||||
{
|
||||
var id = document.querySelector('.new-exclusion input[name="edit-exclusion"]');
|
||||
if (id)
|
||||
{
|
||||
var element = document.querySelector('.exclude-list #' +id.value);
|
||||
if (null !== element)
|
||||
{
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
this.HideExclusionInterface();
|
||||
this.ShowExclusionSaveWarning();
|
||||
|
||||
}
|
||||
|
||||
this.Init();
|
||||
} // SPSettings
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(){
|
||||
var s = new ShortPixelSettings();
|
||||
});
|
@ -0,0 +1,279 @@
|
||||
'use strict';
|
||||
|
||||
var ShortPixelToolTip = function(reserved, processor)
|
||||
{
|
||||
this.strings = '';
|
||||
|
||||
this.Init = function()
|
||||
{
|
||||
|
||||
var paused = localStorage.getItem('tooltipPause'); // string returns, not boolean
|
||||
if (paused == 'true')
|
||||
{
|
||||
console.log('manual paused (tooltip)');
|
||||
processor.PauseProcess();
|
||||
}
|
||||
var control = document.querySelector('.ab-item .controls');
|
||||
if (control)
|
||||
control.addEventListener('click', this.ToggleProcessing.bind(this));
|
||||
|
||||
this.ToggleIcon();
|
||||
|
||||
if (processor.isManualPaused == true)
|
||||
{
|
||||
this.ProcessPause();
|
||||
}
|
||||
|
||||
this.strings = spio_tooltipStrings;
|
||||
|
||||
window.addEventListener('shortpixel.processor.paused', this.ProcessChange.bind(this));
|
||||
}
|
||||
this.GetToolTip = function() // internal function please.
|
||||
{
|
||||
var element = document.querySelector('li.shortpixel-toolbar-processing');
|
||||
if (element === null)
|
||||
{
|
||||
console.error('Tooltip could not be found!');
|
||||
}
|
||||
return element;
|
||||
}
|
||||
this.InitStats = function()
|
||||
{
|
||||
var processData = ShortPixelProcessorData.startData;
|
||||
if (typeof processData !== 'object')
|
||||
{
|
||||
console.error('Tooltip: No start Data found.');
|
||||
return false;
|
||||
}
|
||||
this.RefreshStats(processData.media.stats, 'media');
|
||||
this.RefreshStats(processData.custom.stats, 'custom');
|
||||
this.RefreshStats(processData.total.stats, 'total');
|
||||
|
||||
// Hide Tooltip is manual paused is true, but there is also nothing to do.
|
||||
if (processor.isManualPaused == true && processData.total.stats.total <= 0)
|
||||
{
|
||||
this.ProcessEnd();
|
||||
}
|
||||
}
|
||||
// Used to put a 'todo' number in the tooltip when processing
|
||||
this.RefreshStats = function(stats, type)
|
||||
{
|
||||
var neededType;
|
||||
|
||||
if (processor.screen.isMedia == true && processor.screen.isCustom == true)
|
||||
neededType = 'total';
|
||||
else if (processor.screen.isMedia == true && processor.screen.isCustom == false)
|
||||
neededType = 'media';
|
||||
else if (processor.screen.isMedia == false && processor.screen.isCustom == true)
|
||||
neededType = 'custom';
|
||||
|
||||
if (neededType !== type)
|
||||
return;
|
||||
|
||||
var toolTip = this.GetToolTip();
|
||||
if (toolTip === null)
|
||||
return false;
|
||||
|
||||
var statTip = toolTip.querySelector('.stats');
|
||||
|
||||
if (statTip == null)
|
||||
return;
|
||||
|
||||
var inqueue = stats.in_queue;
|
||||
var inprocess = stats.in_process;
|
||||
|
||||
// @todo This needs fixing.
|
||||
var pattern = new RegExp("\\.|\\,", '');
|
||||
|
||||
if (typeof inqueue === 'string' && inqueue)
|
||||
inqueue = inqueue.replace(pattern,''); // remove number formats
|
||||
if (typeof inprocess === 'string' && inprocess)
|
||||
inprocess = inprocess.replace(pattern,''); // remove number formats
|
||||
|
||||
var number = parseInt(inqueue) + parseInt(inprocess);
|
||||
statTip.textContent = this.FormatNumber(number);
|
||||
|
||||
// Updating the titles.
|
||||
|
||||
var itemTitle = statTip.textContent + ' ';
|
||||
itemTitle += (number == 1) ? this.strings.item : this.strings.items;
|
||||
|
||||
if (toolTip.querySelector('#short-pixel-notice-toolbar') !== null)
|
||||
{
|
||||
toolTip.querySelector('#short-pixel-notice-toolbar').title = this.strings.processing + ' ' + itemTitle;
|
||||
}
|
||||
if (toolTip.querySelector('.dashicons.pause') !== null)
|
||||
{
|
||||
toolTip.querySelector('.dashicons.pause').title = itemTitle + '\n\n' + this.strings.pause;
|
||||
}
|
||||
if (toolTip.querySelector('.dashicons.play') !== null)
|
||||
{
|
||||
toolTip.querySelector('.dashicons.play').title = itemTitle + '\n\n' + this.strings.resume;
|
||||
}
|
||||
|
||||
if (statTip.classList.contains('hidden') && number > 0)
|
||||
statTip.classList.remove('hidden');
|
||||
else if (! statTip.classList.contains('hidden') && number == 0)
|
||||
statTip.classList.add('hidden');
|
||||
}
|
||||
|
||||
this.FormatNumber = function(num)
|
||||
{
|
||||
var digits = 1;
|
||||
var si = [
|
||||
{ value: 1E18, symbol: "E" },
|
||||
{ value: 1E15, symbol: "P" },
|
||||
{ value: 1E12, symbol: "T" },
|
||||
{ value: 1E9, symbol: "G" },
|
||||
{ value: 1E6, symbol: "M" },
|
||||
{ value: 1E3, symbol: "k" }
|
||||
], i;
|
||||
for (i = 0; i < si.length; i++) {
|
||||
if (num >= si[i].value) {
|
||||
return (num / si[i].value).toFixed(digits).replace(/\.?0+$/, "") + si[i].symbol;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
this.ToggleProcessing = function(event)
|
||||
{
|
||||
event.preventDefault();
|
||||
//event.stopProp
|
||||
|
||||
if (processor.isManualPaused == false)
|
||||
{
|
||||
processor.PauseProcess();
|
||||
localStorage.setItem('tooltipPause','true');
|
||||
this.ProcessPause();
|
||||
}
|
||||
else
|
||||
{
|
||||
processor.ResumeProcess();
|
||||
localStorage.setItem('tooltipPause','false');
|
||||
this.ProcessResume();
|
||||
}
|
||||
|
||||
processor.CheckActive();
|
||||
|
||||
}
|
||||
|
||||
this.ToggleIcon = function()
|
||||
{
|
||||
var controls = document.querySelectorAll('.ab-item .controls > span');
|
||||
|
||||
for(var i = 0; i < controls.length; i++)
|
||||
{
|
||||
var control = controls[i];
|
||||
if (control.classList.contains('pause'))
|
||||
{
|
||||
if (processor.isManualPaused == true)
|
||||
control.classList.add('hidden');
|
||||
else
|
||||
control.classList.remove('hidden');
|
||||
}
|
||||
else if (control.classList.contains('play'))
|
||||
{
|
||||
if (processor.isManualPaused == false)
|
||||
control.classList.add('hidden');
|
||||
else
|
||||
control.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.DoingProcess = function()
|
||||
{
|
||||
var tooltip = this.GetToolTip();
|
||||
if (tooltip === null)
|
||||
return false;
|
||||
tooltip.classList.remove('shortpixel-hide');
|
||||
tooltip.classList.add('shortpixel-processing');
|
||||
}
|
||||
|
||||
this.AddNotice = function(message)
|
||||
{
|
||||
var tooltip = this.GetToolTip(); // li.shortpixel-toolbar-processing
|
||||
if (tooltip === null)
|
||||
return false;
|
||||
var toolcontent = tooltip.querySelector('.toolbar-notice-wrapper');
|
||||
|
||||
if (toolcontent == null)
|
||||
{
|
||||
var abItem = tooltip.querySelector('.ab-item');
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.className = 'toolbar-notice-wrapper';
|
||||
abItem.parentNode.insertBefore(wrapper, abItem.nextSibling);
|
||||
var toolcontent = tooltip.querySelector('.toolbar-notice-wrapper');
|
||||
}
|
||||
|
||||
var id = message.replace(/[^a-zA-Z ]/g, "").replace(/ /g, "").slice(0,20);
|
||||
|
||||
var alert = document.createElement('div');
|
||||
alert.dataset.msgid = id;
|
||||
alert.className = 'toolbar-notice toolbar-notice-error';
|
||||
alert.innerHTML = message;
|
||||
|
||||
// Prevent double notices with same message
|
||||
if (toolcontent.querySelector('[data-msgid="' + id + '"]') == null)
|
||||
{
|
||||
var alertChild = toolcontent.appendChild(alert);
|
||||
window.setTimeout (this.RemoveNotice.bind(this), 5000, alertChild);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.RemoveNotice = function(notice)
|
||||
{
|
||||
notice.style.opacity = 0;
|
||||
window.setTimeout(function () { notice.remove() }, 2000);
|
||||
|
||||
}
|
||||
this.ProcessResume = function()
|
||||
{
|
||||
var tooltip = this.GetToolTip();
|
||||
if (tooltip === null)
|
||||
return false;
|
||||
tooltip.classList.remove('shortpixel-paused');
|
||||
tooltip.classList.add('shortpixel-processing');
|
||||
this.ToggleIcon();
|
||||
|
||||
}
|
||||
this.ProcessEnd = function()
|
||||
{
|
||||
var tooltip = this.GetToolTip();
|
||||
if (tooltip === null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
tooltip.classList.add('shortpixel-hide');
|
||||
tooltip.classList.remove('shortpixel-processing');
|
||||
}
|
||||
this.ProcessPause = function()
|
||||
{
|
||||
var tooltip = this.GetToolTip();
|
||||
if (tooltip === null)
|
||||
return false;
|
||||
|
||||
tooltip.classList.add('shortpixel-paused');
|
||||
tooltip.classList.remove('shortpixel-processing');
|
||||
tooltip.classList.remove('shortpixel-hide');
|
||||
this.ToggleIcon();
|
||||
|
||||
}
|
||||
this.ProcessChange = function(e)
|
||||
{
|
||||
var detail = e.detail;
|
||||
|
||||
if (detail.paused == false)
|
||||
this.ProcessResume();
|
||||
else
|
||||
this.ProcessPause();
|
||||
}
|
||||
this.HandleError = function()
|
||||
{
|
||||
console.trace('tooltip error');
|
||||
}
|
||||
|
||||
this.Init();
|
||||
} // tooltip.
|
@ -0,0 +1,161 @@
|
||||
'use strict';
|
||||
|
||||
onmessage = function(e)
|
||||
{
|
||||
|
||||
var action = e.data.action;
|
||||
var data = e.data.data;
|
||||
var nonce = e.data.nonce;
|
||||
var isBulk = false;
|
||||
|
||||
SpWorker.nonce = nonce;
|
||||
|
||||
if (typeof e.data.isBulk !== 'undefined')
|
||||
isBulk = e.data.isBulk;
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case 'setEnv':
|
||||
SpWorker.SetEnv(data);
|
||||
break;
|
||||
case 'shutdown':
|
||||
SpWorker.ShutDown();
|
||||
break;
|
||||
case 'process':
|
||||
SpWorker.Process(data);
|
||||
break;
|
||||
case 'getItemView':
|
||||
SpWorker.GetItemView(data);
|
||||
break;
|
||||
case 'ajaxRequest':
|
||||
SpWorker.AjaxRequest(data);
|
||||
break;
|
||||
case 'updateLocalSecret':
|
||||
var key = e.data.key;
|
||||
SpWorker.UpdateLocalSecret(key);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var SpWorker = {
|
||||
ajaxUrl: null,
|
||||
action: 'shortpixel_image_processing',
|
||||
secret: null,
|
||||
nonce: null,
|
||||
isBulk: false, // If we are on the bulk screen / queue
|
||||
isCustom: false, // Process this queueType - depends on screen
|
||||
isMedia: false, // Process this queueType - depends on screen.
|
||||
stopped: false,
|
||||
|
||||
Fetch: async function (data)
|
||||
{
|
||||
|
||||
var params = new URLSearchParams();
|
||||
params.append('action', this.action);
|
||||
params.append('bulk-secret', this.secret);
|
||||
params.append('nonce', this.nonce);
|
||||
params.append('isBulk', this.isBulk);
|
||||
|
||||
var queues = [];
|
||||
if (this.isMedia == true)
|
||||
queues.push('media');
|
||||
if (this.isCustom == true)
|
||||
queues.push('custom');
|
||||
|
||||
params.append('queues', queues);
|
||||
|
||||
if (typeof data !== 'undefined' && typeof data == 'object')
|
||||
{
|
||||
for(var key in data)
|
||||
params.append(key, data[key]);
|
||||
}
|
||||
|
||||
var response = await fetch(this.ajaxUrl, {
|
||||
'method': 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
|
||||
},
|
||||
body: params.toString(),
|
||||
|
||||
}).catch (function (error){
|
||||
if (this && ! this.stopped) // if page is switched during init , this might not be set.
|
||||
{
|
||||
postMessage({'status' : false, message: error});
|
||||
console.error('Worker.js reporting issue on catch', error);
|
||||
}
|
||||
else {
|
||||
console.log('stopped but not complaining!');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (response.ok)
|
||||
{
|
||||
var json = await response.json();
|
||||
|
||||
postMessage({'status' : true, response: json});
|
||||
}
|
||||
else if(this && ! this.stopped)
|
||||
{
|
||||
var text = await response.text();
|
||||
if ( typeof text === 'undefined') // if no, try json
|
||||
{
|
||||
var text = await response.json();
|
||||
}
|
||||
if (typeof text === 'undefined' || text.length === 0) // if still not, then status text perhaps
|
||||
{
|
||||
var text = response.status + ' ' + response.statusText;
|
||||
}
|
||||
var message = {status: false, http_status: response.status, http_text: text, status_text: response.statusText };
|
||||
|
||||
if (response.status == 500) // fatal error
|
||||
{
|
||||
console.error('Worker: Fatal error detected');
|
||||
}
|
||||
else if (response.status == 502 || response.status == 503) // server gave up
|
||||
{
|
||||
console.error('Worker: server unavailable or overloaded');
|
||||
}
|
||||
else {
|
||||
console.error('Worker: Unknown error', response);
|
||||
}
|
||||
postMessage({'status' : false, message: message});
|
||||
}
|
||||
},
|
||||
SetEnv: function (data)
|
||||
{
|
||||
for (var key in data)
|
||||
{
|
||||
this[key] = data[key];
|
||||
}
|
||||
},
|
||||
ShutDown: function()
|
||||
{
|
||||
this.stopped = true;
|
||||
// this.Fetch();
|
||||
},
|
||||
UpdateLocalSecret: function(key)
|
||||
{
|
||||
this.secret = key;
|
||||
},
|
||||
GetItemView: function(data)
|
||||
{
|
||||
this.action = 'shortpixel_get_item_view';
|
||||
this.Fetch(data);
|
||||
},
|
||||
AjaxRequest: function(data)
|
||||
{
|
||||
this.action = 'shortpixel_ajaxRequest';
|
||||
this.Fetch(data);
|
||||
},
|
||||
Process: function(data)
|
||||
{
|
||||
this.action = 'shortpixel_image_processing';
|
||||
this.Fetch(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // worker
|
@ -0,0 +1,901 @@
|
||||
/**
|
||||
* Short Pixel WordPress Plugin javascript
|
||||
*/
|
||||
// init checks bulkProcess on each page. initSettings is when the settings View is being loaded.
|
||||
jQuery(document).ready(function(){ShortPixel.init(); });
|
||||
|
||||
function delayedInit() {
|
||||
if(typeof ShortPixel !== 'undefined' && ShortPixel.didInit == false) {
|
||||
|
||||
console.error('ShortPixel: Delayed Init. Check your installation for errors');
|
||||
ShortPixel.init();
|
||||
} else {
|
||||
setTimeout(delayedInit, 10000);
|
||||
}
|
||||
}
|
||||
setTimeout(delayedInit, 10000);
|
||||
|
||||
var ShortPixel = function() {
|
||||
|
||||
var updateTimer;
|
||||
|
||||
// The InitSettings usually runs before these settings, making everything complicated (@todo)
|
||||
function init() {
|
||||
|
||||
if (typeof ShortPixel.API_IS_ACTIVE !== 'undefined') return; //was initialized by the 10 sec. setTimeout, rare but who knows, might happen on very slow connections...
|
||||
|
||||
//are we on media list?
|
||||
if( jQuery('table.wp-list-table.media').length > 0) {
|
||||
//register a bulk action
|
||||
jQuery('select[name^="action"] option:last-child').before('<option value="shortpixel-optimize">' + _spTr.optimizeWithSP
|
||||
+ '</option><option value="shortpixel-lossy"> → ' + _spTr.redoLossy
|
||||
+ '</option><option value="shortpixel-glossy"> → ' + _spTr.redoGlossy
|
||||
+ '</option><option value="shortpixel-lossless"> → ' + _spTr.redoLossless
|
||||
+ '</option><option value="shortpixel-restore"> → ' + _spTr.restoreOriginal
|
||||
+ '</option><option value="shortpixel-smartcrop"> → ' + _spTr.redoSmartcrop
|
||||
+ '</option><option value="shortpixel-smartcropless"> → ' + _spTr.redoSmartcropless
|
||||
+ '</option><option value="shortpixel-mark-completed"> → ' + _spTr.markCompleted
|
||||
+ '</option>');
|
||||
}
|
||||
|
||||
// Extracting the protected Array from within the 0 element of the parent array
|
||||
ShortPixel.setOptions(ShortPixelConstants[0]);
|
||||
|
||||
if (jQuery('#shortpixel-form-request-key').length > 0)
|
||||
{
|
||||
jQuery('#pluginemail').on('change, keyup', jQuery.proxy(this.updateSignupEmail, this));
|
||||
jQuery('#request_key').on('mouseenter', jQuery.proxy(this.updateSignupEmail, this));
|
||||
jQuery('#request_key').on('click', jQuery.proxy(this.newApiKey, this));
|
||||
}
|
||||
|
||||
if (window.ShortPixelProcessor)
|
||||
{
|
||||
window.ShortPixelProcessor.Load(ShortPixel['HAS_QUOTA']);
|
||||
}
|
||||
this.didInit = true;
|
||||
|
||||
// Move footer notices to the top, where it should be.
|
||||
$headerEnd = jQuery( '.wp-header-end' );
|
||||
jQuery( 'div.shortpixel-notice' ).not( '.inline, .below-h2' ).insertAfter( $headerEnd );
|
||||
|
||||
var settingsPage = document.querySelector('.is-shortpixel-settings-page');
|
||||
if (settingsPage !== null)
|
||||
{
|
||||
this.initSettings();
|
||||
}
|
||||
}
|
||||
function setOptions(options) {
|
||||
for(var opt in options) {
|
||||
ShortPixel[opt] = options[opt];
|
||||
}
|
||||
}
|
||||
|
||||
function isEmailValid(email) {
|
||||
// return /^\w+([\.+-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,63})+$/.test(email);
|
||||
|
||||
var regex = /^\S+@\S+\.\S+$/;
|
||||
return regex.test(email);
|
||||
}
|
||||
|
||||
function updateSignupEmail() {
|
||||
|
||||
clearTimeout( ShortPixel.updateTimer );
|
||||
|
||||
ShortPixel.updateTimer = setTimeout( function() {
|
||||
|
||||
var email = jQuery('#pluginemail').val().trim();
|
||||
var $submit = jQuery('#request_key');
|
||||
var isValid = ShortPixel.isEmailValid(email)
|
||||
if(isValid) {
|
||||
jQuery('#request_key').removeClass('disabled');
|
||||
$submit.removeClass('disabled');
|
||||
$submit.removeAttr('disabled');
|
||||
}
|
||||
else
|
||||
{
|
||||
$submit.attr('disabled', true);
|
||||
$submit.addClass('disabled');
|
||||
}
|
||||
jQuery('#request_key').attr('href', jQuery('#request_key').attr('href').split('?')[0] + '?pluginemail=' + email);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function validateKey(button){
|
||||
jQuery('#valid').val('validate');
|
||||
|
||||
jQuery(button).parents('form').submit();
|
||||
}
|
||||
|
||||
jQuery("#key").on('keypress', function(e) {
|
||||
if(e.which == 13) {
|
||||
jQuery('#valid').val('validate');
|
||||
}
|
||||
});
|
||||
|
||||
function enableResize(elm) {
|
||||
if(jQuery(elm).is(':checked')) {
|
||||
jQuery("#width,#height").prop("disabled", false);
|
||||
SpioResize.lastW = false; //to trigger the animation
|
||||
jQuery(".resize-type-wrap").show(800, window.SpioResize.run);
|
||||
} else {
|
||||
jQuery("#width,#height").prop("disabled", true);
|
||||
window.SpioResize.hide();
|
||||
jQuery(".resize-type-wrap").hide(800);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkExifWarning()
|
||||
{
|
||||
if (! jQuery('input[name="removeExif"]').is(':checked') && jQuery('input[name="png2jpg"]').is(':checked') )
|
||||
jQuery('.exif_warning').fadeIn();
|
||||
else
|
||||
jQuery('.exif_warning').fadeOut();
|
||||
|
||||
if (! jQuery('input[name="removeExif"]').is(':checked') && jQuery('.exif_imagick_warning').data('imagick') <= 0)
|
||||
jQuery('.exif_imagick_warning').fadeIn();
|
||||
else
|
||||
jQuery('.exif_imagick_warning').fadeOut();
|
||||
|
||||
}
|
||||
|
||||
function checkSmartCropWarning()
|
||||
{
|
||||
if (jQuery('input[name="useSmartcrop"]').is(':checked') && jQuery('.smartcrop_warning').data('smartcrop') == 1 )
|
||||
jQuery('.smartcrop_warning').fadeIn();
|
||||
else
|
||||
jQuery('.smartcrop_warning').fadeOut();
|
||||
|
||||
}
|
||||
|
||||
function checkBackUpWarning()
|
||||
{
|
||||
if (! jQuery('input[name="backupImages"]').is(':checked') )
|
||||
{
|
||||
jQuery('.backup_warning').fadeIn();
|
||||
}
|
||||
else {
|
||||
jQuery('.backup_warning').fadeOut();
|
||||
}
|
||||
}
|
||||
|
||||
function checkHeavyFeatureWarning(name)
|
||||
{
|
||||
var inputName = (name == 'retina') ? 'optimizeRetina' : 'optimizeUnlisted';
|
||||
var input = jQuery('input[name="' + inputName + '"]');
|
||||
|
||||
if (! input)
|
||||
return;
|
||||
|
||||
var warningEl = jQuery('.heavy-feature-virtual.' + name );
|
||||
|
||||
|
||||
if (input.is(':checked'))
|
||||
{
|
||||
//input.attr('disabled', true);
|
||||
warningEl.fadeIn();
|
||||
}
|
||||
else {
|
||||
//input.attr('disabled', false);
|
||||
warningEl.fadeOut();
|
||||
}
|
||||
}
|
||||
|
||||
function setupGeneralTab() {
|
||||
// @todo Make something workable out of this
|
||||
var rad = 0;
|
||||
|
||||
if (typeof document.wp_shortpixel_options !== 'undefined')
|
||||
rad = document.wp_shortpixel_options.compressionType;
|
||||
|
||||
if (document.getElementById('compressionType-database') !== null)
|
||||
var savedCompression = document.getElementById('compressionType-database').value;
|
||||
else
|
||||
var savedCompression = null;
|
||||
|
||||
for(var i = 0, prev = null; i < rad.length; i++) {
|
||||
rad[i].onclick = function() {
|
||||
|
||||
if(this !== prev) {
|
||||
prev = this;
|
||||
}
|
||||
|
||||
if (this.value == savedCompression)
|
||||
jQuery('.compression-notice-row').addClass('shortpixel-hide');
|
||||
else
|
||||
jQuery('.compression-notice-row').removeClass('shortpixel-hide');
|
||||
};
|
||||
}
|
||||
|
||||
ShortPixel.enableResize("#resize");
|
||||
|
||||
jQuery("#resize").on('change', function(){ enableResize(this); });
|
||||
jQuery(".resize-sizes").on('blur', function(e){
|
||||
var elm = jQuery(e.target);
|
||||
|
||||
if(ShortPixel.resizeSizesAlert == elm.val())
|
||||
return; // returns if check in progress, presumed.
|
||||
|
||||
ShortPixel.resizeSizesAlert = elm.val();
|
||||
var minSize = jQuery("#min-" + elm.attr('name')).val();
|
||||
var niceName = jQuery("#min-" + elm.attr('name')).data('nicename');
|
||||
if(elm.val() < Math.min(minSize, 1024)) { // @todo is this correct? This will always be < 1024, and give first error
|
||||
if(minSize > 1024) {
|
||||
alert( SPstringFormat(_spTr.pleaseDoNotSetLesser1024,niceName) );
|
||||
} else {
|
||||
alert( SPstringFormat(_spTr.pleaseDoNotSetLesserSize, niceName, niceName, minSize) );
|
||||
}
|
||||
e.preventDefault();
|
||||
//elm.val(this.defaultValue);
|
||||
elm.focus();
|
||||
}
|
||||
else {
|
||||
this.defaultValue = elm.val();
|
||||
}
|
||||
});
|
||||
|
||||
jQuery('.shortpixel-confirm').on('click', function(event){
|
||||
var choice = confirm(event.target.getAttribute('data-confirm'));
|
||||
if (!choice) {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
jQuery('input[name="removeExif"], input[name="png2jpg"]').on('change', function()
|
||||
{
|
||||
ShortPixel.checkExifWarning();
|
||||
});
|
||||
ShortPixel.checkExifWarning();
|
||||
|
||||
jQuery('input[name="backupImages"]').on('change', function()
|
||||
{
|
||||
ShortPixel.checkBackUpWarning();
|
||||
});
|
||||
ShortPixel.checkBackUpWarning();
|
||||
|
||||
jQuery('input[name="useSmartcrop"]').on('change', function()
|
||||
{
|
||||
ShortPixel.checkSmartCropWarning();
|
||||
});
|
||||
ShortPixel.checkSmartCropWarning();
|
||||
|
||||
}
|
||||
|
||||
function apiKeyChanged() {
|
||||
jQuery(".wp-shortpixel-options .shortpixel-key-valid").css("display", "none");
|
||||
jQuery(".wp-shortpixel-options button#validate").css("display", "inline-block");
|
||||
}
|
||||
|
||||
function setupAdvancedTab() {
|
||||
|
||||
/* @TODO - Removed in favor of AjaxController method . Remove in next version
|
||||
jQuery("input.remove-folder-button").on('click', function(){
|
||||
var id = jQuery(this).data("value");
|
||||
var path = jQuery(this).data('name');
|
||||
var r = confirm( SPstringFormat(_spTr.areYouSureStopOptimizing, path) );
|
||||
if (r == true) {
|
||||
jQuery("#removeFolder").val(id);
|
||||
jQuery('#wp_shortpixel_options').submit();
|
||||
}
|
||||
});
|
||||
|
||||
jQuery("input.recheck-folder-button").on('click', function(){
|
||||
var path = jQuery(this).data("value");
|
||||
var r = confirm( SPstringFormat(_spTr.areYouSureStopOptimizing, path));
|
||||
if (r == true) {
|
||||
jQuery("#recheckFolder").val(path);
|
||||
jQuery('#wp_shortpixel_options').submit();
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
if (document.querySelector('.heavy-feature-virtual.retina') !== null)
|
||||
{
|
||||
jQuery('input[name="optimizeRetina"]').on('change', function()
|
||||
{
|
||||
ShortPixel.checkHeavyFeatureWarning('retina');
|
||||
});
|
||||
ShortPixel.checkHeavyFeatureWarning('retina');
|
||||
}
|
||||
|
||||
if (document.querySelector('.heavy-feature-virtual.unlisted') !== null)
|
||||
{
|
||||
jQuery('input[name="optimizeUnlisted"]').on('change', function()
|
||||
{
|
||||
ShortPixel.checkHeavyFeatureWarning('unlisted');
|
||||
});
|
||||
ShortPixel.checkHeavyFeatureWarning('unlisted');
|
||||
}
|
||||
}
|
||||
|
||||
function checkThumbsUpdTotal(el) {
|
||||
var total = jQuery("#" +(el.checked ? "total" : "main")+ "ToProcess").val();
|
||||
jQuery("div.bulk-play span.total").text(total);
|
||||
jQuery("#displayTotal").text(total);
|
||||
}
|
||||
|
||||
function initSettings() {
|
||||
ShortPixel.adjustSettingsTabs();
|
||||
ShortPixel.setupGeneralTab(); // certain alerts.
|
||||
jQuery( window ).on('resize', function() {
|
||||
ShortPixel.adjustSettingsTabs();
|
||||
});
|
||||
|
||||
|
||||
jQuery("article.sp-tabs a.tab-link").on('click', function(e){
|
||||
var theID = jQuery(e.target).data("id");
|
||||
ShortPixel.switchSettingsTab( theID );
|
||||
});
|
||||
|
||||
|
||||
jQuery('input[type=radio][name=deliverWebpType]').on('change', function(e) {
|
||||
// shortpixel-settings init trigger events for toggles, ignore this when so.
|
||||
if (e.detail && e.detail.init && e.detail.init === true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (this.value == 'deliverWebpAltered') {
|
||||
if(window.confirm(_spTr.alertDeliverWebPAltered)){
|
||||
var selectedItems = jQuery('input[type=radio][name=deliverWebpAlteringType]:checked').length;
|
||||
if (selectedItems == 0) {
|
||||
jQuery('#deliverWebpAlteredWP').prop('checked',true);
|
||||
}
|
||||
} else {
|
||||
jQuery(this).prop('checked', false);
|
||||
}
|
||||
} else if(this.value == 'deliverWebpUnaltered') {
|
||||
window.alert(_spTr.alertDeliverWebPUnaltered);
|
||||
}
|
||||
});
|
||||
|
||||
// Init active tab
|
||||
var activeTab = document.querySelector('section.sel-tab');
|
||||
if (activeTab !== null);
|
||||
ShortPixel.switchSettingsTab(activeTab.getAttribute('id'));
|
||||
}
|
||||
|
||||
// Switch between settings tabs.
|
||||
function switchSettingsTab(target){
|
||||
|
||||
var tab = target.replace("tab-",""),
|
||||
beacon = "",
|
||||
section = jQuery("section#" +target);
|
||||
// url = location.href.replace(location.hash,"") + '#' + tab;
|
||||
/*if(history.pushState) {
|
||||
history.pushState(null, null, url);
|
||||
}
|
||||
else {
|
||||
location.hash = url;
|
||||
} */
|
||||
if (section.length == 0)
|
||||
{
|
||||
tab = 'settings'; // if tab does not exist.
|
||||
}
|
||||
jQuery('input[name="display_part"]').val(tab);
|
||||
var uri = window.location.href.toString();
|
||||
if (uri.indexOf("?") > 0) {
|
||||
var clean_uri = uri.substring(0, uri.indexOf("?"));
|
||||
clean_uri += '?' + jQuery.param({'page':'wp-shortpixel-settings', 'part': tab});
|
||||
window.history.replaceState({}, document.title, clean_uri);
|
||||
}
|
||||
|
||||
if(section.length > 0){
|
||||
jQuery("section").removeClass("sel-tab");
|
||||
jQuery('section .wp-shortpixel-tab-content').fadeOut(50);
|
||||
jQuery(section).addClass("sel-tab");
|
||||
//ShortPixel.adjustSettingsTabs();
|
||||
//jQuery(section).find('.wp-shortpixel-tab-content').fadeIn(50);
|
||||
jQuery(section).find('.wp-shortpixel-tab-content').fadeIn(50, ShortPixel.adjustSettingsTabs);
|
||||
|
||||
var event = new CustomEvent('shortpixel.ui.settingsTabLoad', { detail : {tabName: tab, section: section }});
|
||||
window.dispatchEvent(event);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Fixes the height of the current active tab.
|
||||
function adjustSettingsTabsHeight(){
|
||||
jQuery('.wso.banner').css('opacity', 1);
|
||||
}
|
||||
|
||||
function closeHelpPane() {
|
||||
jQuery('#shortpixel-hs-button-blind').remove();
|
||||
jQuery('#shortpixel-hs-tools').remove();
|
||||
jQuery('#hs-beacon').remove();
|
||||
jQuery('#botbutton').remove();
|
||||
jQuery('#shortpixel-hs-blind').remove();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function checkQuota() {
|
||||
var data = {
|
||||
action:'shortpixel_check_quota',
|
||||
nonce: ShortPixelConstants[0].nonce_ajaxrequest,
|
||||
return_json: true
|
||||
};
|
||||
|
||||
jQuery.post(ShortPixel.AJAX_URL, data, function(result) {
|
||||
console.log("quota refreshed");
|
||||
console.log(result);
|
||||
window.location.href = result.redirect;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function percentDial(query, size) {
|
||||
jQuery(query).knob({
|
||||
'readOnly': true,
|
||||
'width': size,
|
||||
'height': size,
|
||||
'fgColor': '#1CAECB',
|
||||
'format' : function (value) {
|
||||
return value + '%';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function browseContent(browseData) {
|
||||
browseData.action = 'shortpixel_browse_content';
|
||||
|
||||
var browseResponse = "";
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: ShortPixel.AJAX_URL,
|
||||
data: browseData,
|
||||
success: function(response) {
|
||||
browseResponse = response;
|
||||
},
|
||||
async: false
|
||||
});
|
||||
return browseResponse;
|
||||
}
|
||||
|
||||
|
||||
function newApiKey(event) {
|
||||
event.preventDefault();
|
||||
ShortPixel.updateSignupEmail();
|
||||
|
||||
if(!jQuery("#tos").is( ":checked" )) {
|
||||
event.preventDefault();
|
||||
jQuery("#tos-robo").fadeIn(400,function(){jQuery("#tos-hand").fadeIn();});
|
||||
jQuery("#tos").click(function(){
|
||||
jQuery("#tos-robo").css("display", "none");
|
||||
jQuery("#tos-hand").css("display", "none");
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (jQuery('#request_key').is(':disabled'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
jQuery('#request_key').addClass('disabled');
|
||||
jQuery('#pluginemail_spinner').addClass('is-active');
|
||||
|
||||
jQuery('#shortpixel-form-request-key').submit();
|
||||
|
||||
}
|
||||
|
||||
function proposeUpgrade() {
|
||||
//first open the popup window with the spinner
|
||||
jQuery("#shortPixelProposeUpgrade .sp-modal-body").addClass('sptw-modal-spinner');
|
||||
jQuery("#shortPixelProposeUpgrade .sp-modal-body").html("");
|
||||
jQuery("#shortPixelProposeUpgradeShade").css("display", "block");
|
||||
jQuery("#shortPixelProposeUpgrade").removeClass('shortpixel-hide');
|
||||
jQuery("#shortPixelProposeUpgradeShade").on('click', this.closeProposeUpgrade);
|
||||
//get proposal from server
|
||||
var browseData = { 'action': 'shortpixel_propose_upgrade', nonce: ShortPixelConstants[0].nonce_ajaxrequest};
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: ShortPixel.AJAX_URL,
|
||||
data: browseData,
|
||||
success: function(response) {
|
||||
jQuery("#shortPixelProposeUpgrade .sp-modal-body").removeClass('sptw-modal-spinner');
|
||||
jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(response);
|
||||
},
|
||||
complete: function(response, status)
|
||||
{
|
||||
//console.log(response, status);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function closeProposeUpgrade() {
|
||||
jQuery("#shortPixelProposeUpgradeShade").css("display", "none");
|
||||
jQuery("#shortPixelProposeUpgrade").addClass('shortpixel-hide');
|
||||
if(ShortPixel.toRefresh) {
|
||||
ShortPixel.checkQuota();
|
||||
}
|
||||
}
|
||||
|
||||
// used in bulk restore all interface
|
||||
function checkRandomAnswer(e)
|
||||
{
|
||||
var value = jQuery(e.target).val();
|
||||
var answer = jQuery('input[name="random_answer"]').val();
|
||||
var target = jQuery('input[name="random_answer"]').data('target');
|
||||
|
||||
if (value == answer)
|
||||
{
|
||||
jQuery(target).removeClass('disabled').prop('disabled', false);
|
||||
jQuery(target).removeAttr('aria-disabled');
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
jQuery(target).addClass('disabled').prop('disabled', true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function openImageMenu(e) {
|
||||
e.preventDefault();
|
||||
//install (lazily) a window click event to close the menus
|
||||
if(!this.menuCloseEvent) {
|
||||
jQuery(window).on('click', function(e){
|
||||
if (!e.target.matches('.sp-dropbtn')) {
|
||||
jQuery('.sp-dropdown.sp-show').removeClass('sp-show');
|
||||
}
|
||||
});
|
||||
this.menuCloseEvent = true;
|
||||
}
|
||||
var shown = e.target.parentElement.classList.contains("sp-show");
|
||||
jQuery('.sp-dropdown.sp-show').removeClass('sp-show');
|
||||
if(!shown) e.target.parentElement.classList.add("sp-show");
|
||||
}
|
||||
|
||||
function loadComparer(id, type) {
|
||||
this.comparerData.origUrl = false;
|
||||
if(this.comparerData.cssLoaded === false) {
|
||||
jQuery('<link>')
|
||||
.appendTo('head')
|
||||
.attr({
|
||||
type: 'text/css',
|
||||
rel: 'stylesheet',
|
||||
href: this.WP_PLUGIN_URL + '/res/css/twentytwenty.min.css'
|
||||
});
|
||||
this.comparerData.cssLoaded = 2;
|
||||
}
|
||||
if(this.comparerData.jsLoaded === false) {
|
||||
jQuery.getScript(this.WP_PLUGIN_URL + '/res/js/jquery.twentytwenty.min.js', function(){
|
||||
ShortPixel.comparerData.jsLoaded = 2;
|
||||
/* What should this do?
|
||||
if(ShortPixel.comparerData.origUrl.length > 0) {
|
||||
ShortPixel.displayComparerPopup(ShortPixel.comparerData.width, ShortPixel.comparerData.height, ShortPixel.comparerData.origUrl, ShortPixel.comparerData.optUrl);
|
||||
} */
|
||||
});
|
||||
this.comparerData.jsLoaded = 1;
|
||||
//jQuery(".sp-close-button").click(ShortPixel.closeComparerPopup);
|
||||
}
|
||||
if(this.comparerData.origUrl === false) {
|
||||
if (typeof type == 'undefined')
|
||||
var type = 'media'; // default.
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: ShortPixel.AJAX_URL,
|
||||
data: { action : 'shortpixel_get_comparer_data', id : id, type: type, nonce: ShortPixelConstants[0].nonce_ajaxrequest },
|
||||
success: function(response) {
|
||||
// data = JSON.parse(response);
|
||||
|
||||
jQuery.extend(ShortPixel.comparerData, response);
|
||||
if(ShortPixel.comparerData.jsLoaded == 2) {
|
||||
ShortPixel.displayComparerPopup(ShortPixel.comparerData.width, ShortPixel.comparerData.height, ShortPixel.comparerData.origUrl, ShortPixel.comparerData.optUrl);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.comparerData.origUrl = '';
|
||||
}
|
||||
}
|
||||
|
||||
function displayComparerPopup(width, height, imgOriginal, imgOptimized) {
|
||||
//image sizes
|
||||
var origWidth = width;
|
||||
//depending on the sizes choose the right modal
|
||||
var sideBySide = (height < 150 || width < 350);
|
||||
var modal = jQuery(sideBySide ? '#spUploadCompareSideBySide' : '#spUploadCompare');
|
||||
var modalShade = jQuery('.sp-modal-shade');
|
||||
|
||||
if(!sideBySide) {
|
||||
jQuery("#spCompareSlider").html('<img alt="' + _spTr.originalImage + '" class="spUploadCompareOriginal"/><img alt="' + _spTr.optimizedImage + '" class="spUploadCompareOptimized"/>');
|
||||
}
|
||||
//calculate the modal size
|
||||
width = Math.max(350, Math.min(800, (width < 350 ? (width + 25) * 2 : (height < 150 ? width + 25 : width))));
|
||||
height = Math.max(150, (sideBySide ? (origWidth > 350 ? 2 * (height + 45) : height + 45) : height * width / origWidth));
|
||||
|
||||
var marginLeft = '-' + Math.round(width/2); // center
|
||||
|
||||
//set modal sizes and display
|
||||
jQuery(".sp-modal-body", modal).css("width", width);
|
||||
jQuery(".shortpixel-slider", modal).css("width", width);
|
||||
modal.css("width", width);
|
||||
modal.css('marginLeft', marginLeft + 'px');
|
||||
modal.removeClass('shortpixel-hide');
|
||||
jQuery(".sp-modal-body", modal).css("height", height);
|
||||
modal.show();
|
||||
//modal.parent().css('display', 'block');
|
||||
modalShade.show();
|
||||
|
||||
if(!sideBySide) {
|
||||
jQuery("#spCompareSlider").twentytwenty({slider_move: "mousemove"});
|
||||
}
|
||||
|
||||
// Close Options
|
||||
jQuery(".sp-close-button").on('click', { modal: modal}, ShortPixel.closeComparerPopup);
|
||||
jQuery(document).on('keyup.sp_modal_active', { modal: modal}, ShortPixel.closeComparerPopup );
|
||||
jQuery('.sp-modal-shade').on('click', { modal: modal}, ShortPixel.closeComparerPopup, );
|
||||
|
||||
//change images srcs
|
||||
var imgOpt = jQuery(".spUploadCompareOptimized", modal);
|
||||
jQuery(".spUploadCompareOriginal", modal).attr("src", imgOriginal);
|
||||
//these timeouts are for the slider - it needs a punch to work :)
|
||||
setTimeout(function(){
|
||||
jQuery(window).trigger('resize');
|
||||
}, 1000);
|
||||
imgOpt.load(function(){
|
||||
jQuery(window).trigger('resize');
|
||||
});
|
||||
imgOpt.attr("src", imgOptimized);
|
||||
|
||||
console.log('Popup Loaded! ', modal);
|
||||
}
|
||||
|
||||
function closeComparerPopup(e) {
|
||||
|
||||
e.data.modal.addClass('shortpixel-hide');
|
||||
jQuery('.sp-modal-shade').hide();
|
||||
jQuery(document).unbind('keyup.sp_modal_active');
|
||||
jQuery('.sp-modal-shade').off('click');
|
||||
jQuery(".sp-close-button").off('click');
|
||||
}
|
||||
|
||||
function convertPunycode(url) {
|
||||
var parser = document.createElement('a');
|
||||
parser.href = url;
|
||||
if(url.indexOf(parser.protocol + '//' + parser.hostname) < 0) {
|
||||
return parser.href;
|
||||
}
|
||||
return url.replace(parser.protocol + '//' + parser.hostname, parser.protocol + '//' + parser.hostname.split('.').map(function(part) {return sp_punycode.toASCII(part)}).join('.'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
return {
|
||||
init : init,
|
||||
didInit : false,
|
||||
setOptions : setOptions,
|
||||
isEmailValid : isEmailValid,
|
||||
updateSignupEmail : updateSignupEmail,
|
||||
validateKey : validateKey,
|
||||
enableResize : enableResize,
|
||||
setupGeneralTab : setupGeneralTab,
|
||||
apiKeyChanged : apiKeyChanged,
|
||||
setupAdvancedTab : setupAdvancedTab,
|
||||
checkThumbsUpdTotal : checkThumbsUpdTotal,
|
||||
initSettings : initSettings,
|
||||
switchSettingsTab : switchSettingsTab,
|
||||
adjustSettingsTabs : adjustSettingsTabsHeight,
|
||||
closeHelpPane : closeHelpPane,
|
||||
checkQuota : checkQuota,
|
||||
percentDial : percentDial,
|
||||
// initFolderSelector : initFolderSelector,
|
||||
browseContent : browseContent,
|
||||
newApiKey : newApiKey,
|
||||
proposeUpgrade : proposeUpgrade,
|
||||
closeProposeUpgrade : closeProposeUpgrade,
|
||||
// includeUnlisted : includeUnlisted,
|
||||
checkRandomAnswer : checkRandomAnswer,
|
||||
// recheckQuota : recheckQuota,
|
||||
openImageMenu : openImageMenu,
|
||||
menuCloseEvent : false,
|
||||
loadComparer : loadComparer,
|
||||
displayComparerPopup: displayComparerPopup,
|
||||
closeComparerPopup : closeComparerPopup,
|
||||
convertPunycode : convertPunycode,
|
||||
checkExifWarning : checkExifWarning,
|
||||
checkBackUpWarning : checkBackUpWarning,
|
||||
checkSmartCropWarning: checkSmartCropWarning,
|
||||
checkHeavyFeatureWarning : checkHeavyFeatureWarning,
|
||||
comparerData : {
|
||||
cssLoaded : false,
|
||||
jsLoaded : false,
|
||||
origUrl : false,
|
||||
optUrl : false,
|
||||
width : 0,
|
||||
height : 0
|
||||
},
|
||||
toRefresh : false,
|
||||
resizeSizesAlert: false,
|
||||
returnedStatusSearching: 0, // How often this status has come back in a row from server.
|
||||
|
||||
}
|
||||
}(); // End of ShortPixel
|
||||
|
||||
// first is string to replace, rest are arguments.
|
||||
function SPstringFormat() {
|
||||
var params = Array.prototype.slice.call(arguments);
|
||||
|
||||
if (params.length === 0)
|
||||
return;
|
||||
|
||||
var s = params.shift();
|
||||
|
||||
// skip the first one.
|
||||
for (i=0; i< params.length; i++) {
|
||||
s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), params[i]);
|
||||
}
|
||||
return s;
|
||||
};
|
||||
/** This doesn't go well with REACT environments */
|
||||
/*if (!(typeof String.prototype.format == 'function')) {
|
||||
String.prototype.format = stringFormat;
|
||||
} */
|
||||
|
||||
|
||||
( function( $, w, d ) {
|
||||
w.SpioResize = {
|
||||
image : {
|
||||
width : 0,
|
||||
height : 0
|
||||
},
|
||||
lag: 2000,
|
||||
step1: false,
|
||||
step2: false,
|
||||
step3: false,
|
||||
sizeRule: null,
|
||||
initialized: false,
|
||||
lastW: false,
|
||||
lastH: false,
|
||||
lastType: false,
|
||||
};
|
||||
|
||||
SpioResize.hide = function() {
|
||||
jQuery('.presentation-wrap').css('opacity', 0);
|
||||
}
|
||||
|
||||
SpioResize.animate = function(img, step1, frame, step2, rule) {
|
||||
img.animate( step1, 1000, 'swing', function(){
|
||||
SpioResize.step3 = setTimeout(function(){
|
||||
document.styleSheets[0].deleteRule(SpioResize.sizeRule);
|
||||
frame.animate(step2, 1000, 'swing', function() {
|
||||
SpioResize.sizeRule = document.styleSheets[0].insertRule(rule);
|
||||
})
|
||||
}, 600);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
SpioResize.run = function() {
|
||||
if(!SpioResize.initialized) {
|
||||
var $document = $( d );
|
||||
$document.on( 'input change', 'input[name="resizeWidth"], input[name="resizeHeight"]', function(e) {
|
||||
clearTimeout(SpioResize.change);
|
||||
SpioResize.changeDone = true;
|
||||
SpioResize.changeFired = false;
|
||||
SpioResize.change = setTimeout( function() {
|
||||
SpioResize.changeFired = true;
|
||||
SpioResize.run();
|
||||
}, 1500 );
|
||||
} );
|
||||
$document.on( 'blur', 'input[name="resizeWidth"], input[name="resizeHeight"]', function(e) {
|
||||
if(SpioResize.changeFired) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(SpioResize.change);
|
||||
SpioResize.change = setTimeout( function() {
|
||||
SpioResize.run();
|
||||
}, 1500 );
|
||||
} );
|
||||
$document.on( 'change', 'input[name="resizeType"]', function(e) {
|
||||
SpioResize.run();
|
||||
});
|
||||
SpioResize.initialized = true;
|
||||
}
|
||||
|
||||
var w = $('#width').val();
|
||||
var h = $('#height').val();
|
||||
if(!w || !h) return;
|
||||
var type = ($('#resize_type_outer').is(':checked') ? 'outer' : 'inner');
|
||||
if(w === SpioResize.lastW && h === SpioResize.lastH && type === SpioResize.lastType) {
|
||||
return;
|
||||
}
|
||||
SpioResize.hide();
|
||||
SpioResize.lastW = w;
|
||||
SpioResize.lastH = h;
|
||||
SpioResize.lastType = type;
|
||||
|
||||
var frame1W = Math.round(120 * Math.sqrt(w / h));
|
||||
var frame1H = Math.round(120 * Math.sqrt(h / w));
|
||||
var frameAR = frame1W / frame1H;
|
||||
if(frame1W > 280) {
|
||||
frame1W = 280; frame1H = Math.round(280 / frameAR);
|
||||
}
|
||||
if(frame1H > 150) {
|
||||
frame1H = 150; frame1W = Math.round(150 * frameAR);
|
||||
}
|
||||
var imgAR = 15 / 8;
|
||||
var img = $('img.spai-resize-img');
|
||||
img.css('width', '');
|
||||
img.css('height', '');
|
||||
img.css('margin', '0px');
|
||||
var frame = $('div.spai-resize-frame');
|
||||
frame.css('display', 'none');
|
||||
frame.css('width', frame1W + 'px');
|
||||
frame.css('height', frame1H + 'px');
|
||||
frame.css('margin', Math.round((156 - frame1H ) / 2) + 'px auto 0');
|
||||
|
||||
clearTimeout(SpioResize.step1); clearTimeout(SpioResize.step2); clearTimeout(SpioResize.step3);
|
||||
img.stop(); frame.stop();
|
||||
|
||||
if(SpioResize.sizeRule !== null) {
|
||||
document.styleSheets[0].deleteRule(SpioResize.sizeRule);
|
||||
SpioResize.sizeRule = null;
|
||||
}
|
||||
SpioResize.sizeRule = document.styleSheets[0].insertRule('.spai-resize-frame:after { content: "' + w + ' × ' + h + '"; }');
|
||||
frame.addClass('spai-resize-frame');
|
||||
|
||||
$('.presentation-wrap').animate( {opacity: 1}, 500, 'swing', function(){
|
||||
//because damn chrome is not repainting the frame after we change the sizes otherwise... :(
|
||||
frame.css('display', 'block');
|
||||
|
||||
SpioResize.step2 = setTimeout(function(){
|
||||
if(type == 'outer') {
|
||||
if(imgAR > frameAR) {
|
||||
var step1 = {
|
||||
height: frame1H + 'px',
|
||||
margin: Math.round((160 - frame1H) / 2) + 'px 0px'
|
||||
};
|
||||
var frameNewW = frame1H * imgAR;
|
||||
var step2 = { width: Math.round(frameNewW) + 'px' };
|
||||
var rule = '.spai-resize-frame:after { content: "' + Math.round(frameNewW * w / frame1W) + ' × ' + h + '"; }';
|
||||
} else {
|
||||
var step1 = {
|
||||
width: frame1W + 'px',
|
||||
margin: Math.round((160 - frame1W / imgAR) / 2) + 'px 0px'
|
||||
};
|
||||
var frameNewH = frame1W / imgAR;
|
||||
var step2 = {
|
||||
height: Math.round(frameNewH) + 'px',
|
||||
margin: Math.round((156 - frameNewH) / 2) + 'px auto 0'
|
||||
};
|
||||
var rule = '.spai-resize-frame:after { content: "' + w + ' × ' + Math.round(frameNewH * w / frame1W) + '"; }';
|
||||
|
||||
}
|
||||
} else {
|
||||
if(imgAR > frameAR) {
|
||||
var step1 = {
|
||||
width: frame1W,
|
||||
margin: Math.round((160 - frame1W / imgAR) / 2) + 'px 0px'
|
||||
};
|
||||
var frameNewH = frame1W / imgAR;
|
||||
var step2 = {
|
||||
height: Math.round(frameNewH) + 'px',
|
||||
margin: Math.round((156 - frameNewH) / 2) + 'px auto 0'
|
||||
};
|
||||
var rule = '.spai-resize-frame:after { content: "' + w + ' × ' + Math.round(frameNewH * w / frame1W) + '"; }';
|
||||
} else {
|
||||
var step1 = {
|
||||
height: frame1H,
|
||||
margin: Math.round((160 - frame1H) / 2) + 'px 0px'
|
||||
};
|
||||
var frameNewW = frame1H * imgAR;
|
||||
var step2 = {
|
||||
width: Math.round(frameNewW) + 'px'
|
||||
};
|
||||
var rule = '.spai-resize-frame:after { content: "' + Math.round(frameNewW * w / frame1W) + ' × ' + h + '"; }';
|
||||
}
|
||||
}
|
||||
SpioResize.animate(img, step1, frame, step2, rule);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
$( function() {
|
||||
if($('#resize').is('checked')) {
|
||||
SpioResize.run();
|
||||
}
|
||||
} );
|
||||
} )( jQuery, window, document );
|
@ -0,0 +1,213 @@
|
||||
|
||||
/*
|
||||
* jQueryFileTree Plugin
|
||||
*
|
||||
* @author - Cory S.N. LaViska - A Beautiful Site (http://abeautifulsite.net/) - 24 March 2008
|
||||
* @author - Dave Rogers - (https://github.com/daverogers/)
|
||||
*
|
||||
* Usage: $('.fileTreeDemo').fileTree({ options }, callback )
|
||||
*
|
||||
* TERMS OF USE
|
||||
*
|
||||
* This plugin is dual-licensed under the GNU General Public License and the MIT License and
|
||||
* is copyright 2008 A Beautiful Site, LLC.
|
||||
*/
|
||||
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
|
||||
(function($, window) {
|
||||
var FileTree;
|
||||
FileTree = (function() {
|
||||
function FileTree(el, args, callback) {
|
||||
this.onEvent = bind(this.onEvent, this);
|
||||
var $el, _this, defaults;
|
||||
$el = $(el);
|
||||
_this = this;
|
||||
defaults = {
|
||||
root: '/',
|
||||
script: '/files/filetree',
|
||||
folderEvent: 'click',
|
||||
expandSpeed: 500,
|
||||
collapseSpeed: 500,
|
||||
expandEasing: 'swing',
|
||||
collapseEasing: 'swing',
|
||||
multiFolder: true,
|
||||
loadMessage: 'Loading...',
|
||||
errorMessage: 'Unable to get file tree information',
|
||||
multiSelect: false,
|
||||
onlyFolders: false,
|
||||
onlyFiles: false,
|
||||
preventLinkAction: false
|
||||
};
|
||||
this.jqft = {
|
||||
container: $el
|
||||
};
|
||||
this.options = $.extend(defaults, args);
|
||||
this.callback = callback;
|
||||
this.data = {};
|
||||
$el.html('<ul class="jqueryFileTree start"><li class="wait">' + this.options.loadMessage + '<li></ul>');
|
||||
_this.showTree($el, escape(this.options.root), function() {
|
||||
return _this._trigger('filetreeinitiated', {});
|
||||
});
|
||||
$el.delegate("li a", this.options.folderEvent, _this.onEvent);
|
||||
}
|
||||
|
||||
FileTree.prototype.onEvent = function(event) {
|
||||
var $ev, _this, callback, jqft, options, ref;
|
||||
$ev = $(event.target);
|
||||
options = this.options;
|
||||
jqft = this.jqft;
|
||||
_this = this;
|
||||
callback = this.callback;
|
||||
_this.data = {};
|
||||
_this.data.li = $ev.closest('li');
|
||||
_this.data.type = (ref = _this.data.li.hasClass('directory')) != null ? ref : {
|
||||
'directory': 'file'
|
||||
};
|
||||
_this.data.value = $ev.text();
|
||||
_this.data.rel = $ev.prop('rel');
|
||||
_this.data.container = jqft.container;
|
||||
if (options.preventLinkAction) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if ($ev.parent().hasClass('directory')) {
|
||||
_this.jqft.container.find('LI.directory').removeClass('selected');
|
||||
$ev.parent().addClass('selected');
|
||||
if ($ev.parent().hasClass('collapsed')) {
|
||||
if (!options.multiFolder) {
|
||||
$ev.parent().parent().find('UL').slideUp({
|
||||
duration: options.collapseSpeed,
|
||||
easing: options.collapseEasing
|
||||
});
|
||||
$ev.parent().parent().find('LI.directory').removeClass('expanded').addClass('collapsed');
|
||||
}
|
||||
$ev.parent().removeClass('collapsed').addClass('expanded');
|
||||
$ev.parent().find('UL').remove();
|
||||
return _this.showTree($ev.parent(), $ev.attr('rel'), function() {
|
||||
_this._trigger('filetreeexpanded', _this.data);
|
||||
return callback != null;
|
||||
});
|
||||
} else {
|
||||
return $ev.parent().find('UL').slideUp({
|
||||
duration: options.collapseSpeed,
|
||||
easing: options.collapseEasing,
|
||||
start: function() {
|
||||
return _this._trigger('filetreecollapse', _this.data);
|
||||
},
|
||||
complete: function() {
|
||||
$ev.parent().removeClass('expanded').addClass('collapsed');
|
||||
_this._trigger('filetreecollapsed', _this.data);
|
||||
return callback != null;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!options.multiSelect) {
|
||||
jqft.container.find('li').removeClass('selected');
|
||||
$ev.parent().addClass('selected');
|
||||
} else {
|
||||
if ($ev.parent().find('input').is(':checked')) {
|
||||
$ev.parent().find('input').prop('checked', false);
|
||||
$ev.parent().removeClass('selected');
|
||||
} else {
|
||||
$ev.parent().find('input').prop('checked', true);
|
||||
$ev.parent().addClass('selected');
|
||||
}
|
||||
}
|
||||
_this._trigger('filetreeclicked', _this.data);
|
||||
return typeof callback === "function" ? callback($ev.attr('rel')) : void 0;
|
||||
}
|
||||
};
|
||||
|
||||
FileTree.prototype.showTree = function(el, dir, finishCallback) {
|
||||
var $el, _this, data, handleFail, handleResult, options, result;
|
||||
$el = $(el);
|
||||
options = this.options;
|
||||
_this = this;
|
||||
$el.addClass('wait');
|
||||
$(".jqueryFileTree.start").remove();
|
||||
data = {
|
||||
dir: dir,
|
||||
onlyFolders: options.onlyFolders,
|
||||
onlyFiles: options.onlyFiles,
|
||||
multiSelect: options.multiSelect
|
||||
};
|
||||
handleResult = function(result) {
|
||||
var li;
|
||||
$el.find('.start').html('');
|
||||
$el.removeClass('wait').append(result);
|
||||
if (options.root === dir) {
|
||||
$el.find('UL:hidden').show(typeof callback !== "undefined" && callback !== null);
|
||||
} else {
|
||||
if (jQuery.easing[options.expandEasing] === void 0) {
|
||||
console.log('Easing library not loaded. Include jQueryUI or 3rd party lib.');
|
||||
options.expandEasing = 'swing';
|
||||
}
|
||||
$el.find('UL:hidden').slideDown({
|
||||
duration: options.expandSpeed,
|
||||
easing: options.expandEasing,
|
||||
start: function() {
|
||||
return _this._trigger('filetreeexpand', _this.data);
|
||||
},
|
||||
complete: finishCallback
|
||||
});
|
||||
}
|
||||
li = $('[rel="' + decodeURIComponent(dir) + '"]').parent();
|
||||
if (options.multiSelect && li.children('input').is(':checked')) {
|
||||
li.find('ul li input').each(function() {
|
||||
$(this).prop('checked', true);
|
||||
return $(this).parent().addClass('selected');
|
||||
});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
handleFail = function() {
|
||||
$el.find('.start').html('');
|
||||
$el.removeClass('wait').append("<p>" + options.errorMessage + "</p>");
|
||||
return false;
|
||||
};
|
||||
if (typeof options.script === 'function') {
|
||||
result = options.script(data);
|
||||
if (typeof result === 'string' || result instanceof jQuery) {
|
||||
return handleResult(result);
|
||||
} else {
|
||||
return handleFail();
|
||||
}
|
||||
} else {
|
||||
return $.ajax({
|
||||
url: options.script,
|
||||
type: 'POST',
|
||||
dataType: 'HTML',
|
||||
data: data
|
||||
}).done(function(result) {
|
||||
return handleResult(result);
|
||||
}).fail(function() {
|
||||
return handleFail();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
FileTree.prototype._trigger = function(eventType, data) {
|
||||
var $el;
|
||||
$el = this.jqft.container;
|
||||
return $el.triggerHandler(eventType, data);
|
||||
};
|
||||
|
||||
return FileTree;
|
||||
|
||||
})();
|
||||
return $.fn.extend({
|
||||
fileTree: function(args, callback) {
|
||||
return this.each(function() {
|
||||
var $this, data;
|
||||
$this = $(this);
|
||||
data = $this.data('fileTree');
|
||||
if (!data) {
|
||||
$this.data('fileTree', (data = new FileTree(this, args, callback)));
|
||||
}
|
||||
if (typeof args === 'string') {
|
||||
return data[option].apply(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})(window.jQuery, window);
|
1
wp-content/plugins/shortpixel-image-optimiser/res/js/sp-file-tree.min.js
vendored
Normal file
1
wp-content/plugins/shortpixel-image-optimiser/res/js/sp-file-tree.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
var bind=function(a,b){return function(){return a.apply(b,arguments)}};(function(b,a){var c;c=(function(){function d(g,e,j){this.onEvent=bind(this.onEvent,this);var f,i,h;f=b(g);i=this;h={root:"/",script:"/files/filetree",folderEvent:"click",expandSpeed:500,collapseSpeed:500,expandEasing:"swing",collapseEasing:"swing",multiFolder:true,loadMessage:"Loading...",errorMessage:"Unable to get file tree information",multiSelect:false,onlyFolders:false,onlyFiles:false,preventLinkAction:false};this.jqft={container:f};this.options=b.extend(h,e);this.callback=j;this.data={};f.html('<ul class="jqueryFileTree start"><li class="wait">'+this.options.loadMessage+"<li></ul>");i.showTree(f,escape(this.options.root),function(){return i._trigger("filetreeinitiated",{})});f.delegate("li a",this.options.folderEvent,i.onEvent)}d.prototype.onEvent=function(h){var f,k,j,i,e,g;f=b(h.target);e=this.options;i=this.jqft;k=this;j=this.callback;k.data={};k.data.li=f.closest("li");k.data.type=(g=k.data.li.hasClass("directory"))!=null?g:{directory:"file"};k.data.value=f.text();k.data.rel=f.prop("rel");k.data.container=i.container;if(e.preventLinkAction){h.preventDefault()}if(f.parent().hasClass("directory")){k.jqft.container.find("LI.directory").removeClass("selected");f.parent().addClass("selected");if(f.parent().hasClass("collapsed")){if(!e.multiFolder){f.parent().parent().find("UL").slideUp({duration:e.collapseSpeed,easing:e.collapseEasing});f.parent().parent().find("LI.directory").removeClass("expanded").addClass("collapsed")}f.parent().removeClass("collapsed").addClass("expanded");f.parent().find("UL").remove();return k.showTree(f.parent(),f.attr("rel"),function(){k._trigger("filetreeexpanded",k.data);return j!=null})}else{return f.parent().find("UL").slideUp({duration:e.collapseSpeed,easing:e.collapseEasing,start:function(){return k._trigger("filetreecollapse",k.data)},complete:function(){f.parent().removeClass("expanded").addClass("collapsed");k._trigger("filetreecollapsed",k.data);return j!=null}})}}else{if(!e.multiSelect){i.container.find("li").removeClass("selected");f.parent().addClass("selected")}else{if(f.parent().find("input").is(":checked")){f.parent().find("input").prop("checked",false);f.parent().removeClass("selected")}else{f.parent().find("input").prop("checked",true);f.parent().addClass("selected")}}k._trigger("filetreeclicked",k.data);return typeof j==="function"?j(f.attr("rel")):void 0}};d.prototype.showTree=function(f,g,n){var m,i,h,e,j,l,k;m=b(f);l=this.options;i=this;m.addClass("wait");b(".jqueryFileTree.start").remove();h={dir:g,onlyFolders:l.onlyFolders,onlyFiles:l.onlyFiles,multiSelect:l.multiSelect};j=function(p){var o;m.find(".start").html("");m.removeClass("wait").append(p);if(l.root===g){m.find("UL:hidden").show(typeof callback!=="undefined"&&callback!==null)}else{if(jQuery.easing[l.expandEasing]===void 0){console.log("Easing library not loaded. Include jQueryUI or 3rd party lib.");l.expandEasing="swing"}m.find("UL:hidden").slideDown({duration:l.expandSpeed,easing:l.expandEasing,start:function(){return i._trigger("filetreeexpand",i.data)},complete:n})}o=b('[rel="'+decodeURIComponent(g)+'"]').parent();if(l.multiSelect&&o.children("input").is(":checked")){o.find("ul li input").each(function(){b(this).prop("checked",true);return b(this).parent().addClass("selected")})}return false};e=function(){m.find(".start").html("");m.removeClass("wait").append("<p>"+l.errorMessage+"</p>");return false};if(typeof l.script==="function"){k=l.script(h);if(typeof k==="string"||k instanceof jQuery){return j(k)}else{return e()}}else{return b.ajax({url:l.script,type:"POST",dataType:"HTML",data:h}).done(function(o){return j(o)}).fail(function(){return e()})}};d.prototype._trigger=function(f,g){var e;e=this.jqft.container;return e.triggerHandler(f,g)};return d})();return b.fn.extend({fileTree:function(d,e){return this.each(function(){var g,f;g=b(this);f=g.data("fileTree");if(!f){g.data("fileTree",(f=new c(this,d,e)))}if(typeof d==="string"){return f[option].apply(f)}})}})})(window.jQuery,window);
|
Reference in New Issue
Block a user