diff --git a/README.md b/README.md index d5c4baeb6..33fc3bc12 100644 --- a/README.md +++ b/README.md @@ -53,29 +53,31 @@ This fork has the following changes: ### Removal of old JavaScript -This fork uses jQuery.slim and downsized versions of Underscore.js, Jua.js, etc. etc., and has no support for Internet Explorer. +This fork uses jQuery.slim, downsized/simplified versions of scripts and has no support for Internet Explorer. + +The result is faster and smaller download code (good for mobile networks). Things might work in Edge 15-18, Firefox 47-62 and Chrome 54-68 due to one polyfill for array.flat(). -|js/* |1.14.0 |native | div | -|----------- |--------: |--------: |--------: | -|admin.js |2.130.942 |1.359.501 | | -|app.js |4.184.455 |3.127.807 | | -|boot.js | 671.522 | 117.510 | | -|libs.js | 647.614 | 508.324 | | -|polyfills.js | 325.834 | 0 | | -|TOTAL js |7.960.367 |5.119.409 | | +|js/* |1.14.0 |native | +|----------- |--------: |--------: | +|admin.js |2.130.942 |1.359.501 | +|app.js |4.184.455 |3.127.807 | +|boot.js | 671.522 | 109.651 | +|libs.js | 647.614 | 508.324 | +|polyfills.js | 325.834 | 0 | +|TOTAL js |7.960.367 |5.105.283 | -|js/min/* |1.14.0 |native | div | -|----------- |--------: |--------: |--------: | -|admin.js | 252.147 | 177.094 | | -|app.js | 511.202 | 409.778 | | -|boot.js | 66.007 | 14.229 | | -|libs.js | 572.545 | 465.247 | | -|polyfills.js | 32.452 | 0 | | -|TOTAL js/min |1.434.353 |1.066.348 |368.005 | +|js/min/* |1.14.0 |native | +|----------- |--------: |--------: | +|admin.js | 252.147 | 177.094 | +|app.js | 511.202 | 409.778 | +|boot.js | 66.007 | 13.380 | +|libs.js | 572.545 | 465.247 | +|polyfills.js | 32.452 | 0 | +|TOTAL js/min |1.434.353 |1.065.499 | -368.005 bytes is not much, but it feels faster. +368.854 bytes is not much, but it feels faster. ### PHP73 branch diff --git a/dev/Common/Booter.js b/dev/Common/Booter.js index 53117c496..28d2492eb 100644 --- a/dev/Common/Booter.js +++ b/dev/Common/Booter.js @@ -13,92 +13,11 @@ window.__rlah_clear = () => clearHash(); window.__rlah_data = () => RL_APP_DATA_STORAGE; /** - * @param {string} styles * @returns {void} */ -function includeStyle(styles) { - const doc = window.document, style = doc.createElement('style'); - style.type = 'text/css'; - style.textContent = styles; -// style.appendChild(doc.createTextNode(styles)); - doc.head.appendChild(style); -} - -/** - * @param {string} src - * @returns {void} - */ -function includeScr(src) { - const doc = window.document, script = doc.createElement('script'); - script.type = 'text/javascript'; - script.src = src; - doc.head.appendChild(script); -} - -/** - * @returns {boolean} - */ -function includeLayout() { - const app = window.document.getElementById('rl-app'); - - require('Styles/@Boot.css'); - - if (app) { - const layout = require('Html/Layout.html'); - app.innerHTML = ((layout && layout.default ? layout.default : layout) || '').replace(/[\r\n\t]+/g, ''); - return true; - } - - return false; -} - -/** - * @param {boolean} admin = false - * @param {boolean} mobile = false - * @param {boolean} mobileDevice = false - * @returns {void} - */ -function includeAppScr({ admin = false, mobile = false, mobileDevice = false }) { - let src = './?/'; - src += admin ? 'Admin' : ''; - src += 'AppData@'; - src += mobile ? 'mobile' : 'no-mobile'; - src += mobileDevice ? '-1' : '-0'; - src += '/'; - - includeScr( - src + - (window.__rlah ? window.__rlah() || '0' : '0') + - '/' + - window.Math.random() - .toString() - .substr(2) + - '/' - ); -} - -/** - * @returns {object} - */ -function getRainloopBootData() { - let result = {}; - const meta = window.document.getElementById('app-boot-data'); - - if (meta && meta.getAttribute) { - result = JSON.parse(meta.getAttribute('content')) || {}; - } - - return result; -} - -/** - * @param {string} additionalError - * @returns {void} - */ -function showError(additionalError) { +function showError() { const oR = window.document.getElementById('rl-loading'), - oL = window.document.getElementById('rl-loading-error'), - oLA = window.document.getElementById('rl-loading-error-additional'); + oL = window.document.getElementById('rl-loading-error'); if (oR) { oR.style.display = 'none'; @@ -108,60 +27,69 @@ function showError(additionalError) { oL.style.display = 'block'; } - if (oLA && additionalError) { - oLA.style.display = 'block'; - oLA.innerHTML = additionalError; - } - if (progressJs) { progressJs.set(100).end(); } } -/** - * @param {string} description - * @returns {void} - */ -function showDescriptionAndLoading(description) { - const oE = window.document.getElementById('rl-loading'), - oElDesc = window.document.getElementById('rl-loading-desc'); - - if (oElDesc && description) { - oElDesc.innerHTML = description; - } - - if (oE && oE.style) { - oE.style.opacity = 0; - window.setTimeout(() => { - oE.style.opacity = 1; - }, 300); - } -} - /** * @param {boolean} withError - * @param {string} additionalError * @returns {void} */ -function runMainBoot(withError, additionalError) { +function runMainBoot(withError) { if (window.__APP_BOOT && !withError) { window.__APP_BOOT(() => { - showError(additionalError); + showError(); }); } else { - showError(additionalError); + showError(); } } /** + * @param {mixed} data * @returns {void} */ -function runApp() { - const appData = window.__rlah_data(); +window.__initAppData = data => { + RL_APP_DATA_STORAGE = data; + + window.__rlah_set(); + + const doc = window.document; + + if (RL_APP_DATA_STORAGE) { + const css = RL_APP_DATA_STORAGE.IncludeCss, + theme = RL_APP_DATA_STORAGE.NewThemeLink, + description= RL_APP_DATA_STORAGE.LoadingDescriptionEsc || '', + oE = doc.getElementById('rl-loading'), + oElDesc = doc.getElementById('rl-loading-desc'); + + if (theme) { + (doc.getElementById('app-theme-link') || {}).href = theme; + } + + if (css) { + const style = doc.createElement('style'); + style.type = 'text/css'; + style.textContent = css; +// style.appendChild(doc.createTextNode(styles)); + doc.head.appendChild(style); + } + + if (oElDesc && description) { + oElDesc.innerHTML = description; + } + if (oE && oE.style) { + oE.style.opacity = 0; + window.setTimeout(() => oE.style.opacity = 1, 300); + } + } + + const appData = window.__rlah_data(), p = progressJs; if ( jassl && - progressJs && + p && appData && appData.TemplatesLink && appData.LangLink && @@ -169,18 +97,16 @@ function runApp() { appData.StaticAppJsLink && appData.StaticEditorJsLink ) { - const p = progressJs; - p.start().set(5); const libs = () => jassl(appData.StaticLibJsLink).then(() => { - window.document.getElementById('rl-check').remove(); + doc.getElementById('rl-check').remove(); if (appData.IncludeBackground) { const img = appData.IncludeBackground.replace('{{USER}}', window.__rlah ? window.__rlah() || '0' : '0'); if (img) { - window.document.documentElement.classList.add('UserBackground'); - window.document.body.style.backgroundImage = "url("+img+")"; + doc.documentElement.classList.add('UserBackground'); + doc.body.style.backgroundImage = "url("+img+")"; } } }); @@ -216,41 +142,40 @@ function runApp() { } else { runMainBoot(true); } -} - -/** - * @param {mixed} data - * @returns {void} - */ -window.__initAppData = function(data) { - RL_APP_DATA_STORAGE = data; - - window.__rlah_set(); - - if (RL_APP_DATA_STORAGE) { - if (RL_APP_DATA_STORAGE.NewThemeLink) { - (window.document.getElementById('app-theme-link') || {}).href = RL_APP_DATA_STORAGE.NewThemeLink; - } - - if (RL_APP_DATA_STORAGE.IncludeCss) { - includeStyle(RL_APP_DATA_STORAGE.IncludeCss); - } - - showDescriptionAndLoading(RL_APP_DATA_STORAGE.LoadingDescriptionEsc || ''); - } - - runApp(); }; /** * @returns {void} */ -window.__runBoot = function() { +window.__runBoot = () => { + const doc = window.document, + app = doc.getElementById('rl-app'); + if (!window.navigator || !window.navigator.cookieEnabled) { - window.document.location.replace('./?/NoCookie'); + doc.location.replace('./?/NoCookie'); } - if (includeLayout()) { - includeAppScr(getRainloopBootData()); + require('Styles/@Boot.css'); + + if (app) { + const layout = require('Html/Layout.html'), + meta = doc.getElementById('app-boot-data'), + options = meta ? JSON.parse(meta.getAttribute('content')) || {} : {}, + script = doc.createElement('script'); + + app.innerHTML = ((layout && layout.default ? layout.default : layout) || '').replace(/[\r\n\t]+/g, ''); + + script.type = 'text/javascript'; + script.src = './?/' + + (options.admin ? 'Admin' : '') + + 'AppData@' + + (options.mobile ? 'mobile' : 'no-mobile') + + (options.mobileDevice ? '-1' : '-0') + + '/' + + (window.__rlah ? window.__rlah() || '0' : '0') + + '/' + + window.Math.random().toString().substr(2) + + '/'; + doc.head.appendChild(script); } }; diff --git a/dev/Html/Layout.html b/dev/Html/Layout.html index b651c506c..40907cf08 100644 --- a/dev/Html/Layout.html +++ b/dev/Html/Layout.html @@ -8,7 +8,6 @@
An error occurred.
Please refresh the page and try again. -
diff --git a/dev/Styles/Layout.less b/dev/Styles/Layout.less index 05349dd5a..c9e21226d 100644 --- a/dev/Styles/Layout.less +++ b/dev/Styles/Layout.less @@ -434,11 +434,6 @@ html.rl-ctrl-key-pressed { display: none; } -#rl-loading-error-additional { - margin-top: 20px; - font-size: 20px; -} - #rl-app{ display: none; } diff --git a/vendors/Progress.js/minified/progress.min.js b/vendors/Progress.js/minified/progress.min.js index 9e8f8bd45..b020437c0 100644 --- a/vendors/Progress.js/minified/progress.min.js +++ b/vendors/Progress.js/minified/progress.min.js @@ -1 +1 @@ -(e=>{function t(e){void 0!==e.length?this._targetElement=e:this._targetElement=[e],void 0===window._progressjsId&&(window._progressjsId=1),void 0===window._progressjsIntervals&&(window._progressjsIntervals={}),this._options={theme:"rainloop",overlayMode:!1,considerTransition:!0}}function r(){(function(){if(!document.querySelector(".progressjs-container")){var e=document.createElement("div");e.className="progressjs-container",document.body.appendChild(e)}}).call(this);var e=this;e._targetElement.forEach(t=>(function(e){if(e.hasAttribute("data-progressjs"))return;var t=function(e){var t={},r=0,s=0;"body"===e.tagName.toLowerCase()?(t.width=e.clientWidth,t.height=e.clientHeight):(t.width=e.offsetWidth,t.height=e.offsetHeight);for(;e&&!isNaN(e.offsetLeft)&&!isNaN(e.offsetTop);)r+=e.offsetLeft,s+=e.offsetTop,e=e.offsetParent;return t.top=s,t.left=r,t}.call(this,e);e.setAttribute("data-progressjs",window._progressjsId);var r=document.createElement("div");r.className="progressjs-progress progressjs-theme-"+this._options.theme,r.style.position="body"===e.tagName.toLowerCase()?"fixed":"absolute",r.setAttribute("data-progressjs",window._progressjsId);var o=document.createElement("div");o.className="progressjs-inner";var n=document.createElement("div");n.className="progressjs-percent",n.innerHTML="1%",o.appendChild(n),this._options.overlayMode&&"body"===e.tagName.toLowerCase()?(r.style.left=0,r.style.right=0,r.style.top=0,r.style.bottom=0):(r.style.left=t.left+"px",r.style.top=t.top+"px",r.style.width=t.width+"px",this._options.overlayMode&&(r.style.height=t.height+"px"));r.appendChild(o),document.querySelector(".progressjs-container").appendChild(r),s(e,1),++window._progressjsId}).call(e,t))}function s(e,t){t>=100&&(t=100),e.hasAttribute("data-progressjs")&&setTimeout(()=>{var r=o(e);r.style.width=parseInt(t)+"%",r=r.querySelector(".progressjs-percent");var s=parseInt(r.innerHTML.replace("%",""));((e,t,r)=>{var s=!0;t>r&&(s=!1);var o=10;!function e(t,r,n){var i=Math.abs(r-n);o=i<3?30:i<20?20:1,r-n!=0&&(t.innerHTML=(s?++r:--r)+"%",setTimeout(()=>e(t,r,n),o))}(e,t,r)})(r,s,parseInt(t))},50)}function o(e){var t=parseInt(e.getAttribute("data-progressjs"));return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="'+t+'"] > .progressjs-inner')}var n=function(e){if("object"==typeof e)return new t(e);if("string"==typeof e){var r=document.querySelectorAll(e);if(r)return new t(r);throw new Error("There is no element with given selector.")}return new t(document.body)};n.version="0.1.0",n.fn=t.prototype={start:function(){return r.call(this),this},set:function(e){return function(e){var t=this;t._targetElement.forEach(r=>s.call(t,r,e))}.call(this,e),this},end:function(){return function(){void 0!==this._onBeforeEndCallback&&(!0===this._options.considerTransition?o(this._targetElement[0]).addEventListener("transitionend",this._onBeforeEndCallback,!1):this._onBeforeEndCallback.call(this));var e=parseInt(this._targetElement[0].getAttribute("data-progressjs")),t=this;if(t._targetElement.forEach(e=>{var r=o(e);if(r){var n=parseInt(r.style.width.replace("%","")),i=1;n<100&&(s.call(t,e,100),i=500),((e,t)=>{setTimeout(()=>{e.parentNode.className+=" progressjs-end",setTimeout(()=>{e.parentNode.parentNode.removeChild(e.parentNode),t.removeAttribute("data-progressjs")},1e3)},i)})(r,e)}}),window._progressjsIntervals[e])try{clearInterval(window._progressjsIntervals[e]),window._progressjsIntervals[e]=null,delete window._progressjsIntervals[e]}catch(e){}}.call(this),this},onbeforeend:function(e){if("function"!=typeof e)throw new Error("Provided callback for onbeforeend was not a function");return this._onBeforeEndCallback=e,this}},e.progressJs=n})(this); +(e=>{const t=window,r=document,s=e=>void 0!==e;function o(e){this._targetElement=s(e.length)?e:[e],s(t._progressjsId)||(t._progressjsId=1),s(t._progressjsIntervals)||(t._progressjsIntervals={}),this._options={theme:"rainloop",overlayMode:!1,considerTransition:!0}}function n(e){if(!e.hasAttribute("data-progressjs")){var s=function(e){var t={},r=0,s=0;"body"===e.tagName.toLowerCase()?(t.width=e.clientWidth,t.height=e.clientHeight):(t.width=e.offsetWidth,t.height=e.offsetHeight);for(;e&&!isNaN(e.offsetLeft)&&!isNaN(e.offsetTop);)r+=e.offsetLeft,s+=e.offsetTop,e=e.offsetParent;return t.top=s,t.left=r,t}.call(this,e);e.setAttribute("data-progressjs",t._progressjsId);var o=r.createElement("div");o.className="progressjs-progress progressjs-theme-"+this._options.theme,o.style.position="body"===e.tagName.toLowerCase()?"fixed":"absolute",o.setAttribute("data-progressjs",t._progressjsId);var n=r.createElement("div");n.className="progressjs-inner";var i=r.createElement("div");i.className="progressjs-percent",i.innerHTML="1%",n.appendChild(i),this._options.overlayMode&&"body"===e.tagName.toLowerCase()?(o.style.left=0,o.style.right=0,o.style.top=0,o.style.bottom=0):(o.style.left=s.left+"px",o.style.top=s.top+"px",o.style.width=s.width+"px",this._options.overlayMode&&(o.style.height=s.height+"px")),o.appendChild(n),r.querySelector(".progressjs-container").appendChild(o),a(e,1),++t._progressjsId}}function a(e,t){t>=100&&(t=100),e.hasAttribute("data-progressjs")&&setTimeout(()=>{var r=i(e);r.style.width=parseInt(t)+"%",r=r.querySelector(".progressjs-percent");var s=parseInt(r.innerHTML.replace("%",""));((e,t,r)=>{var s=!0;t>r&&(s=!1);var o=10;!function e(t,r,n){var a=Math.abs(r-n);o=a<3?30:a<20?20:1,r-n!=0&&(t.innerHTML=(s?++r:--r)+"%",setTimeout(()=>e(t,r,n),o))}(e,t,r)})(r,s,parseInt(t))},50)}function i(e){var t=parseInt(e.getAttribute("data-progressjs"));return r.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="'+t+'"] > .progressjs-inner')}var l=function(e){if("object"==typeof e)return new o(e);if("string"==typeof e){var t=r.querySelectorAll(e);if(t)return new o(t);throw new Error("There is no element with given selector.")}return new o(r.body)};l.version="0.1.0",l.fn=o.prototype={start:function(){if(!r.querySelector(".progressjs-container")){var e=r.createElement("div");e.className="progressjs-container",r.body.appendChild(e)}var t=this;return t._targetElement.forEach(e=>n.call(t,e)),t},set:function(e){var t=this;return t._targetElement.forEach(r=>a.call(t,r,e)),t},end:function(){var e=this;s(e._onBeforeEndCallback)&&(!0===e._options.considerTransition?i(e._targetElement[0]).addEventListener("transitionend",e._onBeforeEndCallback,!1):e._onBeforeEndCallback.call(e));var r=parseInt(e._targetElement[0].getAttribute("data-progressjs"));if(e._targetElement.forEach(t=>{var r=i(t);if(r){var s=parseInt(r.style.width.replace("%","")),o=1;s<100&&(a.call(e,t,100),o=500),((e,t)=>{setTimeout(()=>{e.parentNode.className+=" progressjs-end",setTimeout(()=>{e.parentNode.parentNode.removeChild(e.parentNode),t.removeAttribute("data-progressjs")},1e3)},o)})(r,t)}}),t._progressjsIntervals[r])try{clearInterval(t._progressjsIntervals[r]),t._progressjsIntervals[r]=null,delete t._progressjsIntervals[r]}catch(e){}return e},onbeforeend:function(e){return this._onBeforeEndCallback=e,this}},e.progressJs=l})(this); diff --git a/vendors/Progress.js/src/progress.js b/vendors/Progress.js/src/progress.js index a43f39161..ed67a2c8e 100644 --- a/vendors/Progress.js/src/progress.js +++ b/vendors/Progress.js/src/progress.js @@ -8,7 +8,10 @@ (exports => { //Default config/variables - var VERSION = '0.1.0'; + const VERSION = '0.1.0', + win = window, + doc = document, + defined = v => undefined !== v; /** * ProgressJs main class @@ -17,17 +20,13 @@ */ function ProgressJs(obj) { - if (typeof obj.length != 'undefined') { - this._targetElement = obj; - } else { - this._targetElement = [obj]; - } + this._targetElement = defined(obj.length) ? obj : [obj]; - if (typeof window._progressjsId === 'undefined') - window._progressjsId = 1; + if (!defined(win._progressjsId)) + win._progressjsId = 1; - if (typeof window._progressjsIntervals === 'undefined') - window._progressjsIntervals = {}; + if (!defined(win._progressjsIntervals)) + win._progressjsIntervals = {}; this._options = { //progress bar theme @@ -39,20 +38,6 @@ }; } - /** - * Start progress for specific element(s) - * - * @api private - * @method _createContainer - */ - function _startProgress() { - //create the container for progress bar - _createContainer.call(this); - - var p = this; - p._targetElement.forEach(item => _setProgress.call(p, item)); - } - /** * Set progress bar for specific element * @@ -69,21 +54,21 @@ //get target element position var targetElementOffset = _getOffset.call(this, targetElement); - targetElement.setAttribute("data-progressjs", window._progressjsId); + targetElement.setAttribute("data-progressjs", win._progressjsId); - var progressElementContainer = document.createElement('div'); + var progressElementContainer = doc.createElement('div'); progressElementContainer.className = 'progressjs-progress progressjs-theme-' + this._options.theme; //set the position percent elements, it depends on targetElement tag progressElementContainer.style.position = targetElement.tagName.toLowerCase() === 'body' ? 'fixed' : 'absolute'; - progressElementContainer.setAttribute("data-progressjs", window._progressjsId); - var progressElement = document.createElement("div"); + progressElementContainer.setAttribute("data-progressjs", win._progressjsId); + var progressElement = doc.createElement("div"); progressElement.className = "progressjs-inner"; //create an element for current percent of progress bar - var progressPercentElement = document.createElement('div'); + var progressPercentElement = doc.createElement('div'); progressPercentElement.className = "progressjs-percent"; progressPercentElement.innerHTML = "1%"; @@ -110,25 +95,13 @@ progressElementContainer.appendChild(progressElement); //append the element to container - var container = document.querySelector('.progressjs-container'); + var container = doc.querySelector('.progressjs-container'); container.appendChild(progressElementContainer); _setPercentFor(targetElement, 1); //and increase the progressId - ++window._progressjsId; - } - - /** - * Set percent for all elements - * - * @api private - * @method _setPercent - * @param {Number} percent - */ - function _setPercent(percent) { - var p = this; - p._targetElement.forEach(item => _setPercentFor.call(p, item, percent)); + ++win._progressjsId; } /** @@ -198,84 +171,7 @@ */ function _getPercentElement(targetElement) { var progressjsId = parseInt(targetElement.getAttribute('data-progressjs')); - return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="' + progressjsId + '"] > .progressjs-inner'); - } - - /** - * Close and remove progress bar - * - * @api private - * @method _end - */ - function _end() { - - //call onBeforeEnd callback - if (typeof this._onBeforeEndCallback != 'undefined') { - if (this._options.considerTransition === true) { - //we can safety assume that all layers would be the same, so `this._targetElement[0]` is the same as `this._targetElement[1]` - _getPercentElement(this._targetElement[0]).addEventListener('transitionend', this._onBeforeEndCallback, false); - } else { - this._onBeforeEndCallback.call(this); - } - } - - var progressjsId = parseInt(this._targetElement[0].getAttribute('data-progressjs')); - - var p = this; - p._targetElement.forEach(currentElement => { - var percentElement = _getPercentElement(currentElement); - - if (!percentElement) - return; - - var existingPercent = parseInt(percentElement.style.width.replace('%', '')); - - var timeoutSec = 1; - if (existingPercent < 100) { - _setPercentFor.call(p, currentElement, 100); - timeoutSec = 500; - } - - //I believe I should handle this situation with eventListener and `transitionend` event but I'm not sure - //about compatibility with IEs. Should be fixed in further versions. - ((percentElement, currentElement) => { - setTimeout(() => { - percentElement.parentNode.className += " progressjs-end"; - - setTimeout(() => { - //remove the percent element from page - percentElement.parentNode.parentNode.removeChild(percentElement.parentNode); - //and remove the attribute - currentElement.removeAttribute("data-progressjs"); - }, 1000); - }, timeoutSec); - })(percentElement, currentElement); - }); - - //clean the setInterval for autoIncrease function - if (window._progressjsIntervals[progressjsId]) { - //`delete` keyword has some problems in IE - try { - clearInterval(window._progressjsIntervals[progressjsId]); - window._progressjsIntervals[progressjsId] = null; - delete window._progressjsIntervals[progressjsId]; - } catch(ex) { } - } - } - - /** - * Create the progress bar container - * - * @api private - * @method _createContainer - */ - function _createContainer() { - //first check if we have an container already, we don't need to create it again - if (!document.querySelector(".progressjs-container")) { - var containerElement = document.createElement("div"); - containerElement.className = "progressjs-container"; - document.body.appendChild(containerElement); - } + return doc.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="' + progressjsId + '"] > .progressjs-inner'); } /** @@ -323,14 +219,14 @@ } if (typeof (targetElm) === 'string') { //select the target element with query selector - var targetElement = document.querySelectorAll(targetElm); + var targetElement = doc.querySelectorAll(targetElm); if (targetElement) { return new ProgressJs(targetElement); } throw new Error('There is no element with given selector.'); } - return new ProgressJs(document.body); + return new ProgressJs(doc.body); }; /** @@ -344,23 +240,80 @@ //Prototype progressJs.fn = ProgressJs.prototype = { start: function() { - _startProgress.call(this); - return this; + //first check if we have an container already, we don't need to create it again + if (!doc.querySelector(".progressjs-container")) { + //create the container for progress bar + var containerElement = doc.createElement("div"); + containerElement.className = "progressjs-container"; + doc.body.appendChild(containerElement); + } + var p = this; + p._targetElement.forEach(item => _setProgress.call(p, item)); + return p; }, set: function(percent) { - _setPercent.call(this, percent); - return this; + var p = this; + p._targetElement.forEach(item => _setPercentFor.call(p, item, percent)); + return p; }, end: function() { - _end.call(this); - return this; + var p = this; + //call onBeforeEnd callback + if (defined(p._onBeforeEndCallback)) { + if (p._options.considerTransition === true) { + //we can safety assume that all layers would be the same, so `p._targetElement[0]` is the same as `p._targetElement[1]` + _getPercentElement(p._targetElement[0]) + .addEventListener('transitionend', p._onBeforeEndCallback, false); + } else { + p._onBeforeEndCallback.call(p); + } + } + + var progressjsId = parseInt(p._targetElement[0].getAttribute('data-progressjs')); + + p._targetElement.forEach(currentElement => { + var percentElement = _getPercentElement(currentElement); + + if (!percentElement) + return; + + var existingPercent = parseInt(percentElement.style.width.replace('%', '')); + + var timeoutSec = 1; + if (existingPercent < 100) { + _setPercentFor.call(p, currentElement, 100); + timeoutSec = 500; + } + + //I believe I should handle this situation with eventListener and `transitionend` event but I'm not sure + //about compatibility with IEs. Should be fixed in further versions. + ((percentElement, currentElement) => { + setTimeout(() => { + percentElement.parentNode.className += " progressjs-end"; + + setTimeout(() => { + //remove the percent element from page + percentElement.parentNode.parentNode.removeChild(percentElement.parentNode); + //and remove the attribute + currentElement.removeAttribute("data-progressjs"); + }, 1000); + }, timeoutSec); + })(percentElement, currentElement); + }); + + //clean the setInterval for autoIncrease function + if (win._progressjsIntervals[progressjsId]) { + //`delete` keyword has some problems in IE + try { + clearInterval(win._progressjsIntervals[progressjsId]); + win._progressjsIntervals[progressjsId] = null; + delete win._progressjsIntervals[progressjsId]; + } catch(ex) { } + } + return p; }, onbeforeend: function(providedCallback) { - if (typeof (providedCallback) === 'function') { - this._onBeforeEndCallback = providedCallback; - } else { - throw new Error('Provided callback for onbeforeend was not a function'); - } + this._onBeforeEndCallback = providedCallback; return this; } };