OpenPGP (#53) UNSTABLE

This commit is contained in:
RainLoop Team 2014-04-01 22:03:37 +04:00
parent 9d26fe049e
commit ee19a5cb41
17 changed files with 1010 additions and 582 deletions

View file

@ -306,10 +306,10 @@ module.exports = function (grunt) {
"dev/Settings/Identity.js", "dev/Settings/Identity.js",
"dev/Settings/Identities.js", "dev/Settings/Identities.js",
"dev/Settings/Social.js", "dev/Settings/Social.js",
"dev/Settings/OpenPGP.js",
"dev/Settings/ChangePassword.js", "dev/Settings/ChangePassword.js",
"dev/Settings/Folders.js", "dev/Settings/Folders.js",
"dev/Settings/Themes.js", "dev/Settings/Themes.js",
"dev/Settings/OpenPGP.js",
"dev/Storages/AbstractData.js", "dev/Storages/AbstractData.js",
"dev/Storages/WebMailData.js", "dev/Storages/WebMailData.js",

View file

@ -250,6 +250,16 @@ Enums.ContactScopeType = {
'ShareAll': 2 'ShareAll': 2
}; };
/**
* @enum {number}
*/
Enums.SignedVerifyStatus = {
'Unverified': -2,
'Error': -1,
'None': 0,
'Success': 1
};
/** /**
* @enum {number} * @enum {number}
*/ */

View file

@ -4,5 +4,9 @@
/** /**
* @type {?RainLoopApp} * @type {?RainLoopApp}
*/ */
var RL = null; var
RL = null,
$proxyDiv = $('<div></div>')
;
/*jshint onevar: true*/ /*jshint onevar: true*/

View file

@ -91,7 +91,8 @@ function MessageModel()
this.isPgpSigned = ko.observable(false); this.isPgpSigned = ko.observable(false);
this.isPgpEncrypted = ko.observable(false); this.isPgpEncrypted = ko.observable(false);
this.pgpSignature = ko.observable(''); this.pgpSignedVerifyStatus = ko.observable(Enums.SignedVerifyStatus.None);
this.pgpSignedVerifyUser = ko.observable('');
this.priority = ko.observable(Enums.MessagePriority.Normal); this.priority = ko.observable(Enums.MessagePriority.Normal);
this.readReceipt = ko.observable(''); this.readReceipt = ko.observable('');
@ -263,7 +264,8 @@ MessageModel.prototype.clear = function ()
this.isPgpSigned(false); this.isPgpSigned(false);
this.isPgpEncrypted(false); this.isPgpEncrypted(false);
this.pgpSignature(''); this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
this.pgpSignedVerifyUser('');
this.priority(Enums.MessagePriority.Normal); this.priority(Enums.MessagePriority.Normal);
this.readReceipt(''); this.readReceipt('');
@ -363,7 +365,6 @@ MessageModel.prototype.initUpdateByMessageJson = function (oJsonMessage)
{ {
this.isPgpSigned(!!oJsonMessage.PgpSigned); this.isPgpSigned(!!oJsonMessage.PgpSigned);
this.isPgpEncrypted(!!oJsonMessage.PgpEncrypted); this.isPgpEncrypted(!!oJsonMessage.PgpEncrypted);
this.pgpSignature(oJsonMessage.PgpSignature);
} }
this.hasAttachments(!!oJsonMessage.HasAttachments); this.hasAttachments(!!oJsonMessage.HasAttachments);
@ -830,7 +831,6 @@ MessageModel.prototype.populateByMessageListItem = function (oMessage)
// this.isPgpSigned(false); // this.isPgpSigned(false);
// this.isPgpEncrypted(false); // this.isPgpEncrypted(false);
// this.pgpSignature('');
this.priority(Enums.MessagePriority.Normal); this.priority(Enums.MessagePriority.Normal);
this.aDraftInfo = []; this.aDraftInfo = [];
@ -897,12 +897,12 @@ MessageModel.prototype.showInternalImages = function (bLazy)
{ {
if (this.body && !this.body.data('rl-init-internal-images')) if (this.body && !this.body.data('rl-init-internal-images'))
{ {
this.body.data('rl-init-internal-images', true);
bLazy = Utils.isUnd(bLazy) ? false : bLazy; bLazy = Utils.isUnd(bLazy) ? false : bLazy;
var self = this; var self = this;
this.body.data('rl-init-internal-images', true);
$('[data-x-src-cid]', this.body).each(function () { $('[data-x-src-cid]', this.body).each(function () {
var oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-cid')); var oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-cid'));
@ -981,3 +981,128 @@ MessageModel.prototype.showInternalImages = function (bLazy)
Utils.windowResize(500); Utils.windowResize(500);
} }
}; };
MessageModel.prototype.storeDataToDom = function ()
{
if (this.body)
{
this.body.data('rl-is-rtl', !!this.isRtl());
this.body.data('rl-is-html', !!this.isHtml());
this.body.data('rl-has-images', !!this.hasImages());
this.body.data('rl-plain-raw', this.plainRaw);
if (RL.data().allowOpenPGP())
{
this.body.data('rl-plain-pgp-signed', !!this.isPgpSigned());
this.body.data('rl-plain-pgp-encrypted', !!this.isPgpEncrypted());
this.body.data('rl-pgp-verify-status', this.pgpSignedVerifyStatus());
this.body.data('rl-pgp-verify-user', this.pgpSignedVerifyUser());
}
}
};
MessageModel.prototype.storePgpVerifyDataToDom = function ()
{
if (this.body && RL.data().allowOpenPGP())
{
this.body.data('rl-pgp-verify-status', this.pgpSignedVerifyStatus());
this.body.data('rl-pgp-verify-user', this.pgpSignedVerifyUser());
}
};
MessageModel.prototype.fetchDataToDom = function ()
{
if (this.body)
{
this.isRtl(!!this.body.data('rl-is-rtl'));
this.isHtml(!!this.body.data('rl-is-html'));
this.hasImages(!!this.body.data('rl-has-images'));
this.plainRaw = Utils.pString(this.body.data('rl-plain-raw'));
if (RL.data().allowOpenPGP())
{
this.isPgpSigned(!!this.body.data('rl-plain-pgp-signed'));
this.isPgpEncrypted(!!this.body.data('rl-plain-pgp-encrypted'));
this.pgpSignedVerifyStatus(this.body.data('rl-pgp-verify-status'));
this.pgpSignedVerifyUser(this.body.data('rl-pgp-verify-user'));
}
else
{
this.isPgpSigned(false);
this.isPgpEncrypted(false);
this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
this.pgpSignedVerifyUser('');
}
}
};
MessageModel.prototype.verifyPgpSignedClearMessage = function ()
{
if (this.isPgpSigned())
{
var
aRes = [],
mPgpMessage = null,
sFrom = this.from && this.from[0] && this.from[0].email ? this.from[0].email : '',
aPublicKey = RL.data().findPublicKeysByEmail(sFrom),
oValidKey = null,
oValidSysKey = null,
sPlain = ''
;
this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Error);
this.pgpSignedVerifyUser('');
try
{
mPgpMessage = window.openpgp.cleartext.readArmored(this.plainRaw);
if (mPgpMessage && mPgpMessage.getText)
{
this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Unverified);
aRes = mPgpMessage.verify(aPublicKey);
if (aRes && 0 < aRes.length)
{
oValidKey = _.find(aRes, function (oItem) {
return oItem && oItem.keyid && oItem.valid;
});
if (oValidKey)
{
oValidSysKey = RL.data().findPublicKeyByHex(oValidKey.keyid.toHex());
if (oValidSysKey)
{
sPlain = mPgpMessage.getText();
this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Success);
this.pgpSignedVerifyUser(oValidSysKey.user);
sPlain =
$proxyDiv.empty().append(
$('<pre class="b-plain-openpgp signed verified"></pre>').text(sPlain)
).html()
;
$proxyDiv.empty();
this.replacePlaneTextBody(sPlain);
}
}
}
}
}
catch (oExc) {}
this.storePgpVerifyDataToDom();
}
};
MessageModel.prototype.replacePlaneTextBody = function (sPlain)
{
if (this.body)
{
this.body.html(sPlain).addClass('b-text-part plain');
}
};

View file

@ -883,49 +883,43 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
RL.data().allowOpenPGP() && RL.data().allowOpenPGP() &&
Utils.isNormal(oData.Result.PlainRaw)) Utils.isNormal(oData.Result.PlainRaw))
{ {
bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(oData.Result.PlainRaw); oMessage.plainRaw = Utils.pString(oData.Result.PlainRaw);
bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(oMessage.plainRaw);
if (!bPgpEncrypted) if (!bPgpEncrypted)
{ {
bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oData.Result.PlainRaw) && bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(oMessage.plainRaw) &&
/-----BEGIN PGP SIGNATURE-----/.test(oData.Result.PlainRaw); /-----BEGIN PGP SIGNATURE-----/.test(oMessage.plainRaw);
} }
if (bPgpSigned && oMessage.isPgpSigned() && oMessage.pgpSignature()) $proxyDiv.empty();
if (bPgpSigned && oMessage.isPgpSigned())
{ {
sPlain = '<pre class="b-plain-openpgp signed">' + oData.Result.PlainRaw + '</pre>'; sPlain =
$proxyDiv.append(
try $('<pre class="b-plain-openpgp signed"></pre>').text(oMessage.plainRaw)
{ ).html()
mPgpMessage = window.openpgp.cleartext.readArmored(oData.Result.PlainRaw); ;
}
catch (oExc) {}
if (mPgpMessage && mPgpMessage.getText)
{
sPlain = mPgpMessage.getText();
}
else
{
bPgpSigned = false;
}
} }
else if (bPgpEncrypted && oMessage.isPgpEncrypted()) else if (bPgpEncrypted && oMessage.isPgpEncrypted())
{ {
try // try
{ // {
mPgpMessage = window.openpgp.message.readArmored(oData.Result.PlainRaw); // mPgpMessage = window.openpgp.message.readArmored(oMessage.plainRaw);
} // }
catch (oExc) {} // catch (oExc) {}
sPlain = '<pre class="b-plain-openpgp encrypted">' + oData.Result.PlainRaw + '</pre>'; sPlain =
$proxyDiv.append(
$('<pre class="b-plain-openpgp encrypted"></pre>').text(oMessage.plainRaw)
).html()
;
} }
if (bPgpSigned || bPgpEncrypted) $proxyDiv.empty();
{
oBody.data('rl-plain-raw', oData.Result.PlainRaw); oMessage.isPgpSigned(bPgpSigned);
oBody.data('rl-plain-pgp-encrypted', bPgpEncrypted); oMessage.isPgpEncrypted(bPgpEncrypted);
oBody.data('rl-plain-pgp-signed', bPgpSigned);
}
} }
oBody.html(sPlain).addClass('b-text-part plain'); oBody.html(sPlain).addClass('b-text-part plain');
@ -935,9 +929,14 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
bIsHtml = false; bIsHtml = false;
} }
oMessage.isHtml(!!bIsHtml);
oMessage.hasImages(!!bHasExternals);
oMessage.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
oMessage.pgpSignedVerifyUser('');
if (oData.Result.Rtl) if (oData.Result.Rtl)
{ {
oBody.data('rl-is-rtl', true); this.isRtl(true);
oBody.addClass('rtl-text-part'); oBody.addClass('rtl-text-part');
} }
@ -945,14 +944,6 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
if (oMessage.body) if (oMessage.body)
{ {
oMessagesBodiesDom.append(oMessage.body); oMessagesBodiesDom.append(oMessage.body);
oMessage.body.data('rl-is-html', bIsHtml);
oMessage.body.data('rl-has-images', bHasExternals);
oMessage.isRtl(!!oMessage.body.data('rl-is-rtl'));
oMessage.isHtml(!!oMessage.body.data('rl-is-html'));
oMessage.hasImages(!!oMessage.body.data('rl-has-images'));
oMessage.plainRaw = Utils.pString(oMessage.body.data('rl-plain-raw'));
} }
if (bHasInternals) if (bHasInternals)
@ -965,6 +956,7 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
oMessage.showExternalImages(true); oMessage.showExternalImages(true);
} }
oMessage.storeDataToDom();
this.purgeMessageBodyCacheThrottle(); this.purgeMessageBodyCacheThrottle();
} }
else else
@ -973,24 +965,10 @@ WebMailDataStorage.prototype.setMessage = function (oData, bCached)
if (oMessage.body) if (oMessage.body)
{ {
oMessage.body.data('rl-cache-count', ++Globals.iMessageBodyCacheCount); oMessage.body.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
oMessage.isRtl(!!oMessage.body.data('rl-is-rtl')); oMessage.fetchDataToDom();
oMessage.isHtml(!!oMessage.body.data('rl-is-html'));
oMessage.hasImages(!!oMessage.body.data('rl-has-images'));
oMessage.plainRaw = Utils.pString(oMessage.body.data('rl-plain-raw'));
} }
} }
if (oMessage.body && RL.data().allowOpenPGP())
{
oMessage.isPgpSigned(!!oMessage.body.data('rl-plain-pgp-signed'));
oMessage.isPgpEncrypted(!!oMessage.body.data('rl-plain-pgp-encrypted'));
}
else
{
oMessage.isPgpSigned(false);
oMessage.isPgpEncrypted(false);
}
this.messageActiveDom(oMessage.body); this.messageActiveDom(oMessage.body);
this.hideMessageBodies(); this.hideMessageBodies();
@ -1148,3 +1126,66 @@ WebMailDataStorage.prototype.setMessageList = function (oData, bCached)
)); ));
} }
}; };
WebMailDataStorage.prototype.findPublicKeyByHex = function (sHash)
{
return _.find(this.openpgpkeysPublic(), function (oItem) {
return oItem && sHash === oItem.id;
});
};
WebMailDataStorage.prototype.findPublicKeysByEmail = function (sEmail)
{
return _.compact(_.map(this.openpgpkeysPublic(), function (oItem) {
var oKey = null;
if (oItem && sEmail === oItem.email)
{
try
{
oKey = window.openpgp.key.readArmored(oItem.armor);
if (oKey && !oKey.err && oKey.keys && oKey.keys[0])
{
return oKey.keys[0];
}
}
catch (e) {}
}
return null;
}));
};
WebMailDataStorage.prototype.findPrivateKeyByEmail = function (sEmail, sPass)
{
var
oPrivateKey = null,
oKey = _.find(this.openpgpkeysPrivate(), function (oItem) {
return oItem && sEmail === oItem.email;
})
;
if (oKey)
{
try
{
oPrivateKey = window.openpgp.key.readArmored(oKey.armor);
if (oPrivateKey && !oPrivateKey.err && oPrivateKey.keys && oPrivateKey.keys[0])
{
oPrivateKey = oPrivateKey.keys[0];
oPrivateKey.decrypt(sPass);
}
else
{
oPrivateKey = null;
}
}
catch (e)
{
oPrivateKey = null;
}
}
return oPrivateKey;
};

View file

@ -187,6 +187,16 @@ html.rl-no-preview-pane {
background-color: #eee; background-color: #eee;
} }
.pgpInfo {
padding: 5px 15px;
border-bottom: 1px solid #ddd;
background-color: #fcf8e3;
&.success {
background-color: #e9f4ff;
}
}
.readReceipt { .readReceipt {
background-color: #ffffd9; background-color: #ffffd9;
} }

View file

@ -36,6 +36,8 @@ function MailBoxMessageViewViewModel()
this.fullScreenMode = oData.messageFullScreenMode; this.fullScreenMode = oData.messageFullScreenMode;
this.showFullInfo = ko.observable(false); this.showFullInfo = ko.observable(false);
this.openPGPInformation = ko.observable('');
this.openPGPInformation.isError = ko.observable(false);
this.messageVisibility = ko.computed(function () { this.messageVisibility = ko.computed(function () {
return !this.messageLoadingThrottle() && !!this.message(); return !this.messageLoadingThrottle() && !!this.message();
@ -105,6 +107,14 @@ function MailBoxMessageViewViewModel()
this.viewUserPic = ko.observable(Consts.DataImages.UserDotPic); this.viewUserPic = ko.observable(Consts.DataImages.UserDotPic);
this.viewUserPicVisible = ko.observable(false); this.viewUserPicVisible = ko.observable(false);
this.viewPgpSignedVerifyStatus = ko.computed(function () {
return this.message() ? this.message().pgpSignedVerifyStatus() : Enums.SignedVerifyStatus.None;
}, this);
this.viewPgpSignedVerifyUser = ko.computed(function () {
return this.message() ? this.message().pgpSignedVerifyUser() : '';
}, this);
this.message.subscribe(function (oMessage) { this.message.subscribe(function (oMessage) {
this.messageActiveDom(null); this.messageActiveDom(null);
@ -176,6 +186,41 @@ function MailBoxMessageViewViewModel()
Utils.extendAsViewModel('MailBoxMessageViewViewModel', MailBoxMessageViewViewModel); Utils.extendAsViewModel('MailBoxMessageViewViewModel', MailBoxMessageViewViewModel);
MailBoxMessageViewViewModel.prototype.isPgpActionVisible = function ()
{
return Enums.SignedVerifyStatus.Success !== this.viewPgpSignedVerifyStatus();
};
MailBoxMessageViewViewModel.prototype.isPgpStatusVerifyVisible = function ()
{
return Enums.SignedVerifyStatus.None !== this.viewPgpSignedVerifyStatus();
};
MailBoxMessageViewViewModel.prototype.isPgpStatusVerifySuccess = function ()
{
return Enums.SignedVerifyStatus.Success === this.viewPgpSignedVerifyStatus();
};
MailBoxMessageViewViewModel.prototype.pgpStatusVerifyMessage = function ()
{
var sResult = '';
switch (this.viewPgpSignedVerifyStatus())
{
// TODO i18n
case Enums.SignedVerifyStatus.Unverified:
sResult = 'Unverified signature';
break;
case Enums.SignedVerifyStatus.Error:
sResult = 'OpenPGP decryption error';
break;
case Enums.SignedVerifyStatus.Success:
sResult = 'Good signature from ' + this.viewPgpSignedVerifyUser();
break;
}
return sResult;
};
MailBoxMessageViewViewModel.prototype.scrollToTop = function () MailBoxMessageViewViewModel.prototype.scrollToTop = function ()
{ {
var oCont = $('.messageItem.nano .content', this.viewModelDom); var oCont = $('.messageItem.nano .content', this.viewModelDom);
@ -354,6 +399,28 @@ MailBoxMessageViewViewModel.prototype.showImages = function (oMessage)
} }
}; };
/**
* @param {MessageModel} oMessage
*/
MailBoxMessageViewViewModel.prototype.verifyPgpSignedClearMessage = function (oMessage)
{
if (oMessage)
{
oMessage.verifyPgpSignedClearMessage();
}
};
/**
* @param {MessageModel} oMessage
*/
MailBoxMessageViewViewModel.prototype.decryptPgpEncryptedMessage = function (oMessage)
{
if (oMessage)
{
oMessage.decryptPgpEncryptedMessage();
}
};
/** /**
* @param {MessageModel} oMessage * @param {MessageModel} oMessage
*/ */

View file

@ -30,80 +30,26 @@ function PopupsComposeOpenPgpViewModel()
var var
self = this, self = this,
bResult = true, bResult = true,
aOpenpgpkeysPublic = RL.data().openpgpkeysPublic(), oData = RL.data(),
oKey = null,
oPrivateKey = null, oPrivateKey = null,
aPublicKeys = [], aPublicKeys = []
fFindPublicKey = function (sEmail) {
var
oResult = null,
oKey = _.find(aOpenpgpkeysPublic, function (oItem) {
return oItem && sEmail === oItem.email;
})
;
if (oKey)
{
try
{
oResult = window.openpgp.key.readArmored(oKey.armor);
if (oResult && !oResult.err && oResult.keys && oResult.keys[0])
{
oResult = oResult.keys[0];
}
else
{
oResult = null;
}
}
catch (e)
{
oResult = null;
}
}
return oResult;
}
; ;
this.submitRequest(true); this.submitRequest(true);
if (bResult && this.sign() && '' === this.from()) if (bResult && this.sign() && '' === this.from())
{ {
this.notification('Please specify From email address'); // TODO i18n
this.notification('Please specify FROM email address');
bResult = false; bResult = false;
} }
if (bResult && this.sign()) if (bResult && this.sign())
{ {
oKey = _.find(RL.data().openpgpkeysPrivate(), function (oItem) { oPrivateKey = oData.findPrivateKeyByEmail(this.from(), this.password());
return oItem && self.from() === oItem.email;
});
if (oKey)
{
try
{
oPrivateKey = window.openpgp.key.readArmored(oKey.armor);
if (oPrivateKey && !oPrivateKey.err && oPrivateKey.keys && oPrivateKey.keys[0])
{
oPrivateKey = oPrivateKey.keys[0];
oPrivateKey.decrypt(this.password());
}
else
{
oPrivateKey = null;
}
}
catch (e)
{
oPrivateKey = null;
}
}
if (!oPrivateKey) if (!oPrivateKey)
{ {
// TODO i18n
this.notification('No private key found for "' + this.from() + '" email'); this.notification('No private key found for "' + this.from() + '" email');
bResult = false; bResult = false;
} }
@ -111,25 +57,27 @@ function PopupsComposeOpenPgpViewModel()
if (bResult && this.encrypt() && 0 === this.to().length) if (bResult && this.encrypt() && 0 === this.to().length)
{ {
// TODO i18n
this.notification('Please specify at least one recipient'); this.notification('Please specify at least one recipient');
bResult = false; bResult = false;
} }
if (bResult && this.encrypt()) if (bResult && this.encrypt())
{ {
aPublicKeys = _.compact(_.map(this.to(), function (sEmail) { aPublicKeys = _.compact(_.union(this.to(), function (sEmail) {
var oKey = fFindPublicKey(sEmail); var aKeys = oData.findPublicKeysByEmail(sEmail);
if (!oKey && bResult) if (0 === aKeys.length && bResult)
{ {
// TODO i18n
self.notification('No public key found for "' + sEmail + '" email'); self.notification('No public key found for "' + sEmail + '" email');
bResult = false; bResult = false;
} }
return oKey; return aKeys;
})); }));
if (0 === aPublicKeys.length || this.to().length !== aPublicKeys.length) if (bResult && (0 === aPublicKeys.length || this.to().length !== aPublicKeys.length))
{ {
bResult = false; bResult = false;
} }
@ -162,6 +110,7 @@ function PopupsComposeOpenPgpViewModel()
} }
catch (e) catch (e)
{ {
// TODO i18n
self.notification('OpenPGP error: ' + e); self.notification('OpenPGP error: ' + e);
bResult = false; bResult = false;
} }

View file

@ -22,8 +22,8 @@
</div> </div>
<div class="btn-group">&nbsp;</div> <div class="btn-group">&nbsp;</div>
<div class="btn-group btn-group-custom-margin"> <div class="btn-group btn-group-custom-margin">
<a class="btn btn-danger buttonDelete" data-placement="bottom" data-bind="command: deleteCommand, tooltip: 'MESSAGE_LIST/BUTTON_DELETE'"> <a class="btn buttonDelete" data-placement="bottom" data-bind="command: deleteCommand, tooltip: 'MESSAGE_LIST/BUTTON_DELETE'">
<i class="icon-trash icon-white"></i> <i class="icon-trash"></i>
<span data-bind="text: 1 < messageListCheckedOrSelectedUidsWithSubMails().length ? ' (' + messageListCheckedOrSelectedUidsWithSubMails().length + ')' : ''"></span> <span data-bind="text: 1 < messageListCheckedOrSelectedUidsWithSubMails().length ? ' (' + messageListCheckedOrSelectedUidsWithSubMails().length + ')' : ''"></span>
</a> </a>
<a class="btn buttonSpam" data-placement="bottom" data-bind="visible: !isSpamFolder() && !isSpamDisabled(), command: spamCommand, tooltip: 'MESSAGE_LIST/BUTTON_SPAM'"> <a class="btn buttonSpam" data-placement="bottom" data-bind="visible: !isSpamFolder() && !isSpamDisabled(), command: spamCommand, tooltip: 'MESSAGE_LIST/BUTTON_SPAM'">

View file

@ -2,58 +2,58 @@
<div class="messageView" data-bind="css: {'message-selected': isMessageSelected}"> <div class="messageView" data-bind="css: {'message-selected': isMessageSelected}">
<div class="toolbar g-ui-user-select-none"> <div class="toolbar g-ui-user-select-none">
<div class="messageButtons btn-toolbar"> <div class="messageButtons btn-toolbar">
<div class="btn-group" data-placement="bottom" data-bind="visible: !$root.usePreviewPane(), tooltip: 'MESSAGE/BUTTON_CLOSE'"> <div class="btn-group" data-placement="bottom" data-bind="visible: !usePreviewPane(), tooltip: 'MESSAGE/BUTTON_CLOSE'">
<a class="btn buttonClose" data-bind="command: $root.closeMessage"> <a class="btn buttonClose" data-bind="command: closeMessage">
<i class="icon-remove"></i> <i class="icon-remove"></i>
</a> </a>
</div> </div>
<div class="btn-group">&nbsp;</div> <div class="btn-group">&nbsp;</div>
<div class="btn-group" data-placement="bottom" data-bind="visible: $root.isDraftFolder(), tooltip: 'MESSAGE/BUTTON_EDIT'"> <div class="btn-group" data-placement="bottom" data-bind="visible: isDraftFolder(), tooltip: 'MESSAGE/BUTTON_EDIT'">
<a class="btn btn-success buttonEdit" data-bind="command: $root.messageEditCommand"> <a class="btn btn-success buttonEdit" data-bind="command: messageEditCommand">
<i class="icon-pencil icon-white"></i> <i class="icon-pencil icon-white"></i>
</a> </a>
</div> </div>
<div class="btn-group" data-bind="visible: !$root.isDraftFolder()"> <div class="btn-group" data-bind="visible: !isDraftFolder()">
<a class="btn buttonReply" data-placement="bottom" data-bind="command: $root.replyCommand, tooltip: 'MESSAGE/BUTTON_REPLY'"> <a class="btn buttonReply" data-placement="bottom" data-bind="command: replyCommand, tooltip: 'MESSAGE/BUTTON_REPLY'">
<i class="icon-reply"></i> <i class="icon-reply"></i>
</a> </a>
<a class="btn buttonReplyAll" data-placement="bottom" data-bind="command: $root.replyAllCommand, tooltip: 'MESSAGE/BUTTON_REPLY_ALL'"> <a class="btn buttonReplyAll" data-placement="bottom" data-bind="command: replyAllCommand, tooltip: 'MESSAGE/BUTTON_REPLY_ALL'">
<i class="icon-reply-all"></i> <i class="icon-reply-all"></i>
</a> </a>
<a class="btn buttonForward" data-placement="bottom" data-bind=" command: $root.forwardCommand, tooltip: 'MESSAGE/BUTTON_FORWARD'"> <a class="btn buttonForward" data-placement="bottom" data-bind=" command: forwardCommand, tooltip: 'MESSAGE/BUTTON_FORWARD'">
<i class="icon-forward"></i> <i class="icon-forward"></i>
</a> </a>
</div> </div>
<div class="btn-group">&nbsp;</div> <div class="btn-group">&nbsp;</div>
<div class="btn-group btn-group-custom-margin"> <div class="btn-group btn-group-custom-margin">
<a class="btn btn-danger buttonDelete" data-placement="bottom" data-bind="command: $root.deleteCommand, tooltip: 'MESSAGE/BUTTON_DELETE'"> <a class="btn btn-danger buttonDelete" data-placement="bottom" data-bind="command: deleteCommand, tooltip: 'MESSAGE/BUTTON_DELETE'">
<i class="icon-trash icon-white"></i> <i class="icon-trash icon-white"></i>
</a> </a>
<a class="btn buttonSpam" data-placement="bottom" data-bind="visible: !$root.isDraftFolder(), command: $root.spamCommand, tooltip: 'MESSAGE/BUTTON_SPAM'"> <a class="btn buttonSpam" data-placement="bottom" data-bind="visible: !isDraftFolder(), command: spamCommand, tooltip: 'MESSAGE/BUTTON_SPAM'">
<i class="icon-bug"></i> <i class="icon-bug"></i>
</a> </a>
</div> </div>
<div class="btn-group">&nbsp;</div> <div class="btn-group">&nbsp;</div>
<div class="btn-group"> <div class="btn-group">
<a class="btn dropdown-toggle buttonMore" data-placement="bottom" data-toggle="dropdown" data-bind="command: $root.messageVisibilityCommand, tooltip: 'MESSAGE/BUTTON_MORE'"> <a class="btn dropdown-toggle buttonMore" data-placement="bottom" data-toggle="dropdown" data-bind="command: messageVisibilityCommand, tooltip: 'MESSAGE/BUTTON_MORE'">
<i class="icon-list"></i> <i class="icon-list"></i>
</a> </a>
<ul class="dropdown-menu g-ui-menu"> <ul class="dropdown-menu g-ui-menu">
<li class="e-item" data-bind="visible: !$root.isDraftFolder()"> <li class="e-item" data-bind="visible: !isDraftFolder()">
<a class="e-link" data-bind="command: $root.forwardAsAttachmentCommand"> <a class="e-link" data-bind="command: forwardAsAttachmentCommand">
<i class="icon-reply"></i> <i class="icon-reply"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
<span class="i18n" data-i18n-text="MESSAGE/BUTTON_FORWARD_AS_ATTACHMENT"></span> <span class="i18n" data-i18n-text="MESSAGE/BUTTON_FORWARD_AS_ATTACHMENT"></span>
</a> </a>
</li> </li>
<li class="e-item" data-bind="visible: !$root.isDraftFolder()"> <li class="e-item" data-bind="visible: !isDraftFolder()">
<a class="e-link" data-bind="command: $root.editAsNewCommand"> <a class="e-link" data-bind="command: editAsNewCommand">
<i class="icon-pencil"></i> <i class="icon-pencil"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
<span class="i18n" data-i18n-text="MESSAGE/BUTTON_EDIT_AS_NEW"></span> <span class="i18n" data-i18n-text="MESSAGE/BUTTON_EDIT_AS_NEW"></span>
</a> </a>
</li> </li>
<li class="divider" data-bind="visible: !$root.isDraftFolder()"></li> <li class="divider" data-bind="visible: !isDraftFolder()"></li>
<li class="e-item"> <li class="e-item">
<a target="_blank" class="e-link" data-bind="click: function () { if (message()) { message().viewPopupMessage(); }}"> <a target="_blank" class="e-link" data-bind="click: function () { if (message()) { message().viewPopupMessage(); }}">
<i class="icon-popup"></i> <i class="icon-popup"></i>
@ -86,11 +86,11 @@
</ul> </ul>
</div> </div>
<div class="btn-group">&nbsp;</div> <div class="btn-group">&nbsp;</div>
<div class="btn-group" data-bind="visible: !$root.usePreviewPane()"> <div class="btn-group" data-bind="visible: !usePreviewPane()">
<a class="btn buttonUp" data-bind="command: $root.goUpCommand"> <a class="btn buttonUp" data-bind="command: goUpCommand">
<i class="icon-left-middle"></i> <i class="icon-left-middle"></i>
</a> </a>
<a class="btn buttonDown" data-bind="command: $root.goDownCommand"> <a class="btn buttonDown" data-bind="command: goDownCommand">
<i class="icon-right-middle"></i> <i class="icon-right-middle"></i>
</a> </a>
</div> </div>
@ -98,11 +98,11 @@
</div> </div>
<div class="b-content thm-message-view-background-color"> <div class="b-content thm-message-view-background-color">
<div> <div>
<div class="b-message-view-desc" data-bind="visible: !message() && '' === $root.messageError()"> <div class="b-message-view-desc" data-bind="visible: !message() && '' === messageError()">
<span class="i18n" data-i18n-text="MESSAGE/MESSAGE_VIEW_DESC"></span> <span class="i18n" data-i18n-text="MESSAGE/MESSAGE_VIEW_DESC"></span>
</div> </div>
<div class="b-message-view-desc error" data-bind="visible: !message() && '' !== $root.messageError()"> <div class="b-message-view-desc error" data-bind="visible: !message() && '' !== messageError()">
<span class="text" data-bind="text: $root.messageError()"></span> <span class="text" data-bind="text: messageError()"></span>
</div> </div>
<div data-bind="visible: message"> <div data-bind="visible: message">
<div class="messageItem" data-bind="css: viewLineAsCcc(), nano: true"> <div class="messageItem" data-bind="css: viewLineAsCcc(), nano: true">
@ -127,14 +127,14 @@
<span class="i18n emptySubjectText" data-i18n-text="MESSAGE/EMPTY_SUBJECT_TEXT"></span> <span class="i18n emptySubjectText" data-i18n-text="MESSAGE/EMPTY_SUBJECT_TEXT"></span>
</div> </div>
<div class="senderParent"> <div class="senderParent">
<div class="g-ui-user-select-none" style="float: left; cursor: pointer;" data-bind="click: function() { $root.showFullInfo(!$root.showFullInfo()); }"> <div class="g-ui-user-select-none" style="float: left; cursor: pointer;" data-bind="click: function() { showFullInfo(!showFullInfo()); }">
<i class="icon-right-dir" data-bind="css: $root.showFullInfo() ? 'icon-down-dir' : 'icon-right-dir'"></i> <i class="icon-right-dir" data-bind="css: showFullInfo() ? 'icon-down-dir' : 'icon-right-dir'"></i>
</div> </div>
<div class="informationShort" data-bind="event: { 'dblclick': toggleFullScreen }"> <div class="informationShort" data-bind="event: { 'dblclick': toggleFullScreen }">
<span data-bind="visible: !$root.isDraftOrSentFolder()"> <span data-bind="visible: !isDraftOrSentFolder()">
<span class="from" data-bind="html: viewFromShort, title: viewFrom"></span> <span class="from" data-bind="html: viewFromShort, title: viewFrom"></span>
</span> </span>
<span data-bind="visible: $root.isDraftOrSentFolder()"> <span data-bind="visible: isDraftOrSentFolder()">
<span class="i18n uiLabel labelTo" data-i18n-text="MESSAGE/LABEL_TO"></span>: <span class="i18n uiLabel labelTo" data-i18n-text="MESSAGE/LABEL_TO"></span>:
<span class="to" data-bind="html: viewToShort, title: viewTo"></span> <span class="to" data-bind="html: viewToShort, title: viewTo"></span>
</span> </span>
@ -143,7 +143,7 @@
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div> </div>
<div class="informationFull" data-bind="visible: $root.showFullInfo()"> <div class="informationFull" data-bind="visible: showFullInfo()">
<div data-bind="visible: '' !== viewFrom()"> <div data-bind="visible: '' !== viewFrom()">
<span class="i18n uiLabel labelFrom" data-i18n-text="MESSAGE/LABEL_FROM"></span>: <span class="i18n uiLabel labelFrom" data-i18n-text="MESSAGE/LABEL_FROM"></span>:
&nbsp; &nbsp;
@ -175,33 +175,41 @@
</div> </div>
</div> </div>
<div class="line-loading e-strip-animation" data-bind="visible: $root.messageLoadingThrottle()"></div> <div class="line-loading e-strip-animation" data-bind="visible: messageLoadingThrottle()"></div>
<div class="loading g-ui-min-height-300" data-bind="visible: $root.messageLoadingThrottle()"> <div class="loading g-ui-min-height-300" data-bind="visible: messageLoadingThrottle()">
<span class="i18n text" data-i18n-text="MESSAGE/MESSAGE_LOADING"></span><span class="textLoadingAnimationD1">.</span><span class="textLoadingAnimationD2">.</span><span class="textLoadingAnimationD3">.</span> <span class="i18n text" data-i18n-text="MESSAGE/MESSAGE_LOADING"></span><span class="textLoadingAnimationD1">.</span><span class="textLoadingAnimationD2">.</span><span class="textLoadingAnimationD3">.</span>
</div> </div>
</div> </div>
<div class="g-ui-min-height-300" data-bind="visible: !$root.messageLoadingThrottle()"> <div class="g-ui-min-height-300" data-bind="visible: !messageLoadingThrottle()">
<div class="showImages" data-bind="visible: message() && message().hasImages(), click: function() { $root.showImages(message()); }"> <div class="showImages" data-bind="visible: message() && message().hasImages(), click: function() { showImages(message()); }">
<i class="icon-image"></i> <i class="icon-image"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
<span class="i18n text" data-i18n-text="MESSAGE/BUTTON_SHOW_IMAGES"></span> <span class="i18n text" data-i18n-text="MESSAGE/BUTTON_SHOW_IMAGES"></span>
</div> </div>
<div class="readReceipt" data-bind="visible: message() && '' !== message().readReceipt() && !message().isReadReceipt(), click: function() { $root.readReceipt(message()); }"> <div class="readReceipt" data-bind="visible: message() && '' !== message().readReceipt() && !message().isReadReceipt(), click: function() { readReceipt(message()); }">
<i class="icon-mail"></i> <i class="icon-mail"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
<span class="i18n text" data-i18n-text="MESSAGE/BUTTON_NOTIFY_READ_RECEIPT"></span> <span class="i18n text" data-i18n-text="MESSAGE/BUTTON_NOTIFY_READ_RECEIPT"></span>
</div> </div>
<div class="pgpSigned" data-bind="visible: message() && message().isPgpSigned()"> <div class="pgpInfo" data-bind="visible: isPgpStatusVerifyVisible(), css: {'success': isPgpStatusVerifySuccess()}">
<i class="icon-key"></i>
&nbsp;&nbsp;
<span data-bind="text: pgpStatusVerifyMessage()"></span>
</div>
<div class="pgpSigned" data-bind="visible: message() && message().isPgpSigned() && isPgpActionVisible(), click: function() { verifyPgpSignedClearMessage(message()); }">
<i class="icon-lock"></i> <i class="icon-lock"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
PGP signed OpenPGP signed message (click to verify)
</div> </div>
<div class="pgpEncrypted" data-bind="visible: message() && message().isPgpEncrypted()"> <div class="pgpEncrypted" data-bind="visible: message() && message().isPgpEncrypted()">
<i class="icon-lock"></i> <i class="icon-lock"></i>
&nbsp;&nbsp; &nbsp;&nbsp;
PGP encrypted <span data-bind="click: function() { decryptPgpEncryptedMessage(message()); }">
OpenPGP encrypted message (click to decrypt)
</span>
<input type="password" />
</div> </div>
<div class="attachmentsPlace" data-bind="visible: message() && message().hasVisibleAttachments()"> <div class="attachmentsPlace" data-bind="visible: message() && message().hasVisibleAttachments()">
<ul class="attachmentList" data-bind="foreach: message() ? message().attachments() : []"> <ul class="attachmentList" data-bind="foreach: message() ? message().attachments() : []">

View file

@ -637,7 +637,7 @@
border-radius: 8px; border-radius: 8px;
} }
/*! normalize.css 2012-03-11T12:53 UTC - http://github.com/necolas/normalize.css */ /*! normalize.css 2012-03-11T12:53 UTC - http://github.com/necolas/normalize.css */
/* ============================================================================= /* =============================================================================
@ -1142,7 +1142,7 @@ table {
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
} }
@charset "UTF-8"; @charset "UTF-8";
@font-face { @font-face {
@ -1474,7 +1474,7 @@ table {
.icon-mail:before { .icon-mail:before {
content: "\e062"; content: "\e062";
} }
/** initial setup **/ /** initial setup **/
.nano { .nano {
/* /*
@ -1591,7 +1591,7 @@ table {
.nano > .pane2:hover > .slider2, .nano > .pane2.active > .slider2 { .nano > .pane2:hover > .slider2, .nano > .pane2.active > .slider2 {
background-color: rgba(0, 0, 0, 0.4); background-color: rgba(0, 0, 0, 0.4);
} }
/* Magnific Popup CSS */ /* Magnific Popup CSS */
.mfp-bg { .mfp-bg {
top: 0; top: 0;
@ -1956,7 +1956,7 @@ img.mfp-img {
right: 0; right: 0;
padding-top: 0; } padding-top: 0; }
/* overlay at start */ /* overlay at start */
.mfp-fade.mfp-bg { .mfp-fade.mfp-bg {
@ -2002,7 +2002,7 @@ img.mfp-img {
-moz-transform: translateX(50px); -moz-transform: translateX(50px);
transform: translateX(50px); transform: translateX(50px);
} }
.simple-pace { .simple-pace {
-webkit-pointer-events: none; -webkit-pointer-events: none;
pointer-events: none; pointer-events: none;
@ -2073,7 +2073,7 @@ img.mfp-img {
@keyframes simple-pace-stripe-animation { @keyframes simple-pace-stripe-animation {
0% { transform: none; transform: none; } 0% { transform: none; transform: none; }
100% { transform: translate(-32px, 0); transform: translate(-32px, 0); } 100% { transform: translate(-32px, 0); transform: translate(-32px, 0); }
} }
.inputosaurus-container { .inputosaurus-container {
background-color:#fff; background-color:#fff;
border:1px solid #bcbec0; border:1px solid #bcbec0;
@ -2141,7 +2141,7 @@ img.mfp-img {
box-shadow:none; box-shadow:none;
} }
.inputosaurus-input-hidden { display:none; } .inputosaurus-input-hidden { display:none; }
.flag-wrapper { .flag-wrapper {
width: 24px; width: 24px;
height: 16px; height: 16px;
@ -2184,7 +2184,7 @@ img.mfp-img {
.flag.flag-pt-br {background-position: -192px -11px} .flag.flag-pt-br {background-position: -192px -11px}
.flag.flag-cn, .flag.flag-zh-tw, .flag.flag-zh-cn, .flag.flag-zh-hk {background-position: -208px -22px} .flag.flag-cn, .flag.flag-zh-tw, .flag.flag-zh-cn, .flag.flag-zh-hk {background-position: -208px -22px}
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ /* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
.clearfix { .clearfix {
*zoom: 1; *zoom: 1;
@ -7226,6 +7226,14 @@ html.rl-no-preview-pane .messageView.message-selected {
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
background-color: #eee; background-color: #eee;
} }
.messageView .b-content .messageItem .pgpInfo {
padding: 5px 15px;
border-bottom: 1px solid #ddd;
background-color: #fcf8e3;
}
.messageView .b-content .messageItem .pgpInfo.success {
background-color: #e9f4ff;
}
.messageView .b-content .messageItem .readReceipt { .messageView .b-content .messageItem .readReceipt {
background-color: #ffffd9; background-color: #ffffd9;
} }

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
/*! RainLoop Webmail Admin Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */ /*! RainLoop Webmail Admin Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
(function (window, $, ko, crossroads, hasher, _) { (function (window, $, ko, crossroads, hasher, _) {
'use strict'; 'use strict';
@ -70,14 +70,14 @@ var
$document = $(window.document), $document = $(window.document),
NotificationClass = window.Notification && window.Notification.requestPermission ? window.Notification : null NotificationClass = window.Notification && window.Notification.requestPermission ? window.Notification : null
; ;
/*jshint onevar: false*/ /*jshint onevar: false*/
/** /**
* @type {?AdminApp} * @type {?AdminApp}
*/ */
var RL = null; var RL = null;
/*jshint onevar: true*/ /*jshint onevar: true*/
/** /**
* @type {?} * @type {?}
*/ */
@ -221,7 +221,7 @@ if (Globals.bAllowPdfPreview && navigator && navigator.mimeTypes)
return oType && 'application/pdf' === oType.type; return oType && 'application/pdf' === oType.type;
}); });
} }
Consts.Defaults = {}; Consts.Defaults = {};
Consts.Values = {}; Consts.Values = {};
Consts.DataImages = {}; Consts.DataImages = {};
@ -339,7 +339,7 @@ Consts.DataImages.UserDotPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA
* @type {string} * @type {string}
*/ */
Consts.DataImages.TranspPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII='; Consts.DataImages.TranspPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII=';
/** /**
* @enum {string} * @enum {string}
*/ */
@ -590,6 +590,16 @@ Enums.ContactScopeType = {
'ShareAll': 2 'ShareAll': 2
}; };
/**
* @enum {number}
*/
Enums.SignedVerifyStatus = {
'Unverified': -2,
'Error': -1,
'None': 0,
'Success': 1
};
/** /**
* @enum {number} * @enum {number}
*/ */
@ -683,7 +693,7 @@ Enums.Notification = {
'UnknownNotification': 999, 'UnknownNotification': 999,
'UnknownError': 999 'UnknownError': 999
}; };
Utils.trim = $.trim; Utils.trim = $.trim;
Utils.inArray = $.inArray; Utils.inArray = $.inArray;
Utils.isArray = _.isArray; Utils.isArray = _.isArray;
@ -2445,7 +2455,7 @@ Utils.openPgpImportPublicKeys = function (sPublicKeysArmored)
return false; return false;
}; };
// Base64 encode / decode // Base64 encode / decode
// http://www.webtoolkit.info/ // http://www.webtoolkit.info/
@ -2608,7 +2618,7 @@ Base64 = {
} }
}; };
/*jslint bitwise: false*/ /*jslint bitwise: false*/
ko.bindingHandlers.tooltip = { ko.bindingHandlers.tooltip = {
'init': function (oElement, fValueAccessor) { 'init': function (oElement, fValueAccessor) {
if (!Globals.bMobileDevice) if (!Globals.bMobileDevice)
@ -3257,7 +3267,7 @@ ko.observable.fn.validateFunc = function (fFunc)
return this; return this;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3555,7 +3565,7 @@ LinkBuilder.prototype.socialFacebook = function ()
{ {
return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : ''); return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : '');
}; };
/** /**
* @type {Object} * @type {Object}
*/ */
@ -3649,7 +3659,7 @@ Plugins.settingsGet = function (sPluginSection, sName)
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3723,7 +3733,7 @@ CookieDriver.prototype.get = function (sKey)
return mResult; return mResult;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3794,7 +3804,7 @@ LocalStorageDriver.prototype.get = function (sKey)
return mResult; return mResult;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3837,7 +3847,7 @@ LocalStorage.prototype.get = function (iKey)
{ {
return this.oDriver ? this.oDriver.get('p' + iKey) : null; return this.oDriver ? this.oDriver.get('p' + iKey) : null;
}; };
/** /**
* @constructor * @constructor
*/ */
@ -3850,7 +3860,7 @@ KnoinAbstractBoot.prototype.bootstart = function ()
{ {
}; };
/** /**
* @param {string=} sPosition = '' * @param {string=} sPosition = ''
* @param {string=} sTemplate = '' * @param {string=} sTemplate = ''
@ -3925,7 +3935,7 @@ KnoinAbstractViewModel.prototype.registerPopupEscapeKey = function ()
return true; return true;
}); });
}; };
/** /**
* @param {string} sScreenName * @param {string} sScreenName
* @param {?=} aViewModels = [] * @param {?=} aViewModels = []
@ -4001,7 +4011,7 @@ KnoinAbstractScreen.prototype.__start = function ()
this.oCross = oRoute; this.oCross = oRoute;
} }
}; };
/** /**
* @constructor * @constructor
*/ */
@ -4387,7 +4397,7 @@ Knoin.prototype.bootstart = function ()
}; };
kn = new Knoin(); kn = new Knoin();
/** /**
* @param {string=} sEmail * @param {string=} sEmail
* @param {string=} sName * @param {string=} sName
@ -4751,7 +4761,7 @@ EmailModel.prototype.inputoTagLine = function ()
{ {
return 0 < this.name.length ? this.name + ' (' + this.email + ')' : this.email; return 0 < this.name.length ? this.name + ' (' + this.email + ')' : this.email;
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -4969,7 +4979,7 @@ PopupsDomainViewModel.prototype.clearForm = function ()
this.smtpAuth(true); this.smtpAuth(true);
this.whiteList(''); this.whiteList('');
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5108,7 +5118,7 @@ PopupsPluginViewModel.prototype.onBuild = function ()
return bResult; return bResult;
}); });
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5224,7 +5234,7 @@ PopupsActivateViewModel.prototype.validateSubscriptionKey = function ()
{ {
var sValue = this.key(); var sValue = this.key();
return '' === sValue || !!/^RL[\d]+-[A-Z0-9\-]+Z$/.test(Utils.trim(sValue)); return '' === sValue || !!/^RL[\d]+-[A-Z0-9\-]+Z$/.test(Utils.trim(sValue));
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5284,7 +5294,7 @@ PopupsLanguagesViewModel.prototype.changeLanguage = function (sLang)
RL.data().mainLanguage(sLang); RL.data().mainLanguage(sLang);
this.cancelCommand(); this.cancelCommand();
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5404,7 +5414,7 @@ PopupsAskViewModel.prototype.onBuild = function ()
}); });
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5491,7 +5501,7 @@ AdminLoginViewModel.prototype.onHide = function ()
{ {
this.loginFocus(false); this.loginFocus(false);
}; };
/** /**
* @param {?} oScreen * @param {?} oScreen
* *
@ -5513,7 +5523,7 @@ AdminMenuViewModel.prototype.link = function (sRoute)
{ {
return '#/' + sRoute; return '#/' + sRoute;
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractViewModel * @extends KnoinAbstractViewModel
@ -5535,7 +5545,7 @@ AdminPaneViewModel.prototype.logoutClick = function ()
RL.remote().adminLogout(function () { RL.remote().adminLogout(function () {
RL.loginAndLogoutReload(); RL.loginAndLogoutReload();
}); });
}; };
/** /**
* @constructor * @constructor
*/ */
@ -5635,7 +5645,7 @@ AdminGeneral.prototype.selectLanguage = function ()
{ {
kn.showScreenPopup(PopupsLanguagesViewModel); kn.showScreenPopup(PopupsLanguagesViewModel);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -5687,7 +5697,7 @@ AdminLogin.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -5756,7 +5766,7 @@ AdminBranding.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -5976,7 +5986,7 @@ AdminContacts.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6065,7 +6075,7 @@ AdminDomains.prototype.onDomainListChangeRequest = function ()
{ {
RL.reloadDomainList(); RL.reloadDomainList();
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6153,7 +6163,7 @@ AdminSecurity.prototype.phpInfoLink = function ()
{ {
return RL.link().phpInfo(); return RL.link().phpInfo();
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6269,7 +6279,7 @@ AdminSocial.prototype.onBuild = function ()
}, 50); }, 50);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6366,7 +6376,7 @@ AdminPlugins.prototype.onPluginDisableRequest = function (sResult, oData)
RL.reloadPluginList(); RL.reloadPluginList();
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6470,7 +6480,7 @@ AdminPackages.prototype.installPackage = function (oPackage)
RL.remote().packageInstall(this.requestHelper(oPackage, true), oPackage); RL.remote().packageInstall(this.requestHelper(oPackage, true), oPackage);
} }
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6521,7 +6531,7 @@ AdminLicensing.prototype.licenseExpiredMomentValue = function ()
{ {
var oDate = moment.unix(this.licenseExpired()); var oDate = moment.unix(this.licenseExpired());
return oDate.format('LL') + ' (' + oDate.from(moment()) + ')'; return oDate.format('LL') + ' (' + oDate.from(moment()) + ')';
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6596,7 +6606,7 @@ AbstractData.prototype.populateDataOnStart = function()
this.contactsIsAllowed(!!RL.settingsGet('ContactsIsAllowed')); this.contactsIsAllowed(!!RL.settingsGet('ContactsIsAllowed'));
}; };
/** /**
* @constructor * @constructor
* @extends AbstractData * @extends AbstractData
@ -6630,7 +6640,7 @@ _.extend(AdminDataStorage.prototype, AbstractData.prototype);
AdminDataStorage.prototype.populateDataOnStart = function() AdminDataStorage.prototype.populateDataOnStart = function()
{ {
AbstractData.prototype.populateDataOnStart.call(this); AbstractData.prototype.populateDataOnStart.call(this);
}; };
/** /**
* @constructor * @constructor
*/ */
@ -6904,7 +6914,7 @@ AbstractAjaxRemoteStorage.prototype.jsVersion = function (fCallback, sVersion)
'Version': sVersion 'Version': sVersion
}); });
}; };
/** /**
* @constructor * @constructor
* @extends AbstractAjaxRemoteStorage * @extends AbstractAjaxRemoteStorage
@ -7148,7 +7158,7 @@ AdminAjaxRemoteStorage.prototype.adminPing = function (fCallback)
{ {
this.defaultRequest(fCallback, 'AdminPing'); this.defaultRequest(fCallback, 'AdminPing');
}; };
/** /**
* @constructor * @constructor
*/ */
@ -7214,7 +7224,7 @@ AbstractCacheStorage.prototype.setEmailsPicsHashesData = function (oData)
{ {
this.oEmailsPicsHashes = oData; this.oEmailsPicsHashes = oData;
}; };
/** /**
* @constructor * @constructor
* @extends AbstractCacheStorage * @extends AbstractCacheStorage
@ -7225,7 +7235,7 @@ function AdminCacheStorage()
} }
_.extend(AdminCacheStorage.prototype, AbstractCacheStorage.prototype); _.extend(AdminCacheStorage.prototype, AbstractCacheStorage.prototype);
/** /**
* @param {Array} aViewModels * @param {Array} aViewModels
* @constructor * @constructor
@ -7403,7 +7413,7 @@ AbstractSettings.prototype.routes = function ()
['', oRules] ['', oRules]
]; ];
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractScreen * @extends KnoinAbstractScreen
@ -7418,7 +7428,7 @@ _.extend(AdminLoginScreen.prototype, KnoinAbstractScreen.prototype);
AdminLoginScreen.prototype.onShow = function () AdminLoginScreen.prototype.onShow = function ()
{ {
RL.setTitle(''); RL.setTitle('');
}; };
/** /**
* @constructor * @constructor
* @extends AbstractSettings * @extends AbstractSettings
@ -7438,7 +7448,7 @@ AdminSettingsScreen.prototype.onShow = function ()
// AbstractSettings.prototype.onShow.call(this); // AbstractSettings.prototype.onShow.call(this);
RL.setTitle(''); RL.setTitle('');
}; };
/** /**
* @constructor * @constructor
* @extends KnoinAbstractBoot * @extends KnoinAbstractBoot
@ -7758,7 +7768,7 @@ AbstractApp.prototype.bootstart = function ()
ssm.ready(); ssm.ready();
}; };
/** /**
* @constructor * @constructor
* @extends AbstractApp * @extends AbstractApp
@ -7997,7 +8007,7 @@ AdminApp.prototype.bootstart = function ()
* @type {AdminApp} * @type {AdminApp}
*/ */
RL = new AdminApp(); RL = new AdminApp();
$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile'); $html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile');
$window.keydown(Utils.killCtrlAandS).keyup(Utils.killCtrlAandS); $window.keydown(Utils.killCtrlAandS).keyup(Utils.killCtrlAandS);
@ -8044,9 +8054,9 @@ window['__RLBOOT'] = function (fCall) {
window['__RLBOOT'] = null; window['__RLBOOT'] = null;
}); });
}; };
if (window.SimplePace) { if (window.SimplePace) {
window.SimplePace.add(10); window.SimplePace.add(10);
} }
}(window, jQuery, ko, crossroads, hasher, _)); }(window, jQuery, ko, crossroads, hasher, _));

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long