Fixed Opening an email with specific content „hangs” RainLoop in the browser (Closes #308)

Code refactoring
This commit is contained in:
RainLoop Team 2014-09-05 19:53:44 +04:00
parent af43329902
commit 7a374ebe03
40 changed files with 1100 additions and 181 deletions

View file

@ -25,12 +25,12 @@
Cache = require('Storage:RainLoop:Cache'),
Remote = require('Storage:RainLoop:Remote'),
EmailModel = require('Model:Email'),
FolderModel = require('Model:Folder'),
MessageModel = require('Model:Message'),
AccountModel = require('Model:Account'),
IdentityModel = require('Model:Identity'),
OpenPgpKeyModel = require('Model:OpenPgpKey'),
EmailModel = require('Model/Email'),
FolderModel = require('Model/Folder'),
MessageModel = require('Model/Message'),
AccountModel = require('Model/Account'),
IdentityModel = require('Model/Identity'),
OpenPgpKeyModel = require('Model/OpenPgpKey'),
AbstractApp = require('App:Abstract')
;
@ -1298,19 +1298,20 @@
{
this.setTitle(Utils.i18n('TITLES/LOADING'));
this.folders(_.bind(function (bValue) {
require.ensure([], function () {
if (bValue)
{
require.ensure([], function () {
self.folders(_.bind(function (bValue) {
kn.hideLoading();
kn.hideLoading();
if (bValue)
{
if (window.$LAB && window.crypto && window.crypto.getRandomValues && Settings.capa(Enums.Capa.OpenPGP))
{
window.$LAB.script(window.openpgp ? '' : LinkBuilder.openPgpJs()).wait(function () {
if (window.openpgp)
{
Data.openpgp = window.openpgp;
Data.openpgpKeyring = new window.openpgp.Keyring();
Data.capaOpenPGP(true);
@ -1400,21 +1401,20 @@
self.initLayoutResizer('#rl-left', '#rl-right', Enums.ClientSideKeyName.FolderListSize);
});
}
});
}
else
{
kn.hideLoading();
}
else
{
self.bootstartLoginScreen();
}
self.bootstartLoginScreen();
}
if (window.SimplePace)
{
window.SimplePace.set(100);
}
if (window.SimplePace)
{
window.SimplePace.set(100);
}
}, this));
}, self));
});
}
else
{

View file

@ -15,26 +15,25 @@
Utils = require('Common/Utils'),
Enums = require('Common/Enums'),
EmailModel = require('Model:Email')
EmailModel = require('Model/Email')
;
Globals.__APP = App;
Globals.__APP__ = App;
Plugins.__boot = App;
Plugins.__remote = App.remote();
Plugins.__data = App.data();
Globals.$win
.keydown(Utils.killCtrlAandS)
.keyup(Utils.killCtrlAandS)
.unload(function () {
Globals.bUnload = true;
})
;
Globals.$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile');
Globals.$win.keydown(Utils.killCtrlAandS).keyup(Utils.killCtrlAandS);
Globals.$win.unload(function () {
Globals.bUnload = true;
});
Globals.$html.on('click.dropdown.data-api', function () {
Utils.detectDropdownVisibility();
});
Globals.$html
.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile')
.on('click.dropdown.data-api', function () {
Utils.detectDropdownVisibility();
})
;
// export
window['rl'] = window['rl'] || {};
@ -49,7 +48,6 @@
window['__APP_BOOT'] = function (fCall) {
// boot
$(function () {
if (window['rainloopTEMPLATES'] && window['rainloopTEMPLATES'][0])
@ -59,7 +57,11 @@
_.delay(function () {
App.bootstart();
Globals.$html.removeClass('no-js rl-booted-trigger').addClass('rl-booted');
Globals.$html
.removeClass('no-js rl-booted-trigger')
.addClass('rl-booted')
;
}, 10);
}

View file

@ -118,7 +118,7 @@
/**
* @type {*}
*/
Globals.__APP = null;
Globals.__APP__ = null;
/**
* @type {Object}

View file

@ -6,6 +6,7 @@
var
_ = require('_'),
Globals = require('Common/Globals'),
Utils = require('Common/Utils')
;
@ -14,19 +15,15 @@
*/
function Plugins()
{
this.__boot = null;
this.__data = null;
this.__remote = null;
this.oSettings = require('Storage:Settings');
this.oViewModelsHooks = {};
this.oSimpleHooks = {};
}
Plugins.prototype.__boot = null;
Plugins.prototype.__data = null;
Plugins.prototype.__remote = null;
/**
* @type {Object}
*/
Plugins.prototype.oSettings = {};
/**
* @type {Object}
@ -90,9 +87,9 @@
*/
Plugins.prototype.remoteRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions)
{
if (this.__remote)
if (Globals.__APP__)
{
this.__remote.defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions);
Globals.__APP__.remote().defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions);
}
};

View file

@ -10,6 +10,7 @@
_ = require('_'),
$ = require('$'),
ko = require('ko'),
Autolinker = require('Autolinker'),
Enums = require('Common/Enums'),
Consts = require('Common/Consts'),
@ -146,7 +147,7 @@
oEmailModel = null,
sEmail = sMailToUrl.replace(/\?.+$/, ''),
sQueryString = sMailToUrl.replace(/^[^\?]*\?/, ''),
EmailModel = require('Model:Email')
EmailModel = require('Model/Email')
;
oEmailModel = new EmailModel();
@ -1517,10 +1518,10 @@
/**
* @param {string} sPlain
* @param {boolean} bLinkify = false
* @param {boolean} bFindEmailAndLinks = false
* @return {string}
*/
Utils.plainToHtml = function (sPlain, bLinkify)
Utils.plainToHtml = function (sPlain, bFindEmailAndLinks)
{
sPlain = sPlain.toString().replace(/\r/g, '');
@ -1551,9 +1552,16 @@
}
else if (!bStart && bIn)
{
bIn = false;
aNextText.push('~~~/blockquote~~~');
aNextText.push(sLine);
if ('' !== sLine)
{
bIn = false;
aNextText.push('~~~/blockquote~~~');
aNextText.push(sLine);
}
else
{
aNextText.push(sLine);
}
}
else if (bStart && bIn)
{
@ -1578,6 +1586,7 @@
sPlain = aText.join("\n");
sPlain = sPlain
// .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
.replace(/&/g, '&')
.replace(/>/g, '&gt;').replace(/</g, '&lt;')
.replace(/~~~blockquote~~~[\s]*/g, '<blockquote>')
@ -1585,7 +1594,7 @@
.replace(/[\-_~]{10,}/g, '<hr />')
.replace(/\n/g, '<br />');
return bLinkify ? Utils.linkify(sPlain) : sPlain;
return bFindEmailAndLinks ? Utils.findEmailAndLinks(sPlain) : sPlain;
};
window.rainloop_Utils_htmlToPlain = Utils.htmlToPlain;
@ -1595,17 +1604,25 @@
* @param {string} sHtml
* @return {string}
*/
Utils.linkify = function (sHtml)
Utils.findEmailAndLinks = function (sHtml)
{
if ($.fn && $.fn.linkify)
{
sHtml = Globals.$div.html(sHtml.replace(/&amp;/ig, 'amp_amp_12345_amp_amp'))
.linkify()
.find('.linkified').removeClass('linkified').end()
.html()
.replace(/amp_amp_12345_amp_amp/g, '&amp;')
;
}
sHtml = Autolinker.link(sHtml, {
'newWindow': true,
'stripPrefix': false,
'urls': true,
'email': true,
'twitter': false
});
// if ($.fn && $.fn.linkify)
// {
// sHtml = Globals.$div.html(sHtml.replace(/&amp;/ig, 'amp_amp_12345_amp_amp'))
// .linkify()
// .find('.linkified').removeClass('linkified').end()
// .html()
// .replace(/amp_amp_12345_amp_amp/g, '&amp;')
// ;
// }
return sHtml;
};
@ -1936,6 +1953,29 @@
}
};
/**
* @param {string} sLanguage
* @param {Function=} fDone
* @param {Function=} fFail
* @param {Function=} fAllways
*/
Utils.reloadLanguage = function (sLanguage, fDone, fFail, fAllways)
{
$.ajax({
'url': require('Common/LinkBuilder').langLink(sLanguage),
'dataType': 'script',
'cache': true
})
.done(function () {
Utils.i18nReload();
(fDone || Utils.emptyFunction)();
})
.fail(fFail || Utils.emptyFunction)
.always(fAllways || Utils.emptyFunction)
;
};
module.exports = Utils;
}());

5
dev/External/ko.js vendored
View file

@ -568,7 +568,7 @@
var
Utils = require('Common/Utils'),
EmailModel = require('Model:Email'),
EmailModel = require('Model/Email'),
$oEl = $(oElement),
fValue = fValueAccessor(),
@ -600,7 +600,6 @@
{
oEmail = new EmailModel();
oEmail.mailsoParse(sValue);
oEmail.clearDuplicateName();
return [oEmail.toLine(false), oEmail];
}
@ -642,7 +641,7 @@
var
Utils = require('Common/Utils'),
ContactTagModel = require('Model:ContactTag'),
ContactTagModel = require('Model/ContactTag'),
$oEl = $(oElement),
fValue = fValueAccessor(),

View file

@ -8,7 +8,7 @@
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
FilterConditionModel = require('Model:FilterCondition')
FilterConditionModel = require('Model/FilterCondition')
;
/**

View file

@ -15,8 +15,8 @@
Globals = require('Common/Globals'),
LinkBuilder = require('Common/LinkBuilder'),
EmailModel = require('Model:Email'),
AttachmentModel = require('Model:Attachment')
EmailModel = require('Model/Email'),
AttachmentModel = require('Model/Attachment')
;
/**
@ -431,8 +431,8 @@
MessageModel.prototype.initUpdateByMessageJson = function (oJsonMessage)
{
var
Data = require('Storage:RainLoop:Data'),
bResult = false,
Data = require('Storage:RainLoop:Data'),
iPriority = Enums.MessagePriority.Normal
;
@ -1156,7 +1156,7 @@
try
{
mPgpMessage = window.openpgp.cleartext.readArmored(this.plainRaw);
mPgpMessage = Data.openpgp.cleartext.readArmored(this.plainRaw);
if (mPgpMessage && mPgpMessage.getText)
{
this.pgpSignedVerifyStatus(
@ -1226,7 +1226,7 @@
try
{
mPgpMessage = window.openpgp.message.readArmored(this.plainRaw);
mPgpMessage = Data.openpgp.message.readArmored(this.plainRaw);
if (mPgpMessage && oPrivateKey && mPgpMessage.decrypt)
{
this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.Unverified);

View file

@ -47,7 +47,7 @@
SettingsContacts.prototype.onBuild = function ()
{
Data.contactsAutosave.subscribe(function (bValue) {
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'ContactsAutosave': bValue ? '1' : '0'
});
});

View file

@ -30,7 +30,7 @@
SettingsFilters.prototype.addFilter = function ()
{
var
FilterModel = require('Model:Filter')
FilterModel = require('Model/Filter')
;
require('App:Knoin').showScreenPopup(

View file

@ -76,28 +76,23 @@
self.languageTrigger(Enums.SaveSettingsStep.Animate);
$.ajax({
'url': LinkBuilder.langLink(sValue),
'dataType': 'script',
'cache': true
}).done(function() {
Utils.i18nReload();
Utils.reloadLanguage(sValue, function() {
self.languageTrigger(Enums.SaveSettingsStep.TrueResult);
}).fail(function() {
}, function() {
self.languageTrigger(Enums.SaveSettingsStep.FalseResult);
}).always(function() {
}, function() {
_.delay(function () {
self.languageTrigger(Enums.SaveSettingsStep.Idle);
}, 1000);
});
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'Language': sValue
});
});
Data.editorDefaultType.subscribe(function (sValue) {
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'EditorDefaultType': sValue
});
});
@ -109,20 +104,20 @@
});
Data.showImages.subscribe(function (bValue) {
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'ShowImages': bValue ? '1' : '0'
});
});
Data.interfaceAnimation.subscribe(function (sValue) {
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'InterfaceAnimation': sValue
});
});
Data.useDesktopNotifications.subscribe(function (bValue) {
Utils.timeOutAction('SaveDesktopNotifications', function () {
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'DesktopNotifications': bValue ? '1' : '0'
});
}, 3000);
@ -130,7 +125,7 @@
Data.replySameFolder.subscribe(function (bValue) {
Utils.timeOutAction('SaveReplySameFolder', function () {
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'ReplySameFolder': bValue ? '1' : '0'
});
}, 3000);
@ -140,7 +135,7 @@
Data.messageList([]);
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'UseThreads': bValue ? '1' : '0'
});
});
@ -149,13 +144,13 @@
Data.messageList([]);
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'Layout': nValue
});
});
Data.useCheckboxesInList.subscribe(function (bValue) {
Remote.saveSettings(Utils.emptyFunction, {
Remote.saveSettings(null, {
'UseCheckboxesInList': bValue ? '1' : '0'
});
});

View file

@ -29,8 +29,8 @@
this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100});
this.oLastAjax = null;
this.iTimer = 0;
this.oThemeAjaxRequest = null;
Data.theme.subscribe(function (sValue) {
@ -62,12 +62,12 @@
window.clearTimeout(self.iTimer);
self.themeTrigger(Enums.SaveSettingsStep.Animate);
if (this.oLastAjax && this.oLastAjax.abort)
if (this.oThemeAjaxRequest && this.oThemeAjaxRequest.abort)
{
this.oLastAjax.abort();
this.oThemeAjaxRequest.abort();
}
this.oLastAjax = $.ajax({
this.oThemeAjaxRequest = $.ajax({
'url': sUrl,
'dataType': 'json'
}).done(function(aData) {
@ -103,7 +103,7 @@
self.themeTrigger(Enums.SaveSettingsStep.Idle);
}, 1000);
self.oLastAjax = null;
self.oThemeAjaxRequest = null;
});
}

View file

@ -64,9 +64,9 @@
if (Consts.Values.TokenErrorLimit < Globals.iTokenErrorCount)
{
if (Globals.__APP)
if (Globals.__APP__)
{
Globals.__APP.loginAndLogoutReload(true);
Globals.__APP__.loginAndLogoutReload(true);
}
}
@ -77,9 +77,9 @@
window.__rlah_clear();
}
if (Globals.__APP)
if (Globals.__APP__)
{
Globals.__APP.loginAndLogoutReload(true);
Globals.__APP__.loginAndLogoutReload(true);
}
}
}

View file

@ -22,7 +22,7 @@
kn = require('App:Knoin'),
MessageModel = require('Model:Message'),
MessageModel = require('Model/Message'),
LocalStorage = require('Storage:LocalStorage'),
AbstractData = require('Storage:Abstract:Data')
@ -323,10 +323,7 @@
if (Enums.Layout.NoPreview === this.layout() &&
-1 < window.location.hash.indexOf('message-preview'))
{
if (Globals.__APP)
{
Globals.__APP.historyBack();
}
require('App:RainLoop').historyBack();
}
}
else if (Enums.Layout.NoPreview === this.layout())
@ -443,6 +440,7 @@
// other
this.capaOpenPGP = ko.observable(false);
this.openpgpkeys = ko.observableArray([]);
this.openpgp = null;
this.openpgpKeyring = null;
this.openpgpkeysPublic = this.openpgpkeys.filter(function (oItem) {
@ -782,7 +780,6 @@
};
/**
* @private
* @param {Object} oMessageTextBody
*/
DataStorage.prototype.initBlockquoteSwitcher = function (oMessageTextBody)
@ -795,22 +792,24 @@
if ($oList && 0 < $oList.length)
{
$oList.each(function () {
var $self = $(this), iH = $self.height();
if (0 === iH || 100 < iH)
{
$self.addClass('rl-bq-switcher hidden-bq');
$('<span class="rlBlockquoteSwitcher"><i class="icon-ellipsis" /></span>')
.insertBefore($self)
.click(function () {
$self.toggleClass('hidden-bq');
Utils.windowResize();
})
.after('<br />')
.before('<br />')
;
}
});
_.delay(function () {
$oList.each(function () {
var $self = $(this), iH = $self.height();
if (0 === iH || 150 < iH)
{
$self.addClass('rl-bq-switcher hidden-bq');
$('<span class="rlBlockquoteSwitcher"><i class="icon-ellipsis" /></span>')
.insertBefore($self)
.click(function () {
$self.toggleClass('hidden-bq');
Utils.windowResize();
})
.after('<br />')
.before('<br />')
;
}
});
}, 100);
}
}
};
@ -818,6 +817,7 @@
DataStorage.prototype.setMessage = function (oData, bCached)
{
var
self = this,
bIsHtml = false,
bHasExternals = false,
bHasInternals = false,
@ -908,7 +908,7 @@
}
oBody
.html(Utils.linkify(sResultHtml))
.html(Utils.findEmailAndLinks(sResultHtml))
.addClass('b-text-part ' + (bIsHtml ? 'html' : 'plain'))
;
@ -961,10 +961,7 @@
Cache.initMessageFlagsFromCache(oMessage);
if (oMessage.unseen())
{
if (Globals.__APP)
{
Globals.__APP.setMessageSeen(oMessage);
}
require('App:RainLoop').setMessageSeen(oMessage);
}
Utils.windowResize();
@ -991,6 +988,7 @@
DataStorage.prototype.findPublicKeysByEmail = function (sEmail)
{
var self = this;
return _.compact(_.map(this.openpgpkeysPublic(), function (oItem) {
var oKey = null;
@ -998,7 +996,7 @@
{
try
{
oKey = window.openpgp.key.readArmored(oItem.armor);
oKey = self.openpgp.key.readArmored(oItem.armor);
if (oKey && !oKey.err && oKey.keys && oKey.keys[0])
{
return oKey.keys[0];
@ -1020,6 +1018,7 @@
DataStorage.prototype.findPrivateKeyByEmail = function (sEmail, sPassword)
{
var
self = this,
oPrivateKey = null,
oKey = _.find(this.openpgpkeysPrivate(), function (oItem) {
return oItem && sEmail === oItem.email;
@ -1030,7 +1029,7 @@
{
try
{
oPrivateKey = window.openpgp.key.readArmored(oKey.armor);
oPrivateKey = self.openpgp.key.readArmored(oKey.armor);
if (oPrivateKey && !oPrivateKey.err && oPrivateKey.keys && oPrivateKey.keys[0])
{
oPrivateKey = oPrivateKey.keys[0];

View file

@ -381,10 +381,7 @@
}
else if (Data.useThreads())
{
if (Globals.__APP)
{
Globals.__APP.reloadFlagsCurrentMessageListAndMessageFromCache();
}
require('App:RainLoop').reloadFlagsCurrentMessageListAndMessageFromCache();
}
};

View file

@ -337,18 +337,16 @@
_.delay(function () {
Data.language.subscribe(function (sValue) {
self.langRequest(true);
$.ajax({
'url': LinkBuilder.langLink(sValue),
'dataType': 'script',
'cache': true
}).done(function() {
Utils.reloadLanguage(sValue, function() {
self.bSendLanguage = true;
Utils.i18nReload();
$.cookie('rllang', Data.language(), {'expires': 30});
}).always(function() {
$.cookie('rllang', sValue, {'expires': 30});
}, null, function() {
self.langRequest(false);
});
});
}, 50);

View file

@ -4,7 +4,6 @@
'use strict';
var
window = require('window'),
_ = require('_'),
ko = require('ko'),
key = require('key'),
@ -14,7 +13,7 @@
Data = require('Storage:RainLoop:Data'),
EmailModel = require('Model:Email'),
EmailModel = require('Model/Email'),
kn = require('App:Knoin'),
KnoinAbstractViewModel = require('Knoin:AbstractViewModel')
@ -114,19 +113,19 @@
if (oPrivateKey && 0 === aPublicKeys.length)
{
self.resultCallback(
window.openpgp.signClearMessage([oPrivateKey], self.text())
Data.openpgp.signClearMessage([oPrivateKey], self.text())
);
}
else if (oPrivateKey && 0 < aPublicKeys.length)
{
self.resultCallback(
window.openpgp.signAndEncryptMessage(aPublicKeys, oPrivateKey, self.text())
Data.openpgp.signAndEncryptMessage(aPublicKeys, oPrivateKey, self.text())
);
}
else if (!oPrivateKey && 0 < aPublicKeys.length)
{
self.resultCallback(
window.openpgp.encryptMessage(aPublicKeys, self.text())
Data.openpgp.encryptMessage(aPublicKeys, self.text())
);
}
}

View file

@ -25,7 +25,7 @@
Cache = require('Storage:RainLoop:Cache'),
Remote = require('Storage:RainLoop:Remote'),
ComposeAttachmentModel = require('Model:ComposeAttachment'),
ComposeAttachmentModel = require('Model/ComposeAttachment'),
kn = require('App:Knoin'),
KnoinAbstractViewModel = require('Knoin:AbstractViewModel')

View file

@ -20,10 +20,10 @@
Data = require('Storage:RainLoop:Data'),
Remote = require('Storage:RainLoop:Remote'),
EmailModel = require('Model:Email'),
ContactModel = require('Model:Contact'),
ContactTagModel = require('Model:ContactTag'),
ContactPropertyModel = require('Model:ContactProperty'),
EmailModel = require('Model/Email'),
ContactModel = require('Model/Contact'),
ContactTagModel = require('Model/ContactTag'),
ContactPropertyModel = require('Model/ContactProperty'),
kn = require('App:Knoin'),
KnoinAbstractViewModel = require('Knoin:AbstractViewModel')

View file

@ -22,7 +22,7 @@
{
KnoinAbstractViewModel.call(this, 'Popups', 'PopupsLanguages');
this.Data = Globals.__APP.data(); // TODO
this.Data = Globals.__APP__.data(); // TODO
this.exp = ko.observable(false);

View file

@ -4,7 +4,6 @@
'use strict';
var
window = require('window'),
_ = require('_'),
ko = require('ko'),
@ -62,8 +61,8 @@
this.submitRequest(true);
_.delay(function () {
// mKeyPair = window.openpgp.generateKeyPair(1, Utils.pInt(self.keyBitLength()), sUserID, Utils.trim(self.password()));
mKeyPair = window.openpgp.generateKeyPair({
// mKeyPair = Data.openpgp.generateKeyPair(1, Utils.pInt(self.keyBitLength()), sUserID, Utils.trim(self.password()));
mKeyPair = Data.openpgp.generateKeyPair({
'userId': sUserID,
'numBits': Utils.pInt(self.keyBitLength()),
'passphrase': Utils.trim(self.password())