Added knockoutjs components (step 1)

This commit is contained in:
RainLoop Team 2014-10-29 02:05:50 +04:00
parent e6438233cf
commit c2b7632c13
35 changed files with 779 additions and 187 deletions

View file

@ -211,7 +211,16 @@
{
Events.pub('rl.bootstart');
var ssm = require('ssm');
var
ssm = require('ssm'),
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'));
Utils.initOnStartOrLangChange(function () {
Utils.initNotificationLanguage();

View file

@ -1355,17 +1355,38 @@
iContactsSyncInterval = 5 <= iContactsSyncInterval ? iContactsSyncInterval : 20;
iContactsSyncInterval = 320 >= iContactsSyncInterval ? iContactsSyncInterval : 320;
_.delay(function () {
self.contactsSync();
}, 10000);
_.delay(function () {
self.folderInformationMultiply(true);
}, 2000);
window.setInterval(function () {
self.contactsSync();
}, iContactsSyncInterval * 60000 + 5000);
if (Settings.capa(Enums.Capa.AdditionalAccounts) || Settings.capa(Enums.Capa.AdditionalIdentities))
{
self.accountsAndIdentities();
}
_.delay(function () {
self.contactsSync();
var sF = Data.currentFolderFullNameRaw();
if (Cache.getFolderInboxName() !== sF)
{
self.folderInformation(sF);
}
}, 1000);
_.delay(function () {
self.quota();
}, 5000);
_.delay(function () {
self.folderInformationMultiply(true);
}, 500);
Remote.appDelayStart(Utils.emptyFunction);
}, 35000);
Plugins.runHook('rl-start-user-screens');
Events.pub('rl.bootstart-user-screens');

View file

@ -1982,6 +1982,9 @@
Utils.reloadLanguage = function (sLanguage, fDone, fFail)
{
var iStart = Utils.microtime();
Globals.$html.addClass('rl-changing-language');
$.ajax({
'url': require('Common/Links').langLink(sLanguage),
'dataType': 'script',
@ -1992,6 +1995,7 @@
_.delay(function () {
Utils.i18nReload();
(fDone || Utils.emptyFunction)();
Globals.$html.removeClass('rl-changing-language');
}, 500 < Utils.microtime() - iStart ? 1 : 500);
})
;

View file

@ -0,0 +1,72 @@
(function () {
'use strict';
var
_ = require('_'),
ko = require('ko'),
Utils = require('Common/Utils')
;
/**
* @constructor
*/
function AbstractComponent()
{
this.disposable = [];
}
/**
* @type {Array}
*/
AbstractComponent.prototype.disposable = [];
AbstractComponent.prototype.dispose = function ()
{
_.each(this.disposable, function (fFuncToDispose) {
if (fFuncToDispose && fFuncToDispose.dispose)
{
fFuncToDispose.dispose();
}
});
};
/**
* @param {AbstractComponent} fClassObject
* @param {string} sTemplateID
* @return {Object}
*/
AbstractComponent.componentExportHelper = function (fClassObject, sTemplateID) {
return {
viewModel: {
createViewModel: function(oParams, oCmponentInfo) {
oParams = oParams || {};
oParams.element = null;
if (oCmponentInfo.element)
{
oParams.element = $(oCmponentInfo.element);
Utils.i18nToNode(oParams.element);
if (!Utils.isUnd(oParams.inline) && ko.unwrap(oParams.inline))
{
oParams.element.css('display', 'inline-block');
}
}
return new fClassObject(oParams);
}
},
template: {
element: sTemplateID
}
};
};
module.exports = AbstractComponent;
}());

View file

@ -0,0 +1,89 @@
(function () {
'use strict';
var
_ = require('_'),
ko = require('ko'),
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
AbstractComponent = require('Components/Abstract')
;
/**
* @constructor
*
* @param {Object} oParams
*
* @extends AbstractComponent
*/
function AbstractInput(oParams) {
AbstractComponent.call(this);
this.value = oParams.value || '';
this.size = oParams.size || 0;
this.label = oParams.label || '';
this.enable = oParams.enable || true;
this.trigger = oParams.trigger && oParams.trigger.subscribe ? oParams.trigger : null;
this.labeled = !Utils.isUnd(oParams.label);
this.triggered = !Utils.isUnd(oParams.trigger) && !!this.trigger;
this.classForTrigger = ko.observable('');
this.className = ko.computed(function () {
var
iSize = ko.unwrap(this.size),
sSuffixValue = this.trigger ?
' ' + Utils.trim('settings-saved-trigger-input ' + this.classForTrigger()) : ''
;
return (0 < iSize ? 'span' + iSize : '') + sSuffixValue;
}, this);
if (!Utils.isUnd(oParams.width) && oParams.element)
{
oParams.element.find('input,select,textarea').css('width', oParams.width);
}
this.disposable.push(this.className);
if (this.trigger)
{
this.setTriggerState(this.trigger());
this.disposable.push(
this.trigger.subscribe(this.setTriggerState, this)
);
}
};
AbstractInput.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(AbstractInput.prototype, AbstractComponent.prototype);
AbstractInput.componentExportHelper = AbstractComponent.componentExportHelper;
module.exports = AbstractInput;
}());

View file

@ -0,0 +1,38 @@
(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');
}());

50
dev/Components/Input.js Normal file
View file

@ -0,0 +1,50 @@
(function () {
'use strict';
var
_ = require('_'),
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
AbstractInput = require('Components/AbstractInput')
;
/**
* @constructor
*
* @param {Object} oParams
*
* @extends AbstractInput
*/
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);
module.exports = AbstractInput.componentExportHelper(
InputComponent, 'InputComponent');
}());

View file

@ -0,0 +1,94 @@
(function () {
'use strict';
var
_ = require('_'),
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
AbstractComponent = require('Components/Abstract')
;
/**
* @constructor
*
* @param {Object} oParams
*
* @extends AbstractComponent
*/
function SaveTriggerComponent(oParams) {
AbstractComponent.call(this);
this.element = oParams.element || null;
this.value = oParams.value && oParams.value.subscribe ? oParams.value : null;
if (this.element)
{
if (this.value)
{
this.element.css('display', 'inline-block');
if (oParams.verticalAlign)
{
this.element.css('vertical-align', oParams.verticalAlign);
}
this.setState(this.value());
this.disposable.push(
this.value.subscribe(this.setState, this)
);
}
else
{
this.element.hide();
}
}
};
SaveTriggerComponent.prototype.setState = function (nValue)
{
switch (Utils.pInt(nValue))
{
case Enums.SaveSettingsStep.TrueResult:
this.element
.find('.animated,.error').hide().removeClass('visible')
.end()
.find('.success').show().addClass('visible')
;
break;
case Enums.SaveSettingsStep.FalseResult:
this.element
.find('.animated,.success').hide().removeClass('visible')
.end()
.find('.error').show().addClass('visible')
;
break;
case Enums.SaveSettingsStep.Animate:
this.element
.find('.error,.success').hide().removeClass('visible')
.end()
.find('.animated').show().addClass('visible')
;
break;
case Enums.SaveSettingsStep.Idle:
default:
this.element
.find('.animated').hide()
.end()
.find('.error,.success').removeClass('visible')
;
break;
}
};
_.extend(SaveTriggerComponent.prototype, AbstractComponent.prototype);
module.exports = AbstractComponent.componentExportHelper(
SaveTriggerComponent, 'SaveTriggerComponent');
}());

37
dev/Components/Select.js Normal file
View file

@ -0,0 +1,37 @@
(function () {
'use strict';
var
_ = require('_'),
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
AbstractInput = require('Components/AbstractInput')
;
/**
* @constructor
*
* @param {Object} oParams
*
* @extends AbstractInput
*/
function SelectComponent(oParams) {
AbstractInput.call(this, oParams);
this.options = oParams.options || '';
this.optionsText = oParams.optionsText || null;
this.optionsValue = oParams.optionsValue || null;
};
_.extend(SelectComponent.prototype, AbstractInput.prototype);
module.exports = AbstractInput.componentExportHelper(
SelectComponent, 'SelectComponent');
}());

View file

@ -0,0 +1,34 @@
(function () {
'use strict';
var
_ = require('_'),
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
AbstractInput = require('Components/AbstractInput')
;
/**
* @constructor
*
* @param {Object} oParams
*
* @extends AbstractInput
*/
function TextAreaComponent(oParams) {
AbstractInput.call(this, oParams);
this.rows = oParams.rows || 5;
};
_.extend(TextAreaComponent.prototype, AbstractInput.prototype);
module.exports = AbstractInput.componentExportHelper(
TextAreaComponent, 'TextAreaComponent');
}());

4
dev/External/ko.js vendored
View file

@ -1,5 +1,5 @@
(function (module, ko) {
(function (ko) {
'use strict';
@ -902,4 +902,4 @@
module.exports = ko;
}(module, ko));
}(ko));

View file

@ -102,32 +102,11 @@
MailBoxUserScreen.prototype.onStart = function ()
{
var
sInboxFolderName = Cache.getFolderInboxName(),
fResizeFunction = function () {
Utils.windowResize();
}
;
if (Settings.capa(Enums.Capa.AdditionalAccounts) || Settings.capa(Enums.Capa.AdditionalIdentities))
{
require('App/User').accountsAndIdentities();
}
_.delay(function () {
if (sInboxFolderName !== Data.currentFolderFullNameRaw())
{
require('App/User').folderInformation(sInboxFolderName);
}
}, 1000);
_.delay(function () {
require('App/User').quota();
}, 5000);
_.delay(function () {
Remote.appDelayStart(Utils.emptyFunction);
}, 35000);
Globals.$html.toggleClass('rl-no-preview-pane', Enums.Layout.NoPreview === Data.layout());
Data.folderList.subscribe(fResizeFunction);

View file

@ -36,6 +36,13 @@
this.useCheckboxesInList = Data.useCheckboxesInList;
this.allowLanguagesOnSettings = Data.allowLanguagesOnSettings;
this.usePreviewPaneCheckbox = ko.computed({
read: this.usePreviewPane,
write: function (bValue) {
this.layout(bValue ? Enums.Layout.SidePreview : Enums.Layout.NoPreview);
}
}, this);
this.isDesktopNotificationsSupported = ko.computed(function () {
return Enums.DesktopNotifications.NotSupported !== Data.desktopNotificationsPermisions();
});

View file

@ -627,7 +627,7 @@
var
aResult = [],
iLimit = 10,
iLimit = 5,
iUtc = moment().unix(),
iTimeout = iUtc - 60 * 5,
aTimeouts = [],

View file

@ -275,3 +275,6 @@ html.rl-ctrl-key-pressed {
background-image: none;
display: none;
}
/*html.rl-changing-language {
}*/

View file

@ -2427,6 +2427,7 @@ class Actions
*/
public function DoAdminSettingsUpdate()
{
// sleep(3);
// return $this->DefaultResponse(__FUNCTION__, false);
$this->IsAdminLoggined();

View file

@ -225,9 +225,11 @@ class Service
'AppleTouchLink' => $sStaticPrefix.'apple-touch-icon.png',
'AppCssLink' => $sStaticPrefix.'css/app'.($bAppCssDebug ? '' : '.min').'.css',
'BootJsLink' => $sStaticPrefix.'js/min/boot.js',
'ComponentsJsLink' => $sStaticPrefix.'js/'.($bAppJsDebug ? '' : 'min/').'components.js',
'LibJsLink' => $sStaticPrefix.'js/min/libs.js',
'EditorJsLink' => $sStaticPrefix.'ckeditor/ckeditor.js',
'OpenPgpJsLink' => $sStaticPrefix.'js/min/openpgp.min.js',
'AppJsCommonLink' => $sStaticPrefix.'js/'.($bAppJsDebug ? '' : 'min/').'common.js',
'AppJsLink' => $sStaticPrefix.'js/'.($bAppJsDebug ? '' : 'min/').($bAdmin ? 'admin' : 'app').'.js'
);
@ -238,9 +240,11 @@ class Service
'{{BaseAppAppleTouchFile}}' => $aData['AppleTouchLink'],
'{{BaseAppMainCssLink}}' => $aData['AppCssLink'],
'{{BaseAppBootScriptLink}}' => $aData['BootJsLink'],
'{{BaseAppComponentsScriptLink}}' => $aData['ComponentsJsLink'],
'{{BaseAppLibsScriptLink}}' => $aData['LibJsLink'],
'{{BaseAppEditorScriptLink}}' => $aData['EditorJsLink'],
'{{BaseAppOpenPgpScriptLink}}' => $aData['OpenPgpJsLink'],
'{{BaseAppMainCommonScriptLink}}' => $aData['AppJsCommonLink'],
'{{BaseAppMainScriptLink}}' => $aData['AppJsLink'],
'{{BaseDir}}' => \in_array($aData['Language'], array('ar', 'he', 'ur')) ? 'rtl' : 'ltr'
);

View file

@ -442,6 +442,7 @@ class ServiceActions
*/
public function ServiceLang()
{
// sleep(2);
$sResult = '';
@\header('Content-Type: application/javascript; charset=utf-8');
@ -1070,7 +1071,9 @@ class ServiceActions
*/
private function compileTemplates($bAdmin = false)
{
$sHtml = \RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views/'.($bAdmin ? 'Admin' : 'User'), $this->oActions).
$sHtml =
\RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views/Components', $this->oActions, 'Component').
\RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views/'.($bAdmin ? 'Admin' : 'User'), $this->oActions).
\RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views/Common', $this->oActions).
$this->oActions->Plugins()->CompileTemplate($bAdmin);

View file

@ -245,10 +245,12 @@ class Utils
/**
* @param string $sDirName
* @param \RainLoop\Actions $oAction
* @param string $sNameSuffix = ''
*
* @return string
*/
public static function CompileTemplates($sDirName, $oAction)
public static function CompileTemplates($sDirName, $oAction, $sNameSuffix = '')
{
$sResult = '';
if (\file_exists($sDirName))
@ -257,7 +259,7 @@ class Utils
foreach ($aList as $sName)
{
$sTemplateName = \substr($sName, 0, -5);
$sTemplateName = \substr($sName, 0, -5).$sNameSuffix;
$sResult .= '<script id="'.\preg_replace('/[^a-zA-Z0-9]/', '', $sTemplateName).'" type="text/html" data-cfasync="false">'.
$oAction->ProcessTemplate($sTemplateName, \file_get_contents($sDirName.'/'.$sName)).'</script>';
}

View file

@ -13,9 +13,15 @@
Page Title
</label>
<div class="controls">
<input type="text" class="span5" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: title, saveTrigger: title.trigger, enable: capa" />
<div data-bind="saveTrigger: title.trigger"></div>
<div data-bind="component: {
name: 'Input',
params: {
value: title,
trigger: title.trigger,
size: 5,
enable: capa
}
}"></div>
</div>
</div>
<div class="control-group">
@ -23,9 +29,15 @@
Loading Description
</label>
<div class="controls">
<input type="text" class="span5" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: loadingDesc, saveTrigger: loadingDesc.trigger, enable: capa" />
<div data-bind="saveTrigger: loadingDesc.trigger"></div>
<div data-bind="component: {
name: 'Input',
params: {
value: loadingDesc,
trigger: loadingDesc.trigger,
size: 5,
enable: capa
}
}"></div>
</div>
</div>
<br />
@ -37,9 +49,16 @@
Logo
</label>
<div class="controls">
<input type="text" class="span5" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
placeholder="https://" data-bind="value: loginLogo, saveTrigger: loginLogo.trigger, enable: capa" />
<div data-bind="saveTrigger: loginLogo.trigger"></div>
<div data-bind="component: {
name: 'Input',
params: {
value: loginLogo,
trigger: loginLogo.trigger,
placeholder: 'https://',
size: 5,
enable: capa
}
}"></div>
</div>
</div>
<div class="control-group">
@ -47,18 +66,26 @@
Description
</label>
<div class="controls">
<input type="text" class="span5" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: loginDescription, saveTrigger: loginDescription.trigger, enable: capa" />
<div data-bind="saveTrigger: loginDescription.trigger"></div>
<div data-bind="component: {
name: 'Input',
params: {
value: loginDescription,
trigger: loginDescription.trigger,
size: 5,
enable: capa
}
}"></div>
</div>
</div>
<!-- <div class="control-group">
<label class="control-label"></label>
<div class="controls">
<label data-bind="click: function () { if (capa) { loginPowered(!loginPowered()); }}">
<i data-bind="css: loginPowered() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Show "Powered by RainLoop" link
</label>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'Show &quot;Powered by RainLoop&quot; link',
value: loginPowered
}
}"></div>
</div>
</div>-->
<div class="control-group">
@ -66,8 +93,16 @@
Custom CSS
</label>
<div class="controls">
<textarea class="input-xxlarge" data-bind="value: loginCss, saveTrigger: loginCss.trigger, enable: capa" rows="7" spellcheck="true"></textarea>
<div style="vertical-align: top;" data-bind="saveTrigger: loginCss.trigger"></div>
<div data-bind="component: {
name: 'TextArea',
params: {
value: loginCss,
trigger: loginCss.trigger,
width: 530,
enable: capa,
rows: 7
}
}"></div>
</div>
</div>
</div>

View file

@ -14,18 +14,14 @@
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { enableContacts(!enableContacts()); }">
<i data-bind="css: enableContacts() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Enable contacts
</label>
<!-- <label data-bind="click: function () { contactsSharing(!contactsSharing()); }">
<i data-bind="css: contactsSharing() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow contacts sharing (disabled)
</label>-->
<label data-bind="click: function () { contactsSync(!contactsSync()); }">
<i data-bind="css: contactsSync() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow contacts sync (with external CardDAV server)
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: enableContacts, label: 'Enable contacts' }
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: { value: contactsSync, label: 'Allow contacts sync (with external CardDAV server)' }
}"></div>
</div>
</div>
</div>

View file

@ -23,7 +23,11 @@
<span data-bind="css: 'flag flag-' + mainLanguage()" style=""></span>
</span>
<span class="flag-name" data-bind="text: mainLanguageFullName, click: selectLanguage"></span>
<div data-bind="saveTrigger: languageTrigger"></div>
&nbsp;&nbsp;
<div data-bind="component: {
name: 'SaveTrigger',
params: { value: languageTrigger }
}"></div>
</label>
</div>
</div>
@ -32,28 +36,47 @@
Theme
</label>
<div class="controls">
<select class="span2" data-bind="options: themesOptions, value: mainTheme, optionsText: 'optText', optionsValue: 'optValue', saveTrigger: themeTrigger"></select>
<div data-bind="saveTrigger: themeTrigger"></div>
<div data-bind="component: {
name: 'Select',
params: {
options: themesOptions,
value: mainTheme,
trigger: themeTrigger,
optionsText: 'optText',
optionsValue: 'optValue',
size: 2
}
}"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { allowLanguagesOnSettings(!allowLanguagesOnSettings()); }">
<i data-bind="css: allowLanguagesOnSettings() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow language selection on settings screen
</label>
<label data-bind="click: function () { capaThemes(!capaThemes()); }">
<i data-bind="css: capaThemes() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow theme selection on settings screen
</label>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'Allow language selection on settings screen',
value: allowLanguagesOnSettings
}
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'Allow theme selection on settings screen',
value: capaThemes
}
}"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="inline" data-bind="click: function () { capaGravatar(!capaGravatar()); }">
<i data-bind="css: capaGravatar() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow Gravatar
</label>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'Allow Gravatar',
value: capaGravatar,
inline: true
}
}"></div>
(<a class="g-ui-link" href="http://en.gravatar.com/" target="_blank">http://en.gravatar.com/</a>)
</div>
</div>
@ -66,8 +89,15 @@
size limit
</label>
<div class="controls">
<input class="span1" type="text" maxlength="3" data-bind="value: mainAttachmentLimit, saveTrigger: attachmentLimitTrigger" /> MB
<div data-bind="saveTrigger: attachmentLimitTrigger"></div>
<div data-bind="component: {
name: 'Input',
params: {
label: 'MB',
value: mainAttachmentLimit,
trigger: attachmentLimitTrigger,
size: 1
}
}"></div>
<br />
<br />
<span class="well well-small" data-bind="visible: '' !== uploadDataDesc">
@ -84,14 +114,20 @@
<br />
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { capaAdditionalAccounts(!capaAdditionalAccounts()); }">
<i data-bind="css: capaAdditionalAccounts() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow additional accounts
</label>
<label data-bind="click: function () { capaAdditionalIdentities(!capaAdditionalIdentities()); }">
<i data-bind="css: capaAdditionalIdentities() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow additional identities
</label>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'Allow additional accounts',
value: capaAdditionalAccounts
}
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'Allow additional identities',
value: capaAdditionalIdentities
}
}"></div>
</div>
</div>
</div>

View file

@ -8,26 +8,31 @@
Default Domain
</label>
<div class="controls">
<input type="text" class="span3" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: defaultDomain, saveTrigger: defaultDomainTrigger" />
<div data-bind="saveTrigger: defaultDomainTrigger"></div>
<div data-bind="component: {
name: 'Input',
params: {
value: defaultDomain,
trigger: defaultDomainTrigger,
size: 3
}
}"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { determineUserDomain(!determineUserDomain()); }">
<i data-bind="css: determineUserDomain() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Try to determine user domain
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: determineUserDomain, label: 'Try to determine user domain' }
}"></div>
<br />
<label data-bind="click: function () { allowLanguagesOnLogin(!allowLanguagesOnLogin()); }">
<i data-bind="css: allowLanguagesOnLogin() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Allow language selection on login screen
</label>
<label data-bind="click: function () { determineUserLanguage(!determineUserLanguage()); }">
<i data-bind="css: determineUserLanguage() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Try to determine user language
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: allowLanguagesOnLogin, label: 'Allow language selection on login screen' }
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: { value: determineUserLanguage, label: 'Try to determine user language' }
}"></div>
</div>
</div>
</div>

View file

@ -12,11 +12,10 @@
</div>
<div>
<label data-bind="click: function () { enabledPlugins(!enabledPlugins()); }">
<i data-bind="css: enabledPlugins() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
Enable plugins
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: enabledPlugins, label: 'Enable plugins' }
}"></div>
</div>
<br />
<div class="row">

View file

@ -5,40 +5,38 @@
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { capaTwoFactorAuth(!capaTwoFactorAuth()); }">
<i data-bind="css: capaTwoFactorAuth() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
Allow 2-Step Verification (Google Authenticator)
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: capaTwoFactorAuth, label: 'Allow 2-Step Verification (Google Authenticator)' }
}"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { useLocalProxyForExternalImages(!useLocalProxyForExternalImages()); }">
<i data-bind="css: useLocalProxyForExternalImages() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
Use local proxy for external images
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: useLocalProxyForExternalImages, label: 'Use local proxy for external images' }
}"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { capaOpenPGP(!capaOpenPGP()); }">
<i data-bind="css: capaOpenPGP() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
Allow OpenPGP
<span style="color:red">(beta)</span>
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: capaOpenPGP, label: 'Allow OpenPGP', inline: true }
}"></div>
&nbsp;&nbsp;
<span style="color:red">(beta)</span>
</div>
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { verifySslCertificate(!verifySslCertificate()); }">
<i data-bind="css: verifySslCertificate() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
Require verification of SSL certificate used (IMAP/SMTP).
<span style="color:red">(beta)</span>
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: verifySslCertificate, label: 'Require verification of SSL certificate used (IMAP/SMTP)', inline: true }
}"></div>
&nbsp;&nbsp;
<span style="color:red">(beta)</span>
</div>
</div>
<div class="control-group">

View file

@ -11,21 +11,21 @@
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { googleEnable(!googleEnable()); }">
<i data-bind="css: googleEnable() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Enable Google Integration
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: googleEnable, label: 'Enable Google Integration' }
}"></div>
<div data-bind="visible: googleEnable">
<br />
<blockquote>
<label data-bind="click: function () { googleEnable.auth(!googleEnable.auth()); }">
<i data-bind="css: googleEnable.auth() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Authentication
</label>
<label data-bind="click: function () { googleEnable.drive(!googleEnable.drive()); }" style="margin-top: 5px">
<i data-bind="css: googleEnable.drive() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Google Drive Integration (Compose view)
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: googleEnable.auth, label: 'Authentication' }
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: { value: googleEnable.drive, label: 'Google Drive Integration (Compose view)' }
}"></div>
</blockquote>
</div>
</div>
@ -56,9 +56,15 @@
Api Key
</label>
<div class="controls">
<input type="text" class="span5" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: googleApiKey, saveTrigger: googleTrigger3, enable: googleEnable.drive" />
<div data-bind="saveTrigger: googleTrigger3"></div>
<div data-bind="component: {
name: 'Input',
params: {
value: googleApiKey,
trigger: googleTrigger3,
size: 5,
enable: googleEnable.drive
}
}"></div>
<blockquote style="margin-top: 10px; margin-bottom: 0">
<p class="muted">
Required for Google Drive File Picker
@ -73,10 +79,10 @@
<div data-bind="if: facebookSupported">
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { facebookEnable(!facebookEnable()); }">
<i data-bind="css: facebookEnable() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Enable Facebook Integration (Authentication)
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: facebookEnable, label: 'Enable Facebook Integration (Authentication)' }
}"></div>
</div>
</div>
<div class="control-group">
@ -105,10 +111,10 @@
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { twitterEnable(!twitterEnable()); }">
<i data-bind="css: twitterEnable() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Enable Twitter Integration (Authentication)
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: twitterEnable, label: 'Enable Twitter Integration (Authentication)' }
}"></div>
</div>
</div>
<div class="control-group">
@ -136,10 +142,10 @@
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { dropboxEnable(!dropboxEnable()); }">
<i data-bind="css: dropboxEnable() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
Enable Dropbox Integration (Compose view)
</label>
<div data-bind="component: {
name: 'Checkbox',
params: { value: dropboxEnable, label: 'Enable Dropbox Integration (Compose view)' }
}"></div>
</div>
</div>
<div class="control-group">

View file

@ -0,0 +1,4 @@
<label data-bind="click: toggle, css: {'inline': inline}">
<i data-bind="css: value() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;<span class="i18n" data-bind="attr: {'data-i18n-text': label}"></span>
</label>

View file

@ -0,0 +1,14 @@
<input class="i18n" type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" placeholder=""
data-bind="value: value, attr: {'data-i18n-placeholder': placeholder}, enable: enable, css: className" />
<!-- ko if: labeled -->
&nbsp;
<span class="i18n" data-bind="attr: {'data-i18n-text': label}"></span>
&nbsp;
<!-- /ko -->
<!-- ko if: triggered -->
&nbsp;
<div data-bind="component: {
name: 'SaveTrigger',
params: { value: trigger }
}"></div>
<!-- /ko -->

View file

@ -0,0 +1,3 @@
<div class="settings-saved-trigger">
<i class="icon-spinner animated"></i><i class="icon-remove error"></i><i class="icon-ok success"></i>
</div>

View file

@ -0,0 +1,13 @@
<select data-bind="options: options, value: value, optionsText: optionsText, optionsValue: optionsValue, css: className"></select>
<!-- ko if: labeled -->
&nbsp;
<span class="i18n" data-bind="attr: {'data-i18n-text': label}"></span>
&nbsp;
<!-- /ko -->
<!-- ko if: triggered -->
&nbsp;&nbsp;
<div data-bind="component: {
name: 'SaveTrigger',
params: { value: trigger }
}"></div>
<!-- /ko -->

View file

@ -0,0 +1,9 @@
<textarea class="i18n" rows="5" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="true"
data-bind="value: value, enable: enable, attr: { rows: rows }, css: className"></textarea>
<!-- ko if: triggered -->
&nbsp;
<div data-bind="component: {
name: 'SaveTrigger',
params: { value: trigger, verticalAlign: 'top' }
}"></div>
<!-- /ko -->

View file

@ -13,7 +13,11 @@
<span data-bind="css: 'flag flag-' + mainLanguage()" style=""></span>
</span>
<span class="flag-name" data-bind="text: mainLanguageFullName, click: selectLanguage"></span>
<div data-bind="saveTrigger: languageTrigger"></div>
&nbsp;&nbsp;
<div data-bind="component: {
name: 'SaveTrigger',
params: { value: languageTrigger }
}"></div>
</label>
</div>
</div>
@ -43,38 +47,56 @@
</div>
<div class="control-group">
<div class="controls">
<select class="span2" data-bind="options: mainMessagesPerPageArray, value: mainMessagesPerPage, saveTrigger: mppTrigger" style="width: 70px;"></select>
<span class="i18n help-inline" data-i18n-text="SETTINGS_GENERAL/LABEL_MESSAGE_PER_PAGE"></span>
<div data-bind="saveTrigger: mppTrigger"></div>
<div data-bind="component: {
name: 'Select',
params: {
label: 'SETTINGS_GENERAL/LABEL_MESSAGE_PER_PAGE',
options: mainMessagesPerPageArray,
value: mainMessagesPerPage,
trigger: mppTrigger,
size: 2,
width: 70
}
}"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label data-bind="click: function () { showImages(!showImages()); }">
<i data-bind="css: showImages() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="SETTINGS_GENERAL/LABEL_SHOW_IMAGES"></span>
</label>
<label data-bind="click: function () { useCheckboxesInList(!useCheckboxesInList()); }">
<i data-bind="css: useCheckboxesInList() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="SETTINGS_GENERAL/LABEL_USE_CHECKBOXES_IN_LIST"></span>
</label>
<label data-bind="click: toggleLayout">
<i data-bind="css: usePreviewPane() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="SETTINGS_GENERAL/LABEL_USE_PREVIEW_PANE"></span>
</label>
<label data-bind="visible: threading, click: function () { useThreads(!useThreads()); }">
<i data-bind="css: useThreads() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="SETTINGS_GENERAL/LABEL_USE_THREADS"></span>
</label>
<label data-bind="click: function () { replySameFolder(!replySameFolder()); }">
<i data-bind="css: replySameFolder() ? 'icon-checkbox-checked' : 'icon-checkbox-unchecked'"></i>
&nbsp;&nbsp;
<span class="i18n" data-i18n-text="SETTINGS_GENERAL/LABEL_REPLY_SAME_FOLDER"></span>
</label>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'SETTINGS_GENERAL/LABEL_SHOW_IMAGES',
value: showImages
}
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'SETTINGS_GENERAL/LABEL_USE_CHECKBOXES_IN_LIST',
value: useCheckboxesInList
}
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'SETTINGS_GENERAL/LABEL_USE_PREVIEW_PANE',
value: usePreviewPaneCheckbox
}
}"></div>
<div data-bind="visible: threading, component: {
name: 'Checkbox',
params: {
label: 'SETTINGS_GENERAL/LABEL_USE_THREADS',
value: useThreads
}
}"></div>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'SETTINGS_GENERAL/LABEL_REPLY_SAME_FOLDER',
value: replySameFolder
}
}"></div>
</div>
</div>
</div>

View file

@ -2,7 +2,11 @@
<div class="form-horizontal">
<div class="legend">
<span class="i18n" data-i18n-text="SETTINGS_THEMES/LEGEND_THEMES"></span>
<div class="themeTrigger" data-bind="saveTrigger: themeTrigger"></div>
&nbsp;&nbsp;
<div data-bind="component: {
name: 'SaveTrigger',
params: { value: themeTrigger }
}"></div>
</div>
</div>
<div class="b-themes-list" data-bind="foreach: themesObjects">

View file

@ -13,6 +13,7 @@ module.exports = {
chunkFilename: '[chunkhash].chunk.js'
},
plugins: [
// new webpack.optimize.CommonsChunkPlugin('common.js'),
new webpack.optimize.OccurenceOrderPlugin()
],
resolve: {