FileMaster
Search
Toggle Dark Mode
Home
/
.
/
wp-content
/
plugins
/
backup-backup
/
admin
/
js
Edit File: backup-migration.min.js
jQuery(document).ready(function($) { (function(root, factory) { if (typeof define === 'function' && define.amd) { define(["jquery"], function(a0) { return (factory(a0)); }); } else if (typeof exports === 'object') { module.exports = factory(require("jquery")); } else { factory(jQuery); } }(this, function($) { // This file will be UMDified by a build task. var defaults = { animation: 'fade', animationDuration: 350, content: null, contentAsHTML: false, contentCloning: false, debug: true, delay: 300, delayTouch: [300, 500], functionInit: null, functionBefore: null, functionReady: null, functionAfter: null, functionFormat: null, IEmin: 6, interactive: false, multiple: false, // will default to document.body, or must be an element positioned at (0, 0) // in the document, typically like the very top views of an app. parent: null, plugins: ['sideTip'], repositionOnScroll: false, restoration: 'none', selfDestruction: true, theme: [], timer: 0, trackerInterval: 500, trackOrigin: false, trackTooltip: false, trigger: 'hover', triggerClose: { click: false, mouseleave: false, originClick: false, scroll: false, tap: false, touchleave: false }, triggerOpen: { click: false, mouseenter: false, tap: false, touchstart: false }, updateAnimation: 'rotate', zIndex: 9999999 }, // we'll avoid using the 'window' global as a good practice but npm's // jquery@<2.1.0 package actually requires a 'window' global, so not sure // it's useful at all win = (typeof window != 'undefined') ? window : null, // env will be proxied by the core for plugins to have access its properties env = { // detect if this device can trigger touch events. Better have a false // positive (unused listeners, that's ok) than a false negative. // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js // http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript hasTouchCapability: !!( win && ('ontouchstart' in win || (win.DocumentTouch && win.document instanceof win.DocumentTouch) || win.navigator.maxTouchPoints ) ), hasTransitions: transitionSupport(), IE: false, // don't set manually, it will be updated by a build task after the manifest semVer: '4.2.8', window: win }, core = function() { // core variables // the core emitters this.__$emitterPrivate = $({}); this.__$emitterPublic = $({}); this.__instancesLatestArr = []; // collects plugin constructors this.__plugins = {}; // proxy env variables for plugins who might use them this._env = env; }; // core methods core.prototype = { /** * A function to proxy the public methods of an object onto another * * @param {object} constructor The constructor to bridge * @param {object} obj The object that will get new methods (an instance or the core) * @param {string} pluginName A plugin name for the console log message * @return {core} * @private */ __bridge: function(constructor, obj, pluginName) { // if it's not already bridged if (!obj[pluginName]) { var fn = function() {}; fn.prototype = constructor; var pluginInstance = new fn(); // the _init method has to exist in instance constructors but might be missing // in core constructors if (pluginInstance.__init) { pluginInstance.__init(obj); } $.each(constructor, function(methodName, fn) { // don't proxy "private" methods, only "protected" and public ones if (methodName.indexOf('__') != 0) { // if the method does not exist yet if (!obj[methodName]) { obj[methodName] = function() { return pluginInstance[methodName].apply(pluginInstance, Array.prototype.slice.apply(arguments)); }; // remember to which plugin this method corresponds (several plugins may // have methods of the same name, we need to be sure) obj[methodName].bridged = pluginInstance; } else if (defaults.debug) {} } }); obj[pluginName] = pluginInstance; } return this; }, /** * For mockup in Node env if need be, for testing purposes * * @return {core} * @private */ __setWindow: function(window) { env.window = window; return this; }, /** * Returns a ruler, a tool to help measure the size of a tooltip under * various settings. Meant for plugins * * @see Ruler * @return {object} A Ruler instance * @protected */ _getRuler: function($tooltip) { return new Ruler($tooltip); }, /** * For internal use by plugins, if needed * * @return {core} * @protected */ _off: function() { this.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments)); return this; }, /** * For internal use by plugins, if needed * * @return {core} * @protected */ _on: function() { this.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments)); return this; }, /** * For internal use by plugins, if needed * * @return {core} * @protected */ _one: function() { this.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments)); return this; }, /** * Returns (getter) or adds (setter) a plugin * * @param {string|object} plugin Provide a string (in the full form * "namespace.name") to use as as getter, an object to use as a setter * @return {object|core} * @protected */ _plugin: function(plugin) { var self = this; // getter if (typeof plugin == 'string') { var pluginName = plugin, p = null; // if the namespace is provided, it's easy to search if (pluginName.indexOf('.') > 0) { p = self.__plugins[pluginName]; } // otherwise, return the first name that matches else { $.each(self.__plugins, function(i, plugin) { if (plugin.name.substring(plugin.name.length - pluginName.length - 1) == '.' + pluginName) { p = plugin; return false; } }); } return p; } // setter else { // force namespaces if (plugin.name.indexOf('.') < 0) { throw new Error('Plugins must be namespaced'); } self.__plugins[plugin.name] = plugin; // if the plugin has core features if (plugin.core) { // bridge non-private methods onto the core to allow new core methods self.__bridge(plugin.core, self, plugin.name); } return this; } }, /** * Trigger events on the core emitters * * @returns {core} * @protected */ _trigger: function() { var args = Array.prototype.slice.apply(arguments); if (typeof args[0] == 'string') { args[0] = { type: args[0] }; } // note: the order of emitters matters this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args); this.__$emitterPublic.trigger.apply(this.__$emitterPublic, args); return this; }, /** * Returns instances of all tooltips in the page or an a given element * * @param {string|HTML object collection} selector optional Use this * parameter to restrict the set of objects that will be inspected * for the retrieval of instances. By default, all instances in the * page are returned. * @return {array} An array of instance objects * @public */ instances: function(selector) { var instances = [], sel = selector || '.tooltipstered'; $(sel).each(function() { var $this = $(this), ns = $this.data('tooltipster-ns'); if (ns) { $.each(ns, function(i, namespace) { instances.push($this.data(namespace)); }); } }); return instances; }, /** * Returns the Tooltipster objects generated by the last initializing call * * @return {array} An array of instance objects * @public */ instancesLatest: function() { return this.__instancesLatestArr; }, /** * For public use only, not to be used by plugins (use ::_off() instead) * * @return {core} * @public */ off: function() { this.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); return this; }, /** * For public use only, not to be used by plugins (use ::_on() instead) * * @return {core} * @public */ on: function() { this.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); return this; }, /** * For public use only, not to be used by plugins (use ::_one() instead) * * @return {core} * @public */ one: function() { this.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); return this; }, /** * Returns all HTML elements which have one or more tooltips * * @param {string} selector optional Use this to restrict the results * to the descendants of an element * @return {array} An array of HTML elements * @public */ origins: function(selector) { var sel = selector ? selector + ' ' : ''; return $(sel + '.tooltipstered').toArray(); }, /** * Change default options for all future instances * * @param {object} d The options that should be made defaults * @return {core} * @public */ setDefaults: function(d) { $.extend(defaults, d); return this; }, /** * For users to trigger their handlers on the public emitter * * @returns {core} * @public */ triggerHandler: function() { this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); return this; } }; // $.tooltipster will be used to call core methods $.tooltipster = new core(); // the Tooltipster instance class (mind the capital T) $.Tooltipster = function(element, options) { // list of instance variables // stack of custom callbacks provided as parameters to API methods this.__callbacks = { close: [], open: [] }; // the schedule time of DOM removal this.__closingTime; // this will be the user content shown in the tooltip. A capital "C" is used // because there is also a method called content() this.__Content; // for the size tracker this.__contentBcr; // to disable the tooltip after destruction this.__destroyed = false; // we can't emit directly on the instance because if a method with the same // name as the event exists, it will be called by jQuery. Se we use a plain // object as emitter. This emitter is for internal use by plugins, // if needed. this.__$emitterPrivate = $({}); // this emitter is for the user to listen to events without risking to mess // with our internal listeners this.__$emitterPublic = $({}); this.__enabled = true; // the reference to the gc interval this.__garbageCollector; // various position and size data recomputed before each repositioning this.__Geometry; // the tooltip position, saved after each repositioning by a plugin this.__lastPosition; // a unique namespace per instance this.__namespace = 'tooltipster-' + Math.round(Math.random() * 1000000); this.__options; // will be used to support origins in scrollable areas this.__$originParents; this.__pointerIsOverOrigin = false; // to remove themes if needed this.__previousThemes = []; // the state can be either: appearing, stable, disappearing, closed this.__state = 'closed'; // timeout references this.__timeouts = { close: [], open: null }; // store touch events to be able to detect emulated mouse events this.__touchEvents = []; // the reference to the tracker interval this.__tracker = null; // the element to which this tooltip is associated this._$origin; // this will be the tooltip element (jQuery wrapped HTML element). // It's the job of a plugin to create it and append it to the DOM this._$tooltip; // launch this.__init(element, options); }; $.Tooltipster.prototype = { /** * @param origin * @param options * @private */ __init: function(origin, options) { var self = this; self._$origin = $(origin); self.__options = $.extend(true, {}, defaults, options); // some options may need to be reformatted self.__optionsFormat(); // don't run on old IE if asked no to if (!env.IE || env.IE >= self.__options.IEmin ) { // note: the content is null (empty) by default and can stay that // way if the plugin remains initialized but not fed any content. The // tooltip will just not appear. // let's save the initial value of the title attribute for later // restoration if need be. var initialTitle = null; // it will already have been saved in case of multiple tooltips if (self._$origin.data('tooltipster-initialTitle') === undefined) { initialTitle = self._$origin.attr('title'); // we do not want initialTitle to be "undefined" because // of how jQuery's .data() method works if (initialTitle === undefined) initialTitle = null; self._$origin.data('tooltipster-initialTitle', initialTitle); } // If content is provided in the options, it has precedence over the // title attribute. // Note: an empty string is considered content, only 'null' represents // the absence of content. // Also, an existing title="" attribute will result in an empty string // content if (self.__options.content !== null) { self.__contentSet(self.__options.content); } else { var selector = self._$origin.attr('data-tooltip-content'), $el; if (selector) { $el = $(selector); } if ($el && $el[0]) { self.__contentSet($el.first()); } else { self.__contentSet(initialTitle); } } self._$origin // strip the title off of the element to prevent the default tooltips // from popping up .removeAttr('title') // to be able to find all instances on the page later (upon window // events in particular) .addClass('tooltipstered'); // set listeners on the origin self.__prepareOrigin(); // set the garbage collector self.__prepareGC(); // init plugins $.each(self.__options.plugins, function(i, pluginName) { self._plug(pluginName); }); // to detect swiping if (env.hasTouchCapability) { $(env.window.document.body).on('touchmove.' + self.__namespace + '-triggerOpen', function(event) { self._touchRecordEvent(event); }); } self // prepare the tooltip when it gets created. This event must // be fired by a plugin ._on('created', function() { self.__prepareTooltip(); }) // save position information when it's sent by a plugin ._on('repositioned', function(e) { self.__lastPosition = e.position; }); } else { self.__options.disabled = true; } }, /** * Insert the content into the appropriate HTML element of the tooltip * * @returns {self} * @private */ __contentInsert: function() { var self = this, $el = self._$tooltip.find('.tooltipster-content'), formattedContent = self.__Content, format = function(content) { formattedContent = content; }; self._trigger({ type: 'format', content: self.__Content, format: format }); if (self.__options.functionFormat) { formattedContent = self.__options.functionFormat.call( self, self, { origin: self._$origin[0] }, self.__Content ); } if (typeof formattedContent === 'string' && !self.__options.contentAsHTML) { $el.text(formattedContent); } else { $el .empty() .append(formattedContent); } return self; }, /** * Save the content, cloning it beforehand if need be * * @param content * @returns {self} * @private */ __contentSet: function(content) { // clone if asked. Cloning the object makes sure that each instance has its // own version of the content (in case a same object were provided for several // instances) // reminder: typeof null === object if (content instanceof $ && this.__options.contentCloning) { content = content.clone(true); } this.__Content = content; this._trigger({ type: 'updated', content: content }); return this; }, /** * Error message about a method call made after destruction * * @private */ __destroyError: function() { throw new Error('This tooltip has been destroyed and cannot execute your method call.'); }, /** * Gather all information about dimensions and available space, * called before every repositioning * * @private * @returns {object} */ __geometry: function() { var self = this, $target = self._$origin, originIsArea = self._$origin.is('area'); // if this._$origin is a map area, the target we'll need // the dimensions of is actually the image using the map, // not the area itself if (originIsArea) { var mapName = self._$origin.parent().attr('name'); $target = $('img[usemap="#' + mapName + '"]'); } var bcr = $target[0].getBoundingClientRect(), $document = $(env.window.document), $window = $(env.window), $parent = $target, // some useful properties of important elements geo = { // available space for the tooltip, see down below available: { document: null, window: null }, document: { size: { height: $document.height(), width: $document.width() } }, window: { scroll: { // the second ones are for IE compatibility left: env.window.scrollX || env.window.document.documentElement.scrollLeft, top: env.window.scrollY || env.window.document.documentElement.scrollTop }, size: { height: $window.height(), width: $window.width() } }, origin: { // the origin has a fixed lineage if itself or one of its // ancestors has a fixed position fixedLineage: false, // relative to the document offset: {}, size: { height: bcr.bottom - bcr.top, width: bcr.right - bcr.left }, usemapImage: originIsArea ? $target[0] : null, // relative to the window windowOffset: { bottom: bcr.bottom, left: bcr.left, right: bcr.right, top: bcr.top } } }, geoFixed = false; // if the element is a map area, some properties may need // to be recalculated if (originIsArea) { var shape = self._$origin.attr('shape'), coords = self._$origin.attr('coords'); if (coords) { coords = coords.split(','); $.map(coords, function(val, i) { coords[i] = parseInt(val); }); } // if the image itself is the area, nothing more to do if (shape != 'default') { switch (shape) { case 'circle': var circleCenterLeft = coords[0], circleCenterTop = coords[1], circleRadius = coords[2], areaTopOffset = circleCenterTop - circleRadius, areaLeftOffset = circleCenterLeft - circleRadius; geo.origin.size.height = circleRadius * 2; geo.origin.size.width = geo.origin.size.height; geo.origin.windowOffset.left += areaLeftOffset; geo.origin.windowOffset.top += areaTopOffset; break; case 'rect': var areaLeft = coords[0], areaTop = coords[1], areaRight = coords[2], areaBottom = coords[3]; geo.origin.size.height = areaBottom - areaTop; geo.origin.size.width = areaRight - areaLeft; geo.origin.windowOffset.left += areaLeft; geo.origin.windowOffset.top += areaTop; break; case 'poly': var areaSmallestX = 0, areaSmallestY = 0, areaGreatestX = 0, areaGreatestY = 0, arrayAlternate = 'even'; for (var i = 0; i < coords.length; i++) { var areaNumber = coords[i]; if (arrayAlternate == 'even') { if (areaNumber > areaGreatestX) { areaGreatestX = areaNumber; if (i === 0) { areaSmallestX = areaGreatestX; } } if (areaNumber < areaSmallestX) { areaSmallestX = areaNumber; } arrayAlternate = 'odd'; } else { if (areaNumber > areaGreatestY) { areaGreatestY = areaNumber; if (i == 1) { areaSmallestY = areaGreatestY; } } if (areaNumber < areaSmallestY) { areaSmallestY = areaNumber; } arrayAlternate = 'even'; } } geo.origin.size.height = areaGreatestY - areaSmallestY; geo.origin.size.width = areaGreatestX - areaSmallestX; geo.origin.windowOffset.left += areaSmallestX; geo.origin.windowOffset.top += areaSmallestY; break; } } } // user callback through an event var edit = function(r) { geo.origin.size.height = r.height, geo.origin.windowOffset.left = r.left, geo.origin.windowOffset.top = r.top, geo.origin.size.width = r.width }; self._trigger({ type: 'geometry', edit: edit, geometry: { height: geo.origin.size.height, left: geo.origin.windowOffset.left, top: geo.origin.windowOffset.top, width: geo.origin.size.width } }); // calculate the remaining properties with what we got geo.origin.windowOffset.right = geo.origin.windowOffset.left + geo.origin.size.width; geo.origin.windowOffset.bottom = geo.origin.windowOffset.top + geo.origin.size.height; geo.origin.offset.left = geo.origin.windowOffset.left + geo.window.scroll.left; geo.origin.offset.top = geo.origin.windowOffset.top + geo.window.scroll.top; geo.origin.offset.bottom = geo.origin.offset.top + geo.origin.size.height; geo.origin.offset.right = geo.origin.offset.left + geo.origin.size.width; // the space that is available to display the tooltip relatively to the document geo.available.document = { bottom: { height: geo.document.size.height - geo.origin.offset.bottom, width: geo.document.size.width }, left: { height: geo.document.size.height, width: geo.origin.offset.left }, right: { height: geo.document.size.height, width: geo.document.size.width - geo.origin.offset.right }, top: { height: geo.origin.offset.top, width: geo.document.size.width } }; // the space that is available to display the tooltip relatively to the viewport // (the resulting values may be negative if the origin overflows the viewport) geo.available.window = { bottom: { // the inner max is here to make sure the available height is no bigger // than the viewport height (when the origin is off screen at the top). // The outer max just makes sure that the height is not negative (when // the origin overflows at the bottom). height: Math.max(geo.window.size.height - Math.max(geo.origin.windowOffset.bottom, 0), 0), width: geo.window.size.width }, left: { height: geo.window.size.height, width: Math.max(geo.origin.windowOffset.left, 0) }, right: { height: geo.window.size.height, width: Math.max(geo.window.size.width - Math.max(geo.origin.windowOffset.right, 0), 0) }, top: { height: Math.max(geo.origin.windowOffset.top, 0), width: geo.window.size.width } }; while ($parent[0].tagName.toLowerCase() != 'html') { if ($parent.css('position') == 'fixed') { geo.origin.fixedLineage = true; break; } $parent = $parent.parent(); } return geo; }, /** * Some options may need to be formated before being used * * @returns {self} * @private */ __optionsFormat: function() { if (typeof this.__options.animationDuration == 'number') { this.__options.animationDuration = [this.__options.animationDuration, this.__options.animationDuration]; } if (typeof this.__options.delay == 'number') { this.__options.delay = [this.__options.delay, this.__options.delay]; } if (typeof this.__options.delayTouch == 'number') { this.__options.delayTouch = [this.__options.delayTouch, this.__options.delayTouch]; } if (typeof this.__options.theme == 'string') { this.__options.theme = [this.__options.theme]; } // determine the future parent if (this.__options.parent === null) { this.__options.parent = $(env.window.document.body); } else if (typeof this.__options.parent == 'string') { this.__options.parent = $(this.__options.parent); } if (this.__options.trigger == 'hover') { this.__options.triggerOpen = { mouseenter: true, touchstart: true }; this.__options.triggerClose = { mouseleave: true, originClick: true, touchleave: true }; } else if (this.__options.trigger == 'click') { this.__options.triggerOpen = { click: true, tap: true }; this.__options.triggerClose = { click: true, tap: true }; } // for the plugins this._trigger('options'); return this; }, /** * Schedules or cancels the garbage collector task * * @returns {self} * @private */ __prepareGC: function() { var self = this; // in case the selfDestruction option has been changed by a method call if (self.__options.selfDestruction) { // the GC task self.__garbageCollector = setInterval(function() { var now = new Date().getTime(); // forget the old events self.__touchEvents = $.grep(self.__touchEvents, function(event, i) { // 1 minute return now - event.time > 60000; }); // auto-destruct if the origin is gone if (!bodyContains(self._$origin)) { self.close(function() { self.destroy(); }); } }, 20000); } else { clearInterval(self.__garbageCollector); } return self; }, /** * Sets listeners on the origin if the open triggers require them. * Unlike the listeners set at opening time, these ones * remain even when the tooltip is closed. It has been made a * separate method so it can be called when the triggers are * changed in the options. Closing is handled in _open() * because of the bindings that may be needed on the tooltip * itself * * @returns {self} * @private */ __prepareOrigin: function() { var self = this; // in case we're resetting the triggers self._$origin.off('.' + self.__namespace + '-triggerOpen'); // if the device is touch capable, even if only mouse triggers // are asked, we need to listen to touch events to know if the mouse // events are actually emulated (so we can ignore them) if (env.hasTouchCapability) { self._$origin.on( 'touchstart.' + self.__namespace + '-triggerOpen ' + 'touchend.' + self.__namespace + '-triggerOpen ' + 'touchcancel.' + self.__namespace + '-triggerOpen', function(event) { self._touchRecordEvent(event); } ); } // mouse click and touch tap work the same way if (self.__options.triggerOpen.click || (self.__options.triggerOpen.tap && env.hasTouchCapability) ) { var eventNames = ''; if (self.__options.triggerOpen.click) { eventNames += 'click.' + self.__namespace + '-triggerOpen '; } if (self.__options.triggerOpen.tap && env.hasTouchCapability) { eventNames += 'touchend.' + self.__namespace + '-triggerOpen'; } self._$origin.on(eventNames, function(event) { if (self._touchIsMeaningfulEvent(event)) { self._open(event); } }); } // mouseenter and touch start work the same way if (self.__options.triggerOpen.mouseenter || (self.__options.triggerOpen.touchstart && env.hasTouchCapability) ) { var eventNames = ''; if (self.__options.triggerOpen.mouseenter) { eventNames += 'mouseenter.' + self.__namespace + '-triggerOpen '; } if (self.__options.triggerOpen.touchstart && env.hasTouchCapability) { eventNames += 'touchstart.' + self.__namespace + '-triggerOpen'; } self._$origin.on(eventNames, function(event) { if (self._touchIsTouchEvent(event) || !self._touchIsEmulatedEvent(event) ) { self.__pointerIsOverOrigin = true; self._openShortly(event); } }); } // info for the mouseleave/touchleave close triggers when they use a delay if (self.__options.triggerClose.mouseleave || (self.__options.triggerClose.touchleave && env.hasTouchCapability) ) { var eventNames = ''; if (self.__options.triggerClose.mouseleave) { eventNames += 'mouseleave.' + self.__namespace + '-triggerOpen '; } if (self.__options.triggerClose.touchleave && env.hasTouchCapability) { eventNames += 'touchend.' + self.__namespace + '-triggerOpen touchcancel.' + self.__namespace + '-triggerOpen'; } self._$origin.on(eventNames, function(event) { if (self._touchIsMeaningfulEvent(event)) { self.__pointerIsOverOrigin = false; } }); } return self; }, /** * Do the things that need to be done only once after the tooltip * HTML element it has been created. It has been made a separate * method so it can be called when options are changed. Remember * that the tooltip may actually exist in the DOM before it is * opened, and present after it has been closed: it's the display * plugin that takes care of handling it. * * @returns {self} * @private */ __prepareTooltip: function() { var self = this, p = self.__options.interactive ? 'auto' : ''; // this will be useful to know quickly if the tooltip is in // the DOM or not self._$tooltip .attr('id', self.__namespace) .css({ // pointer events 'pointer-events': p, zIndex: self.__options.zIndex }); // themes // remove the old ones and add the new ones $.each(self.__previousThemes, function(i, theme) { self._$tooltip.removeClass(theme); }); $.each(self.__options.theme, function(i, theme) { self._$tooltip.addClass(theme); }); self.__previousThemes = $.merge([], self.__options.theme); return self; }, /** * Handles the scroll on any of the parents of the origin (when the * tooltip is open) * * @param {object} event * @returns {self} * @private */ __scrollHandler: function(event) { var self = this; if (self.__options.triggerClose.scroll) { self._close(event); } else { // if the origin or tooltip have been removed: do nothing, the tracker will // take care of it later if (bodyContains(self._$origin) && bodyContains(self._$tooltip)) { var geo = null; // if the scroll happened on the window if (event.target === env.window.document) { // if the origin has a fixed lineage, window scroll will have no // effect on its position nor on the position of the tooltip if (!self.__Geometry.origin.fixedLineage) { // we don't need to do anything unless repositionOnScroll is true // because the tooltip will already have moved with the window // (and of course with the origin) if (self.__options.repositionOnScroll) { self.reposition(event); } } } // if the scroll happened on another parent of the tooltip, it means // that it's in a scrollable area and now needs to have its position // adjusted or recomputed, depending ont the repositionOnScroll // option. Also, if the origin is partly hidden due to a parent that // hides its overflow, we'll just hide (not close) the tooltip. else { geo = self.__geometry(); var overflows = false; // a fixed position origin is not affected by the overflow hiding // of a parent if (self._$origin.css('position') != 'fixed') { self.__$originParents.each(function(i, el) { var $el = $(el), overflowX = $el.css('overflow-x'), overflowY = $el.css('overflow-y'); if (overflowX != 'visible' || overflowY != 'visible') { var bcr = el.getBoundingClientRect(); if (overflowX != 'visible') { if (geo.origin.windowOffset.left < bcr.left || geo.origin.windowOffset.right > bcr.right ) { overflows = true; return false; } } if (overflowY != 'visible') { if (geo.origin.windowOffset.top < bcr.top || geo.origin.windowOffset.bottom > bcr.bottom ) { overflows = true; return false; } } } // no need to go further if fixed, for the same reason as above if ($el.css('position') == 'fixed') { return false; } }); } if (overflows) { self._$tooltip.css('visibility', 'hidden'); } else { self._$tooltip.css('visibility', 'visible'); // reposition if (self.__options.repositionOnScroll) { self.reposition(event); } // or just adjust offset else { // we have to use offset and not windowOffset because this way, // only the scroll distance of the scrollable areas are taken into // account (the scrolltop value of the main window must be // ignored since the tooltip already moves with it) var offsetLeft = geo.origin.offset.left - self.__Geometry.origin.offset.left, offsetTop = geo.origin.offset.top - self.__Geometry.origin.offset.top; // add the offset to the position initially computed by the display plugin self._$tooltip.css({ left: self.__lastPosition.coord.left + offsetLeft, top: self.__lastPosition.coord.top + offsetTop }); } } } self._trigger({ type: 'scroll', event: event, geo: geo }); } } return self; }, /** * Changes the state of the tooltip * * @param {string} state * @returns {self} * @private */ __stateSet: function(state) { this.__state = state; this._trigger({ type: 'state', state: state }); return this; }, /** * Clear appearance timeouts * * @returns {self} * @private */ __timeoutsClear: function() { // there is only one possible open timeout: the delayed opening // when the mouseenter/touchstart open triggers are used clearTimeout(this.__timeouts.open); this.__timeouts.open = null; // ... but several close timeouts: the delayed closing when the // mouseleave close trigger is used and the timer option $.each(this.__timeouts.close, function(i, timeout) { clearTimeout(timeout); }); this.__timeouts.close = []; return this; }, /** * Start the tracker that will make checks at regular intervals * * @returns {self} * @private */ __trackerStart: function() { var self = this, $content = self._$tooltip.find('.tooltipster-content'); // get the initial content size if (self.__options.trackTooltip) { self.__contentBcr = $content[0].getBoundingClientRect(); } self.__tracker = setInterval(function() { // if the origin or tooltip elements have been removed. // Note: we could destroy the instance now if the origin has // been removed but we'll leave that task to our garbage collector if (!bodyContains(self._$origin) || !bodyContains(self._$tooltip)) { self._close(); } // if everything is alright else { // compare the former and current positions of the origin to reposition // the tooltip if need be if (self.__options.trackOrigin) { var g = self.__geometry(), identical = false; // compare size first (a change requires repositioning too) if (areEqual(g.origin.size, self.__Geometry.origin.size)) { // for elements that have a fixed lineage (see __geometry()), we track the // top and left properties (relative to window) if (self.__Geometry.origin.fixedLineage) { if (areEqual(g.origin.windowOffset, self.__Geometry.origin.windowOffset)) { identical = true; } } // otherwise, track total offset (relative to document) else { if (areEqual(g.origin.offset, self.__Geometry.origin.offset)) { identical = true; } } } if (!identical) { // close the tooltip when using the mouseleave close trigger // (see https://github.com/calebjacob/tooltipster/pull/253) if (self.__options.triggerClose.mouseleave) { self._close(); } else { self.reposition(); } } } if (self.__options.trackTooltip) { var currentBcr = $content[0].getBoundingClientRect(); if (currentBcr.height !== self.__contentBcr.height || currentBcr.width !== self.__contentBcr.width ) { self.reposition(); self.__contentBcr = currentBcr; } } } }, self.__options.trackerInterval); return self; }, /** * Closes the tooltip (after the closing delay) * * @param event * @param callback * @param force Set to true to override a potential refusal of the user's function * @returns {self} * @protected */ _close: function(event, callback, force) { var self = this, ok = true; self._trigger({ type: 'close', event: event, stop: function() { ok = false; } }); // a destroying tooltip (force == true) may not refuse to close if (ok || force) { // save the method custom callback and cancel any open method custom callbacks if (callback) self.__callbacks.close.push(callback); self.__callbacks.open = []; // clear open/close timeouts self.__timeoutsClear(); var finishCallbacks = function() { // trigger any close method custom callbacks and reset them $.each(self.__callbacks.close, function(i, c) { c.call(self, self, { event: event, origin: self._$origin[0] }); }); self.__callbacks.close = []; }; if (self.__state != 'closed') { var necessary = true, d = new Date(), now = d.getTime(), newClosingTime = now + self.__options.animationDuration[1]; // the tooltip may already already be disappearing, but if a new // call to close() is made after the animationDuration was changed // to 0 (for example), we ought to actually close it sooner than // previously scheduled. In that case it should be noted that the // browser will not adapt the animation duration to the new // animationDuration that was set after the start of the closing // animation. // Note: the same thing could be considered at opening, but is not // really useful since the tooltip is actually opened immediately // upon a call to _open(). Since it would not make the opening // animation finish sooner, its sole impact would be to trigger the // state event and the open callbacks sooner than the actual end of // the opening animation, which is not great. if (self.__state == 'disappearing') { if (newClosingTime > self.__closingTime // in case closing is actually overdue because the script // execution was suspended. See #679 && self.__options.animationDuration[1] > 0 ) { necessary = false; } } if (necessary) { self.__closingTime = newClosingTime; if (self.__state != 'disappearing') { self.__stateSet('disappearing'); } var finish = function() { // stop the tracker clearInterval(self.__tracker); // a "beforeClose" option has been asked several times but would // probably useless since the content element is still accessible // via ::content(), and because people can always use listeners // inside their content to track what's going on. For the sake of // simplicity, this has been denied. Bur for the rare people who // really need the option (for old browsers or for the case where // detaching the content is actually destructive, for file or // password inputs for example), this event will do the work. self._trigger({ type: 'closing', event: event }); // unbind listeners which are no longer needed self._$tooltip .off('.' + self.__namespace + '-triggerClose') .removeClass('tooltipster-dying'); // orientationchange, scroll and resize listeners $(env.window).off('.' + self.__namespace + '-triggerClose'); // scroll listeners self.__$originParents.each(function(i, el) { $(el).off('scroll.' + self.__namespace + '-triggerClose'); }); // clear the array to prevent memory leaks self.__$originParents = null; $(env.window.document.body).off('.' + self.__namespace + '-triggerClose'); self._$origin.off('.' + self.__namespace + '-triggerClose'); self._off('dismissable'); // a plugin that would like to remove the tooltip from the // DOM when closed should bind on this self.__stateSet('closed'); // trigger event self._trigger({ type: 'after', event: event }); // call our constructor custom callback function if (self.__options.functionAfter) { self.__options.functionAfter.call(self, self, { event: event, origin: self._$origin[0] }); } // call our method custom callbacks functions finishCallbacks(); }; if (env.hasTransitions) { self._$tooltip.css({ '-moz-animation-duration': self.__options.animationDuration[1] + 'ms', '-ms-animation-duration': self.__options.animationDuration[1] + 'ms', '-o-animation-duration': self.__options.animationDuration[1] + 'ms', '-webkit-animation-duration': self.__options.animationDuration[1] + 'ms', 'animation-duration': self.__options.animationDuration[1] + 'ms', 'transition-duration': self.__options.animationDuration[1] + 'ms' }); self._$tooltip // clear both potential open and close tasks .clearQueue() .removeClass('tooltipster-show') // for transitions only .addClass('tooltipster-dying'); if (self.__options.animationDuration[1] > 0) { self._$tooltip.delay(self.__options.animationDuration[1]); } self._$tooltip.queue(finish); } else { self._$tooltip .stop() .fadeOut(self.__options.animationDuration[1], finish); } } } // if the tooltip is already closed, we still need to trigger // the method custom callbacks else { finishCallbacks(); } } return self; }, /** * For internal use by plugins, if needed * * @returns {self} * @protected */ _off: function() { this.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments)); return this; }, /** * For internal use by plugins, if needed * * @returns {self} * @protected */ _on: function() { this.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments)); return this; }, /** * For internal use by plugins, if needed * * @returns {self} * @protected */ _one: function() { this.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments)); return this; }, /** * Opens the tooltip right away. * * @param event * @param callback Will be called when the opening animation is over * @returns {self} * @protected */ _open: function(event, callback) { var self = this; // if the destruction process has not begun and if this was not // triggered by an unwanted emulated click event if (!self.__destroying) { // check that the origin is still in the DOM if (bodyContains(self._$origin) // if the tooltip is enabled && self.__enabled ) { var ok = true; // if the tooltip is not open yet, we need to call functionBefore. // otherwise we can jst go on if (self.__state == 'closed') { // trigger an event. The event.stop function allows the callback // to prevent the opening of the tooltip self._trigger({ type: 'before', event: event, stop: function() { ok = false; } }); if (ok && self.__options.functionBefore) { // call our custom function before continuing ok = self.__options.functionBefore.call(self, self, { event: event, origin: self._$origin[0] }); } } if (ok !== false) { // if there is some content if (self.__Content !== null) { // save the method callback and cancel close method callbacks if (callback) { self.__callbacks.open.push(callback); } self.__callbacks.close = []; // get rid of any appearance timeouts self.__timeoutsClear(); var extraTime, finish = function() { if (self.__state != 'stable') { self.__stateSet('stable'); } // trigger any open method custom callbacks and reset them $.each(self.__callbacks.open, function(i, c) { c.call(self, self, { origin: self._$origin[0], tooltip: self._$tooltip[0] }); }); self.__callbacks.open = []; }; // if the tooltip is already open if (self.__state !== 'closed') { // the timer (if any) will start (or restart) right now extraTime = 0; // if it was disappearing, cancel that if (self.__state === 'disappearing') { self.__stateSet('appearing'); if (env.hasTransitions) { self._$tooltip .clearQueue() .removeClass('tooltipster-dying') .addClass('tooltipster-show'); if (self.__options.animationDuration[0] > 0) { self._$tooltip.delay(self.__options.animationDuration[0]); } self._$tooltip.queue(finish); } else { // in case the tooltip was currently fading out, bring it back // to life self._$tooltip .stop() .fadeIn(finish); } } // if the tooltip is already open, we still need to trigger the method // custom callback else if (self.__state == 'stable') { finish(); } } // if the tooltip isn't already open, open it else { // a plugin must bind on this and store the tooltip in this._$tooltip self.__stateSet('appearing'); // the timer (if any) will start when the tooltip has fully appeared // after its transition extraTime = self.__options.animationDuration[0]; // insert the content inside the tooltip self.__contentInsert(); // reposition the tooltip and attach to the DOM self.reposition(event, true); // animate in the tooltip. If the display plugin wants no css // animations, it may override the animation option with a // dummy value that will produce no effect if (env.hasTransitions) { // note: there seems to be an issue with start animations which // are randomly not played on fast devices in both Chrome and FF, // couldn't find a way to solve it yet. It seems that applying // the classes before appending to the DOM helps a little, but // it messes up some CSS transitions. The issue almost never // happens when delay[0]==0 though self._$tooltip .addClass('tooltipster-' + self.__options.animation) .addClass('tooltipster-initial') .css({ '-moz-animation-duration': self.__options.animationDuration[0] + 'ms', '-ms-animation-duration': self.__options.animationDuration[0] + 'ms', '-o-animation-duration': self.__options.animationDuration[0] + 'ms', '-webkit-animation-duration': self.__options.animationDuration[0] + 'ms', 'animation-duration': self.__options.animationDuration[0] + 'ms', 'transition-duration': self.__options.animationDuration[0] + 'ms' }); setTimeout( function() { // a quick hover may have already triggered a mouseleave if (self.__state != 'closed') { self._$tooltip .addClass('tooltipster-show') .removeClass('tooltipster-initial'); if (self.__options.animationDuration[0] > 0) { self._$tooltip.delay(self.__options.animationDuration[0]); } self._$tooltip.queue(finish); } }, 0 ); } else { // old browsers will have to live with this self._$tooltip .css('display', 'none') .fadeIn(self.__options.animationDuration[0], finish); } // checks if the origin is removed while the tooltip is open self.__trackerStart(); // NOTE: the listeners below have a '-triggerClose' namespace // because we'll remove them when the tooltip closes (unlike // the '-triggerOpen' listeners). So some of them are actually // not about close triggers, rather about positioning. $(env.window) // reposition on resize .on('resize.' + self.__namespace + '-triggerClose', function(e) { var $ae = $(document.activeElement); // reposition only if the resize event was not triggered upon the opening // of a virtual keyboard due to an input field being focused within the tooltip // (otherwise the repositioning would lose the focus) if ((!$ae.is('input') && !$ae.is('textarea')) || !$.contains(self._$tooltip[0], $ae[0]) ) { self.reposition(e); } }) // same as below for parents .on('scroll.' + self.__namespace + '-triggerClose', function(e) { self.__scrollHandler(e); }); self.__$originParents = self._$origin.parents(); // scrolling may require the tooltip to be moved or even // repositioned in some cases self.__$originParents.each(function(i, parent) { $(parent).on('scroll.' + self.__namespace + '-triggerClose', function(e) { self.__scrollHandler(e); }); }); if (self.__options.triggerClose.mouseleave || (self.__options.triggerClose.touchleave && env.hasTouchCapability) ) { // we use an event to allow users/plugins to control when the mouseleave/touchleave // close triggers will come to action. It allows to have more triggering elements // than just the origin and the tooltip for example, or to cancel/delay the closing, // or to make the tooltip interactive even if it wasn't when it was open, etc. self._on('dismissable', function(event) { if (event.dismissable) { if (event.delay) { timeout = setTimeout(function() { // event.event may be undefined self._close(event.event); }, event.delay); self.__timeouts.close.push(timeout); } else { self._close(event); } } else { clearTimeout(timeout); } }); // now set the listeners that will trigger 'dismissable' events var $elements = self._$origin, eventNamesIn = '', eventNamesOut = '', timeout = null; // if we have to allow interaction, bind on the tooltip too if (self.__options.interactive) { $elements = $elements.add(self._$tooltip); } if (self.__options.triggerClose.mouseleave) { eventNamesIn += 'mouseenter.' + self.__namespace + '-triggerClose '; eventNamesOut += 'mouseleave.' + self.__namespace + '-triggerClose '; } if (self.__options.triggerClose.touchleave && env.hasTouchCapability) { eventNamesIn += 'touchstart.' + self.__namespace + '-triggerClose'; eventNamesOut += 'touchend.' + self.__namespace + '-triggerClose touchcancel.' + self.__namespace + '-triggerClose'; } $elements // close after some time spent outside of the elements .on(eventNamesOut, function(event) { // it's ok if the touch gesture ended up to be a swipe, // it's still a "touch leave" situation if (self._touchIsTouchEvent(event) || !self._touchIsEmulatedEvent(event) ) { var delay = (event.type == 'mouseleave') ? self.__options.delay : self.__options.delayTouch; self._trigger({ delay: delay[1], dismissable: true, event: event, type: 'dismissable' }); } }) // suspend the mouseleave timeout when the pointer comes back // over the elements .on(eventNamesIn, function(event) { // it's also ok if the touch event is a swipe gesture if (self._touchIsTouchEvent(event) || !self._touchIsEmulatedEvent(event) ) { self._trigger({ dismissable: false, event: event, type: 'dismissable' }); } }); } // close the tooltip when the origin gets a mouse click (common behavior of // native tooltips) if (self.__options.triggerClose.originClick) { self._$origin.on('click.' + self.__namespace + '-triggerClose', function(event) { // we could actually let a tap trigger this but this feature just // does not make sense on touch devices if (!self._touchIsTouchEvent(event) && !self._touchIsEmulatedEvent(event) ) { self._close(event); } }); } // set the same bindings for click and touch on the body to close the tooltip if (self.__options.triggerClose.click || (self.__options.triggerClose.tap && env.hasTouchCapability) ) { // don't set right away since the click/tap event which triggered this method // (if it was a click/tap) is going to bubble up to the body, we don't want it // to close the tooltip immediately after it opened setTimeout(function() { if (self.__state != 'closed') { var eventNames = '', $body = $(env.window.document.body); if (self.__options.triggerClose.click) { eventNames += 'click.' + self.__namespace + '-triggerClose '; } if (self.__options.triggerClose.tap && env.hasTouchCapability) { eventNames += 'touchend.' + self.__namespace + '-triggerClose'; } $body.on(eventNames, function(event) { if (self._touchIsMeaningfulEvent(event)) { self._touchRecordEvent(event); if (!self.__options.interactive || !$.contains(self._$tooltip[0], event.target)) { self._close(event); } } }); // needed to detect and ignore swiping if (self.__options.triggerClose.tap && env.hasTouchCapability) { $body.on('touchstart.' + self.__namespace + '-triggerClose', function(event) { self._touchRecordEvent(event); }); } } }, 0); } self._trigger('ready'); // call our custom callback if (self.__options.functionReady) { self.__options.functionReady.call(self, self, { origin: self._$origin[0], tooltip: self._$tooltip[0] }); } } // if we have a timer set, let the countdown begin if (self.__options.timer > 0) { var timeout = setTimeout(function() { self._close(); }, self.__options.timer + extraTime); self.__timeouts.close.push(timeout); } } } } } return self; }, /** * When using the mouseenter/touchstart open triggers, this function will * schedule the opening of the tooltip after the delay, if there is one * * @param event * @returns {self} * @protected */ _openShortly: function(event) { var self = this, ok = true; if (self.__state != 'stable' && self.__state != 'appearing') { // if a timeout is not already running if (!self.__timeouts.open) { self._trigger({ type: 'start', event: event, stop: function() { ok = false; } }); if (ok) { var delay = (event.type.indexOf('touch') == 0) ? self.__options.delayTouch : self.__options.delay; if (delay[0]) { self.__timeouts.open = setTimeout(function() { self.__timeouts.open = null; // open only if the pointer (mouse or touch) is still over the origin. // The check on the "meaningful event" can only be made here, after some // time has passed (to know if the touch was a swipe or not) if (self.__pointerIsOverOrigin && self._touchIsMeaningfulEvent(event)) { // signal that we go on self._trigger('startend'); self._open(event); } else { // signal that we cancel self._trigger('startcancel'); } }, delay[0]); } else { // signal that we go on self._trigger('startend'); self._open(event); } } } } return self; }, /** * Meant for plugins to get their options * * @param {string} pluginName The name of the plugin that asks for its options * @param {object} defaultOptions The default options of the plugin * @returns {object} The options * @protected */ _optionsExtract: function(pluginName, defaultOptions) { var self = this, options = $.extend(true, {}, defaultOptions); // if the plugin options were isolated in a property named after the // plugin, use them (prevents conflicts with other plugins) var pluginOptions = self.__options[pluginName]; // if not, try to get them as regular options if (!pluginOptions) { pluginOptions = {}; $.each(defaultOptions, function(optionName, value) { var o = self.__options[optionName]; if (o !== undefined) { pluginOptions[optionName] = o; } }); } // let's merge the default options and the ones that were provided. We'd want // to do a deep copy but not let jQuery merge arrays, so we'll do a shallow // extend on two levels, that will be enough if options are not more than 1 // level deep $.each(options, function(optionName, value) { if (pluginOptions[optionName] !== undefined) { if ((typeof value == 'object' && !(value instanceof Array) && value != null ) && (typeof pluginOptions[optionName] == 'object' && !(pluginOptions[optionName] instanceof Array) && pluginOptions[optionName] != null ) ) { $.extend(options[optionName], pluginOptions[optionName]); } else { options[optionName] = pluginOptions[optionName]; } } }); return options; }, /** * Used at instantiation of the plugin, or afterwards by plugins that activate themselves * on existing instances * * @param {object} pluginName * @returns {self} * @protected */ _plug: function(pluginName) { var plugin = $.tooltipster._plugin(pluginName); if (plugin) { // if there is a constructor for instances if (plugin.instance) { // proxy non-private methods on the instance to allow new instance methods $.tooltipster.__bridge(plugin.instance, this, plugin.name); } } else { throw new Error('The "' + pluginName + '" plugin is not defined'); } return this; }, /** * This will return true if the event is a mouse event which was * emulated by the browser after a touch event. This allows us to * really dissociate mouse and touch triggers. * * There is a margin of error if a real mouse event is fired right * after (within the delay shown below) a touch event on the same * element, but hopefully it should not happen often. * * @returns {boolean} * @protected */ _touchIsEmulatedEvent: function(event) { var isEmulated = false, now = new Date().getTime(); for (var i = this.__touchEvents.length - 1; i >= 0; i--) { var e = this.__touchEvents[i]; // delay, in milliseconds. It's supposed to be 300ms in // most browsers (350ms on iOS) to allow a double tap but // can be less (check out FastClick for more info) if (now - e.time < 500) { if (e.target === event.target) { isEmulated = true; } } else { break; } } return isEmulated; }, /** * Returns false if the event was an emulated mouse event or * a touch event involved in a swipe gesture. * * @param {object} event * @returns {boolean} * @protected */ _touchIsMeaningfulEvent: function(event) { return ( (this._touchIsTouchEvent(event) && !this._touchSwiped(event.target)) || (!this._touchIsTouchEvent(event) && !this._touchIsEmulatedEvent(event)) ); }, /** * Checks if an event is a touch event * * @param {object} event * @returns {boolean} * @protected */ _touchIsTouchEvent: function(event) { return event.type.indexOf('touch') == 0; }, /** * Store touch events for a while to detect swiping and emulated mouse events * * @param {object} event * @returns {self} * @protected */ _touchRecordEvent: function(event) { if (this._touchIsTouchEvent(event)) { event.time = new Date().getTime(); this.__touchEvents.push(event); } return this; }, /** * Returns true if a swipe happened after the last touchstart event fired on * event.target. * * We need to differentiate a swipe from a tap before we let the event open * or close the tooltip. A swipe is when a touchmove (scroll) event happens * on the body between the touchstart and the touchend events of an element. * * @param {object} target The HTML element that may have triggered the swipe * @returns {boolean} * @protected */ _touchSwiped: function(target) { var swiped = false; for (var i = this.__touchEvents.length - 1; i >= 0; i--) { var e = this.__touchEvents[i]; if (e.type == 'touchmove') { swiped = true; break; } else if ( e.type == 'touchstart' && target === e.target ) { break; } } return swiped; }, /** * Triggers an event on the instance emitters * * @returns {self} * @protected */ _trigger: function() { var args = Array.prototype.slice.apply(arguments); if (typeof args[0] == 'string') { args[0] = { type: args[0] }; } // add properties to the event args[0].instance = this; args[0].origin = this._$origin ? this._$origin[0] : null; args[0].tooltip = this._$tooltip ? this._$tooltip[0] : null; // note: the order of emitters matters this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args); $.tooltipster._trigger.apply($.tooltipster, args); this.__$emitterPublic.trigger.apply(this.__$emitterPublic, args); return this; }, /** * Deactivate a plugin on this instance * * @returns {self} * @protected */ _unplug: function(pluginName) { var self = this; // if the plugin has been activated on this instance if (self[pluginName]) { var plugin = $.tooltipster._plugin(pluginName); // if there is a constructor for instances if (plugin.instance) { // unbridge $.each(plugin.instance, function(methodName, fn) { // if the method exists (privates methods do not) and comes indeed from // this plugin (may be missing or come from a conflicting plugin). if (self[methodName] && self[methodName].bridged === self[pluginName] ) { delete self[methodName]; } }); } // destroy the plugin if (self[pluginName].__destroy) { self[pluginName].__destroy(); } // remove the reference to the plugin instance delete self[pluginName]; } return self; }, /** * @see self::_close * @returns {self} * @public */ close: function(callback) { if (!this.__destroyed) { this._close(null, callback); } else { this.__destroyError(); } return this; }, /** * Sets or gets the content of the tooltip * * @returns {mixed|self} * @public */ content: function(content) { var self = this; // getter method if (content === undefined) { return self.__Content; } // setter method else { if (!self.__destroyed) { // change the content self.__contentSet(content); if (self.__Content !== null) { // update the tooltip if it is open if (self.__state !== 'closed') { // reset the content in the tooltip self.__contentInsert(); // reposition and resize the tooltip self.reposition(); // if we want to play a little animation showing the content changed if (self.__options.updateAnimation) { if (env.hasTransitions) { // keep the reference in the local scope var animation = self.__options.updateAnimation; self._$tooltip.addClass('tooltipster-update-' + animation); // remove the class after a while. The actual duration of the // update animation may be shorter, it's set in the CSS rules setTimeout(function() { if (self.__state != 'closed') { self._$tooltip.removeClass('tooltipster-update-' + animation); } }, 1000); } else { self._$tooltip.fadeTo(200, 0.5, function() { if (self.__state != 'closed') { self._$tooltip.fadeTo(200, 1); } }); } } } } else { self._close(); } } else { self.__destroyError(); } return self; } }, /** * Destroys the tooltip * * @returns {self} * @public */ destroy: function() { var self = this; if (!self.__destroyed) { if (self.__state != 'closed') { // no closing delay self.option('animationDuration', 0) // force closing ._close(null, null, true); } else { // there might be an open timeout still running self.__timeoutsClear(); } // send event self._trigger('destroy'); self.__destroyed = true; self._$origin .removeData(self.__namespace) // remove the open trigger listeners .off('.' + self.__namespace + '-triggerOpen'); // remove the touch listener $(env.window.document.body).off('.' + self.__namespace + '-triggerOpen'); var ns = self._$origin.data('tooltipster-ns'); // if the origin has been removed from DOM, its data may // well have been destroyed in the process and there would // be nothing to clean up or restore if (ns) { // if there are no more tooltips on this element if (ns.length === 1) { // optional restoration of a title attribute var title = null; if (self.__options.restoration == 'previous') { title = self._$origin.data('tooltipster-initialTitle'); } else if (self.__options.restoration == 'current') { // old school technique to stringify when outerHTML is not supported title = (typeof self.__Content == 'string') ? self.__Content : $('<div></div>').append(self.__Content).html(); } if (title) { self._$origin.attr('title', title); } // final cleaning self._$origin.removeClass('tooltipstered'); self._$origin .removeData('tooltipster-ns') .removeData('tooltipster-initialTitle'); } else { // remove the instance namespace from the list of namespaces of // tooltips present on the element ns = $.grep(ns, function(el, i) { return el !== self.__namespace; }); self._$origin.data('tooltipster-ns', ns); } } // last event self._trigger('destroyed'); // unbind private and public event listeners self._off(); self.off(); // remove external references, just in case self.__Content = null; self.__$emitterPrivate = null; self.__$emitterPublic = null; self.__options.parent = null; self._$origin = null; self._$tooltip = null; // make sure the object is no longer referenced in there to prevent // memory leaks $.tooltipster.__instancesLatestArr = $.grep($.tooltipster.__instancesLatestArr, function(el, i) { return self !== el; }); clearInterval(self.__garbageCollector); } else { self.__destroyError(); } // we return the scope rather than true so that the call to // .tooltipster('destroy') actually returns the matched elements // and applies to all of them return self; }, /** * Disables the tooltip * * @returns {self} * @public */ disable: function() { if (!this.__destroyed) { // close first, in case the tooltip would not disappear on // its own (no close trigger) this._close(); this.__enabled = false; return this; } else { this.__destroyError(); } return this; }, /** * Returns the HTML element of the origin * * @returns {self} * @public */ elementOrigin: function() { if (!this.__destroyed) { return this._$origin[0]; } else { this.__destroyError(); } }, /** * Returns the HTML element of the tooltip * * @returns {self} * @public */ elementTooltip: function() { return this._$tooltip ? this._$tooltip[0] : null; }, /** * Enables the tooltip * * @returns {self} * @public */ enable: function() { this.__enabled = true; return this; }, /** * Alias, deprecated in 4.0.0 * * @param {function} callback * @returns {self} * @public */ hide: function(callback) { return this.close(callback); }, /** * Returns the instance * * @returns {self} * @public */ instance: function() { return this; }, /** * For public use only, not to be used by plugins (use ::_off() instead) * * @returns {self} * @public */ off: function() { if (!this.__destroyed) { this.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); } return this; }, /** * For public use only, not to be used by plugins (use ::_on() instead) * * @returns {self} * @public */ on: function() { if (!this.__destroyed) { this.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); } else { this.__destroyError(); } return this; }, /** * For public use only, not to be used by plugins * * @returns {self} * @public */ one: function() { if (!this.__destroyed) { this.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); } else { this.__destroyError(); } return this; }, /** * @see self::_open * @returns {self} * @public */ open: function(callback) { if (!this.__destroyed) { this._open(null, callback); } else { this.__destroyError(); } return this; }, /** * Get or set options. For internal use and advanced users only. * * @param {string} o Option name * @param {mixed} val optional A new value for the option * @return {mixed|self} If val is omitted, the value of the option * is returned, otherwise the instance itself is returned * @public */ option: function(o, val) { // getter if (val === undefined) { return this.__options[o]; } // setter else { if (!this.__destroyed) { // change value this.__options[o] = val; // format this.__optionsFormat(); // re-prepare the triggers if needed if ($.inArray(o, ['trigger', 'triggerClose', 'triggerOpen']) >= 0) { this.__prepareOrigin(); } if (o === 'selfDestruction') { this.__prepareGC(); } } else { this.__destroyError(); } return this; } }, /** * This method is in charge of setting the position and size properties of the tooltip. * All the hard work is delegated to the display plugin. * Note: The tooltip may be detached from the DOM at the moment the method is called * but must be attached by the end of the method call. * * @param {object} event For internal use only. Defined if an event such as * window resizing triggered the repositioning * @param {boolean} tooltipIsDetached For internal use only. Set this to true if you * know that the tooltip not being in the DOM is not an issue (typically when the * tooltip element has just been created but has not been added to the DOM yet). * @returns {self} * @public */ reposition: function(event, tooltipIsDetached) { var self = this; if (!self.__destroyed) { // if the tooltip is still open and the origin is still in the DOM if (self.__state != 'closed' && bodyContains(self._$origin)) { // if the tooltip has not been removed from DOM manually (or if it // has been detached on purpose) if (tooltipIsDetached || bodyContains(self._$tooltip)) { if (!tooltipIsDetached) { // detach in case the tooltip overflows the window and adds // scrollbars to it, so __geometry can be accurate self._$tooltip.detach(); } // refresh the geometry object before passing it as a helper self.__Geometry = self.__geometry(); // let a plugin fo the rest self._trigger({ type: 'reposition', event: event, helper: { geo: self.__Geometry } }); } } } else { self.__destroyError(); } return self; }, /** * Alias, deprecated in 4.0.0 * * @param callback * @returns {self} * @public */ show: function(callback) { return this.open(callback); }, /** * Returns some properties about the instance * * @returns {object} * @public */ status: function() { return { destroyed: this.__destroyed, enabled: this.__enabled, open: this.__state !== 'closed', state: this.__state }; }, /** * For public use only, not to be used by plugins * * @returns {self} * @public */ triggerHandler: function() { if (!this.__destroyed) { this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments)); } else { this.__destroyError(); } return this; } }; $.fn.tooltipster = function() { // for using in closures var args = Array.prototype.slice.apply(arguments), // common mistake: an HTML element can't be in several tooltips at the same time contentCloningWarning = 'You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.'; // this happens with $(sel).tooltipster(...) when $(sel) does not match anything if (this.length === 0) { // still chainable return this; } // this happens when calling $(sel).tooltipster('methodName or options') // where $(sel) matches one or more elements else { // method calls if (typeof args[0] === 'string') { var v = '#*$~&'; this.each(function() { // retrieve the namepaces of the tooltip(s) that exist on that element. // We will interact with the first tooltip only. var ns = $(this).data('tooltipster-ns'), // self represents the instance of the first tooltipster plugin // associated to the current HTML object of the loop self = ns ? $(this).data(ns[0]) : null; // if the current element holds a tooltipster instance if (self) { if (typeof self[args[0]] === 'function') { if (this.length > 1 && args[0] == 'content' && (args[1] instanceof $ || (typeof args[1] == 'object' && args[1] != null && args[1].tagName) ) && !self.__options.contentCloning && self.__options.debug ) { } // note : args[1] and args[2] may not be defined var resp = self[args[0]](args[1], args[2]); } else { throw new Error('Unknown method "' + args[0] + '"'); } // if the function returned anything other than the instance // itself (which implies chaining, except for the `instance` method) if (resp !== self || args[0] === 'instance') { v = resp; // return false to stop .each iteration on the first element // matched by the selector return false; } } else { throw new Error('You called Tooltipster\'s "' + args[0] + '" method on an uninitialized element'); } }); return (v !== '#*$~&') ? v : this; } // first argument is undefined or an object: the tooltip is initializing else { // reset the array of last initialized objects $.tooltipster.__instancesLatestArr = []; // is there a defined value for the multiple option in the options object ? var multipleIsSet = args[0] && args[0].multiple !== undefined, // if the multiple option is set to true, or if it's not defined but // set to true in the defaults multiple = (multipleIsSet && args[0].multiple) || (!multipleIsSet && defaults.multiple), // same for content contentIsSet = args[0] && args[0].content !== undefined, content = (contentIsSet && args[0].content) || (!contentIsSet && defaults.content), // same for contentCloning contentCloningIsSet = args[0] && args[0].contentCloning !== undefined, contentCloning = (contentCloningIsSet && args[0].contentCloning) || (!contentCloningIsSet && defaults.contentCloning), // same for debug debugIsSet = args[0] && args[0].debug !== undefined, debug = (debugIsSet && args[0].debug) || (!debugIsSet && defaults.debug); if (this.length > 1 && (content instanceof $ || (typeof content == 'object' && content != null && content.tagName) ) && !contentCloning && debug ) { } // create a tooltipster instance for each element if it doesn't // already have one or if the multiple option is set, and attach the // object to it this.each(function() { var go = false, $this = $(this), ns = $this.data('tooltipster-ns'), obj = null; if (!ns) { go = true; } else if (multiple) { go = true; } else if (debug) {} if (go) { obj = new $.Tooltipster(this, args[0]); // save the reference of the new instance if (!ns) ns = []; ns.push(obj.__namespace); $this.data('tooltipster-ns', ns); // save the instance itself $this.data(obj.__namespace, obj); // call our constructor custom function. // we do this here and not in ::init() because we wanted // the object to be saved in $this.data before triggering // it if (obj.__options.functionInit) { obj.__options.functionInit.call(obj, obj, { origin: this }); } // and now the event, for the plugins and core emitter obj._trigger('init'); } $.tooltipster.__instancesLatestArr.push(obj); }); return this; } } }; // Utilities /** * A class to check if a tooltip can fit in given dimensions * * @param {object} $tooltip The jQuery wrapped tooltip element, or a clone of it */ function Ruler($tooltip) { // list of instance variables this.$container; this.constraints = null; this.__$tooltip; this.__init($tooltip); } Ruler.prototype = { /** * Move the tooltip into an invisible div that does not allow overflow to make * size tests. Note: the tooltip may or may not be attached to the DOM at the * moment this method is called, it does not matter. * * @param {object} $tooltip The object to test. May be just a clone of the * actual tooltip. * @private */ __init: function($tooltip) { this.__$tooltip = $tooltip; this.__$tooltip .css({ // for some reason we have to specify top and left 0 left: 0, // any overflow will be ignored while measuring overflow: 'hidden', // positions at (0,0) without the div using 100% of the available width position: 'absolute', top: 0 }) // overflow must be auto during the test. We re-set this in case // it were modified by the user .find('.tooltipster-content') .css('overflow', 'auto'); this.$container = $('<div class="tooltipster-ruler"></div>') .append(this.__$tooltip) .appendTo(env.window.document.body); }, /** * Force the browser to redraw (re-render) the tooltip immediately. This is required * when you changed some CSS properties and need to make something with it * immediately, without waiting for the browser to redraw at the end of instructions. * * @see http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes * @private */ __forceRedraw: function() { // note: this would work but for Webkit only //this.__$tooltip.close(); //this.__$tooltip[0].offsetHeight; //this.__$tooltip.open(); // works in FF too var $p = this.__$tooltip.parent(); this.__$tooltip.detach(); this.__$tooltip.appendTo($p); }, /** * Set maximum dimensions for the tooltip. A call to ::measure afterwards * will tell us if the content overflows or if it's ok * * @param {int} width * @param {int} height * @return {Ruler} * @public */ constrain: function(width, height) { this.constraints = { width: width, height: height }; this.__$tooltip.css({ // we disable display:flex, otherwise the content would overflow without // creating horizontal scrolling (which we need to detect). display: 'block', // reset any previous height height: '', // we'll check if horizontal scrolling occurs overflow: 'auto', // we'll set the width and see what height is generated and if there // is horizontal overflow width: width }); return this; }, /** * Reset the tooltip content overflow and remove the test container * * @returns {Ruler} * @public */ destroy: function() { // in case the element was not a clone this.__$tooltip .detach() .find('.tooltipster-content') .css({ // reset to CSS value display: '', overflow: '' }); this.$container.remove(); }, /** * Removes any constraints * * @returns {Ruler} * @public */ free: function() { this.constraints = null; // reset to natural size this.__$tooltip.css({ display: '', height: '', overflow: 'visible', width: '' }); return this; }, /** * Returns the size of the tooltip. When constraints are applied, also returns * whether the tooltip fits in the provided dimensions. * The idea is to see if the new height is small enough and if the content does * not overflow horizontally. * * @param {int} width * @param {int} height * @returns {object} An object with a bool `fits` property and a `size` property * @public */ measure: function() { this.__forceRedraw(); var tooltipBcr = this.__$tooltip[0].getBoundingClientRect(), result = { size: { // bcr.width/height are not defined in IE8- but in this // case, bcr.right/bottom will have the same value // except in iOS 8+ where tooltipBcr.bottom/right are wrong // after scrolling for reasons yet to be determined. // tooltipBcr.top/left might not be 0, see issue #514 height: tooltipBcr.height || (tooltipBcr.bottom - tooltipBcr.top), width: tooltipBcr.width || (tooltipBcr.right - tooltipBcr.left) } }; if (this.constraints) { // note: we used to use offsetWidth instead of boundingRectClient but // it returned rounded values, causing issues with sub-pixel layouts. // note2: noticed that the bcrWidth of text content of a div was once // greater than the bcrWidth of its container by 1px, causing the final // tooltip box to be too small for its content. However, evaluating // their widths one against the other (below) surprisingly returned // equality. Happened only once in Chrome 48, was not able to reproduce // => just having fun with float position values... var $content = this.__$tooltip.find('.tooltipster-content'), height = this.__$tooltip.outerHeight(), contentBcr = $content[0].getBoundingClientRect(), fits = { height: height <= this.constraints.height, width: ( // this condition accounts for min-width property that // may apply tooltipBcr.width <= this.constraints.width // the -1 is here because scrollWidth actually returns // a rounded value, and may be greater than bcr.width if // it was rounded up. This may cause an issue for contents // which actually really overflow by 1px or so, but that // should be rare. Not sure how to solve this efficiently. // See http://blogs.msdn.com/b/ie/archive/2012/02/17/sub-pixel-rendering-and-the-css-object-model.aspx && contentBcr.width >= $content[0].scrollWidth - 1 ) }; result.fits = fits.height && fits.width; } // old versions of IE get the width wrong for some reason and it causes // the text to be broken to a new line, so we round it up. If the width // is the width of the screen though, we can assume it is accurate. if (env.IE && env.IE <= 11 && result.size.width !== env.window.document.documentElement.clientWidth ) { result.size.width = Math.ceil(result.size.width) + 1; } return result; } }; // quick & dirty compare function, not bijective nor multidimensional function areEqual(a, b) { var same = true; $.each(a, function(i, _) { if (b[i] === undefined || a[i] !== b[i]) { same = false; return false; } }); return same; } /** * A fast function to check if an element is still in the DOM. It * tries to use an id as ids are indexed by the browser, or falls * back to jQuery's `contains` method. May fail if two elements * have the same id, but so be it * * @param {object} $obj A jQuery-wrapped HTML element * @return {boolean} */ function bodyContains($obj) { var id = $obj.attr('id'), el = id ? env.window.document.getElementById(id) : null; // must also check that the element with the id is the one we want return el ? el === $obj[0] : $.contains(env.window.document.body, $obj[0]); } // detect IE versions for dirty fixes var uA = navigator.userAgent.toLowerCase(); if (uA.indexOf('msie') != -1) env.IE = parseInt(uA.split('msie')[1]); else if (uA.toLowerCase().indexOf('trident') !== -1 && uA.indexOf(' rv:11') !== -1) env.IE = 11; else if (uA.toLowerCase().indexOf('edge/') != -1) env.IE = parseInt(uA.toLowerCase().split('edge/')[1]); // detecting support for CSS transitions function transitionSupport() { // env.window is not defined yet when this is called if (!win) return false; var b = win.document.body || win.document.documentElement, s = b.style, p = 'transition', v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms']; if (typeof s[p] == 'string') { return true; } p = p.charAt(0).toUpperCase() + p.substr(1); for (var i = 0; i < v.length; i++) { if (typeof s[v[i] + p] == 'string') { return true; } } return false; } // we'll return jQuery for plugins not to have to declare it as a dependency, // but it's done by a build task since it should be included only once at the // end when we concatenate the main file with a pluginreturn $; // sideTip is Tooltipster's default plugin. // This file will be UMDified by a build task. $.tooltipster._plugin({ name: 'tooltipster.sideTip', instance: { /** * Defaults are provided as a function for an easy override by inheritance * * @return {object} An object with the defaults options * @private */ __defaults: function() { return { // if the tooltip should display an arrow that points to the origin arrow: true, // the distance in pixels between the tooltip and the origin distance: 6, // allows to easily change the position of the tooltip functionPosition: null, maxWidth: null, // used to accomodate the arrow of tooltip if there is one. // First to make sure that the arrow target is not too close // to the edge of the tooltip, so the arrow does not overflow // the tooltip. Secondly when we reposition the tooltip to // make sure that it's positioned in such a way that the arrow is // still pointing at the target (and not a few pixels beyond it). // It should be equal to or greater than half the width of // the arrow (by width we mean the size of the side which touches // the side of the tooltip). minIntersection: 16, minWidth: 0, // deprecated in 4.0.0. Listed for _optionsExtract to pick it up position: null, side: 'top', // set to false to position the tooltip relatively to the document rather // than the window when we open it viewportAware: true }; }, /** * Run once: at instantiation of the plugin * * @param {object} instance The tooltipster object that instantiated this plugin * @private */ __init: function(instance) { var self = this; // list of instance variables self.__instance = instance; self.__namespace = 'tooltipster-sideTip-' + Math.round(Math.random() * 1000000); self.__previousState = 'closed'; self.__options; // initial formatting self.__optionsFormat(); self.__instance._on('state.' + self.__namespace, function(event) { if (event.state == 'closed') { self.__close(); } else if (event.state == 'appearing' && self.__previousState == 'closed') { self.__create(); } self.__previousState = event.state; }); // reformat every time the options are changed self.__instance._on('options.' + self.__namespace, function() { self.__optionsFormat(); }); self.__instance._on('reposition.' + self.__namespace, function(e) { self.__reposition(e.event, e.helper); }); }, /** * Called when the tooltip has closed * * @private */ __close: function() { // detach our content object first, so the next jQuery's remove() // call does not unbind its event handlers if (this.__instance.content() instanceof $) { this.__instance.content().detach(); } // remove the tooltip from the DOM this.__instance._$tooltip.remove(); this.__instance._$tooltip = null; }, /** * Creates the HTML element of the tooltip. * * @private */ __create: function() { // note: we wrap with a .tooltipster-box div to be able to set a margin on it // (.tooltipster-base must not have one) var $html = $( '<div class="tooltipster-base tooltipster-sidetip">' + '<div class="tooltipster-box">' + '<div class="tooltipster-content"></div>' + '</div>' + '<div class="tooltipster-arrow">' + '<div class="tooltipster-arrow-uncropped">' + '<div class="tooltipster-arrow-border"></div>' + '<div class="tooltipster-arrow-background"></div>' + '</div>' + '</div>' + '</div>' ); // hide arrow if asked if (!this.__options.arrow) { $html .find('.tooltipster-box') .css('margin', 0) .end() .find('.tooltipster-arrow') .hide(); } // apply min/max width if asked if (this.__options.minWidth) { $html.css('min-width', this.__options.minWidth + 'px'); } if (this.__options.maxWidth) { $html.css('max-width', this.__options.maxWidth + 'px'); } this.__instance._$tooltip = $html; // tell the instance that the tooltip element has been created this.__instance._trigger('created'); }, /** * Used when the plugin is to be unplugged * * @private */ __destroy: function() { this.__instance._off('.' + self.__namespace); }, /** * (Re)compute this.__options from the options declared to the instance * * @private */ __optionsFormat: function() { var self = this; // get the options self.__options = self.__instance._optionsExtract('tooltipster.sideTip', self.__defaults()); // for backward compatibility, deprecated in v4.0.0 if (self.__options.position) { self.__options.side = self.__options.position; } // options formatting // format distance as a four-cell array if it ain't one yet and then make // it an object with top/bottom/left/right properties if (typeof self.__options.distance != 'object') { self.__options.distance = [self.__options.distance]; } if (self.__options.distance.length < 4) { if (self.__options.distance[1] === undefined) self.__options.distance[1] = self.__options.distance[0]; if (self.__options.distance[2] === undefined) self.__options.distance[2] = self.__options.distance[0]; if (self.__options.distance[3] === undefined) self.__options.distance[3] = self.__options.distance[1]; } self.__options.distance = { top: self.__options.distance[0], right: self.__options.distance[1], bottom: self.__options.distance[2], left: self.__options.distance[3] }; // let's transform: // 'top' into ['top', 'bottom', 'right', 'left'] // 'right' into ['right', 'left', 'top', 'bottom'] // 'bottom' into ['bottom', 'top', 'right', 'left'] // 'left' into ['left', 'right', 'top', 'bottom'] if (typeof self.__options.side == 'string') { var opposites = { 'top': 'bottom', 'right': 'left', 'bottom': 'top', 'left': 'right' }; self.__options.side = [self.__options.side, opposites[self.__options.side]]; if (self.__options.side[0] == 'left' || self.__options.side[0] == 'right') { self.__options.side.push('top', 'bottom'); } else { self.__options.side.push('right', 'left'); } } // misc // disable the arrow in IE6 unless the arrow option was explicitly set to true if ($.tooltipster._env.IE === 6 && self.__options.arrow !== true ) { self.__options.arrow = false; } }, /** * This method must compute and set the positioning properties of the * tooltip (left, top, width, height, etc.). It must also make sure the * tooltip is eventually appended to its parent (since the element may be * detached from the DOM at the moment the method is called). * * We'll evaluate positioning scenarios to find which side can contain the * tooltip in the best way. We'll consider things relatively to the window * (unless the user asks not to), then to the document (if need be, or if the * user explicitly requires the tests to run on the document). For each * scenario, measures are taken, allowing us to know how well the tooltip * is going to fit. After that, a sorting function will let us know what * the best scenario is (we also allow the user to choose his favorite * scenario by using an event). * * @param {object} helper An object that contains variables that plugin * creators may find useful (see below) * @param {object} helper.geo An object with many layout properties * about objects of interest (window, document, origin). This should help * plugin users compute the optimal position of the tooltip * @private */ __reposition: function(event, helper) { var self = this, finalResult, // to know where to put the tooltip, we need to know on which point // of the x or y axis we should center it. That coordinate is the target targets = self.__targetFind(helper), testResults = []; // make sure the tooltip is detached while we make tests on a clone self.__instance._$tooltip.detach(); // we could actually provide the original element to the Ruler and // not a clone, but it just feels right to keep it out of the // machinery. var $clone = self.__instance._$tooltip.clone(), // start position tests session ruler = $.tooltipster._getRuler($clone), satisfied = false, animation = self.__instance.option('animation'); // an animation class could contain properties that distort the size if (animation) { $clone.removeClass('tooltipster-' + animation); } // start evaluating scenarios $.each(['window', 'document'], function(i, container) { var takeTest = null; // let the user decide to keep on testing or not self.__instance._trigger({ container: container, helper: helper, satisfied: satisfied, takeTest: function(bool) { takeTest = bool; }, results: testResults, type: 'positionTest' }); if (takeTest == true || (takeTest != false && satisfied == false // skip the window scenarios if asked. If they are reintegrated by // the callback of the positionTest event, they will have to be // excluded using the callback of positionTested && (container != 'window' || self.__options.viewportAware) ) ) { // for each allowed side for (var i = 0; i < self.__options.side.length; i++) { var distance = { horizontal: 0, vertical: 0 }, side = self.__options.side[i]; if (side == 'top' || side == 'bottom') { distance.vertical = self.__options.distance[side]; } else { distance.horizontal = self.__options.distance[side]; } // this may have an effect on the size of the tooltip if there are css // rules for the arrow or something else self.__sideChange($clone, side); $.each(['natural', 'constrained'], function(i, mode) { takeTest = null; // emit an event on the instance self.__instance._trigger({ container: container, event: event, helper: helper, mode: mode, results: testResults, satisfied: satisfied, side: side, takeTest: function(bool) { takeTest = bool; }, type: 'positionTest' }); if (takeTest == true || (takeTest != false && satisfied == false ) ) { var testResult = { container: container, // we let the distance as an object here, it can make things a little easier // during the user's calculations at positionTest/positionTested distance: distance, // whether the tooltip can fit in the size of the viewport (does not mean // that we'll be able to make it initially entirely visible, see 'whole') fits: null, mode: mode, outerSize: null, side: side, size: null, target: targets[side], // check if the origin has enough surface on screen for the tooltip to // aim at it without overflowing the viewport (this is due to the thickness // of the arrow represented by the minIntersection length). // If not, the tooltip will have to be partly or entirely off screen in // order to stay docked to the origin. This value will stay null when the // container is the document, as it is not relevant whole: null }; // get the size of the tooltip with or without size constraints var rulerConfigured = (mode == 'natural') ? ruler.free() : ruler.constrain( helper.geo.available[container][side].width - distance.horizontal, helper.geo.available[container][side].height - distance.vertical ), rulerResults = rulerConfigured.measure(); testResult.size = rulerResults.size; testResult.outerSize = { height: rulerResults.size.height + distance.vertical, width: rulerResults.size.width + distance.horizontal }; if (mode == 'natural') { if (helper.geo.available[container][side].width >= testResult.outerSize.width && helper.geo.available[container][side].height >= testResult.outerSize.height ) { testResult.fits = true; } else { testResult.fits = false; } } else { testResult.fits = rulerResults.fits; } if (container == 'window') { if (!testResult.fits) { testResult.whole = false; } else { if (side == 'top' || side == 'bottom') { testResult.whole = ( helper.geo.origin.windowOffset.right >= self.__options.minIntersection && helper.geo.window.size.width - helper.geo.origin.windowOffset.left >= self.__options.minIntersection ); } else { testResult.whole = ( helper.geo.origin.windowOffset.bottom >= self.__options.minIntersection && helper.geo.window.size.height - helper.geo.origin.windowOffset.top >= self.__options.minIntersection ); } } } testResults.push(testResult); // we don't need to compute more positions if we have one fully on screen if (testResult.whole) { satisfied = true; } else { // don't run the constrained test unless the natural width was greater // than the available width, otherwise it's pointless as we know it // wouldn't fit either if (testResult.mode == 'natural' && (testResult.fits || testResult.size.width <= helper.geo.available[container][side].width ) ) { return false; } } } }); } } }); // the user may eliminate the unwanted scenarios from testResults, but he's // not supposed to alter them at this point. functionPosition and the // position event serve that purpose. self.__instance._trigger({ edit: function(r) { testResults = r; }, event: event, helper: helper, results: testResults, type: 'positionTested' }); /** * Sort the scenarios to find the favorite one. * * The favorite scenario is when we can fully display the tooltip on screen, * even if it means that the middle of the tooltip is no longer centered on * the middle of the origin (when the origin is near the edge of the screen * or even partly off screen). We want the tooltip on the preferred side, * even if it means that we have to use a constrained size rather than a * natural one (as long as it fits). When the origin is off screen at the top * the tooltip will be positioned at the bottom (if allowed), if the origin * is off screen on the right, it will be positioned on the left, etc. * If there are no scenarios where the tooltip can fit on screen, or if the * user does not want the tooltip to fit on screen (viewportAware == false), * we fall back to the scenarios relative to the document. * * When the tooltip is bigger than the viewport in either dimension, we stop * looking at the window scenarios and consider the document scenarios only, * with the same logic to find on which side it would fit best. * * If the tooltip cannot fit the document on any side, we force it at the * bottom, so at least the user can scroll to see it. */ testResults.sort(function(a, b) { // best if it's whole (the tooltip fits and adapts to the viewport) if (a.whole && !b.whole) { return -1; } else if (!a.whole && b.whole) { return 1; } else if (a.whole && b.whole) { var ai = self.__options.side.indexOf(a.side), bi = self.__options.side.indexOf(b.side); // use the user's sides fallback array if (ai < bi) { return -1; } else if (ai > bi) { return 1; } else { // will be used if the user forced the tests to continue return a.mode == 'natural' ? -1 : 1; } } else { // better if it fits if (a.fits && !b.fits) { return -1; } else if (!a.fits && b.fits) { return 1; } else if (a.fits && b.fits) { var ai = self.__options.side.indexOf(a.side), bi = self.__options.side.indexOf(b.side); // use the user's sides fallback array if (ai < bi) { return -1; } else if (ai > bi) { return 1; } else { // will be used if the user forced the tests to continue return a.mode == 'natural' ? -1 : 1; } } else { // if everything failed, this will give a preference to the case where // the tooltip overflows the document at the bottom if (a.container == 'document' && a.side == 'bottom' && a.mode == 'natural' ) { return -1; } else { return 1; } } } }); finalResult = testResults[0]; // now let's find the coordinates of the tooltip relatively to the window finalResult.coord = {}; switch (finalResult.side) { case 'left': case 'right': finalResult.coord.top = Math.floor(finalResult.target - finalResult.size.height / 2); break; case 'bottom': case 'top': finalResult.coord.left = Math.floor(finalResult.target - finalResult.size.width / 2); break; } switch (finalResult.side) { case 'left': finalResult.coord.left = helper.geo.origin.windowOffset.left - finalResult.outerSize.width; break; case 'right': finalResult.coord.left = helper.geo.origin.windowOffset.right + finalResult.distance.horizontal; break; case 'top': finalResult.coord.top = helper.geo.origin.windowOffset.top - finalResult.outerSize.height; break; case 'bottom': finalResult.coord.top = helper.geo.origin.windowOffset.bottom + finalResult.distance.vertical; break; } // if the tooltip can potentially be contained within the viewport dimensions // and that we are asked to make it fit on screen if (finalResult.container == 'window') { // if the tooltip overflows the viewport, we'll move it accordingly (then it will // not be centered on the middle of the origin anymore). We only move horizontally // for top and bottom tooltips and vice versa. if (finalResult.side == 'top' || finalResult.side == 'bottom') { // if there is an overflow on the left if (finalResult.coord.left < 0) { // prevent the overflow unless the origin itself gets off screen (minus the // margin needed to keep the arrow pointing at the target) if (helper.geo.origin.windowOffset.right - this.__options.minIntersection >= 0) { finalResult.coord.left = 0; } else { finalResult.coord.left = helper.geo.origin.windowOffset.right - this.__options.minIntersection - 1; } } // or an overflow on the right else if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) { if (helper.geo.origin.windowOffset.left + this.__options.minIntersection <= helper.geo.window.size.width) { finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width; } else { finalResult.coord.left = helper.geo.origin.windowOffset.left + this.__options.minIntersection + 1 - finalResult.size.width; } } } else { // overflow at the top if (finalResult.coord.top < 0) { if (helper.geo.origin.windowOffset.bottom - this.__options.minIntersection >= 0) { finalResult.coord.top = 0; } else { finalResult.coord.top = helper.geo.origin.windowOffset.bottom - this.__options.minIntersection - 1; } } // or at the bottom else if (finalResult.coord.top > helper.geo.window.size.height - finalResult.size.height) { if (helper.geo.origin.windowOffset.top + this.__options.minIntersection <= helper.geo.window.size.height) { finalResult.coord.top = helper.geo.window.size.height - finalResult.size.height; } else { finalResult.coord.top = helper.geo.origin.windowOffset.top + this.__options.minIntersection + 1 - finalResult.size.height; } } } } else { // there might be overflow here too but it's easier to handle. If there has // to be an overflow, we'll make sure it's on the right side of the screen // (because the browser will extend the document size if there is an overflow // on the right, but not on the left). The sort function above has already // made sure that a bottom document overflow is preferred to a top overflow, // so we don't have to care about it. // if there is an overflow on the right if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) { // this may actually create on overflow on the left but we'll fix it in a sec finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width; } // if there is an overflow on the left if (finalResult.coord.left < 0) { // don't care if it overflows the right after that, we made our best finalResult.coord.left = 0; } } // submit the positioning proposal to the user function which may choose to change // the side, size and/or the coordinates // first, set the rules that corresponds to the proposed side: it may change // the size of the tooltip, and the custom functionPosition may want to detect the // size of something before making a decision. So let's make things easier for the // implementor self.__sideChange($clone, finalResult.side); // add some variables to the helper helper.tooltipClone = $clone[0]; helper.tooltipParent = self.__instance.option('parent').parent[0]; // move informative values to the helper helper.mode = finalResult.mode; helper.whole = finalResult.whole; // add some variables to the helper for the functionPosition callback (these // will also be added to the event fired by self.__instance._trigger but that's // ok, we're just being consistent) helper.origin = self.__instance._$origin[0]; helper.tooltip = self.__instance._$tooltip[0]; // leave only the actionable values in there for functionPosition delete finalResult.container; delete finalResult.fits; delete finalResult.mode; delete finalResult.outerSize; delete finalResult.whole; // keep only the distance on the relevant side, for clarity finalResult.distance = finalResult.distance.horizontal || finalResult.distance.vertical; // beginners may not be comfortable with the concept of editing the object // passed by reference, so we provide an edit function and pass a clone var finalResultClone = $.extend(true, {}, finalResult); // emit an event on the instance self.__instance._trigger({ edit: function(result) { finalResult = result; }, event: event, helper: helper, position: finalResultClone, type: 'position' }); if (self.__options.functionPosition) { var result = self.__options.functionPosition.call(self, self.__instance, helper, finalResultClone); if (result) finalResult = result; } // end the positioning tests session (the user might have had a // use for it during the position event, now it's over) ruler.destroy(); // compute the position of the target relatively to the tooltip root // element so we can place the arrow and make the needed adjustments var arrowCoord, maxVal; if (finalResult.side == 'top' || finalResult.side == 'bottom') { arrowCoord = { prop: 'left', val: finalResult.target - finalResult.coord.left }; maxVal = finalResult.size.width - this.__options.minIntersection; } else { arrowCoord = { prop: 'top', val: finalResult.target - finalResult.coord.top }; maxVal = finalResult.size.height - this.__options.minIntersection; } // cannot lie beyond the boundaries of the tooltip, minus the // arrow margin if (arrowCoord.val < this.__options.minIntersection) { arrowCoord.val = this.__options.minIntersection; } else if (arrowCoord.val > maxVal) { arrowCoord.val = maxVal; } var originParentOffset; // let's convert the window-relative coordinates into coordinates relative to the // future positioned parent that the tooltip will be appended to if (helper.geo.origin.fixedLineage) { // same as windowOffset when the position is fixed originParentOffset = helper.geo.origin.windowOffset; } else { // this assumes that the parent of the tooltip is located at // (0, 0) in the document, typically like when the parent is // <body>. // If we ever allow other types of parent, .tooltipster-ruler // will have to be appended to the parent to inherit css style // values that affect the display of the text and such. originParentOffset = { left: helper.geo.origin.windowOffset.left + helper.geo.window.scroll.left, top: helper.geo.origin.windowOffset.top + helper.geo.window.scroll.top }; } finalResult.coord = { left: originParentOffset.left + (finalResult.coord.left - helper.geo.origin.windowOffset.left), top: originParentOffset.top + (finalResult.coord.top - helper.geo.origin.windowOffset.top) }; // set position values on the original tooltip element self.__sideChange(self.__instance._$tooltip, finalResult.side); if (helper.geo.origin.fixedLineage) { self.__instance._$tooltip .css('position', 'fixed'); } else { // CSS default self.__instance._$tooltip .css('position', ''); } self.__instance._$tooltip .css({ left: finalResult.coord.left, top: finalResult.coord.top, // we need to set a size even if the tooltip is in its natural size // because when the tooltip is positioned beyond the width of the body // (which is by default the width of the window; it will happen when // you scroll the window horizontally to get to the origin), its text // content will otherwise break lines at each word to keep up with the // body overflow strategy. height: finalResult.size.height, width: finalResult.size.width }) .find('.tooltipster-arrow') .css({ 'left': '', 'top': '' }) .css(arrowCoord.prop, arrowCoord.val); // append the tooltip HTML element to its parent self.__instance._$tooltip.appendTo(self.__instance.option('parent')); self.__instance._trigger({ type: 'repositioned', event: event, position: finalResult }); }, /** * Make whatever modifications are needed when the side is changed. This has * been made an independant method for easy inheritance in custom plugins based * on this default plugin. * * @param {object} $obj * @param {string} side * @private */ __sideChange: function($obj, side) { $obj .removeClass('tooltipster-bottom') .removeClass('tooltipster-left') .removeClass('tooltipster-right') .removeClass('tooltipster-top') .addClass('tooltipster-' + side); }, /** * Returns the target that the tooltip should aim at for a given side. * The calculated value is a distance from the edge of the window * (left edge for top/bottom sides, top edge for left/right side). The * tooltip will be centered on that position and the arrow will be * positioned there (as much as possible). * * @param {object} helper * @return {integer} * @private */ __targetFind: function(helper) { var target = {}, rects = this.__instance._$origin[0].getClientRects(); // these lines fix a Chrome bug (issue #491) if (rects.length > 1) { var opacity = this.__instance._$origin.css('opacity'); if (opacity == 1) { this.__instance._$origin.css('opacity', 0.99); rects = this.__instance._$origin[0].getClientRects(); this.__instance._$origin.css('opacity', 1); } } // by default, the target will be the middle of the origin if (rects.length < 2) { target.top = Math.floor(helper.geo.origin.windowOffset.left + (helper.geo.origin.size.width / 2)); target.bottom = target.top; target.left = Math.floor(helper.geo.origin.windowOffset.top + (helper.geo.origin.size.height / 2)); target.right = target.left; } // if multiple client rects exist, the element may be text split // up into multiple lines and the middle of the origin may not be // best option anymore. We need to choose the best target client rect else { // top: the first var targetRect = rects[0]; target.top = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2); // right: the middle line, rounded down in case there is an even // number of lines (looks more centered => check out the // demo with 4 split lines) if (rects.length > 2) { targetRect = rects[Math.ceil(rects.length / 2) - 1]; } else { targetRect = rects[0]; } target.right = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2); // bottom: the last targetRect = rects[rects.length - 1]; target.bottom = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2); // left: the middle line, rounded up if (rects.length > 2) { targetRect = rects[Math.ceil((rects.length + 1) / 2) - 1]; } else { targetRect = rects[rects.length - 1]; } target.left = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2); } return target; } } }); })); }); jQuery(document).ready(function($) { var fchunker_upload = { fchunker: function(config) { $.extend(config); if ($.upId && $.upUrl) { $.domHtml = $('#' + $.upId).html(); $.upInputId = $.upId + '_input'; } }, fchunker_limitFileSize: function(file, limitSize) { var arr = ["KB", "MB", "GB"], limit = limitSize.toUpperCase(), limitNum = 0; for (var i = 0; i < arr.length; i++) { var leval = limit.indexOf(arr[i]); if (leval > -1) { limitNum = parseInt(limit.substr(0, leval)) * Math.pow(1024, (i + 1)); break; } } if (file.size > limitNum) { return false; } return true; }, upErrorMsg: function(err) { $.upError = err; }, upStop: function(err) { $.upError = err; }, upStatus: function() { if ($.upError) { if (typeof $.upStop == 'function') { $.upStop($.upError); } return false; } return true; }, fchunker_getPercent: function(num, total) { num = parseInt(num); total = parseInt(total); if (isNaN(num) || isNaN(total)) { return "-"; } let sum = total <= 0 ? 0 : (Math.round(num / total * 100)); return sum; }, fchunker_upload: function(x, xfile) { $.upError = ''; $.tempFile = $('#' + $.upInputId)[0].files[0]; if (x == 'file') $.tempFile = xfile; var file = $.tempFile; if (!file) { return false; } if (typeof $.upStart == 'function') { $.upStart(); } var filename = file.name, index1 = filename.lastIndexOf("."), index2 = filename.length, suffix = filename.substring(index1 + 1, index2); if ($.upType) { uptype = $.upType.split(","); if ($.inArray(suffix, uptype) == -1) { $.upError = 'Type error: Error-' + suffix; } } // if ($.upMaxSize) { // if (!$.fchunker_limitFileSize(file, $.upMaxSize + 'MB')) { // $.upError = 'Error'; // } // } if ($.upStatus() == false) { return false; } $.taskStart = +new Date(); setTimeout("jQuery.fchunker_upload_core()", "100"); }, fchunker_upload_core: function() { var file = $.tempFile; if (!file) { return false; } if (!$.upShardSize) { $.upShardSize = 2; } $.upShardSize = $.upShardSize * 0.8; var filename = file.name, size = file.size, index1 = filename.lastIndexOf("."), index2 = filename.length, suffix = filename.substring(index1 + 1, index2), shardSize = $.upShardSize * 1024 * 1024, succeed = 0, shardCount = Math.ceil(size / shardSize); var re = []; var start, end = 0; for (var i = 0; i < shardCount; ++i) { re[i] = []; start = i * shardSize, end = Math.min(size, start + shardSize); re[i]["file_data"] = file.slice(start, end); re[i]["file_name"] = filename; re[i]["file_size"] = size; } const URL = $.upUrl; var i2 = 0, i3 = 1, fcs = Array(); var xhr = new XMLHttpRequest(); function ajaxStack(stack) { if ($.upStatus() == false) { return; } var form = new FormData(); if (stack[i2]) { fcs = stack[i2]; form.append("file_data", fcs['file_data']); form.append("file_name", fcs['file_name']); form.append("file_size", fcs['file_size']); form.append("file_total", shardCount); form.append("file_index", i3); form.append("taskStart", $.taskStart); form.append("action", "backup_migration"); form.append("token", "bmi"); form.append("f", "upload-backup"); form.append("nonce", $.bmiNonce); xhr.open('POST', URL, true); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest"); xhr.onload = function() { ajaxStack(stack); } xhr.onreadystatechange = function() { if ($.upStatus() == false) { return; } if (xhr.readyState == 4 && xhr.status == 200) { var data = xhr.responseText ? eval('(' + xhr.responseText + ')') : ''; ++succeed; var cent = $.fchunker_getPercent(succeed, shardCount); if (typeof $.upEvent == 'function') { $.upEvent(cent); } if (cent == 100) { setTimeout(function() { if (typeof $.upCallBack == 'function') { $.upCallBack(data); } }, 500); } else { if (typeof $.upCallBack == 'function') { $.upCallBack(data); } } } } xhr.send(form); i2++; i3++; form.delete('file_data'); form.delete('file_name'); form.delete('file_size'); form.delete('file_total'); form.delete('taskStart'); form.delete('file_index'); form.delete('action'); form.delete('token'); form.delete('nonce'); form.delete('f'); } } ajaxStack(re); re = null, file = null; } }; $.extend(fchunker_upload); }); // Preloader jQuery(window).on('load', function() { if (pagenow !== 'toplevel_page_backup-migration') return; setTimeout(function() { jQuery('#bmi').css({ opacity: 0 }); jQuery('#bmi-preload').css({ opacity: 1 }); jQuery('#bmi-preload').animate({ opacity: 0 }, 150, function() { jQuery('#bmi-preload').remove(); jQuery('#bmi').css({ display: 'block' }); jQuery.bmi.dropdowns.init(); setTimeout(function() { jQuery('#bmi').animate({ opacity: 1 }, 350, function () { jQuery(window).trigger("bmi-preload-collapsed"); }); jQuery('#bmi_carrousel').show(200); }, 100); }); }, 50); }); // Plugin for jQuery - Handler of BMI jQuery(document).ready(function($) { let collapsing = false; let ongoing_latest_token = false; let currentUploadType = null; wakeLock = null; function escapeHtml(t){return(t=""+t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")} $.extend({ bmi: { requestWakeLock: async () => { try { if ( wakeLock == null && 'wakeLock' in navigator) { wakeLock = await navigator.wakeLock.request('screen'); // Listen for release (e.g., if user switches tabs) wakeLock.addEventListener('release', () => { wakeLock = null; }); } } catch (err) { console.error(`${err.name}, ${err.message}`); } }, releaseWakeLock: () => { if (typeof wakeLock !== 'undefined' && wakeLock !== null) { wakeLock.release(); wakeLock = null; } }, // STATIC: Copy to clipboard clipboard: function(str, text = false) { try { const el = document.createElement('textarea'); el.value = str; el.setAttribute('readonly', ''); el.style.position = 'absolute'; el.style.left = '-9999px'; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); let def = $('#bmi-success-copy').text(); if (text != false) def = text; $.bmi.alert('success', def, 3000); return true; } catch (e) { console.log(e); $.bmi.alert('warning', $('#bmi-failed-copy').text(), 3000); return false; } }, // Alert alert: function(type = 'default', msg = '---', timeout = 7000) { if ($('.bmi-notification-box').length <= 0) $('body').find('#bmi').prepend($('<div class="bmi-notification-box"></div>')); if (type == 'default') type = ''; else if (type == 'success') type = ' is-success'; else if (type == 'warning') type = ' is-warning'; else if (type == 'error') type = ' is-danger'; else if (type == 'info') type = ' is-info'; else type = ' is-info'; let elid = Math.floor(Math.random() * Math.floor(64000)); let $html = `<div style="display: none;" id="ntf-${elid}" class="bmi-notification${type}"> <button class="bmi-times-button" onclick="jQuery.bmi.hideAlert(this)">×</button> <div class="bmi-cf"> <div class="bmi-left bmi-alert-icon"><div class="bmi-icon-bg"></div></div> <div class="bmi-left bmi-alert-msg-title"> <div class="bmi-title${type}">Backup Migration</div> <div>${msg}</div> </div> </div> </div>`; $('.bmi-notification-box').prepend($html); let ntf = $(`#ntf-${elid}`); ntf.css({ opacity: 0, display: 'block' }); let width = ntf.outerWidth(), height = ntf.outerHeight(); ntf.css({ right: '-35vw', 'font-size': '0px', width: 0, padding: 0, opacity: '0' }); ntf.animate({ right: '15px', width: width, padding: '1rem 2rem 1rem 1.5rem', opacity: '1' }, { duration: 200, queue: false }); ntf.animate({ 'font-size': '16px' }, { duration: 300, queue: false }); setTimeout(() => { $(`#ntf-${elid}`).css({ width: '' }); }, 250); setTimeout(() => { ntf.animate({ 'font-size': '0px' }, { duration: 200, queue: false }); ntf.animate({ right: '-35vw', height: 0, width: 0, margin: 0, padding: 0, opacity: '0' }, 300, function() { ntf.remove(); }); }, timeout); }, // Response message _msg: function(res) { if (res.status != 'msg') return; if (typeof res.level == 'undefined') res.level = 'info'; $.bmi.alert(res.level, res.why, 3000); console.log('Backup-migration: ', '[' + res.level.toUpperCase() + ']', res.why); }, // Hide alert hideAlert: function(self) { let ntf = $(self).parents('.bmi-notification'); ntf.animate({ 'font-size': '0px' }, { duration: 200, queue: false }); ntf.animate({ right: '-35vw', height: 0, width: 0, margin: 0, padding: 0, opacity: '0' }, 300, function() { ntf.remove(); }); }, // OBJECT: Modal modal: function(id = false) { let mod = false; if (id != false) mod = document.getElementById(id); return { clearModal: function() { mod.querySelectorAll('.customselect').forEach(function(dropdown) { dropdown.classList.remove('active'); }); mod.querySelectorAll('input[type="text"]').forEach(function(input) { input.value = ''; input.setAttribute('value', ''); }); }, open: function(cb = function() {}) { mod.classList.add('before-open'); setTimeout(function() { mod.classList.add('open'); $('html')[0].style.overflowY = 'hidden'; setTimeout(cb, 410); }, 10); }, close: function(cb = function() {}) { if (mod.offsetWidth > 0 && mod.offsetHeight > 0) { mod.classList.add('before-close'); setTimeout(function() { mod.classList.add('closed'); setTimeout(function() { mod.classList.remove('before-open'); mod.classList.remove('open'); mod.classList.remove('before-close'); mod.classList.remove('closed'); $.bmi.modal(mod.id).clearModal(); cb(); }, 410); }, 10); } else { mod.classList.remove('before-open'); mod.classList.remove('open'); mod.classList.remove('before-close'); mod.classList.remove('closed'); cb(); } $('html')[0].style.overflowY = 'auto'; }, closeAll: function() { let modals = document.querySelectorAll('.modal'); modals.forEach(function(mod) { $.bmi.modal(mod.id).close(); }); $('html')[0].style.overflowY = 'auto'; }, setParent: function(parentId) { mod.setAttribute('data-parent-id',parentId); }, getParent: function() { return mod.getAttribute('data-parent-id'); } } }, // PROMISE: Return JSON (from string) or FAIL json: function(str) { let originalString = str; return new Promise(function(resolve, reject) { try { let json = JSON.parse(str); return resolve(json); } catch (e) { if (typeof str === 'string') { let reversed = $.bmi.reverse(str); let lastcorrect = reversed.indexOf('}'); if (lastcorrect == 0) lastcorrect = str.length; else lastcorrect = -lastcorrect; str = str.slice(str.indexOf('{'), lastcorrect); try { let json = JSON.parse(str); return resolve(json); } catch (e) { return resolve(originalString); } } else return reject(false); } }); }, // STATIC: Returns reversed string reverse: function(str) { if (typeof str === 'string') { return (str === '') ? '' : $.bmi.reverse(str.substr(1)) + str.charAt(0); } else { return str; } }, // AJAX: Logger of JSON logJsonError: function(errorLogObj, func) { data = {}; data.action = 'backup_migration'; data.token = 'bmi'; data.nonce = bmiVariables.nonce; data.f = 'front-end-ajax-error'; data.call = func; data.error = errorLogObj; $.post(ajaxurl, data).done((res) => { $.bmi.json(res).then(function(res) { return; }).catch(function(error) { console.log(error); }); }).fail((error) => { console.error(error); }); }, objectToFormData: (obj, form = null, namespace = '') => { const formData = form || new FormData(); const isArr = Array.isArray(obj); for (const key in obj) { if (!obj.hasOwnProperty(key) || obj[key] === null || obj[key] === undefined) { continue; } const formKey = namespace ? (isArr ? `${namespace}[]` : `${namespace}[${key}]`) : key; if (typeof obj[key] === 'string') { formData.append(formKey, obj[key]); } else if (obj[key] instanceof Date) { formData.append(formKey, obj[key].toISOString()); } else if (obj[key] instanceof File) { formData.append(formKey, obj[key]); } else if (typeof obj[key] !== 'object') { formData.append(formKey, obj[key].toString()); } else if (Array.isArray(obj[key])) { obj[key].forEach((item, index) => { const arrayKey = `${formKey}[${index}]`; if (typeof item === 'string') formData.append(arrayKey, item); else jQuery.bmi.objectToFormData(item, formData, arrayKey); }); } else { jQuery.bmi.objectToFormData(obj[key], formData, formKey); } } return formData; }, // PROMISE: BMI POST Requests ajax: function(func, data = {}) { return new Promise(async function(resolve, reject) { function _error(error) { let ajaxErrorObj = {}; console.log('------- BACKUP MIGRATION ERROR START -------'); console.log('The error:', error); console.log('Call: ', func); ajaxErrorObj['call'] = func; if (typeof error == 'object') { for (let i = 0; i < error.length; ++i) { if (typeof error[i] == 'object') { if (typeof error[i]['message'] != 'undefined') { console.log(i, error[i]['message']); ajaxErrorObj[`${i}_x`] = error[i]['message']; } for (let k in error[i]) { if (typeof error[i][k] != 'function') { if (typeof error[i][k] == 'string' && error[i][k].length > 2000) { ajaxErrorObj[`${i}_${k}`] = error[i][k].slice(0, 2000); console.log(i, k); console.warn(error[i][k]); } else { console.log(i, k, error[i][k]); ajaxErrorObj[`${i}_${k}`] = error[i][k]; } } } } else { console.log(i, error[i]); ajaxErrorObj[`${i}_x`] = error[i]; } } } else { console.log(error); if (typeof error == 'string' && error.length > 2000) { ajaxErrorObj[`single_error_txt`] = error.slice(0, 2000); } else { ajaxErrorObj[`single_error_txt`] = error; } } console.log('-------- BACKUP MIGRATION ERROR END --------\n\n'); $.bmi.logJsonError(ajaxErrorObj, func); reject(error); } data.action = 'backup_migration'; data.token = 'bmi'; data.nonce = bmiVariables.nonce; data.f = func; try { let res = await fetch(ajaxurl + '?cache=false', { "body": new URLSearchParams($.bmi.objectToFormData(data)).toString(), "cache": "default", "credentials": "include", "headers": { "Accept": "*/*", "Accept-Language": navigator.language + ";q=0.9", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "User-Agent": navigator.userAgent, "X-Requested-With": "XMLHttpRequest" }, "method": "POST", "mode": "cors", "redirect": "follow", "referrer": window.location.href, "referrerPolicy": "strict-origin-when-cross-origin" }); let response = null; if (res.ok === true) { response = await res.text(); $.bmi.json(response).then(function(parsedResponse) { resolve(parsedResponse); }).catch(function(error) { console.error(error); _error(['json', error, res, func, data, (response || false)]); }); } else { response = await res.text().catch(() => ''); throw new Error('Response is not OK (' + res.status + '): ' + (response || 'No response body')); } } catch (error) { _error([error, func, data]); } // $.post(ajaxurl + '?cache=false', data).done((res) => { // $.bmi.json(res).then(function(res) { // resolve(res); // }).catch(function(error) { // console.error(error); // _error(['json', error, res, func, data, (res.responseText || false)]); // }); // }).fail((error) => { // _error([error, func, data]); // }); }); }, // STATIC: Tooltips tooltips: { init: function() { function tooltipReposition() { setTimeout(() => { let instances = $.tooltipster.instances(); for (instance in instances) instances[instance].reposition(); }, 10); } let settings = { delay: 200, debug: false, delayTouch: [100, 200], interactive: false, distance: 0, side: 'top', contentAsHTML: false, maxWidth: 460, triggerOpen: { mouseenter: true, touchstart: true }, triggerClose: { mouseleave: true, click: true, tap: true }, theme: ['bmi-tooltip', 'bmi-tt-default', 'bmi-tt-default-customized'], repositionOnScroll: true, functionReady: tooltipReposition } function extractThemesFromElement(el) { try { const base = settings.theme; const classList = (el && el.className ? el.className : '') .split(/\s+/) .filter(Boolean); const extracted = classList.filter(c => c.indexOf('bmi-tt-') === 0); if (extracted.length) return base.concat(extracted); else return base; } catch (e) { return settings.theme; } } let tts = $('.tooltip'); let tts_html = $('.tooltip-html'); let premiums = $('.premium-wrapper'); let settings_html = JSON.parse(JSON.stringify(settings)); settings_html.contentAsHTML = true; settings_html.interactive = true; for (let i = 0; i < tts.length; ++i) { let tooltip = tts[i]; let top = tooltip.getAttribute('data-top'); let side = tooltip.getAttribute('side'); let s = JSON.parse(JSON.stringify(settings)); s.content = tooltip.getAttribute('tooltip'); s.theme = extractThemesFromElement(tooltip); if (top) s.distance = parseInt(top); if (side && side.trim().length > 0) s.side = side; $(tooltip).tooltipster(s); } for (let i = 0; i < tts_html.length; ++i) { let tooltip = tts_html[i]; let side = tooltip.getAttribute('side'); let s = JSON.parse(JSON.stringify(settings_html)); s.content = tooltip.getAttribute('tooltip'); s.theme = extractThemesFromElement(tooltip); if (side && side.trim().length > 0) s.side = side; $(tooltip).tooltipster(s); } for (let i = 0; i < premiums.length; ++i) { let premium = premiums[i]; let semiums = JSON.parse(JSON.stringify(settings)); semiums.contentAsHTML = true; semiums.interactive = true; semiums.maxWidth = 500; semiums.theme = extractThemesFromElement(premium); if (premium.getAttribute('tooltip')) semiums.content = premium.getAttribute('tooltip'); else if (premium.getAttribute('data-ready')) { semiums.content = $('#premium-tooltip-pre')[0].innerHTML.trim() + ' ' + premium.getAttribute('data-ready').trim() + ' ' + $('#premium-tooltip-r')[0].innerHTML.trim(); } else semiums.content = $('#premium-tooltip')[0].innerHTML; if (premium.getAttribute('side')) semiums.side = premium.getAttribute('side'); $(premium).tooltipster(semiums); } }, hideAll: function(rightnow = false) { function _hide() { let instances = $.tooltipster.instances(); for (instance in instances) instances[instance].close(); } if (rightnow) _hide(); else setTimeout(_hide, 10); } }, // STATIC: Collapsers collapsers: { toggle: function(self) { if (collapsing === true) return; else collapsing = true; let group = self.getAttribute('group'); if (self.classList.contains('active')) $.bmi.collapsers.close(self); else $.bmi.collapsers.open(self, group); }, open: function(el, group) { $.bmi.collapsers.closeGroup(group); $(el).addClass('active'); $(el).find('.content').show(300); setTimeout(function() { collapsing = false; }, 300); }, close: function(el) { $(el).removeClass('active'); $(el).find('.content').hide(300); setTimeout(function() { collapsing = false; }, 300); }, closeGroup: function(group) { $('.collapser[group="' + group + '"]').removeClass('active'); $('.collapser[group="' + group + '"]').find('.content').hide(300); setTimeout(function() { collapsing = false; }, 300); }, closeAll: function() { $('.collapser').removeClass('active'); $('.collapser').find('.content').hide(300); setTimeout(function() { collapsing = false; }, 300); } }, // STATIC: URL Validation isUrlValid: function(url) { var re_weburl = new RegExp( "^" + "(?:(?:(?:https?|ftp):)?\\/\\/)" + "(?:\\S+(?::\\S*)?@)?" + "(?:" + "(?!(?:10|127)(?:\\.\\d{1,3}){3})" + "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" + "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" + "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + "|" + "(?:" + "(?:" + "[a-z0-9\\u00a1-\\uffff]" + "[a-z0-9\\u00a1-\\uffff_-]{0,62}" + ")?" + "[a-z0-9\\u00a1-\\uffff]\\." + ")+" + "(?:[a-z\\u00a1-\\uffff]{2,}\\.?)" + ")" + "(?::\\d{2,5})?" + "(?:[/?#]\\S*)?" + "$", "i" ); if (re_weburl.test(url)) return true; else return false; }, // STATIC: Human Readable bytesToHuman: function(a, b, c, d, e) { return (b = Math, c = b.log, d = 1024, e = c(a) / c(d) | 0, a / b.pow(d, e)) .toFixed(2) + ' ' + (e ? 'KMGTPEZY' [--e] + 'B' : 'Bytes'); }, // STATIC: Human Readable Cut Decimal bytesToHumanCut: function(a, b, c, d, e) { return Math.ceil((b = Math, c = b.log, d = 1024, e = c(a) / c(d) | 0, a / b.pow(d, e))) + ' ' + (e ? 'KMGTPEZY' [--e] + 'B' : 'Bytes'); }, // STATIC: Getting backups getCurrentBackups: function(done = function() {}, tries = 0, q = '') { if ($('#reloading-bm-list').length > 0 && $('#reloading-bm-list')[0].style.display == 'none') { $('#reloading-bm-list').show(); $.bmi.ajax('get-current-backups', { q: q }).then(function(res) { // console.warn('Backup list loaded...'); $.bmi.ajax('check-not-uploaded-backups').then(function(res) { // console.warn('Checking for not uploaded backups...'); // console.log(res); }); $('#reloading-bm-list').hide(); done(res); }).catch(function(error) { $('#reloading-bm-list').hide(); if (tries > 5) return; setTimeout(() => { $.bmi.getCurrentBackups(done, (tries+1)); }, 1000); }); } }, getCurrentStaging: function(done = function() {}) { if ($('#reloading-bm-stg-list').length > 0 && $('#reloading-bm-stg-list')[0].style.display == 'none') { $('#reloading-bm-stg-list').show(); $.bmi.ajax('staging-get-updated-list', {}).then(function(res) { $('#reloading-bm-stg-list').hide(); done(res); }).catch(function(error) { // }); } }, getExpirationTime: function(time) { let $tbody = $('#stg-tbody-table'); let expiresNever = $tbody.data('never'); if (isNaN(parseInt(time)) || time == expiresNever) { return time; } let now = +new Date(); let destination = time * 1000; let diff = (destination - now); let days = Math.floor(diff / 24 / 60 / 60 / 1000); let hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); let minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); let seconds = Math.floor((diff % (1000 * 60)) / 1000); if (destination < now) { days = 0; hours = 0; minutes = 0; seconds = 0; } if (days == 0 && hours == 0 && minutes == 0 && (seconds == 2 || seconds == 1)) { clearTimeout(window.bmiRefreshExpired); window.bmiRefreshExpired = setTimeout(function () { $.bmi.reloadStaging(); }, 3000); } return `${('0' + days).slice(-2)}:${('0' + hours).slice(-2)}:${('0' + minutes).slice(-2)}:${('0' + seconds).slice(-2)}`; }, fillWithNewStagings: function(sites, cb = function() {}) { let stagingSiteNames = []; let amountOfSites = 0; let $tbody = $('#stg-tbody-table'); let $templateOrigin = $('.br_stg_tr_template'); let emptyText = $tbody.data('empty'); let localText = $tbody.data('local'); let prefixText = $tbody.data('prefix'); let expiresNever = $tbody.data('never'); let displayText = $tbody.data('display'); let originalText = $tbody.data('original'); let emptyElementTR = document.createElement('TR'); let emptyElementTD = document.createElement('TD'); emptyElementTD.setAttribute('colspan', '100%'); emptyElementTD.classList.add('center'); emptyElementTD.innerText = emptyText; emptyElementTR.append(emptyElementTD); $tbody.html(''); for (let site in sites) { site = sites[site]; if (typeof site.name == 'undefined') continue; if (typeof site.url == 'undefined') continue; if (typeof site.db_prefix == 'undefined') continue; stagingSiteNames.push(escapeHtml(site.name)); let $template = $templateOrigin.clone(); $template.removeClass('br_stg_tr_template'); $template.attr('name', escapeHtml(site.name)); $template.find('.stg-tr-name').text(escapeHtml(site.display_name)); $template.find('.stg-tr-name').attr('tooltip', `<b>${originalText}</b>: ${escapeHtml(site.name)}<br><b>${displayText}</b>: ${escapeHtml(site.display_name)}`); if (escapeHtml(site.name) == escapeHtml(site.display_name)) { $template.find('.stg-tr-name').attr('tooltip', `<b>${displayText}</b>: ${escapeHtml(site.display_name)}`); } $template.find('.stg-tr-url-el').attr('href', escapeHtml(site.url)); $template.find('.stg-tr-url-el').attr('tooltip', escapeHtml(site.url)); $template.find('.stg-tr-url-el').text(escapeHtml(site.url)); $template.find('.stg-tr-size').text(escapeHtml(site.total_size) + ' (' + escapeHtml(site.total_files) + ')'); $template.find('.stg-tr-server').text((site.communication_secret == 'local') ? escapeHtml(localText) : 'TasteWP'); $template.find('.stg-tr-server').attr('tooltip', prefixText + ': ' + escapeHtml(site.db_prefix)); $template.find('.stg-tr-creation').text(escapeHtml(site.creation_date)); $template.find('.stg-tr-expiration span').text(escapeHtml(site.expiration_time)); if (site.communication_secret != 'local') { $template.addClass('bmi-tastewp-staging-row'); $template.attr('server', 'tastewp'); $template.attr('token', escapeHtml(site.communication_secret)); if (isNaN(parseInt(site.expiration_time)) || site.expiration_time == expiresNever) { $template.attr('expiration', escapeHtml(expiresNever)); $template.find('.stg-tr-expiration span').text(escapeHtml(expiresNever)); if (site.is_premium == '1') $template.find('.stg-tr-expiration span').addClass('stg-premium-stars'); } else { $template.attr('expiration', parseInt(site.expiration_time)); $template.find('.stg-tr-expiration span').text($.bmi.getExpirationTime(parseInt(site.expiration_time))); } } else { $template.attr('server', 'local'); $template.find('.stg-tr-expiration span').text(escapeHtml(expiresNever)); } $template.hide(); $template.prependTo($tbody); amountOfSites++; } if (amountOfSites == 0) { $tbody.html(emptyElementTR); } if ($('#bmi-stg-subname-input').val() == '') { let j = 1; let defaultName = bmiVariables.stgStagingDefaultName; for (let i = 0; i < stagingSiteNames.length; ++i) { let name = stagingSiteNames[i]; if (stagingSiteNames.includes(defaultName)) { defaultName = bmiVariables.stgStagingDefaultName + j; j++; } else break; } $('#bmi-stg-subname-input').val(defaultName); } $.bmi.tooltips.init(); $.bmi.showStagings(); }, // STATIC: Filling backups fillWithNewBackups: function(res, ongoing, cb = function() {}, search = '') { // let backupsList = {}; let external = res.external; let local = res.local; let backups = {}; // Local backups for (let name in local) { if (search !== '' && local[name][0].toLowerCase().indexOf(search.toLowerCase()) === -1) continue; let backup = local[name]; backups[backup[7]] = backup; backups[backup[7]][10] = backup[9]; backups[backup[7]][9] = backup[8]; backups[backup[7]][8] = { local: true }; } // Google Drive and FTP backups // for (let cloudName in external) { // for (let md5 in external[cloudName]) { // let backup = external[cloudName][md5]; // for (let md51 in external[cloudName]) { // if (typeof backups[md51] == 'undefined') { // if (cloudName === 'FTP'){ // backups[md51] = backup; // backups[md51][9] = backup[9]; // if (typeof backups[md51][8] == 'undefined' || typeof backups[md51][8] != 'object') { // backups[md51][8] = {local: false, ftp: backup[8]} // } else if (typeof backups[md51][8] == 'object') { // backups[md51][8] = backup[8]; // } // }else if(cloudName === 'gdrive'){ // backups[md51] = backup; // backups[md51][9] = backup[9]; // if (typeof backups[md51][8] == 'undefined' || typeof backups[md51][8] != 'object') { // backups[md51][8] = {local: false, gdrive: backup[8]} // } else if (typeof backups[md51][8] == 'object') { // backups[md51][8].gdrive = backup[8]; // } // } // } else { // if (cloudName === 'FTP'){ // backups[md51][8].ftp = backup[8]; // }else if(cloudName === 'gdrive'){ // backups[md51][8].gdrive = backup[8]; // } // } // } // } // } // Google Drive backups for (let drive in external) { for (let backupKey in external[drive]) { if (search !== '' && external[drive][backupKey][0].toLowerCase().indexOf(search.toLowerCase()) === -1) continue; let backup = external[drive][backupKey]; let md5 = backup[7]; if (typeof backups[md5] == 'undefined') { backups[md5] = {...backup}; backups[md5][9] = backup[9]; if (typeof backups[md5][8] == 'undefined' || typeof backups[md5][8] != 'object') { backups[md5][8] = { local: false }; if (typeof backups[md5][8][drive] == 'undefined') { backups[md5][8][drive] = backup[8]; } } else if (typeof backups[md5][8] == 'object') { if (typeof backups[md5][8][drive] == 'undefined') { backups[md5][8][drive] = backup[8]; } } } else { if (typeof backups[md5][8][drive] == 'undefined') { backups[md5][8][drive] = backup[8]; } } } } $('#bmi_restore_tbody').html(''); $('.bmi-stg-dropdown-area-inner-scroll').html(''); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-name').text(bmiVariables.stgLoading); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-date i').text('---'); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-size i').text('---'); let totalStagingPossibleBackups = 0; let lockedtxt = $('#bmi-manual-locked').text().trim(); let backupsSorted = Object.keys(backups).sort(function(a, b) { let x = +new Date(backups[a][1].replace(/\-/g, '/')); let y = +new Date(backups[b][1].replace(/\-/g, '/')); return x - y; }); let i = 0; for (; i < backupsSorted.length; ++i) { let storages = []; let index = backupsSorted[i]; let md5 = backups[index][7]; let domain = backups[index][9]; let locked = backups[index][5] === 'locked' ? true : false; let name = backups[index][0]; let originalname = backups[index][0]; if (backups[index][0].includes('#%&')) { name = backups[index][0].split('#%&')[1]; originalname = backups[index][0].split('#%&')[0]; } name = name.replace(/ /g, ''); name = name.trim(); originalname = originalname.replace(/ /g, ''); originalname = originalname.trim(); let isLocalBackup = true; let isGoogleDrive = false; let isFtp = false; let isDropbox = false; let isCloud = false; let isOneDrive = false; let isPCloud = false; let isAWS = false; let isWasabi = false; let isBackupBliss = false; let isSftp = false; if (typeof backups[index][8] != 'undefined') { if (typeof backups[index][8] == 'object') { for (let storage in backups[index][8]) { if (storage == 'gdrive') { isGoogleDrive = backups[index][8][storage]; } else if (storage == 'FTP') { isFtp = backups[index][8][storage]; } else if (storage == 'dropbox') { isDropbox = backups[index][8][storage]; } else if (storage == 'local') { isLocalBackup = backups[index][8][storage]; } else if (storage == 'onedrive') { isOneDrive = backups[index][8][storage]; } else if (storage == 'pcloud') { isPCloud = backups[index][8][storage]; } else if (storage == 'aws') { isAWS = backups[index][8][storage]; } else if (storage == 'wasabi') { isWasabi = backups[index][8][storage]; } else if (storage == 'backupbliss') { isBackupBliss = backups[index][8][storage]; } else if (storage == 'sftp') { isSftp = backups[index][8][storage]; } } } } isCloud = isGoogleDrive || isFtp || isDropbox || isOneDrive || isBackupBliss || isSftp || isAWS || isWasabi || isPCloud; let bwsc = '<b>' + $('#bmi-backup-created-on').text().trim() + '</b>'; let bonc = '<b>' + $('#bmi-backup-original-name').text().trim() + '</b>'; let bfnc = '<b>' + $('#bmi-backup-file-name').text().trim() + '</b>'; let id = 'bmi_br_backup_' + i; let $template = $('.br_tr_template').clone(); $template.removeClass('br_tr_template'); $template[0].style.display = 'none'; $template.attr('md5', md5); if (isGoogleDrive) $template.attr('gdrive-id', isGoogleDrive); if (isFtp) $template.attr('ftp-id', isFtp); if (isDropbox) $template.attr('dropbox-id', isDropbox); if (!isLocalBackup && isCloud) $template.attr('data-is-local', 'no'); else $template.attr('data-is-local', 'yes'); if (isOneDrive) $template.attr('onedrive-id', isOneDrive); if (isPCloud) $template.attr('pcloud-id', isPCloud); if (isAWS) $template.attr('aws-id', isAWS); if (isWasabi) $template.attr('wasabi-id', isWasabi); if (isBackupBliss) $template.attr('backupbliss-id', isBackupBliss); if (isSftp) $template.attr('sftp-id', isSftp); $template.find('.br_label').attr('for', id); $template.find('.br_checkbox').attr('id', id); $template.find('.bc-download-btn').attr('href', $('#BMI_BLOG_URL').text().trim() + '/?backup-migration=BMI_BACKUP&bmi-id=' + name + '&sk=' + $('#BMI_SECRET_KEY').text().trim()); $template.find('.bc-logs-btn').attr('href', $('#BMI_BLOG_URL').text().trim() + '/?backup-migration=BMI_BACKUP_LOGS&bmi-id=' + name + '&sk=' + $('#BMI_SECRET_KEY').text().trim()); $template.find('.br_date').text(backups[index][1]); $template.find('.br_name').text(name); if (originalname == name) { $template.find('.br_name').attr('tooltip', (bonc + ' ' + escapeHtml(originalname) + '<br><br>' + bwsc + ' ' + escapeHtml(domain))); } else { $template.find('.br_name').attr('tooltip', (bonc + ' ' + escapeHtml(originalname) + '<br><br>' + bfnc + ' ' + escapeHtml(name) + '<br><br>' + bwsc + ' ' + escapeHtml(domain))); } let readableBytesNotCut = $.bmi.bytesToHuman(backups[index][4]); let readableBytes = $.bmi.bytesToHuman(backups[index][4]); if (readableBytes.includes('MB') || readableBytes.includes('KB')) { readableBytes = $.bmi.bytesToHumanCut(backups[index][4]); } $template.find('.br_size').text(readableBytes + ' (' + backups[index][2] + ')'); if (isGoogleDrive) { $template.find('.br_stroage').find('.strg-gdrive').addClass('img-green'); storages.push('Google Drive'); } else { $template.find('.br_stroage').find('.strg-gdrive').addClass('img-red'); } // if (isLocalBackup && isCloud) { // $template.find('.br_stroage').find('.strg-suc').addClass('img-green'); // } else { // $template.find('.br_stroage').find('.strg-suc').addClass('img-orange'); // } if (isFtp) { $template.find('.br_stroage').find('.strg-ftp').addClass('img-green'); storages.push('FTP'); } else { $template.find('.br_stroage').find('.strg-ftp').addClass('img-red'); } if (isDropbox) { $template.find('.br_stroage').find('.strg-dropbox').addClass('img-green'); storages.push('Dropbox'); } else { $template.find('.br_stroage').find('.strg-dropbox').addClass('img-red'); } if (isOneDrive) { $template.find('.br_stroage').find('.strg-onedrive').addClass('img-green'); storages.push('OneDrive'); } else { $template.find('.br_stroage').find('.strg-onedrive').addClass('img-red'); } if (isPCloud) { $template.find('.br_stroage').find('.strg-pcloud').addClass('img-green'); storages.push('pCloud'); } else { $template.find('.br_stroage').find('.strg-pcloud').addClass('img-red'); } if (isAWS) { $template.find('.br_stroage').find('.strg-aws').addClass('img-green'); storages.push('AWS S3'); } else { $template.find('.br_stroage').find('.strg-aws').addClass('img-red'); } if (isWasabi) { $template.find('.br_stroage').find('.strg-wasabi').addClass('img-green'); storages.push('Wasabi'); } else { $template.find('.br_stroage').find('.strg-wasabi').addClass('img-red'); } if (isBackupBliss) { $template.find('.br_stroage').find('.strg-backupbliss').addClass('img-green'); storages.push('BackupBliss'); } else { $template.find('.br_stroage').find('.strg-backupbliss').addClass('img-red'); } if (isSftp) { $template.find('.br_stroage').find('.strg-sftp').addClass('img-green'); storages.push('SFTP'); } else { $template.find('.br_stroage').find('.strg-sftp').addClass('img-red'); } if (isLocalBackup) { $template.find('.br_stroage').find('.strg-local').addClass('img-green'); storages.push('Local Storage'); for (let key in backups[index][10]) { if (backups[index][10].hasOwnProperty(key)) { if ($template.find('.br_stroage').find('.strg-' + key).length > 0 && $template.find('.br_stroage').find('.strg-' + key).hasClass('img-red')) { let storageElement = $template.find('.br_stroage').find('.strg-' + key); let storageElementTooltip = storageElement.attr('tooltip'); storageElement.addClass('can-be-manually-uploaded'); storageElement.attr('tooltip', 'Upload To ' + storageElementTooltip); } } } } else { $template.find('.br_stroage').find('.strg-local').addClass('img-red'); $template.find('.brow_subactions').hide(); $template.find('.brow_lock').hide(); } //$template.find('.br_stroage').find('.strg-suc').attr('tooltip', 'Backup is stored on: ' + storages.join(', ') + '.'); if (!$('#bmi-pro-storage-gdrive-toggle').is(':checked')) { $template.find('.br_stroage').addClass('bmi-gdrive-disabled'); } if (!$('#bmi-pro-storage-ftp-toggle').is(':checked')) { $template.find('.br_stroage').addClass('bmi-ftp-disabled'); } if (!$('#bmi-pro-storage-onedrive-toggle').is(':checked')) { $template.find('.br_stroage').addClass('bmi-onedrive-disabled'); } if ((''+backups[index][6]).trim().length == 0 || (backups[index][6]+'') == 'false') { $template.find('.bc-locked-btn').addClass('forever'); $template.find('.bc-locked-btn').attr('tooltip', lockedtxt); locked = true; } if (locked) { $template.find('.bc-unlocked-btn').hide(); } else { $template.find('.bc-locked-btn').hide(); } isDirectLinkEnabled = $('[name="radioAccessViaLink"]:checked').val() === "true"; if (!isDirectLinkEnabled) { $template.find('.bc-url-btn svg') .css({ cursor: "not-allowed", color: "red" }) .addClass('disabled'); $template.find('.bc-url-btn') .attr('tooltip', $('#direct-link-disabled-tooltip').text().trim()); } else { $template.find('.bc-url-btn svg') .css({ cursor: "pointer", color: "#B6B6B6" }) .removeClass('disabled'); $template.find('.bc-url-btn') .attr('tooltip', $('#direct-link-enabled-tooltip').text().trim()); } $template.prependTo('#bmi_restore_tbody'); $('.bmi-stg-drop-option.active').removeClass('active'); if (isLocalBackup) { let $stgOptionTemplate = $('.bmi-stg-option-template').clone(); $stgOptionTemplate.removeClass('bmi-stg-option-template'); $stgOptionTemplate[0].style.display = ''; $stgOptionTemplate.attr('backup-name', name); $stgOptionTemplate.addClass('active'); $stgOptionTemplate.find('.bmi-stg-option-name').text(name); $stgOptionTemplate.find('.bmi-stg-option-date i').text(backups[index][1]); $stgOptionTemplate.find('.bmi-stg-option-size i').text(readableBytesNotCut); $stgOptionTemplate.prependTo('.bmi-stg-dropdown-area-inner-scroll'); // if (!isLocalBackup && isGoogleDrive) { // Unreachable code // $stgOptionTemplate.attr('gdrive-id', isGoogleDrive); // $stgOptionTemplate.attr('data-is-local', 'no'); // } else if (isLocalBackup) { // $stgOptionTemplate.attr('data-is-local', 'yes'); // } $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-name').text(name); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-date i').text(backups[index][1]); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-size i').text(readableBytesNotCut); $('#bmi-stg-current-backup-selected').val(name); totalStagingPossibleBackups++; } // backups[name].push(name); // backupsList[id] = backups[name]; } if ($('.bmi-stg-sel-box.bmi-active').attr('data-mode') == 'tastewp') { $('.bmi-stg-creation-box-local').hide(300); $('.bmi-stg-creation-box-tastewp').hide(300); $('.bmi-stg-creation-box-tastewp-empty').hide(300); if ($('.bmi-stg-drop-option:not(.bmi-stg-option-template)').length > 0) { $('.bmi-stg-creation-box-tastewp').show(300); } else { $('.bmi-stg-creation-box-tastewp-empty').show(300); } } else { $('.bmi-stg-creation-box-local').show(300); $('.bmi-stg-creation-box-tastewp').hide(300); $('.bmi-stg-creation-box-tastewp-empty').hide(300); } if (i == 0) { let empty = $('#bmi_restore_tbody').data('empty'); $('#bmi_restore_tbody').html('<tr class="bmi-empty-text"><td class="center text-muted" colspan="100%">' + empty + '</td></tr>'); } $.bmi.tooltips.init(); $.bmi.showMoreBackups(); if ($('.bmi-stg-sel-box.bmi-active').data('mode') == 'tastewp') { $('.bmi-stg-creation-box-local').hide(300); $('.bmi-stg-creation-box-tastewp').hide(300); $('.bmi-stg-creation-box-tastewp-empty').hide(300); if ($('#bmi_restore_tbody').find('tr:not(.bmi-empty-text)').length > 0) { $('.bmi-stg-creation-box-tastewp').show(300); } else { $('.bmi-stg-creation-box-tastewp-empty').show(300); } } if (typeof ongoing != 'undefined') $.bmi.fillOnGoing(ongoing); cb(); }, // STATIC: Loading 10 more backups showMoreBackups: function(res) { backups = {}; let trs = $('#bmi_restore_tbody').find('tr:hidden'); for (let i = 0; (i < trs.length && i < 10); ++i) { setTimeout(function() { $(trs[i]).show(300); }, (i * 50)); } if ((trs.length - 10) <= 0) { $('#load-more-backups-wrp').hide(300); } else { $('#load-more-backups-wrp').show(300); } }, // STATIC: Animate staging list show showStagings: function() { backups = {}; let trs = $('#stg-tbody-table').find('tr:hidden'); for (let i = 0; i < trs.length; ++i) { setTimeout(function() { $(trs[i]).show(300); }, (i * 50)); } }, setBackupProgressList: function(md5, type, tooltip = false) { //let suc = $('#bmi_restore_tbody').find('tr[md5="' + md5 + '"]').find('.strg-suc'); let warn = $('#bmi_restore_tbody').find('tr[md5="' + md5 + '"]').find('.strg-warn'); let ong = $('#bmi_restore_tbody').find('tr[md5="' + md5 + '"]').find('.strg-ong'); let wait = $('#bmi_restore_tbody').find('tr[md5="' + md5 + '"]').find('.strg-wait'); //suc.hide(); warn.hide(); ong.hide(); wait.hide(); // if (type == 'suc') { // suc.show(); // if (tooltip) suc.tooltipster('content', tooltip); // } if (type == 'warn') { warn.show(); if (tooltip) warn.tooltipster('content', tooltip); } if (type == 'ong') { ong.show(); if (tooltip) ong.tooltipster('content', tooltip); } if (type == 'wait') { wait.show(); if (tooltip) wait.tooltipster('content', tooltip); } }, fillOnGoing: function(ongoing = false) { if (ongoing && typeof ongoing.queue != 'undefined' && typeof ongoing.current_upload != 'undefined') { for (let task in ongoing.queue) { let data = ongoing.queue[task]; let md5 = data.md5; uploadType = task.split('_')[0]; //Replaces existing img- class or add it with new $('#bmi_restore_tbody').find('tr[md5="' + md5 + '"]').find('.strg-' + uploadType).attr('class', function(i, cls) { return /\bimg-[^\s]+/.test(cls) ? cls.replace(/\bimg-[^\s]+/g, 'img-purple') : cls + ' img-purple'; }); $.bmi.setBackupProgressList(md5, 'wait'); } if (typeof ongoing.current_upload == 'object') { if (ongoing.current_upload.length == 0) { if (ongoing_latest_token) { //$.bmi.reloadBackups(); ongoing_failed = false; if (typeof ongoing.failed != 'undefined') { ongoing_failed = currentUploadType + "_" + ongoing_latest_token in ongoing.failed; } $('#bmi_restore_tbody').find('tr[md5="' + ongoing_latest_token + '"]').find('.strg-' + currentUploadType).attr('class', function(i, cls) { return /\bimg-[^\s]+/.test(cls) ? cls.replace(/\bimg-[^\s]+/g, ongoing_failed ? 'img-red' : 'img-green') : cls + ongoing_failed ? ' img-red' : ' img-green'; }); $.bmi.setBackupProgressList(ongoing_latest_token, 'done'); ongoing_latest_token = false; } } else { if (!ongoing_latest_token) { ongoing_latest_token = ongoing.current_upload.md5; } if (ongoing_latest_token && ongoing_latest_token != ongoing.current_upload.md5) { //$.bmi.reloadBackups(); ongoing_failed = false; if (typeof ongoing.failed != 'undefined') { ongoing_failed = currentUploadType + "_" + ongoing_latest_token in ongoing.failed; } $('#bmi_restore_tbody').find('tr[md5="' + ongoing_latest_token + '"]').find('.strg-' + currentUploadType).attr('class', function(i, cls) { return /\bimg-[^\s]+/.test(cls) ? cls.replace(/\bimg-[^\s]+/g, ongoing_failed ? 'img-red' : 'img-green') : cls + ongoing_failed ? ' img-red' : ' img-green'; }); $.bmi.setBackupProgressList(ongoing_latest_token, 'done'); ongoing_latest_token = ongoing.current_upload.md5; } let progress = '0%'; if (typeof ongoing.current_upload.progress != 'undefined') progress = ongoing.current_upload.progress; //Detect type currentUploadType = ongoing.current_upload.task.split('_')[0]; let message = 'Upload to '; let externalStorageType = 'Google Drive'; switch (currentUploadType) { case 'ftp': externalStorageType = 'FTP'; break; case 'dropbox': externalStorageType = 'Dropbox'; break; case 'onedrive': externalStorageType = 'OneDrive'; break; case 'aws': externalStorageType = 'Amazon S3'; break; case 'wasabi': externalStorageType = 'Wasabi'; break; case 'pcloud': externalStorageType = 'pCloud'; case 'backupbliss': externalStorageType = 'BackupBliss'; break; case 'sftp': externalStorageType = 'SFTP'; break; } //Replaces existing img- class or add it with new $('#bmi_restore_tbody').find('tr[md5="' + ongoing_latest_token + '"]').find('.strg-' + currentUploadType).attr('class', function(i, cls) { return /\bimg-[^\s]+/.test(cls) ? cls.replace(/\bimg-[^\s]+/g, 'img-orange') : cls + ' img-orange'; }); message += externalStorageType; $.bmi.setBackupProgressList(ongoing.current_upload.md5, 'ong', message + ' in progress: ' + progress); } } } if (typeof ongoing.failed != 'undefined') { for (let token in ongoing.failed) { data = token.split("_"); md5 = data[1]; uploadType = data[0]; if (!(ongoing.current_upload instanceof Array)) if (ongoing.current_upload.md5 == md5) // Checks if the current upload task is of the same backup the failed task is return; //There's an ongoing upload for the same backup, so will not show any failures to show the upload status. // if (typeof ongoing.queue[token] != 'undefined') { // md5 = ongoing.queue[token].md5; // } // if (typeof ongoing.current_upload.task != 'undefined' && ongoing.current_upload.task == token) { // md5 = ongoing.current_upload.md5; // } if (md5) { //Replaces existing img- class or add it with new $('#bmi_restore_tbody').find('tr[md5="' + md5 + '"]').find('.strg-' + uploadType).attr('class', function(i, cls) { return /\bimg-[^\s]+/.test(cls) ? cls.replace(/\bimg-[^\s]+/g, 'img-red') : cls + ' img-red'; }); let message = 'There was an error during upload to: '; if (uploadType == null || uploadType == 'gdrive') externalStorageType = 'Google Drive'; if (uploadType == 'ftp') externalStorageType = 'FTP'; if (uploadType == 'dropbox') externalStorageType = 'Dropbox'; if (uploadType == 'pcloud') externalStorageType = 'pCloud'; if (uploadType == 'onedrive') externalStorageType = 'OneDrive'; if (uploadType == 'aws') externalStorageType = 'AWS'; if (uploadType == 'wasabi') externalStorageType = 'Wasabi'; if (uploadType == 'backupbliss') externalStorageType = 'BackupBliss'; if (uploadType == 'sftp') externalStorageType = 'SFTP'; message += externalStorageType; $.bmi.setBackupProgressList(md5, 'warn', message); } } } // Update tooltips of external storage icons with upload status const tooltips = { 'img-green': 'Backup is available on %s.', 'img-orange': 'Upload to %s is in progress.', 'img-purple': 'Upload to %s is queued.', 'img-red': 'Backup is not available on %s.', }; const $tbody = $('#bmi_restore_tbody'); let storagesToStr = { 'strg-local': 'Local Storage', 'strg-ftp': 'FTP', 'strg-aws': 'AWS S3', 'strg-backupbliss': 'BackupBliss', 'strg-sftp': 'SFTP', 'strg-gdrive': 'Google Drive', 'strg-onedrive': 'OneDrive', 'strg-pcloud': 'pCloud', 'strg-wasabi': 'Wasabi', 'strg-dropbox': 'Dropbox', } Object.entries(tooltips).forEach(([imgClass, template]) => { $tbody.find(`.${imgClass}`).each(function () { const $el = $(this); const classes = $el.attr('class').split(/\s+/); if (classes.includes('can-be-manually-uploaded')) return; const strgClass = classes.find(c => c.startsWith('strg-')); if (!strgClass || ['strg-suc', 'strg-warn', 'strg-ong', 'strg-wait'].includes(strgClass)) return; let cap = ''; cap = storagesToStr[strgClass] || strgClass.replace('strg-', '').charAt(0).toUpperCase() + strgClass.replace('strg-', '').slice(1); const tooltip = template.replace('%s', cap); $el.tooltipster('content', tooltip); }); }); }, adjustStorageIcons: function() { let es = ['gdrive', 'onedrive', 'sftp', 'ftp', 'dropbox', 'aws', 'wasabi', 'pcloud']; let activeEsCount = 2; for (let i = 0; i < es.length; ++i) { if ($('#bmi-pro-storage-' + es[i] + '-toggle').is(':checked')) { $('.strg-' + es[i]).show(); activeEsCount++; } else { $('.strg-' + es[i]).hide(); } } if ($('.storage-icons-container').length == 0) return; if (activeEsCount > 5 ) { $('.storage-icons-container').css('grid-template-rows', 'repeat(2, auto)'); } else { $('.storage-icons-container').css('grid-template-rows', 'none'); } }, // STATIC: Reload backups list reloadBackups: function(callagain = function() {}) { $.bmi.getCurrentBackups(function(res) { $.bmi.fillWithNewBackups(res.backups, res.backups.ongoing, function() { callagain(); $('#backups-select-all').prop('checked', false); $('.del-all-btn-wrp').hide(300); }); }); }, // STATIC: Reload staging list reloadStaging: function(callagain = function() {}) { $.bmi.getCurrentStaging(function(res) { $.bmi.fillWithNewStagings(res.sites, function() { callagain(); }); }); }, searchInBackups: function(keyword, callagain = function() {}) { $.bmi.getCurrentBackups(function(res) { $.bmi.fillWithNewBackups(res.backups, res.backups.ongoing, function() { callagain(); }, keyword ); }); }, // STATIC: Hides all dropdowns hideAllLists: function() { let opens = $('.dropdown-open'); if (opens.length <= 0) return; for (let i = 0; i < opens.length; ++i) { let open = $(opens[i]); if (open.hasClass('ignored-open')) { open.removeClass('ignored-open'); } else { open.hide(300); open.removeClass('dropdown-open'); $(open[0].closest('.bmi-dropdown')).removeClass('active'); } } }, // Sets and option setOption: function($dropdown, $option = null, value = false) { let $optlist = $dropdown.find('.dropdown-options'); if ($dropdown.attr('data-optioner')) { $optlist = $('.optioner-' + $dropdown.attr('data-optioner')); } $optlist.find('.active-option').removeClass('active-option'); if (value !== false) { $option = $optlist.find('.dropdown-option[data-value="' + value + '"]'); } if ($($option).hasClass('active-option')) return; $dropdown.find('.dropdown-title').text($option.text()); $dropdown.attr('data-selected', $option.data('value')); $option.addClass('active-option'); if (value === false) { $dropdown.change(); } $.bmi.hideAllLists(); }, // STATIC: Prepare file frmo text prepareFile: function(filename, text) { let element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); $.bmi.alert('success', $('#bmi-download-should-start').text(), 3000); }, // Utility to escape html escapeHtml: function(text) { return escapeHtml(text) } } }); }); jQuery(document).ready(function($) { $('.collapser .header').on('click', function(e) { e.preventDefault(); let el = $(this).parent('.collapser')[0]; $.bmi.collapsers.toggle(el); }); $('.bmi_will_collapse').on('change', function(e) { e.preventDefault(); let doNotShow = false; if (this.getAttribute('type') == 'radio') { if (this.getAttribute('value') == 'false') { doNotShow = true; } } $child = $(this).data('if-checked'); if (this.checked === true && !doNotShow) { $('#' + $child).show(300); } else $('#' + $child).hide(300); }); $('.collapser-openner').on('click', function(e) { e.preventDefault(); let group = 'configuration'; let el = $(this).data('el'); if ($(this).data('group')) { group = $(this).data('group'); } $.bmi.collapsers.open(el, group); setTimeout(function() { $([document.documentElement, document.body]).animate({ scrollTop: $(el).offset().top - 50 + 'px' }, 300); }, 300); }); (function() { let $triggers = $('.bmi_will_collapse'); for (let i = 0; i < $triggers.length; ++i) { let doNotShow = false; $trigger = $triggers[i]; $child = $($trigger).data('if-checked'); if ($trigger.getAttribute('type') == 'radio') { if ($trigger.getAttribute('value') == 'false') { doNotShow = true; } } if ($trigger.checked === true) { $('#' + $child).show(); } else $('#' + $child).hide(); } })(); });jQuery(document).ready(function($) { var firsttime = true; var initialized = false; $.bmi.crons = function() { if (initialized === true) return; else initialized = true; if (location.href.includes("crons=true") && location.href.includes("page=backup-migration")){ setTimeout(function(){ $('#i-backup-cron').click(); },300); } function getCronResult(settings, done) { $.bmi.ajax('calculate-cron', settings).then(function(res) { if (res.status == 'success') { done(res); } else { done(false); $.bmi._msg(res); } }).catch(function(error) { done(false); console.log(error); }); } function settings_changed() { let settings = { type: $('[data-id="cron-period"]').attr('data-selected'), day: $('[data-id="cron-day"]').attr('data-selected'), week: $('[data-id="cron-week"]').attr('data-selected'), hour: $('[data-id="cron-hour"]').attr('data-selected'), minute: $('[data-id="cron-minute"]').attr('data-selected'), keep: $('[data-id="cron-keep-backups"]').attr('data-selected'), enabled: ((!$('#cron-btn-toggle')[0].checked === true) ? true : false) } getCronResult(settings, function(res) { if (res.status === 'success' && res !== false) { $('.cron-time-server').tooltipster('option', 'interactive', false); $('.cron-time-server').tooltipster('option', 'contentAsHTML', true); if ($('#cron-btn-toggle')[0].checked === true) res.data = '---'; $('.cron-time-server').tooltipster('content', '<b>' + $('#bmi-next-cron').text() + '</b>' + res.data + '<br>' + '<b>' + $('#bmi-current-time').text() + '</b>' + res.currdata); if (!firsttime) $.bmi.alert('success', $('#bmi-cron-updated').text(), 1500); else firsttime = false; } else { if (!firsttime) $.bmi.alert('error', $('#bmi-cron-updated-fail').text(), 2500); else firsttime = false; } }); } $('#bmi').on('change', '[data-id="cron-period"]', function(e) { settings_changed(); adjust_text(e.target.getAttribute('data-selected')); }); $('#bmi').on('change', '[data-id="cron-day"]', function(e) { let val = e.target.getAttribute('data-selected'); settings_changed(); }); $('#bmi').on('change', '[data-id="cron-week"]', function(e) { let val = e.target.getAttribute('data-selected'); settings_changed(); }); $('#bmi').on('change', '[data-id="cron-hour"]', function(e) { let val = e.target.getAttribute('data-selected'); settings_changed(); }); $('#bmi').on('change', '[data-id="cron-minute"]', function(e) { let val = e.target.getAttribute('data-selected'); settings_changed(); }); $('#bmi').on('change', '[data-id="cron-keep-backups"]', function(e) { let val = e.target.getAttribute('data-selected'); settings_changed(); }); $('#i-backup-cron').on('click', function() { if ($('.cron-backups').find('.turned-off').is(':visible')) { $('#cron-btn-toggle').prop('checked', false); $('.cron-backups').removeClass('disabled'); settings_changed(); $('.cron-backups').find('.turned-on').css({ opacity: 0 }); $('.cron-backups').find('.turned-off').css({ opacity: 0 }); $('.cron-backups').find('.turned-on').show(); $('.cron-backups').find('.turned-on').css({ opacity: 1 }); setTimeout(function() { $('.cron-backups').find('.turned-off').hide(); }, 300); } }); $('#cron-btn-toggle').on('change', function() { if (!this.checked) { $('.cron-backups').removeClass('disabled'); } else { $('.cron-backups').addClass('disabled'); } settings_changed(); }); function adjust_text(val) { if (val == 'month') { $('.cron-the').show(); $('[data-id="cron-day"]').show(); $('[data-id="cron-week"]').hide(); $('#cron-on-word').show(); } else if (val == 'week') { $('.cron-the').hide(); $('[data-id="cron-day"]').hide(); $('[data-id="cron-week"]').show(); $('#cron-on-word').show(); } else { $('.cron-the').hide(); $('[data-id="cron-day"]').hide(); $('[data-id="cron-week"]').hide(); $('#cron-on-word').hide(); } } (function() { adjust_text($('[data-id="cron-period"]')[0].getAttribute('data-selected')); settings_changed(); })(); } });jQuery(document).ready(function($) { $.bmi.dropdowns = { init: function() { let $r = $('#bmi'); function scanSelects() { let selects = $r.find('select'); for (let i = 0; i < selects.length; ++i) { let select = selects[i]; handleSelect(select); } } function createDropdown(title = '---') { let dropdown = $('.dropdown-template').clone(); dropdown.removeClass('dropdown-template'); dropdown.find('.dropdown-title').text(title); return dropdown; } function createOption(value = 'null', text = '---') { let option = $('.option-template').clone(); option.removeClass('option-template'); option.attr('data-value', value); option.text(text); return option; } function longestOption(options) { let longest = ''; for (let i = 0; i < options.length; ++i) { let len = options[i].innerText; if (longest.length < len.length) longest = len; } return longest; } function handleSelect(select) { if (select.style.display != 'none') { select.style.display = 'none'; let $select = $(select); let options = $select.find('option'); let longest = longestOption(options); let dropdown = createDropdown(longest); dropdown = handleOptions(dropdown, options); let def = options[0].value; let parent = select.getAttribute('data-parent'); let classes = select.getAttribute('data-classes'); let isHidden = select.getAttribute('data-hide') === 'true' ? true : false; if ($select.attr('data-def')) def = $select.attr('data-def'); $(dropdown).attr('data-id', select.id); $(dropdown).attr('class', ((classes != null ? classes : '') + ' bmi-dropdown').trim()); $(dropdown).insertBefore($select); if (parent !== null) { let num = parseInt(Math.random() * (987654321 - 123456789) + 123456789); $(dropdown).attr('data-optioner', num); $(dropdown).find('.dropdown-options').attr('data-oparent', num); $(dropdown).find('.dropdown-options').addClass('optioner-' + num); $(dropdown).find('.dropdown-options').appendTo(parent); $(parent).css({ position: 'relative' }); } let clone = $(dropdown).clone(); if (!clone) return; clone[0].style.visibility = 'hidden'; $r.append(clone); let width = clone.width(); clone.remove(); $.bmi.setOption($(dropdown), null, def); let fixedWidth = $select.attr('data-width'); if (fixedWidth) width = parseInt(fixedWidth); $(dropdown).find('.dropdown-title')[0].style.minWidth = (width + 10) + 'px'; let readonly = $select.attr('data-readonly'); if (readonly == 'true') { $(dropdown).find('.dropdown-title')[0].style.pointerEvents = 'none'; $(dropdown).closest('.bmi-dropdown')[0].style.background = '#f1f1f1'; } if (isHidden) $(dropdown).hide(); } } function handleOptions(dropdown, options) { let list = $(dropdown).find('.dropdown-options'); if ($(dropdown).attr('data-optioner')) { list = $('.optioner-' + $(dropdown).attr('data-optioner')); } for (let i = 0; i < options.length; ++i) { let option = options[i]; list.append(createOption(option.value, option.innerText)); } return dropdown; } function toggleDropdown($dropdown) { let $list = $dropdown.find('.dropdown-options'); if ($dropdown.attr('data-optioner')) { $list = $('.optioner-' + $dropdown.attr('data-optioner')); $list.css({ position: 'absolute' }); let width = $dropdown[0].offsetWidth; let left = $dropdown[0].offsetLeft + 240; let top = $dropdown[0].offsetTop + $dropdown[0].offsetHeight + 5; $list.css({ maxWidth: width + 'px', minWidth: width + 'px', top: top + 'px', left: left + 'px' }); } if ($list.hasClass('dropdown-open')) { $dropdown.removeClass('active'); $list.removeClass('dropdown-open'); $list.hide(300); } else { $dropdown.addClass('active'); $list.addClass('dropdown-open'); $list.addClass('ignored-open'); $list.show(300); } } // Initlaization scanSelects(); // Init crons after init of drop $.bmi.crons(); // Events $r.on('click', function(e) { if (!($(e.target).hasClass('bmi-dropdown') || e.target.closest('.bmi-dropdown'))) $.bmi.hideAllLists(); }); $r.on('click', '.dropdown-title', function(e) { $dropdown = $(e.target.closest('.bmi-dropdown')); toggleDropdown($dropdown); $.bmi.hideAllLists(); }); $r.on('click', '.dropdown-option', function(e) { if ($(e.target.closest('.dropdown-options')).attr('data-oparent')) { $dropdown = $('.bmi-dropdown[data-optioner="' + $(e.target.closest('.dropdown-options')).attr('data-oparent') + '"]'); $option = $(e.target); $.bmi.setOption($dropdown, $option); } else { $dropdown = $(e.target.closest('.bmi-dropdown')); $option = $(e.target); $.bmi.setOption($dropdown, $option); } }); } } }); jQuery(document).ready(function ($) { var backups = {}; var bacupisDone = false, progressIsDone = false; var timeouter, curdivs = 0, iprogres; var stopBackgroundBackup = false; let totalSize = 0, totalExcluded = 0, totalSizesI = 0; let current_restore = null; let current_last = null; let latest_delete = null; let latest_delete_cloud = null; let backupOnGoing = false; let restoreOnGoing = false; let ongoing_interval = 10000; let triggeredByIntv = false; let backgroundBackup = false; let backgroundName = null; let headers_for_middleware = false; let cli_quickmigration = false; let restoreCLI = false; let autoLog = {}; let latestLines = []; let lineTimeoutAppend = null; let isLineAppendTimeoutRunning = false; let latestStep = ""; let currentGDriveIdRestoration = null; let restoreStartTime = null; let downloadBackupFinished = false; let restoreLogs = null; window.bmi = {}; function isChecked(id) { $cb = $("#" + id).is(":checked"); if ($cb === true) return "true"; else return "false"; } function getSelectedSize() { size = 0; if ($("#files-group-backup").is(":checked")) { if ($("#files-group-plugins").is(":checked")) { size += parseInt( $('label[for="files-group-plugins"]').find(".value").attr("bytes"), ); } if ($("#files-group-uploads").is(":checked")) { size += parseInt( $('label[for="files-group-uploads"]').find(".value").attr("bytes"), ); } if ($("#files-group-themes").is(":checked")) { size += parseInt( $('label[for="files-group-themes"]').find(".value").attr("bytes"), ); } if ($("#files-group-other-contents").is(":checked")) { size += parseInt( $('label[for="files-group-other-contents"]') .find(".value") .attr("bytes"), ); } if ($("#files-group-wp-install").is(":checked")) { size += parseInt( $('label[for="files-group-wp-install"]').find(".value").attr("bytes"), ); } } if ($("#database-group-backup").is(":checked")) { size += parseInt( $('label[for="database-group-backup"]').find(".value").attr("bytes"), ); } return size; } function locationSet(location, res) { totalSizesI += 1; if (location != "database") totalSize += parseInt(res["bytes"]); totalExcluded += parseInt(res["excluded"]); if (res["bytes"] <= 10000) { $("#bmi-scan-" + location) .find(".value") .text("(0 MB)"); } else { let megas = (parseInt(res["bytes"]) / 1024 / 1024).toFixed(2); $("#bmi-scan-" + location) .find(".value") .text("(" + megas + " MB)"); } $("#bmi-scan-" + location) .find(".value") .attr("bytes", parseInt(res["bytes"])); $("#bmi-scan-" + location) .find(".value") .attr("excluded", parseInt(res["excluded"])); if (totalSizesI == 6) doSomethingWithTotal(); } function scanAndSet(location) { return new Promise(function (resolve) { $.bmi .ajax("scan-directory", { folder: location, }) .then(function (res) { setTimeout(resolve, 150); locationSet(location, res); }) .catch(function (error) { setTimeout(resolve, 150); locationSet(location, { bytes: "0", excluded: "0", readable: "0 B", }); }); }); } function resetSpinners(resources, withTotal = false) { if (withTotal) { $("#bmi-scan-total") .find(".value") .html('(<div class="spinner-loader"></div>)'); $("#bmi-scan-total").find(".value").removeAttr("bytes"); } for (let i = 0; i < resources.length; i++) { $("#bmi-scan-" + resources[i]) .find(".value") .html('(<div class="spinner-loader"></div>)'); $("#bmi-scan-" + resources[i]) .find(".value") .removeAttr("bytes"); } $("#esta-exclude").html('(<div class="spinner-loader"></div>)'); $("#esta-exclude-total").html('(<div class="spinner-loader"></div>)'); $("#esta-size-for").html('(<div class="spinner-loader"></div>)'); let preloader_divs = ""; for (let i = 0; i < 12; ++i) preloader_divs += "<div></div>"; $(".spinner-loader").html(preloader_divs).addClass("lds-spinner"); } async function scanDirectories() { totalSizesI = 0; totalSize = 0; totalExcluded = 0; let resources = [ "plugins", "uploads", "themes", "contents_others", "wordpress", "database", ]; await resetSpinners(resources, true); for (let i = 0; i < resources.length; i++) { await scanAndSet(resources[i]); } } function doSomethingWithTotal() { $("#bmi-scan-total") .find(".value") .text("(" + $.bmi.bytesToHuman(totalSize) + ")"); $("#bmi-scan-total").find(".value").attr("bytes", parseInt(totalSize)); updateEsta(); } // Live log $("#live-log-toggle").on("click", function () { if ($(".expanded-logs").length > 0) { $(this).text($(this).data("hide")); } else $(this).text($(this).data("show")); $("#live-log-wrapper").toggleClass("expanded-logs"); }); async function stopBackgroundProcess() { await forceBackupToStop(true); window.onbeforeunload = null; window.location.reload(); } // Stop backup $("#backup-stop").on("click", function () { if (isChecked("experimental-hard-timeout") === "true") { $.bmi.modal("freeze-loading-modal").open(); stopBackgroundBackup = true; return; } $.bmi .ajax("stop-backup", {}) .then(function (res) { if (res.status == "success") $.bmi.alert("success", $("#bmi-abort-soon").text(), 3000); else $.bmi._msg(res); }) .catch(function (error) { // }); }); // Is backup running function isRunning(mute = false, cb = function () { }) { $.bmi .ajax("is-running-backup", {}) .then(function (res) { if (typeof res.ongoing != "undefined") { $.bmi.fillOnGoing(res.ongoing); if (typeof res.ongoing.queue == 'object' || typeof res.ongoing.current_upload == 'object') { if (!(res.ongoing.queue instanceof Array) || !(res.ongoing.current_upload instanceof Array)) { if (typeof (globalBMIKeepAlive) == "function") { globalBMIKeepAlive(); } } else { $.bmi.ajax('check-not-uploaded-backups').then(function(res) { // console.warn('Checking for not uploaded backups...'); // console.log(res); }); } } } if (res.status == "success") cb(false); else { if (mute == true) cb(true); else { $.bmi.modal("freeze-loading-modal").close(); $.bmi._msg(res); } } }) .catch(function (error) { cb(false); $.bmi.modal("freeze-loading-modal").close(); // }); } function forceBackupToStop(withNotice = false) { return new Promise((resolve) => { $.bmi .ajax("force-backup-to-stop") .then(function (res) { if (withNotice) { $.bmi.alert("success", $("#bmi-force-stop-success").text(), 6000); } return resolve(true); }) .catch(function (error) { if (withNotice) { $.bmi.alert("error", $("#failed-to-stop").text(), 6000); } return resolve(false); }); }); } $("#bmi-force-backup-to-stop").on("click", function (e) { e.preventDefault(); $.bmi.alert("info", $("#bmi-force-stop-in-progress").text(), 3000); $.bmi .ajax("force-backup-to-stop") .then(function (res) { $.bmi.alert("success", $("#bmi-force-stop-success").text(), 6000); }) .catch(function (error) { $.bmi.alert("error", $("#failed-to-stop").text(), 6000); }); }); $("#bmi-force-restore-to-stop").on("click", function (e) { e.preventDefault(); $.bmi.alert("info", $("#bmi-force-stop-in-progress").text(), 3000); $.bmi .ajax("force-restore-to-stop") .then(function (res) { $.bmi.alert("success", $("#bmi-force-stop-success").text(), 6000); }) .catch(function (error) { $.bmi.alert("error", $("#failed-to-stop").text(), 6000); }); }); $("#bmi_restore_tbody").on("click", ".bc-unlocked-btn", function (e) { e.preventDefault(); let $el = e.target; let name = $el.closest("tr").querySelector(".br_name").innerText.trim(); $.bmi .ajax("lock-backup", { filename: name, }) .then(function (res) { if (res.status == "success") { $.bmi.alert("success", $("#bmi-lock-success").text(), 6000); $($el.closest("tr").querySelector(".bc-unlocked-btn")).hide(); $($el.closest("tr").querySelector(".bc-locked-btn")).show(); } else { $.bmi.alert("error", $("#bmi-lock-error").text(), 8000); console.error("BMI Backend error: ", res); } }) .catch(function (error) { // }); }); function updateEsta() { let pluginsSize = parseInt( $('label[for="files-group-plugins"]').find(".value").attr("bytes"), ); let uploadsSize = parseInt( $('label[for="files-group-uploads"]').find(".value").attr("bytes"), ); let themesSize = parseInt( $('label[for="files-group-themes"]').find(".value").attr("bytes"), ); let otherSize = parseInt( $('label[for="files-group-other-contents"]').find(".value").attr("bytes"), ); let wpSize = parseInt( $('label[for="files-group-wp-install"]').find(".value").attr("bytes"), ); let dbSize = parseInt( $('label[for="database-group-backup"]').find(".value").attr("bytes"), ); let pluginsExcluded = parseInt( $('label[for="files-group-plugins"]').find(".value").attr("excluded"), ); let uploadsExcluded = parseInt( $('label[for="files-group-uploads"]').find(".value").attr("excluded"), ); let themesExcluded = parseInt( $('label[for="files-group-themes"]').find(".value").attr("excluded"), ); let otherExcluded = parseInt( $('label[for="files-group-other-contents"]') .find(".value") .attr("excluded"), ); let wpExcluded = parseInt( $('label[for="files-group-wp-install"]').find(".value").attr("excluded"), ); let dbExcluded = parseInt( $('label[for="database-group-backup"]').find(".value").attr("excluded"), ); let databaseExcludedSizeInBytes = 0; let excludedSize = pluginsExcluded + uploadsExcluded + themesExcluded + otherExcluded + wpExcluded + dbExcluded; let totalSize = excludedSize + pluginsSize + uploadsSize + themesSize + otherSize + wpSize + dbSize; if ($("#files-group-backup").is(":checked")) { if (!$("#files-group-plugins").is(":checked")) excludedSize += pluginsSize; if (!$("#files-group-uploads").is(":checked")) excludedSize += uploadsSize; if (!$("#files-group-themes").is(":checked")) excludedSize += themesSize; if (!$("#files-group-other-contents").is(":checked")) excludedSize += otherSize; if (!$("#files-group-wp-install").is(":checked")) excludedSize += wpSize; } else { excludedSize += pluginsSize + uploadsSize + themesSize + otherSize + wpSize; } if ($("#database-group-backup").is(":checked")) { if ( $("#bmi_total_size_excluded").length > 0 && $("#bmi-pro-db-tables-exclusion").is(":checked") ) { databaseExcludedSizeInBytes = parseFloat($("#bmi_total_size_excluded").text().split("/")[0]) * 1024 * 1024; if (!isNaN(databaseExcludedSizeInBytes)) excludedSize += databaseExcludedSizeInBytes; } } else excludedSize += dbSize; $("#esta-exclude").text($.bmi.bytesToHuman(excludedSize)); $("#esta-exclude-total").text($.bmi.bytesToHuman(totalSize)); $("#esta-size-for").text($.bmi.bytesToHuman(totalSize - excludedSize)); } $("#files-group-backup").on("change", updateEsta); $("#database-group-backup").on("change", updateEsta); $(".basic-file-exlusion").on("change", 'input[type="checkbox"]', updateEsta); $("#bmi_restore_tbody").on("click", ".bc-locked-btn", function (e) { e.preventDefault(); if ($(e.target).hasClass("forever")) return; let $el = e.target; let name = $el.closest("tr").querySelector(".br_name").innerText.trim(); $.bmi .ajax("unlock-backup", { filename: name, }) .then(function (res) { if (res.status == "success") { $.bmi.alert("success", $("#bmi-unlock-success").text(), 3000); $($el.closest("tr").querySelector(".bc-locked-btn")).hide(); $($el.closest("tr").querySelector(".bc-unlocked-btn")).show(); } else { $.bmi.alert("error", $("#bmi-unlock-error").text(), 3000); console.error("BMI Backend error: ", res); } }) .catch(function (error) { // }); }); $("#bmi_restore_tbody").on("click", ".bc-url-btn", function (e) { e.preventDefault(); let $el = e.target; if ($el.closest("svg").classList.contains("disabled")) return; let url = $el .closest("tr") .querySelector(".bc-download-btn") .getAttribute("href"); $.bmi.clipboard(url, bmiVariables.urlCopies); }); $("#stg-tbody-table").on("click", ".bc-stg-url-btn", function (e) { let $el = e.target; let url = $el .closest("tr") .querySelector(".stg-tr-url-el") .getAttribute("href"); $.bmi.clipboard(url, bmiVariables.urlCopies); }); $("#bmi_restore_tbody").on("click", ".bc-remove-btn", function (e) { let $el = e.target; let name = $el.closest('tr').querySelector('.br_name').innerText.trim(); let isCloud = Array.from($el.closest('tr').querySelectorAll('[class*="strg-"]')).filter(el => !el.classList.contains('strg-local')).some(el => el.classList.contains('img-green')); let notOnLocalTr = $($el.closest('tr')).data('is-local') == 'no' ? true : false; latest_delete = [name]; latest_delete_cloud = {}; latest_delete_cloud[name] = { md5: $el.closest("tr").getAttribute("md5"), gid: $el.closest("tr").getAttribute("gdrive-id"), }; $("#delete-confirm-modal").find(".text2").hide(); $("#delete-confirm-modal").find(".text3").hide(); $("#delete-confirm-modal").find(".text4").hide(); $("#delete-confirm-modal").find(".text1").show(); if (isCloud) $(".bmi-cloud-removal").show(); else $(".bmi-cloud-removal").hide(); $("#remove-cloud-backup-as-well")[0].checked = false; if (isCloud && notOnLocalTr) { $("#remove-cloud-backup-as-well")[0].checked = true; $(".bmi-cloud-removal").hide(); $("#delete-confirm-modal").find(".text1").hide(); $("#delete-confirm-modal").find(".text2").hide(); $("#delete-confirm-modal").find(".text3").hide(); $("#delete-confirm-modal").find(".text4").show(); $(".del-more-than-one").hide(); $(".del-only-one").show(); } $.bmi.modal("delete-confirm-modal").open(); }); $("#sure_delete").on("click", function (e) { e.preventDefault(); $.bmi.modal("delete-confirm-modal").close(); $.bmi.modal("freeze-loading-modal").open(); $.bmi .ajax("delete-backup", { filenames: latest_delete, deleteCloud: $("#remove-cloud-backup-as-well")[0].checked ? "yes" : "no", cloudDetails: latest_delete_cloud, }) .then(function (res) { latest_delete = null; latest_delete_cloud = null; $("#remove-cloud-backup-as-well")[0].checked = false; $.bmi.modal("freeze-loading-modal").close(); if (res.status == "success") { $.bmi.reloadBackups(() => { $.bmi.reloadBackups(); // twice on purpose }); $.bmi.alert("success", $("#bmi-remove-success").text(), 3000); } else { $.bmi.alert("warning", $("#bmi-remove-error").text(), 3000); console.error("BMI Backend error: ", res); } }) .catch(function (error) { $.bmi.modal("freeze-loading-modal").close(); }); }); $(".bmi-send-troubleshooting-logs").on("click", function (e) { e.preventDefault(); $.bmi.alert("info", $("#bmi-support-send-start").text(), 6000); $(".bmi-send-troubleshooting-logs").addClass("disabled"); let errorVisible = false; let stagingErrorVisible = false; if ($("#error-modal").is(":visible")) { $.bmi.modal("error-modal").close(); errorVisible = true; stagingErrorVisible = false; } if ($("#staging-error-modal").is(":visible")) { $.bmi.modal("staging-error-modal").close(); errorVisible = false; stagingErrorVisible = true; } $.bmi.modal("freeze-loading-modal").open(); let logsSource = $("#after-logs-sent-modal").attr("data-error-source"); $.bmi .ajax("send-troubleshooting-logs", { source: logsSource }) .then(function (res) { $.bmi.modal("freeze-loading-modal").close(); if (res.status == "success") { $("#bmi-support-code-generated").text(res.code); setTimeout(function () { $.bmi.alert("success", $("#bmi-support-send-success").text(), 4000); $.bmi.modal("after-logs-sent-modal").open(); }, 300); } else { $.bmi.alert("error", $("#bmi-support-send-fail").text(), 6000); if (errorVisible) $.bmi.modal("error-modal").open(); if (stagingErrorVisible) $.bmi.modal("staging-error-modal").open(); } $(".bmi-send-troubleshooting-logs").removeClass("disabled"); }) .catch(function (error) { $.bmi.modal("freeze-loading-modal").close(); $.bmi.alert("success", $("#bmi-support-send-fail").text(), 6000); alert( "Something went wrong on your browser side and we could not send your logs to support team.", ); $(".bmi-send-troubleshooting-logs").removeClass("disabled"); if (errorVisible) $.bmi.modal("error-modal").open(); if (stagingErrorVisible) $.bmi.modal("staging-error-modal").open(); }); }); $("#share-logs-allowed").on("click", function (e) { e.preventDefault(); let newModalName = $("#logs-sharing-ask-modal").attr("data-destination"); $.bmi.alert("success", $("#bmi-share-logs-thank-you").text(), 3000); $.bmi.modal("logs-sharing-ask-modal").close(); $.bmi.modal("freeze-loading-modal").open(); shareLogsStatus("set_yes", function () { setTimeout(function () { handleAfterDesicionMadeSharing(newModalName); }, 300); }); }); $("#share-logs-not-allowed").on("click", function (e) { e.preventDefault(); let newModalName = $("#logs-sharing-ask-modal").attr("data-destination"); $.bmi.modal("logs-sharing-ask-modal").close(); $.bmi.modal("freeze-loading-modal").open(); shareLogsStatus("set_no", function () { setTimeout(function () { handleAfterDesicionMadeSharing(newModalName); }, 300); }); }); $("#ignore-share-log-request-for-now").on("click", function (e) { e.preventDefault(); $.bmi.modal("logs-sharing-ask-modal").close(); let newModalName = $("#logs-sharing-ask-modal").attr("data-destination"); handleAfterDesicionMadeSharing(newModalName); }); function handleAfterDesicionMadeSharing(modalName) { if (modalName == "backup-prenotice") { runPrenoticeBeforeBackup(); } else { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { $.bmi.modal(modalName).open(); }, 300); } } function isAllowedToShareLogs(cb = function () { }) { shareLogsStatus("is_allowed", function (res) { cb(res); }); } function shareLogsStatus(type, cb = function () { }) { // Res to: is_allowed (res.result) // allowed // not-allowed // ask // // For set_yes, set_no there is no response only status success or fail if (type == "is_allowed") cb("not-allowed"); else cb(); // DISABLED: // $.bmi.ajax('log-sharing-details', { question: type }).then(function(res) { // // if (res.status == 'success') { // // if (type == 'is_allowed') { // // if (typeof res.result != 'undefined') { // if (['allowed', 'not-allowed', 'ask'].includes(res.result)) { // cb(res.result); // } else { // cb('not-allowed') // } // } // // } else { // // cb(); // // } // // } else { // // cb('error'); // // } // // }).catch(function(error) { // // alert('Something went wrong on browser side and we could not send your decision, for now we will assume that you have not agreed, more details in developer console.'); // cb('error'); // // }); } $("#add-exclusion-rule").on("click", function (e) { e.preventDefault(); let $template = $(".exclusion_template").clone(); $template[0].classList.remove("exclusion_template"); $template[0].style.display = "none"; $("#bmi_exclusion_rules").append($template); $template.show(300); }); $("#bmi_exclusion_rules").on("click", ".kill-exclusion-rule", function (e) { e.preventDefault(); $el = e.target; $parent = $el.closest(".exclude-row"); if ($parent) { $($parent).hide(300); setTimeout(function () { $parent.remove(); }, 320); } }); function isOnlyDB() { if (!(isChecked("database-group-backup") === "true")) { return false; } else { if (isChecked("database-group-backup") === "true") { if (!(isChecked("files-group-backup") === "true")) { return true; } else { if ( isChecked("files-group-plugins") === "true" || isChecked("files-group-themes") === "true" || isChecked("files-group-uploads") === "true" || isChecked("files-group-wp-install") === "true" || isChecked("files-group-other-contents") === "true" ) { return false; } } } else return false; } } function isOnlyFiles() { if (isChecked("database-group-backup") === "true") { return false; } else { if (!(isChecked("database-group-backup") === "true")) { if ( isChecked("files-group-backup") === "true" && (isChecked("files-group-plugins") === "true" || isChecked("files-group-themes") === "true" || isChecked("files-group-uploads") === "true" || isChecked("files-group-wp-install") === "true" || isChecked("files-group-other-contents") === "true") ) { return true; } else return false; } else return false; } } function isOnlyPart() { if ( isChecked("database-group-backup") === "true" && isChecked("files-group-backup") === "true" && isChecked("files-group-plugins") === "true" && isChecked("files-group-themes") === "true" && isChecked("files-group-uploads") === "true" && isChecked("files-group-other-contents") === "true" ) { return false; } return true; } function isFilesOrDb() { if (isChecked("database-group-backup") === "true") { return true; } else { if (isChecked("files-group-backup") === "true") { if ( isChecked("files-group-plugins") === "true" || isChecked("files-group-themes") === "true" || isChecked("files-group-uploads") === "true" || isChecked("files-group-wp-install") === "true" || isChecked("files-group-other-contents") === "true" ) { return true; } } } return false; } function setupPrenotice() { $("#prenotice-modal .prenotice").hide(); $("#prenotice-size").text($("#esta-size-for").text()); $(".prenotic-3").show(); if (isOnlyDB()) { $(".prenotic-6").show(); } if (isOnlyFiles()) { $(".prenotic-5").show(); } if (isOnlyPart()) { $(".prenotic-4").show(); } $("#prenotice-modal .prenotice:visible").css({ background: "", }); let prenotices = $("#prenotice-modal .prenotice"), sorted = []; for (let i = 0; i < prenotices.length; ++i) { if (!(prenotices[i].style.display === "none")) { sorted.push(prenotices[i]); } } for (let i = 0; i < sorted.length; i += 2) { sorted[i].style.background = "#f8f8f8"; } } // Backup creation $("#i-backup-creator, .i-backup-creator-trigger").on("click", function () { if (isNaN(getSelectedSize())) { $.bmi.alert("warning", $("#bmi-preb-processing").text(), 3000); return; } if ( getSelectedSize() / 1024 / 1024 > parseInt($("#BMI_REV").text().trim()) * 1000 ) { return handleBfs(); } if (!isFilesOrDb()) { $.bmi.alert("warning", $("#bmi-no-selected").text(), 3000); return; } $.bmi.modal("freeze-loading-modal").open(); setTimeout(function () { shareLogsStatus("is_allowed", function (res) { if (res === "ask") { $.bmi.modal("freeze-loading-modal").close(); $("#logs-sharing-ask-modal").attr( "data-destination", "backup-prenotice", ); setTimeout(function () { $.bmi.modal("logs-sharing-ask-modal").open(); }, 300); } else { runPrenoticeBeforeBackup(); } }); }, 300); }); function runPrenoticeBeforeBackup() { $.bmi.modal("freeze-loading-modal").open(); setupPrenotice(); isRunning(false, function () { setTimeout(function () { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { $.bmi.modal("prenotice-modal").open(); }, 300); }, 300); }); } $("#BFFSIN").on("change", function (e) { let i = parseInt(this.value); if (isNaN(i)) { this.value = 1; return; } else { if (i > 9999) { this.value = 9999; return; } if (i <= 0) { this.value = 1; return; } this.value = i; } }); function saveBtnEventHandler(e = false, type = false, cb = () => { }) { if (e) e.preventDefault(); let data = {}; let save = type; if (e != false && type == false) save = $(this.closest(".save-action")).data("save"); if (!save) return; if (save == "save-storage") { data["directory"] = $("#bmi_path_storage_default").val(); data["access"] = $('[name="radioAccessViaLink"]:checked').val() === "true" ? "true" : "false"; data["gdrive"] = $("#bmi-pro-storage-gdrive-toggle").is(":checked") === true ? "true" : "false"; if ($("#bmip-googledrive-path").length > 0) { data["gdrivedirname"] = $("#bmip-googledrive-path").val().trim(); } else { data["gdrivedirname"] = "BACKUP_MIGRATION_BACKUPS"; } // onedrive data["onedrive"] = $("#bmi-pro-storage-onedrive-toggle").is(":checked") === true ? "true" : "false"; data["sftp"] = $("#bmi-pro-storage-sftp-toggle").is(":checked") === true ? 'true' : 'false'; // storage ftp data['ftp'] = $('#bmi-pro-storage-ftp-toggle').is(':checked') === true ? 'true' : 'false'; if ($('#bmip-ftp-host-ip').length > 0) { data['ftphostip'] = $('#bmip-ftp-host-ip').val().trim(); } else { data['ftphostip'] = ''; } data['dropbox'] = $('#bmi-pro-storage-dropbox-toggle').is(':checked') === true ? 'true' : 'false'; data['pcloud'] = $('#bmi-pro-storage-pcloud-toggle').is(':checked') === true ? 'true' : 'false'; if ($('#bmip-ftp-user-name').length > 0) { data['ftphostusername'] = $('#bmip-ftp-user-name').val().trim(); } else { data['ftphostusername'] = ''; } if ($('#bmip-ftp-password').length > 0) { data['ftppassword'] = $('#bmip-ftp-password').val().trim(); } else { data['ftppassword'] = ''; } if ($('#bmip-ftp-backup-dir').length > 0) { data['ftpdir'] = $('#bmip-ftp-backup-dir').val().trim(); } else { data['ftpdir'] = ''; } if ($('#bmip-ftp-host-port').length > 0) { data['ftpport'] = $('#bmip-ftp-host-port').val().trim(); } else { data['ftpport'] = ''; } data['aws'] = $('#bmi-pro-storage-aws-toggle').is(':checked') === true ? 'true' : 'false'; data['wasabi'] = $('#bmi-pro-storage-wasabi-toggle').is(':checked') === true ? 'true' : 'false'; } else if (save == 'save-file-config') { // Main groups data["database_group"] = isChecked("database-group-backup"); data["files_group"] = isChecked("files-group-backup"); // Additional database exclusion rules if ($("#bmi-pro-db-tables-exclusion").length > 0) { data["db-exclude-tables-group"] = isChecked( "bmi-pro-db-tables-exclusion", ); data["db-excluded-tables"] = ["empty"]; let excludedTables = $(".bmi_pro_tables_display").find("input:checked"); if (excludedTables.length > 0) { data["db-excluded-tables"] = []; for (let i = 0; i < excludedTables.length; ++i) { data["db-excluded-tables"].push(excludedTables[i].value); } } else { data["db-exclude-tables-group"] = "false"; } } else { data["db-exclude-tables-group"] = "false"; data["db-excluded-tables"] = ["empty"]; } // Subgroup of files data["files-group-plugins"] = isChecked("files-group-plugins"); data["files-group-uploads"] = isChecked("files-group-uploads"); data["files-group-themes"] = isChecked("files-group-themes"); data["files-group-other-contents"] = isChecked( "files-group-other-contents", ); data["files-group-wp-install"] = isChecked("files-group-wp-install"); // Subgroup of filters of files data["files_by_filters"] = isChecked("files_by_filters"); data["ex_b_fs"] = isChecked("ex_b_fs"); data["BFFSIN"] = $("#BFFSIN").val() ? $("#BFFSIN").val() : "1"; data["ex_b_names"] = isChecked("ex_b_names"); data["ex_b_fpaths"] = isChecked("ex_b_fpaths"); data["ex_b_dpaths"] = isChecked("ex_b_dpaths"); // Make dynamic let rules = []; let rows = $("#bmi_exclusion_rules").find(".exclude-row"); for (let i = 0; i < rows.length; ++i) { let row = $(rows[i]); let txt = row.find(".exclusion_txt").val(); let pos = row .find(".exclusion_position") .find(".bmi-dropdown") .data("selected") + ""; let whr = row.find(".exclusion_where").find(".bmi-dropdown").data("selected") + ""; rules.push({ txt: txt, pos: pos, whr: whr, }); } // Continue data data["dynamic-names"] = rules; data["dynamic-fpaths-names"] = $("#dynamic-fpaths-names") .val() .split("\n"); data["dynamic-dpaths-names"] = $("#dynamic-dpaths-names") .val() .split("\n"); data["smart-exclusion-enabled"] = isChecked("smart-exclusion-enabled"); // SMART:EXCLUSION:ENABLED data["smart-exclusion-cache"] = isChecked("smart-exclusion-cache"); // SMART:EXCLUSION:CACHE data["smart-exclusion-deactivated-plugins"] = isChecked("smart-exclusion-deactivated-plugins"); // SMART:EXCLUSION:DPLUGINS data["smart-exclusion-debug-logs"] = isChecked("smart-exclusion-debug-logs"); // SMART:EXCLUSION:DLOGS data["smart-exclusion-non-used-themes"] = isChecked("smart-exclusion-non-used-themes"); // SMART:EXCLUSION:NUTHEMES data["smart-exclusion-post-revisions"] = isChecked("smart-exclusion-post-revisions"); // SMART:EXCLUSION:PREVISIONS } else if (save == "store-config") { data["name"] = $("#backup_filename").val().trim(); if ($("input[name=backup_type_extension]")) { data["extension"] = $( "input[name=backup_type_extension]:checked", ).val(); } else { data["extension"] = ".zip"; } } else if (save == "save-other-options") { data["email"] = $("#email-for-notices").val().trim(); data["email_title"] = $("#email-title-for-notices").val().trim(); data["schedule_issues"] = isChecked("scheduled-issues"); data["experiment_timeout"] = isChecked("experimental-timeout"); data["experimental_hard_timeout"] = isChecked( "experimental-hard-timeout", ); data["php_cli_disable_others"] = isChecked("cli-disable-others"); data["php_cli_manual_path"] = $("#cli-manual-path").val().trim(); data["download_technique"] = isChecked("download-technique"); data["uninstall_config"] = isChecked("uninstalling-configs"); data["uninstall_backups"] = isChecked("uninstalling-backups"); data["normal_timeout"] = isChecked("normal-timeout"); data["backup_success_notify"] = isChecked("backup-success-notify"); data["restore_success_notify"] = isChecked("restore-success-notify"); data["backup_failed_notify"] = isChecked("backup-failed-notify"); data["restore_failed_notify"] = isChecked("restore-failed-notify"); data["generate_debug_code"] = isChecked("generate-debug-code-yes") == "true" && isChecked("generate-debug-code-no") !== "true"; data["add_logs_email"] = isChecked("add-logs-email-yes") == "true" && isChecked("add-logs-email-no") !== "true"; data["db_queries_amount"] = $("#db_queries_amount").val().trim(); // OTHER:DB:QUERIES data["db_search_replace_max"] = $("#db_search_replace_max").val().trim(); // OTHER:DB:SEARCHREPLACE:MAX data["file_limit_extraction_max"] = $("#file_limit_extraction_max") .val() .trim(); // OTHER:FILE:EXTRACT:MAX data["bmi-restore-splitting"] = isChecked("bmi-restore-splitting"); // OTHER:RESTORE:SPLITTING data["bmi-db-v3-restore-engine"] = isChecked("bmi-db-v3-restore-engine"); // OTHER:RESTORE:SPLITTING data["remove-assets-before-restore"] = isChecked( "remove-assets-before-restore", ); // OTHER:RESTORE:BEFORE:CLEANUP data["hide-promotional-bmi-banners"] = isChecked( "hide-promotional-bmi-banners", ); // OTHER:PROMOTIONAL:DISPLAY data["bmi-db-single-file-backup"] = isChecked( "bmi-db-single-file-backup", ); // OTHER:BACKUP:DB:SINGLE:FILE data["bmi-db-batching-backup"] = isChecked("bmi-db-batching-backup"); // OTHER:BACKUP:DB:BATCHING data["bmi-disable-space-check-function"] = isChecked( "bmi-do-not-check-free-space-backup", ); // OTHER:BACKUP:SPACE:CHECKING data["before_update_trigger"] = ((!$('#before-updates-switch')[0].checked === true) ? true : false) // OTHER:TRIGGER:BEFORE:UPDATES data["use_new_search_replace_engine"] = isChecked("bmi-use-new-search-replace-engine"); // OTHER::NEW_SEARCH_REPLACE_ENGINE data["use_new_database_export_engine"] = isChecked("bmi-use-new-database-export-engine"); // OTHER::NEW_DATABASE_EXPORT_ENGINE } else return; $.bmi .ajax(save, data) .then(function (res) { if (res.status == "success") { if (res.errors <= 0) { if ($('.save-brw-details').length > 0) $('.save-brw-details').triggerHandler('click'); if (e) $.bmi.alert("success", $("#bmi-save-success").text(), 3000); $.bmi.reloadBackups(); $.bmi.adjustStorageIcons(); if ( typeof window.saveStorageWithoutClose != "undefined" && window.saveStorageWithoutClose === true ) { window.saveStorageWithoutClose = false; } else { if (e) $.bmi.collapsers.closeAll(); } } else { if (e) $.bmi.alert("warning", $("#bmi-save-issues").text(), 3000); } } else { $.bmi._msg(res); } }) .catch(function (error) { // }) .finally(() => { if (save == "save-file-config") { scanDirectories(); } cb(); }); } $(".save-btn").on("click", saveBtnEventHandler); $(".close-chapters").on("click", function (e) { e.preventDefault(); $.bmi.collapsers.closeAll(); }); $("#rescan-for-backups").on("click", function (e) { e.preventDefault(); $.bmi.reloadBackups(); }); // Storage things $(".storage-checkbox").on("click", function () { let target = $(this).attr("data-toggle"); let tab = $($(this)[0].closest(".tab2-item")); if ($(this).is(":checked")) { $("#" + target).show(300); tab.addClass("activeList"); } else { $("#" + target).hide(300); tab.removeClass("activeList"); } }); function httpGet(theUrl, callback = function () { }) { let isHttps = window.location.protocol.includes("https"); let isUrlHttps = theUrl.includes("https"); if (isUrlHttps) theUrl = theUrl.slice(5); else theUrl = theUrl.slice(4); if (isHttps) theUrl = "https" + theUrl; else theUrl = "http" + theUrl; try { if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onloadend = function () { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { callback(xmlhttp.responseText); } else callback(false); }; xmlhttp.open("GET", theUrl); xmlhttp.send(); } catch (e) { callback(false); } } function goThroughEndCodes() { let stepSet = false; let endCodeFound = false; for (let i = 0; i < latestLines.length; ++i) { let line = latestLines[i]; if ( endCodeFound == false && line && line.trim().includes("[END-CODE]") && (backgroundBackup === true || restoreCLI === true || cli_quickmigration === true) ) { endCodeFound = true; let code_line = line; if (cli_quickmigration === true) { if (code_line.includes("205")) { cli_quickmigration = false; $("#restore-progress-modal .progress-active-bar")[0].style.width = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; letsRestore(true); } else if (code_line.includes("206")){ $.bmi.modal("restore-progress-modal").close(); $('#restore-progress-modal .title').text($('#bmi-restore-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-restore-progress-modal-warning').text()); setTimeout(function () { if (!downloadBackupFinished) { // Avoid double success message $.bmi.alert('success', $('#bmi-backup-downloaded').text(), 3000); downloadBackupFinished = true; } }, 300); } else { restoreFailed(); } } else if (restoreCLI === true) { if (code_line.includes("001")) { setTimeout(function () { restoreCLISuccess(); }, 1000); } else { restoreFailed(); } restoreOnGoing = false; restoreCLI = false; } else { backgroundBackup = false; if (code_line.includes("001")) { bacupisDone = true; progressIsDone = true; clearTimeout(timeouter); backupOnGoing = false; completedBackup({ filename: backgroundName }, true); } else if (code_line.includes("002")) { // $.bmi.modal('backup-progress-modal').close(); backupError(1); } else if (code_line.includes("003")) { $.bmi.modal("backup-progress-modal").close(); $.bmi.alert("info", $("#bmi-aborted-al").text(), 3000); } else if (code_line.includes("100")) { $.bmi.modal("backup-progress-modal").close(); handleBfs(); $.bmi.modal("backup-progress-modal").close(); } else { backupError(2); } } } } return endCodeFound; } function showNextLine(el) { let delayedDisplayTime = 40; let line = latestLines[curdivs]; let div = document.createElement("DIV"); let color = ""; if (typeof line == "undefined" || !line) return; if (line.substr(0, 6) == "[INFO]") color = "blue"; else if (line.substr(0, 9) == "[SUCCESS]") color = "green"; else if (line.substr(0, 6) == "[WARN]") color = "orange"; else if (line.substr(0, 7) == "[ERROR]") color = "red"; else if (line.substr(0, 10) == "[END-CODE]") color = "hide_so_much"; else if (line.substr(0, 9) == "[VERBOSE]") color = "hide_verbose"; else if (line.substr(0, 6) == "[STEP]") { div.classList.add("bold"); div.classList.add("step"); } else { if (line && line.trim().length > 0 && line[0] != "[") { curdivs--; } } let mostRecentStep = ""; if (line.substr(0, 6) == "[STEP]") mostRecentStep = line.slice(29); if (color.length > 0) div.classList.add(color); div.style.display = "none"; div.innerText = line; el.appendChild(div); let endCodeFound = goThroughEndCodes(); $(div).show(delayedDisplayTime, function () { if (mostRecentStep != "" && mostRecentStep != latestStep) { latestStep = mostRecentStep; if ($("#restore-progress-modal").hasClass("open")) { $("#restore_current_step").text(mostRecentStep); } else { $("#current_step").text(mostRecentStep); } } }); el.scrollTop = el.scrollHeight; curdivs++; if (curdivs < latestLines.length && endCodeFound == false) { isLineAppendTimeoutRunning = true; lineTimeoutAppend = setTimeout(function () { showNextLine(el); }, delayedDisplayTime); } else { isLineAppendTimeoutRunning = false; } } function showAllLines(el, latestLines) { for (let i = 0; i < latestLines.length; i++) { let line = latestLines[i]; let div = document.createElement("DIV"); let color = ""; if (typeof line == "undefined" || !line) continue; if (line.substr(0, 6) == "[INFO]") color = "blue"; else if (line.substr(0, 9) == "[SUCCESS]") color = "green"; else if (line.substr(0, 6) == "[WARN]") color = "orange"; else if (line.substr(0, 7) == "[ERROR]") color = "red"; else if (line.substr(0, 10) == "[END-CODE]") color = "red"; else if (line.substr(0, 9) == "[VERBOSE]") color = "gray"; else if (line.substr(0, 6) == "[STEP]") { div.classList.add("bold"); div.classList.add("step"); } else { if (line && line.trim().length > 0 && line[0] != "[") { i--; } } let mostRecentStep = ""; if (line.substr(0, 6) == "[STEP]") mostRecentStep = line.slice(29); if (color.length > 0) div.classList.add(color); div.style.display = "none"; div.innerText = line; el.appendChild(div); $(div).show(); } } function insertPre(log, el) { if (log === false) return; let lines = log.split("\n"); if (lines.length >= 1) lines = lines.slice(0, -1); latestLines = lines; if (isLineAppendTimeoutRunning == false) { if (curdivs < latestLines.length) { showNextLine(el); } } } function setProgress(end = 0, duration = 1000, res = null) { if (current_last == end) return; else current_last = end; clearInterval(iprogres); let start = parseFloat($(".progress-percentage")[0].style.left) - 1; if ($("#restore-progress-modal").hasClass("open")) { start = parseFloat( $("#restore-progress-modal .progress-percentage")[0].style.left, ) - 1; } // if (start > end && end != 0) return; let range = end - start; let current = start; let increment = 1; let stepTime = Math.abs(Math.floor(duration / range)); iprogres = setInterval(function () { current += increment; if ($("#restore-progress-modal").hasClass("open")) { $("#restore-progress-modal .progress-active-bar")[0].style.width = current.toFixed(2) + "%"; $("#restore-progress-modal .progress-percentage")[0].style.left = current.toFixed(2) + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = current.toFixed(0) + "%"; } else { $(".progress-active-bar")[0].style.width = current.toFixed(2) + "%"; $(".progress-percentage")[0].style.left = current.toFixed(2) + "%"; $(".progress-percentage")[0].innerText = current.toFixed(0) + "%"; } if (current >= 100) { clearInterval(iprogres); } if (current >= 100 && res != null) { current_last = null; if ($("#backup-progress-modal").hasClass("open")) { bacupisDone = true; progressIsDone = true; let force = backupOnGoing == false ? true : false; completedBackup(res, force); } } if (current > end) clearInterval(iprogres); }, stepTime); } var curmaxnum = 0; async function animateValue(obj, start, end, duration) { let startTimestamp = null; let step = function (timestamp) { if (curmaxnum > end) return; if (!startTimestamp) startTimestamp = timestamp; let progress = Math.min((timestamp - startTimestamp) / duration, 1); obj.innerText = Math.floor(progress * (end - start) + start); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } function refreshContentInstant(cb = function () { }) { let url = $("#BMI_BLOG_URL").text().trim(); if (url.slice(-url.length) !== "/") url = url + "/"; httpGet( url + "?backup-migration=PROGRESS_LOGS&progress-id=latest_full.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(), function (res2) { if (!res2) return cb(); let res1 = res2.split("\n").slice(0, 1)[0]; if (res1.trim() === "") { res1 = res2.split("\n").slice(0, 2)[1]; res2 = res2.split("\n").slice(2).join("\n"); } else { res2 = res2.split("\n").slice(1).join("\n"); } let pre = $(".log-wrapper").find("pre")[0]; let making = $("#bmi-making-archive").text().trim(); if (res1 && res1 != false && typeof res1 !== "undefined") { if ( $("#current_step").text().trim().slice(0, making.length) == making ) { let obj = document.getElementById("bmi_counter_magic"); if (obj) { let currnum = parseInt(obj.innerText); curmaxnum = parseInt(res1.split("/")[0]); if (!isNaN(currnum) && !isNaN(curmaxnum)) { setProgress( (parseInt(res1.split("/")[0]) / parseInt(res1.split("/")[1])) * 100, ); animateValue(obj, currnum, curmaxnum, 2000); if ( $("#bmi_magic_max_count").text() === "---" && parseInt(res1.split("/")[1]) != 100 ) { $("#bmi_magic_max_count").text(parseInt(res1.split("/")[1])); if ($("#entire_magic_counter").is(":hidden")) $("#entire_magic_counter").show(); } } } else { let numv = parseInt(res1.split("/")[1]); if (numv == 100) numv = "---"; $("#current_step").html( making + ' <span id="entire_magic_counter">(<span id="bmi_counter_magic">0</span>/<span id="bmi_magic_max_count">' + numv + "</span>)</span>", ); if (isNaN(parseInt(numv)) || numv == "---") $("#entire_magic_counter").hide(); } } else { setProgress( (parseInt(res1.split("/")[0]) / parseInt(res1.split("/")[1])) * 100, ); } } if (res2 && res2 != false && typeof res2 !== "undefined") insertPre(res2, pre); cb(); }, ); } function refreshLogAndProgress(preserveLogs = false) { if (preserveLogs == false) { $(".log-wrapper").find("pre")[0].innerText = ""; } setProgress(0); function update() { refreshContentInstant(function () { clearTimeout(timeouter); timeouter = setTimeout(function () { if (backupOnGoing === true) update(); }, 1500); }); } setTimeout(function () { refreshContentInstant(function () { update(); }); }, 300); } bmi.refreshLogAndProgress = refreshLogAndProgress; function refreshLogAndProgressRestore(resetLogs = true) { if (resetLogs === true) { $(".log-wrapper").find("pre")[0].innerText = ""; setProgress(0); } function update() { getMigrationLogs(function () { timeouter = setTimeout(function () { if (restoreOnGoing === true || cli_quickmigration === true) update(); }, 800); }); } getMigrationLogs(function () { clearTimeout(timeouter); update(); }); } function isBackupOngoing(done = function () { }) { isRunning(true, function (res) { done(res); }); } function resetLogsPromise(migration = false) { return new Promise((resolve) => { resetLogs(migration, () => { return resolve(); }); }); } bmi.resetLogsPromise = resetLogsPromise; function resetLogs(migration = false, done = function () {}) { $.bmi .ajax("reset-latest", {}) .then(function (res) { if (migration === true) { done(); } else { if (res.status == "success") { done(); setTimeout(function () { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { // Make sure the progress modal is open $.bmi.modal("backup-progress-modal").open(); }, 300); }, 300); } else { $.bmi._msg(res); } } }) .catch(function (error) { // }); } function completedBackup(res, forced = false) { if (!(bacupisDone && progressIsDone) && !forced) return; $.bmi.releaseWakeLock(); setTimeout(function () { backupOnGoing = false; clearInterval(iprogres); clearTimeout(timeouter); let url_x = $("#BMI_BLOG_URL").text().trim(); if (url_x.slice(-url_x.length) !== "/") url_x = url_x + "/"; $.bmi .ajax("get-latest-backup", {}) .then(function (res_latest) { let url = url_x + "?backup-migration=BMI_BACKUP&bmi-id=" + res_latest + "&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); let logs = url_x + "?backup-migration=PROGRESS_LOGS&progress-id=latest.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); $("#text-input-copy")[0].value = url; $("#download-backup-url").attr("href", url); $(".download-backup-log-url").attr("href", logs); $.bmi.reloadBackups(); setTimeout(function () { clearInterval(iprogres); $(".log-wrapper").find("pre")[0].innerText = ""; $(".progress-active-bar")[0].style.width = "0%"; $(".progress-percentage")[0].style.left = "0%"; $(".progress-percentage")[0].innerText = "0%"; }, 300); if ($("#backup-progress-modal").hasClass("open")) { $.bmi.modal("backup-progress-modal").close(); if ($('[name="radioAccessViaLink"]:checked').val() == "true") { $("#accessible-at-section").show(); } else $("#accessible-at-section").hide(); $.bmi.modal("backup-success-modal").open(); } }) .catch(function (error) { if ($("#backup-progress-modal").hasClass("open")) { $.bmi.modal("backup-progress-modal").close(); if ($('[name="radioAccessViaLink"]:checked').val() == "true") { $("#accessible-at-section").show(); } else $("#accessible-at-section").hide(); $.bmi.modal("backup-success-modal").open(); } let url = url_x + "?backup-migration=BMI_BACKUP&bmi-id=" + res.filename + "&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); let logs = url_x + "?backup-migration=PROGRESS_LOGS&progress-id=latest.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); $("#text-input-copy")[0].value = url; $("#download-backup-url").attr("href", url); $(".download-backup-log-url").attr("href", logs); $.bmi.reloadBackups(); setTimeout(function () { clearInterval(iprogres); $(".log-wrapper").find("pre")[0].innerText = ""; $(".progress-active-bar")[0].style.width = "0%"; $(".progress-percentage")[0].style.left = "0%"; $(".progress-percentage")[0].innerText = "0%"; }, 300); }); }, 700); } function sleepFunction(seconds = 1) { return new Promise(async (resolve) => { setTimeout(() => { return resolve(); }, 1000 * seconds); }); } function saveOtherOptionsPromise() { return new Promise(async (resolve) => { saveBtnEventHandler(false, "save-other-options", resolve); }); } function tryToSaveBackupProcess(errorDetails = false) { return new Promise(async (resolve) => { let details = errorDetails; if (details === false) return resolve(false); if (typeof details != "object") return resolve(false); if (typeof details[0] == "undefined") return resolve(false); if (typeof details[0]["status"] == "undefined") return resolve(false); if (typeof details[0]["statusText"] == "undefined") return resolve(false); if (typeof details[0]["responseText"] == "undefined") return resolve(false); let status = details[0]["status"]; let statusText = details[0]["statusText"]; let responseText = details[0]["responseText"]; let isCLIDisabled = isChecked("cli-disable-others"); let isDefaultBackup = isChecked("normal-timeout"); let isCURLBackup = isChecked("experimental-timeout"); let isBrowserBackup = isChecked("experimental-hard-timeout"); if (isBrowserBackup == true && isCLIDisabled == true) return resolve(false); // 1. Force stop backup process await forceBackupToStop(); // 2. Adjust Other Options $("#cli-disable-others").prop("checked", true); $("#experimental-hard-timeout").prop("checked", true).change(); // 3. Save Other options await saveOtherOptionsPromise(); await sleepFunction(3); // 4. Run backup process from point zero without reseting logs setTimeout(() => { startBackupProcessNow(null, true); }); // Resolve as true return resolve(true); }); } async function backupError(type = -1, errorDetails = false) { clearInterval(iprogres); clearTimeout(timeouter); $(".progress-active-bar")[0].style.width = "0%"; $(".progress-percentage")[0].style.left = "0%"; $(".progress-percentage")[0].innerText = "0%"; if (errorDetails && (await tryToSaveBackupProcess(errorDetails))) { return; } $.bmi.releaseWakeLock(); await cleanUpAfterError(); console.error("Backup error type:", type); setTimeout(function () { $(".log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("backup-progress-modal").close(); setupBackupErrorOptions().then(() => { setTimeout(function () { $.bmi.modal("error-modal").open(); $.bmi.modal("error-modal").setParent("backup-progress-modal"); }, 300); }); $("#after-logs-sent-modal").attr("data-error-source", "backup"); }, 2000); } bmi.backupError = backupError; async function cleanUpAfterError() { await $.bmi.ajax("clean-up-after-error", {}); } function handleBfs() { $.bmi.modal("bfs-modal").open(); } function sendRequestOfBackupPart(callback, errors = 0) { let callbackSent = false; let cb = (data) => { if (callbackSent == false) { callbackSent = true; return callback(data); } }; $.bmi .ajax("backup-browser-method", {}) .then(function (res) { if (typeof res.status != "undefined" && res.status == "success") { if ( typeof res.status != "undefined" && res.backup_process_error == "true" ) { errors++; return callback({ status: false, errors: errors }); } if ( typeof res.backup_completed != "undefined" && res.backup_completed == "true" ) return callback({ status: true, errors: errors }); else return callback({ status: false, errors: errors }); } else { // Increment the errors errors++; console.error(res); return callback({ status: false, errors: errors }); } }) .catch(function (error) { // Increment the errors errors++; console.error(error); // Return with a tiemouted retry return callback({ status: false, errors: errors }); }); // // Require browser client // let http = new XMLHttpRequest(); // // Open POST connection // http.open('POST', h.url, true); // // Send proper headers with settings // http.setRequestHeader('Content-Type', 'application/json'); // http.setRequestHeader('Content-Accept', '*/*'); // http.setRequestHeader('Access-Control-Allow-Origin', '*'); // http.setRequestHeader('Content-ConfigDir', h.config_dir); // http.setRequestHeader('Content-Content', h.content_dir); // http.setRequestHeader('Content-Backups', h.backup_dir); // http.setRequestHeader('Content-Identy', h.identy); // http.setRequestHeader('Content-Url', h.url); // http.setRequestHeader('Content-Abs', h.abs_dir); // http.setRequestHeader('Content-Dir', h.root_dir); // http.setRequestHeader('Content-Manifest', h.manifest); // http.setRequestHeader('Content-Name', h.backupname); // http.setRequestHeader('Content-Safelimit', h.safelimit); // http.setRequestHeader('Content-Start', h.start); // http.setRequestHeader('Content-Filessofar', h.filessofar); // http.setRequestHeader('Content-Total', h.total_files); // http.setRequestHeader('Content-Rev', h.rev); // http.setRequestHeader('Content-It', h.iteratio); // http.setRequestHeader('Content-Dbit', h.dbiteratio); // http.setRequestHeader('Content-Dblast', h.dblast); // http.setRequestHeader('Content-Bmitmp', h.bmitmp); // http.setRequestHeader('Content-Browser', true); // // Handle success // http.onload = function () { // // Check if we can get the headers // if (http.status === 200) { // // Make sure the headers exists // let isFinished = http.getResponseHeader('Content-Finished'); // // Check if it's finished // if (typeof isFinished != 'undefined' && isFinished && isFinished == 'true') { // // Reset errors // errors = 0; // // Return with success // return callback({ status: true, iteratio: -1, dbiteratio: -1, dblast: 0, sf: -1, errors: errors }); // } // // Get iteratio value // let iteratio = http.getResponseHeader('Content-It'); // let dbiteratio = http.getResponseHeader('Content-Dbit'); // let dblast = http.getResponseHeader('Content-Dblast'); // let soFar = http.getResponseHeader('Content-Filessofar'); // if (typeof iteratio != 'undefined' && iteratio) { // // Return success // return callback({ status: true, iteratio: iteratio, dbiteratio: dbiteratio, dblast: dblast, sf: soFar, errors: errors }); // } else { // // Increment the errors // errors++; // // Return with failure and a tiemouted retry // return callback({ status: false, iteratio: -1, dbiteratio: dbiteratio, dblast: dblast, sf: -1, errors: errors }); // } // } else { // // Increment the errors // errors++; // // Return with failure and a tiemouted retry // return callback({ status: false, iteratio: -1, dbiteratio: -1, dblast: 0, sf: -1, errors: errors }); // } // } // // Handle failure // http.onerror = function () { // // Increment the errors // errors++; // // Return with a tiemouted retry // return callback({ status: false, iteratio: -1, dbiteratio: -1, dblast: 0, sf: -1, errors: errors }); // } // // Send prepared connection to the server // http.send(); } function middlewareForResponses(res) { // Variables let status = res.status; let errors = parseInt(res.errors); // Check if finished if (status == "true" || status === true) { // Return and show success let backgroundNameTmp = backgroundName; backgroundBackup = false; backgroundName = false; headers_for_middleware = false; window.onbeforeunload = null; $(".backup-minimize").removeClass("disabled"); // Return return completedBackup({ filename: backgroundNameTmp }, true); } // Check for errors // Abort if above 4 errors if (isNaN(errors) || errors > 0) { // Unset the headers and variables backgroundBackup = false; backgroundName = false; headers_for_middleware = false; window.onbeforeunload = null; $(".backup-minimize").removeClass("disabled"); // End this process if ($("#backup-progress-modal").hasClass("open")) { return backupError(3); } else return; } else { // Handle case of success return handleBrowserBackup(errors); } } function handleBrowserBackup(errors = 0) { if (stopBackgroundBackup === true) { stopBackgroundProcess(); return; } // Send the request setTimeout( function () { sendRequestOfBackupPart(middlewareForResponses, errors); }, Math.floor(Math.random() * (523 - 330)) + 330, ); } $("#configuration-reset-absolute").on("click", function (e) { e.preventDefault(); $.bmi .ajax("reset-configuration", {}) .then(function (res) { if (res.status == "success") { window.location.reload(); } else { $.bmi._msg(res); } }) .catch(function (error) { // }); }); $("#download-site-infos").on("click", function (e) { e.preventDefault(); $.bmi .ajax("get-site-data", {}) .then(function (res) { if (res.status == "success") { $.bmi.prepareFile( "site_details_troubleshooting.txt", JSON.stringify(res.data), ); } else { $.bmi._msg(res); } }) .catch(function (error) { // }); }); $("#start-entire-backup").on("click", startBackupProcessNow); async function startBackupProcessNow(e, preserveLogs = false) { if (preserveLogs == false) { $.bmi.modal("prenotice-modal").close(); $.bmi.modal("freeze-loading-modal").open(); } $(".backup-minimize").removeClass("disabled"); await fixHtaccessPromise(); if (preserveLogs == false) { curdivs = 0; await resetLogsPromise(false); } clearTimeout(timeouter); triggeredByIntv = false; bacupisDone = false; backupOnGoing = true; $.bmi.requestWakeLock(); refreshLogAndProgress(preserveLogs); callBackupRunAjax(preserveLogs); } function callBackupRunAjax(preserveLogs = false) { stopBackgroundBackup = false; if (preserveLogs == false) { $.bmi.modal("freeze-loading-modal").close(); $.bmi.modal("backup-progress-modal").open(); } $.bmi .ajax("create-backup", { preserveLogs: preserveLogs, }) .then(function (res) { if (res.status == "success") { bacupisDone = true; clearTimeout(timeouter); backupOnGoing = false; refreshContentInstant(function () { setTimeout(function () { // setProgress(101, 500, res); completedBackup(res, true); }, 350); }); } else if (res.status == "background") { backgroundBackup = true; backgroundName = res.filename; let end_code = document.querySelectorAll(".hide_so_much"); if (end_code && end_code.length > 0) { end_code = end_code[end_code.length - 1]; let code_line = end_code.innerText; if (code_line.includes("001")) { bacupisDone = true; progressIsDone = true; clearTimeout(timeouter); backupOnGoing = false; completedBackup({ filename: backgroundName }, true); } if (code_line.includes("002") || code_line.includes("004")) { // $.bmi.modal('backup-progress-modal').close(); backupError(4); } if (code_line.includes("003")) { $.bmi.modal("backup-progress-modal").close(); $.bmi.alert("info", $("#bmi-aborted-al").text(), 3000); } } } else if (res.status == "background_hard") { // Set the background receiver backgroundBackup = true; // Set Global name of current backup backgroundName = res.filename; // Append URL res.url = res.url; // Display success of receiver $.bmi.alert("success", $("#bmi-received-hard").text(), 3000); // Disable button $(".backup-minimize").addClass("disabled"); // Make sure modal is visible if (!$("#backup-progress-modal").hasClass("open")) { setTimeout(function () { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { // Make sure the progress modal is open $.bmi.modal("backup-progress-modal").open(); }, 300); }, 300); } // Make sure the backup won't be dismissed by mistake window.onbeforeunload = function () { return "Backup in progress..."; }; // Send first request handleBrowserBackup(); } else { backupOnGoing = false; setTimeout(function () { clearInterval(iprogres); $(".log-wrapper").find("pre")[0].innerText = ""; $(".progress-active-bar")[0].style.width = "0%"; $(".progress-percentage")[0].style.left = "0%"; $(".progress-percentage")[0].innerText = "0%"; }, 300); $.bmi._msg(res); console.log(res); $.bmi.modal("backup-progress-modal").close(); if (typeof res.bfs !== "undefined") handleBfs(); else backupError(5); } }) .catch(function (error) { console.error(error); backupError(6, error); }); } $("#open_trouble_extenstion").on("click", function () { if ($("#trouble_extenstion").hasClass("openned")) { $("#trouble_extenstion").hide(300); $("#trouble_extenstion").removeClass("openned"); $(this).removeClass("active"); } else { $("#trouble_extenstion").show(300); $("#trouble_extenstion").addClass("openned"); $(this).addClass("active"); } }); $("#switch-show-trs").on("click", function () { let seemore = this.dataset.see; let hide = this.dataset.hide; let $trs = $(".hide-show-tr"); if ($(this).hasClass("shown")) { $trs.hide(300); $(this).removeClass("shown"); this.innerText = seemore; } else { $trs.show(300); $(this).addClass("shown"); this.innerText = hide; } }); $("#ex_b_fs").on("change", function () { if ($("#ex_b_fs").is(":checked")) $("#bmi__collon").show(); else $("#bmi__collon").hide(); }); $("#show-upload-area").on("click", function () { if ($(".upload_area").hasClass("hidden")) { $(".upload_area").show(300); $(".upload_area").removeClass("hidden"); $([document.documentElement, document.body]).animate( { scrollTop: $(this).offset().top - 50 + "px", }, 300, ); } else { $(".upload_area").hide(300); $(".upload_area").addClass("hidden"); } }); $(".bmi-copper").on("click", function (e) { e.preventDefault(); let $el = $("#" + this.getAttribute("data-copy"))[0]; if ($el.value && $el.value.length > 0) { $.bmi.clipboard($el.value); } else { $.bmi.clipboard($el.innerText); } }); $("#bmi_restore_tbody").on("click", ".restore-btn", function (e) { isMigrationLocked(function (isNotLocked) { if (isNotLocked) { let name = ''; if (e.target.closest('tr').getAttribute('data-is-local') === 'no') { if (e.target.closest('tr').getAttribute('gdrive-id') !== null) { name = '?#googledrive#_' + e.target.closest('tr').getAttribute('gdrive-id'); current_restore = name; } if (e.target.closest('tr').getAttribute('ftp-id') !== null) { name = '?#ftp#_' + e.target.closest('tr').getAttribute('ftp-id'); current_restore = name; } if(e.target.closest('tr').getAttribute('dropbox-id') !== null){ name = '?#dropbox#_' + e.target.closest('tr').getAttribute('dropbox-id'); current_restore = name; } if (e.target.closest('tr').getAttribute('onedrive-id') !== null) { name = '?#onedrive#_' + e.target.closest('tr').getAttribute('onedrive-id'); current_restore = name; } if(e.target.closest('tr').getAttribute('pcloud-id') !== null){ name = '?#pcloud#_' + e.target.closest('tr').getAttribute('pcloud-id'); current_restore = name; } if (e.target.closest('tr').getAttribute('aws-id') !== null) { name = '?#aws#_' + e.target.closest('tr').getAttribute('aws-id'); current_restore = name; } if (e.target.closest('tr').getAttribute('wasabi-id') !== null) { name = '?#wasabi#_' + e.target.closest('tr').getAttribute('wasabi-id'); current_restore = name; } if (e.target.closest('tr').getAttribute('backupbliss-id') !== null) { name = '?#backupbliss#_' + e.target.closest('tr').getAttribute('backupbliss-id'); current_restore = name; } if (e.target.closest('tr').getAttribute('sftp-id') !== null) { name = '?#sftp#_' + e.target.closest('tr').getAttribute('sftp-id'); current_restore = name; } } else { name = e.target.closest("tr").querySelector(".br_name").innerText; current_restore = name; } if (!name || name.trim().length <= 0) return $.bmi.alert("warning", $("#bmi-no-file").text(), 3000); $("#restore-ok").prop("checked", false); $.bmi.modal("freeze-loading-modal").open(); setTimeout(function () { shareLogsStatus("is_allowed", function (res) { if (res === "ask") { $.bmi.modal("freeze-loading-modal").close(); $("#logs-sharing-ask-modal").attr( "data-destination", "pre-restore-modal", ); setTimeout(function () { $.bmi.modal("logs-sharing-ask-modal").open(); }, 300); } else { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { $.bmi.modal("pre-restore-modal").open(); }, 300); } }); }, 300); } }); }); $("#bmi_restore_tbody").on("click", ".stg-restore-btn", function (e) { $.bmi.modal("freeze-loading-modal").open(); let name = e.target.closest("tr").querySelector(".br_name").innerText; // if (e.target.closest('tr').getAttribute('data-is-local') === 'no') { // name = '?#googledrive#_' + e.target.closest('tr').getAttribute('gdrive-id'); // } if (!name || name.trim().length <= 0) { return $.bmi.alert("warning", $("#bmi-no-file").text(), 3000); } $('.bmi-stg-sel-box[data-mode="tastewp"]').click(); $('.bmi-stg-drop-option[backup-name="' + name.trim() + '"]').click(); $("#stgng").click(); setTimeout(function () { $.bmi.modal("freeze-loading-modal").close(); }, 150); }); $("#quick-download-migration").on("click", function () { let url = $("#bm-d-url").val(); if ($.bmi.isUrlValid(url)) { isMigrationLocked(function (isNotLocked) { if (isNotLocked) { if (url.length > 0) { current_restore = -100; $("#restore-ok").prop("checked", false); $.bmi.modal("freeze-loading-modal").open(); setTimeout(function () { shareLogsStatus("is_allowed", function (res) { if (res === "ask") { $.bmi.modal("freeze-loading-modal").close(); $("#logs-sharing-ask-modal").attr( "data-destination", "pre-restore-modal", ); setTimeout(function () { $.bmi.modal("logs-sharing-ask-modal").open(); }, 300); } else { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { $.bmi.modal("pre-restore-modal").open(); }, 300); } }); }, 300); } else $.bmi.alert("warning", $("#bmi-invalid-url").text(), 5000); } }); } else $.bmi.alert("warning", $("#bmi-invalid-url").text(), 5000); }); $('#restore-start-sure').on('click', function () { if ($('#restore-ok').is(':checked')) { if (current_restore === -100) downloadMigration(); else if (current_restore.includes('?#googledrive#_')) downloadGDrive(); else if (current_restore.includes('?#ftp#_')) downloadFTP(); else if (current_restore.includes('?#dropbox#_')) downloadDropbox(); else if (current_restore.includes('?#onedrive#_')) downloadOneDrive(); else if (current_restore.includes('?#pcloud#_')) downloadPCloud(); else if (current_restore.includes('?#aws#_')) downloadS3(true, 'aws'); else if (current_restore.includes('?#wasabi#_')) downloadS3(true, 'wasabi'); else if (current_restore.includes('?#backupbliss#_')) downloadBackupBliss(); else if (current_restore.includes('?#sftp#_')) downloadSFTP(); else letsRestore(); } else $.bmi.alert("warning", $("#bmi-restore-require-checkmark").text(), 3000); }); $(".backup-minimize").on("click", function () { isBackupOngoing(function (isRunnin) { if (isRunnin === true) $("#bmi-ongoing-backup").show(300); else $("#bmi-ongoing-backup").hide(); }); }); function checkIfBackupOnGoing(cb = function () { }) { isBackupOngoing(function (isRunnin) { if (isRunnin === true) { if (!$("#backup-progress-modal").hasClass("open")) { if (backupOnGoing === false) { bacupisDone = false; backupOnGoing = true; triggeredByIntv = true; } $("#bmi-ongoing-backup").show(300); } } else { if ($("#bmi-ongoing-backup").is(":visible")) { $("#bmi-ongoing-backup").hide(300); } if ( $("#backup-progress-modal").hasClass("open") && triggeredByIntv === true ) { if (backupOnGoing === true) { backupOnGoing = false; } triggeredByIntv = false; reloadAndHandleBackupEnd(); } else { if ( backupOnGoing === true && !$("#backup-progress-modal").hasClass("open") ) { backupOnGoing = false; $.bmi.reloadBackups(); } } } cb(); }); } function handleNotOwnBackupEnd() { let url = $("#BMI_BLOG_URL").text().trim(); if (url.slice(-url.length) !== "/") url = url + "/"; httpGet( url + "?backup-migration=PROGRESS_LOGS&progress-id=latest.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(), function (rez) { if (rez === false) { $.bmi.modal("backup-progress-modal").close(); } else { rez = rez.split("\n"); let abort = "Backup process aborted"; let error = "[ERROR]"; if ( rez[rez.length - 1].includes(abort) || rez[rez.length - 2].includes(abort) ) { $.bmi.modal("backup-progress-modal").close(); $.bmi.alert("info", $("#bmi-aborted-al").text(), 3000); } else if ( rez[rez.length - 1].includes(error) || rez[rez.length - 2].includes(error) ) { // $.bmi.modal('backup-progress-modal').close(); backupError(7); } else { let url_x = $("#BMI_BLOG_URL").text().trim(); if (url_x.slice(-url_x.length) !== "/") url_x = url_x + "/"; $.bmi .ajax("get-latest-backup", {}) .then(function (res) { let url = url_x + "?backup-migration=BMI_BACKUP&bmi-id=" + res + "&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); let logs = url_x + "?backup-migration=PROGRESS_LOGS&progress-id=latest.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); $("#text-input-copy")[0].value = url; $("#download-backup-url").attr("href", url); $(".download-backup-log-url").attr("href", logs); $.bmi.modal("backup-progress-modal").close(); $.bmi.modal("backup-success-modal").open(); }) .catch(function (error) { $.bmi.modal("backup-progress-modal").close(); $.bmi.modal("backup-success-modal").open(); let url = $($("#bmi_restore_tbody").find("tr")[0]) .find(".bc-download-btn") .attr("href"); $("#download-backup-url").attr({ href: url }); $("#text-input-copy").val(url); }); } } }, ); } function reloadAndHandleBackupEnd() { $.bmi.getCurrentBackups(function (res) { $.bmi.fillWithNewBackups(res.backups, res.backups.ongoing, function () { handleNotOwnBackupEnd(); }); }); } // ONGOING BACKUP function runCheckOnGoing() { checkIfBackupOnGoing(function () { setTimeout(function () { runCheckOnGoing(); }, ongoing_interval); }); } runCheckOnGoing(); $("#bmi-ongoing-backup").on("click", function () { isBackupOngoing(function (isRunnin) { if (isRunnin === true) { curdivs = 0; refreshLogAndProgress(); setTimeout(function () { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { // Make sure the progress modal is open $.bmi.modal("backup-progress-modal").open(); }, 300); }, 300); } else { $.bmi.alert("info", $("#bmi-bc-ended").text(), 3000); $.bmi.reloadBackups(); } $("#bmi-ongoing-backup").hide(300); }); }); function getMigrationLogs(cb = function () { }) { let url = $("#BMI_BLOG_URL").text().trim(); if (url.slice(-url.length) !== "/") url = url + "/"; httpGet( url + "?backup-migration=PROGRESS_LOGS&progress-id=latest_migration_full.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(), function (res1) { if (!res1) { return cb(); } let res2 = res1.split("\n").slice(0, 1)[0]; res1 = res1.split("\n").slice(1).join("\n"); if (res2 === false || isNaN(parseFloat(res2))) { return cb(); } restoreLogs = res1; let pre = $("#restore-live-log-wrapper").find("pre")[0]; if (!res1.includes("<") && !res1.includes(">")) { if (res1 && res1 != false && typeof res1 !== "undefined") { insertPre(res1, pre); } } setProgress(res2); cb(); }, ); } function fixHtaccessPromise() { return new Promise((resolve) => { fixHtaccess(() => { return resolve(); }); }); } bmi.fixHtaccessPromise = fixHtaccessPromise; function fixHtaccess(cb = function () {}) { $.bmi .ajax("htaccess-litespeed", {}) .then(function (res) { setTimeout(function () { cb(true); }, 400); }) .catch(function (error) { cb(false); }); } function isMigrationLocked( cb = function () { }, mute = false, clearLogs = true, ) { $.bmi .ajax("migration-locked", { clearLogs: clearLogs }) .then(function (res) { if (res.status == "success") cb(true); else { if (!mute) $.bmi._msg(res); cb(false); } }) .catch(function (error) { // }); } function downloadGDrive(startRestoreProcess = true) { $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; let currentGDriveIdRestoration = current_restore.split("?#googledrive#_")[1]; current_restore = null; if (startRestoreProcess == false) { $('#restore-progress-modal .title').text($('#bmi-download-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-download-warning').text()); } isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal("pre-restore-modal").close(); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("restore-progress-modal").open(); performGDriveDownload(startRestoreProcess, currentGDriveIdRestoration); } }); }); }); } $.bmi.downloadGDrive = downloadGDrive; function downloadFTP(startRestoreProcess = true) { $('#restore-live-log-wrapper').find('pre')[0].innerText = ''; let currentFtpIdRestoration = current_restore.split('?#ftp#_')[1]; let md5 = $("#bmi_restore_tbody").find("tr[ftp-id='" + currentFtpIdRestoration + "']").attr("md5"); current_restore = null; if (startRestoreProcess == false) { $('#restore-progress-modal .title').text($('#bmi-download-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-download-warning').text()); } isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal('pre-restore-modal').close(); $('#restore-live-log-wrapper').find('pre')[0].innerText = ''; $.bmi.modal('restore-progress-modal').open(); performFtpDownload(startRestoreProcess, currentFtpIdRestoration, 0, false, md5); } }); }); }); } $.bmi.downloadFTP = downloadFTP; function downloadOneDrive(startRestoreProcess = true) { $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; let currentOneDriveIdRestoration = current_restore.split("?#onedrive#_")[1]; let md5 = $("#bmi_restore_tbody").find("tr[onedrive-id='" + currentOneDriveIdRestoration + "']").attr("md5"); current_restore = null; if (startRestoreProcess == false) { $('#restore-progress-modal .title').text($('#bmi-download-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-download-warning').text()); } isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal("pre-restore-modal").close(); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("restore-progress-modal").open(); performOneDriveDownload(startRestoreProcess, currentOneDriveIdRestoration, 0, false, md5); } }); }); }); } $.bmi.downloadOneDrive = downloadOneDrive; function downloadBackupBliss(startRestoreProcess = true) { $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; let currentBackupBlissIdRestoration = current_restore.split("?#backupbliss#_")[1]; let md5 = $("#bmi_restore_tbody").find("tr[backupbliss-id='" + currentBackupBlissIdRestoration + "']").attr("md5"); current_restore = null; isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal("pre-restore-modal").close(); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("restore-progress-modal").open(); performBackupBlissDownload(startRestoreProcess, currentBackupBlissIdRestoration, 0, false, md5); } }); }); }); } $.bmi.downloadBackupBliss = downloadBackupBliss; function performFtpDownload(startRestoreProcess = true, fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = 1000000, secret = false) { $.bmi.ajax('download-cloud-backup', { storage: 'ftp', startRestoreProcess: startRestoreProcess, fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, secret: secret }).then(function (res) { if (res.status == 'success') { if (typeof res.size != 'undefined') size = res.size; if (typeof res.md5 != 'undefined') md5 = res.md5; if (typeof res.originalFilename != 'undefined') originalFilename = res.originalFilename; if (typeof res.writepath != 'undefined') writepath = res.writepath; if (typeof res.chunksize != 'undefined') chunksize = res.chunksize; if (typeof res.secret != 'undefined') secret = res.secret; if (typeof res.finished != 'undefined' && res.finished != 'true') { step++; performFtpDownload(startRestoreProcess, fileId, step, size, md5, originalFilename, writepath, chunksize, secret); } else { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $('#restore-progress-modal .progress-active-bar')[0].style.width = 0 + '%'; $('#restore-progress-modal .progress-percentage')[0].style.left = 0 + '%'; $('#restore-progress-modal .progress-percentage')[0].innerText = 0 + '%'; $('#restore_current_step').text($('#bmi-restoring-prepare').text()); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }).catch(function (error) { restoreFailed(error); }); } function performGDriveDownload(startRestoreProcess = true, fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = 1000000, secret = false) { $.bmi.ajax('download-cloud-backup', { storage: 'googledrive', startRestoreProcess: startRestoreProcess, fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, secret: secret }).then(function (res) { if (res.status == 'success') { if (typeof res.size != 'undefined') size = res.size; if (typeof res.md5 != 'undefined') md5 = res.md5; if (typeof res.originalFilename != 'undefined') originalFilename = res.originalFilename; if (typeof res.writepath != 'undefined') writepath = res.writepath; if (typeof res.chunksize != 'undefined') chunksize = res.chunksize; if (typeof res.secret != 'undefined') secret = res.secret; if (typeof res.finished != 'undefined' && res.finished != 'true') { step++; performGDriveDownload(startRestoreProcess, fileId, step, size, md5, originalFilename, writepath, chunksize, secret); } else if (res.finished == 'true') { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $( "#restore-progress-modal .progress-active-bar", )[0].style.width = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; $("#restore_current_step").text( $("#bmi-restoring-prepare").text(), ); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }) .catch(function (error) { restoreFailed(error); }); } function downloadDropbox(startRestoreProcess = true) { $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; let currentDropboxIdRestoration = current_restore.split("?#dropbox#_")[1]; let md5 = $("#bmi_restore_tbody").find("tr[dropbox-id='" + currentDropboxIdRestoration + "']").attr("md5"); current_restore = null; if (startRestoreProcess == false) { $('#restore-progress-modal .title').text($('#bmi-download-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-download-warning').text()); } isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal("pre-restore-modal").close(); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("restore-progress-modal").open(); performDropboxDownload(startRestoreProcess, currentDropboxIdRestoration, 0, false, md5); } }); }); }); } function performDropboxDownload(startRestoreProcess = true, fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = false, secret = false) { $.bmi.ajax('download-dropbox-backup', { fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, startRestoreProcess: startRestoreProcess, secret: secret }).then(function(res) { if (res.status == 'success') { if (typeof res.size != 'undefined') size = res.size; if (typeof res.md5 != 'undefined') md5 = res.md5; if (typeof res.originalFilename != 'undefined') originalFilename = res.originalFilename; if (typeof res.writepath != 'undefined') writepath = res.writepath; if (typeof res.chunksize != 'undefined') chunksize = res.chunksize; if (typeof res.secret != 'undefined') secret = res.secret; if (typeof res.finished != 'undefined' && res.finished != 'true') { step++; performDropboxDownload(startRestoreProcess, fileId, step, size, md5, originalFilename, writepath, chunksize, secret); } else if (res.finished == 'true') { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $( "#restore-progress-modal .progress-active-bar", )[0].style.width = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; $("#restore_current_step").text( $("#bmi-restoring-prepare").text(), ); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }).catch(function(error) { restoreFailed(error); }); } function downloadS3(startRestoreProcess = true, provider = 'aws') { $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; let currentS3IdRestoration = current_restore.split("?#" + provider + "#_")[1]; let md5 = $("#bmi_restore_tbody").find("tr[" + provider + "-id='" + currentS3IdRestoration + "']").attr("md5"); current_restore = null; isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal("pre-restore-modal").close(); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("restore-progress-modal").open(); performS3Download(startRestoreProcess, provider, currentS3IdRestoration, 0, false, md5); } }); }); }); } function performS3Download(startRestoreProcess = true, provider = 'aws', fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = 1000000, secret = false) { $.bmi.ajax('download-cloud-backup', { storage: 's3', provider: provider, fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, startRestoreProcess: startRestoreProcess, secret: secret }).then(function (res) { if (res.status == 'success') { if (typeof res.size != 'undefined') size = res.size; if (typeof res.md5 != 'undefined') md5 = res.md5; if (typeof res.originalFilename != 'undefined') originalFilename = res.originalFilename; if (typeof res.writepath != 'undefined') writepath = res.writepath; if (typeof res.chunksize != 'undefined') chunksize = res.chunksize; if (typeof res.secret != 'undefined') secret = res.secret; if (typeof res.finished != 'undefined' && res.finished != 'true') { step++; performS3Download(startRestoreProcess, provider, fileId, step, size, md5, originalFilename, writepath, chunksize, secret); } else if (res.finished == 'true') { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $( "#restore-progress-modal .progress-active-bar", )[0].style.width = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; $("#restore_current_step").text( $("#bmi-restoring-prepare").text(), ); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }).catch(function (error) { restoreFailed(error); }); } $.bmi.downloadS3 = downloadS3; function performOneDriveDownload(startRestoreProcess = true,fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = 1000000, secret = false) { $.bmi.ajax('download-cloud-backup', { storage: 'onedrive', fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, startRestoreProcess: startRestoreProcess, secret: secret }).then(function (res) { if (res.status == 'success') { if (typeof res.size != 'undefined') size = res.size; if (typeof res.md5 != 'undefined') md5 = res.md5; if (typeof res.originalFilename != 'undefined') originalFilename = res.originalFilename; if (typeof res.writepath != 'undefined') writepath = res.writepath; if (typeof res.chunksize != 'undefined') chunksize = res.chunksize; if (typeof res.secret != 'undefined') secret = res.secret; if (typeof res.finished != 'undefined' && res.finished != 'true') { step++; performOneDriveDownload(startRestoreProcess, fileId, step, size, md5, originalFilename, writepath, chunksize, secret); } else if (res.finished == 'true') { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $( "#restore-progress-modal .progress-active-bar", )[0].style.width = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; $("#restore_current_step").text( $("#bmi-restoring-prepare").text(), ); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }) .catch(function (error) { restoreFailed(error); }); } function performBackupBlissDownload(startRestoreProcess = true,fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = 1000000, secret = false) { $.bmi.ajax('download-cloud-backup', { storage: 'backupbliss', fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, startRestoreProcess: startRestoreProcess, secret: secret }).then(function (res) { if (res.status == 'success') { if (typeof res.size != 'undefined') size = res.size; if (typeof res.md5 != 'undefined') md5 = res.md5; if (typeof res.originalFilename != 'undefined') originalFilename = res.originalFilename; if (typeof res.writepath != 'undefined') writepath = res.writepath; if (typeof res.chunksize != 'undefined') chunksize = res.chunksize; if (typeof res.secret != 'undefined') secret = res.secret; if (typeof res.finished != 'undefined' && res.finished != 'true') { step++; performBackupBlissDownload(startRestoreProcess, fileId, step, size, md5, originalFilename, writepath, chunksize, secret); } else if (res.finished == 'true') { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $( "#restore-progress-modal .progress-active-bar", )[0].style.width = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; $("#restore_current_step").text( $("#bmi-restoring-prepare").text(), ); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }) .catch(function (error) { restoreFailed(error); }); } function downloadSFTP(startRestoreProcess = true) { console.log("downloadSFTP"); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; let currentSFTPIdRestoration = current_restore.split("?#sftp#_")[1]; let md5 = $("#bmi_restore_tbody").find("tr[sftp-id='" + currentSFTPIdRestoration + "']").attr("md5"); current_restore = null; isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal("pre-restore-modal").close(); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("restore-progress-modal").open(); performSFTPDownload(startRestoreProcess, currentSFTPIdRestoration, 0, false, md5); } }); }); }); } function performSFTPDownload(startRestoreProcess = true, fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = 1000000, secret = false) { $.bmi.ajax('download-sftp-backup', { fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, startRestoreProcess: startRestoreProcess, secret: secret }).then(function (res) { if (res.status == 'success') { if (typeof res.size != 'undefined') size = res.size; if (typeof res.md5 != 'undefined') md5 = res.md5; if (typeof res.originalFilename != 'undefined') originalFilename = res.originalFilename; if (typeof res.writepath != 'undefined') writepath = res.writepath; if (typeof res.chunksize != 'undefined') chunksize = res.chunksize; if (typeof res.secret != 'undefined') secret = res.secret; if (typeof res.finished != 'undefined' && res.finished != 'true') { step++; performSFTPDownload(startRestoreProcess, fileId, step, size, md5, originalFilename, writepath, chunksize, secret); } else if (res.finished == 'true') { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $("#restore-progress-modal .progress-active-bar")[0].style.width = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; $("#restore_current_step").text($("#bmi-restoring-prepare").text()); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }) .catch(function (error) { restoreFailed(error); }); } $.bmi.downloadSFTP = downloadSFTP; function downloadPCloud(startRestoreProcess = true) { $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; let currentPCloudIdRestoration = current_restore.split("?#pcloud#_")[1]; let md5 = $("#bmi_restore_tbody").find("tr[pcloud-id='" + currentPCloudIdRestoration + "']").attr("md5"); current_restore = null; if (startRestoreProcess == false) { $('#restore-progress-modal .title').text($('#bmi-download-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-download-warning').text()); } isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { curdivs = 0; refreshLogAndProgressRestore(); restoreOnGoing = true; cli_quickmigration = true; $.bmi.modal("pre-restore-modal").close(); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; $.bmi.modal("restore-progress-modal").open(); performPCloudDownload(startRestoreProcess, currentPCloudIdRestoration, 0, false, md5); } }); }); }); } $.bmi.downloadPCloud = downloadPCloud; function performPCloudDownload( startRestoreProcess = true, fileId = false, step = 0, size = false, md5 = false, originalFilename = false, writepath = false, chunksize = false, secret = false ) { $.bmi .ajax("download-cloud-backup", { storage: "pcloud", fileId: fileId, step: step, size: size, md5: md5, filename: originalFilename, writepath: writepath, chunksize: chunksize, startRestoreProcess: startRestoreProcess, secret: secret, }) .then(function (res) { if (res.status == "success") { if (typeof res.size != "undefined") size = res.size; if (typeof res.md5 != "undefined") md5 = res.md5; if (typeof res.originalFilename != "undefined") originalFilename = res.originalFilename; if (typeof res.writepath != "undefined") writepath = res.writepath; if (typeof res.chunksize != "undefined") chunksize = res.chunksize; if (typeof res.secret != "undefined") secret = res.secret; if (typeof res.finished != "undefined" && res.finished != "true") { step++; performPCloudDownload( startRestoreProcess, fileId, step, size, md5, originalFilename, writepath, chunksize, secret, ); } else if (res.finished == "true") { cli_quickmigration = true; current_restore = res.filename; refreshLogAndProgressRestore(false); $.bmi.reloadBackups(function () { setTimeout(function () { clearInterval(iprogres); $( "#restore-progress-modal .progress-active-bar", )[0].style.width = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; $("#restore_current_step").text( $("#bmi-restoring-prepare").text(), ); }, 600); }); } } else { $.bmi._msg(res); restoreFailed(); console.error(res); } }) .catch(function (error) { restoreFailed(error); }); } $.bmi.downloadDropbox = downloadDropbox; function downloadMigration( startRestoreProcess = true) { current_restore = null; $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; if (startRestoreProcess == false) { $('#restore-progress-modal .title').text($('#bmi-download-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-download-warning').text()); } isMigrationLocked(function (isNotLocked) { resetLogs(true, function () { fixHtaccess(function () { if (isNotLocked) { let url = $("#bm-d-url").val(); $("#restore_current_step").text( $("#bmi-downloading-remote").text(), ); $.bmi .ajax("download-backup", { url: url, startRestoreProcess: startRestoreProcess }) .then(function (res) { clearInterval(iprogres); clearTimeout(timeouter); if (res.status === "success") { // Set backup to restore name current_restore = res.name; // Refresh logs in such case cli_quickmigration = true; refreshLogAndProgressRestore(false); // Reload backup list $.bmi.reloadBackups(); // setProgress(100, 300); setTimeout(function () { clearInterval(iprogres); $( "#restore-progress-modal .progress-active-bar", )[0].style.width = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].style.left = 0 + "%"; $( "#restore-progress-modal .progress-percentage", )[0].innerText = 0 + "%"; $("#restore_current_step").text( $("#bmi-restoring-prepare").text(), ); }, 600); } else if (res.status == "cli_download") { current_restore = ".cli_download"; cli_quickmigration = true; refreshLogAndProgressRestore(false); } else if (res.status === "error") { restoreFailed(); } else { $.bmi._msg(res); restoreFailed(); } }) .catch(function (error) { restoreFailed(error); }); $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; curdivs = 0; restoreOnGoing = true; cli_quickmigration = true; refreshLogAndProgressRestore(); $.bmi.modal("pre-restore-modal").close(); $.bmi.modal("restore-progress-modal").open(); } }); }); }); } $.bmi.downloadMigration = downloadMigration; function restoreFailed(text = "") { $('#restore-progress-modal .title').text($('#bmi-restore-progress-modal-title').text()); $('#restore-progress-modal .red-error-bg .red-warning').text($('#bmi-restore-progress-modal-warning').text()); setTimeout(function () { $("#restore-progress-modal .progress-active-bar")[0].style.width = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; }, 500); $.bmi.releaseWakeLock(); isMigrationLocked( function (isNotLocked) { if (isNotLocked) { setTimeout(function () { if (!$("#restore-progress-modal").hasClass("open")) return; restoreOnGoing = false; cli_quickmigration = false; $("#restore-error-pre").text( $("#bmi-loading-translation").text().trim(), ); $("#after-logs-sent-modal").attr("data-error-source", "migration"); let url = $("#BMI_BLOG_URL").text().trim(); if (url.slice(-url.length) !== "/") url = url + "/"; // httpGet(url + '?backup-migration=PROGRESS_LOGS&progress-id=latest_migration.log&bmi-id=current&t=' + +new Date(), function(res) { // // if (res == false) { // setTimeout(function () { // restoreFailed(); // }, 1500); // } else { // let pre = $('#restore-error-pre')[0]; // $('#restore-error-pre').text(''); // curdivs = 0; // insertPre(res, pre); // } // // }); $.bmi.modal("restore-progress-modal").close(); setupRestoreErrorOptions().then(function () { $.bmi.modal("error-modal").open(); $.bmi.modal("error-modal").setParent("restore-progress-modal"); }); }, 1000); } else { setTimeout(function () { $.bmi.modal("restore-progress-modal").close(); setupRestoreErrorOptions().then(function () { $.bmi.modal("error-modal").open(); $.bmi.modal("error-modal").setParent("restore-progress-modal"); }); }); } }, true, false, ); } function restoreCLISuccess() { $.bmi.modal("restore-progress-modal").close(); restoreExecutionTime = (new Date().getTime() - restoreStartTime) / 1000; $.bmi.modal("restore-success-modal").open(); setTimeout(function () { $("#restore-progress-modal .progress-active-bar")[0].style.width = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; }, 500); restoreCLI = false; } function letsRestore(remote = false, secret = null) { let name = current_restore; if (!name || name.trim().length <= 0) return $.bmi.alert("warning", $("#bmi-no-file").text(), 3000); if ($("#pre-restore-modal").hasClass("open")) $.bmi.modal("pre-restore-modal").close(); if (!$("#restore-progress-modal").hasClass("open")) $.bmi.modal("restore-progress-modal").open(); if (!remote) $("#restore-live-log-wrapper").find("pre")[0].innerText = ""; if (secret == null) { if (!remote) curdivs = 0; restoreOnGoing = true; clearTimeout(timeouter); restoreStartTime = new Date().getTime(); function initializeRestoration() { fixHtaccess(function () { getMigrationLogs(function () { runRestoreProcess(name, remote, secret); }); }); } $.bmi.requestWakeLock(); if (!remote) resetLogs(true, initializeRestoration); else initializeRestoration(); } } $.bmi.letsRestore = letsRestore; function runRestoreProcess( name, remote, secret, tmpname = false, ignoreRunning = "false", options = {}, ) { if (secret == null && remote !== true) { refreshLogAndProgressRestore(true); } if (typeof options.storage != "undefined") { options.storage = options.storage.replace(/[\\\\/]+/g, "/"); } $.bmi .ajax("restore-backup", { file: name, remote: remote, secret: secret, ignoreRunning: ignoreRunning, tmpname: tmpname, options: options, }) .then(function (res) { if (res.status === "cli") { autoLog = { l: res.login, u: res.url }; restoreCLI = true; let end_code = document.querySelectorAll(".hide_so_much"); if (end_code && end_code.length > 0) { end_code = end_code[end_code.length - 1]; let code_line = end_code.innerText; if (code_line.includes("001")) { $.bmi.releaseWakeLock(); setTimeout(function () { restoreCLISuccess(); restoreOnGoing = false; restoreCLI = false; }, 1000); } else { restoreFailed(); } } } else if (res.status === "success") { autoLog = { l: res.login, u: res.url }; $.bmi.releaseWakeLock(); setTimeout(function () { clearInterval(iprogres); clearTimeout(timeouter); restoreOnGoing = false; $.bmi.modal("restore-progress-modal").close(); restoreExecutionTime = (new Date().getTime() - restoreStartTime) / 1000; if (restoreExecutionTime > 60) $.bmi.modal("restore-success-modal").open(); setTimeout(function () { $("#restore-progress-modal .progress-active-bar")[0].style.width = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].style.left = 0 + "%"; $("#restore-progress-modal .progress-percentage")[0].innerText = 0 + "%"; }, 500); }, 1500); } else if (res.status === "secret") { res.options.step = parseInt(res.options.step) + 1; runRestoreProcess( name, remote, res.secret, res.tmp, "true", res.options, ); } else if (res.status === "restore_ongoing") { if (typeof res.options.firstDB != "undefined") { res.options.firstDB = false; } if (typeof res.options.dbFinished != "undefined") { if ( res.options.dbFinished === true || res.options.dbFinished === "true" || res.options.dbFinished === "1" ) { res.options.step = parseInt(res.options.step) + 1; } } else if (typeof res.options.dbConvertionFinished != "undefined") { if ( res.options.dbConvertionFinished === "true" || res.options.dbConvertionFinished === true || res.options.dbConvertionFinished === "1" ) { res.options.step = parseInt(res.options.step) + 1; } } else if (typeof res.options.replaceFinished != "undefined") { if ( res.options.replaceFinished === "true" || res.options.replaceFinished === true || res.options.replaceFinished === "1" ) { res.options.step = parseInt(res.options.step) + 1; } } else { res.options.step = parseInt(res.options.step) + 1; if ( (res.options.step == 4 || res.options.step == "4") && typeof res.options.repeat_export != "undefined" ) { if ( res.options.repeat_export === true || res.options.repeat_export === "true" || res.options.repeat_export === "1" ) { res.options.step = 3; res.options.firstExtract = "false"; } } } setTimeout( function () { runRestoreProcess( name, remote, res.secret, res.tmp, "true", res.options, ); }, Math.floor(Math.random() * (523 - 330)) + 330, ); } else if (res.status === "error") { setTimeout(function () { clearInterval(iprogres); clearTimeout(timeouter); console.error(res); restoreFailed(); }, 1000); } else { $.bmi.modal("pre-restore-modal").close(); $.bmi.modal("restore-progress-modal").close(); $.bmi._msg(res); } }) .catch(function (error) { console.error(error); restoreFailed(error); }); } function getAndInsertDynamicNames() { $.bmi .ajax("get-dynamic-names", {}) .then(function (res) { let rules = res.data; $("#bmi_exclusion_rules").text(""); if (typeof rules === "undefined") return; if (typeof rules.length === "undefined") return; for (let i = 0; i < rules.length; ++i) { let row = $(".exclusion_template").clone(); row.removeClass("exclusion_template"); row.find(".exclusion_txt").val(rules[i].txt); let posdd = row.find(".exclusion_position").find("select"); let whrdd = row.find(".exclusion_where").find("select"); if (!posdd) continue; else posdd[0].setAttribute("data-def", rules[i].pos); if (!whrdd) continue; else whrdd[0].setAttribute("data-def", rules[i].whr); $("#bmi_exclusion_rules").append(row); if ( row.find(".exclusion_position").find(".bmi-dropdown").length > 0 ) { $.bmi.setOption( row.find(".exclusion_position").find(".bmi-dropdown"), null, rules[i].pos, ); } if (row.find(".exclusion_where").find(".bmi-dropdown").length > 0) { $.bmi.setOption( row.find(".exclusion_where").find(".bmi-dropdown"), null, rules[i].whr, ); } } $("#dynamic-fpaths-names").text(res["dynamic-fpaths-names"].join("\n")); $("#dynamic-dpaths-names").text(res["dynamic-dpaths-names"].join("\n")); }) .catch(function (error) { // }); } $("#bmi_support_chat").on("click", function () { if ($("#support-bmi").length === 0) { $("#bmi").append( '<script id="support-bmi" src="' + $("#bmi-support-url-translation").val() + '" async></script>', ); setTimeout(function () { $("#bmi_support_chat").hide(); }, 100); var loaded = false; let loadinter = setInterval(function () { if (loaded == true) clearInterval(loadinter); if (typeof window.jivo_api !== "undefined") { window.jivo_api.open(); loaded = true; } }, 30); } }); function getAllSelectedBackups() { return $("#bmi_restore_tbody").find('input[type="checkbox"]:checked'); } // del-all-btn-wrp $("#bmi_restore_tbody").on("change", 'input[type="checkbox"]', function (e) { let $selected = getAllSelectedBackups().length; if ($selected > 0) { $(".del-all-btn-wrp").show(300); } else $(".del-all-btn-wrp").hide(300); if ( $selected == $("#bmi_restore_tbody").find('input[type="checkbox"]').length ) { $("#backups-select-all").prop("checked", true); } else { $("#backups-select-all").prop("checked", false); } }); $("#fix-uname-issues").on("click", function (e) { e.preventDefault(); $.bmi .ajax("fix_uname_issues", {}) .then(function (res) { $.bmi.alert("success", $("#bmi-default-success").text(), 3000); }) .catch(function (error) { $.bmi.alert("error", $("#bmi-default-fail").text(), 3000); }); }); $("#revert-uname-issues").on("click", function (e) { e.preventDefault(); $.bmi .ajax("revert_uname_issues", {}) .then(function (res) { $.bmi.alert("success", $("#bmi-default-success").text(), 3000); }) .catch(function (error) { $.bmi.alert("error", $("#bmi-default-fail").text(), 3000); }); }); $("#backups-select-all").on("change", function () { if (this.checked === true) { $("#bmi_restore_tbody") .find('input[type="checkbox"]') .prop("checked", true); } else { $("#bmi_restore_tbody") .find('input[type="checkbox"]') .prop("checked", false); } let $selected = getAllSelectedBackups().length; if ($selected > 0) { $(".del-all-btn-wrp").show(300); } else $(".del-all-btn-wrp").hide(300); }); $(".lrn-mr-btn, .closer-learn-more").on("click", function () { if ($(".learn_more_about_cron").hasClass("open")) { $(".learn_more_about_cron").removeClass("open"); $(".learn_more_about_cron").hide(300); $(".lrn-mr-btn").show(); $(".lrn-mr-btn").css({ opacity: 0, }); $(".lrn-mr-btn").animate( { opacity: 1, }, 300, ); } else { $(".learn_more_about_cron").addClass("open"); $(".learn_more_about_cron").show(300); $(".lrn-mr-btn").css({ opacity: 1, }); $(".lrn-mr-btn").animate( { opacity: 0, }, 300, function () { $(".lrn-mr-btn").hide(); }, ); } }); $(".bmi-error-toggle").on("click", function () { let parent = $(this).closest(".error-noticer"); let parentId = parent.attr("id"); let errorBody = $("#" + parentId + " .error-body"); if ($(errorBody).hasClass("open")) { $(errorBody).hide(300); $(errorBody).removeClass("open"); $("#" + parentId + " .bmi-error-toggle").text($("#" + parentId + " .bmi-error-toggle").data("expand")); } else { $(errorBody).show(300); $(errorBody).addClass("open"); $("#" + parentId + " .bmi-error-toggle").text($("#" + parentId + " .bmi-error-toggle").data("collapse")); } }); function runTimerST() { let time = parseInt($("#server-time-auto").attr("data-time")) * 1000; let date = new Date(time); $("#server-time-auto").text(date.toUTCString()); setInterval(function () { time += 1000; date = new Date(time); $("#server-time-auto").text(date.toUTCString()); }, 1000); if ($("#ex_b_fs").is(":checked")) $("#bmi__collon").show(); else $("#bmi__collon").hide(); } $("#bmi_send_test_mail").on("click", function (e) { e.preventDefault(); $.bmi .ajax("send-test-mail", {}) .then(function (res) { $.bmi.alert("success", $("#bmi-email-success").text(), 3000); }) .catch(function (error) { $.bmi.alert("error", $("#bmi-email-fail").text(), 3000); }); }); $("#bmi-error-dismiss").on("click", function () { let parent = $(this).closest(".error-noticer"); let parentId = parent.attr("id"); $("#" + parentId).hide(300); setTimeout(function () { $("#" + parentId).remove(); }, 330); $.bmi .ajax("dismiss-error-notice", { option_id: parentId, }) .then(function (res) {}) .catch(function (error) {}); }); $(".deleteAllSelected").on("click", function () { let isCloud = false; let $selected = getAllSelectedBackups(), names = []; latest_delete_cloud = {}; let notOnLocal = []; for (let i = 0; i < $selected.length; ++i) { let tr = $selected[i].closest("tr"); let notOnLocalTr = $(tr).data("is-local") == "no" ? true : false; let name = tr.querySelector(".br_name").innerText; names.push(name); if (notOnLocalTr) { notOnLocal.push(name); } latest_delete_cloud[name] = { md5: tr.getAttribute("md5"), gid: tr.getAttribute("gdrive-id"), }; isCloud = Array.from(tr.querySelectorAll('[class*="strg-"]')).filter(el => !el.classList.contains('strg-local')).some(el => el.classList.contains('img-green')); } $("#delete-confirm-modal").find(".text1").hide(); $("#delete-confirm-modal").find(".text4").hide(); $("#delete-confirm-modal").find(".text3").hide(); $("#delete-confirm-modal").find(".text2").show(); let count = names.length; if (count <= 0) return; else { $(".backup-multiple-del-count").text(count); if (count > 1) { $(".del-only-one").hide(); $(".del-more-than-one").show(); } else { $(".del-more-than-one").hide(); $(".del-only-one").show(); } } latest_delete = names; if (isCloud) $(".bmi-cloud-removal").show(); else $(".bmi-cloud-removal").hide(); $("#remove-cloud-backup-as-well")[0].checked = false; if (isCloud && notOnLocal.length === $selected.length) { $("#remove-cloud-backup-as-well")[0].checked = true; $(".bmi-cloud-removal").hide(); $("#delete-confirm-modal").find(".text1").hide(); $("#delete-confirm-modal").find(".text2").hide(); $("#delete-confirm-modal").find(".text4").hide(); $("#delete-confirm-modal").find(".text3").show(); } $.bmi.modal("delete-confirm-modal").open(); }); $("#load-more-backups").on("click", function (e) { e.preventDefault(); $.bmi.showMoreBackups(); }); function toggleFormatTip(e) { e.preventDefault(); $("#format-tip-wrp")[0].style.minWidth = "calc(100% - 120px)"; if ($("#format-tip-wrp")[0].style.display === "none") { $("#format-tip-wrp").show(300); } else { $("#format-tip-wrp").hide(300); } } $("#show-format-tip").on("click", toggleFormatTip); $("#hide-format-tip").on("click", toggleFormatTip); $(".bmi-review-btn").on("click", function (e) { e.preventDefault(); var url = $(this).attr("href"); $.bmi.ajax("clicked-on-plugin-review", {}).then(function (res) { $(".bmi-ask-for-review").hide(300); window.open(url, "_blank"); }); }); $(".go-to-marbs").on("click", function (e) { e.preventDefault(); document.getElementById("marbs").click(); $.bmi.modal().closeAll(); }); $(".go-to-stgng").on("click", function (e) { e.preventDefault(); document.getElementById("stgng").click(); $.bmi.modal().closeAll(); }); $(".site-reloader").on("click", function () { element_enable_crons = [ "choose-auto-backup-interval", "weekly-auto-backup-switch", ]; let element_id = $(this).attr("id"); let crons_enabled = element_enable_crons.includes(element_id) ? "&crons=true" : null; let url = autoLog.u; if (url.slice(-url.length) !== "/") url = url + "/"; let url_final = url + "?backup-migration=AFTER_RESTORE&bmi-id=" + autoLog.l + "&progress-id=4u70L051n&t=" + crons_enabled + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); window.location = url_final; }); $(".get-file-database-sizes").on("click", function (e) { e.preventDefault(); let resources = [ "plugins", "uploads", "themes", "contents_others", "wordpress", "database", ]; resetSpinners(resources, true); saveBtnEventHandler(false, "save-file-config"); }); $("#bmi-pro-storage-gdrive-toggle").on("change", function (e) { if (!$("#bmi-pro-storage-gdrive-toggle").is(":checked")) { $("td.br_stroage.center").addClass("bmi-gdrive-disabled"); } else { $("td.br_stroage.center").removeClass("bmi-gdrive-disabled"); } }); $(".open-logs-modal-url").on("click", function () { let parentId = $(this).closest(".bmi-modal").attr("id"); $.bmi.modal("logs-modal").setParent(parentId); $.bmi.modal(parentId).close(); $.bmi.modal("freeze-loading-modal").open(); setupLogsModal(); }); $(".skip-share-logs-after-restore, .shared-log-after-restore").on("click", function () { $.bmi.modal("supportive-restore-success-modal").close(); $.bmi.modal("supportive-restore-success-cont-modal").open(); }); $(".try-in-different-way").on("click", tryInDifferentWay); function refreshBBStorageInfo(silent=false) { $('.refresh-img').addClass("loading"); $.bmi.ajax('bb-storage-info').then(function (res) { if (res.status == 'success') { $(".bb-storage-amount").text(res.data.storage_info.total_space_humanized); $(".bb-storage-used").text(res.data.storage_info.used_space_humanized); $(".bb-storage-used-percent").text("("+res.data.storage_info.used_space_percent+"%)"); } else { if (!silent) $.bmi.alert('error', res.message); } $('.refresh-img').removeClass("loading"); }).catch(function (error) { $('.refresh-img').removeClass("loading"); if (!silent) $.bmi.alert('error', 'There was an error contacting the plugin backend.'); }); } refreshBBStorageInfo(true); $(".refresh-bb-storage").on("click", function(e){ e.preventDefault(); refreshBBStorageInfo(); }); $("#bb-upload-fail-dismiss").on("click", function(e){ e.preventDefault(); $.bmi .ajax("dismiss-error-notice", { option_id: "backupbliss-dismiss-upload-issue", }) .then(function (res) {}) .catch(function (error) {}); $("#bb-warning-notice").hide(300); setTimeout(function () { $("#bb-warning-notice").remove(); }, 330); }); $(".bb-disconnect").on("click", function (e) { e.preventDefault(); $.bmi.modal("bb-disconnect-modal").open(); }); $(".bb-disconnect-cancel").on("click", function (e) { e.preventDefault(); $.bmi.modal("bb-disconnect-modal").close(); }); $(".bb-disconnect-btn").on("click", function(e){ e.preventDefault(); $.bmi.modal("bb-disconnect-modal").close(); $.bmi.modal("freeze-loading-modal").open(); $.bmi.ajax('bb-disconnect').then(function (res) { if (res.status == 'success') { $(".how-it-works").show(); $(".youre-connected").hide(); } else { $.bmi.alert('error', res.message); } $.bmi.modal('freeze-loading-modal').close(); }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'There was an error contacting the plugin backend.'); }); }); $(".bb-connect").on("click", function(e){ e.preventDefault(); $.bmi.modal("freeze-loading-modal").open(); $.bmi.ajax('bb-connect', { api_key: $(".api-key-input").val() }).then(function (res) { if (res.status == 'success') { refreshBBStorageInfo(); $(".how-it-works").hide(); $(".youre-connected").show(); $.bmi.reloadBackups(); } else { $.bmi.alert('error', res.message); } $.bmi.modal('freeze-loading-modal').close(); }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'There was an error contacting the plugin backend.'); }); }); $('#dropbox-connect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('get-dropbox-token').then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.token != 'undefined') { let url = 'https://authentication.backupbliss.com/v1/dropbox/connect'; url += '?token=' + encodeURIComponent(res.token); url += '&redirect=' + encodeURIComponent(window.location.origin + window.location.pathname); window.location.href = url; } else { $.bmi.alert('error', 'We could not generate individual token at this moment, please refresh page and try again [#Dropbox-02].'); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection [#Dropbox-01].'); }); }); $('#dropbox-disconnect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('disconnect-dropbox').then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status == 'success') { window.location.reload(); } else { $.bmi.alert('error', 'We could not disconnect you at this moment, please refresh page and try again.'); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection.'); }); }); function verifyDropboxConnection(silent = false) { $.bmi.ajax('verify-dropbox-connection', { uri: window.location.host }).then(function (res) { $('#dropbox-unauthenticated-box').show(); $('#dropbox-authenticated-box').hide(); if (typeof res.status != 'undefined' && typeof res.result != 'undefined' && res.status == 'success') { if (res.result == 'connected') { $('#dropbox-unauthenticated-box').hide(); $('#dropbox-authenticated-box').show(); } } else if (typeof res.status != 'undefined' && res.status == 'error') { if (!silent) { $.bmi.alert('error', 'We could not verify Dropbox connection, some error happened during communication with API, look for more details in global logs [#DB-07].'); } } else { if (!silent) { $.bmi.alert('error', 'We could not verify Dropbox connection, please refresh page and try again [#DB-05].'); } } }).catch(function (error) { if (!silent) { $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection [#DB-08].'); } }); } $('#bmi-pro-storage-dropbox-toggle').on('change', function (e) { e.preventDefault(); $('#dropbox-authenticated-box').hide(); $('#dropbox-unauthenticated-box').show(); if ($('#bmi-pro-storage-dropbox-toggle').is(':checked') === true) { verifyDropboxConnection(); } }); $('#bmip-dropbox-issues-dismiss').on("click", function () { $('#dropbox-issues').hide(300); setTimeout(function () { $('#dropbox-issues').remove(); }, 330); $.bmi.ajax('dismiss-dropbox-notice', {}).then(function (res) { }).catch(function (error) { }); }); $('#gdrive-connect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); let backupDirectoryPath = $('#bmip-googledrive-path').val(); $.bmi.ajax('get-gdrive-token', { backupDirectoryPath: backupDirectoryPath } ).then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.token != 'undefined') { let url = 'https://authentication.backupbliss.com/v1/gdrive/connect'; url += '?token=' + encodeURIComponent(res.token); url += '&redirect=' + encodeURIComponent(window.location.origin + window.location.pathname); window.location.href = url; } else { if (typeof res.status != 'undefined' && res.status === 'msg') { $.bmi.alert('warning', res.why); } else { $.bmi.alert('error', 'We could not generate individual token at this moment, please refresh page and try again [#GD-02].'); } } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection [#GD-01].'); }); }); $('#gdrive-disconnect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('disconnect-gdrive').then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status == 'success') { window.location.reload(); } else { $.bmi.alert('error', 'We could not disconnect you at this moment, please refresh page and try again [#GD-03].'); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection [#GD-04].'); }); }); function verifyGDriveConnection(silent = false) { $.bmi.ajax('verify-gdrive-connection', { uri: window.location.host }).then(function (res) { $('#gdrive-unauthenticated-box').show(); $('#gdrive-authenticated-box').hide(); if (typeof res.status != 'undefined' && typeof res.result != 'undefined' && res.status == 'success') { if (res.result == 'connected') { $('#gdrive-unauthenticated-box').hide(); $('#gdrive-authenticated-box').show(); } } else if (typeof res.status != 'undefined' && res.status == 'error') { if (!silent) { $.bmi.alert('error', 'We could not verify Google Drive connection, some error happened during communication with API, look for more details in global logs [#GD-07].'); } } else { if (!silent) { $.bmi.alert('error', 'We could not verify Google Drive connection, please refresh page and try again [#GD-05].'); } } }).catch(function (error) { if (!silent) { $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection [#GD-08].'); } }); } $('#bmi-pro-storage-gdrive-toggle').on('change', function (e) { e.preventDefault(); $('#gdrive-authenticated-box').hide(); $('#gdrive-unauthenticated-box').show(); if ($('#bmi-pro-storage-gdrive-toggle').is(':checked') === true) { verifyGDriveConnection(); } }); $('#ftp-connect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); let data = {}; data['bmip-ftp-host'] = $('#bmip-ftp-host-ip').val(); data['bmip-ftp-backup-dir'] = $('#bmip-ftp-backup-dir').val(); data['bmip-ftp-host-port'] = $('#bmip-ftp-host-port').val(); data['bmip-ftp-username'] = $('#bmip-ftp-user-name').val(); data['bmip-ftp-password'] = $('#bmip-ftp-password').val(); $.bmi.ajax('get-ftp-config', data).then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status === 'success') { if (e) $.bmi.alert('success', $('#bmi-save-connect-ftp').text(), 3000); setTimeout(function () { window.location.reload(); }, 300); } else { $.bmi.alert('error', res.msg); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', ''); }); }); $('#ftp-disconnect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('disconnect-ftp').then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status == 'success') { window.location.reload(); } else { $.bmi.alert('error', 'We could not disconnect you at this moment, please refresh page and try again [#GD-03].'); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection [#GD-04].'); }); }); $('#aws-connect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); let data = {}; data['access-key'] = $('#bmip-aws-access-key').val(); data['secret-key'] = $('#bmip-aws-secret-key').val(); data['bucket'] = $('#bmip-aws-bucket').val(); data['sse'] = $('#bmip-aws-sse').is(':checked') === true ? $('#bmip-aws-sse').val().trim() : ''; data['path'] = $('#bmip-aws-path').val(); data['storage-class'] = $('[data-id="bmip-aws-storage-class"]').attr('data-selected'); data['region'] = $('[data-id="bmip-aws-region"]').attr('data-selected'); $.bmi.ajax('save-aws-config', data).then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status === 'success') { if (e) $.bmi.alert('success', $('#bmi-save-connect-s3-success').text(), 3000); window.location.reload(); } else { $.bmi.alert('error', res.msg); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'There was an error while trying to connect to Amazon S3, please try again.'); }); }); $('#aws-disconnect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('disconnect-aws').then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status == 'success') { window.location.reload(); } else { $.bmi.alert('error', 'We could not disconnect you at this moment, please refresh page and try again.'); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection.'); }); }); function verifyAWSConnection(silent = false) { $.bmi.ajax('verify-aws-connection', { uri: window.location.host}).then(function (res) { $('#aws-unauthenticated-box').show(); $('#aws-authenticated-box').hide(); if (typeof res.status != 'undefined' && typeof res.result != 'undefined' && res.status == 'success') { if (res.result == 'connected') { $('#aws-unauthenticated-box').hide(); $('#aws-authenticated-box').show(); $('#bmip-aws-path').val(res.configs['path']).attr('readonly', true); $('#bmip-aws-bucket').val(res.configs['bucket']).attr('readonly', true); $('.bmi-dropdown[data-id="bmip-aws-storage-class"]').attr('data-selected', res.configs['storage-class']).val(res.configs['storage-class']).css('background', '#f1f1f1').css('pointerEvents', 'none'); $('#storage-s3-row .region-container').hide(); $('#storage-s3-row .aws-access-key-container').hide(); $('#storage-s3-row .aws-secret-key-container').hide(); $('#bmip-aws-sse').prop('checked', res.configs['sse'] === 'AES256').attr('disabled', true).css('cursor', 'not-allowed'); $('#bmip-aws-sse').closest('.checkbox-container').css('cursor', 'not-allowed'); } else { $('#aws-unauthenticated-box').show(); $('#aws-authenticated-box').hide(); } } else if (typeof res.status != 'undefined' && res.status == 'error') { if (!silent) { $.bmi.alert('error', 'We could not verify AWS S3 connection, some error happened during communication with API.'); } } else { if (!silent) { $.bmi.alert('error', 'We could not verify AWS S3 connection, please refresh page and try again.'); } } }).catch(function (error) { if (!silent) { $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection.'); } }); } $('#bmi-pro-storage-aws-toggle').on('change', function (e) { e.preventDefault(); $('#aws-authenticated-box').hide(); $('#aws-unauthenticated-box').show(); if ($('#bmi-pro-storage-aws-toggle').is(':checked') === true) { verifyAWSConnection(); } }); $('#wasabi-connect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); let data = {}; data['access-key'] = $('#bmip-wasabi-access-key').val(); data['secret-key'] = $('#bmip-wasabi-secret-key').val(); data['bucket'] = $('#bmip-wasabi-bucket').val(); data['path'] = $('#bmip-wasabi-path').val(); data['region'] = $('[data-id="bmip-wasabi-region"]').attr('data-selected'); $.bmi.ajax('save-wasabi-config', data).then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status === 'success') { if (e) $.bmi.alert('success', $('#bmi-save-connect-s3-success').text(), 3000); window.location.reload(); } else { $.bmi.alert('error', res.msg); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'There was an error while trying to connect to Wasabi, please try again.'); }); }); $('#wasabi-disconnect-btn').on('click', function (e) { e.preventDefault(); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('disconnect-wasabi').then(function (res) { $.bmi.modal('freeze-loading-modal').close(); if (typeof res.status != 'undefined' && res.status == 'success') { window.location.reload(); } else { $.bmi.alert('error', 'We could not disconnect you at this moment, please refresh page and try again.'); } }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection.'); }); }); function verifyWasabiConnection(silent = false) { $.bmi.ajax('verify-wasabi-connection', { uri: window.location.host}).then(function (res) { $('#wasabi-unauthenticated-box').show(); $('#wasabi-authenticated-box').hide(); if (typeof res.status != 'undefined' && typeof res.result != 'undefined' && res.status == 'success') { if (res.result == 'connected') { $('#wasabi-unauthenticated-box').hide(); $('#wasabi-authenticated-box').show(); $('#bmip-wasabi-path').val(res.configs['path']).attr('readonly', true); $('#bmip-wasabi-bucket').val(res.configs['bucket']).attr('readonly', true); $('#storage-wasabi-row .region-container').hide(); $('#storage-wasabi-row .wasabi-access-key-container').hide(); $('#storage-wasabi-row .wasabi-secret-key-container').hide(); } else { $('#wasabi-unauthenticated-box').show(); $('#wasabi-authenticated-box').hide(); } } else if (typeof res.status != 'undefined' && res.status == 'error') { if (!silent) { $.bmi.alert('error', 'We could not verify Wasabi connection, some error happened during communication with API.'); } } else { if (!silent) { $.bmi.alert('error', 'We could not verify Wasabi connection, please refresh page and try again.'); } } }).catch(function (error) { if (!silent) { $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection.'); } }); } $('#bmi-pro-storage-wasabi-toggle').on('change', function (e) { e.preventDefault(); $('#wasabi-authenticated-box').hide(); $('#wasabi-unauthenticated-box').show(); if ($('#bmi-pro-storage-wasabi-toggle').is(':checked') === true) { verifyWasabiConnection(); } }); $('#bmi_restore_tbody').on('click', '.can-be-manually-uploaded', function (e) { e.preventDefault(); const classList = $(this).attr('class').split(/\s+/); let type = false; let md5 = $(this).closest('tr').attr('md5'); for (let cls of classList) { if (cls.startsWith('strg-')) { type = cls.replace('strg-', ''); // get the part after 'strg-' break; } } $.bmi.ajax('manually-enqueue-upload', { type: type, md5: md5 }).then(function (res) { if (res.status == 'success') { $(this).removeClass('can-be-manually-uploaded'); $.bmi.alert('success', 'Backup will be added to the upload queue shortly.'); } else { $.bmi.alert('error', res.msg || 'There was an error while trying to enqueue the backup for upload.'); } }); }); $(window).on("bmi-preload-collapsed", function (e) { const urlSearchParams = new URLSearchParams(window.location.search); const params = Object.fromEntries(urlSearchParams.entries()); if (typeof params.bmi_drive != 'undefined') { window.history.pushState('', window.title, window.location.pathname + '?page=backup-migration'); if (typeof params.bmi_auth_status != 'undefined' && params.bmi_auth_status == 'error') { if (typeof params.bmi_error_reason != 'undefined') { if (params.bmi_drive == 'gdrive') { if (params.bmi_error_reason == '1') return $.bmi.alert('error', 'Error during Google Drive connection: We could not setup auth space for you at this moment. [#GD-11].'); if (params.bmi_error_reason == '2') return $.bmi.alert('error', 'Error during Google Drive connection: We could not check for existing authentication, please try again. [#GD-12].'); if (params.bmi_error_reason == '3') return $.bmi.alert('error', 'Error during Google Drive connection: We could not update your your auth token, please try again. [#GD-13].'); if (params.bmi_error_reason == '4') return $.bmi.alert('error', 'Error during Google Drive connection: Access has been denied by you during authorization. [#GD-14].'); if (params.bmi_error_reason == '5') return $.bmi.alert('error', 'Error during Google Drive connection: Some unexpected error happened (google side), please try again. [#GD-15].'); if (params.bmi_error_reason == '6') return $.bmi.alert('error', 'Error during Google Drive connection: Access token and refresh token has been revoked. [#GD-16].'); } else if (params.bmi_drive == 'dropbox') { if (params.bmi_error_reason == '1') return $.bmi.alert('error', 'Error during Dropbox connection: We could not setup auth space for you at this moment. [#DB-11].'); if (params.bmi_error_reason == '2') return $.bmi.alert('error', 'Error during Dropbox connection: We could not check for existing authentication, please try again. [#DB-12].'); if (params.bmi_error_reason == '3') return $.bmi.alert('error', 'Error during Dropbox connection: We could not update your your auth token, please try again. [#DB-13].'); if (params.bmi_error_reason == '4') return $.bmi.alert('error', 'Error during Dropbox connection: Access has been denied by you during authorization. [#DB-14].'); if (params.bmi_error_reason == '5') return $.bmi.alert('error', 'Error during Dropbox connection: Some unexpected error happened (dropbox side), please try again. [#DB-15].'); if (params.bmi_error_reason == '6') return $.bmi.alert('error', 'Error during Dropbox connection: Access token and refresh token has been revoked. [#DB-16].'); } } } if (typeof params.bmi_token == 'undefined' || typeof params.bmi_secret == 'undefined' || typeof params.bmi_auth_status == 'undefined') { if (params.bmi_drive == 'gdrive') { return $.bmi.alert('error', 'Cannot save connection with Google Drive, due to insufficient details [#GD-09].'); } else if (params.bmi_drive == 'dropbox') { return $.bmi.alert('error', 'Cannot save connection with Dropbox, due to insufficient details [#DB-09].'); } } if (params.bmi_auth_status != 'success') { if (params.bmi_drive == 'gdrive') { return $.bmi.alert('error', 'Cannot save connection with Google Drive, due to unknown response from Google API [#GD-10].'); } else if (params.bmi_drive == 'dropbox') { return $.bmi.alert('error', 'Cannot save connection with Dropbox, due to unknown response from Dropbox API [#DB-10].'); } } $.bmi.modal('freeze-loading-modal').open(); $('#bmi-external-storage-options').click(); if (params.bmi_drive == 'gdrive') { if ($('#bmi-pro-storage-gdrive-toggle').is(':checked') === false) { $('#bmi-pro-storage-gdrive-toggle').click(); } } else if (params.bmi_drive == 'dropbox') { if ($('#bmi-pro-storage-dropbox-toggle').is(':checked') === false) { $('#bmi-pro-storage-dropbox-toggle').click(); } } if (params.bmi_drive == 'gdrive') { $.bmi.ajax('keep-gdrive-connection', { receivedToken: params.bmi_token, receivedClientID: params.bmi_secret }).then(function (res) { $.bmi.modal('freeze-loading-modal').close(); setTimeout(function () { $('#bmi-pro-storage-gdrive-toggle')[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); setTimeout(function () { $('#gdrive-unauthenticated-box').fadeOut(); $('#gdrive-authenticated-box').fadeIn(); setTimeout(function () { $('#gdrive-authed-content-box')[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); window.saveStorageWithoutClose = true; $('#storage-options').find('.save-btn').click(); }, 300); }, 300); }, 300); }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot save connection with Google Drive, please try again [#GD-06].'); }); } else if (params.bmi_drive == 'dropbox') { $.bmi.ajax('keep-dropbox-connection', { receivedToken: params.bmi_token, receivedClientID: params.bmi_secret }).then(function (res) { $.bmi.modal('freeze-loading-modal').close(); setTimeout(function () { $('#bmi-pro-storage-dropbox-toggle')[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); setTimeout(function () { $('#dropbox-unauthenticated-box').fadeOut(); $('#dropbox-authenticated-box').fadeIn(); setTimeout(function () { $('#dropbox-authed-content-box')[0].scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); window.saveStorageWithoutClose = true; $('#storage-options').find('.save-btn').click(); }, 300); }, 300); }, 300); }).catch(function (error) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.alert('error', 'Cannot save connection with Dropbox, please try again [#DB-06].'); }); } else { jQuery(window).trigger("bmi-preload-collapsed-pro", [params]); } } if ($('#bmi-pro-storage-dropbox-toggle').is(':checked') === true) { verifyDropboxConnection(true); } if ($('#bmi-pro-storage-gdrive-toggle').is(':checked') === true) { verifyGDriveConnection(true); } if ($('#bmi-pro-storage-aws-toggle').is(':checked') === true) { verifyAWSConnection(true); } if ($('#bmi-pro-storage-wasabi-toggle').is(':checked') === true) { verifyWasabiConnection(true); } }); // Currently not used $('.bmi-check-disk-space').on('click', function (e) { e.preventDefault(); // Prevent multiple clicks if (!$('.space-checking .loading').hasClass('hide_verbose')) return; $('.space-checking .loading').removeClass('hide_verbose'); // Hide all verbose messages if any shown if (!$('.checking-result .not-enough-space').hasClass('hide_verbose')) $('.checking-result .not-enough-space').addClass('hide_verbose'); if (!$('.checking-result .enough-space').hasClass('hide_verbose')) $('.checking-result .enough-space').addClass('hide_verbose'); if (!$('.checking-result .failed').hasClass('hide_verbose')) $('.checking-result .failed').addClass('hide_verbose'); $.bmi.ajax('check-disk-space').then(function (res) { if (res.status == 'enough-space') { $('.space-checking .loading').addClass('hide_verbose'); $('.checking-result .enough-space').removeClass('hide_verbose'); } else if (res.status == 'not-enough-space') { $('.space-checking .loading').addClass('hide_verbose'); $('.checking-result .not-enough-space').removeClass('hide_verbose'); $('.checking-result .not-enough-space').find('.required-space').text(res.data['required']); $('.checking-result .not-enough-space').find('.available-space').text(res.data['available']); } }).catch(function (error) { console.error(error); $('.space-checking .loading').addClass('hide_verbose'); $('.checking-result .failed').removeClass('hide_verbose'); }); }); async function tryInDifferentWay() { let errorParent = $.bmi.modal("error-modal").getParent(); if (errorParent == "backup-progress-modal") { if (isNaN(getSelectedSize())) { setTimeout(tryInDifferentWay, 1000); } $("#cli-disable-others").prop("checked", true); $("#experimental-hard-timeout").prop("checked", true); $("#download-technique").prop("checked", true); $("#bmi-db-batching-backup").prop("checked", true); $("#bmi-use-new-database-export-engine").prop("checked", true); await saveOtherOptionsPromise(); $.bmi.modal($(this).closest(".bmi-modal").attr("id")).close(); $("#start-entire-backup").click(); } else if (errorParent == "restore-progress-modal") { $("#cli-disable-others").prop("checked", true); $("#file_limit_extraction_max").val("300"); await saveOtherOptionsPromise(); $.bmi.modal($(this).closest(".bmi-modal").attr("id")).close(); $("#restore-start-sure").click(); } } function bmiSetFailureReasonsState(reasonCount) { const $plural = $(".there-are-reasons"); const $single = $(".there-is-a-reason"); const $none = $(".there-are-no-reasons"); const $box = $(".debug-it-yourself"); const $content = $box.find(".content"); // Hide all first $plural.hide(); $single.hide(); $none.hide(); if (reasonCount <= 0) { $none.show(); $box.removeClass("active"); $content.css("display", "none"); } else if (reasonCount === 1) { $single.show(); $box.addClass("active"); $content.css("display", "block"); } else { $plural.show(); $box.addClass("active"); $content.css("display", "block"); } } async function setupRestoreErrorOptions() { $.bmi.modal("freeze-loading-modal").open(); $("#error-modal").find(".modal-title").text($("#bmi-restore-error-modal-title").text()); const tryInDifferentWayBtn = $(".try-in-different-way"); const tryInDifferentWayOption = tryInDifferentWayBtn.closest(".failure-option"); const failureReasons = $(".failure-reasons"); if ( !$("#cli-disable-others").is(":checked") || $("#file_limit_extraction_max").val() != "300" ) { tryInDifferentWayOption.show(); } else { tryInDifferentWayOption.hide(); } try { const res = await $.bmi.ajax("check-comptability", { for: "restore" }); $.bmi.modal("freeze-loading-modal").close(); failureReasons.empty(); let reasonCount = 0; if (res.status === "success" ) { if (Array.isArray(res.data) && res.data.length > 0) { res.data.forEach(r => failureReasons.append("<li>" + r + "</li>")); reasonCount = failureReasons.find("li").length; } if (res.mainReasonFound) { tryInDifferentWayOption.hide(); } } bmiSetFailureReasonsState(reasonCount); setupDownloadLogsHref("restore"); } catch (error) { console.log(error); $.bmi.modal("freeze-loading-modal").close(); } } async function setupBackupErrorOptions() { $.bmi.modal("freeze-loading-modal").open(); $("#error-modal").find(".modal-title").text($("#bmi-error-modal-title").text()); const tryInDifferentWayBtn = $(".try-in-different-way"); const tryInDifferentWayOption = tryInDifferentWayBtn.closest(".failure-option"); const failureReasons = $(".failure-reasons"); if ( !$("#cli-disable-others").is(":checked") || !$("#experimental-hard-timeout").is(":checked") || !$("#download-technique").is(":checked") || !$("#bmi-db-batching-backup").is(":checked") || !$("#bmi-use-new-database-export-engine").is(":checked") ) { if (!tryInDifferentWayOption.hasClass("force_hide")) { tryInDifferentWayOption.show(); } } else { tryInDifferentWayOption.hide(); } try { const res = await $.bmi.ajax("check-comptability", { for: "backup" }); $.bmi.modal("freeze-loading-modal").close(); failureReasons.empty(); let reasonCount = 0; if (res.status === "success" && Array.isArray(res.data) && res.data.length > 0) { res.data.forEach(r => failureReasons.append("<li>" + r + "</li>")); reasonCount = failureReasons.find("li").length; } bmiSetFailureReasonsState(reasonCount); setupDownloadLogsHref("backup"); } catch (error) { console.log(error); $.bmi.modal("freeze-loading-modal").close(); } } async function fillLogs( type = "backup", preElement = $(".log-wrapper").find("pre")[0], logPath = "?backup-migration=PROGRESS_LOGS&progress-id=latest_full.log&uncensored=true&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(), ) { let url = $("#BMI_BLOG_URL").text().trim(); if (url.slice(-url.length) !== "/") url = url + "/"; if (type === "backup") logPath += "&progress-id=latest_full.log"; else if (type === "restore") logPath += "&progress-id=latest_migration_full.log"; return new Promise((resolve, reject) => { httpGet(url + logPath, function (log) { let res1 = log.split("\n").slice(0, 1)[0]; if (res1.trim() === "") { res1 = log.split("\n").slice(0, 2)[1]; log = log.split("\n").slice(2).join("\n"); } else { log = log.split("\n").slice(1).join("\n"); } if (log && log != false && typeof log !== "undefined") { if (log === false) { reject("Error: Failed to retrieve backup logs"); return; } let lines = log.split("\n"); if (lines.length >= 1) lines = lines.slice(0, -1); preElement.innerText = ""; showAllLines(preElement, lines); resolve(); } else { reject("Error: Failed to retrieve backup logs"); } }); }); } function runStagingTimers() { setInterval(function () { $trs = $(".bmi-tastewp-staging-row"); $trs.each(function (i) { let $tr = $($trs[i]); let expiration = $tr.attr("expiration"); if (expiration && !isNaN(parseInt(expiration))) { expiration = parseInt(expiration); $tr .find(".stg-tr-expiration span") .text($.bmi.getExpirationTime(expiration)); } }); }, 1000); } function setupLogsModal() { let errorParent = $.bmi.modal("error-modal").getParent(); let type = ""; if (errorParent == "backup-progress-modal") { $("#logs-modal").find(".modal-title").text($('#bmi-backup-logs-modal-title').text()); type = "backup"; } else if (errorParent == "restore-progress-modal") { $("#logs-modal").find(".modal-title").text($('#bmi-restore-logs-modal-title').text()); type = "restore"; } let preElement = $("#logs-modal").find("pre")[0]; fillLogs(type, preElement).then(function () { $.bmi.modal("freeze-loading-modal").close(); setTimeout(function () { $.bmi.modal("logs-modal").open(); preElement.scroll({ top: preElement.scrollHeight }); }, 300); }); } function fillRestoreLogs() { let textarea = $('#restore-log')[0]; textarea.value = restoreLogs; } function setupDownloadLogsHref(type = "backup") { let url = $("#BMI_BLOG_URL").text().trim(); if (url.slice(-url.length) !== "/") url = url + "/"; $progressId = type == "backup" ? "latest_full.log" : "latest_migration_full.log"; let logs_url = url + "?backup-migration=PROGRESS_LOGS&progress-id=" + $progressId + "&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); $(".download-log-url.censored").attr("download", "secure-" + (type == "backup" ? "backup" : "restore") + "-logs.txt") $(".download-log-url.uncensored").attr("download", (type == "backup" ? "backup" : "restore") + "-logs.txt") $(".download-log-url.censored").attr("href", logs_url); $(".download-log-url.uncensored").attr("href", logs_url + "&uncensored=true"); } function getCurrentRestore() { return current_restore; } function getIsDownloadBackupFinished() { return downloadBackupFinished; } $.bmi.getCurrentRestore = getCurrentRestore; $.bmi.getIsDownloadBackupFinished = getIsDownloadBackupFinished; function updateSuffixPosition() { let localBackupsPath = document.getElementById('bmi_path_storage_default'); let localBackupsPathSuffix = document.getElementById('local-backups-suffix'); let textWidth = getTextWidth(localBackupsPath.value, window.getComputedStyle(localBackupsPath).font); let suffixWidth = getTextWidth(localBackupsPathSuffix.innerText, window.getComputedStyle(localBackupsPathSuffix).font); localBackupsPath.style.paddingRight = suffixWidth + 22 + 'px'; if (localBackupsPath.value === '') { localBackupsPathSuffix.style.display = 'none'; return; } else { localBackupsPathSuffix.style.display = 'inline-block'; } localBackupsPathSuffix.style.left = Math.min(textWidth + 20, localBackupsPath.clientWidth - suffixWidth - 20) + 'px'; } function getTextWidth(text, font) { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); ctx.font = font; return ctx.measureText(text).width; } $('#bmi_path_storage_default').on('input', updateSuffixPosition); $('#storage-options').on('click', function() { setTimeout(() => { updateSuffixPosition(); }, 100); setTimeout(() => { updateSuffixPosition(); }, 300); }); $('#bmi_backup_search_input').on('input', function() { if ($(this).hasClass('processing')) return; $(this).addClass('processing'); let searchTerm = $(this).val().toLowerCase(); if (searchTerm.trim() === '') { $.bmi.reloadBackups(); $(this).removeClass('processing'); return; } $.bmi.searchInBackups(searchTerm); setTimeout(() => { $(this).removeClass('processing'); }, 500); }); $('#bmi_backup_search_input').on('keypress', function(e) { if (e.which === 13) { e.preventDefault(); let searchTerm = $(this).val().toLowerCase(); if (searchTerm.trim() === ''){ $.bmi.reloadBackups(); return; } $.bmi.searchInBackups(searchTerm); } }); $(window).on('resize', updateSuffixPosition); $(document).on('visibilitychange', async function() { if ((backupOnGoing || restoreOnGoing) && document.visibilityState === 'visible') { await $.bmi.requestWakeLock(); } }); $('#resync-with-ping-server').on('click', function(e) { e.preventDefault(); $.bmi.ajax('resync-with-ping-server').then(function (res) { if (res.status == 'success') { $.bmi.alert('success', 'Your site has been registered successfully with our ping server.'); } else { $.bmi.alert('error', res.msg || 'There was an error while trying to resync with ping server.'); } }).catch(function (error) { $.bmi.alert('error', 'Cannot send request to your server, please check your internet connection.'); }); }); // Init (function () { if (pagenow !== 'toplevel_page_backup-migration') return; scanDirectories(); getAndInsertDynamicNames(); $.bmi.reloadBackups(); $.bmi.adjustStorageIcons(); $.bmi.reloadStaging(); runTimerST(); runStagingTimers(); let url_x = $("#BMI_BLOG_URL").text().trim(); if (url_x.slice(-url_x.length) !== "/") url_x = url_x + "/"; let logs_backup = url_x + "?backup-migration=PROGRESS_LOGS&progress-id=latest.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); let logs_backup_uncensored = url_x + "?backup-migration=PROGRESS_LOGS&progress-id=latest.log&uncensored=true&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); let logs_restore = url_x + "?backup-migration=PROGRESS_LOGS&progress-id=latest_migration.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); let logs_staging = url_x + "?backup-migration=PROGRESS_LOGS&progress-id=latest_staging.log&bmi-id=current&t=" + +new Date() + "&sk=" + $("#BMI_SECRET_KEY").text().trim(); $(".download-backup-log-url").attr("href", logs_backup); $(".download-backup-log-url.uncensored").attr( "href", logs_backup_uncensored, ); $(".download-restore-log-url").attr("href", logs_restore); $(".download-staging-log-url").attr("href", logs_staging); })(); }); jQuery(document).ready(function($) { $('.bmi-modal-opener').on('click', function(e) { if (this.getAttribute('data-modal') && this.getAttribute('data-modal') != '') { e.preventDefault(); if (this.getAttribute('data-close')) $.bmi.modal(this.getAttribute('data-close')).close(); $.bmi.modal(this.getAttribute('data-modal')).open(); } }); $('.bmi-modal-closer').on('click', function(e) { if (this.getAttribute('data-close') && this.getAttribute('data-close') != '') { e.preventDefault(); $.bmi.modal(this.getAttribute('data-close')).close(); } else { if (this.closest('.bmi-modal')) { e.preventDefault(); if ($('#' + this.closest('.bmi-modal').getAttribute('id')).length > 0) $.bmi.modal(this.closest('.bmi-modal').getAttribute('id')).close(); } } }); $('.bmi-modal-close').on('click', function(e) { if (this.closest('.bmi-modal')) { e.preventDefault(); $.bmi.modal(this.closest('.bmi-modal').id).close(); } }); $('.bmi-modal').on('click', function(e) { if (e.target == this && !$(e.target).hasClass('bmi-modal-no-close')) { $.bmi.modal(this.id).close(); } }); $('.bmi-modal-back').on('click', function(e) { if (this.closest('.bmi-modal')){ e.preventDefault(); let modal = $.bmi.modal(this.closest('.bmi-modal').id); let modalParent = modal.getParent(); if ( modalParent ){ modal.close(); $.bmi.modal(modalParent).open(); } } }); });jQuery(document).ready(function($) { // Init tooltips if(pagenow === 'toplevel_page_backup-migration') $.bmi.tooltips.init(); // Progress interval let upload_progress, current_last = -1, startmsg = false; // Replace pleaceholders with real preloaders let preloader_divs = ''; for (let i = 0; i < 12; ++i) preloader_divs += '<div></div>'; $('.spinner-loader').html(preloader_divs).addClass('lds-spinner'); function setProgress(end = 0, duration = 1000) { if (current_last == end) return; else current_last = end; clearInterval(upload_progress); let start = parseInt($('.upload-percentage').text()) - 1; if (start > end && end != 0) return; let range = end - start; let current = start; let increment = 1; let stepTime = Math.abs(Math.floor(duration / range)); upload_progress = setInterval(function() { current += increment; $('.upload-progress-bar').find('span')[0].style.width = current + '%'; $('.upload-percentage').text(current + '%'); if (current >= 100) { clearInterval(upload_progress); current_last = null; } }, stepTime); } function Progress(value) { clearInterval(upload_progress); if (value == 0) { $('.upload-progress-bar').find('span')[0].style.width = value + '%'; $('.upload-percentage').text(value + '%'); } else if (value == 100) { $('.upload-progress-bar').find('span')[0].style.width = value + '%'; $('.upload-percentage').text(value + '%'); } else { $('.upload-progress-bar').find('span')[0].style.width = value + '%'; $('.upload-percentage').text(value + '%'); // setProgress(value, 300); } } $.fchunker({ upId: 'upid', upShardSize: bmiVariables.maxUploadSize, upMaxSize: '2000', upUrl: ajaxurl + '?cache=false', upType: 'zip,tar,gz', bmiNonce: bmiVariables.nonce, upCallBack: function(res) { var status = res.status; var msg = res.message; var url = res.url + "?" + Math.random(); if (status == 2) { setTimeout(function() { $('#drop-area').show(300); $('.upload-progress').hide(300); }, 100); $.bmi.alert('success', $('#bmi-upload-end').text(), 3000); $.bmi.modal('upload-success-modal').open(); $.bmi.reloadBackups(); } if (status == 1) { // console.log(msg); if (!startmsg) { $.bmi.alert('success', $('#bmi-upload-start').text(), 3000); startmsg = true; } } if (status == 0) { $.upErrorMsg(msg); $('#drop-area').show(300); $('.upload-progress').hide(300); } if (status == 5) { $.bmi.modal('upload-invalid-manifest-modal').open(); $('#drop-area').show(300); $('.upload-progress').hide(300); } if (status == 3) { Progress(100); $.upErrorMsg(msg); $('#drop-area').show(300); $('.upload-progress').hide(300); } }, upEvent: function(num) { Progress(num); }, upStop: function(errmsg) { Progress(0); setTimeout(function() { $('#drop-area').show(300); $('.upload-progress').hide(300); }, 100); if (errmsg.includes('Type error')) { $.bmi.modal('upload-wrong-file-modal').open(); $.bmi.alert('warning', $('#bmi-upload-wrong').text(), 3000); } else if (errmsg.includes('File already exists')) { $.bmi.modal('upload-exist-file-modal').open(); $.bmi.alert('warning', $('#bmi-upload-exists').text(), 3000); } else { $.bmi.alert('error', $('#bmi-upload-error').text(), 3000); console.error(errmsg); } }, upStart: function() { startmsg = false; current_last = -1; Progress(0); setTimeout(function() { $('#drop-area').hide(300); $('.upload-progress').show(300); }, 100); } }); }); // function bmi_debug_function(data = {}) { // // jQuery.bmi.ajax('debugging', data).then(function(res) { // // console.log(res); // // }).catch(function(error) { // // console.log(error); // // }); // // } jQuery(document).ready(function($) { function setRadios(radios) { for (let i = 0; i < radios.length; ++i) { let c = radios[i].closest('.container-radio'); if (c && typeof c.classList != undefined) { c.classList.remove('active'); if (radios[i].checked === true) { c.classList.add('active'); } } } } $('input[type="radio"]').on('change', function() { let name = this.getAttribute('name'); let container = this.closest('.container-radio'); let radios = document.querySelectorAll('[name="' + name + '"]'); setRadios(radios); }); (function() { if (pagenow !== 'toplevel_page_backup-migration') return; let radios = document.getElementById('bmi').querySelectorAll('input[type="radio"]'); setRadios(radios); })(); });jQuery(document).ready(function($) { let current_last = null; let logs_progress = null; let timeouter = null; let isLineAppendTimeoutRunning = false; let latestLines = []; let curmaxnum = 0; let curdivs = 0; let latestStep = ''; let lineAppender = null; let endCodeCall = null; let nextBatchStop = false; async function repeatLogUpdate() { clearTimeout(timeouter); updateStagingLogs(); initializeStagingLogsUpdater(true); } async function initializeStagingLogsUpdater(selfcall = false) { if (selfcall == false) { $('#staging-live-log-wrapper .log-wrapper').find('pre')[0].innerText = ''; $('#staging-progress-modal .progress-active-bar')[0].style.width = '0%'; $('#staging-progress-modal .progress-percentage')[0].style.left = '0%'; $('#staging-progress-modal .progress-percentage')[0].innerText = '0%'; setProgressStaging(0); repeatLogUpdate(); } else { timeouter = setTimeout(repeatLogUpdate, 1500); } } function endStagingLogerUpdater() { clearInterval(logs_progress); clearTimeout(lineAppender); clearTimeout(endCodeCall); clearTimeout(timeouter); latestStep = ''; latestLines = []; curmaxnum = 0; curdivs = 0; isLineAppendTimeoutRunning = false; } function insertPre(log, el) { if (log === false) return; let lines = log.split('\n'); if (lines.length >= 1) lines = lines.slice(0, -1); latestLines = lines; if (isLineAppendTimeoutRunning == false) { if (curdivs < latestLines.length) { showNextLine(el); } } } function httpGet(theUrl) { return new Promise(function(resolve) { let isHttps = window.location.protocol.includes('https'); let isUrlHttps = theUrl.includes('https'); if (isUrlHttps) theUrl = theUrl.slice(5); else theUrl = theUrl.slice(4); if (isHttps) theUrl = 'https' + theUrl; else theUrl = 'http' + theUrl; try { if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject('Microsoft.XMLHTTP'); } xmlhttp.onloadend = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { return resolve(xmlhttp.responseText); } else return resolve(false); } xmlhttp.open('GET', theUrl); xmlhttp.send(); } catch (e) { return resolve(false); } }); } function setProgressStaging(end = 0, duration = 1500) { if (current_last == end) return; else current_last = end; clearInterval(logs_progress); let start = parseFloat($('#staging-progress-modal .progress-percentage')[0].style.left) - 1; let range = end - start; let current = start; let increment = 1; let stepTime = Math.abs(Math.floor(duration / range)); logs_progress = setInterval(function() { current += increment; $('#staging-progress-modal .progress-active-bar')[0].style.width = (current).toFixed(2) + '%'; $('#staging-progress-modal .progress-percentage')[0].style.left = (current).toFixed(2) + '%'; $('#staging-progress-modal .progress-percentage')[0].innerText = (current).toFixed(0) + '%'; if (current >= 100) { current_last = null; clearInterval(logs_progress); } if (current > end) clearInterval(logs_progress); }, stepTime); } async function updateStagingLogs() { return new Promise(async function (resolve) { let url = $('#BMI_BLOG_URL').text().trim(); if (url.slice(-url.length) !== '/') url = url + '/'; let res = await httpGet(url + '?backup-migration=PROGRESS_LOGS&progress-id=latest_staging_full.log&bmi-id=current&t=' + +new Date() + '&sk=' + $('#BMI_SECRET_KEY').text().trim()); if (!res) return resolve(); let progress = res.split('\n').slice(0, 1)[0]; res = res.split('\n').slice(1).join('\n'); if (progress === false || isNaN(parseFloat(progress))) return resolve(); let pre = $('#staging-live-log-wrapper').find('pre')[0]; if (!res.includes('<') && !res.includes('>')) { if (res && res != false && typeof res !== 'undefined') { insertPre(res, pre); } } setProgressStaging(progress); return resolve(); }); } function showNextLine(el) { let mostRecentStep = ''; let delayedDisplayTime = 40; let line = latestLines[curdivs]; let div = document.createElement('DIV'); let color = ''; if (typeof line == 'undefined' || !line) return; if (line.substr(0, 6) == '[INFO]') color = 'blue'; else if (line.substr(0, 9) == '[SUCCESS]') color = 'green'; else if (line.substr(0, 6) == '[WARN]') color = 'orange'; else if (line.substr(0, 7) == '[ERROR]') color = 'red'; else if (line.substr(0, 10) == '[END-CODE]') color = 'hide_so_much'; else if (line.substr(0, 9) == '[VERBOSE]') color = 'hide_verbose'; else if (line.substr(0, 6) == '[STEP]') { div.classList.add('bold'); div.classList.add('step'); } else { if (line && line.trim().length > 0 && line[0] != '[') { curdivs--; } } if (line.substr(0, 6) == '[STEP]') mostRecentStep = line.slice(29); if (color.length > 0) div.classList.add(color); div.style.display = 'none'; div.innerText = line; el.appendChild(div); let endCodeFound = goThroughEndCodes(); $(div).show(delayedDisplayTime, function () { if (mostRecentStep != '' && mostRecentStep != latestStep) { latestStep = mostRecentStep; $('#staging_current_step').text(mostRecentStep); } }); el.scrollTop = el.scrollHeight; curdivs++; if (curdivs < latestLines.length && endCodeFound == false) { isLineAppendTimeoutRunning = true; lineAppender = setTimeout(function () { showNextLine(el); }, delayedDisplayTime); } else { isLineAppendTimeoutRunning = false; } } function goThroughEndCodes() { let mostRecentStep = ''; let endCodeFound = false; for (let i = 0; i < latestLines.length; ++i) { let line = latestLines[i]; if (line.substr(0, 6) == '[STEP]') mostRecentStep = line.slice(29); else if (!endCodeFound && line && line.trim().includes('[END-CODE]')) { endCodeFound = true; clearTimeout(endCodeCall); if (line.includes('001')) endCodeCall = setTimeout(stagingCreationSuccess, 2500); else endCodeCall = setTimeout(stagingCreationFailed, 2500); } } return endCodeFound; } function stagingCreationSuccess() { endStagingLogerUpdater(); $.bmi.modal('freeze-loading-modal').close(); $.bmi.modal('staging-progress-modal').close(); $.bmi.modal('staging-error-modal').close(); $.bmi.modal('staging-success-modal').open(); } function stagingCreationFailed(hideDefault = false) { $('#after-logs-sent-modal').attr('data-error-source', 'staging'); endStagingLogerUpdater(); $.bmi.modal('freeze-loading-modal').close(); $.bmi.modal('staging-progress-modal').close(); $.bmi.modal('staging-success-modal').close(); $.bmi.modal('staging-error-modal').open(); if (!hideDefault) { let errorNotice = $('#stg-notices-button').attr('c-errorProcess'); $.bmi.alert('error', errorNotice, 5000); } } function abortCreationProcess(name) { endStagingLogerUpdater(); $.bmi.modal('freeze-loading-modal').close(); $.bmi.modal('staging-progress-modal').close(); $.bmi.modal('staging-success-modal').close(); $.bmi.modal('staging-error-modal').close(); $.bmi.alert('info', $('#bmi-stg-aborted-al').text(), 3000); $.bmi.reloadStaging(); } function callLocalStagingCreationProcess(data, continuation = false) { return new Promise(function(resolve) { let endpoint = 'staging-start-local-creation'; if (!continuation) { $.bmi.modal('freeze-loading-modal').open(); } else { endpoint = 'staging-local-creation-process'; } $.bmi.ajax(endpoint, data).then(function(res) { if (!continuation) { $.bmi.modal('freeze-loading-modal').close(); $.bmi.modal('staging-progress-modal').open(); } if (res.status == 'success') { $('#bmi-tastewp-staging-success-text').hide(); $('#bmi-local-staging-success-text').show(); $('.bmi-staging-success-img-normal').addClass('bmi-image-hide'); $('.bmi-staging-success-img-tastewp').addClass('bmi-image-hide'); $('.bmi-staging-success-img-normal').removeClass('bmi-image-hide'); $('#bmi-stg-subname-input').val(''); $.bmi.reloadStaging(); let loginURL = `${res.url}/wp-login.php?autologin=true&user=${res.userid}&secret=${res.password}`; $('#bmi-visit-latest-staging').attr('href', loginURL); $('#bmi-staging-latest-url').attr('href', loginURL); endCodeCall = setTimeout(stagingCreationSuccess, 500); } else if (res.status == 'continue') { if (!continuation) initializeStagingLogsUpdater(); if (nextBatchStop) res['data']['delete'] = true; callLocalStagingCreationProcess(res['data'], true); } else if (res.status == 'fail') { stagingCreationFailed(true); return $.bmi.alert('warning', res.message, 5000); } else if (res.status == 'deleted') { abortCreationProcess(res['name']); } else { stagingCreationFailed(); } }).catch(function(error) { stagingCreationFailed(); console.error(error); }); }); } function callTasteWPStagingCreationProcess(data, initialize = false) { return new Promise(function(resolve) { let endpoint = 'staging-tastewp-creation-process'; if (initialize) { $.bmi.modal('freeze-loading-modal').open(); data['initialize'] = true; } $.bmi.ajax(endpoint, data).then(function(res) { if (res.status == 'success') { $.bmi.reloadStaging(); let accessURL = `${res.url}`; $('#bmi-visit-latest-staging').attr('href', accessURL); $('#bmi-staging-latest-url').attr('href', accessURL); $('#bmi-staging-latest-url').text(accessURL); $('#bmi-tastewp-staging-success-text').show(); $('#bmi-local-staging-success-text').hide(); $('.bmi-staging-success-img-normal').addClass('bmi-image-hide'); $('.bmi-staging-success-img-tastewp').addClass('bmi-image-hide'); $('.bmi-staging-success-img-tastewp').removeClass('bmi-image-hide'); endCodeCall = setTimeout(stagingCreationSuccess, 500); } else if (res.status == 'continue') { if (initialize) { initializeStagingLogsUpdater(); $.bmi.modal('freeze-loading-modal').close(); $.bmi.modal('staging-progress-modal').open(); } if (nextBatchStop) res['data']['delete'] = true; callTasteWPStagingCreationProcess(res['data']); } else if (res.status == 'fail') { stagingCreationFailed(true); return $.bmi.alert('warning', res.message, 5000); } else if (res.status == 'deleted') { abortCreationProcess(res['name']); } else { stagingCreationFailed(); } }).catch(function(error) { stagingCreationFailed(); console.error(error); }); }); } $('#bmi').on('click', '.bmi-stg-sel-box', function (e) { if ($(this)[0].classList.contains('bmi-active')) return; if (e.target.tagName == 'A') return; $('.bmi-stg-sel-box.bmi-active').removeClass('bmi-active'); $(this).addClass('bmi-active'); if ($(this).data('mode') == 'tastewp') { $('.bmi-stg-creation-box-local').hide(300); $('.bmi-stg-creation-box-tastewp').hide(300); $('.bmi-stg-creation-box-tastewp-empty').hide(300); if ($('.bmi-stg-drop-option:not(.bmi-stg-option-template)').length > 0) { $('.bmi-stg-creation-box-tastewp').show(300); } else { $('.bmi-stg-creation-box-tastewp-empty').show(300); } } else { $('.bmi-stg-creation-box-local').show(300); $('.bmi-stg-creation-box-tastewp').hide(300); $('.bmi-stg-creation-box-tastewp-empty').hide(300); } }); $('.bmi-stg-dropdown-area-selector').on('click', function () { $('.bmi-stg-dropdown-area').toggleClass('bmi-active'); }); $('body').on('click', ':not(.bmi-stg-dropdown-area)', function (e) { if (!e.target.closest('.bmi-stg-dropdown-area')) { $('.bmi-stg-dropdown-area').removeClass('bmi-active'); } }); $('.bmi-stg-dropdown-area-inner-scroll').on('click', '.bmi-stg-drop-option', function (e) { let name = $(this).attr('backup-name'); let date = $(this).find('.bmi-stg-option-date i').text(); let size = $(this).find('.bmi-stg-option-size i').text(); $('.bmi-stg-drop-option.active').removeClass('active'); $(this).addClass('active'); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-name').text(name); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-date i').text(date); $('.bmi-stg-dropdown-area-selector').find('.bmi-stg-option-size i').text(size); $('#bmi-stg-current-backup-selected').val(name); $('.bmi-stg-dropdown-area').removeClass('bmi-active'); }); $('.i-staging-creator-tastewp').on('click', function () { let backupName = $('.bmi-stg-dropdown-area-selector .bmi-stg-option-name').text(); $('#stg-prenotice-mode-local').hide(); $('#stg-prenotice-mode-tastewp').show(); $('#start-entire-staging').attr('mode', 'tastewp'); $('#bmi-staging-local-current-backup').text(backupName); $.bmi.modal('staging-prenotice-modal').open(); }); $('.i-staging-creator-local').on('click', function () { let name = $('#bmi-stg-subname-input').val().trim(); let empty = $(this).attr('c-empty'); let long = $(this).attr('c-long'); let errorNotice = $(this).attr('c-error'); let invalid = $(this).attr('c-invalid'); let validRegex = /^[a-zA-Z0-9-_]+$/; if (name.length <= 0) { return $.bmi.alert('warning', empty, 5000); } if (!validRegex.test(name)) { return $.bmi.alert('warning', invalid, 5000); } if (name.length >= 24) { return $.bmi.alert('warning', long, 5000); } $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('staging-local-name', { name: name }).then(function(res) { $.bmi.modal('freeze-loading-modal').close(); if (res.status == 'success') { let url = $('#bmi-stg-homeurl').text() + $('#bmi-stg-subname-input').val(); $('#stg-prenotice-mode-local').show(); $('#stg-prenotice-mode-tastewp').hide(); $('#bmi-staging-local-current-url').text(url); $('#bmi-staging-latest-url').text(url); $('#bmi-staging-latest-url, #bmi-visit-latest-staging').attr('href', url); $('#start-entire-staging').attr('mode', 'local'); // tastewp for TWP $.bmi.modal('staging-prenotice-modal').open(); } else if (res.status == 'fail') { return $.bmi.alert('warning', res.message, 5000); } else { return $.bmi.alert('error', errorNotice, 5000); } }).catch(function(error) { $.bmi.modal('freeze-loading-modal').close(); return $.bmi.alert('error', errorNotice, 5000); console.error(error); }); }); $('#start-entire-staging').on('click', function (e) { e.preventDefault(); $.bmi.modal('staging-prenotice-modal').close(); nextBatchStop = false; if ($(this).attr('mode') == 'local') { let name = $('#bmi-stg-subname-input').val().trim(); callLocalStagingCreationProcess({ name: name }); } else if ($(this).attr('mode') == 'tastewp') { let currMills = +new Date() + ''; let name = Math.random().toString(36).substr(2, 16) + currMills.slice(-4); let backupName = $('#bmi-stg-current-backup-selected').val(); callTasteWPStagingCreationProcess({ name: name, backupName: backupName }, true); } else { $.bmi.modal('freeze-loading-modal').close(); } }); $('#rescan-for-staging').on('click', function(e) { e.preventDefault(); $.bmi.reloadStaging(); }); $('#stg-tbody-table').on('click', '.bc-stg-edit-btn', function(e) { e.preventDefault(); let name = $(this).closest('tr').attr('name'); let displayName = $(this).closest('tr').find('.stg-tr-name').text(); $('#bmi-stg-rename-input').val(displayName); $('#stg-display-name-edit-confirm').attr('data-name', name); $.bmi.modal('staging-rename-modal').open(); }); $('#stg-display-name-edit-confirm').on('click', function(e) { e.preventDefault(); let empty = $('.i-staging-creator-local').attr('c-empty'); let long = $('.i-staging-creator-local').attr('c-long'); let invalid = $('.i-staging-creator-local').attr('c-invalid'); let errorNotice = $('.i-staging-creator-local').attr('c-error'); let newName = $('#bmi-stg-rename-input').val(); let oldName = $(this).attr('data-name'); let validRegex = /^[a-zA-Z0-9-_]+$/; if (newName.length <= 0) return $.bmi.alert('warning', empty, 5000); if (!validRegex.test(newName)) return $.bmi.alert('warning', invalid, 5000); if (newName.length >= 24) return $.bmi.alert('warning', long, 5000); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('staging-rename-display', { name: oldName, new: newName }).then(function(res) { $.bmi.modal('freeze-loading-modal').close(); if (res.status == 'success') { $.bmi.modal('staging-rename-modal').close(); $.bmi.reloadStaging(); } else if (res.status == 'fail') { return $.bmi.alert('warning', res.message, 5000); } else { return $.bmi.alert('error', errorNotice, 5000); } }).catch(function(error) { $.bmi.modal('freeze-loading-modal').close(); return $.bmi.alert('error', errorNotice, 5000); console.error(error); }); }); $('#bmi-visit-latest-staging').on('click', function (e) { if ($('#bmi-staging-latest-url').text().includes('tastewp')) { setTimeout(function () { $.bmi.reloadStaging(); }, 8000); } }); $('#bmi-staging-stop').on('click', function () { $.bmi.modal('freeze-loading-modal').open(); nextBatchStop = true; }); $('#stg-tbody-table').on('click', '.stg-login-btn', function(e) { if ($(this).closest('tr').attr('server') == 'tastewp') { let url = $(this).closest('tr').find('.stg-tr-url-el').text(); if (url.includes('/stg/')) $(this).attr('href', url); else { setTimeout(function () { $.bmi.reloadStaging(); }, 8000); $(this).attr('href', 'https://tastewp.com/stg/access/' + $(this).closest('tr').attr('token')); } return true; } e.preventDefault(); let name = $(this).closest('tr').attr('name'); let errorNotice = $('.i-staging-creator-local').attr('c-error'); let self = this; $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('staging-prepare-login', { name: name }).then(function(res) { $.bmi.modal('freeze-loading-modal').close(); if (res.status == 'success') { $(self).attr('href', res.url); window.open(res.url, '_blank'); } else if (res.status == 'fail') { return $.bmi.alert('warning', res.message, 5000); } else { return $.bmi.alert('error', errorNotice, 5000); } }).catch(function(error) { $.bmi.modal('freeze-loading-modal').close(); return $.bmi.alert('error', errorNotice, 5000); console.error(error); }); }); $('#stg-tbody-table').on('click', '.bc-stg-remove-btn', function(e) { e.preventDefault(); let name = $(this).closest('tr').attr('name'); let url = $(this).closest('tr').find('.stg-tr-url-el').text(); $('#bmi-staging-removal-url').attr('href', url); $('#bmi-staging-removal-url').text(url); $('#stg-removal-confirm').attr('data-name', name); $.bmi.modal('staging-delete-confirm-modal').open(); }); $('#stg-removal-confirm').on('click', function(e) { e.preventDefault(); let name = $(this).attr('data-name'); let errorNotice = $('.i-staging-creator-local').attr('c-error'); $.bmi.modal('freeze-loading-modal').open(); $.bmi.ajax('staging-delete-permanently', { name: name }).then(function(res) { $.bmi.modal('freeze-loading-modal').close(); if (res.status == 'success') { $.bmi.modal('staging-delete-confirm-modal').close(); $.bmi.reloadStaging(); } else if (res.status == 'fail') { return $.bmi.alert('warning', res.message, 5000); } else { return $.bmi.alert('error', errorNotice, 5000); } }).catch(function(error) { $.bmi.modal('freeze-loading-modal').close(); return $.bmi.alert('error', errorNotice, 5000); console.error(error); }); }); let wrapper = document.querySelector('.bmi-stg-dropdown-area-inner-scroll'); if (wrapper) { wrapper.addEventListener('wheel', function (e) { let space = (wrapper.scrollHeight - wrapper.offsetHeight) - wrapper.scrollTop; if (e.deltaY < 0) { if (wrapper.scrollTop == 0) { e.preventDefault(); e.stopPropagation(); } } else if (space <= 0) { e.preventDefault(); e.stopPropagation(); } }); } }); jQuery(document).ready(function($) { let transition = false; $('.bmi-tabs').on('click', '.bmi-tab', function(e) { if (this.classList.contains('active')) return; if (transition === true) return; else transition = true; $.bmi.collapsers.closeAll(); let id = this.getAttribute('data-point'); if (id == 'manage-restore-wrapper') { $('#create-backup-wrapper').hide(300); $('#staging-sites-wrapper').hide(300); $('[data-point="create-backup-wrapper"]').removeClass('active'); $('[data-point="staging-sites-wrapper"]').removeClass('active'); } else if (id == 'staging-sites-wrapper') { $('#create-backup-wrapper').hide(300); $('#manage-restore-wrapper').hide(300); $('[data-point="create-backup-wrapper"]').removeClass('active'); $('[data-point="manage-restore-wrapper"]').removeClass('active'); } else if (id == 'create-backup-wrapper') { $('#manage-restore-wrapper').hide(300); $('#staging-sites-wrapper').hide(300); $('[data-point="manage-restore-wrapper"]').removeClass('active'); $('[data-point="staging-sites-wrapper"]').removeClass('active'); } $('#' + id).show(300); $(this).addClass('active'); setTimeout(function() { transition = false; }, 320); }); }); jQuery(document).ready(function($) { let dropArea = document.getElementById("drop-area"); if (!dropArea) return; ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropArea.addEventListener(eventName, preventDefaults, false) }); ['dragenter', 'dragover'].forEach(eventName => { dropArea.addEventListener(eventName, highlight, false); document.querySelector('body').addEventListener(eventName, highlight, false); }); ['dragleave', 'drop', 'mouseleave'].forEach(eventName => { dropArea.addEventListener(eventName, unhighlight, false); }); $('body, #drop-area').on('mouseleave dragleave drop', function() { unhighlight(); }); dropArea.addEventListener('drop', handleDrop, false); function preventDefaults(e) { e.preventDefault() e.stopPropagation() } function highlight(e) { dropArea.classList.add('highlight') } function unhighlight(e) { dropArea.classList.remove('highlight') } function handleDrop(e) { var dt = e.dataTransfer var files = dt.files handleFiles(files) } function handleFiles(files) { files = [...files]; jQuery.fchunker_upload('file', files[0]); } });
Save
Back