Improve scripts load system

This commit is contained in:
RainLoop Team 2016-05-20 03:04:15 +03:00
parent 58b9eed8e8
commit 72bf212f67
39 changed files with 916 additions and 411 deletions

View file

@ -23,7 +23,7 @@ class AbstractApp extends AbstractBoot
{ {
super(); super();
this.iframe = $('<iframe style="display:none" src="javascript:;" />').appendTo('body'); this.iframe = $('<iframe style="display:none" />').appendTo('body');
Globals.$win.on('error', function (oEvent) { Globals.$win.on('error', function (oEvent) {
if (oEvent && oEvent.originalEvent && oEvent.originalEvent.message && if (oEvent && oEvent.originalEvent && oEvent.originalEvent.message &&

View file

@ -1213,13 +1213,6 @@ class AppUser extends AbstractApp
{ {
kn.hideLoading(); kn.hideLoading();
progressJs.onbeforeend(() => {
$('.progressjs-container').hide();
_.delay(() => {
$('.progressjs-container').remove();
}, 100);
});
progressJs.set(100).end(); progressJs.set(100).end();
} }
else else
@ -1239,7 +1232,6 @@ class AppUser extends AbstractApp
require('Stores/User/Contact').populate(); require('Stores/User/Contact').populate();
var var
$LAB = require('$LAB'),
sJsHash = Settings.appSettingsGet('jsHash'), sJsHash = Settings.appSettingsGet('jsHash'),
sStartupUrl = Utils.pString(Settings.settingsGet('StartupUrl')), sStartupUrl = Utils.pString(Settings.settingsGet('StartupUrl')),
iContactsSyncInterval = Utils.pInt(Settings.settingsGet('ContactsSyncInterval')), iContactsSyncInterval = Utils.pInt(Settings.settingsGet('ContactsSyncInterval')),
@ -1288,7 +1280,7 @@ class AppUser extends AbstractApp
kn.routeOn(); kn.routeOn();
} }
if ($LAB && window.crypto && window.crypto.getRandomValues && Settings.capa(Enums.Capa.OpenPGP)) if (window.jsloader && window.crypto && window.crypto.getRandomValues && Settings.capa(Enums.Capa.OpenPGP))
{ {
const openpgpCallback = (openpgp) => { const openpgpCallback = (openpgp) => {
@ -1298,8 +1290,7 @@ class AppUser extends AbstractApp
{ {
try try
{ {
// PgpStore.openpgp.initWorker(Links.openPgpWorkerJs()); // 1.2.0 PgpStore.openpgp.initWorker({path: Links.openPgpWorkerJs()});
PgpStore.openpgp.initWorker({path: Links.openPgpWorkerJs()}); // 2.3.0
} }
catch (e) catch (e)
{ {
@ -1321,7 +1312,7 @@ class AppUser extends AbstractApp
} }
else else
{ {
$LAB.script(Links.openPgpJs()).wait(() => { window.jsloader(Links.openPgpJs()).then(() => {
if (window.openpgp) if (window.openpgp)
{ {
openpgpCallback(window.openpgp); openpgpCallback(window.openpgp);

View file

@ -1,13 +1,20 @@
import window from 'window'; import window from 'window';
import $ from '$'; import $ from '$';
import progressJs from 'progressJs';
import rainLoopStorage from 'Storage/RainLoop'; import rainLoopStorage from 'Storage/RainLoop';
let rlAppDataStorage = null;
window.__rlah = () => { window.__rlah = () => {
return rainLoopStorage ? rainLoopStorage.getHash() : null; return rainLoopStorage ? rainLoopStorage.getHash() : null;
}; };
window.__rlah_data = () => {
return rlAppDataStorage;
};
window.__rlah_set = () => { window.__rlah_set = () => {
if (rainLoopStorage) if (rainLoopStorage)
{ {
@ -22,20 +29,59 @@ window.__rlah_clear = () => {
} }
}; };
window.__includeScr = (src) => { function includeStyle(styles)
window.document.write(unescape('%3Csc' + 'ript data-cfasync="false" type="text/jav' + 'ascr' + 'ipt" sr' + 'c="' + src + '"%3E%3C/' + 'scr' + 'ipt%3E')); {
};
window.__includeAppScr = (src) => {
window.__includeScr(src + (window.__rlah ? window.__rlah() || '0' : '0') + '/' + window.Math.random().toString().substr(2) + '/');
};
window.__includeStyle = (styles) => {
window.document.write(unescape('%3Csty' + 'le%3E' + styles + '"%3E%3C/' + 'sty' + 'le%3E')); window.document.write(unescape('%3Csty' + 'le%3E' + styles + '"%3E%3C/' + 'sty' + 'le%3E'));
}; }
window.__showError = (additionalError) => { function includeScr(src)
{
window.document.write(unescape('%3Csc' + 'ript type="text/jav' + 'ascr' + 'ipt" data-cfasync="false" sr' + 'c="' + src + '"%3E%3C/' + 'scr' + 'ipt%3E'));
}
function includeLayout()
{
const
layout = require('Html/Layout.html'),
app = window.document.getElementById('rl-app')
;
if (app && layout)
{
app.innerHTML = layout.replace(/[\r\n\t]+/g, '');
return true;
}
return false;
}
function includeAppScr(data = {})
{
let src = './?/';
src += data.admin ? 'Admin' : '';
src += 'AppData@';
src += data.mobile ? 'mobile' : 'no-mobile';
src += data.mobileDevice ? '-1' : '-0';
src += '/';
includeScr(src + (window.__rlah ? window.__rlah() || '0' : '0') + '/' + window.Math.random().toString().substr(2) + '/');
}
function getRainloopBootData()
{
let result = {};
const meta = window.document.getElementById('app-boot-data');
if (meta && meta.getAttribute)
{
result = JSON.parse(meta.getAttribute('content')) || {};
}
return result;
}
function showError(additionalError)
{
const const
oR = window.document.getElementById('rl-loading'), oR = window.document.getElementById('rl-loading'),
oL = window.document.getElementById('rl-loading-error'), oL = window.document.getElementById('rl-loading-error'),
@ -58,14 +104,14 @@ window.__showError = (additionalError) => {
oLA.innerHTML = additionalError; oLA.innerHTML = additionalError;
} }
if (window.rainloopProgressJs) if (progressJs)
{ {
window.rainloopProgressJs.set(100); progressJs.set(100).end();
}
} }
};
window.__showDescription = (description) => {
function showDescriptionAndLoading(description)
{
const const
oE = window.document.getElementById('rl-loading'), oE = window.document.getElementById('rl-loading'),
oElDesc = window.document.getElementById('rl-loading-desc') oElDesc = window.document.getElementById('rl-loading-desc')
@ -83,76 +129,81 @@ window.__showDescription = (description) => {
oE.style.opacity = 1; oE.style.opacity = 1;
}, 300); }, 300);
} }
}; }
window.__runBoot = (withError, additionalError) => { function runMainBoot(withError, additionalError)
if (window.__APP_BOOT && !withError) { {
if (window.__APP_BOOT && !withError)
{
window.__APP_BOOT(function (bV) { window.__APP_BOOT(function (bV) {
if (!bV) { if (!bV)
window.__showError(additionalError); {
showError(additionalError);
} }
}); });
} else {
window.__showError(additionalError);
} }
}; else
window.__runApp = (BaseAppLibsScriptLink, BaseAppMainScriptLink, BaseAppEditorScriptLink) => {
const appData = window.rainloopAppData;
if (window.$LAB && window.progressJs && appData && appData.TemplatesLink && appData.LangLink)
{ {
const p = window.progressJs(); showError(additionalError);
window.rainloopProgressJs = p; }
}
function runApp()
{
const appData = window.__rlah_data();
if (window.jsloader && progressJs && appData && appData.TemplatesLink && appData.LangLink &&
appData.StaticLibJsLink && appData.StaticAppJsLink && appData.StaticEditorJsLink)
{
const p = progressJs;
p.setOptions({theme: 'rainloop'}); p.setOptions({theme: 'rainloop'});
p.start().set(5); p.start().set(5);
window.$LAB const
.script(function () { libs = window.jsloader(appData.StaticLibJsLink).then(() => {
return [ if (window.$)
{src: BaseAppLibsScriptLink, type: 'text/javascript', charset: 'utf-8'} {
]; if (!window.$('#rl-check').is(':visible'))
}) {
.wait(function () { window.$('html').addClass('no-css');
throw new Error('no-css');
}
p.set(20); window.$('#rl-check').remove();
if (appData.IncludeBackground && $) { if (appData.IncludeBackground)
$('#rl-bg').attr('style', 'background-image: none !important;') {
window.$('#rl-bg').attr('style', 'background-image: none !important;')
.backstretch(appData.IncludeBackground.replace('{{USER}}', .backstretch(appData.IncludeBackground.replace('{{USER}}',
(window.__rlah ? window.__rlah() || '0' : '0')), {fade: 100, centeredX: true, centeredY: true}) (window.__rlah ? (window.__rlah() || '0') : '0')), {fade: 100, centeredX: true, centeredY: true})
.removeAttr('style') .removeAttr('style')
; ;
} }
}) }
.script(function () { }),
return [ common = window.Promise.all([
{src: appData.TemplatesLink, type: 'text/javascript', charset: 'utf-8'}, window.jsloader(appData.TemplatesLink),
{src: appData.LangLink, type: 'text/javascript', charset: 'utf-8'} window.jsloader(appData.LangLink)
]; ])
}) ;
.wait(function () {
window.Promise.all([libs, common])
.then(() => {
p.set(30); p.set(30);
}) return window.jsloader(appData.StaticAppJsLink);
.script(function () { }).then(() => {
return {src: BaseAppMainScriptLink, type: 'text/javascript', charset: 'utf-8'};
})
.wait(function () {
p.set(50); p.set(50);
}) return appData.PluginsLink ? window.jsloader(appData.PluginsLink) : window.Promise.resolve();
.script(function () { }).then(() => {
return appData.PluginsLink ? {src: appData.PluginsLink, type: 'text/javascript', charset: 'utf-8'} : null;
})
.wait(function () {
p.set(70); p.set(70);
window.__runBoot(false); runMainBoot(false);
}) }).catch((e) => {
.script(function () { runMainBoot(true);
return {src: BaseAppEditorScriptLink, type: 'text/javascript', charset: 'utf-8'}; throw e;
}) }).then(() => {
.wait(function () { return window.jsloader(appData.StaticEditorJsLink);
}).then(() => {
if (window.CKEDITOR && window.__initEditor) { if (window.CKEDITOR && window.__initEditor) {
window.__initEditor(); window.__initEditor();
window.__initEditor = null; window.__initEditor = null;
@ -162,6 +213,41 @@ window.__runApp = (BaseAppLibsScriptLink, BaseAppMainScriptLink, BaseAppEditorSc
} }
else else
{ {
window.__runBoot(true); runMainBoot(true);
}
}
window.__initAppData = function(data) {
rlAppDataStorage = data;
window.__rlah_set();
if (rlAppDataStorage.NewThemeLink)
{
window.document.getElementById('app-theme-link').href = rlAppDataStorage.NewThemeLink;
}
if (rlAppDataStorage.IncludeCss)
{
includeStyle(rlAppDataStorage.IncludeCss);
}
showDescriptionAndLoading(rlAppDataStorage ? (rlAppDataStorage.LoadingDescriptionEsc || '') : '');
runApp();
};
window.__runBoot = function() {
if (!window.navigator || !window.navigator.cookieEnabled)
{
window.document.location.replace('./?/NoCookie');
}
if (includeLayout())
{
includeAppScr(getRainloopBootData());
} }
}; };

25
dev/Common/Loader.jsx Normal file
View file

@ -0,0 +1,25 @@
import window from 'window';
import {Promise} from 'es6-promise-polyfill/promise.js';
window.Promise = window.Promise || Promise;
export default (url) => {
return new window.Promise((resolve, reject) => {
const element = document.createElement('script');
element.onload = () => {
resolve(url);
};
element.onerror = () => {
reject(new Error(url));
};
element.async = true;
element.src = url;
document.body.appendChild(element);
});
};

View file

@ -1419,7 +1419,7 @@
aContent.push('' + sKey + '=' + sValue); aContent.push('' + sKey + '=' + sValue);
}); });
$('#rl-head-viewport').attr('content', aContent.join(', ')); $('#app-head-viewport').attr('content', aContent.join(', '));
}; };
/** /**
@ -1538,8 +1538,8 @@
Utils.changeTheme = function (sValue, themeTrigger) Utils.changeTheme = function (sValue, themeTrigger)
{ {
var var
oThemeLink = $('#rlThemeLink'), oThemeLink = $('#app-theme-link'),
oThemeStyle = $('#rlThemeStyle'), oThemeStyle = $('#app-theme-style'),
sUrl = oThemeLink.attr('href') sUrl = oThemeLink.attr('href')
; ;
@ -1576,7 +1576,7 @@
{ {
if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0])) if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0]))
{ {
oThemeStyle = $('<style id="rlThemeStyle"></style>'); oThemeStyle = $('<style id="app-theme-style"></style>');
oThemeLink.after(oThemeStyle); oThemeLink.after(oThemeStyle);
oThemeLink.remove(); oThemeLink.remove();
} }

24
dev/Html/Layout.html Normal file
View file

@ -0,0 +1,24 @@
<div id="rl-bg" class="thm-body"></div>
<div id="rl-loading" class="thm-loading" style="opacity:0">
<div id="rl-loading-desc"></div>
<div class="e-spinner">
<div class="e-bounce bounce1"></div>
<div class="e-bounce bounce2"></div>
<div class="e-bounce bounce3"></div>
</div>
</div>
<div id="rl-loading-error" class="thm-loading">
An error occurred. <br /> Please refresh the page and try again.
<div id="rl-loading-error-additional"></div>
</div>
<div id="rl-content">
<div id="rl-popups"></div>
<div id="rl-center">
<div id="rl-top"></div>
<div id="rl-left"></div>
<div id="rl-right"></div>
<div id="rl-bottom"></div>
</div>
</div>
<div id="rl-templates"></div>
<div id="rl-hidden"></div>

View file

@ -32,7 +32,7 @@ class RainLoopStorage
setHash() { setHash() {
const const
key = 'AuthAccountHash', key = 'AuthAccountHash',
appData = window.rainloopAppData appData = window.__rlah_data()
; ;
if (this.s) if (this.s)
{ {

View file

@ -8,7 +8,7 @@ class SettingsStorage
appSettings = {}; appSettings = {};
constructor() { constructor() {
this.settings = window.rainloopAppData || {}; this.settings = window.__rlah_data() || {};
this.settings = Utils.isNormal(this.settings) ? this.settings : {}; this.settings = Utils.isNormal(this.settings) ? this.settings : {};
this.appSettings = this.settings.System || null; this.appSettings = this.settings.System || null;

View file

@ -349,7 +349,7 @@ html.rl-ctrl-key-pressed {
#rl-loading, #rl-loading-error { #rl-loading, #rl-loading-error {
position: absolute; position: absolute;
font-size: 30px; font-size: 30px;
line-height: 100%; line-height: 130%;
top: 50%; top: 50%;
width: 100%; width: 100%;
height: 65px; height: 65px;
@ -370,6 +370,14 @@ html.rl-ctrl-key-pressed {
font-size: 20px; font-size: 20px;
} }
#rl-app{
display: none;
}
#rl-check{
display: block;
}
html.rl-mobile .hide-on-mobile { html.rl-mobile .hide-on-mobile {
display: none !important; display: none !important;
} }

View file

@ -28,10 +28,6 @@
opacity: 0; opacity: 0;
} }
#rl-check {
display: block;
}
.opentip-container { .opentip-container {
z-index: 2001 !important; z-index: 2001 !important;

View file

@ -1,12 +1,27 @@
import window from 'window'; import window from 'window';
import jsloader from 'Common/Loader';
import {progressJs} from 'progress.js/src/progress.js';
window.jsloader = jsloader;
window.progressJs = window.progressJs || progressJs();
window.progressJs.onbeforeend(() => {
if (window.$)
{
window.$('.progressjs-container').hide();
window.setTimeout(() => {
window.$('.progressjs-container').remove();
}, 100);
}
});
require('json2/json2.js'); require('json2/json2.js');
require('modernizr/modernizr-custom.js'); require('modernizr/modernizr-custom.js');
require('Common/Booter.jsx'); require('Common/Booter.jsx');
import {$LAB} from 'labjs/LAB.src.js'; if (window.__runBoot)
import {progressJs} from 'progress.js/src/progress.js'; {
window.__runBoot();
window.$LAB = $LAB; }
window.progressJs = progressJs;

View file

@ -48,17 +48,10 @@ export default (App) => {
window['rl']['EmailModel'] = EmailModel; window['rl']['EmailModel'] = EmailModel;
window['rl']['Enums'] = Enums; window['rl']['Enums'] = Enums;
window['__APP_BOOT'] = function (fCall) { window.__APP_BOOT = function (fCall) {
$(_.delay(function () { $(_.delay(function () {
if (!$('#rl-check').is(':visible'))
{
Globals.$html.addClass('no-css');
}
$('#rl-check').remove();
if (window['rainloopTEMPLATES'] && window['rainloopTEMPLATES'][0]) if (window['rainloopTEMPLATES'] && window['rainloopTEMPLATES'][0])
{ {
$('#rl-templates').html(window['rainloopTEMPLATES'][0]); $('#rl-templates').html(window['rainloopTEMPLATES'][0]);
@ -79,7 +72,7 @@ export default (App) => {
fCall(false); fCall(false);
} }
window['__APP_BOOT'] = null; window.__APP_BOOT = null;
}, 10)); }, 10));
}; };

View file

@ -97,7 +97,7 @@ function copyFile(sFile, sNewFile, callback)
callback(); callback();
} }
cfg.paths.globjs = 'dev/**/*.{js,jsx}'; cfg.paths.globjs = 'dev/**/*.{js,jsx,html}';
cfg.paths.globjsonly = 'dev/**/*.js'; cfg.paths.globjsonly = 'dev/**/*.js';
cfg.paths.globjsxonly = 'dev/**/*.jsx'; cfg.paths.globjsxonly = 'dev/**/*.jsx';
cfg.paths.static = 'rainloop/v/' + cfg.devVersion + '/static/'; cfg.paths.static = 'rainloop/v/' + cfg.devVersion + '/static/';
@ -260,7 +260,6 @@ gulp.task('package:community-off', function() {
}); });
gulp.task('css:clear-less', ['css:main-begin'], function() { gulp.task('css:clear-less', ['css:main-begin'], function() {
return gulp.src(cfg.paths.staticCSS + cfg.paths.less.main.name, {read: false}) return gulp.src(cfg.paths.staticCSS + cfg.paths.less.main.name, {read: false})
.pipe(require('gulp-rimraf')()); .pipe(require('gulp-rimraf')());
}); });

View file

@ -2,7 +2,7 @@
"name": "RainLoop", "name": "RainLoop",
"title": "RainLoop Webmail", "title": "RainLoop Webmail",
"version": "1.10.0", "version": "1.10.0",
"release": "108", "release": "112",
"ownCloudPackageVersion": "4.16", "ownCloudPackageVersion": "4.16",
"description": "Simple, modern & fast web-based email client", "description": "Simple, modern & fast web-based email client",
"homepage": "http://rainloop.net", "homepage": "http://rainloop.net",
@ -84,6 +84,7 @@
"lodash": "~3.9.3", "lodash": "~3.9.3",
"node-fs": "*", "node-fs": "*",
"node-notifier": "~4.2.3", "node-notifier": "~4.2.3",
"raw-loader": "^0.5.1",
"rimraf": "*", "rimraf": "*",
"webpack": "*" "webpack": "*"
} }

8
phpunit.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" stopOnFailure="true" syntaxCheck="true" bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite name="RainLoop Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>

View file

@ -1905,11 +1905,6 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
} }
} }
$sStaticCache = \md5(APP_VERSION.$this->Plugins()->Hash());
$sTheme = $this->ValidateTheme($sTheme, $bMobile);
$sNewThemeLink = './?/Css/0/'.($bAdmin ? 'Admin' : 'User').'/-/'.$sTheme.'/-/'.$sStaticCache.'/Hash/-/';
if (!$aResult['Auth']) if (!$aResult['Auth'])
{ {
if (!$bAdmin) if (!$bAdmin)
@ -1923,14 +1918,11 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
} }
} }
$sPluginsLink = ''; $sTheme = $this->ValidateTheme($sTheme, $bMobile);
if (0 < $this->Plugins()->Count() && $this->Plugins()->HaveJs($bAdmin)) $sStaticCache = $this->StaticCache();
{
$sPluginsLink = './?/Plugins/0/'.($bAdmin ? 'Admin' : 'User').'/'.$sStaticCache.'/';
}
$aResult['Theme'] = $sTheme; $aResult['Theme'] = $sTheme;
$aResult['NewThemeLink'] = $sNewThemeLink; $aResult['NewThemeLink'] = $this->ThemeLink($sTheme, $bAdmin);
$aResult['Language'] = $this->ValidateLanguage($sLanguage, '', false); $aResult['Language'] = $this->ValidateLanguage($sLanguage, '', false);
$aResult['LanguageAdmin'] = $this->ValidateLanguage($sLanguageAdmin, '', true); $aResult['LanguageAdmin'] = $this->ValidateLanguage($sLanguageAdmin, '', true);
@ -1940,11 +1932,23 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
$aResult['UserLanguage'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', false, true); $aResult['UserLanguage'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', false, true);
$aResult['UserLanguageAdmin'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', true, true); $aResult['UserLanguageAdmin'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', true, true);
$aResult['PluginsLink'] = '';
if (0 < $this->Plugins()->Count() && $this->Plugins()->HaveJs($bAdmin))
{
$aResult['PluginsLink'] = './?/Plugins/0/'.($bAdmin ? 'Admin' : 'User').'/'.$sStaticCache.'/';
}
$aResult['LangLink'] = './?/Lang/0/'.($bAdmin ? 'Admin' : 'App').'/'. $aResult['LangLink'] = './?/Lang/0/'.($bAdmin ? 'Admin' : 'App').'/'.
($bAdmin ? $aResult['LanguageAdmin'] : $aResult['Language']).'/'.$sStaticCache.'/'; ($bAdmin ? $aResult['LanguageAdmin'] : $aResult['Language']).'/'.$sStaticCache.'/';
$aResult['TemplatesLink'] = './?/Templates/0/'.($bAdmin ? 'Admin' : 'App').'/'.$sStaticCache.'/'; $aResult['TemplatesLink'] = './?/Templates/0/'.($bAdmin ? 'Admin' : 'App').'/'.$sStaticCache.'/';
$aResult['PluginsLink'] = $sPluginsLink;
$bAppJsDebug = !!$this->Config()->Get('labs', 'use_app_debug_js', false);
$aResult['StaticLibJsLink'] = $this->StaticPath('js/min/libs.js');
$aResult['StaticAppJsLink'] = $this->StaticPath('js/'.($bAppJsDebug ? '' : 'min/').($bAdmin ? 'admin' : 'app').'.js');
$aResult['StaticEditorJsLink'] = $this->StaticPath('ckeditor/ckeditor.js');
$aResult['EditorDefaultType'] = \in_array($aResult['EditorDefaultType'], array('Plain', 'Html', 'HtmlForced', 'PlainForced')) ? $aResult['EditorDefaultType'] = \in_array($aResult['EditorDefaultType'], array('Plain', 'Html', 'HtmlForced', 'PlainForced')) ?
$aResult['EditorDefaultType'] : 'Plain'; $aResult['EditorDefaultType'] : 'Plain';
@ -9057,6 +9061,29 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
return $mResult; return $mResult;
} }
/**
* @return string
*/
public function StaticCache()
{
static $sCache = null;
if (!$sCache)
{
$sCache = \md5(APP_VERSION.$this->Plugins()->Hash());
}
return $sCache;
}
/**
* @param string $sTheme
*
* @return string
*/
public function ThemeLink($sTheme, $bAdmin)
{
return './?/Css/0/'.($bAdmin ? 'Admin' : 'User').'/-/'.$sTheme.'/-/'.$this->StaticCache().'/Hash/-/';
}
/** /**
* @param string $sTheme * @param string $sTheme
* *
@ -9694,6 +9721,18 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
return isset($aLang[$sKey]) ? $aLang[$sKey] : $sKey; return isset($aLang[$sKey]) ? $aLang[$sKey] : $sKey;
} }
/**
* @param string $sPath
*
* @return string
*/
public function StaticPath($sPath)
{
$sResult = \RainLoop\Utils::WebStaticPath().$sPath;
return $sResult.(false === \strpos($sResult, '?') ? '?' : '&').
($this->IsOpen() ? 'community' : 'standard');
}
/** /**
* @return MailSo\Cache\CacheClient|null * @return MailSo\Cache\CacheClient|null
*/ */

View file

@ -241,7 +241,7 @@ class Service
$sResult .= '][owncloud:true'; $sResult .= '][owncloud:true';
} }
$sResult .= '] //-->'; $sResult .= ']-->';
} }
// Output result // Output result
@ -259,9 +259,7 @@ class Service
*/ */
private function staticPath($sPath) private function staticPath($sPath)
{ {
$sResult = \RainLoop\Utils::WebStaticPath().$sPath; return $this->oActions->StaticPath($sPath);
return $sResult.(false === \strpos($sResult, '?') ? '?' : '&').
($this->oActions->IsOpen() ? 'v=community' : 'v=standard');
} }
/** /**
@ -283,42 +281,27 @@ class Service
$sFaviconUrl = (string) $this->oActions->Config()->Get('webmail', 'favicon_url', ''); $sFaviconUrl = (string) $this->oActions->Config()->Get('webmail', 'favicon_url', '');
$aData = array( $sFaviconPngLink = $sFaviconUrl ? $sFaviconUrl : $this->staticPath('apple-touch-icon.png');
'Language' => $sLanguage, $sAppleTouchLink = $sFaviconUrl ? '' : $this->staticPath('apple-touch-icon.png');
'Theme' => $sTheme,
'FaviconPngLink' => $sFaviconUrl ? $sFaviconUrl : $this->staticPath('apple-touch-icon.png'),
'AppleTouchLink' => $sFaviconUrl ? '' : $this->staticPath('apple-touch-icon.png'),
'AppCssLink' => $this->staticPath('css/app'.($bAppCssDebug ? '' : '.min').'.css'),
'BootJsLink' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'boot.js'),
'LibJsLink' => $this->staticPath('js/min/libs.js'),
'EditorJsLink' => $this->staticPath('ckeditor/ckeditor.js'),
'OpenPgpJsLink' => $this->staticPath('js/min/openpgp.min.js'),
'AppJsCommonLink' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'common.js'),
'AppJsLink' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').($bAdmin ? 'admin' : 'app').'.js')
);
$aAdd = array();
$aAdd[] = $bMobile ? 'mobile' : 'no-mobile';
$aAdd[] = $bMobileDevice ? '1' : '0';
$aTemplateParameters = array( $aTemplateParameters = array(
'{{BaseAppDataScriptLink}}' => ($bAdmin ? './?/AdminAppData' : './?/AppData').(0 < \count($aAdd) ? '@'.\implode('-', $aAdd) : '').'/', '{{BaseAppFaviconPngLinkTag}}' => $sFaviconPngLink ? '<link type="image/png" rel="shortcut icon" href="'.$sFaviconPngLink.'" />' : '',
'{{BaseAppFaviconPngLinkTag}}' => $aData['FaviconPngLink'] ? '<link rel="shortcut icon" href="'.$aData['FaviconPngLink'].'" type="image/png" />' : '', '{{BaseAppFaviconTouchLinkTag}}' => $sAppleTouchLink ? '<link type="image/png" rel="apple-touch-icon" href="'.$sAppleTouchLink.'" />' : '',
'{{BaseAppFaviconTouchLinkTag}}' => $aData['AppleTouchLink'] ? '<link rel="apple-touch-icon" href="'.$aData['AppleTouchLink'].'" type="image/png" />' : '', '{{BaseAppMainCssLink}}' => $this->staticPath('css/app'.($bAppCssDebug ? '' : '.min').'.css'),
'{{BaseAppAppleTouchFile}}' => $aData['AppleTouchLink'], '{{BaseAppThemeCssLink}}' => $this->oActions->ThemeLink($sTheme, $bAdmin),
'{{BaseAppMainCssLink}}' => $aData['AppCssLink'], '{{BaseAppBootScriptLink}}' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'boot.js'),
'{{BaseAppBootScriptLink}}' => $aData['BootJsLink'],
'{{BaseAppLibsScriptLink}}' => $aData['LibJsLink'],
'{{BaseAppEditorScriptLink}}' => $aData['EditorJsLink'],
'{{BaseAppOpenPgpScriptLink}}' => $aData['OpenPgpJsLink'],
'{{BaseAppMainCommonScriptLink}}' => $aData['AppJsCommonLink'],
'{{BaseAppMainScriptLink}}' => $aData['AppJsLink'],
'{{BaseVersion}}' => APP_VERSION,
'{{BaseViewport}}' => $bMobile ? 'width=device-width,initial-scale=1,user-scalable=no' : 'width=950,maximum-scale=2', '{{BaseViewport}}' => $bMobile ? 'width=device-width,initial-scale=1,user-scalable=no' : 'width=950,maximum-scale=2',
'{{BaseDir}}' => 'ltr' '{{BaseDir}}' => false && \in_array($sLanguage, array('ar', 'he', 'ur')) ? 'rtl' : 'ltr'
// '{{BaseDir}}' => \in_array($aData['Language'], array('ar', 'he', 'ur')) ? 'rtl' : 'ltr'
); );
$aTemplateParameters['{{RainloopBootData}}'] = \json_encode(array(
'admin' => $bAdmin,
'language' => $sLanguage,
'theme' => $sTheme,
'mobile' => $bMobile,
'mobileDevice' => $bMobileDevice
));
$aTemplateParameters['{{BaseHash}}'] = \md5( $aTemplateParameters['{{BaseHash}}'] = \md5(
\implode('~', array( \implode('~', array(
$bAdmin ? '1' : '0', $bAdmin ? '1' : '0',

View file

@ -1369,9 +1369,8 @@ class ServiceActions
private function compileAppData($aAppData, $bWrapByScriptTag = true) private function compileAppData($aAppData, $bWrapByScriptTag = true)
{ {
return return
($bWrapByScriptTag ? '<script data-cfasync="false">' : ''). ($bWrapByScriptTag ? '<script type="text/javascript" data-cfasync="false">' : '').
'window.rainloopAppData='.\json_encode($aAppData).';'. 'if(window.__initAppData){window.__initAppData('.\json_encode($aAppData).');}'.
'if(window.__rlah_set){__rlah_set()};'.
($bWrapByScriptTag ? '</script>' : '') ($bWrapByScriptTag ? '</script>' : '')
; ;
} }

View file

@ -475,12 +475,13 @@ class Utils
public static function ClearHtmlOutput($sHtml) public static function ClearHtmlOutput($sHtml)
{ {
// return $sHtml; // return $sHtml;
return \str_replace('> <', '><', return \trim(\str_replace('> <', '><',
\str_replace('" />', '"/>',
\preg_replace('/[\s]+&nbsp;/i', '&nbsp;', \preg_replace('/[\s]+&nbsp;/i', '&nbsp;',
\preg_replace('/&nbsp;[\s]+/i', '&nbsp;', \preg_replace('/&nbsp;[\s]+/i', '&nbsp;',
\preg_replace('/[\r\n\t]+/', ' ', \preg_replace('/[\r\n\t]+/', ' ',
$sHtml $sHtml
)))); ))))));
} }
/** /**

View file

@ -1,74 +1,29 @@
<!DOCTYPE html> <!DOCTYPE html>
<html class="no-js rl-booted-trigger rl-started-trigger" dir="{{BaseDir}}"> <html class="no-js rl-booted-trigger rl-started-trigger" dir="{{BaseDir}}">
<head> <head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta id="rl-head-viewport" name="viewport" content="{{BaseViewport}}">
<meta name="apple-mobile-web-app-capable" content="yes" />
<noscript> <noscript>
<meta http-equiv="refresh" content="0; URL=./?/NoScript" /> <meta http-equiv="refresh" content="0; URL=./?/NoScript" />
</noscript> </noscript>
<!--[if lte IE 8]> <!--[if lte IE 8]>
<meta http-equiv="refresh" content="0; URL=./?/BadBrowser" /> <meta http-equiv="refresh" content="0; URL=./?/BadBrowser" />
<![endif]--> <![endif]-->
<script type="text/javascript" data-cfasync="false"> <meta charset="utf-8" />
if (!window.navigator || !window.navigator.cookieEnabled) { <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
window.document.location.replace('./?/NoCookie'); <meta name="viewport" content="{{BaseViewport}}" id="app-head-viewport">
} <meta name="apple-mobile-web-app-capable" content="yes" />
</script>
<meta name="Author" content="RainLoop Team" />
<meta name="robots" content="noindex,nofollow,noodp" />
<meta name="google" content="notranslate" /> <meta name="google" content="notranslate" />
<meta name="robots" content="noindex,nofollow,noodp" />
<meta name="AppBootData" content='{{RainloopBootData}}' id="app-boot-data" />
<title></title> <title></title>
<style>#rl-content{display:none;}#rl-check{display:none;}</style> {{BaseAppFaviconPngLinkTag}}
{{BaseAppFaviconPngLinkTag}}{{BaseAppFaviconTouchLinkTag}} {{BaseAppFaviconTouchLinkTag}}
<style>#rl-check{display:none}</style>
<link type="text/css" rel="stylesheet" href="{{BaseAppMainCssLink}}" /> <link type="text/css" rel="stylesheet" href="{{BaseAppMainCssLink}}" />
<link type="text/css" rel="stylesheet" id="rlThemeLink" /> <link type="text/css" rel="stylesheet" href="{{BaseAppThemeCssLink}}" id="app-theme-link" />
<script type="text/javascript" data-cfasync="false" src="{{BaseAppBootScriptLink}}"></script>
<script type="text/javascript" data-cfasync="false">
window.__includeAppScr('{{BaseAppDataScriptLink}}');
</script>
<script type="text/javascript" data-cfasync="false">
if (window.rainloopAppData && window.rainloopAppData['NewThemeLink']) {
window.document.getElementById('rlThemeLink').href = window.rainloopAppData['NewThemeLink'];
}
</script>
<script type="text/javascript" data-cfasync="false">
if (window.rainloopAppData && window.rainloopAppData['IncludeCss']) {
window.__includeStyle(window.rainloopAppData['IncludeCss']);
}
</script>
<script type="text/javascript" data-cfasync="false"></script>
</head> </head>
<body> <body>
<div id="rl-app"></div>
<div id="rl-check"></div> <div id="rl-check"></div>
<div id="rl-bg" class="thm-body"></div> <script type="text/javascript" data-cfasync="false" src="{{BaseAppBootScriptLink}}"></script>
<div id="rl-loading" class="thm-loading">
<div id="rl-loading-desc">Loading</div>
<div class="e-spinner">
<div class="e-bounce bounce1"></div>
<div class="e-bounce bounce2"></div>
<div class="e-bounce bounce3"></div>
</div>
</div>
<div id="rl-loading-error" class="thm-loading">
An Error occurred,
<br />
please refresh the page and try again.
<div id="rl-loading-error-additional"></div>
</div>
<div id="rl-content">
<div id="rl-popups"></div>
<div id="rl-center">
<div id="rl-top"></div>
<div id="rl-left"></div>
<div id="rl-right"></div>
<div id="rl-bottom"></div>
</div>
</div>
<div id="rl-templates"></div>
<div id="rl-hidden"></div>
<script type="text/javascript" data-cfasync="false">__showDescription(window.rainloopAppData ? window.rainloopAppData['LoadingDescriptionEsc'] : '');</script>
<script type="text/javascript" data-cfasync="false">__runApp('{{BaseAppLibsScriptLink}}', '{{BaseAppMainScriptLink}}', '{{BaseAppEditorScriptLink}}');</script>
</body> </body>
</html> </html>

View file

@ -187,9 +187,39 @@
.thm-rgba-background-color(@message-background-color, @message-rgba-background-color); .thm-rgba-background-color(@message-background-color, @message-rgba-background-color);
} }
#rl-app{
display: block;
}
html.no-css { html.no-css {
margin: 0;
padding: 0;
font-family: Arial, Verdana, Geneva, sans-serif;
body {
margin: 0;
padding: 0;
}
#rl-loading, #rl-loading-error {
position: absolute;
font-size: 30px;
line-height: 130%;
top: 50%;
width: 100%;
height: 65px;
margin: 0;
margin-top: -60px;
background-color: transparent;
text-align: center;
color: #333;
}
.progressjs-container {
display: none;
}
.thm-body { .thm-body {
color: #333; color: #333;
background-color: #aaa; background-color: #aaa;

View file

@ -3,13 +3,12 @@
<div class="btn-toolbar"> <div class="btn-toolbar">
<div class="btn-group btn-group-last pull-right dropdown colored-toggle" data-bind="registrateBootstrapDropdown: true, openDropdownTrigger: accountMenuDropdownTrigger"> <div class="btn-group btn-group-last pull-right dropdown colored-toggle" data-bind="registrateBootstrapDropdown: true, openDropdownTrigger: accountMenuDropdownTrigger">
<a id="top-system-dropdown-id" href="#" tabindex="-1" class="btn single btn-ellipsis btn-block dropdown-toggle system-dropdown" data-toggle="dropdown"> <a id="top-system-dropdown-id" href="#" tabindex="-1" class="btn single btn-ellipsis btn-block dropdown-toggle system-dropdown" data-toggle="dropdown">
<i data-bind="css: {'icon-user': !accounts.loading(), 'icon-spinner animated': accounts.loading()}" <i data-bind="css: {'icon-user': !accounts.loading(), 'icon-spinner animated': accounts.loading()}"></i>
></i>
<!-- <!--
<b data-bind="text: accountsUnreadCount, visible: 100 > accountsUnreadCount() && 0 < accountsUnreadCount()"></b> <b data-bind="text: accountsUnreadCount, visible: 100 > accountsUnreadCount() && 0 < accountsUnreadCount()"></b>
<b data-bind="visible: 99 < accountsUnreadCount()">99+</b> <b data-bind="visible: 99 < accountsUnreadCount()">99+</b>
-->
&nbsp; &nbsp;
-->
&nbsp; &nbsp;
<span class="caret"></span> <span class="caret"></span>
</a> </a>

View file

@ -1,6 +0,0 @@
module.exports = {
url: 'https://mail.rainloop.net/',
testLogin: 'demo@rainloop.test',
testPassword: '12345'
};

1
tests/bootstrap.php Normal file
View file

@ -0,0 +1 @@
<?php

View file

@ -1,70 +0,0 @@
var cfg = require('./_config.js');
casper.start(cfg.url);
casper.then(function() {
this.echo('testing: ' + cfg.url);
}).wait(100);
casper.then(function() {
casper.test.begin('Login page should contains "Sign In" button', 1, function (test) {
casper.then(function() {
test.assertExists('button.buttonLogin');
});
casper.then(function() {
test.done();
});
});
casper.test.begin('Login page should allow langs selection', 3, function (test) {
casper.then(function() {
test.assertExists('.e-languages .flag-selector .flag-name');
});
casper.then(function() {
this.click('.e-languages .flag-selector .flag-name');
}).wait(300);
casper.then(function() {
test.assertExists('.b-languages-content');
});
casper.then(function() {
this.click('.b-languages-content .lang-item .flag.flag-ru_ru');
}).wait(1000);
casper.then(function() {
test.assertEquals('Войти', this.fetchText('button.buttonLogin'));
});
casper.then(function() {
test.done();
});
});
casper.test.begin('Login page submit', 1, function (test) {
casper.then(function() {
this.fill('form.loginForm', {
'RainLoopEmail': cfg.testLogin,
'RainLoopPassword': cfg.testPassword
}, true);
}).wait(3000);
casper.then(function() {
test.assertEquals(cfg.testLogin, this.fetchText('.accountPlace'));
});
casper.then(function() {
test.done();
});
});
});
casper.run();

View file

@ -0,0 +1,2 @@
/node_modules
/tmp

View file

@ -0,0 +1,3 @@
/node_modules/
/tmp
/test

View file

@ -0,0 +1,6 @@
language: node_js
sudo: false
node_js:
- "0.12"
- "node"
- "iojs"

View file

@ -0,0 +1,18 @@
## 1.2.0 (December 8, 2015)
- Support for IE8 and below
- Promises/A+ tests added
## 1.1.0 (October 16, 2015)
- Change way to get reference to `global`, since `Function()()` may be prohibited
- Add AMD support
## 1.0.1 (September 14, 2015)
- Fix exports - use polyfill only if native implementation isn't supported
- Add license
## 1.0.0 (June 19, 2014)
- Init release

View file

@ -1,4 +1,6 @@
Copyright 2015 RainLoop Team (The MIT License)
Copyright (c) 2014 Roman Dvornov
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the

88
vendors/es6-promise-polyfill/README.md vendored Normal file
View file

@ -0,0 +1,88 @@
[![NPM version](https://img.shields.io/npm/v/es6-promise-polyfill.svg)](https://www.npmjs.com/package/es6-promise-polyfill)
[![Build Status](https://travis-ci.org/lahmatiy/es6-promise-polyfill.svg?branch=master)](https://travis-ci.org/lahmatiy/es6-promise-polyfill)
# ES6 Promise polyfill
This is a polyfill of [ES6 Promise](https://github.com/domenic/promises-unwrapping). The implementation based on [Jake Archibald implementation](https://github.com/jakearchibald/es6-promise) a subset of [rsvp.js](https://github.com/tildeio/rsvp.js). If you're wanting extra features and more debugging options, check out the [full library](https://github.com/tildeio/rsvp.js).
For API details and how to use promises, see the <a href="http://www.html5rocks.com/en/tutorials/es6/promises/">JavaScript Promises HTML5Rocks article</a>.
## Notes
The main target: implementation should be conformance with browser's implementations and to be minimal as possible in size. So it's strictly polyfill of ES6 Promise specification and nothing more.
It passes both [Promises/A+ test suite](https://github.com/promises-aplus/promises-tests) and [rsvp.js test suite](https://github.com/jakearchibald/es6-promise/tree/master/test). And as small as 2,6KB min (or 1KB min+gzip).
The polyfill uses `setImmediate` if available, or fallback to use `setTimeout`. Use [setImmediate polyfill](https://github.com/YuzuJS/setImmediate) by @YuzuJS to reach better performance.
## How to use
### Browser
To install:
```sh
bower install es6-promise-polyfill
```
To use:
```html
<script src="bower_components/es6-promise-polyfill/promise.min.js"></script>
<script>
var promise = new Promise(...);
</script>
```
### Node.js
To install:
```sh
npm install es6-promise-polyfill
```
To use:
```js
var Promise = require('es6-promise-polyfill').Promise;
var promise = new Promise(...);
```
### AMD
To install:
```sh
npm install es6-promise-polyfill
```
To use:
```js
define(['es6-promise-polyfill'], function(Promise) {
var promise = new Promise(...);
});
```
## Usage in IE<9
`catch` is a reserved word in IE<9, meaning `promise.catch(func)` throws a syntax error. To work around this, use a string to access the property:
```js
promise['catch'](function(err) {
// ...
});
```
Or use `.then` instead:
```js
promise.then(undefined, function(err) {
// ...
});
```
## License
Licensed under the MIT License.

11
vendors/es6-promise-polyfill/bower.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"name": "es6-promise-polyfill",
"version": "1.1.1",
"main": "promise.js",
"ignore": [
".*",
"**/.*",
"node_modules",
"test"
]
}

View file

@ -0,0 +1,27 @@
{
"name": "es6-promise-polyfill",
"description": "Polyfill for ES6 Promise",
"version": "1.2.0",
"author": "Roman Dvornov <rdvornov@gmail.com>",
"license": "MIT",
"repository": "lahmatiy/es6-promise-polyfill",
"bugs": {
"url": "https://github.com/lahmatiy/es6-promise-polyfill/issues"
},
"main": "promise.js",
"dependencies": {
},
"devDependencies": {
"promises-aplus-tests": "*"
},
"scripts": {
"test": "promises-aplus-tests test/test-adapter"
},
"keywords": [
"es6",
"es2015",
"polyfill",
"promise",
"promises"
]
}

346
vendors/es6-promise-polyfill/promise.js vendored Normal file
View file

@ -0,0 +1,346 @@
(function(global){
//
// Check for native Promise and it has correct interface
//
var NativePromise = global['Promise'];
var nativePromiseSupported =
NativePromise &&
// Some of these methods are missing from
// Firefox/Chrome experimental implementations
'resolve' in NativePromise &&
'reject' in NativePromise &&
'all' in NativePromise &&
'race' in NativePromise &&
// Older version of the spec had a resolver object
// as the arg rather than a function
(function(){
var resolve;
new NativePromise(function(r){ resolve = r; });
return typeof resolve === 'function';
})();
//
// export if necessary
//
if (typeof exports !== 'undefined' && exports)
{
// node.js
exports.Promise = nativePromiseSupported ? NativePromise : Promise;
exports.Polyfill = Promise;
}
else
{
// AMD
if (typeof define == 'function' && define.amd)
{
define(function(){
return nativePromiseSupported ? NativePromise : Promise;
});
}
else
{
// in browser add to global
if (!nativePromiseSupported)
global['Promise'] = Promise;
}
}
//
// Polyfill
//
var PENDING = 'pending';
var SEALED = 'sealed';
var FULFILLED = 'fulfilled';
var REJECTED = 'rejected';
var NOOP = function(){};
function isArray(value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
// async calls
var asyncSetTimer = typeof setImmediate !== 'undefined' ? setImmediate : setTimeout;
var asyncQueue = [];
var asyncTimer;
function asyncFlush(){
// run promise callbacks
for (var i = 0; i < asyncQueue.length; i++)
asyncQueue[i][0](asyncQueue[i][1]);
// reset async asyncQueue
asyncQueue = [];
asyncTimer = false;
}
function asyncCall(callback, arg){
asyncQueue.push([callback, arg]);
if (!asyncTimer)
{
asyncTimer = true;
asyncSetTimer(asyncFlush, 0);
}
}
function invokeResolver(resolver, promise) {
function resolvePromise(value) {
resolve(promise, value);
}
function rejectPromise(reason) {
reject(promise, reason);
}
try {
resolver(resolvePromise, rejectPromise);
} catch(e) {
rejectPromise(e);
}
}
function invokeCallback(subscriber){
var owner = subscriber.owner;
var settled = owner.state_;
var value = owner.data_;
var callback = subscriber[settled];
var promise = subscriber.then;
if (typeof callback === 'function')
{
settled = FULFILLED;
try {
value = callback(value);
} catch(e) {
reject(promise, e);
}
}
if (!handleThenable(promise, value))
{
if (settled === FULFILLED)
resolve(promise, value);
if (settled === REJECTED)
reject(promise, value);
}
}
function handleThenable(promise, value) {
var resolved;
try {
if (promise === value)
throw new TypeError('A promises callback cannot return that same promise.');
if (value && (typeof value === 'function' || typeof value === 'object'))
{
var then = value.then; // then should be retrived only once
if (typeof then === 'function')
{
then.call(value, function(val){
if (!resolved)
{
resolved = true;
if (value !== val)
resolve(promise, val);
else
fulfill(promise, val);
}
}, function(reason){
if (!resolved)
{
resolved = true;
reject(promise, reason);
}
});
return true;
}
}
} catch (e) {
if (!resolved)
reject(promise, e);
return true;
}
return false;
}
function resolve(promise, value){
if (promise === value || !handleThenable(promise, value))
fulfill(promise, value);
}
function fulfill(promise, value){
if (promise.state_ === PENDING)
{
promise.state_ = SEALED;
promise.data_ = value;
asyncCall(publishFulfillment, promise);
}
}
function reject(promise, reason){
if (promise.state_ === PENDING)
{
promise.state_ = SEALED;
promise.data_ = reason;
asyncCall(publishRejection, promise);
}
}
function publish(promise) {
var callbacks = promise.then_;
promise.then_ = undefined;
for (var i = 0; i < callbacks.length; i++) {
invokeCallback(callbacks[i]);
}
}
function publishFulfillment(promise){
promise.state_ = FULFILLED;
publish(promise);
}
function publishRejection(promise){
promise.state_ = REJECTED;
publish(promise);
}
/**
* @class
*/
function Promise(resolver){
if (typeof resolver !== 'function')
throw new TypeError('Promise constructor takes a function argument');
if (this instanceof Promise === false)
throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.');
this.then_ = [];
invokeResolver(resolver, this);
}
Promise.prototype = {
constructor: Promise,
state_: PENDING,
then_: null,
data_: undefined,
then: function(onFulfillment, onRejection){
var subscriber = {
owner: this,
then: new this.constructor(NOOP),
fulfilled: onFulfillment,
rejected: onRejection
};
if (this.state_ === FULFILLED || this.state_ === REJECTED)
{
// already resolved, call callback async
asyncCall(invokeCallback, subscriber);
}
else
{
// subscribe
this.then_.push(subscriber);
}
return subscriber.then;
},
'catch': function(onRejection) {
return this.then(null, onRejection);
}
};
Promise.all = function(promises){
var Class = this;
if (!isArray(promises))
throw new TypeError('You must pass an array to Promise.all().');
return new Class(function(resolve, reject){
var results = [];
var remaining = 0;
function resolver(index){
remaining++;
return function(value){
results[index] = value;
if (!--remaining)
resolve(results);
};
}
for (var i = 0, promise; i < promises.length; i++)
{
promise = promises[i];
if (promise && typeof promise.then === 'function')
promise.then(resolver(i), reject);
else
results[i] = promise;
}
if (!remaining)
resolve(results);
});
};
Promise.race = function(promises){
var Class = this;
if (!isArray(promises))
throw new TypeError('You must pass an array to Promise.race().');
return new Class(function(resolve, reject) {
for (var i = 0, promise; i < promises.length; i++)
{
promise = promises[i];
if (promise && typeof promise.then === 'function')
promise.then(resolve, reject);
else
resolve(promise);
}
});
};
Promise.resolve = function(value){
var Class = this;
if (value && typeof value === 'object' && value.constructor === Class)
return value;
return new Class(function(resolve){
resolve(value);
});
};
Promise.reject = function(reason){
var Class = this;
return new Class(function(resolve, reject){
reject(reason);
});
};
})(typeof window != 'undefined' ? window : typeof global != 'undefined' ? global : typeof self != 'undefined' ? self : this);

View file

@ -0,0 +1,6 @@
(function(t){function z(){for(var a=0;a<g.length;a++)g[a][0](g[a][1]);g=[];m=!1}function n(a,b){g.push([a,b]);m||(m=!0,A(z,0))}function B(a,b){function c(a){p(b,a)}function h(a){k(b,a)}try{a(c,h)}catch(d){h(d)}}function u(a){var b=a.owner,c=b.state_,b=b.data_,h=a[c];a=a.then;if("function"===typeof h){c=l;try{b=h(b)}catch(d){k(a,d)}}v(a,b)||(c===l&&p(a,b),c===q&&k(a,b))}function v(a,b){var c;try{if(a===b)throw new TypeError("A promises callback cannot return that same promise.");if(b&&("function"===
typeof b||"object"===typeof b)){var h=b.then;if("function"===typeof h)return h.call(b,function(d){c||(c=!0,b!==d?p(a,d):w(a,d))},function(b){c||(c=!0,k(a,b))}),!0}}catch(d){return c||k(a,d),!0}return!1}function p(a,b){a!==b&&v(a,b)||w(a,b)}function w(a,b){a.state_===r&&(a.state_=x,a.data_=b,n(C,a))}function k(a,b){a.state_===r&&(a.state_=x,a.data_=b,n(D,a))}function y(a){var b=a.then_;a.then_=void 0;for(a=0;a<b.length;a++)u(b[a])}function C(a){a.state_=l;y(a)}function D(a){a.state_=q;y(a)}function e(a){if("function"!==
typeof a)throw new TypeError("Promise constructor takes a function argument");if(!1===this instanceof e)throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");this.then_=[];B(a,this)}var f=t.Promise,s=f&&"resolve"in f&&"reject"in f&&"all"in f&&"race"in f&&function(){var a;new f(function(b){a=b});return"function"===typeof a}();"undefined"!==typeof exports&&exports?(exports.Promise=s?f:e,exports.Polyfill=e):"function"==
typeof define&&define.amd?define(function(){return s?f:e}):s||(t.Promise=e);var r="pending",x="sealed",l="fulfilled",q="rejected",E=function(){},A="undefined"!==typeof setImmediate?setImmediate:setTimeout,g=[],m;e.prototype={constructor:e,state_:r,then_:null,data_:void 0,then:function(a,b){var c={owner:this,then:new this.constructor(E),fulfilled:a,rejected:b};this.state_===l||this.state_===q?n(u,c):this.then_.push(c);return c.then},"catch":function(a){return this.then(null,a)}};e.all=function(a){if("[object Array]"!==
Object.prototype.toString.call(a))throw new TypeError("You must pass an array to Promise.all().");return new this(function(b,c){function h(a){e++;return function(c){d[a]=c;--e||b(d)}}for(var d=[],e=0,f=0,g;f<a.length;f++)(g=a[f])&&"function"===typeof g.then?g.then(h(f),c):d[f]=g;e||b(d)})};e.race=function(a){if("[object Array]"!==Object.prototype.toString.call(a))throw new TypeError("You must pass an array to Promise.race().");return new this(function(b,c){for(var e=0,d;e<a.length;e++)(d=a[e])&&"function"===
typeof d.then?d.then(b,c):b(d)})};e.resolve=function(a){return a&&"object"===typeof a&&a.constructor===this?a:new this(function(b){b(a)})};e.reject=function(a){return new this(function(b,c){c(a)})}})("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this);

View file

@ -0,0 +1,22 @@
var assert = require('assert');
var Promise = require('../promise').Polyfill;
var resolve = Promise.resolve;
var reject = Promise.reject;
function defer(){
var deferred = {};
deferred.promise = new Promise(function(resolve, reject){
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
}
module.exports = {
resolved: function(a){ return Promise.resolve(a); },
rejected: function(a){ return Promise.reject(a); },
deferred: defer,
Promise: Promise
};

View file

@ -1,2 +0,0 @@
/*! RainLoop Index Helper v1.5 (c) 2015 RainLoop Team; Licensed under MIT */
!function(t,e,n){function r(){}r.prototype.s=t.sessionStorage,r.prototype.t=t.top||t,r.prototype.getHash=function(){var t=null;if(this.s)t=this.s.getItem("__rlA")||null;else if(this.t){var e=this.t.name&&n&&"{"===this.t.name.toString().substr(0,1)?n.parse(this.t.name.toString()):null;t=e?e.__rlA||null:null}return t},r.prototype.setHash=function(){var e=t.rainloopAppData,r=null;this.s?this.s.setItem("__rlA",e&&e.AuthAccountHash?e.AuthAccountHash:""):this.t&&n&&(r={},r.__rlA=e&&e.AuthAccountHash?e.AuthAccountHash:"",this.t.name=n.stringify(r))},r.prototype.clearHash=function(){this.s?this.s.setItem("__rlA",""):this.t&&(this.t.name="")},t._rlhh=new r,t.__rlah=function(){return t._rlhh?t._rlhh.getHash():null},t.__rlah_set=function(){t._rlhh&&t._rlhh.setHash()},t.__rlah_clear=function(){t._rlhh&&t._rlhh.clearHash()},t.__includeScr=function(t){e.write(unescape('%3Cscript data-cfasync="false" type="text/javascript" src="'+t+'"%3E%3C/script%3E'))},t.__includeStyle=function(t){e.write(unescape("%3Cstyle%3E"+t+'"%3E%3C/style%3E'))},t.__showError=function(n){var r=e.getElementById("rl-loading"),s=e.getElementById("rl-loading-error"),l=e.getElementById("rl-loading-error-additional");r&&(r.style.display="none"),s&&(s.style.display="block"),l&&n&&(l.style.display="block",l.innerHTML=n),t.SimplePace&&t.SimplePace.set(100)},t.__simplePace=function(e){t.SimplePace&&t.SimplePace.add(e)},t.__runBoot=function(e,n){t.__APP_BOOT&&!e?t.__APP_BOOT(function(t){t||__showError(n)}):__showError(n)}}(window,window.document,window.JSON);

105
vendors/rl/rl.js vendored
View file

@ -1,105 +0,0 @@
/*! RainLoop Index Helper v1.5 (c) 2015 RainLoop Team; Licensed under MIT */
(function (window, document, JSON, undefined) {
/**
* @constructor
*/
function CRLTopDriver() {}
CRLTopDriver.prototype.s = window['sessionStorage'] || null;
CRLTopDriver.prototype.t = window['top'] || window;
/**
* @return {(string|null)}
*/
CRLTopDriver.prototype['getHash'] = function() {
var mR = null;
if (this.s) {
mR = this.s['getItem']('__rlA') || null;
} else if (this.t) {
var mData = this.t['name'] && JSON && '{' === this.t['name']['toString']()['substr'](0, 1) ? JSON['parse'](this.t['name']['toString']()) : null;
mR = mData ? (mData['__rlA'] || null) : null;
}
return mR;
};
CRLTopDriver.prototype['setHash'] = function() {
var mData = window['rainloopAppData'], mRes = null;
if (this.s) {
this.s['setItem']('__rlA', mData && mData['AuthAccountHash'] ? mData['AuthAccountHash'] : '');
} else if (this.t && JSON) {
mRes = {};
mRes['__rlA'] = mData && mData['AuthAccountHash'] ? mData['AuthAccountHash'] : '';
this.t['name'] = JSON['stringify'](mRes);
}
};
CRLTopDriver.prototype['clearHash'] = function() {
if (this.s) {
this.s['setItem']('__rlA', '');
} else if (this.t) {
this.t['name'] = '';
}
};
window['_rlhh'] = new CRLTopDriver();
/**
* @returns {(string|null)}
*/
window['__rlah'] = function () {
return window['_rlhh'] ? window['_rlhh']['getHash']() : null;
};
window['__rlah_set'] = function () {
if (window['_rlhh']) {
window['_rlhh']['setHash']();
}
};
window['__rlah_clear'] = function () {
if (window['_rlhh']) {
window['_rlhh']['clearHash']();
}
};
// index function
window['__includeScr'] = function (sSrc) {
document.write(unescape('%3Csc' + 'ript data-cfasync="false" type="text/jav' + 'ascr' + 'ipt" sr' + 'c="' + sSrc + '"%3E%3C/' + 'scr' + 'ipt%3E'));
};
window['__includeStyle'] = function (sStyles) {
document.write(unescape('%3Csty' + 'le%3E' + sStyles + '"%3E%3C/' + 'sty' + 'le%3E'));
};
window['__showError'] = function (sAdditionalError) {
var oR = document.getElementById('rl-loading'),
oL = document.getElementById('rl-loading-error'),
oLA = document.getElementById('rl-loading-error-additional');
if (oR) {oR.style.display = 'none';}
if (oL) {oL.style.display = 'block';}
if (oLA && sAdditionalError) { oLA.style.display = 'block'; oLA.innerHTML = sAdditionalError; }
if (window.SimplePace) {window.SimplePace.set(100);}
};
window['__simplePace'] = function (nVal) {
if (window.SimplePace) {
window.SimplePace.add(nVal);
}
};
window['__runBoot'] = function (bWithError, sAdditionalError) {
if (window.__APP_BOOT && !bWithError) {
window.__APP_BOOT(function (bV) {
if (!bV) {
__showError(sAdditionalError);
}
});
} else {
__showError(sAdditionalError);
}
};
}(window, window.document, window.JSON));

View file

@ -32,6 +32,10 @@ module.exports = {
}, },
module: { module: {
loaders: [ loaders: [
{
test: /\.html$/,
loader: 'raw'
},
{ {
test: /\.jsx$/, test: /\.jsx$/,
loader: 'babel', loader: 'babel',
@ -49,7 +53,7 @@ module.exports = {
'JSON': 'window.JSON', 'JSON': 'window.JSON',
'JSEncrypt': 'window.JSEncrypt', 'JSEncrypt': 'window.JSEncrypt',
'$LAB': 'window.$LAB', '$LAB': 'window.$LAB',
'progressJs': 'window.rainloopProgressJs', 'progressJs': 'window.progressJs',
'queue': 'window.queue', 'queue': 'window.queue',
'moment': 'window.moment', 'moment': 'window.moment',
'ifvisible': 'window.ifvisible', 'ifvisible': 'window.ifvisible',