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();
this.iframe = $('<iframe style="display:none" src="javascript:;" />').appendTo('body');
this.iframe = $('<iframe style="display:none" />').appendTo('body');
Globals.$win.on('error', function (oEvent) {
if (oEvent && oEvent.originalEvent && oEvent.originalEvent.message &&

View file

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

View file

@ -1,13 +1,20 @@
import window from 'window';
import $ from '$';
import progressJs from 'progressJs';
import rainLoopStorage from 'Storage/RainLoop';
let rlAppDataStorage = null;
window.__rlah = () => {
return rainLoopStorage ? rainLoopStorage.getHash() : null;
};
window.__rlah_data = () => {
return rlAppDataStorage;
};
window.__rlah_set = () => {
if (rainLoopStorage)
{
@ -22,20 +29,59 @@ window.__rlah_clear = () => {
}
};
window.__includeScr = (src) => {
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) => {
function includeStyle(styles)
{
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
oR = window.document.getElementById('rl-loading'),
oL = window.document.getElementById('rl-loading-error'),
@ -58,14 +104,14 @@ window.__showError = (additionalError) => {
oLA.innerHTML = additionalError;
}
if (window.rainloopProgressJs)
if (progressJs)
{
window.rainloopProgressJs.set(100);
progressJs.set(100).end();
}
};
window.__showDescription = (description) => {
}
function showDescriptionAndLoading(description)
{
const
oE = window.document.getElementById('rl-loading'),
oElDesc = window.document.getElementById('rl-loading-desc')
@ -83,76 +129,81 @@ window.__showDescription = (description) => {
oE.style.opacity = 1;
}, 300);
}
};
}
window.__runBoot = (withError, additionalError) => {
if (window.__APP_BOOT && !withError) {
function runMainBoot(withError, additionalError)
{
if (window.__APP_BOOT && !withError)
{
window.__APP_BOOT(function (bV) {
if (!bV) {
window.__showError(additionalError);
if (!bV)
{
showError(additionalError);
}
});
} else {
window.__showError(additionalError);
}
};
window.__runApp = (BaseAppLibsScriptLink, BaseAppMainScriptLink, BaseAppEditorScriptLink) => {
const appData = window.rainloopAppData;
if (window.$LAB && window.progressJs && appData && appData.TemplatesLink && appData.LangLink)
else
{
const p = window.progressJs();
window.rainloopProgressJs = p;
showError(additionalError);
}
}
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.start().set(5);
window.$LAB
.script(function () {
return [
{src: BaseAppLibsScriptLink, type: 'text/javascript', charset: 'utf-8'}
];
})
.wait(function () {
const
libs = window.jsloader(appData.StaticLibJsLink).then(() => {
if (window.$)
{
if (!window.$('#rl-check').is(':visible'))
{
window.$('html').addClass('no-css');
throw new Error('no-css');
}
p.set(20);
window.$('#rl-check').remove();
if (appData.IncludeBackground && $) {
$('#rl-bg').attr('style', 'background-image: none !important;')
.backstretch(appData.IncludeBackground.replace('{{USER}}',
(window.__rlah ? window.__rlah() || '0' : '0')), {fade: 100, centeredX: true, centeredY: true})
.removeAttr('style')
;
if (appData.IncludeBackground)
{
window.$('#rl-bg').attr('style', 'background-image: none !important;')
.backstretch(appData.IncludeBackground.replace('{{USER}}',
(window.__rlah ? (window.__rlah() || '0') : '0')), {fade: 100, centeredX: true, centeredY: true})
.removeAttr('style')
;
}
}
})
.script(function () {
return [
{src: appData.TemplatesLink, type: 'text/javascript', charset: 'utf-8'},
{src: appData.LangLink, type: 'text/javascript', charset: 'utf-8'}
];
})
.wait(function () {
}),
common = window.Promise.all([
window.jsloader(appData.TemplatesLink),
window.jsloader(appData.LangLink)
])
;
window.Promise.all([libs, common])
.then(() => {
p.set(30);
})
.script(function () {
return {src: BaseAppMainScriptLink, type: 'text/javascript', charset: 'utf-8'};
})
.wait(function () {
return window.jsloader(appData.StaticAppJsLink);
}).then(() => {
p.set(50);
})
.script(function () {
return appData.PluginsLink ? {src: appData.PluginsLink, type: 'text/javascript', charset: 'utf-8'} : null;
})
.wait(function () {
return appData.PluginsLink ? window.jsloader(appData.PluginsLink) : window.Promise.resolve();
}).then(() => {
p.set(70);
window.__runBoot(false);
})
.script(function () {
return {src: BaseAppEditorScriptLink, type: 'text/javascript', charset: 'utf-8'};
})
.wait(function () {
runMainBoot(false);
}).catch((e) => {
runMainBoot(true);
throw e;
}).then(() => {
return window.jsloader(appData.StaticEditorJsLink);
}).then(() => {
if (window.CKEDITOR && window.__initEditor) {
window.__initEditor();
window.__initEditor = null;
@ -162,6 +213,41 @@ window.__runApp = (BaseAppLibsScriptLink, BaseAppMainScriptLink, BaseAppEditorSc
}
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);
});
$('#rl-head-viewport').attr('content', aContent.join(', '));
$('#app-head-viewport').attr('content', aContent.join(', '));
};
/**
@ -1538,8 +1538,8 @@
Utils.changeTheme = function (sValue, themeTrigger)
{
var
oThemeLink = $('#rlThemeLink'),
oThemeStyle = $('#rlThemeStyle'),
oThemeLink = $('#app-theme-link'),
oThemeStyle = $('#app-theme-style'),
sUrl = oThemeLink.attr('href')
;
@ -1576,7 +1576,7 @@
{
if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0]))
{
oThemeStyle = $('<style id="rlThemeStyle"></style>');
oThemeStyle = $('<style id="app-theme-style"></style>');
oThemeLink.after(oThemeStyle);
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() {
const
key = 'AuthAccountHash',
appData = window.rainloopAppData
appData = window.__rlah_data()
;
if (this.s)
{

View file

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

View file

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

View file

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

View file

@ -1,12 +1,27 @@
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('modernizr/modernizr-custom.js');
require('Common/Booter.jsx');
import {$LAB} from 'labjs/LAB.src.js';
import {progressJs} from 'progress.js/src/progress.js';
window.$LAB = $LAB;
window.progressJs = progressJs;
if (window.__runBoot)
{
window.__runBoot();
}

View file

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

View file

@ -97,7 +97,7 @@ function copyFile(sFile, sNewFile, callback)
callback();
}
cfg.paths.globjs = 'dev/**/*.{js,jsx}';
cfg.paths.globjs = 'dev/**/*.{js,jsx,html}';
cfg.paths.globjsonly = 'dev/**/*.js';
cfg.paths.globjsxonly = 'dev/**/*.jsx';
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() {
return gulp.src(cfg.paths.staticCSS + cfg.paths.less.main.name, {read: false})
.pipe(require('gulp-rimraf')());
});

View file

@ -2,7 +2,7 @@
"name": "RainLoop",
"title": "RainLoop Webmail",
"version": "1.10.0",
"release": "108",
"release": "112",
"ownCloudPackageVersion": "4.16",
"description": "Simple, modern & fast web-based email client",
"homepage": "http://rainloop.net",
@ -84,6 +84,7 @@
"lodash": "~3.9.3",
"node-fs": "*",
"node-notifier": "~4.2.3",
"raw-loader": "^0.5.1",
"rimraf": "*",
"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 (!$bAdmin)
@ -1923,14 +1918,11 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
}
}
$sPluginsLink = '';
if (0 < $this->Plugins()->Count() && $this->Plugins()->HaveJs($bAdmin))
{
$sPluginsLink = './?/Plugins/0/'.($bAdmin ? 'Admin' : 'User').'/'.$sStaticCache.'/';
}
$sTheme = $this->ValidateTheme($sTheme, $bMobile);
$sStaticCache = $this->StaticCache();
$aResult['Theme'] = $sTheme;
$aResult['NewThemeLink'] = $sNewThemeLink;
$aResult['NewThemeLink'] = $this->ThemeLink($sTheme, $bAdmin);
$aResult['Language'] = $this->ValidateLanguage($sLanguage, '', false);
$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['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').'/'.
($bAdmin ? $aResult['LanguageAdmin'] : $aResult['Language']).'/'.$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'] : 'Plain';
@ -9057,6 +9061,29 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
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
*
@ -9694,6 +9721,18 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
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
*/

View file

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

View file

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

View file

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

View file

@ -1,74 +1,29 @@
<!DOCTYPE html>
<html class="no-js rl-booted-trigger rl-started-trigger" dir="{{BaseDir}}">
<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>
<meta http-equiv="refresh" content="0; URL=./?/NoScript" />
</noscript>
<!--[if lte IE 8]>
<meta http-equiv="refresh" content="0; URL=./?/BadBrowser" />
<![endif]-->
<script type="text/javascript" data-cfasync="false">
if (!window.navigator || !window.navigator.cookieEnabled) {
window.document.location.replace('./?/NoCookie');
}
</script>
<meta name="Author" content="RainLoop Team" />
<meta name="robots" content="noindex,nofollow,noodp" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="{{BaseViewport}}" id="app-head-viewport">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="google" content="notranslate" />
<meta name="robots" content="noindex,nofollow,noodp" />
<meta name="AppBootData" content='{{RainloopBootData}}' id="app-boot-data" />
<title></title>
<style>#rl-content{display:none;}#rl-check{display:none;}</style>
{{BaseAppFaviconPngLinkTag}}{{BaseAppFaviconTouchLinkTag}}
{{BaseAppFaviconPngLinkTag}}
{{BaseAppFaviconTouchLinkTag}}
<style>#rl-check{display:none}</style>
<link type="text/css" rel="stylesheet" href="{{BaseAppMainCssLink}}" />
<link type="text/css" rel="stylesheet" id="rlThemeLink" />
<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>
<link type="text/css" rel="stylesheet" href="{{BaseAppThemeCssLink}}" id="app-theme-link" />
</head>
<body>
<div id="rl-app"></div>
<div id="rl-check"></div>
<div id="rl-bg" class="thm-body"></div>
<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>
<script type="text/javascript" data-cfasync="false" src="{{BaseAppBootScriptLink}}"></script>
</body>
</html>

View file

@ -187,9 +187,39 @@
.thm-rgba-background-color(@message-background-color, @message-rgba-background-color);
}
#rl-app{
display: block;
}
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 {
color: #333;
background-color: #aaa;

View file

@ -3,13 +3,12 @@
<div class="btn-toolbar">
<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">
<i data-bind="css: {'icon-user': !accounts.loading(), 'icon-spinner animated': accounts.loading()}"
></i>
<i data-bind="css: {'icon-user': !accounts.loading(), 'icon-spinner animated': accounts.loading()}"></i>
<!--
<b data-bind="text: accountsUnreadCount, visible: 100 > accountsUnreadCount() && 0 < accountsUnreadCount()"></b>
<b data-bind="visible: 99 < accountsUnreadCount()">99+</b>
-->
&nbsp;
-->
&nbsp;
<span class="caret"></span>
</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
a copy of this software and associated documentation files (the
@ -17,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

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: {
loaders: [
{
test: /\.html$/,
loader: 'raw'
},
{
test: /\.jsx$/,
loader: 'babel',
@ -49,7 +53,7 @@ module.exports = {
'JSON': 'window.JSON',
'JSEncrypt': 'window.JSEncrypt',
'$LAB': 'window.$LAB',
'progressJs': 'window.rainloopProgressJs',
'progressJs': 'window.progressJs',
'queue': 'window.queue',
'moment': 'window.moment',
'ifvisible': 'window.ifvisible',