diff --git a/dev/Apps/RainLoopApp.js b/dev/Apps/RainLoopApp.js index b94a981d8..8aa5d60db 100644 --- a/dev/Apps/RainLoopApp.js +++ b/dev/Apps/RainLoopApp.js @@ -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 { diff --git a/dev/Boot.js b/dev/Boot.js index 7859b25d7..eec1bff40 100644 --- a/dev/Boot.js +++ b/dev/Boot.js @@ -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); } diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index 7f4e4f65e..ce60cbb66 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -118,7 +118,7 @@ /** * @type {*} */ - Globals.__APP = null; + Globals.__APP__ = null; /** * @type {Object} diff --git a/dev/Common/Plugins.js b/dev/Common/Plugins.js index da37b5223..c25564796 100644 --- a/dev/Common/Plugins.js +++ b/dev/Common/Plugins.js @@ -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); } }; diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index 702b94cc4..660d5c0de 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -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, '>').replace(/') @@ -1585,7 +1594,7 @@ .replace(/[\-_~]{10,}/g, '
') .replace(/\n/g, '
'); - 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(/&/ig, 'amp_amp_12345_amp_amp')) - .linkify() - .find('.linkified').removeClass('linkified').end() - .html() - .replace(/amp_amp_12345_amp_amp/g, '&') - ; - } + sHtml = Autolinker.link(sHtml, { + 'newWindow': true, + 'stripPrefix': false, + 'urls': true, + 'email': true, + 'twitter': false + }); + +// if ($.fn && $.fn.linkify) +// { +// sHtml = Globals.$div.html(sHtml.replace(/&/ig, 'amp_amp_12345_amp_amp')) +// .linkify() +// .find('.linkified').removeClass('linkified').end() +// .html() +// .replace(/amp_amp_12345_amp_amp/g, '&') +// ; +// } 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; }()); \ No newline at end of file diff --git a/dev/External/ko.js b/dev/External/ko.js index fd2cbc7e6..a549085e2 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -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(), diff --git a/dev/Models/AccountModel.js b/dev/Model/Account.js similarity index 100% rename from dev/Models/AccountModel.js rename to dev/Model/Account.js diff --git a/dev/Models/AttachmentModel.js b/dev/Model/Attachment.js similarity index 100% rename from dev/Models/AttachmentModel.js rename to dev/Model/Attachment.js diff --git a/dev/Models/ComposeAttachmentModel.js b/dev/Model/ComposeAttachment.js similarity index 100% rename from dev/Models/ComposeAttachmentModel.js rename to dev/Model/ComposeAttachment.js diff --git a/dev/Models/ContactModel.js b/dev/Model/Contact.js similarity index 100% rename from dev/Models/ContactModel.js rename to dev/Model/Contact.js diff --git a/dev/Models/ContactPropertyModel.js b/dev/Model/ContactProperty.js similarity index 100% rename from dev/Models/ContactPropertyModel.js rename to dev/Model/ContactProperty.js diff --git a/dev/Models/ContactTagModel.js b/dev/Model/ContactTag.js similarity index 100% rename from dev/Models/ContactTagModel.js rename to dev/Model/ContactTag.js diff --git a/dev/Models/EmailModel.js b/dev/Model/Email.js similarity index 100% rename from dev/Models/EmailModel.js rename to dev/Model/Email.js diff --git a/dev/Models/FilterModel.js b/dev/Model/Filter.js similarity index 97% rename from dev/Models/FilterModel.js rename to dev/Model/Filter.js index 54f0a26b0..88f6da5d3 100644 --- a/dev/Models/FilterModel.js +++ b/dev/Model/Filter.js @@ -8,7 +8,7 @@ Enums = require('Common/Enums'), Utils = require('Common/Utils'), - FilterConditionModel = require('Model:FilterCondition') + FilterConditionModel = require('Model/FilterCondition') ; /** diff --git a/dev/Models/FilterConditionModel.js b/dev/Model/FilterCondition.js similarity index 100% rename from dev/Models/FilterConditionModel.js rename to dev/Model/FilterCondition.js diff --git a/dev/Models/FolderModel.js b/dev/Model/Folder.js similarity index 100% rename from dev/Models/FolderModel.js rename to dev/Model/Folder.js diff --git a/dev/Models/IdentityModel.js b/dev/Model/Identity.js similarity index 100% rename from dev/Models/IdentityModel.js rename to dev/Model/Identity.js diff --git a/dev/Models/MessageModel.js b/dev/Model/Message.js similarity index 99% rename from dev/Models/MessageModel.js rename to dev/Model/Message.js index 33a380f90..718db9f50 100644 --- a/dev/Models/MessageModel.js +++ b/dev/Model/Message.js @@ -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); diff --git a/dev/Models/OpenPgpKeyModel.js b/dev/Model/OpenPgpKey.js similarity index 100% rename from dev/Models/OpenPgpKeyModel.js rename to dev/Model/OpenPgpKey.js diff --git a/dev/Settings/App/SettingsContacts.js b/dev/Settings/App/SettingsContacts.js index d0993a438..d2ae55609 100644 --- a/dev/Settings/App/SettingsContacts.js +++ b/dev/Settings/App/SettingsContacts.js @@ -47,7 +47,7 @@ SettingsContacts.prototype.onBuild = function () { Data.contactsAutosave.subscribe(function (bValue) { - Remote.saveSettings(Utils.emptyFunction, { + Remote.saveSettings(null, { 'ContactsAutosave': bValue ? '1' : '0' }); }); diff --git a/dev/Settings/App/SettingsFilters.js b/dev/Settings/App/SettingsFilters.js index 244d3666c..1ec2c476b 100644 --- a/dev/Settings/App/SettingsFilters.js +++ b/dev/Settings/App/SettingsFilters.js @@ -30,7 +30,7 @@ SettingsFilters.prototype.addFilter = function () { var - FilterModel = require('Model:Filter') + FilterModel = require('Model/Filter') ; require('App:Knoin').showScreenPopup( diff --git a/dev/Settings/App/SettingsGeneral.js b/dev/Settings/App/SettingsGeneral.js index 74a6b7ca7..6682dbbc4 100644 --- a/dev/Settings/App/SettingsGeneral.js +++ b/dev/Settings/App/SettingsGeneral.js @@ -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' }); }); diff --git a/dev/Settings/App/SettingsThemes.js b/dev/Settings/App/SettingsThemes.js index bb10a685a..ab3880f42 100644 --- a/dev/Settings/App/SettingsThemes.js +++ b/dev/Settings/App/SettingsThemes.js @@ -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; }); } diff --git a/dev/Storages/AbstractRemoteStorage.js b/dev/Storages/AbstractRemoteStorage.js index 356ba6d33..0759e1743 100644 --- a/dev/Storages/AbstractRemoteStorage.js +++ b/dev/Storages/AbstractRemoteStorage.js @@ -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); } } } diff --git a/dev/Storages/DataStorage.js b/dev/Storages/DataStorage.js index 8e5947c78..8aa50ed28 100644 --- a/dev/Storages/DataStorage.js +++ b/dev/Storages/DataStorage.js @@ -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'); - $('') - .insertBefore($self) - .click(function () { - $self.toggleClass('hidden-bq'); - Utils.windowResize(); - }) - .after('
') - .before('
') - ; - } - }); + _.delay(function () { + $oList.each(function () { + var $self = $(this), iH = $self.height(); + if (0 === iH || 150 < iH) + { + $self.addClass('rl-bq-switcher hidden-bq'); + $('') + .insertBefore($self) + .click(function () { + $self.toggleClass('hidden-bq'); + Utils.windowResize(); + }) + .after('
') + .before('
') + ; + } + }); + }, 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]; diff --git a/dev/Storages/RemoteStorage.js b/dev/Storages/RemoteStorage.js index d8b587667..333cf400e 100644 --- a/dev/Storages/RemoteStorage.js +++ b/dev/Storages/RemoteStorage.js @@ -381,10 +381,7 @@ } else if (Data.useThreads()) { - if (Globals.__APP) - { - Globals.__APP.reloadFlagsCurrentMessageListAndMessageFromCache(); - } + require('App:RainLoop').reloadFlagsCurrentMessageListAndMessageFromCache(); } }; diff --git a/dev/ViewModels/LoginViewModel.js b/dev/ViewModels/LoginViewModel.js index b9330a60d..2ef141401 100644 --- a/dev/ViewModels/LoginViewModel.js +++ b/dev/ViewModels/LoginViewModel.js @@ -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); diff --git a/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js b/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js index 2e7d531f9..1de6a3f43 100644 --- a/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js +++ b/dev/ViewModels/Popups/PopupsComposeOpenPgpViewModel.js @@ -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()) ); } } diff --git a/dev/ViewModels/Popups/PopupsComposeViewModel.js b/dev/ViewModels/Popups/PopupsComposeViewModel.js index df419f739..4a6fcb10d 100644 --- a/dev/ViewModels/Popups/PopupsComposeViewModel.js +++ b/dev/ViewModels/Popups/PopupsComposeViewModel.js @@ -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') diff --git a/dev/ViewModels/Popups/PopupsContactsViewModel.js b/dev/ViewModels/Popups/PopupsContactsViewModel.js index 1af7befeb..b7449d4aa 100644 --- a/dev/ViewModels/Popups/PopupsContactsViewModel.js +++ b/dev/ViewModels/Popups/PopupsContactsViewModel.js @@ -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') diff --git a/dev/ViewModels/Popups/PopupsLanguagesViewModel.js b/dev/ViewModels/Popups/PopupsLanguagesViewModel.js index 48543f7a9..89750be23 100644 --- a/dev/ViewModels/Popups/PopupsLanguagesViewModel.js +++ b/dev/ViewModels/Popups/PopupsLanguagesViewModel.js @@ -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); diff --git a/dev/ViewModels/Popups/PopupsNewOpenPgpKeyViewModel.js b/dev/ViewModels/Popups/PopupsNewOpenPgpKeyViewModel.js index 1c46ba562..dc6394044 100644 --- a/dev/ViewModels/Popups/PopupsNewOpenPgpKeyViewModel.js +++ b/dev/ViewModels/Popups/PopupsNewOpenPgpKeyViewModel.js @@ -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()) diff --git a/gulpfile.js b/gulpfile.js index d79ce5cdb..e70c409e6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -144,7 +144,7 @@ cfg.paths.js = { 'vendors/jquery-lazyload/jquery.lazyload.min.js', 'vendors/jquery-nanoscroller/jquery.nanoscroller-0.7.min.js', 'vendors/jquery-wakeup/jquery.wakeup.min.js', - 'vendors/jquery-linkify/jquery.linkify.min.js', +// 'vendors/jquery-linkify/jquery.linkify.min.js', 'vendors/inputosaurus/inputosaurus.min.js', 'vendors/moment/min/moment.min.js ', 'vendors/routes/signals.min.js', @@ -154,6 +154,7 @@ cfg.paths.js = { 'vendors/knockout-projections/knockout-projections-1.0.0.min.js', 'vendors/ssm/ssm.min.js', 'vendors/jua/jua.min.js', + 'vendors/Autolinker/Autolinker.min.js', 'vendors/jsbn/bundle.js', 'vendors/keymaster/keymaster.js', 'vendors/ifvisible/ifvisible.min.js', diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index 48c86d05d..70a7bc4b0 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -2650,13 +2650,22 @@ class Actions $bResult = false; $oConfig = $this->Config(); + $sLogin = \trim($this->GetActionParam('Login', '')); $sPassword = $this->GetActionParam('Password', ''); $sNewPassword = $this->GetActionParam('NewPassword', ''); + $this->Logger()->AddSecret($sPassword); + $this->Logger()->AddSecret($sNewPassword); + if ($oConfig->ValidatePassword($sPassword)) { - $bResult = true; + if (0 < strlen($sLogin)) + { + $oConfig->Set('security', 'admin_login', $sLogin); + } + $oConfig->SetPassword($sNewPassword); + $bResult = true; } return $this->DefaultResponse(__FUNCTION__, $bResult ? $oConfig->Save() : false); @@ -7400,6 +7409,8 @@ class Actions $mResult['Plain'] = $sPlain; // $mResult['Plain'] = 0 === \strlen($sPlain) ? '' : \MailSo\Base\HtmlUtils::ConvertPlainToHtml($sPlain); + $this->Logger()->WriteDump($mResult['Html']); + $mResult['TextHash'] = \md5($mResult['Html'].$mResult['Plain']); $mResult['TextPartIsTrimmed'] = $mResponse->TextPartIsTrimmed(); diff --git a/rainloop/v/0.0.0/app/templates/Index.html b/rainloop/v/0.0.0/app/templates/Index.html index cb5187b58..be13a044d 100644 --- a/rainloop/v/0.0.0/app/templates/Index.html +++ b/rainloop/v/0.0.0/app/templates/Index.html @@ -1,5 +1,5 @@ - + @@ -8,7 +8,7 @@ - +``` + +#### Using with the [Bower](http://bower.io) package manager: + +Command line: + +```shell +bower install Autolinker.js --save +``` + +#### Using with [Node.js](http://nodejs.org) via [npm](https://www.npmjs.org/): + +Command Line: + +```shell +npm install autolinker --save +``` + +JavaScript: + +```javascript +var Autolinker = require( 'autolinker' ); +// note: npm wants an all-lowercase package name, but the utility is a class and should be +// aliased with a captial letter +``` + + +## Usage + +Using the static `link()` method: + +```javascript +var linkedText = Autolinker.link( textToAutolink[, options] ); +``` + +Using as a class: + +```javascript +var autolinker = new Autolinker( [ options ] ); + +var linkedText = autolinker.link( textToAutoLink ); +``` + + +#### Example: + +```javascript +var linkedText = Autolinker.link( "Check out google.com", { className: "myLink" } ); +// Produces: "Check out google.com" +``` + +## Options + +These are the options which may be specified for linking. These are specified by providing an Object as the second parameter to `Autolinker.link()`. These include: + +- **newWindow** : Boolean
+ `true` to have the links should open in a new window when clicked, `false` otherwise. Defaults to `true`.

+- **stripPrefix** : Boolean
+ `true` to have the 'http://' or 'https://' and/or the 'www.' stripped from the beginning of links, `false` otherwise. Defaults to `true`.

+- **truncate** : Number
+ A number for how many characters long URLs/emails/twitter handles should be truncated to inside the text of a link. If the URL/email/twitter is over the number of characters, it will be truncated to this length by replacing the end of the string with a two period ellipsis ('..').

+ Example: a url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters may look like this: 'yahoo.com/some/long/pat..'
+- **className** : String
+ A CSS class name to add to the generated anchor tags. This class will be added to all links, as well as this class + plus "url"/"email"/"twitter" suffixes for styling url/email/twitter links differently. + + For example, if this config is provided as "myLink", then: + + 1) URL links will have the CSS classes: "myLink myLink-url"
+ 2) Email links will have the CSS classes: "myLink myLink-email", and
+ 3) Twitter links will have the CSS classes: "myLink myLink-twitter"
+ +- **urls** : Boolean
+ `true` to have URLs auto-linked, `false` to skip auto-linking of URLs. Defaults to `true`.
+- **email** : Boolean
+ `true` to have email addresses auto-linked, `false` to skip auto-linking of email addresses. Defaults to `true`.

+- **twitter** : Boolean
+ `true` to have Twitter handles auto-linked, `false` to skip auto-linking of Twitter handles. Defaults to `true`. + +For example, if you wanted to disable links from opening in new windows, you could do: + +```javascript +var linkedText = Autolinker.link( "Check out google.com", { newWindow: false } ); +// Produces: "Check out google.com" +``` + +And if you wanted to truncate the length of URLs (while also not opening in a new window), you could do: + +```javascript +var linkedText = Autolinker.link( "http://www.yahoo.com/some/long/path/to/a/file", { truncate: 25, newWindow: false } ); +// Produces: "yahoo.com/some/long/pat.." +``` + +## More Examples +One could update an entire DOM element that has unlinked text to auto-link them as such: + +```javascript +var myTextEl = document.getElementById( 'text' ); +myTextEl.innerHTML = Autolinker.link( myTextEl.innerHTML ); +``` + +Using the same pre-configured Autolinker instance in multiple locations of a codebase (usually by dependency injection): + +```javascript +var autolinker = new Autolinker( { newWindow: false, truncate: 25 } ); + +//... + +autolinker.link( "Check out http://www.yahoo.com/some/long/path/to/a/file" ); +// Produces: "Check out yahoo.com/some/long/pat.." + +//... + +autolinker.link( "Go to www.google.com" ); +// Produces: "Go to google.com" + +``` + + +## Changelog: + +### 0.11.0 + +- Allow Autolinker to link fully-capitalized URLs/Emails/Twitter handles. + +### 0.10.1 + +- Added fix to not autolink strings like "version:1.0", which were accidentally being interpreted as a protocol:domain string. + +### 0.10.0 + +- Added support for protocol-relative URLs (ex: `//google.com`, which will effectively either have the `http://` or `https://` + protocol depending on the protocol that is hosting the website) + +### 0.9.4 + +- Fixed an issue where a string in the form of `abc:def` would be autolinked as a protocol and domain name URL. Autolinker now + requires the domain name to have at least one period in it to be considered. + +### 0.9.3 + +- Fixed an issue where Twitter handles wouldn't be autolinked if they existed as the sole entity within parenthesis or brackets + (thanks [@busticated](https://github.com/busticated) for pointing this out and providing unit tests) + +### 0.9.2 + +- Fixed an issue with nested tags within an existing <a> tag, where the nested tags' inner text would be accidentally + removed from the output (thanks [@mjsabin01](https://github.com/mjsabin01)) + +### 0.9.1 + +- Added a patch to attempt to better handle extraneous </a> tags in the input string if any exist. This is for when the + input may have some invalid markup (for instance, on sites which allow user comments, blog posts, etc.). + +### 0.9.0 + +- Added better support for the processing of existing HTML in the input string. Now handles namespaced tags, and attribute names + with dashes or any other Unicode character (thanks [@aziraphale](https://github.com/aziraphale)) + +### 0.8.0 + +- Added `className` option for easily styling produced links (thanks [@busticated](https://github.com/busticated)) +- Refactored into a JS class. Autolinker can now be instantiated using: + +```javascript +var autolinker = new Autolinker( { newWindow: false, truncate: 25 } ); + +autolinker.link( "Check out http://www.yahoo.com/some/long/path/to/a/file" ); +// Produces: "Check out yahoo.com/some/long/pat.." +``` + +This allows options to be set on a single instance, and used throughout a codebase by injecting the `autolinker` instance as a dependency to the modules/classes that use it. (Note: Autolinker may still be used with the static `Autolinker.link()` method as was previously available as well.) + +### 0.7.0 + +- Changed build system to Grunt. +- Added AMD and CommonJS module loading support (ex: RequireJS, and Node.js's module loader). +- Added command line Jasmine test runner (`grunt test`) +- Upgraded Jasmine from 1.3.1 to 2.0 +- Added license header to dist files. + +(Thanks to [@busticated](https://github.com/busticated)!) + +### 0.6.1 + +- Added LICENSE file to repository. + +### 0.6.0 + +- Added options for granular control of which types are linked (urls, email addresses, and/or twitter handles). + (thanks [@aziraphale](https://github.com/aziraphale)) + +### 0.5.0 + +- Simplified the path / query string / hash processing into a single regular expression instead of 3 separate ones. +- Added support for parenthesis in URLs, such as: `en.wikipedia.org/wiki/IANA_(disambiguation)` (thanks [@dandv](https://github.com/dandv)) +- Add all known top-level domains (TLDs) (thanks [@wouter0100](https://github.com/wouter0100)) + +### 0.4.0 + +Merged pull requests from [@afeld](https://github.com/afeld): + +- strip protocol and 'www.' by default - fixes #1 +- truncate URLs from the end +- make simpler regex for detecting prefix +- remove trailing slashes from URLs, and handle periods at the end of paths +- re-use domain+TLD regexes for email matching +- add .me and .io to list of TLDs + +Thanks Aidan :) + +### 0.3.1 + +- Fixed an issue with handling nested HTML tags within anchor tags. + +### 0.3 + +- Implemented the `truncate` option. + +### 0.2 + +- Implemented autolinking Twitter handles. + +### 0.1 + +* Initial implementation, which autolinks URLs and email addresses. Working on linking Twitter handles. diff --git a/webpack.config.js b/webpack.config.js index 4f8d86c35..55fe39dd9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,6 +20,7 @@ module.exports = { extensions: ['', '.js'], alias: { "ko": __dirname + "/dev/External/ko.js", + "openpgp": __dirname + "/vendors/openpgp/openpgp-0.7.2.min.js", "Knoin:AbstractBoot": __dirname + "/dev/Knoin/KnoinAbstractBoot.js", "Knoin:AbstractScreen": __dirname + "/dev/Knoin/KnoinAbstractScreen.js", @@ -31,20 +32,6 @@ module.exports = { "App:RainLoop": __dirname + "/dev/Apps/RainLoopApp.js", "App:Admin": __dirname + "/dev/Apps/AdminApp.js", - "Model:Account": __dirname + "/dev/Models/AccountModel.js", - "Model:Attachment": __dirname + "/dev/Models/AttachmentModel.js", - "Model:ComposeAttachment": __dirname + "/dev/Models/ComposeAttachmentModel.js", - "Model:Contact": __dirname + "/dev/Models/ContactModel.js", - "Model:ContactProperty": __dirname + "/dev/Models/ContactPropertyModel.js", - "Model:ContactTag": __dirname + "/dev/Models/ContactTagModel.js", - "Model:Email": __dirname + "/dev/Models/EmailModel.js", - "Model:Filter": __dirname + "/dev/Models/FilterModel.js", - "Model:FilterCondition": __dirname + "/dev/Models/FilterConditionModel.js", - "Model:Folder": __dirname + "/dev/Models/FolderModel.js", - "Model:Identity": __dirname + "/dev/Models/IdentityModel.js", - "Model:Message": __dirname + "/dev/Models/MessageModel.js", - "Model:OpenPgpKey": __dirname + "/dev/Models/OpenPgpKeyModel.js", - "Storage:LocalStorage": __dirname + "/dev/Storages/LocalStorage.js", "Storage:LocalStorage:Cookie": __dirname + "/dev/Storages/LocalStorages/CookieDriver.js", "Storage:LocalStorage:LocalStorage": __dirname + "/dev/Storages/LocalStorages/LocalStorageDriver.js", @@ -137,8 +124,9 @@ module.exports = { 'moment': 'moment', 'ifvisible': 'ifvisible', 'crossroads': 'crossroads', - 'Jua': 'Jua', 'hasher': 'hasher', + 'Jua': 'Jua', + 'Autolinker': 'Autolinker', 'ssm': 'ssm', 'key': 'key', '_': '_',