mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-25 10:09:20 +03:00
Improve boot script
This commit is contained in:
parent
a655b94aba
commit
e3fa252cf2
17 changed files with 2595 additions and 125 deletions
163
dev/Common/Booter.jsx
Normal file
163
dev/Common/Booter.jsx
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
|
||||||
|
import window from 'window';
|
||||||
|
import $ from '$';
|
||||||
|
|
||||||
|
import rainLoopStorage from 'Storage/RainLoop';
|
||||||
|
|
||||||
|
window.__rlah = () => {
|
||||||
|
return rainLoopStorage ? rainLoopStorage.getHash() : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__rlah_set = () => {
|
||||||
|
if (rainLoopStorage)
|
||||||
|
{
|
||||||
|
rainLoopStorage.setHash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__rlah_clear = () => {
|
||||||
|
if (rainLoopStorage)
|
||||||
|
{
|
||||||
|
rainLoopStorage.clearHash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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.__includeStyle = (styles) => {
|
||||||
|
window.document.write(unescape('%3Csty' + 'le%3E' + styles + '"%3E%3C/' + 'sty' + 'le%3E'));
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__showError = (additionalError) => {
|
||||||
|
|
||||||
|
const
|
||||||
|
oR = window.document.getElementById('rl-loading'),
|
||||||
|
oL = window.document.getElementById('rl-loading-error'),
|
||||||
|
oLA = window.document.getElementById('rl-loading-error-additional')
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oR)
|
||||||
|
{
|
||||||
|
oR.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oL)
|
||||||
|
{
|
||||||
|
oL.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oLA && additionalError)
|
||||||
|
{
|
||||||
|
oLA.style.display = 'block';
|
||||||
|
oLA.innerHTML = additionalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.rainloopProgressJs)
|
||||||
|
{
|
||||||
|
window.rainloopProgressJs.set(100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__showDescription = (description) => {
|
||||||
|
|
||||||
|
const
|
||||||
|
oE = window.document.getElementById('rl-loading'),
|
||||||
|
oElDesc = window.document.getElementById('rl-loading-desc')
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oElDesc && description)
|
||||||
|
{
|
||||||
|
oElDesc.innerHTML = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oE && oE.style)
|
||||||
|
{
|
||||||
|
oE.style.opacity = 0;
|
||||||
|
window.setTimeout(() => {
|
||||||
|
oE.style.opacity = 1;
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.__runBoot = (withError, additionalError) => {
|
||||||
|
if (window.__APP_BOOT && !withError) {
|
||||||
|
window.__APP_BOOT(function (bV) {
|
||||||
|
if (!bV) {
|
||||||
|
window.__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)
|
||||||
|
{
|
||||||
|
const p = window.progressJs();
|
||||||
|
window.rainloopProgressJs = p;
|
||||||
|
|
||||||
|
p.setOptions({theme: 'rainloop'});
|
||||||
|
p.start().set(5);
|
||||||
|
|
||||||
|
window.$LAB
|
||||||
|
.script(function () {
|
||||||
|
return [
|
||||||
|
{src: BaseAppLibsScriptLink, type: 'text/javascript', charset: 'utf-8'}
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.wait(function () {
|
||||||
|
|
||||||
|
p.set(20);
|
||||||
|
|
||||||
|
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')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.script(function () {
|
||||||
|
return [
|
||||||
|
{src: appData.TemplatesLink, type: 'text/javascript', charset: 'utf-8'},
|
||||||
|
{src: appData.LangLink, type: 'text/javascript', charset: 'utf-8'}
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.wait(function () {
|
||||||
|
p.set(30);
|
||||||
|
})
|
||||||
|
.script(function () {
|
||||||
|
return {src: BaseAppMainScriptLink, type: 'text/javascript', charset: 'utf-8'};
|
||||||
|
})
|
||||||
|
.wait(function () {
|
||||||
|
p.set(50);
|
||||||
|
})
|
||||||
|
.script(function () {
|
||||||
|
return appData.PluginsLink ? {src: appData.PluginsLink, type: 'text/javascript', charset: 'utf-8'} : null;
|
||||||
|
})
|
||||||
|
.wait(function () {
|
||||||
|
p.set(70);
|
||||||
|
window.__runBoot(false);
|
||||||
|
})
|
||||||
|
.script(function () {
|
||||||
|
return {src: BaseAppEditorScriptLink, type: 'text/javascript', charset: 'utf-8'};
|
||||||
|
})
|
||||||
|
.wait(function () {
|
||||||
|
if (window.CKEDITOR && window.__initEditor) {
|
||||||
|
window.__initEditor();
|
||||||
|
window.__initEditor = null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.__runBoot(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
62
dev/Storage/RainLoop.jsx
Normal file
62
dev/Storage/RainLoop.jsx
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
import window from 'window';
|
||||||
|
|
||||||
|
const STORAGE_KEY = '__rlA';
|
||||||
|
|
||||||
|
class RainLoopStorage
|
||||||
|
{
|
||||||
|
s = null;
|
||||||
|
t = null;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this.s = window.sessionStorage || null;
|
||||||
|
this.t = window.top || window;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHash() {
|
||||||
|
let result = null;
|
||||||
|
if (this.s)
|
||||||
|
{
|
||||||
|
result = this.s.getItem(STORAGE_KEY) || null;
|
||||||
|
}
|
||||||
|
else if (this.t && JSON)
|
||||||
|
{
|
||||||
|
const data = this.t.name && '{' === this.t.name.toString().substr(0, 1) ? JSON.parse(this.t.name.toString()) : null;
|
||||||
|
result = data ? (data[STORAGE_KEY] || null) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
setHash() {
|
||||||
|
const
|
||||||
|
key = 'AuthAccountHash',
|
||||||
|
appData = window.rainloopAppData
|
||||||
|
;
|
||||||
|
if (this.s)
|
||||||
|
{
|
||||||
|
this.s.setItem(STORAGE_KEY, appData && appData[key] ? appData[key] : '');
|
||||||
|
}
|
||||||
|
else if (this.t && JSON)
|
||||||
|
{
|
||||||
|
let data = {};
|
||||||
|
data[STORAGE_KEY] = appData && appData[key] ? appData[key] : '';
|
||||||
|
|
||||||
|
this.t.name = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearHash() {
|
||||||
|
if (this.s)
|
||||||
|
{
|
||||||
|
this.s.setItem(STORAGE_KEY, '');
|
||||||
|
}
|
||||||
|
else if (this.t)
|
||||||
|
{
|
||||||
|
this.t.name = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new RainLoopStorage();
|
||||||
|
|
@ -51,7 +51,7 @@ select:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.mobile * {
|
html.mobile *, html.rl-mobile * {
|
||||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
dev/boot.jsx
Normal file
12
dev/boot.jsx
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
import window from 'window';
|
||||||
|
|
||||||
|
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;
|
||||||
19
gulpfile.js
19
gulpfile.js
|
|
@ -141,16 +141,6 @@ cfg.paths.css = {
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg.paths.js = {
|
cfg.paths.js = {
|
||||||
boot: {
|
|
||||||
name: 'boot.js',
|
|
||||||
src: [
|
|
||||||
'vendors/json2.min.js',
|
|
||||||
'vendors/labjs/LAB.min.js',
|
|
||||||
'vendors/modernizr.js',
|
|
||||||
'vendors/progress.js/minified/progress.min.js',
|
|
||||||
'vendors/rl/rl-1.5.min.js'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
openpgp: {
|
openpgp: {
|
||||||
name: 'openpgp.min.js',
|
name: 'openpgp.min.js',
|
||||||
src: [
|
src: [
|
||||||
|
|
@ -293,13 +283,6 @@ gulp.task('css:main:min', ['css:main'], function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// JS
|
// JS
|
||||||
gulp.task('js:boot', function() {
|
|
||||||
return gulp.src(cfg.paths.js.boot.src)
|
|
||||||
.pipe(concat(cfg.paths.js.boot.name))
|
|
||||||
.pipe(eol('\n', true))
|
|
||||||
.pipe(gulp.dest(cfg.paths.staticMinJS));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('js:encrypt', function() {
|
gulp.task('js:encrypt', function() {
|
||||||
return gulp.src(cfg.paths.js.encrypt.src)
|
return gulp.src(cfg.paths.js.encrypt.src)
|
||||||
.pipe(concat(cfg.paths.js.encrypt.name))
|
.pipe(concat(cfg.paths.js.encrypt.name))
|
||||||
|
|
@ -705,7 +688,7 @@ gulp.task('rainloop:owncloud:shortname', ['rainloop:owncloud:md5'], function(cal
|
||||||
// MAIN
|
// MAIN
|
||||||
gulp.task('js:pgp', ['js:openpgp', 'js:openpgpworker']);
|
gulp.task('js:pgp', ['js:openpgp', 'js:openpgpworker']);
|
||||||
|
|
||||||
gulp.task('default', ['js:libs', 'js:boot', 'js:pgp', 'js:min', 'css:main:min', 'ckeditor', 'fontastic']);
|
gulp.task('default', ['js:libs', 'js:pgp', 'js:min', 'css:main:min', 'ckeditor', 'fontastic']);
|
||||||
gulp.task('fast-', ['js:app', 'js:admin', 'js:chunks', 'css:main']);
|
gulp.task('fast-', ['js:app', 'js:admin', 'js:chunks', 'css:main']);
|
||||||
|
|
||||||
gulp.task('fast', ['package:community-on', 'fast-']);
|
gulp.task('fast', ['package:community-on', 'fast-']);
|
||||||
|
|
|
||||||
|
|
@ -194,9 +194,14 @@ class Service
|
||||||
}
|
}
|
||||||
|
|
||||||
$aTemplateParameters = $this->indexTemplateParameters($bAdmin, $bMobile, $bMobileDevice);
|
$aTemplateParameters = $this->indexTemplateParameters($bAdmin, $bMobile, $bMobileDevice);
|
||||||
|
if (!empty($aTemplateParameters['{{BaseApplicationConfigurationJson}}']))
|
||||||
|
{
|
||||||
|
$this->oActions->Logger()->Write($aTemplateParameters['{{BaseApplicationConfigurationJson}}'],
|
||||||
|
\MailSo\Log\Enumerations\Type::INFO, 'APP');
|
||||||
|
}
|
||||||
|
|
||||||
$sCacheFileName = '';
|
$sCacheFileName = '';
|
||||||
if ($this->oActions->Config()->Get('labs', 'cache_system_data', true))
|
if ($this->oActions->Config()->Get('labs', 'cache_system_data', true) && !empty($aTemplateParameters['{{BaseHash}}']))
|
||||||
{
|
{
|
||||||
$sCacheFileName = 'TMPL:'.$aTemplateParameters['{{BaseHash}}'];
|
$sCacheFileName = 'TMPL:'.$aTemplateParameters['{{BaseHash}}'];
|
||||||
$sResult = $this->oActions->Cacher()->Get($sCacheFileName);
|
$sResult = $this->oActions->Cacher()->Get($sCacheFileName);
|
||||||
|
|
@ -327,6 +332,18 @@ class Service
|
||||||
) : array());
|
) : array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $sPath
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function staticPath($sPath)
|
||||||
|
{
|
||||||
|
$sStaticSuffix = $this->oActions->IsOpen() ? '?vo' : '?vs';
|
||||||
|
|
||||||
|
return \RainLoop\Utils::WebStaticPath().$sPath.$sStaticSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $bAdmin = false
|
* @param bool $bAdmin = false
|
||||||
* @param bool $bMobile = false
|
* @param bool $bMobile = false
|
||||||
|
|
@ -346,21 +363,18 @@ class Service
|
||||||
|
|
||||||
$sFaviconUrl = (string) $this->oActions->Config()->Get('webmail', 'favicon_url', '');
|
$sFaviconUrl = (string) $this->oActions->Config()->Get('webmail', 'favicon_url', '');
|
||||||
|
|
||||||
$sStaticPrefix = \RainLoop\Utils::WebStaticPath();
|
|
||||||
|
|
||||||
$aData = array(
|
$aData = array(
|
||||||
'Language' => $sLanguage,
|
'Language' => $sLanguage,
|
||||||
'Theme' => $sTheme,
|
'Theme' => $sTheme,
|
||||||
'FaviconPngLink' => $sFaviconUrl ? $sFaviconUrl : $sStaticPrefix.'favicon.png',
|
'FaviconPngLink' => $sFaviconUrl ? $sFaviconUrl : $this->staticPath('apple-touch-icon.png'),
|
||||||
'AppleTouchLink' => $sFaviconUrl ? '' : $sStaticPrefix.'apple-touch-icon.png',
|
'AppleTouchLink' => $sFaviconUrl ? '' : $this->staticPath('apple-touch-icon.png'),
|
||||||
'AppCssLink' => $sStaticPrefix.'css/app'.($bAppCssDebug ? '' : '.min').'.css',
|
'AppCssLink' => $this->staticPath('css/app'.($bAppCssDebug ? '' : '.min').'.css'),
|
||||||
'BootJsLink' => $sStaticPrefix.'js/min/boot.js',
|
'BootJsLink' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'boot.js'),
|
||||||
'ComponentsJsLink' => $sStaticPrefix.'js/'.($bAppJsDebug ? '' : 'min/').'components.js',
|
'LibJsLink' => $this->staticPath('js/min/libs.js'),
|
||||||
'LibJsLink' => $sStaticPrefix.'js/min/libs.js',
|
'EditorJsLink' => $this->staticPath('ckeditor/ckeditor.js'),
|
||||||
'EditorJsLink' => $sStaticPrefix.'ckeditor/ckeditor.js',
|
'OpenPgpJsLink' => $this->staticPath('js/min/openpgp.min.js'),
|
||||||
'OpenPgpJsLink' => $sStaticPrefix.'js/min/openpgp.min.js',
|
'AppJsCommonLink' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').'common.js'),
|
||||||
'AppJsCommonLink' => $sStaticPrefix.'js/'.($bAppJsDebug ? '' : 'min/').'common.js',
|
'AppJsLink' => $this->staticPath('js/'.($bAppJsDebug ? '' : 'min/').($bAdmin ? 'admin' : 'app').'.js')
|
||||||
'AppJsLink' => $sStaticPrefix.'js/'.($bAppJsDebug ? '' : 'min/').($bAdmin ? 'admin' : 'app').'.js'
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$aTemplateParameters = array(
|
$aTemplateParameters = array(
|
||||||
|
|
@ -370,7 +384,6 @@ class Service
|
||||||
'{{BaseAppAppleTouchFile}}' => $aData['AppleTouchLink'],
|
'{{BaseAppAppleTouchFile}}' => $aData['AppleTouchLink'],
|
||||||
'{{BaseAppMainCssLink}}' => $aData['AppCssLink'],
|
'{{BaseAppMainCssLink}}' => $aData['AppCssLink'],
|
||||||
'{{BaseAppBootScriptLink}}' => $aData['BootJsLink'],
|
'{{BaseAppBootScriptLink}}' => $aData['BootJsLink'],
|
||||||
'{{BaseAppComponentsScriptLink}}' => $aData['ComponentsJsLink'],
|
|
||||||
'{{BaseAppLibsScriptLink}}' => $aData['LibJsLink'],
|
'{{BaseAppLibsScriptLink}}' => $aData['LibJsLink'],
|
||||||
'{{BaseAppEditorScriptLink}}' => $aData['EditorJsLink'],
|
'{{BaseAppEditorScriptLink}}' => $aData['EditorJsLink'],
|
||||||
'{{BaseAppOpenPgpScriptLink}}' => $aData['OpenPgpJsLink'],
|
'{{BaseAppOpenPgpScriptLink}}' => $aData['OpenPgpJsLink'],
|
||||||
|
|
@ -388,7 +401,8 @@ class Service
|
||||||
$bAdmin ? '1' : '0',
|
$bAdmin ? '1' : '0',
|
||||||
\md5($this->oActions->Config()->Get('cache', 'index', '')),
|
\md5($this->oActions->Config()->Get('cache', 'index', '')),
|
||||||
$this->oActions->Plugins()->Hash(),
|
$this->oActions->Plugins()->Hash(),
|
||||||
\RainLoop\Utils::WebVersionPath(), APP_VERSION
|
\RainLoop\Utils::WebVersionPath(),
|
||||||
|
APP_VERSION,
|
||||||
)).
|
)).
|
||||||
\implode('~', $aTemplateParameters)
|
\implode('~', $aTemplateParameters)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -69,89 +69,7 @@
|
||||||
<div id="rl-templates"></div>
|
<div id="rl-templates"></div>
|
||||||
<div id="rl-hidden"></div>
|
<div id="rl-hidden"></div>
|
||||||
<script type="application/json" data-cfasync="false" data-configuration="application">{{BaseApplicationConfigurationJson}}</script>
|
<script type="application/json" data-cfasync="false" data-configuration="application">{{BaseApplicationConfigurationJson}}</script>
|
||||||
<script type="text/javascript" data-cfasync="false">
|
<script type="text/javascript" data-cfasync="false">__showDescription(window.rainloopAppData ? window.rainloopAppData['LoadingDescriptionEsc'] : '');</script>
|
||||||
(function (window) {
|
<script type="text/javascript" data-cfasync="false">__runApp('{{BaseAppLibsScriptLink}}', '{{BaseAppMainScriptLink}}', '{{BaseAppEditorScriptLink}}');</script>
|
||||||
var
|
|
||||||
oE = window.document.getElementById('rl-loading'),
|
|
||||||
oElDesc = window.document.getElementById('rl-loading-desc')
|
|
||||||
;
|
|
||||||
if (oElDesc && window.rainloopAppData['LoadingDescriptionEsc']) {
|
|
||||||
oElDesc.innerHTML = window.rainloopAppData['LoadingDescriptionEsc'];
|
|
||||||
}
|
|
||||||
if (oE && oE.style) {
|
|
||||||
oE.style.opacity = 0;
|
|
||||||
window.setTimeout(function () {
|
|
||||||
oE.style.opacity = 1;
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
}(window));
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript" data-cfasync="false">
|
|
||||||
|
|
||||||
if (window.$LAB && window.rainloopAppData && window.rainloopAppData['TemplatesLink'] && window.rainloopAppData['LangLink'])
|
|
||||||
{
|
|
||||||
window.rainloopProgressJs = progressJs();
|
|
||||||
|
|
||||||
window.rainloopProgressJs.setOptions({'theme': 'rainloop'});
|
|
||||||
window.rainloopProgressJs.start().set(5);
|
|
||||||
|
|
||||||
window.$LAB
|
|
||||||
.script(function () {
|
|
||||||
return [
|
|
||||||
{'src': '{{BaseAppLibsScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'}
|
|
||||||
];
|
|
||||||
})
|
|
||||||
.wait(function () {
|
|
||||||
|
|
||||||
window.rainloopProgressJs.set(20);
|
|
||||||
|
|
||||||
if (window.rainloopAppData['IncludeBackground']) {
|
|
||||||
$('#rl-bg').attr('style', 'background-image: none !important;').backstretch(
|
|
||||||
window.rainloopAppData['IncludeBackground'].replace('{{USER}}',
|
|
||||||
(window.__rlah ? window.__rlah() || '0' : '0')), {
|
|
||||||
'fade': 100, 'centeredX': true, 'centeredY': true
|
|
||||||
}).removeAttr('style');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.script(function () {
|
|
||||||
return [
|
|
||||||
{'src': window.rainloopAppData['TemplatesLink'], 'type': 'text/javascript', 'charset': 'utf-8'},
|
|
||||||
{'src': window.rainloopAppData['LangLink'], 'type': 'text/javascript', 'charset': 'utf-8'}
|
|
||||||
];
|
|
||||||
})
|
|
||||||
.wait(function () {
|
|
||||||
window.rainloopProgressJs.set(30);
|
|
||||||
})
|
|
||||||
.script(function () {
|
|
||||||
return {'src': '{{BaseAppMainScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'};
|
|
||||||
})
|
|
||||||
.wait(function () {
|
|
||||||
window.rainloopProgressJs.set(50);
|
|
||||||
})
|
|
||||||
.script(function () {
|
|
||||||
return window.rainloopAppData['PluginsLink'] ?
|
|
||||||
{'src': window.rainloopAppData['PluginsLink'], 'type': 'text/javascript', 'charset': 'utf-8'} : null;
|
|
||||||
})
|
|
||||||
.wait(function () {
|
|
||||||
window.rainloopProgressJs.set(70);
|
|
||||||
__runBoot(false);
|
|
||||||
})
|
|
||||||
.script(function () {
|
|
||||||
return {'src': '{{BaseAppEditorScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'};
|
|
||||||
})
|
|
||||||
.wait(function () {
|
|
||||||
if (window.CKEDITOR && window.__initEditor) {
|
|
||||||
window.__initEditor();
|
|
||||||
window.__initEditor = null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
__runBoot(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
2
vendors/json2.min.js
vendored
2
vendors/json2.min.js
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
/*! See http://www.JSON.org/js.html */
|
|
||||||
var JSON;JSON||(JSON={}),function(){function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&&typeof i=="object"&&typeof i.toJSON=="function"&&(i=i.toJSON(a)),typeof rep=="function"&&(i=rep.call(b,a,i));switch(typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";gap+=indent,h=[];if(Object.prototype.toString.apply(i)==="[object Array]"){f=i.length;for(c=0;c<f;c+=1)h[c]=str(c,i)||"null";e=h.length===0?"[]":gap?"[\n"+gap+h.join(",\n"+gap)+"\n"+g+"]":"["+h.join(",")+"]",gap=g;return e}if(rep&&typeof rep=="object"){f=rep.length;for(c=0;c<f;c+=1)d=rep[c],typeof d=="string"&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e))}else for(d in i)Object.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&h.push(quote(d)+(gap?": ":":")+e));e=h.length===0?"{}":gap?"{\n"+gap+h.join(",\n"+gap)+"\n"+g+"}":"{"+h.join(",")+"}",gap=g;return e}}function quote(a){escapable.lastIndex=0;return escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return typeof b=="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function f(a){return a<10?"0"+a:a}"use strict",typeof Date.prototype.toJSON!="function"&&(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;typeof JSON.stringify!="function"&&(JSON.stringify=function(a,b,c){var d;gap="",indent="";if(typeof c=="number")for(d=0;d<c;d+=1)indent+=" ";else typeof c=="string"&&(indent=c);rep=b;if(b&&typeof b!="function"&&(typeof b!="object"||typeof b.length!="number"))throw new Error("JSON.stringify");return str("",{"":a})}),typeof JSON.parse!="function"&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&typeof e=="object")for(c in e)Object.hasOwnProperty.call(e,c)&&(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver=="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")})}();
|
|
||||||
40
vendors/json2/README
vendored
Normal file
40
vendors/json2/README
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
JSON in JavaScript
|
||||||
|
|
||||||
|
|
||||||
|
Douglas Crockford
|
||||||
|
douglas@crockford.com
|
||||||
|
|
||||||
|
2015-05-03
|
||||||
|
|
||||||
|
|
||||||
|
JSON is a light-weight, language independent, data interchange format.
|
||||||
|
See http://www.JSON.org/
|
||||||
|
|
||||||
|
The files in this collection implement JSON encoders/decoders in JavaScript.
|
||||||
|
|
||||||
|
JSON became a built-in feature of JavaScript when the ECMAScript Programming
|
||||||
|
Language Standard - Fifth Edition was adopted by the ECMA General Assembly
|
||||||
|
in December 2009. Most of the files in this collection are for applications
|
||||||
|
that are expected to run in obsolete web browsers. For most purposes, json2.js
|
||||||
|
is the best choice.
|
||||||
|
|
||||||
|
|
||||||
|
json2.js: This file creates a JSON property in the global object, if there
|
||||||
|
isn't already one, setting its value to an object containing a stringify
|
||||||
|
method and a parse method. The parse method uses the eval method to do the
|
||||||
|
parsing, guarding it with several regular expressions to defend against
|
||||||
|
accidental code execution hazards. On current browsers, this file does nothing,
|
||||||
|
preferring the built-in JSON object. There is no reason to use this file unless
|
||||||
|
fate compels you to support IE8, which is something that no one should ever
|
||||||
|
have to do again.
|
||||||
|
|
||||||
|
json_parse.js: This file contains an alternative JSON parse function that
|
||||||
|
uses recursive descent instead of eval.
|
||||||
|
|
||||||
|
json_parse_state.js: This files contains an alternative JSON parse function that
|
||||||
|
uses a state machine instead of eval.
|
||||||
|
|
||||||
|
cycle.js: This file contains two functions, JSON.decycle and JSON.retrocycle,
|
||||||
|
which make it possible to encode cyclical structures and dags in JSON, and to
|
||||||
|
then recover them. This is a capability that is not provided by ES5. JSONPath
|
||||||
|
is used to represent the links. [http://GOESSNER.net/articles/JsonPath/]
|
||||||
172
vendors/json2/cycle.js
vendored
Normal file
172
vendors/json2/cycle.js
vendored
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
cycle.js
|
||||||
|
2015-02-25
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint eval, for */
|
||||||
|
|
||||||
|
/*property
|
||||||
|
$ref, apply, call, decycle, hasOwnProperty, length, prototype, push,
|
||||||
|
retrocycle, stringify, test, toString
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (typeof JSON.decycle !== 'function') {
|
||||||
|
JSON.decycle = function decycle(object) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Make a deep copy of an object or array, assuring that there is at most
|
||||||
|
// one instance of each object or array in the resulting structure. The
|
||||||
|
// duplicate references (which might be forming cycles) are replaced with
|
||||||
|
// an object of the form
|
||||||
|
// {$ref: PATH}
|
||||||
|
// where the PATH is a JSONPath string that locates the first occurance.
|
||||||
|
// So,
|
||||||
|
// var a = [];
|
||||||
|
// a[0] = a;
|
||||||
|
// return JSON.stringify(JSON.decycle(a));
|
||||||
|
// produces the string '[{"$ref":"$"}]'.
|
||||||
|
|
||||||
|
// JSONPath is used to locate the unique object. $ indicates the top level of
|
||||||
|
// the object or array. [NUMBER] or [STRING] indicates a child member or
|
||||||
|
// property.
|
||||||
|
|
||||||
|
var objects = [], // Keep a reference to each unique object or array
|
||||||
|
paths = []; // Keep the path to each unique object or array
|
||||||
|
|
||||||
|
return (function derez(value, path) {
|
||||||
|
|
||||||
|
// The derez recurses through the object, producing the deep copy.
|
||||||
|
|
||||||
|
var i, // The loop counter
|
||||||
|
name, // Property name
|
||||||
|
nu; // The new object or array
|
||||||
|
|
||||||
|
// typeof null === 'object', so go on if this value is really an object but not
|
||||||
|
// one of the weird builtin objects.
|
||||||
|
|
||||||
|
if (typeof value === 'object' && value !== null &&
|
||||||
|
!(value instanceof Boolean) &&
|
||||||
|
!(value instanceof Date) &&
|
||||||
|
!(value instanceof Number) &&
|
||||||
|
!(value instanceof RegExp) &&
|
||||||
|
!(value instanceof String)) {
|
||||||
|
|
||||||
|
// If the value is an object or array, look to see if we have already
|
||||||
|
// encountered it. If so, return a $ref/path object. This is a hard way,
|
||||||
|
// linear search that will get slower as the number of unique objects grows.
|
||||||
|
|
||||||
|
for (i = 0; i < objects.length; i += 1) {
|
||||||
|
if (objects[i] === value) {
|
||||||
|
return {$ref: paths[i]};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, accumulate the unique value and its path.
|
||||||
|
|
||||||
|
objects.push(value);
|
||||||
|
paths.push(path);
|
||||||
|
|
||||||
|
// If it is an array, replicate the array.
|
||||||
|
|
||||||
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||||
|
nu = [];
|
||||||
|
for (i = 0; i < value.length; i += 1) {
|
||||||
|
nu[i] = derez(value[i], path + '[' + i + ']');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// If it is an object, replicate the object.
|
||||||
|
|
||||||
|
nu = {};
|
||||||
|
for (name in value) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(value, name)) {
|
||||||
|
nu[name] = derez(value[name],
|
||||||
|
path + '[' + JSON.stringify(name) + ']');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nu;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}(object, '$'));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof JSON.retrocycle !== 'function') {
|
||||||
|
JSON.retrocycle = function retrocycle($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Restore an object that was reduced by decycle. Members whose values are
|
||||||
|
// objects of the form
|
||||||
|
// {$ref: PATH}
|
||||||
|
// are replaced with references to the value found by the PATH. This will
|
||||||
|
// restore cycles. The object will be mutated.
|
||||||
|
|
||||||
|
// The eval function is used to locate the values described by a PATH. The
|
||||||
|
// root object is kept in a $ variable. A regular expression is used to
|
||||||
|
// assure that the PATH is extremely well formed. The regexp contains nested
|
||||||
|
// * quantifiers. That has been known to have extremely bad performance
|
||||||
|
// problems on some browsers for very long strings. A PATH is expected to be
|
||||||
|
// reasonably short. A PATH is allowed to belong to a very restricted subset of
|
||||||
|
// Goessner's JSONPath.
|
||||||
|
|
||||||
|
// So,
|
||||||
|
// var s = '[{"$ref":"$"}]';
|
||||||
|
// return JSON.retrocycle(JSON.parse(s));
|
||||||
|
// produces an array containing a single element which is the array itself.
|
||||||
|
|
||||||
|
var px = /^\$(?:\[(?:\d+|\"(?:[^\\\"\u0000-\u001f]|\\([\\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*\")\])*$/;
|
||||||
|
|
||||||
|
(function rez(value) {
|
||||||
|
|
||||||
|
// The rez function walks recursively through the object looking for $ref
|
||||||
|
// properties. When it finds one that has a value that is a path, then it
|
||||||
|
// replaces the $ref object with a reference to the value that is found by
|
||||||
|
// the path.
|
||||||
|
|
||||||
|
var i, item, name, path;
|
||||||
|
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||||
|
for (i = 0; i < value.length; i += 1) {
|
||||||
|
item = value[i];
|
||||||
|
if (item && typeof item === 'object') {
|
||||||
|
path = item.$ref;
|
||||||
|
if (typeof path === 'string' && px.test(path)) {
|
||||||
|
value[i] = eval(path);
|
||||||
|
} else {
|
||||||
|
rez(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (name in value) {
|
||||||
|
if (typeof value[name] === 'object') {
|
||||||
|
item = value[name];
|
||||||
|
if (item) {
|
||||||
|
path = item.$ref;
|
||||||
|
if (typeof path === 'string' && px.test(path)) {
|
||||||
|
value[name] = eval(path);
|
||||||
|
} else {
|
||||||
|
rez(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}($));
|
||||||
|
return $;
|
||||||
|
};
|
||||||
|
}
|
||||||
519
vendors/json2/json2.js
vendored
Normal file
519
vendors/json2/json2.js
vendored
Normal file
|
|
@ -0,0 +1,519 @@
|
||||||
|
/*
|
||||||
|
json2.js
|
||||||
|
2015-05-03
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
See http://www.JSON.org/js.html
|
||||||
|
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
|
||||||
|
|
||||||
|
This file creates a global JSON object containing two methods: stringify
|
||||||
|
and parse. This file is provides the ES5 JSON capability to ES3 systems.
|
||||||
|
If a project might run on IE8 or earlier, then this file should be included.
|
||||||
|
This file does nothing on ES5 systems.
|
||||||
|
|
||||||
|
JSON.stringify(value, replacer, space)
|
||||||
|
value any JavaScript value, usually an object or array.
|
||||||
|
|
||||||
|
replacer an optional parameter that determines how object
|
||||||
|
values are stringified for objects. It can be a
|
||||||
|
function or an array of strings.
|
||||||
|
|
||||||
|
space an optional parameter that specifies the indentation
|
||||||
|
of nested structures. If it is omitted, the text will
|
||||||
|
be packed without extra whitespace. If it is a number,
|
||||||
|
it will specify the number of spaces to indent at each
|
||||||
|
level. If it is a string (such as '\t' or ' '),
|
||||||
|
it contains the characters used to indent at each level.
|
||||||
|
|
||||||
|
This method produces a JSON text from a JavaScript value.
|
||||||
|
|
||||||
|
When an object value is found, if the object contains a toJSON
|
||||||
|
method, its toJSON method will be called and the result will be
|
||||||
|
stringified. A toJSON method does not serialize: it returns the
|
||||||
|
value represented by the name/value pair that should be serialized,
|
||||||
|
or undefined if nothing should be serialized. The toJSON method
|
||||||
|
will be passed the key associated with the value, and this will be
|
||||||
|
bound to the value
|
||||||
|
|
||||||
|
For example, this would serialize Dates as ISO strings.
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10
|
||||||
|
? '0' + n
|
||||||
|
: n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z';
|
||||||
|
};
|
||||||
|
|
||||||
|
You can provide an optional replacer method. It will be passed the
|
||||||
|
key and value of each member, with this bound to the containing
|
||||||
|
object. The value that is returned from your method will be
|
||||||
|
serialized. If your method returns undefined, then the member will
|
||||||
|
be excluded from the serialization.
|
||||||
|
|
||||||
|
If the replacer parameter is an array of strings, then it will be
|
||||||
|
used to select the members to be serialized. It filters the results
|
||||||
|
such that only members with keys listed in the replacer array are
|
||||||
|
stringified.
|
||||||
|
|
||||||
|
Values that do not have JSON representations, such as undefined or
|
||||||
|
functions, will not be serialized. Such values in objects will be
|
||||||
|
dropped; in arrays they will be replaced with null. You can use
|
||||||
|
a replacer function to replace those with JSON values.
|
||||||
|
JSON.stringify(undefined) returns undefined.
|
||||||
|
|
||||||
|
The optional space parameter produces a stringification of the
|
||||||
|
value that is filled with line breaks and indentation to make it
|
||||||
|
easier to read.
|
||||||
|
|
||||||
|
If the space parameter is a non-empty string, then that string will
|
||||||
|
be used for indentation. If the space parameter is a number, then
|
||||||
|
the indentation will be that many spaces.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||||
|
// text is '["e",{"pluribus":"unum"}]'
|
||||||
|
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||||
|
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||||
|
|
||||||
|
text = JSON.stringify([new Date()], function (key, value) {
|
||||||
|
return this[key] instanceof Date
|
||||||
|
? 'Date(' + this[key] + ')'
|
||||||
|
: value;
|
||||||
|
});
|
||||||
|
// text is '["Date(---current time---)"]'
|
||||||
|
|
||||||
|
|
||||||
|
JSON.parse(text, reviver)
|
||||||
|
This method parses a JSON text to produce an object or array.
|
||||||
|
It can throw a SyntaxError exception.
|
||||||
|
|
||||||
|
The optional reviver parameter is a function that can filter and
|
||||||
|
transform the results. It receives each of the keys and values,
|
||||||
|
and its return value is used instead of the original value.
|
||||||
|
If it returns what it received, then the structure is not modified.
|
||||||
|
If it returns undefined then the member is deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// Parse the text. Values that look like ISO date strings will
|
||||||
|
// be converted to Date objects.
|
||||||
|
|
||||||
|
myData = JSON.parse(text, function (key, value) {
|
||||||
|
var a;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
a =
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||||
|
if (a) {
|
||||||
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||||
|
+a[5], +a[6]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||||
|
var d;
|
||||||
|
if (typeof value === 'string' &&
|
||||||
|
value.slice(0, 5) === 'Date(' &&
|
||||||
|
value.slice(-1) === ')') {
|
||||||
|
d = new Date(value.slice(5, -1));
|
||||||
|
if (d) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
This is a reference implementation. You are free to copy, modify, or
|
||||||
|
redistribute.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint
|
||||||
|
eval, for, this
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*property
|
||||||
|
JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||||
|
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||||
|
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||||
|
test, toJSON, toString, valueOf
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Create a JSON object only if one does not already exist. We create the
|
||||||
|
// methods in a closure to avoid creating global variables.
|
||||||
|
|
||||||
|
if (typeof JSON !== 'object') {
|
||||||
|
JSON = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var rx_one = /^[\],:{}\s]*$/,
|
||||||
|
rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
|
||||||
|
rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
|
||||||
|
rx_four = /(?:^|:|,)(?:\s*\[)+/g,
|
||||||
|
rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
|
||||||
|
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10
|
||||||
|
? '0' + n
|
||||||
|
: n;
|
||||||
|
}
|
||||||
|
|
||||||
|
function this_value() {
|
||||||
|
return this.valueOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Date.prototype.toJSON !== 'function') {
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function () {
|
||||||
|
|
||||||
|
return isFinite(this.valueOf())
|
||||||
|
? this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z'
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
Boolean.prototype.toJSON = this_value;
|
||||||
|
Number.prototype.toJSON = this_value;
|
||||||
|
String.prototype.toJSON = this_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gap,
|
||||||
|
indent,
|
||||||
|
meta,
|
||||||
|
rep;
|
||||||
|
|
||||||
|
|
||||||
|
function quote(string) {
|
||||||
|
|
||||||
|
// If the string contains no control characters, no quote characters, and no
|
||||||
|
// backslash characters, then we can safely slap some quotes around it.
|
||||||
|
// Otherwise we must also replace the offending characters with safe escape
|
||||||
|
// sequences.
|
||||||
|
|
||||||
|
rx_escapable.lastIndex = 0;
|
||||||
|
return rx_escapable.test(string)
|
||||||
|
? '"' + string.replace(rx_escapable, function (a) {
|
||||||
|
var c = meta[a];
|
||||||
|
return typeof c === 'string'
|
||||||
|
? c
|
||||||
|
: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
}) + '"'
|
||||||
|
: '"' + string + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function str(key, holder) {
|
||||||
|
|
||||||
|
// Produce a string from holder[key].
|
||||||
|
|
||||||
|
var i, // The loop counter.
|
||||||
|
k, // The member key.
|
||||||
|
v, // The member value.
|
||||||
|
length,
|
||||||
|
mind = gap,
|
||||||
|
partial,
|
||||||
|
value = holder[key];
|
||||||
|
|
||||||
|
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||||
|
|
||||||
|
if (value && typeof value === 'object' &&
|
||||||
|
typeof value.toJSON === 'function') {
|
||||||
|
value = value.toJSON(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we were called with a replacer function, then call the replacer to
|
||||||
|
// obtain a replacement value.
|
||||||
|
|
||||||
|
if (typeof rep === 'function') {
|
||||||
|
value = rep.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// What happens next depends on the value's type.
|
||||||
|
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'string':
|
||||||
|
return quote(value);
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
|
||||||
|
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||||
|
|
||||||
|
return isFinite(value)
|
||||||
|
? String(value)
|
||||||
|
: 'null';
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
case 'null':
|
||||||
|
|
||||||
|
// If the value is a boolean or null, convert it to a string. Note:
|
||||||
|
// typeof null does not produce 'null'. The case is included here in
|
||||||
|
// the remote chance that this gets fixed someday.
|
||||||
|
|
||||||
|
return String(value);
|
||||||
|
|
||||||
|
// If the type is 'object', we might be dealing with an object or an array or
|
||||||
|
// null.
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
|
||||||
|
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||||
|
// so watch out for that case.
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an array to hold the partial results of stringifying this object value.
|
||||||
|
|
||||||
|
gap += indent;
|
||||||
|
partial = [];
|
||||||
|
|
||||||
|
// Is the value an array?
|
||||||
|
|
||||||
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||||
|
|
||||||
|
// The value is an array. Stringify every element. Use null as a placeholder
|
||||||
|
// for non-JSON values.
|
||||||
|
|
||||||
|
length = value.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
partial[i] = str(i, value) || 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the elements together, separated with commas, and wrap them in
|
||||||
|
// brackets.
|
||||||
|
|
||||||
|
v = partial.length === 0
|
||||||
|
? '[]'
|
||||||
|
: gap
|
||||||
|
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
|
||||||
|
: '[' + partial.join(',') + ']';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the replacer is an array, use it to select the members to be stringified.
|
||||||
|
|
||||||
|
if (rep && typeof rep === 'object') {
|
||||||
|
length = rep.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
if (typeof rep[i] === 'string') {
|
||||||
|
k = rep[i];
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (
|
||||||
|
gap
|
||||||
|
? ': '
|
||||||
|
: ':'
|
||||||
|
) + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Otherwise, iterate through all of the keys in the object.
|
||||||
|
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (
|
||||||
|
gap
|
||||||
|
? ': '
|
||||||
|
: ':'
|
||||||
|
) + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the member texts together, separated with commas,
|
||||||
|
// and wrap them in braces.
|
||||||
|
|
||||||
|
v = partial.length === 0
|
||||||
|
? '{}'
|
||||||
|
: gap
|
||||||
|
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
|
||||||
|
: '{' + partial.join(',') + '}';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a stringify method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.stringify !== 'function') {
|
||||||
|
meta = { // table of character substitutions
|
||||||
|
'\b': '\\b',
|
||||||
|
'\t': '\\t',
|
||||||
|
'\n': '\\n',
|
||||||
|
'\f': '\\f',
|
||||||
|
'\r': '\\r',
|
||||||
|
'"': '\\"',
|
||||||
|
'\\': '\\\\'
|
||||||
|
};
|
||||||
|
JSON.stringify = function (value, replacer, space) {
|
||||||
|
|
||||||
|
// The stringify method takes a value and an optional replacer, and an optional
|
||||||
|
// space parameter, and returns a JSON text. The replacer can be a function
|
||||||
|
// that can replace values, or an array of strings that will select the keys.
|
||||||
|
// A default replacer method can be provided. Use of the space parameter can
|
||||||
|
// produce text that is more easily readable.
|
||||||
|
|
||||||
|
var i;
|
||||||
|
gap = '';
|
||||||
|
indent = '';
|
||||||
|
|
||||||
|
// If the space parameter is a number, make an indent string containing that
|
||||||
|
// many spaces.
|
||||||
|
|
||||||
|
if (typeof space === 'number') {
|
||||||
|
for (i = 0; i < space; i += 1) {
|
||||||
|
indent += ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the space parameter is a string, it will be used as the indent string.
|
||||||
|
|
||||||
|
} else if (typeof space === 'string') {
|
||||||
|
indent = space;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a replacer, it must be a function or an array.
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
|
||||||
|
rep = replacer;
|
||||||
|
if (replacer && typeof replacer !== 'function' &&
|
||||||
|
(typeof replacer !== 'object' ||
|
||||||
|
typeof replacer.length !== 'number')) {
|
||||||
|
throw new Error('JSON.stringify');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a fake root object containing our value under the key of ''.
|
||||||
|
// Return the result of stringifying the value.
|
||||||
|
|
||||||
|
return str('', {'': value});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a parse method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.parse !== 'function') {
|
||||||
|
JSON.parse = function (text, reviver) {
|
||||||
|
|
||||||
|
// The parse method takes a text and an optional reviver function, and returns
|
||||||
|
// a JavaScript value if the text is a valid JSON text.
|
||||||
|
|
||||||
|
var j;
|
||||||
|
|
||||||
|
function walk(holder, key) {
|
||||||
|
|
||||||
|
// The walk method is used to recursively walk the resulting structure so
|
||||||
|
// that modifications can be made.
|
||||||
|
|
||||||
|
var k, v, value = holder[key];
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||||
|
v = walk(value, k);
|
||||||
|
if (v !== undefined) {
|
||||||
|
value[k] = v;
|
||||||
|
} else {
|
||||||
|
delete value[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reviver.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Parsing happens in four stages. In the first stage, we replace certain
|
||||||
|
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||||
|
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||||
|
|
||||||
|
text = String(text);
|
||||||
|
rx_dangerous.lastIndex = 0;
|
||||||
|
if (rx_dangerous.test(text)) {
|
||||||
|
text = text.replace(rx_dangerous, function (a) {
|
||||||
|
return '\\u' +
|
||||||
|
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the second stage, we run the text against regular expressions that look
|
||||||
|
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||||
|
// because they can cause invocation, and '=' because it can cause mutation.
|
||||||
|
// But just to be safe, we want to reject all unexpected forms.
|
||||||
|
|
||||||
|
// We split the second stage into 4 regexp operations in order to work around
|
||||||
|
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||||
|
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||||
|
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||||
|
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||||
|
// we look to see that the remaining characters are only whitespace or ']' or
|
||||||
|
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||||
|
|
||||||
|
if (
|
||||||
|
rx_one.test(
|
||||||
|
text
|
||||||
|
.replace(rx_two, '@')
|
||||||
|
.replace(rx_three, ']')
|
||||||
|
.replace(rx_four, '')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
|
||||||
|
// In the third stage we use the eval function to compile the text into a
|
||||||
|
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||||
|
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||||
|
// in parens to eliminate the ambiguity.
|
||||||
|
|
||||||
|
j = eval('(' + text + ')');
|
||||||
|
|
||||||
|
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||||
|
// each name/value pair to a reviver function for possible transformation.
|
||||||
|
|
||||||
|
return typeof reviver === 'function'
|
||||||
|
? walk({'': j}, '')
|
||||||
|
: j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||||
|
|
||||||
|
throw new SyntaxError('JSON.parse');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}());
|
||||||
354
vendors/json2/json_parse.js
vendored
Normal file
354
vendors/json2/json_parse.js
vendored
Normal file
|
|
@ -0,0 +1,354 @@
|
||||||
|
/*
|
||||||
|
json_parse.js
|
||||||
|
2015-05-02
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
This file creates a json_parse function.
|
||||||
|
|
||||||
|
json_parse(text, reviver)
|
||||||
|
This method parses a JSON text to produce an object or array.
|
||||||
|
It can throw a SyntaxError exception.
|
||||||
|
|
||||||
|
The optional reviver parameter is a function that can filter and
|
||||||
|
transform the results. It receives each of the keys and values,
|
||||||
|
and its return value is used instead of the original value.
|
||||||
|
If it returns what it received, then the structure is not modified.
|
||||||
|
If it returns undefined then the member is deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// Parse the text. Values that look like ISO date strings will
|
||||||
|
// be converted to Date objects.
|
||||||
|
|
||||||
|
myData = json_parse(text, function (key, value) {
|
||||||
|
var a;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
a =
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||||
|
if (a) {
|
||||||
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||||
|
+a[5], +a[6]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
This is a reference implementation. You are free to copy, modify, or
|
||||||
|
redistribute.
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint for */
|
||||||
|
|
||||||
|
/*property
|
||||||
|
at, b, call, charAt, f, fromCharCode, hasOwnProperty, message, n, name,
|
||||||
|
prototype, push, r, t, text
|
||||||
|
*/
|
||||||
|
|
||||||
|
var json_parse = (function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// This is a function that can parse a JSON text, producing a JavaScript
|
||||||
|
// data structure. It is a simple, recursive descent parser. It does not use
|
||||||
|
// eval or regular expressions, so it can be used as a model for implementing
|
||||||
|
// a JSON parser in other languages.
|
||||||
|
|
||||||
|
// We are defining the function inside of another function to avoid creating
|
||||||
|
// global variables.
|
||||||
|
|
||||||
|
var at, // The index of the current character
|
||||||
|
ch, // The current character
|
||||||
|
escapee = {
|
||||||
|
'"': '"',
|
||||||
|
'\\': '\\',
|
||||||
|
'/': '/',
|
||||||
|
b: '\b',
|
||||||
|
f: '\f',
|
||||||
|
n: '\n',
|
||||||
|
r: '\r',
|
||||||
|
t: '\t'
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
|
||||||
|
error = function (m) {
|
||||||
|
|
||||||
|
// Call error when something is wrong.
|
||||||
|
|
||||||
|
throw {
|
||||||
|
name: 'SyntaxError',
|
||||||
|
message: m,
|
||||||
|
at: at,
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
next = function (c) {
|
||||||
|
|
||||||
|
// If a c parameter is provided, verify that it matches the current character.
|
||||||
|
|
||||||
|
if (c && c !== ch) {
|
||||||
|
error("Expected '" + c + "' instead of '" + ch + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next character. When there are no more characters,
|
||||||
|
// return the empty string.
|
||||||
|
|
||||||
|
ch = text.charAt(at);
|
||||||
|
at += 1;
|
||||||
|
return ch;
|
||||||
|
},
|
||||||
|
|
||||||
|
number = function () {
|
||||||
|
|
||||||
|
// Parse a number value.
|
||||||
|
|
||||||
|
var number,
|
||||||
|
string = '';
|
||||||
|
|
||||||
|
if (ch === '-') {
|
||||||
|
string = '-';
|
||||||
|
next('-');
|
||||||
|
}
|
||||||
|
while (ch >= '0' && ch <= '9') {
|
||||||
|
string += ch;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
if (ch === '.') {
|
||||||
|
string += '.';
|
||||||
|
while (next() && ch >= '0' && ch <= '9') {
|
||||||
|
string += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ch === 'e' || ch === 'E') {
|
||||||
|
string += ch;
|
||||||
|
next();
|
||||||
|
if (ch === '-' || ch === '+') {
|
||||||
|
string += ch;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
while (ch >= '0' && ch <= '9') {
|
||||||
|
string += ch;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
number = +string;
|
||||||
|
if (!isFinite(number)) {
|
||||||
|
error("Bad number");
|
||||||
|
} else {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
string = function () {
|
||||||
|
|
||||||
|
// Parse a string value.
|
||||||
|
|
||||||
|
var hex,
|
||||||
|
i,
|
||||||
|
string = '',
|
||||||
|
uffff;
|
||||||
|
|
||||||
|
// When parsing for string values, we must look for " and \ characters.
|
||||||
|
|
||||||
|
if (ch === '"') {
|
||||||
|
while (next()) {
|
||||||
|
if (ch === '"') {
|
||||||
|
next();
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
if (ch === '\\') {
|
||||||
|
next();
|
||||||
|
if (ch === 'u') {
|
||||||
|
uffff = 0;
|
||||||
|
for (i = 0; i < 4; i += 1) {
|
||||||
|
hex = parseInt(next(), 16);
|
||||||
|
if (!isFinite(hex)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uffff = uffff * 16 + hex;
|
||||||
|
}
|
||||||
|
string += String.fromCharCode(uffff);
|
||||||
|
} else if (typeof escapee[ch] === 'string') {
|
||||||
|
string += escapee[ch];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
string += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("Bad string");
|
||||||
|
},
|
||||||
|
|
||||||
|
white = function () {
|
||||||
|
|
||||||
|
// Skip whitespace.
|
||||||
|
|
||||||
|
while (ch && ch <= ' ') {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
word = function () {
|
||||||
|
|
||||||
|
// true, false, or null.
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case 't':
|
||||||
|
next('t');
|
||||||
|
next('r');
|
||||||
|
next('u');
|
||||||
|
next('e');
|
||||||
|
return true;
|
||||||
|
case 'f':
|
||||||
|
next('f');
|
||||||
|
next('a');
|
||||||
|
next('l');
|
||||||
|
next('s');
|
||||||
|
next('e');
|
||||||
|
return false;
|
||||||
|
case 'n':
|
||||||
|
next('n');
|
||||||
|
next('u');
|
||||||
|
next('l');
|
||||||
|
next('l');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
error("Unexpected '" + ch + "'");
|
||||||
|
},
|
||||||
|
|
||||||
|
value, // Place holder for the value function.
|
||||||
|
|
||||||
|
array = function () {
|
||||||
|
|
||||||
|
// Parse an array value.
|
||||||
|
|
||||||
|
var array = [];
|
||||||
|
|
||||||
|
if (ch === '[') {
|
||||||
|
next('[');
|
||||||
|
white();
|
||||||
|
if (ch === ']') {
|
||||||
|
next(']');
|
||||||
|
return array; // empty array
|
||||||
|
}
|
||||||
|
while (ch) {
|
||||||
|
array.push(value());
|
||||||
|
white();
|
||||||
|
if (ch === ']') {
|
||||||
|
next(']');
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
next(',');
|
||||||
|
white();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("Bad array");
|
||||||
|
},
|
||||||
|
|
||||||
|
object = function () {
|
||||||
|
|
||||||
|
// Parse an object value.
|
||||||
|
|
||||||
|
var key,
|
||||||
|
object = {};
|
||||||
|
|
||||||
|
if (ch === '{') {
|
||||||
|
next('{');
|
||||||
|
white();
|
||||||
|
if (ch === '}') {
|
||||||
|
next('}');
|
||||||
|
return object; // empty object
|
||||||
|
}
|
||||||
|
while (ch) {
|
||||||
|
key = string();
|
||||||
|
white();
|
||||||
|
next(':');
|
||||||
|
if (Object.hasOwnProperty.call(object, key)) {
|
||||||
|
error('Duplicate key "' + key + '"');
|
||||||
|
}
|
||||||
|
object[key] = value();
|
||||||
|
white();
|
||||||
|
if (ch === '}') {
|
||||||
|
next('}');
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
next(',');
|
||||||
|
white();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("Bad object");
|
||||||
|
};
|
||||||
|
|
||||||
|
value = function () {
|
||||||
|
|
||||||
|
// Parse a JSON value. It could be an object, an array, a string, a number,
|
||||||
|
// or a word.
|
||||||
|
|
||||||
|
white();
|
||||||
|
switch (ch) {
|
||||||
|
case '{':
|
||||||
|
return object();
|
||||||
|
case '[':
|
||||||
|
return array();
|
||||||
|
case '"':
|
||||||
|
return string();
|
||||||
|
case '-':
|
||||||
|
return number();
|
||||||
|
default:
|
||||||
|
return ch >= '0' && ch <= '9'
|
||||||
|
? number()
|
||||||
|
: word();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return the json_parse function. It will have access to all of the above
|
||||||
|
// functions and variables.
|
||||||
|
|
||||||
|
return function (source, reviver) {
|
||||||
|
var result;
|
||||||
|
|
||||||
|
text = source;
|
||||||
|
at = 0;
|
||||||
|
ch = ' ';
|
||||||
|
result = value();
|
||||||
|
white();
|
||||||
|
if (ch) {
|
||||||
|
error("Syntax error");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a reviver function, we recursively walk the new structure,
|
||||||
|
// passing each name/value pair to the reviver function for possible
|
||||||
|
// transformation, starting with a temporary root object that holds the result
|
||||||
|
// in an empty key. If there is not a reviver function, we simply return the
|
||||||
|
// result.
|
||||||
|
|
||||||
|
return typeof reviver === 'function'
|
||||||
|
? (function walk(holder, key) {
|
||||||
|
var k, v, value = holder[key];
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||||
|
v = walk(value, k);
|
||||||
|
if (v !== undefined) {
|
||||||
|
value[k] = v;
|
||||||
|
} else {
|
||||||
|
delete value[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reviver.call(holder, key, value);
|
||||||
|
}({'': result}, ''))
|
||||||
|
: result;
|
||||||
|
};
|
||||||
|
}());
|
||||||
403
vendors/json2/json_parse_state.js
vendored
Normal file
403
vendors/json2/json_parse_state.js
vendored
Normal file
|
|
@ -0,0 +1,403 @@
|
||||||
|
/*
|
||||||
|
json_parse_state.js
|
||||||
|
2015-05-02
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
This file creates a json_parse function.
|
||||||
|
|
||||||
|
json_parse(text, reviver)
|
||||||
|
This method parses a JSON text to produce an object or array.
|
||||||
|
It can throw a SyntaxError exception.
|
||||||
|
|
||||||
|
The optional reviver parameter is a function that can filter and
|
||||||
|
transform the results. It receives each of the keys and values,
|
||||||
|
and its return value is used instead of the original value.
|
||||||
|
If it returns what it received, then the structure is not modified.
|
||||||
|
If it returns undefined then the member is deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// Parse the text. Values that look like ISO date strings will
|
||||||
|
// be converted to Date objects.
|
||||||
|
|
||||||
|
myData = json_parse(text, function (key, value) {
|
||||||
|
var a;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
a =
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||||
|
if (a) {
|
||||||
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||||
|
+a[5], +a[6]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
This is a reference implementation. You are free to copy, modify, or
|
||||||
|
redistribute.
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint for */
|
||||||
|
|
||||||
|
/*property
|
||||||
|
acomma, avalue, b, call, colon, container, exec, f, false, firstavalue,
|
||||||
|
firstokey, fromCharCode, go, hasOwnProperty, key, length, n, null, ocomma,
|
||||||
|
okey, ovalue, pop, prototype, push, r, replace, slice, state, t, test,
|
||||||
|
true
|
||||||
|
*/
|
||||||
|
|
||||||
|
var json_parse = (function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// This function creates a JSON parse function that uses a state machine rather
|
||||||
|
// than the dangerous eval function to parse a JSON text.
|
||||||
|
|
||||||
|
var state, // The state of the parser, one of
|
||||||
|
// 'go' The starting state
|
||||||
|
// 'ok' The final, accepting state
|
||||||
|
// 'firstokey' Ready for the first key of the object or
|
||||||
|
// the closing of an empty object
|
||||||
|
// 'okey' Ready for the next key of the object
|
||||||
|
// 'colon' Ready for the colon
|
||||||
|
// 'ovalue' Ready for the value half of a key/value pair
|
||||||
|
// 'ocomma' Ready for a comma or closing }
|
||||||
|
// 'firstavalue' Ready for the first value of an array or
|
||||||
|
// an empty array
|
||||||
|
// 'avalue' Ready for the next value of an array
|
||||||
|
// 'acomma' Ready for a comma or closing ]
|
||||||
|
stack, // The stack, for controlling nesting.
|
||||||
|
container, // The current container object or array
|
||||||
|
key, // The current key
|
||||||
|
value, // The current value
|
||||||
|
escapes = { // Escapement translation table
|
||||||
|
'\\': '\\',
|
||||||
|
'"': '"',
|
||||||
|
'/': '/',
|
||||||
|
't': '\t',
|
||||||
|
'n': '\n',
|
||||||
|
'r': '\r',
|
||||||
|
'f': '\f',
|
||||||
|
'b': '\b'
|
||||||
|
},
|
||||||
|
string = { // The actions for string tokens
|
||||||
|
go: function () {
|
||||||
|
state = 'ok';
|
||||||
|
},
|
||||||
|
firstokey: function () {
|
||||||
|
key = value;
|
||||||
|
state = 'colon';
|
||||||
|
},
|
||||||
|
okey: function () {
|
||||||
|
key = value;
|
||||||
|
state = 'colon';
|
||||||
|
},
|
||||||
|
ovalue: function () {
|
||||||
|
state = 'ocomma';
|
||||||
|
},
|
||||||
|
firstavalue: function () {
|
||||||
|
state = 'acomma';
|
||||||
|
},
|
||||||
|
avalue: function () {
|
||||||
|
state = 'acomma';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
number = { // The actions for number tokens
|
||||||
|
go: function () {
|
||||||
|
state = 'ok';
|
||||||
|
},
|
||||||
|
ovalue: function () {
|
||||||
|
state = 'ocomma';
|
||||||
|
},
|
||||||
|
firstavalue: function () {
|
||||||
|
state = 'acomma';
|
||||||
|
},
|
||||||
|
avalue: function () {
|
||||||
|
state = 'acomma';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
action = {
|
||||||
|
|
||||||
|
// The action table describes the behavior of the machine. It contains an
|
||||||
|
// object for each token. Each object contains a method that is called when
|
||||||
|
// a token is matched in a state. An object will lack a method for illegal
|
||||||
|
// states.
|
||||||
|
|
||||||
|
'{': {
|
||||||
|
go: function () {
|
||||||
|
stack.push({state: 'ok'});
|
||||||
|
container = {};
|
||||||
|
state = 'firstokey';
|
||||||
|
},
|
||||||
|
ovalue: function () {
|
||||||
|
stack.push({container: container, state: 'ocomma', key: key});
|
||||||
|
container = {};
|
||||||
|
state = 'firstokey';
|
||||||
|
},
|
||||||
|
firstavalue: function () {
|
||||||
|
stack.push({container: container, state: 'acomma'});
|
||||||
|
container = {};
|
||||||
|
state = 'firstokey';
|
||||||
|
},
|
||||||
|
avalue: function () {
|
||||||
|
stack.push({container: container, state: 'acomma'});
|
||||||
|
container = {};
|
||||||
|
state = 'firstokey';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'}': {
|
||||||
|
firstokey: function () {
|
||||||
|
var pop = stack.pop();
|
||||||
|
value = container;
|
||||||
|
container = pop.container;
|
||||||
|
key = pop.key;
|
||||||
|
state = pop.state;
|
||||||
|
},
|
||||||
|
ocomma: function () {
|
||||||
|
var pop = stack.pop();
|
||||||
|
container[key] = value;
|
||||||
|
value = container;
|
||||||
|
container = pop.container;
|
||||||
|
key = pop.key;
|
||||||
|
state = pop.state;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'[': {
|
||||||
|
go: function () {
|
||||||
|
stack.push({state: 'ok'});
|
||||||
|
container = [];
|
||||||
|
state = 'firstavalue';
|
||||||
|
},
|
||||||
|
ovalue: function () {
|
||||||
|
stack.push({container: container, state: 'ocomma', key: key});
|
||||||
|
container = [];
|
||||||
|
state = 'firstavalue';
|
||||||
|
},
|
||||||
|
firstavalue: function () {
|
||||||
|
stack.push({container: container, state: 'acomma'});
|
||||||
|
container = [];
|
||||||
|
state = 'firstavalue';
|
||||||
|
},
|
||||||
|
avalue: function () {
|
||||||
|
stack.push({container: container, state: 'acomma'});
|
||||||
|
container = [];
|
||||||
|
state = 'firstavalue';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
']': {
|
||||||
|
firstavalue: function () {
|
||||||
|
var pop = stack.pop();
|
||||||
|
value = container;
|
||||||
|
container = pop.container;
|
||||||
|
key = pop.key;
|
||||||
|
state = pop.state;
|
||||||
|
},
|
||||||
|
acomma: function () {
|
||||||
|
var pop = stack.pop();
|
||||||
|
container.push(value);
|
||||||
|
value = container;
|
||||||
|
container = pop.container;
|
||||||
|
key = pop.key;
|
||||||
|
state = pop.state;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
':': {
|
||||||
|
colon: function () {
|
||||||
|
if (Object.hasOwnProperty.call(container, key)) {
|
||||||
|
throw new SyntaxError('Duplicate key "' + key + '"');
|
||||||
|
}
|
||||||
|
state = 'ovalue';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
',': {
|
||||||
|
ocomma: function () {
|
||||||
|
container[key] = value;
|
||||||
|
state = 'okey';
|
||||||
|
},
|
||||||
|
acomma: function () {
|
||||||
|
container.push(value);
|
||||||
|
state = 'avalue';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'true': {
|
||||||
|
go: function () {
|
||||||
|
value = true;
|
||||||
|
state = 'ok';
|
||||||
|
},
|
||||||
|
ovalue: function () {
|
||||||
|
value = true;
|
||||||
|
state = 'ocomma';
|
||||||
|
},
|
||||||
|
firstavalue: function () {
|
||||||
|
value = true;
|
||||||
|
state = 'acomma';
|
||||||
|
},
|
||||||
|
avalue: function () {
|
||||||
|
value = true;
|
||||||
|
state = 'acomma';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'false': {
|
||||||
|
go: function () {
|
||||||
|
value = false;
|
||||||
|
state = 'ok';
|
||||||
|
},
|
||||||
|
ovalue: function () {
|
||||||
|
value = false;
|
||||||
|
state = 'ocomma';
|
||||||
|
},
|
||||||
|
firstavalue: function () {
|
||||||
|
value = false;
|
||||||
|
state = 'acomma';
|
||||||
|
},
|
||||||
|
avalue: function () {
|
||||||
|
value = false;
|
||||||
|
state = 'acomma';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'null': {
|
||||||
|
go: function () {
|
||||||
|
value = null;
|
||||||
|
state = 'ok';
|
||||||
|
},
|
||||||
|
ovalue: function () {
|
||||||
|
value = null;
|
||||||
|
state = 'ocomma';
|
||||||
|
},
|
||||||
|
firstavalue: function () {
|
||||||
|
value = null;
|
||||||
|
state = 'acomma';
|
||||||
|
},
|
||||||
|
avalue: function () {
|
||||||
|
value = null;
|
||||||
|
state = 'acomma';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function debackslashify(text) {
|
||||||
|
|
||||||
|
// Remove and replace any backslash escapement.
|
||||||
|
|
||||||
|
return text.replace(/\\(?:u(.{4})|([^u]))/g, function (ignore, b, c) {
|
||||||
|
return b
|
||||||
|
? String.fromCharCode(parseInt(b, 16))
|
||||||
|
: escapes[c];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (source, reviver) {
|
||||||
|
|
||||||
|
// A regular expression is used to extract tokens from the JSON text.
|
||||||
|
// The extraction process is cautious.
|
||||||
|
|
||||||
|
var result,
|
||||||
|
tx = /^[\u0020\t\n\r]*(?:([,:\[\]{}]|true|false|null)|(-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)|"((?:[^\r\n\t\\\"]|\\(?:["\\\/trnfb]|u[0-9a-fA-F]{4}))*)")/;
|
||||||
|
|
||||||
|
// Set the starting state.
|
||||||
|
|
||||||
|
state = 'go';
|
||||||
|
|
||||||
|
// The stack records the container, key, and state for each object or array
|
||||||
|
// that contains another object or array while processing nested structures.
|
||||||
|
|
||||||
|
stack = [];
|
||||||
|
|
||||||
|
// If any error occurs, we will catch it and ultimately throw a syntax error.
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// For each token...
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
result = tx.exec(source);
|
||||||
|
if (!result) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// result is the result array from matching the tokenizing regular expression.
|
||||||
|
// result[0] contains everything that matched, including any initial whitespace.
|
||||||
|
// result[1] contains any punctuation that was matched, or true, false, or null.
|
||||||
|
// result[2] contains a matched number, still in string form.
|
||||||
|
// result[3] contains a matched string, without quotes but with escapement.
|
||||||
|
|
||||||
|
if (result[1]) {
|
||||||
|
|
||||||
|
// Token: Execute the action for this state and token.
|
||||||
|
|
||||||
|
action[result[1]][state]();
|
||||||
|
|
||||||
|
} else if (result[2]) {
|
||||||
|
|
||||||
|
// Number token: Convert the number string into a number value and execute
|
||||||
|
// the action for this state and number.
|
||||||
|
|
||||||
|
value = +result[2];
|
||||||
|
number[state]();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// String token: Replace the escapement sequences and execute the action for
|
||||||
|
// this state and string.
|
||||||
|
|
||||||
|
value = debackslashify(result[3]);
|
||||||
|
string[state]();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the token from the string. The loop will continue as long as there
|
||||||
|
// are tokens. This is a slow process, but it allows the use of ^ matching,
|
||||||
|
// which assures that no illegal tokens slip through.
|
||||||
|
|
||||||
|
source = source.slice(result[0].length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we find a state/token combination that is illegal, then the action will
|
||||||
|
// cause an error. We handle the error by simply changing the state.
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
state = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The parsing is finished. If we are not in the final 'ok' state, or if the
|
||||||
|
// remaining source contains anything except whitespace, then we did not have
|
||||||
|
//a well-formed JSON text.
|
||||||
|
|
||||||
|
if (state !== 'ok' || (/[^\u0020\t\n\r]/.test(source))) {
|
||||||
|
throw state instanceof SyntaxError
|
||||||
|
? state
|
||||||
|
: new SyntaxError('JSON');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a reviver function, we recursively walk the new structure,
|
||||||
|
// passing each name/value pair to the reviver function for possible
|
||||||
|
// transformation, starting with a temporary root object that holds the current
|
||||||
|
// value in an empty key. If there is not a reviver function, we simply return
|
||||||
|
// that value.
|
||||||
|
|
||||||
|
return typeof reviver === 'function'
|
||||||
|
? (function walk(holder, key) {
|
||||||
|
var k, v, value = holder[key];
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||||
|
v = walk(value, k);
|
||||||
|
if (v !== undefined) {
|
||||||
|
value[k] = v;
|
||||||
|
} else {
|
||||||
|
delete value[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reviver.call(holder, key, value);
|
||||||
|
}({'': value}, ''))
|
||||||
|
: value;
|
||||||
|
};
|
||||||
|
}());
|
||||||
4
vendors/modernizr.js
vendored
4
vendors/modernizr.js
vendored
File diff suppressed because one or more lines are too long
11
vendors/modernizr/config.json
vendored
Normal file
11
vendors/modernizr/config.json
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"minify": false,
|
||||||
|
"options": [
|
||||||
|
"setClasses"
|
||||||
|
],
|
||||||
|
"feature-detects": [
|
||||||
|
"test/css/animations",
|
||||||
|
"test/css/rgba",
|
||||||
|
"test/css/transitions"
|
||||||
|
]
|
||||||
|
}
|
||||||
824
vendors/modernizr/modernizr-custom.js
vendored
Normal file
824
vendors/modernizr/modernizr-custom.js
vendored
Normal file
|
|
@ -0,0 +1,824 @@
|
||||||
|
/*!
|
||||||
|
* modernizr v3.3.1
|
||||||
|
* Build http://modernizr.com/download?-cssanimations-csstransitions-rgba-setclasses-dontmin
|
||||||
|
*
|
||||||
|
* Copyright (c)
|
||||||
|
* Faruk Ates
|
||||||
|
* Paul Irish
|
||||||
|
* Alex Sexton
|
||||||
|
* Ryan Seddon
|
||||||
|
* Patrick Kettner
|
||||||
|
* Stu Cox
|
||||||
|
* Richard Herrera
|
||||||
|
|
||||||
|
* MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modernizr tests which native CSS3 and HTML5 features are available in the
|
||||||
|
* current UA and makes the results available to you in two ways: as properties on
|
||||||
|
* a global `Modernizr` object, and as classes on the `<html>` element. This
|
||||||
|
* information allows you to progressively enhance your pages with a granular level
|
||||||
|
* of control over the experience.
|
||||||
|
*/
|
||||||
|
|
||||||
|
;(function(window, document, undefined){
|
||||||
|
var classes = [];
|
||||||
|
|
||||||
|
|
||||||
|
var tests = [];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* ModernizrProto is the constructor for Modernizr
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
|
||||||
|
var ModernizrProto = {
|
||||||
|
// The current version, dummy
|
||||||
|
_version: '3.3.1',
|
||||||
|
|
||||||
|
// Any settings that don't work as separate modules
|
||||||
|
// can go in here as configuration.
|
||||||
|
_config: {
|
||||||
|
'classPrefix': '',
|
||||||
|
'enableClasses': true,
|
||||||
|
'enableJSClass': true,
|
||||||
|
'usePrefixes': true
|
||||||
|
},
|
||||||
|
|
||||||
|
// Queue of tests
|
||||||
|
_q: [],
|
||||||
|
|
||||||
|
// Stub these for people who are listening
|
||||||
|
on: function(test, cb) {
|
||||||
|
// I don't really think people should do this, but we can
|
||||||
|
// safe guard it a bit.
|
||||||
|
// -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
|
||||||
|
// This is in case people listen to synchronous tests. I would leave it out,
|
||||||
|
// but the code to *disallow* sync tests in the real version of this
|
||||||
|
// function is actually larger than this.
|
||||||
|
var self = this;
|
||||||
|
setTimeout(function() {
|
||||||
|
cb(self[test]);
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
addTest: function(name, fn, options) {
|
||||||
|
tests.push({name: name, fn: fn, options: options});
|
||||||
|
},
|
||||||
|
|
||||||
|
addAsyncTest: function(fn) {
|
||||||
|
tests.push({name: null, fn: fn});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Fake some of Object.create so we can force non test results to be non "own" properties.
|
||||||
|
var Modernizr = function() {};
|
||||||
|
Modernizr.prototype = ModernizrProto;
|
||||||
|
|
||||||
|
// Leak modernizr globally when you `require` it rather than force it here.
|
||||||
|
// Overwrite name so constructor name is nicer :D
|
||||||
|
Modernizr = new Modernizr();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is returns a boolean if the typeof an obj is exactly type.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function is
|
||||||
|
* @param {*} obj - A thing we want to check the type of
|
||||||
|
* @param {string} type - A string to compare the typeof against
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function is(obj, type) {
|
||||||
|
return typeof obj === type;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run through all tests and detect their support in the current UA.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function testRunner() {
|
||||||
|
var featureNames;
|
||||||
|
var feature;
|
||||||
|
var aliasIdx;
|
||||||
|
var result;
|
||||||
|
var nameIdx;
|
||||||
|
var featureName;
|
||||||
|
var featureNameSplit;
|
||||||
|
|
||||||
|
for (var featureIdx in tests) {
|
||||||
|
if (tests.hasOwnProperty(featureIdx)) {
|
||||||
|
featureNames = [];
|
||||||
|
feature = tests[featureIdx];
|
||||||
|
// run the test, throw the return value into the Modernizr,
|
||||||
|
// then based on that boolean, define an appropriate className
|
||||||
|
// and push it into an array of classes we'll join later.
|
||||||
|
//
|
||||||
|
// If there is no name, it's an 'async' test that is run,
|
||||||
|
// but not directly added to the object. That should
|
||||||
|
// be done with a post-run addTest call.
|
||||||
|
if (feature.name) {
|
||||||
|
featureNames.push(feature.name.toLowerCase());
|
||||||
|
|
||||||
|
if (feature.options && feature.options.aliases && feature.options.aliases.length) {
|
||||||
|
// Add all the aliases into the names list
|
||||||
|
for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
|
||||||
|
featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the test, or use the raw value if it's not a function
|
||||||
|
result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
|
||||||
|
|
||||||
|
|
||||||
|
// Set each of the names on the Modernizr object
|
||||||
|
for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
|
||||||
|
featureName = featureNames[nameIdx];
|
||||||
|
// Support dot properties as sub tests. We don't do checking to make sure
|
||||||
|
// that the implied parent tests have been added. You must call them in
|
||||||
|
// order (either in the test, or make the parent test a dependency).
|
||||||
|
//
|
||||||
|
// Cap it to TWO to make the logic simple and because who needs that kind of subtesting
|
||||||
|
// hashtag famous last words
|
||||||
|
featureNameSplit = featureName.split('.');
|
||||||
|
|
||||||
|
if (featureNameSplit.length === 1) {
|
||||||
|
Modernizr[featureNameSplit[0]] = result;
|
||||||
|
} else {
|
||||||
|
// cast to a Boolean, if not one already
|
||||||
|
/* jshint -W053 */
|
||||||
|
if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
|
||||||
|
Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* docElement is a convenience wrapper to grab the root element of the document
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @returns {HTMLElement|SVGElement} The root element of the document
|
||||||
|
*/
|
||||||
|
|
||||||
|
var docElement = document.documentElement;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience helper to check if the document we are running in is an SVG document
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
var isSVG = docElement.nodeName.toLowerCase() === 'svg';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setClasses takes an array of class names and adds them to the root element
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function setClasses
|
||||||
|
* @param {string[]} classes - Array of class names
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Pass in an and array of class names, e.g.:
|
||||||
|
// ['no-webp', 'borderradius', ...]
|
||||||
|
function setClasses(classes) {
|
||||||
|
var className = docElement.className;
|
||||||
|
var classPrefix = Modernizr._config.classPrefix || '';
|
||||||
|
|
||||||
|
if (isSVG) {
|
||||||
|
className = className.baseVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change `no-js` to `js` (independently of the `enableClasses` option)
|
||||||
|
// Handle classPrefix on this too
|
||||||
|
if (Modernizr._config.enableJSClass) {
|
||||||
|
var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
|
||||||
|
className = className.replace(reJS, '$1' + classPrefix + 'js$2');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Modernizr._config.enableClasses) {
|
||||||
|
// Add the new classes
|
||||||
|
className += ' ' + classPrefix + classes.join(' ' + classPrefix);
|
||||||
|
isSVG ? docElement.className.baseVal = className : docElement.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* createElement is a convenience wrapper around document.createElement. Since we
|
||||||
|
* use createElement all over the place, this allows for (slightly) smaller code
|
||||||
|
* as well as abstracting away issues with creating elements in contexts other than
|
||||||
|
* HTML documents (e.g. SVG documents).
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function createElement
|
||||||
|
* @returns {HTMLElement|SVGElement} An HTML or SVG element
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createElement() {
|
||||||
|
if (typeof document.createElement !== 'function') {
|
||||||
|
// This is the case in IE7, where the type of createElement is "object".
|
||||||
|
// For this reason, we cannot call apply() as Object is not a Function.
|
||||||
|
return document.createElement(arguments[0]);
|
||||||
|
} else if (isSVG) {
|
||||||
|
return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
|
||||||
|
} else {
|
||||||
|
return document.createElement.apply(document, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
/*!
|
||||||
|
{
|
||||||
|
"name": "CSS rgba",
|
||||||
|
"caniuse": "css3-colors",
|
||||||
|
"property": "rgba",
|
||||||
|
"tags": ["css"],
|
||||||
|
"notes": [{
|
||||||
|
"name": "CSSTricks Tutorial",
|
||||||
|
"href": "https://css-tricks.com/rgba-browser-support/"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
!*/
|
||||||
|
|
||||||
|
Modernizr.addTest('rgba', function() {
|
||||||
|
var style = createElement('a').style;
|
||||||
|
style.cssText = 'background-color:rgba(150,255,150,.5)';
|
||||||
|
|
||||||
|
return ('' + style.backgroundColor).indexOf('rgba') > -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the browsers follow the spec, then they would expose vendor-specific style as:
|
||||||
|
* elem.style.WebkitBorderRadius
|
||||||
|
* instead of something like the following, which would be technically incorrect:
|
||||||
|
* elem.style.webkitBorderRadius
|
||||||
|
|
||||||
|
* Webkit ghosts their properties in lowercase but Opera & Moz do not.
|
||||||
|
* Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
|
||||||
|
* erik.eae.net/archives/2008/03/10/21.48.10/
|
||||||
|
|
||||||
|
* More here: github.com/Modernizr/Modernizr/issues/issue/21
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @returns {string} The string representing the vendor-specific style properties
|
||||||
|
*/
|
||||||
|
|
||||||
|
var omPrefixes = 'Moz O ms Webkit';
|
||||||
|
|
||||||
|
|
||||||
|
var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
|
||||||
|
ModernizrProto._cssomPrefixes = cssomPrefixes;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of JavaScript DOM values used for tests
|
||||||
|
*
|
||||||
|
* @memberof Modernizr
|
||||||
|
* @name Modernizr._domPrefixes
|
||||||
|
* @optionName Modernizr._domPrefixes
|
||||||
|
* @optionProp domPrefixes
|
||||||
|
* @access public
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
|
||||||
|
* than kebab-case properties, all properties are their Capitalized variant
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
|
||||||
|
ModernizrProto._domPrefixes = domPrefixes;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contains checks to see if a string contains another string
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function contains
|
||||||
|
* @param {string} str - The string we want to check for substrings
|
||||||
|
* @param {string} substr - The substring we want to search the first string for
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function contains(str, substr) {
|
||||||
|
return !!~('' + str).indexOf(substr);
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cssToDOM takes a kebab-case string and converts it to camelCase
|
||||||
|
* e.g. box-sizing -> boxSizing
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function cssToDOM
|
||||||
|
* @param {string} name - String name of kebab-case prop we want to convert
|
||||||
|
* @returns {string} The camelCase version of the supplied name
|
||||||
|
*/
|
||||||
|
|
||||||
|
function cssToDOM(name) {
|
||||||
|
return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
|
||||||
|
return m1 + m2.toUpperCase();
|
||||||
|
}).replace(/^-/, '');
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function fnBind
|
||||||
|
* @param {function} fn - a function you want to change `this` reference to
|
||||||
|
* @param {object} that - the `this` you want to call the function with
|
||||||
|
* @returns {function} The wrapped version of the supplied function
|
||||||
|
*/
|
||||||
|
|
||||||
|
function fnBind(fn, that) {
|
||||||
|
return function() {
|
||||||
|
return fn.apply(that, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testDOMProps is a generic DOM property test; if a browser supports
|
||||||
|
* a certain property, it won't return undefined for it.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function testDOMProps
|
||||||
|
* @param {array.<string>} props - An array of properties to test for
|
||||||
|
* @param {object} obj - An object or Element you want to use to test the parameters again
|
||||||
|
* @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
|
||||||
|
*/
|
||||||
|
function testDOMProps(props, obj, elem) {
|
||||||
|
var item;
|
||||||
|
|
||||||
|
for (var i in props) {
|
||||||
|
if (props[i] in obj) {
|
||||||
|
|
||||||
|
// return the property name as a string
|
||||||
|
if (elem === false) {
|
||||||
|
return props[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
item = obj[props[i]];
|
||||||
|
|
||||||
|
// let's bind a function
|
||||||
|
if (is(item, 'function')) {
|
||||||
|
// bind to obj unless overriden
|
||||||
|
return fnBind(item, elem || obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the unbound function or obj or value
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create our "modernizr" element that we do most feature tests on.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var modElem = {
|
||||||
|
elem: createElement('modernizr')
|
||||||
|
};
|
||||||
|
|
||||||
|
// Clean up this element
|
||||||
|
Modernizr._q.push(function() {
|
||||||
|
delete modElem.elem;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var mStyle = {
|
||||||
|
style: modElem.elem.style
|
||||||
|
};
|
||||||
|
|
||||||
|
// kill ref for gc, must happen before mod.elem is removed, so we unshift on to
|
||||||
|
// the front of the queue.
|
||||||
|
Modernizr._q.unshift(function() {
|
||||||
|
delete mStyle.style;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* domToCSS takes a camelCase string and converts it to kebab-case
|
||||||
|
* e.g. boxSizing -> box-sizing
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function domToCSS
|
||||||
|
* @param {string} name - String name of camelCase prop we want to convert
|
||||||
|
* @returns {string} The kebab-case version of the supplied name
|
||||||
|
*/
|
||||||
|
|
||||||
|
function domToCSS(name) {
|
||||||
|
return name.replace(/([A-Z])/g, function(str, m1) {
|
||||||
|
return '-' + m1.toLowerCase();
|
||||||
|
}).replace(/^ms-/, '-ms-');
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getBody returns the body of a document, or an element that can stand in for
|
||||||
|
* the body if a real body does not exist
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function getBody
|
||||||
|
* @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
|
||||||
|
* artificially created element that stands in for the body
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getBody() {
|
||||||
|
// After page load injecting a fake body doesn't work so check if body exists
|
||||||
|
var body = document.body;
|
||||||
|
|
||||||
|
if (!body) {
|
||||||
|
// Can't use the real body create a fake one.
|
||||||
|
body = createElement(isSVG ? 'svg' : 'body');
|
||||||
|
body.fake = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* injectElementWithStyles injects an element with style element and some CSS rules
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function injectElementWithStyles
|
||||||
|
* @param {string} rule - String representing a css rule
|
||||||
|
* @param {function} callback - A function that is used to test the injected element
|
||||||
|
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
|
||||||
|
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function injectElementWithStyles(rule, callback, nodes, testnames) {
|
||||||
|
var mod = 'modernizr';
|
||||||
|
var style;
|
||||||
|
var ret;
|
||||||
|
var node;
|
||||||
|
var docOverflow;
|
||||||
|
var div = createElement('div');
|
||||||
|
var body = getBody();
|
||||||
|
|
||||||
|
if (parseInt(nodes, 10)) {
|
||||||
|
// In order not to give false positives we create a node for each test
|
||||||
|
// This also allows the method to scale for unspecified uses
|
||||||
|
while (nodes--) {
|
||||||
|
node = createElement('div');
|
||||||
|
node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
|
||||||
|
div.appendChild(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
style = createElement('style');
|
||||||
|
style.type = 'text/css';
|
||||||
|
style.id = 's' + mod;
|
||||||
|
|
||||||
|
// IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
|
||||||
|
// Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
|
||||||
|
(!body.fake ? div : body).appendChild(style);
|
||||||
|
body.appendChild(div);
|
||||||
|
|
||||||
|
if (style.styleSheet) {
|
||||||
|
style.styleSheet.cssText = rule;
|
||||||
|
} else {
|
||||||
|
style.appendChild(document.createTextNode(rule));
|
||||||
|
}
|
||||||
|
div.id = mod;
|
||||||
|
|
||||||
|
if (body.fake) {
|
||||||
|
//avoid crashing IE8, if background image is used
|
||||||
|
body.style.background = '';
|
||||||
|
//Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
|
||||||
|
body.style.overflow = 'hidden';
|
||||||
|
docOverflow = docElement.style.overflow;
|
||||||
|
docElement.style.overflow = 'hidden';
|
||||||
|
docElement.appendChild(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = callback(div, rule);
|
||||||
|
// If this is done after page load we don't want to remove the body so check if body exists
|
||||||
|
if (body.fake) {
|
||||||
|
body.parentNode.removeChild(body);
|
||||||
|
docElement.style.overflow = docOverflow;
|
||||||
|
// Trigger layout so kinetic scrolling isn't disabled in iOS6+
|
||||||
|
docElement.offsetHeight;
|
||||||
|
} else {
|
||||||
|
div.parentNode.removeChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nativeTestProps allows for us to use native feature detection functionality if available.
|
||||||
|
* some prefixed form, or false, in the case of an unsupported rule
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function nativeTestProps
|
||||||
|
* @param {array} props - An array of property names
|
||||||
|
* @param {string} value - A string representing the value we want to check via @supports
|
||||||
|
* @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Accepts a list of property names and a single value
|
||||||
|
// Returns `undefined` if native detection not available
|
||||||
|
function nativeTestProps(props, value) {
|
||||||
|
var i = props.length;
|
||||||
|
// Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
|
||||||
|
if ('CSS' in window && 'supports' in window.CSS) {
|
||||||
|
// Try every prefixed variant of the property
|
||||||
|
while (i--) {
|
||||||
|
if (window.CSS.supports(domToCSS(props[i]), value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Otherwise fall back to at-rule (for Opera 12.x)
|
||||||
|
else if ('CSSSupportsRule' in window) {
|
||||||
|
// Build a condition string for every prefixed variant
|
||||||
|
var conditionText = [];
|
||||||
|
while (i--) {
|
||||||
|
conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
|
||||||
|
}
|
||||||
|
conditionText = conditionText.join(' or ');
|
||||||
|
return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
|
||||||
|
return getComputedStyle(node, null).position == 'absolute';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
// testProps is a generic CSS / DOM property test.
|
||||||
|
|
||||||
|
// In testing support for a given CSS property, it's legit to test:
|
||||||
|
// `elem.style[styleName] !== undefined`
|
||||||
|
// If the property is supported it will return an empty string,
|
||||||
|
// if unsupported it will return undefined.
|
||||||
|
|
||||||
|
// We'll take advantage of this quick test and skip setting a style
|
||||||
|
// on our modernizr element, but instead just testing undefined vs
|
||||||
|
// empty string.
|
||||||
|
|
||||||
|
// Property names can be provided in either camelCase or kebab-case.
|
||||||
|
|
||||||
|
function testProps(props, prefixed, value, skipValueTest) {
|
||||||
|
skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
|
||||||
|
|
||||||
|
// Try native detect first
|
||||||
|
if (!is(value, 'undefined')) {
|
||||||
|
var result = nativeTestProps(props, value);
|
||||||
|
if (!is(result, 'undefined')) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise do it properly
|
||||||
|
var afterInit, i, propsLength, prop, before;
|
||||||
|
|
||||||
|
// If we don't have a style element, that means we're running async or after
|
||||||
|
// the core tests, so we'll need to create our own elements to use
|
||||||
|
|
||||||
|
// inside of an SVG element, in certain browsers, the `style` element is only
|
||||||
|
// defined for valid tags. Therefore, if `modernizr` does not have one, we
|
||||||
|
// fall back to a less used element and hope for the best.
|
||||||
|
var elems = ['modernizr', 'tspan'];
|
||||||
|
while (!mStyle.style) {
|
||||||
|
afterInit = true;
|
||||||
|
mStyle.modElem = createElement(elems.shift());
|
||||||
|
mStyle.style = mStyle.modElem.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the objects if we created them.
|
||||||
|
function cleanElems() {
|
||||||
|
if (afterInit) {
|
||||||
|
delete mStyle.style;
|
||||||
|
delete mStyle.modElem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
propsLength = props.length;
|
||||||
|
for (i = 0; i < propsLength; i++) {
|
||||||
|
prop = props[i];
|
||||||
|
before = mStyle.style[prop];
|
||||||
|
|
||||||
|
if (contains(prop, '-')) {
|
||||||
|
prop = cssToDOM(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mStyle.style[prop] !== undefined) {
|
||||||
|
|
||||||
|
// If value to test has been passed in, do a set-and-check test.
|
||||||
|
// 0 (integer) is a valid property value, so check that `value` isn't
|
||||||
|
// undefined, rather than just checking it's truthy.
|
||||||
|
if (!skipValueTest && !is(value, 'undefined')) {
|
||||||
|
|
||||||
|
// Needs a try catch block because of old IE. This is slow, but will
|
||||||
|
// be avoided in most cases because `skipValueTest` will be used.
|
||||||
|
try {
|
||||||
|
mStyle.style[prop] = value;
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
// If the property value has changed, we assume the value used is
|
||||||
|
// supported. If `value` is empty string, it'll fail here (because
|
||||||
|
// it hasn't changed), which matches how browsers have implemented
|
||||||
|
// CSS.supports()
|
||||||
|
if (mStyle.style[prop] != before) {
|
||||||
|
cleanElems();
|
||||||
|
return prefixed == 'pfx' ? prop : true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise just return true, or the property name if this is a
|
||||||
|
// `prefixed()` call
|
||||||
|
else {
|
||||||
|
cleanElems();
|
||||||
|
return prefixed == 'pfx' ? prop : true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cleanElems();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testPropsAll tests a list of DOM properties we want to check against.
|
||||||
|
* We specify literally ALL possible (known and/or likely) properties on
|
||||||
|
* the element including the non-vendor prefixed one, for forward-
|
||||||
|
* compatibility.
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @function testPropsAll
|
||||||
|
* @param {string} prop - A string of the property to test for
|
||||||
|
* @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
|
||||||
|
* @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
|
||||||
|
* @param {string} [value] - A string of a css value
|
||||||
|
* @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
|
||||||
|
*/
|
||||||
|
function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
|
||||||
|
|
||||||
|
var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
|
||||||
|
props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
|
||||||
|
|
||||||
|
// did they call .prefixed('boxSizing') or are we just testing a prop?
|
||||||
|
if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
|
||||||
|
return testProps(props, prefixed, value, skipValueTest);
|
||||||
|
|
||||||
|
// otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
|
||||||
|
} else {
|
||||||
|
props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
|
||||||
|
return testDOMProps(props, prefixed, elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modernizr.testAllProps() investigates whether a given style property,
|
||||||
|
// or any of its vendor-prefixed variants, is recognized
|
||||||
|
//
|
||||||
|
// Note that the property names must be provided in the camelCase variant.
|
||||||
|
// Modernizr.testAllProps('boxSizing')
|
||||||
|
ModernizrProto.testAllProps = testPropsAll;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testAllProps determines whether a given CSS property is supported in the browser
|
||||||
|
*
|
||||||
|
* @memberof Modernizr
|
||||||
|
* @name Modernizr.testAllProps
|
||||||
|
* @optionName Modernizr.testAllProps()
|
||||||
|
* @optionProp testAllProps
|
||||||
|
* @access public
|
||||||
|
* @function testAllProps
|
||||||
|
* @param {string} prop - String naming the property to test (either camelCase or kebab-case)
|
||||||
|
* @param {string} [value] - String of the value to test
|
||||||
|
* @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* testAllProps determines whether a given CSS property, in some prefixed form,
|
||||||
|
* is supported by the browser.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* testAllProps('boxSizing') // true
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* It can optionally be given a CSS value in string form to test if a property
|
||||||
|
* value is valid
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* testAllProps('display', 'block') // true
|
||||||
|
* testAllProps('display', 'penguin') // false
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* A boolean can be passed as a third parameter to skip the value check when
|
||||||
|
* native detection (@supports) isn't available.
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* testAllProps('shapeOutside', 'content-box', true);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
function testAllProps(prop, value, skipValueTest) {
|
||||||
|
return testPropsAll(prop, undefined, undefined, value, skipValueTest);
|
||||||
|
}
|
||||||
|
ModernizrProto.testAllProps = testAllProps;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
{
|
||||||
|
"name": "CSS Animations",
|
||||||
|
"property": "cssanimations",
|
||||||
|
"caniuse": "css-animation",
|
||||||
|
"polyfills": ["transformie", "csssandpaper"],
|
||||||
|
"tags": ["css"],
|
||||||
|
"warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
|
||||||
|
"notes": [{
|
||||||
|
"name" : "Article: 'Dispelling the Android CSS animation myths'",
|
||||||
|
"href": "https://goo.gl/OGw5Gm"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
!*/
|
||||||
|
/* DOC
|
||||||
|
Detects whether or not elements can be animated using CSS
|
||||||
|
*/
|
||||||
|
|
||||||
|
Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
|
||||||
|
|
||||||
|
/*!
|
||||||
|
{
|
||||||
|
"name": "CSS Transitions",
|
||||||
|
"property": "csstransitions",
|
||||||
|
"caniuse": "css-transitions",
|
||||||
|
"tags": ["css"]
|
||||||
|
}
|
||||||
|
!*/
|
||||||
|
|
||||||
|
Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
|
||||||
|
|
||||||
|
|
||||||
|
// Run each test
|
||||||
|
testRunner();
|
||||||
|
|
||||||
|
// Remove the "no-js" class if it exists
|
||||||
|
setClasses(classes);
|
||||||
|
|
||||||
|
delete ModernizrProto.addTest;
|
||||||
|
delete ModernizrProto.addAsyncTest;
|
||||||
|
|
||||||
|
// Run the things that are supposed to run after the tests
|
||||||
|
for (var i = 0; i < Modernizr._q.length; i++) {
|
||||||
|
Modernizr._q[i]();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leak Modernizr namespace
|
||||||
|
window.Modernizr = Modernizr;
|
||||||
|
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
})(window, document);
|
||||||
|
|
@ -6,6 +6,7 @@ var
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
|
'boot': __dirname + '/dev/boot.jsx',
|
||||||
'app': __dirname + '/dev/app.jsx',
|
'app': __dirname + '/dev/app.jsx',
|
||||||
'admin': __dirname + '/dev/admin.jsx'
|
'admin': __dirname + '/dev/admin.jsx'
|
||||||
},
|
},
|
||||||
|
|
@ -22,7 +23,7 @@ module.exports = {
|
||||||
new webpack.optimize.OccurenceOrderPlugin()
|
new webpack.optimize.OccurenceOrderPlugin()
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
root: path.resolve(__dirname, 'dev'),
|
root: [path.resolve(__dirname, 'dev'), path.resolve(__dirname, 'vendors')],
|
||||||
extensions: ['', '.js', '.jsx'],
|
extensions: ['', '.js', '.jsx'],
|
||||||
alias: {
|
alias: {
|
||||||
'Opentip': __dirname + '/dev/External/Opentip.js',
|
'Opentip': __dirname + '/dev/External/Opentip.js',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue