diff --git a/dev/App/Abstract.js b/dev/App/Abstract.js
index 89176fdb8..7fcd9d0eb 100644
--- a/dev/App/Abstract.js
+++ b/dev/App/Abstract.js
@@ -216,11 +216,20 @@
ko = require('ko')
;
- ko.components.register('SaveTrigger', require('Components/SaveTrigger'));
- ko.components.register('Checkbox', require('Components/Checkbox'));
- ko.components.register('Input', require('Components/Input'));
- ko.components.register('Select', require('Components/Select'));
- ko.components.register('TextArea', require('Components/TextArea'));
+ ko.components.register('SaveTrigger', require('Component/SaveTrigger'));
+ ko.components.register('Input', require('Component/Input'));
+ ko.components.register('Select', require('Component/Select'));
+ ko.components.register('TextArea', require('Component/TextArea'));
+ ko.components.register('Radio', require('Component/Radio'));
+
+ if (Settings.settingsGet('MaterialDesign'))
+ {
+ ko.components.register('Checkbox', require('Component/MaterialDesign/Checkbox'));
+ }
+ else
+ {
+ ko.components.register('Checkbox', require('Component/Checkbox'));
+ }
Utils.initOnStartOrLangChange(function () {
Utils.initNotificationLanguage();
diff --git a/dev/App/User.js b/dev/App/User.js
index aa461fc9e..e4845ff2a 100644
--- a/dev/App/User.js
+++ b/dev/App/User.js
@@ -1291,6 +1291,8 @@
{
this.setTitle(Utils.i18n('TITLES/LOADING'));
+//require.ensure([], function() { // require code splitting
+
self.folders(_.bind(function (bValue) {
kn.hideLoading();
@@ -1425,6 +1427,9 @@
}
}, self));
+
+//}); // require code splitting
+
}
else
{
diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js
index ba1bb635f..95dab0cf0 100644
--- a/dev/Common/Utils.js
+++ b/dev/Common/Utils.js
@@ -403,8 +403,9 @@
/**
* @param {Object} oElement
+ * @param {boolean=} bAnimate = false
*/
- Utils.i18nToNode = function (oElement)
+ Utils.i18nToNode = function (oElement, bAnimate)
{
_.defer(function () {
$('.i18n', oElement).each(function () {
@@ -439,6 +440,13 @@
}
}
});
+
+ if (bAnimate)
+ {
+ $('.i18n-animation.i18n', oElement).letterfx({
+ 'fx': 'fall fade', 'backwards': false, 'timing': 50, 'fx_duration': '50ms', 'letter_end': 'restore', 'element_end': 'restore'
+ });
+ }
});
};
@@ -448,7 +456,7 @@
{
Globals.oI18N = window['rainloopI18N'] || {};
- Utils.i18nToNode(Globals.$doc);
+ Utils.i18nToNode(Globals.$doc, true);
Globals.langChangeTrigger(!Globals.langChangeTrigger());
}
@@ -1618,8 +1626,9 @@
.replace(/>/g, '>').replace(/')
.replace(/[\s]*~~~\/blockquote~~~/g, '')
-// .replace(/[\-_~]{10,}/g, '
')
- .replace(/\n/g, '
');
+ .replace(/ /g, ' ')
+ .replace(/\n/g, '
')
+ ;
return bFindEmailAndLinks ? Utils.findEmailAndLinks(sPlain) : sPlain;
};
@@ -2015,7 +2024,8 @@
};
/**
- * @param {Object} oObject
+ * @param {mixed} mPropOrValue
+ * @param {mixed} mValue
*/
Utils.disposeOne = function (mPropOrValue, mValue)
{
diff --git a/dev/Component/AbstracCheckbox.js b/dev/Component/AbstracCheckbox.js
new file mode 100644
index 000000000..9be52944b
--- /dev/null
+++ b/dev/Component/AbstracCheckbox.js
@@ -0,0 +1,66 @@
+
+(function () {
+
+ 'use strict';
+
+ var
+ _ = require('_'),
+ ko = require('ko'),
+
+ Utils = require('Common/Utils'),
+
+ AbstractComponent = require('Component/Abstract')
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {Object} oParams
+ *
+ * @extends AbstractComponent
+ */
+ function AbstracCheckbox(oParams) {
+
+ AbstractComponent.call(this);
+
+ this.value = oParams.value;
+ if (Utils.isUnd(this.value) || !this.value.subscribe)
+ {
+ this.value = ko.observable(Utils.isUnd(this.value) ? false : !!this.value);
+ }
+
+ this.enable = oParams.enable;
+ if (Utils.isUnd(this.enable) || !this.enable.subscribe)
+ {
+ this.enable = ko.observable(Utils.isUnd(this.enable) ? true : !!this.enable);
+ }
+
+ this.disable = oParams.disable;
+ if (Utils.isUnd(this.disable) || !this.disable.subscribe)
+ {
+ this.disable = ko.observable(Utils.isUnd(this.disable) ? false : !!this.disable);
+ }
+
+ this.label = oParams.label || '';
+ this.inline = Utils.isUnd(oParams.inline) ? false : oParams.inline;
+
+ this.readOnly = Utils.isUnd(oParams.readOnly) ? false : !!oParams.readOnly;
+ this.inverted = Utils.isUnd(oParams.inverted) ? false : !!oParams.inverted;
+
+ this.labeled = !Utils.isUnd(oParams.label);
+ };
+
+ _.extend(AbstracCheckbox.prototype, AbstractComponent.prototype);
+
+ AbstracCheckbox.prototype.click = function() {
+ if (!this.readOnly && this.enable() && !this.disable())
+ {
+ this.value(!this.value());
+ }
+ };
+
+ AbstracCheckbox.componentExportHelper = AbstractComponent.componentExportHelper;
+
+ module.exports = AbstracCheckbox;
+
+}());
diff --git a/dev/Component/AbstracRadio.js b/dev/Component/AbstracRadio.js
new file mode 100644
index 000000000..4a7e3430d
--- /dev/null
+++ b/dev/Component/AbstracRadio.js
@@ -0,0 +1,65 @@
+
+(function () {
+
+ 'use strict';
+
+ var
+ _ = require('_'),
+ ko = require('ko'),
+
+ Utils = require('Common/Utils'),
+
+ AbstractComponent = require('Component/Abstract')
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {Object} oParams
+ *
+ * @extends AbstractComponent
+ */
+ function AbstracRadio(oParams) {
+
+ AbstractComponent.call(this);
+
+ this.values = ko.observableArray([]);
+
+ this.value = oParams.value;
+ if (Utils.isUnd(this.value) || !this.value.subscribe)
+ {
+ this.value = ko.observable('');
+ }
+
+ this.inline = Utils.isUnd(oParams.inline) ? false : oParams.inline;
+ this.readOnly = Utils.isUnd(oParams.readOnly) ? false : !!oParams.readOnly;
+
+ if (oParams.values)
+ {
+ var aValues = _.map(oParams.values, function (sLabel, sValue) {
+ return {
+ 'label': sLabel,
+ 'value': sValue
+ };
+ });
+
+ this.values(aValues);
+ }
+
+ this.click = _.bind(this.click, this);
+ };
+
+ AbstracRadio.prototype.click = function(oValue) {
+ if (!this.readOnly && oValue)
+ {
+ this.value(oValue.value);
+ }
+ };
+
+ _.extend(AbstracRadio.prototype, AbstractComponent.prototype);
+
+ AbstracRadio.componentExportHelper = AbstractComponent.componentExportHelper;
+
+ module.exports = AbstracRadio;
+
+}());
diff --git a/dev/Components/Abstract.js b/dev/Component/Abstract.js
similarity index 100%
rename from dev/Components/Abstract.js
rename to dev/Component/Abstract.js
diff --git a/dev/Components/AbstractInput.js b/dev/Component/AbstractInput.js
similarity index 94%
rename from dev/Components/AbstractInput.js
rename to dev/Component/AbstractInput.js
index a261db0d8..54c3b6f66 100644
--- a/dev/Components/AbstractInput.js
+++ b/dev/Component/AbstractInput.js
@@ -10,7 +10,7 @@
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
- AbstractComponent = require('Components/Abstract')
+ AbstractComponent = require('Component/Abstract')
;
/**
@@ -29,6 +29,7 @@
this.label = oParams.label || '';
this.enable = oParams.enable || true;
this.trigger = oParams.trigger && oParams.trigger.subscribe ? oParams.trigger : null;
+ this.placeholder = oParams.placeholder || '';
this.labeled = !Utils.isUnd(oParams.label);
this.triggered = !Utils.isUnd(oParams.trigger) && !!this.trigger;
diff --git a/dev/Component/Checkbox.js b/dev/Component/Checkbox.js
new file mode 100644
index 000000000..3846450c6
--- /dev/null
+++ b/dev/Component/Checkbox.js
@@ -0,0 +1,29 @@
+
+(function () {
+
+ 'use strict';
+
+ var
+ _ = require('_'),
+
+ AbstracCheckbox = require('Component/AbstracCheckbox')
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {Object} oParams
+ *
+ * @extends AbstracCheckbox
+ */
+ function CheckboxComponent(oParams) {
+
+ AbstracCheckbox.call(this, oParams);
+ };
+
+ _.extend(CheckboxComponent.prototype, AbstracCheckbox.prototype);
+
+ module.exports = AbstracCheckbox.componentExportHelper(
+ CheckboxComponent, 'CheckboxComponent');
+
+}());
diff --git a/dev/Components/Input.js b/dev/Component/Input.js
similarity index 51%
rename from dev/Components/Input.js
rename to dev/Component/Input.js
index c2aeda53f..bfc58263a 100644
--- a/dev/Components/Input.js
+++ b/dev/Component/Input.js
@@ -9,7 +9,7 @@
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
- AbstractInput = require('Components/AbstractInput')
+ AbstractInput = require('Component/AbstractInput')
;
/**
@@ -22,24 +22,6 @@
function InputComponent(oParams) {
AbstractInput.call(this, oParams);
-
- this.placeholder = oParams.placeholder || ''
- };
-
- InputComponent.prototype.setTriggerState = function (nValue)
- {
- switch (Utils.pInt(nValue))
- {
- case Enums.SaveSettingsStep.TrueResult:
- this.classForTrigger('success');
- break;
- case Enums.SaveSettingsStep.FalseResult:
- this.classForTrigger('error');
- break;
- default:
- this.classForTrigger('');
- break;
- }
};
_.extend(InputComponent.prototype, AbstractInput.prototype);
diff --git a/dev/Component/MaterialDesign/Checkbox.js b/dev/Component/MaterialDesign/Checkbox.js
new file mode 100644
index 000000000..486e0f858
--- /dev/null
+++ b/dev/Component/MaterialDesign/Checkbox.js
@@ -0,0 +1,66 @@
+
+(function () {
+
+ 'use strict';
+
+ var
+ _ = require('_'),
+ ko = require('ko'),
+
+ AbstracCheckbox = require('Component/AbstracCheckbox')
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {Object} oParams
+ *
+ * @extends AbstracCheckbox
+ */
+ function CheckboxMaterialDesignComponent(oParams) {
+
+ AbstracCheckbox.call(this, oParams);
+
+ this.animationBox = ko.observable(false).extend({'falseTimeout': 200});
+ this.animationCheckmark = ko.observable(false).extend({'falseTimeout': 200});
+
+ this.animationBoxSetTrue = _.bind(this.animationBoxSetTrue, this);
+ this.animationCheckmarkSetTrue = _.bind(this.animationCheckmarkSetTrue, this);
+
+ this.disposable.push(
+ this.value.subscribe(function (bValue) {
+ this.triggerAnimation(bValue);
+ }, this)
+ );
+ };
+
+ _.extend(CheckboxMaterialDesignComponent.prototype, AbstracCheckbox.prototype);
+
+ CheckboxMaterialDesignComponent.prototype.animationBoxSetTrue = function()
+ {
+ this.animationBox(true);
+ };
+
+ CheckboxMaterialDesignComponent.prototype.animationCheckmarkSetTrue = function()
+ {
+ this.animationCheckmark(true);
+ };
+
+ CheckboxMaterialDesignComponent.prototype.triggerAnimation = function(bBox)
+ {
+ if (bBox)
+ {
+ this.animationBoxSetTrue();
+ _.delay(this.animationCheckmarkSetTrue, 200);
+ }
+ else
+ {
+ this.animationCheckmarkSetTrue();
+ _.delay(this.animationBoxSetTrue, 200);
+ }
+ };
+
+ module.exports = AbstracCheckbox.componentExportHelper(
+ CheckboxMaterialDesignComponent, 'CheckboxMaterialDesignComponent');
+
+}());
diff --git a/dev/Component/Radio.js b/dev/Component/Radio.js
new file mode 100644
index 000000000..178bbc0d4
--- /dev/null
+++ b/dev/Component/Radio.js
@@ -0,0 +1,29 @@
+
+(function () {
+
+ 'use strict';
+
+ var
+ _ = require('_'),
+
+ AbstracRadio = require('Component/AbstracRadio')
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {Object} oParams
+ *
+ * @extends AbstracRadio
+ */
+ function RadioComponent(oParams) {
+
+ AbstracRadio.call(this, oParams);
+ };
+
+ _.extend(RadioComponent.prototype, AbstracRadio.prototype);
+
+ module.exports = AbstracRadio.componentExportHelper(
+ RadioComponent, 'RadioComponent');
+
+}());
diff --git a/dev/Components/SaveTrigger.js b/dev/Component/SaveTrigger.js
similarity index 96%
rename from dev/Components/SaveTrigger.js
rename to dev/Component/SaveTrigger.js
index a49777020..1cba4f40a 100644
--- a/dev/Components/SaveTrigger.js
+++ b/dev/Component/SaveTrigger.js
@@ -9,7 +9,7 @@
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
- AbstractComponent = require('Components/Abstract')
+ AbstractComponent = require('Component/Abstract')
;
/**
@@ -36,7 +36,7 @@
{
this.element.css('vertical-align', oParams.verticalAlign);
}
-
+
this.setState(this.value());
this.disposable.push(
diff --git a/dev/Components/Select.js b/dev/Component/Select.js
similarity index 82%
rename from dev/Components/Select.js
rename to dev/Component/Select.js
index 3f1750422..d9162b166 100644
--- a/dev/Components/Select.js
+++ b/dev/Component/Select.js
@@ -6,10 +6,9 @@
var
_ = require('_'),
- Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
- AbstractInput = require('Components/AbstractInput')
+ AbstractInput = require('Component/AbstractInput')
;
/**
@@ -27,6 +26,8 @@
this.optionsText = oParams.optionsText || null;
this.optionsValue = oParams.optionsValue || null;
+
+ this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
};
_.extend(SelectComponent.prototype, AbstractInput.prototype);
diff --git a/dev/Components/TextArea.js b/dev/Component/TextArea.js
similarity index 77%
rename from dev/Components/TextArea.js
rename to dev/Component/TextArea.js
index 8c21565a3..11cd1b0ba 100644
--- a/dev/Components/TextArea.js
+++ b/dev/Component/TextArea.js
@@ -6,10 +6,9 @@
var
_ = require('_'),
- Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
- AbstractInput = require('Components/AbstractInput')
+ AbstractInput = require('Component/AbstractInput')
;
/**
@@ -24,6 +23,7 @@
AbstractInput.call(this, oParams);
this.rows = oParams.rows || 5;
+ this.spellcheck = Utils.isUnd(oParams.spellcheck) ? false : !!oParams.spellcheck;
};
_.extend(TextAreaComponent.prototype, AbstractInput.prototype);
diff --git a/dev/Components/Checkbox.js b/dev/Components/Checkbox.js
deleted file mode 100644
index 1693a9948..000000000
--- a/dev/Components/Checkbox.js
+++ /dev/null
@@ -1,38 +0,0 @@
-
-(function () {
-
- 'use strict';
-
- var
- _ = require('_'),
- ko = require('ko'),
-
- AbstractComponent = require('Components/Abstract')
- ;
-
- /**
- * @constructor
- *
- * @param {Object} oParams
- *
- * @extends AbstractComponent
- */
- function CheckboxComponent(oParams) {
-
- AbstractComponent.call(this);
-
- this.value = oParams.value || ko.observable(false);
- this.label = oParams.label || '';
- this.inline = oParams.inline;
- };
-
- _.extend(CheckboxComponent.prototype, AbstractComponent.prototype);
-
- CheckboxComponent.prototype.toggle = function() {
- this.value(!this.value());
- };
-
- module.exports = AbstractComponent.componentExportHelper(
- CheckboxComponent, 'CheckboxComponent');
-
-}());
diff --git a/dev/Settings/Admin/Login.js b/dev/Settings/Admin/Login.js
index f3e6a0503..1cb499396 100644
--- a/dev/Settings/Admin/Login.js
+++ b/dev/Settings/Admin/Login.js
@@ -26,6 +26,8 @@
this.allowLanguagesOnLogin = Data.allowLanguagesOnLogin;
this.defaultDomainTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.dummy = ko.observable(false);
}
LoginAdminSetting.prototype.onBuild = function ()
diff --git a/dev/Styles/@Main.less b/dev/Styles/@Main.less
index c802056c7..ea0fd5ecb 100644
--- a/dev/Styles/@Main.less
+++ b/dev/Styles/@Main.less
@@ -52,6 +52,7 @@
@import "Main.less";
@import "Layout.less";
@import "Scroll.less";
+@import "Components.less";
@import "SystemDropDown.less";
@import "Login.less";
@import "Ask.less";
diff --git a/dev/Styles/Components.less b/dev/Styles/Components.less
new file mode 100644
index 000000000..8846c7e97
--- /dev/null
+++ b/dev/Styles/Components.less
@@ -0,0 +1,145 @@
+
+.checkbox-box-sizes() {
+ top: 0px;
+ left: 0px;
+ width: 18px;
+ height: 18px;
+ border: solid 2px #999;
+
+ transform: rotate(0deg);
+}
+
+.checkbox-mark-sizes() {
+/* top: -4px;
+ left: 6px;
+ width: 10px;
+ height: 21px;*/
+
+ top: -1px;
+ left: 5px;
+ width: 10px;
+ height: 18px;
+
+ border-right-width: 2px;
+ border-bottom-width: 2px;
+
+ transform: rotate(45deg);
+}
+
+.checkbox-result-sizes() {
+ top: 13px;
+ left: 5px;
+ width: 4px;
+ height: 4px;
+
+ transform: rotate(45deg);
+}
+
+.e-component {
+
+ &.e-checkbox {
+
+ cursor: pointer;
+
+ &.disabled {
+ cursor: default;
+ color: #999;
+ }
+ }
+
+ &.e-radio {
+
+ cursor: pointer;
+
+ &.disabled {
+ cursor: default;
+ color: #999;
+ }
+ }
+}
+
+.e-component.material-design {
+
+ &.e-checkbox {
+
+ .sub-checkbox-container {
+ display: inline-block;
+ position: relative;
+ transform: translateZ(0);
+ width: 18px;
+ height: 18px;
+ vertical-align: bottom;
+ margin-bottom: 3px;
+ margin-top: 1px;
+ }
+
+ .sub-label {
+ padding-left: 8px;
+ }
+
+ .sub-checkbox {
+ position: absolute;
+ box-sizing: border-box;
+
+ .checkbox-box-sizes();
+ }
+
+ &.disabled .sub-checkbox {
+ cursor: default;
+ color: #aaa;
+ }
+
+ .sub-checkbox.checked {
+ border-top: none;
+ border-left: none;
+ border-color: #0F9D58;
+
+ .checkbox-mark-sizes();
+ }
+
+ // animation
+ .sub-checkbox.checked {
+ &.box {
+ border: solid 2px;
+ animation: box-shrink 140ms ease-out forwards;
+ }
+ &.checkmark {
+ border-left: none;
+ border-top: none;
+ animation: checkmark-expand 140ms ease-out forwards;
+ }
+ }
+
+ .sub-checkbox.unchecked {
+ &.box {
+ animation: box-expand 140ms ease-out forwards;
+ }
+ &.checkmark {
+ border-left: none;
+ border-top: none;
+ transform: rotate(45deg);
+ animation: checkmark-shrink 140ms ease-out forwards;
+ }
+ }
+ }
+}
+
+@keyframes box-shrink {
+ 0% { .checkbox-box-sizes(); }
+ 100% { .checkbox-result-sizes(); }
+}
+
+@keyframes checkmark-expand {
+ 0% { .checkbox-result-sizes(); }
+ 100% { .checkbox-mark-sizes(); }
+}
+
+@keyframes checkmark-shrink {
+ 0% { .checkbox-mark-sizes(); }
+ 100% { .checkbox-result-sizes(); }
+}
+
+@keyframes box-expand {
+ 0% { .checkbox-result-sizes(); }
+ 100% { .checkbox-box-sizes(); }
+}
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
index 839131846..fd9caba16 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -95,6 +95,7 @@ cfg.paths.css = {
'vendors/jquery-nanoscroller/nanoscroller.css',
'vendors/jquery-magnific-popup/magnific-popup.css',
'vendors/jquery-magnific-popup/magnific-popup-animations.css',
+ 'vendors/jquery-letterfx/jquery-letterfx.min.css',
'vendors/simple-pace/styles.css',
'vendors/inputosaurus/inputosaurus.css',
'vendors/flags/flags-fixed.css',
@@ -146,6 +147,7 @@ cfg.paths.js = {
'vendors/jquery-lazyload/jquery.lazyload.min.js',
'vendors/jquery-nanoscroller/jquery.nanoscroller-0.7.min.js',
'vendors/jquery-wakeup/jquery.wakeup.min.js',
+ 'vendors/jquery-letterfx/jquery-letterfx.min.js',
'vendors/inputosaurus/inputosaurus.min.js',
'vendors/moment/min/moment.min.js ',
'vendors/routes/signals.min.js',
@@ -194,7 +196,7 @@ gulp.task('css:main', ['less:main'], function() {
return gulp.src(cfg.paths.css.main.src)
.pipe(concat(cfg.paths.css.main.name))
.pipe(autoprefixer('last 3 versions', '> 1%', 'ie 9', 'Firefox ESR', 'Opera 12.1'))
- .pipe(csscomb())
+// .pipe(csscomb())
// .pipe(csslint())
// .pipe(csslint.reporter())
.pipe(eol('\n', true))
diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php
index 5eb1220e8..d731f6a7e 100644
--- a/rainloop/v/0.0.0/app/src/RainLoop/Actions.php
+++ b/rainloop/v/0.0.0/app/src/RainLoop/Actions.php
@@ -1020,11 +1020,14 @@ class Actions
'UseImapThread' => (bool) $oConfig->Get('labs', 'use_imap_thread', false),
'UseImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true),
'AllowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false),
+ 'MaterialDesign' => (bool) $oConfig->Get('labs', 'use_material_design', true),
'PremType' => $this->PremType(),
'Capa' => array(),
'Plugins' => array()
);
+// $aResult['MaterialDesign'] = false;
+
if ($aResult['UseRsaEncryption'] &&
\file_exists(APP_PRIVATE_DATA.'rsa/public') && \file_exists(APP_PRIVATE_DATA.'rsa/private'))
{
diff --git a/rainloop/v/0.0.0/app/src/RainLoop/Service.php b/rainloop/v/0.0.0/app/src/RainLoop/Service.php
index 380a9a5b6..944d7c3de 100644
--- a/rainloop/v/0.0.0/app/src/RainLoop/Service.php
+++ b/rainloop/v/0.0.0/app/src/RainLoop/Service.php
@@ -164,6 +164,7 @@ class Service
if (0 === \strlen($sResult))
{
+// $aTemplateParameters['{{BaseTemplates}}'] = $this->oServiceActions->compileTemplates($bAdmin, false);
$sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Index.html'), $aTemplateParameters);
$sResult = \RainLoop\Utils::ClearHtmlOutput($sResult);
diff --git a/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php b/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php
index 34d211c1e..6d8a86847 100644
--- a/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php
+++ b/rainloop/v/0.0.0/app/src/RainLoop/ServiceActions.php
@@ -1066,10 +1066,11 @@ class ServiceActions
/**
* @param bool $bAdmin = false
+ * @param bool $bJsOutput = true
*
* @return string
*/
- private function compileTemplates($bAdmin = false)
+ public function compileTemplates($bAdmin = false, $bJsOutput = true)
{
$sHtml =
\RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views/Components', $this->oActions, 'Component').
@@ -1077,7 +1078,7 @@ class ServiceActions
\RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views/Common', $this->oActions).
$this->oActions->Plugins()->CompileTemplate($bAdmin);
- return 'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml), $this->Logger()).';';
+ return $bJsOutput ? 'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml), $this->Logger()).';' : $sHtml;
}
/**
diff --git a/rainloop/v/0.0.0/app/templates/Index.html b/rainloop/v/0.0.0/app/templates/Index.html
index a44e38988..0395264aa 100644
--- a/rainloop/v/0.0.0/app/templates/Index.html
+++ b/rainloop/v/0.0.0/app/templates/Index.html
@@ -45,20 +45,21 @@
An Error occurred,
diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html
index c63ce404f..f245ecf6e 100644
--- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html
+++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminSettingsPluginProperty.html
@@ -12,18 +12,19 @@
data-bind="value: value, attr: {placeholder: placeholder}" />
-
+
-
+
diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html b/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html
index e4e5e0aa8..140f2cb43 100644
--- a/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html
+++ b/rainloop/v/0.0.0/app/templates/Views/Admin/PopupsDomain.html
@@ -48,21 +48,26 @@
-
+
-
+
+
+ (user@domain.com → user)
-
-
+
+
+ (user@domain.com → user)
+
+
@@ -20,11 +22,13 @@
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/SettingsGeneral.html b/rainloop/v/0.0.0/app/templates/Views/User/SettingsGeneral.html
index 190906b63..24f39a517 100644
--- a/rainloop/v/0.0.0/app/templates/Views/User/SettingsGeneral.html
+++ b/rainloop/v/0.0.0/app/templates/Views/User/SettingsGeneral.html
@@ -1,7 +1,7 @@
diff --git a/rainloop/v/0.0.0/app/templates/Views/User/SettingsSecurity.html b/rainloop/v/0.0.0/app/templates/Views/User/SettingsSecurity.html
index ce1a93e41..11368cfca 100644
--- a/rainloop/v/0.0.0/app/templates/Views/User/SettingsSecurity.html
+++ b/rainloop/v/0.0.0/app/templates/Views/User/SettingsSecurity.html
@@ -5,11 +5,13 @@
diff --git a/vendors/jquery-letterfx/LICENSE.md b/vendors/jquery-letterfx/LICENSE.md
new file mode 100644
index 000000000..ea208db2d
--- /dev/null
+++ b/vendors/jquery-letterfx/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Jared Anderson, dba tuxsudo.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendors/jquery-letterfx/README.md b/vendors/jquery-letterfx/README.md
new file mode 100644
index 000000000..e720c041f
--- /dev/null
+++ b/vendors/jquery-letterfx/README.md
@@ -0,0 +1,11 @@
+LetterFX
+========
+
+A jQuery plugin to apply animated, visual effects to letters, words or other text patterns.
+
+example usage:
+
+ $(element).letterfx({"fx":"fly-right fly-bottom spin"})
+
+
+[More Info](http://tuxsudo.com/code/project/letterfx)
diff --git a/vendors/jquery-letterfx/jquery-letterfx.css b/vendors/jquery-letterfx/jquery-letterfx.css
new file mode 100644
index 000000000..eef6cd71d
--- /dev/null
+++ b/vendors/jquery-letterfx/jquery-letterfx.css
@@ -0,0 +1,111 @@
+.letterfx-container{}
+
+.letterfx{
+ display:inline-block;
+ margin:0;
+ padding:0;
+ transition: all 1s; -ms-transition: all 1s; -webkit-transition: all 1s;
+}
+
+/* Spin FX */
+.letterfx-spin-before{
+ transform:rotate(3600deg); -ms-transform:rotate(3600deg); -webkit-transform:rotate(3600deg);
+}
+
+.letterfx-spin-after{
+ transform:none;
+}
+
+/* Fade FX */
+.letterfx-fade-before{
+ opacity: 0;
+}
+
+
+/* Grow FX */
+.letterfx-grow-before{
+ transform:scale(0,0); -ms-transform:scale(0,0); -webkit-transform:scale(0,0);
+}
+
+.letterfx-grow-after{
+ transform:none;
+}
+
+
+/* Smear FX */
+.letterfx-smear-before{
+ color: transparent;
+ text-shadow:-1px -1px 25px transparent;
+}
+
+.letterfx-smear-after{
+ color:inherit;
+ text-shadow:0 0 #333;
+
+}
+
+/* Fall FX */
+.letterfx-fall-before
+{
+ visibility: hidden;
+ transform:scale(3,3); -ms-transform:scale(3,3); -webkit-transform:scale(3,3);
+}
+
+.letterfx-fall-after{
+ transform:scale(1,1); -ms-transform:scale(1,1); -webkit-transform:scale(1,1);
+ text-shadow:0;
+}
+
+/* Swirl FX */
+.letterfx-swirl-before
+{
+ visibility: hidden;
+ transform:scale(3,3) rotate(3600deg); -ms-transform:scale(3,3) rotate(3600deg); -webkit-transform:scale(3,3) rotate(3600deg);
+}
+
+.letterfx-swirl-after{
+ transform:none
+ text-shadow:0;
+}
+
+
+/* Wave FX */
+.letterfx-wave-container .letterfx
+{
+ position:relative;
+}
+
+.letterfx-wave-before
+{
+ bottom:0;
+}
+
+.letterfx-wave-after{
+ bottom:15px;
+}
+
+
+
+/* FLY FX */
+.letterfx-fly-left-container .letterfx,
+.letterfx-fly-right-container .letterfx,
+.letterfx-fly-top-container .letterfx,
+.letterfx-fly-bottom-container .letterfx
+{
+ position:relative;
+}
+
+.letterfx-fly-left-before{ left:-50em; }
+.letterfx-fly-left-after{ left:0; }
+
+.letterfx-fly-right-before{ right:-50em; }
+.letterfx-fly-right-after{ right:0; }
+
+.letterfx-fly-top-before{ top:-20em; }
+.letterfx-fly-top-after{ top:0; }
+
+.letterfx-fly-bottom-before{ bottom:-20em; }
+.letterfx-fly-bottom-after{ bottom:0; }
+
+
+
diff --git a/vendors/jquery-letterfx/jquery-letterfx.js b/vendors/jquery-letterfx/jquery-letterfx.js
new file mode 100644
index 000000000..0370399af
--- /dev/null
+++ b/vendors/jquery-letterfx/jquery-letterfx.js
@@ -0,0 +1,332 @@
+(function ($) {
+
+ "use strict";
+
+ var LetterFx = function (element, options) {
+
+ this.options = $.extend({}, $.fn.letterfx.defaults, options);
+
+ this.num_completed_fx = 0;
+
+ this.is_done = false;
+
+ this.monitor_timer = null;
+
+ this.killswitch=null;
+
+ this.$element = $(element);
+
+ if(this.options.restore)
+ this.original_html = this.$element.html();
+
+ this.init();
+
+ }
+
+ LetterFx.prototype.init = function(){
+
+ this.new_html = this.$element.text().replace( this.options.pattern, this.options.replacement );
+
+ this.$element.addClass(this.options.css.element.base).addClass( this.options.css.element.before );
+
+ this.$element.html( this.new_html );
+
+ this.$letters = this.$element.find(this.options.selector);
+
+ this.$letters
+ .css('transition-duration', this.options.fx_duration)
+ .addClass(this.options.css.letters.base)
+ .addClass(this.options.css.letters.before);
+
+ this.bindLetterFxEnd();
+
+ this.num_letters = this.$letters.length;
+
+
+ this.fx();
+
+ return this;
+ }
+
+ LetterFx.prototype.bindLetterFxEnd = function(){
+ var options = this.options;
+ var lfx = this;
+ this.$letters.bind("transitionend", function(){
+ options.onLetterComplete( $(this), lfx.$element, lfx );
+ lfx.notifyFXEnd( );
+
+ switch(options.letter_end){
+ case "destroy":
+ $(this).remove();
+ break;
+
+ case "rewind":
+ lfx.applyLetterFx( $(this), options.timing, options.css.letters.after, options.css.letters.before );
+ break;
+
+ case "stay":
+ break;
+
+ // restore
+ default:
+ $(this).replaceWith( $(this).text() );
+ }
+
+ });
+ return lfx;
+ }
+
+ LetterFx.prototype.terminate=function(){
+ this.is_done = true;
+ this.options.onElementComplete(this.$element, this);
+
+ clearTimeout(this.killswitch);
+
+ switch(this.options.element_end){
+ case "destroy":
+ this.$element.remove();
+ break;
+
+ case "stay":
+ break;
+
+ // restore
+ default:
+ this.$element.html( this.original_html );
+ this.$element.removeClass( this.options.css.element.base ).removeClass(this.options.css.element.after);
+ break;
+ }
+
+ }
+
+ LetterFx.prototype.notifyFXEnd=function(){
+ clearTimeout(this.monitor_timer);
+ this.num_completed_fx++;
+
+ var lfx = this;
+ this.monitor_timer = setTimeout(
+ function(){
+ if(lfx.num_completed_fx % lfx.num_letters===0){
+ lfx.terminate();
+ }
+ },
+ Math.max(this.options.timing+10, 50)
+ );
+
+ return this;
+ }
+
+ LetterFx.prototype.startKillWatch = function(){
+ var fx_duration = this.options.fx_duration.match(/\d+s/) ? parseInt(this.options.fx_duration) : 1;
+ var time = Math.ceil(1.5 * this.num_letters * this.options.timing * fx_duration );
+ var lfx = this;
+ this.killswitch = window.setTimeout(function(){
+ if(!lfx.isDone()){
+ lfx.terminate()
+ }
+ }, time)
+ }
+
+ LetterFx.prototype.fx = function(){
+ var lfx = this;
+ this.startKillWatch();
+ this.$element.removeClass(this.options.css.element.before).addClass(this.options.css.element.after);
+ var $letters = this.options.sort(this.$letters);
+ var options = this.options;
+
+
+
+ $letters.each(
+ function(i, letter){
+ lfx.applyLetterFx( $(letter), (i+1)*options.timing, options.css.letters.before, options.css.letters.after);
+ }
+ );
+ return this;
+ }
+
+ LetterFx.prototype.applyLetterFx = function($letter, timing, css_before, css_after){
+ var options = this.options;
+
+ window.setTimeout(
+ function(){
+ $letter.removeClass(css_before).addClass(css_after);
+ },
+ timing
+ );
+ return this
+ }
+
+ LetterFx.prototype.isDone = function(){
+ return this.is_done;
+ }
+
+
+
+
+ var LetterFxConfig = function(conf){
+ this.config = $.extend({}, $.fn.letterfx.defaults, conf);
+ this.buildCss(this.config.backwards);
+
+ // check & change to word pattern
+ if(this.config.words)
+ this.config.pattern=/(\S+)/g;
+
+
+ }
+
+
+ LetterFxConfig.prototype.buildCss = function(flip){
+ var options = this.config;
+ var before = flip ? 'after' : 'before';
+ var after = flip ? 'before' : 'after';
+
+
+ var css = { element:{}, letters:{} };
+
+ css.element.base=options.element_class+ "-container " + options.fx.replace(/(\S+)/g, options.element_class + "-$1-container");
+ css.element[before]=options.fx.replace(/(\S+)/g, options.element_class + "-$1-before-container");
+ css.element[after]=options.fx.replace(/(\S+)/g, options.element_class + "-$1-after-container");
+
+ css.letters.base = options.element_class;
+ css.letters[before] = options.fx.replace(/(\S+)/g, options.element_class + "-$1-before")
+ css.letters[after] = options.fx.replace(/(\S+)/g, options.element_class + "-$1-after")
+
+ this.config = $.extend( options, {'css':css} );
+ }
+
+ LetterFxConfig.prototype.getConfig = function(){
+ return this.config;
+ }
+
+ LetterFxConfig.parse=function(config){
+ return (new LetterFxConfig( config )).getConfig();
+ }
+
+
+
+
+$.fn.letterfx=function(config){
+
+ config = LetterFxConfig.parse( config );
+
+ return $(this).each(function(){
+ var $element = $(this);
+ if (! $element.data('letterfx-obj') || $element.data('letterfx-obj').isDone() ){
+ $element.data('letterfx-obj', new LetterFx( $element, config ) );
+ }
+ });
+
+};
+
+$.fn.letterfx.sort={
+ random:function(array){
+ var currentIndex = array.length, temporaryValue, randomIndex;
+
+ // While there remain elements to shuffle...
+ while (0 !== currentIndex) {
+
+ // Pick a remaining element...
+ randomIndex = Math.floor(Math.random() * currentIndex);
+ currentIndex -= 1;
+
+ // And swap it with the current element.
+ temporaryValue = array[currentIndex];
+ array[currentIndex] = array[randomIndex];
+ array[randomIndex] = temporaryValue;
+ }
+
+ return array;
+ },
+ reverse:function($array){
+ return $array.toArray().reverse();
+ }
+}
+
+$.fn.letterfx.patterns={
+ letters:/(\S)/gi
+}
+
+// Plugin Configurables
+$.fn.letterfx.defaults = {
+
+ // Default fx
+ fx:'spin fly-top',
+
+ // defaults to selecting all characters
+ pattern:/(\S)/gi,
+
+ // switch from letter FX to word FX.
+ word:false,
+
+ // fx, like fly or fade, can happen in (eg fade-in) or out (eg fade-out).
+ // The default is in; change backwards to true to reverse the order of the effects.
+ backwards:false,
+
+ // defaults to injecting spans, can be any inline element
+ replacement:"$1",
+
+ //selector -- should match replacement above
+ selector:'span',
+
+ // letter fx start sequentially: letters start their fx one after another.
+ // this sets time between the letters
+ timing:50,
+
+ //duration of each fx
+ // options the same as css property for transition-duration ("1ms", "1s", etc)
+ fx_duration:"1s",
+
+
+ // stabile dimensions
+ // stabilize:true,
+
+ // sort callback for custom sorting elements
+ sort:function($letters){ return $letters; },
+
+
+ // Callback when letter is done animating. Runs after each letter
+ onLetterComplete:function($letter, $element, LetterFXObj){},
+
+ // Runs after all are done.
+ onElementComplete:function($element, LetterFXObj){},
+
+
+ // what to do when a letter completes its animation.
+ // options include
+ // restore: return letter to plain text (default)
+ // destroy: get rid of the letter.
+ // stay: leave it as is.
+ // rewind: reverse the animation
+ letter_end:"restore",
+
+
+ // what to do when the entire element has completed all its letter effects
+ // options include:
+ // restore: return element to its pre-fx state (default)
+ // stay: do nothing
+ // destroy: get rid of the element... FOREVER
+ element_end:"restore",
+
+ // Restore container element back to original state.
+ // options: true, false, "element" ("element" waits until all letters complete fx before restoring)
+ restore:true,
+
+ // destroy element/letters after fx, useful on {out:true} fx
+ // options: true, false, "letters" ("letters" destroys each letter after fx, but elements original content may be restored after all letters complete fx)
+ destroy:false,
+
+ // default class for injected elements
+ element_class:'letterfx',
+
+ // placeholder values that are calculated on launch
+ css:{
+ element:{ base:'', before:'', after:''},
+ letters:{ base:'', before:'', after:''}
+ }
+
+
+
+};
+
+}(jQuery));
+
diff --git a/vendors/jquery-letterfx/jquery-letterfx.min.css b/vendors/jquery-letterfx/jquery-letterfx.min.css
new file mode 100644
index 000000000..2a0f6877f
--- /dev/null
+++ b/vendors/jquery-letterfx/jquery-letterfx.min.css
@@ -0,0 +1 @@
+.letterfx{display:inline-block;margin:0;padding:0;transition:all 1s;-ms-transition:all 1s;-webkit-transition:all 1s}.letterfx-spin-before{transform:rotate(3600deg);-ms-transform:rotate(3600deg);-webkit-transform:rotate(3600deg)}.letterfx-spin-after{transform:none}.letterfx-fade-before{opacity:0}.letterfx-grow-before{transform:scale(0,0);-ms-transform:scale(0,0);-webkit-transform:scale(0,0)}.letterfx-grow-after{transform:none}.letterfx-smear-before{color:transparent;text-shadow:-1px -1px 25px transparent}.letterfx-smear-after{color:inherit;text-shadow:0 0 #333}.letterfx-fall-before{visibility:hidden;transform:scale(3,3);-ms-transform:scale(3,3);-webkit-transform:scale(3,3)}.letterfx-fall-after{transform:scale(1,1);-ms-transform:scale(1,1);-webkit-transform:scale(1,1);text-shadow:0}.letterfx-swirl-before{visibility:hidden;transform:scale(3,3) rotate(3600deg);-ms-transform:scale(3,3) rotate(3600deg);-webkit-transform:scale(3,3) rotate(3600deg)}.letterfx-swirl-after{transform:none text-shadow:0}.letterfx-wave-container .letterfx{position:relative}.letterfx-wave-before{bottom:0}.letterfx-wave-after{bottom:15px}.letterfx-fly-left-container .letterfx,.letterfx-fly-right-container .letterfx,.letterfx-fly-top-container .letterfx,.letterfx-fly-bottom-container .letterfx{position:relative}.letterfx-fly-left-before{left:-50em}.letterfx-fly-left-after{left:0}.letterfx-fly-right-before{right:-50em}.letterfx-fly-right-after{right:0}.letterfx-fly-top-before{top:-20em}.letterfx-fly-top-after{top:0}.letterfx-fly-bottom-before{bottom:-20em}.letterfx-fly-bottom-after{bottom:0}
\ No newline at end of file
diff --git a/vendors/jquery-letterfx/jquery-letterfx.min.js b/vendors/jquery-letterfx/jquery-letterfx.min.js
new file mode 100644
index 000000000..8aeb86b18
--- /dev/null
+++ b/vendors/jquery-letterfx/jquery-letterfx.min.js
@@ -0,0 +1 @@
+(function($){"use strict";var LetterFx=function(element,options){this.options=$.extend({},$.fn.letterfx.defaults,options);this.num_completed_fx=0;this.is_done=false;this.monitor_timer=null;this.killswitch=null;this.$element=$(element);if(this.options.restore)this.original_html=this.$element.html();this.init()};LetterFx.prototype.init=function(){this.new_html=this.$element.text().replace(this.options.pattern,this.options.replacement);this.$element.addClass(this.options.css.element.base).addClass(this.options.css.element.before);this.$element.html(this.new_html);this.$letters=this.$element.find(this.options.selector);this.$letters.css("transition-duration",this.options.fx_duration).addClass(this.options.css.letters.base).addClass(this.options.css.letters.before);this.bindLetterFxEnd();this.num_letters=this.$letters.length;this.fx();return this};LetterFx.prototype.bindLetterFxEnd=function(){var options=this.options;var lfx=this;this.$letters.bind("transitionend",function(){options.onLetterComplete($(this),lfx.$element,lfx);lfx.notifyFXEnd();switch(options.letter_end){case"destroy":$(this).remove();break;case"rewind":lfx.applyLetterFx($(this),options.timing,options.css.letters.after,options.css.letters.before);break;case"stay":break;default:$(this).replaceWith($(this).text())}});return lfx};LetterFx.prototype.terminate=function(){this.is_done=true;this.options.onElementComplete(this.$element,this);clearTimeout(this.killswitch);switch(this.options.element_end){case"destroy":this.$element.remove();break;case"stay":break;default:this.$element.html(this.original_html);this.$element.removeClass(this.options.css.element.base).removeClass(this.options.css.element.after);break}};LetterFx.prototype.notifyFXEnd=function(){clearTimeout(this.monitor_timer);this.num_completed_fx++;var lfx=this;this.monitor_timer=setTimeout(function(){if(lfx.num_completed_fx%lfx.num_letters===0){lfx.terminate()}},Math.max(this.options.timing+10,50));return this};LetterFx.prototype.startKillWatch=function(){var fx_duration=this.options.fx_duration.match(/\d+s/)?parseInt(this.options.fx_duration):1;var time=Math.ceil(1.5*this.num_letters*this.options.timing*fx_duration);var lfx=this;this.killswitch=window.setTimeout(function(){if(!lfx.isDone()){lfx.terminate()}},time)};LetterFx.prototype.fx=function(){var lfx=this;this.startKillWatch();this.$element.removeClass(this.options.css.element.before).addClass(this.options.css.element.after);var $letters=this.options.sort(this.$letters);var options=this.options;$letters.each(function(i,letter){lfx.applyLetterFx($(letter),(i+1)*options.timing,options.css.letters.before,options.css.letters.after)});return this};LetterFx.prototype.applyLetterFx=function($letter,timing,css_before,css_after){var options=this.options;window.setTimeout(function(){$letter.removeClass(css_before).addClass(css_after)},timing);return this};LetterFx.prototype.isDone=function(){return this.is_done};var LetterFxConfig=function(conf){this.config=$.extend({},$.fn.letterfx.defaults,conf);this.buildCss(this.config.backwards);if(this.config.words)this.config.pattern=/(\S+)/g};LetterFxConfig.prototype.buildCss=function(flip){var options=this.config;var before=flip?"after":"before";var after=flip?"before":"after";var css={element:{},letters:{}};css.element.base=options.element_class+"-container "+options.fx.replace(/(\S+)/g,options.element_class+"-$1-container");css.element[before]=options.fx.replace(/(\S+)/g,options.element_class+"-$1-before-container");css.element[after]=options.fx.replace(/(\S+)/g,options.element_class+"-$1-after-container");css.letters.base=options.element_class;css.letters[before]=options.fx.replace(/(\S+)/g,options.element_class+"-$1-before");css.letters[after]=options.fx.replace(/(\S+)/g,options.element_class+"-$1-after");this.config=$.extend(options,{css:css})};LetterFxConfig.prototype.getConfig=function(){return this.config};LetterFxConfig.parse=function(config){return new LetterFxConfig(config).getConfig()};$.fn.letterfx=function(config){config=LetterFxConfig.parse(config);return $(this).each(function(){var $element=$(this);if(!$element.data("letterfx-obj")||$element.data("letterfx-obj").isDone()){$element.data("letterfx-obj",new LetterFx($element,config))}})};$.fn.letterfx.sort={random:function(array){var currentIndex=array.length,temporaryValue,randomIndex;while(0!==currentIndex){randomIndex=Math.floor(Math.random()*currentIndex);currentIndex-=1;temporaryValue=array[currentIndex];array[currentIndex]=array[randomIndex];array[randomIndex]=temporaryValue}return array},reverse:function($array){return $array.toArray().reverse()}};$.fn.letterfx.patterns={letters:/(\S)/gi};$.fn.letterfx.defaults={fx:"spin fly-top",pattern:/(\S)/gi,word:false,backwards:false,replacement:"$1",selector:"span",timing:50,fx_duration:"1s",sort:function($letters){return $letters},onLetterComplete:function($letter,$element,LetterFXObj){},onElementComplete:function($element,LetterFXObj){},letter_end:"restore",element_end:"restore",restore:true,destroy:false,element_class:"letterfx",css:{element:{base:"",before:"",after:""},letters:{base:"",before:"",after:""}}}})(jQuery);
\ No newline at end of file