Small fixes

Utf8 clear supports icon unicode
This commit is contained in:
RainLoop Team 2015-02-25 19:29:34 +04:00
parent e6725198c4
commit 19f089d0bf
15 changed files with 141 additions and 62 deletions

View file

@ -7,7 +7,6 @@
Globals = {},
window = require('window'),
is = require('is'),
_ = require('_'),
$ = require('$'),
ko = require('ko'),
@ -69,14 +68,21 @@
Globals.bUnload = false;
/**
* @type {boolean}
* @type {string}
*/
Globals.bTabletDevice = is.tablet();
Globals.sUserAgent = 'navigator' in window && 'userAgent' in window.navigator &&
window.navigator.userAgent.toLowerCase() || '';
/**
* @type {boolean}
*/
Globals.bMobileDevice = is.mobile() || is.tablet();
Globals.bMobileDevice =
/android/i.test(Globals.sUserAgent) ||
/iphone/i.test(Globals.sUserAgent) ||
/ipod/i.test(Globals.sUserAgent) ||
/ipad/i.test(Globals.sUserAgent) ||
/blackberry/i.test(Globals.sUserAgent)
;
/**
* @type {boolean}

View file

@ -58,7 +58,7 @@
this.selectedItem(null);
}
}
else if (this.bAutoSelect && this.focusedItem())
else if (this.autoSelect() && this.focusedItem())
{
this.selectedItem(this.focusedItem());
}
@ -124,10 +124,10 @@
this.sItemFocusedSelector = sItemFocusedSelector;
this.sLastUid = '';
this.bAutoSelect = true;
this.oCallbacks = {};
this.emptyFunction = function () {};
this.emptyTrueFunction = function () { return true; };
this.focusedItem.subscribe(function (oItem) {
if (oItem)
@ -221,7 +221,7 @@
this.selectedItemUseCallback = true;
if (!bChecked && !bSelected && this.bAutoSelect)
if (!bChecked && !bSelected && this.autoSelect())
{
if (self.focusedItem())
{
@ -392,9 +392,12 @@
}
};
Selector.prototype.autoSelect = function (bValue)
/**
* @returns {boolean}
*/
Selector.prototype.autoSelect = function ()
{
this.bAutoSelect = !!bValue;
return !!(this.oCallbacks['onAutoSelect'] || this.emptyTrueFunction)();
};
/**
@ -540,7 +543,7 @@
}
}
if ((this.bAutoSelect || !!bForceSelect) &&
if ((this.autoSelect() || !!bForceSelect) &&
!this.isListChecked() && Enums.EventKeyCode.Space !== iEventKeyCode)
{
this.selectedItem(oResult);

View file

@ -244,9 +244,7 @@
*/
Utils.encodeHtml = function (sText)
{
return Utils.isNormal(sText) ? sText.toString()
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/"/g, '&quot;').replace(/'/g, '&#039;') : '';
return Utils.isNormal(sText) ? _.escape(sText.toString()) : '';
};
/**
@ -512,7 +510,7 @@
/**
* @param {?} oEvent
*/
Utils.killCtrlAandS = function (oEvent)
Utils.kill_CtrlA_CtrlS = function (oEvent)
{
oEvent = oEvent || window.event;
if (oEvent && oEvent.ctrlKey && !oEvent.shiftKey && !oEvent.altKey)
@ -944,7 +942,7 @@
fixAttibuteValue = function () {
return (arguments && 1 < arguments.length) ?
'' + arguments[1] + arguments[2].replace(/</g, '&lt;').replace(/>/g, '&gt;') : '';
'' + arguments[1] + _.escape(arguments[2]) : '';
},
convertLinks = function () {
@ -1550,6 +1548,36 @@
}
};
/**
* @param {string} sStr
* @return {string}
*/
Utils.FullHtmlEncode = function (sStr)
{
var
iIndex = 0,
sChr = '',
iChrCode = 0,
sResult = '';
;
for (iIndex = 0; iIndex < sStr.length; iIndex++)
{
sChr = sStr[iIndex];
if (-1 < Utils.inArray(sChr, ['&', '<', '>', '"', '`', '\'']))
{
sResult += _.escape(sChr);
}
else
{
iChrCode = sChr.charCodeAt(0);
sResult += (iChrCode > 128) ? '&#' + iChrCode + ';' : sChr;
}
}
return sResult;
};
/**
* @param {Object|Array} mObjectOrObjects
*/

View file

@ -63,7 +63,7 @@
if (Consts.Values.TokenErrorLimit < Globals.iTokenErrorCount)
{
if (Globals.__APP__)
if (Globals.__APP__ && Globals.__APP__.loginAndLogoutReload)
{
Globals.__APP__.loginAndLogoutReload(true);
}
@ -71,11 +71,11 @@
if (oData.ClearAuth || oData.Logout || Consts.Values.AjaxErrorLimit < Globals.iAjaxErrorCount)
{
if (Globals.__APP__)
if (Globals.__APP__ && Globals.__APP__.clearClientSideToken)
{
Globals.__APP__.clearClientSideToken();
if (!oData.ClearAuth)
if (!oData.ClearAuth && Globals.__APP__.loginAndLogoutReload)
{
Globals.__APP__.loginAndLogoutReload(true);
}

View file

@ -43,6 +43,7 @@
this.submitRequest = ko.observable(false);
this.submitError = ko.observable('');
this.submitErrorAdditional = ko.observable('');
this.emailFocus = ko.observable(false);
@ -61,21 +62,28 @@
Remote.accountSetup(_.bind(function (sResult, oData) {
this.submitRequest(false);
if (Enums.StorageResultType.Success === sResult && oData && 'AccountSetup' === oData.Action)
if (Enums.StorageResultType.Success === sResult && oData)
{
if (oData.Result)
{
require('App/User').accountsAndIdentities();
this.cancelCommand();
}
else if (oData.ErrorCode)
else
{
this.submitError(Translator.getNotification(oData.ErrorCode));
this.submitError(oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) :
Translator.getNotification(Enums.Notification.UnknownError));
if (oData.ErrorMessageAdditional)
{
this.submitErrorAdditional(oData.ErrorMessageAdditional);
}
}
}
else
{
this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
this.submitErrorAdditional('');
}
}, this), this.email(), this.password(), this.isNew());
@ -104,6 +112,7 @@
this.submitRequest(false);
this.submitError('');
this.submitErrorAdditional('');
};
AccountPopupView.prototype.onShow = function (oAccount)

View file

@ -251,15 +251,9 @@
return oMessage ? oMessage.generateUid() : '';
});
MessageStore.messageListEndHash.subscribe(function () {
this.selector.scrollToTop();
}, this);
SettingsStore.layout.subscribe(function (mValue) {
this.selector.autoSelect(Enums.Layout.NoPreview !== mValue);
}, this);
SettingsStore.layout.valueHasMutated();
this.selector.on('onAutoSelect', _.bind(function () {
return this.useAutoSelect();
}, this));
Events
.sub('mailbox.message-list.selector.go-down', function () {
@ -270,6 +264,10 @@
}, this)
;
MessageStore.messageListEndHash.subscribe(function () {
this.selector.scrollToTop();
}, this);
kn.constructorEnd(this);
}
@ -281,6 +279,16 @@
*/
MessageListMailBoxUserView.prototype.emptySubjectValue = '';
MessageListMailBoxUserView.prototype.useAutoSelect = function ()
{
if (/is:unseen/.test(this.mainMessageListSearch()))
{
return false;
}
return Enums.Layout.NoPreview !== SettingsStore.layout();
};
MessageListMailBoxUserView.prototype.searchEnterAction = function ()
{
this.mainMessageListSearch(this.sLastSearchValue);
@ -721,6 +729,14 @@
return false;
});
key('enter', Enums.KeyState.MessageList, function () {
if (self.message() && self.useAutoSelect())
{
Events.pub('mailbox.message-view.toggle-full-screen');
return false;
}
});
// archive (zip)
key('z', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
self.archiveCommand();

View file

@ -323,6 +323,10 @@
Events.pub('mailbox.message-list.selector.go-down');
});
Events.sub('mailbox.message-view.toggle-full-screen', function () {
this.toggleFullScreen();
}, this);
kn.constructorEnd(this);
}
@ -581,6 +585,11 @@
if (this.fullScreenMode())
{
this.fullScreenMode(false);
if (Enums.Layout.NoPreview !== this.layout())
{
this.message.focused(false);
}
}
else if (Enums.Layout.NoPreview === this.layout())
{
@ -610,14 +619,6 @@
return false;
});
key('enter', Enums.KeyState.MessageList, function () {
if (Enums.Layout.NoPreview !== self.layout() && self.message())
{
self.toggleFullScreen();
return false;
}
});
// reply
key('r', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
if (MessageStore.message())

6
dev/bootstrap.js vendored
View file

@ -22,8 +22,8 @@
Globals.__APP__ = App;
Globals.$win
.keydown(Utils.killCtrlAandS)
.keyup(Utils.killCtrlAandS)
.keydown(Utils.kill_CtrlA_CtrlS)
.keyup(Utils.kill_CtrlA_CtrlS)
.unload(function () {
Globals.bUnload = true;
})
@ -45,7 +45,7 @@
window['rl']['createCommand'] = Utils.createCommand;
window['rl']['addSettingsViewModel'] = _.bind(Plugins.addSettingsViewModel, Plugins);
window['rl']['pluginRemoteRequest'] = _.bind(Plugins.remoteRequest, Plugins);
window['rl']['pluginSettingsGet'] = _.bind(Plugins.settingsGet, Plugins);

View file

@ -2,7 +2,7 @@
"name": "RainLoop",
"title": "RainLoop Webmail",
"version": "1.8.1",
"release": "272",
"release": "274",
"description": "Simple, modern & fast web-based email client",
"homepage": "http://rainloop.net",
"main": "gulpfile.js",

View file

@ -17,6 +17,22 @@ namespace MailSo\Base;
*/
class Utils
{
/**
* @var string
*/
static $sValidUtf8Regexp = <<<'END'
/
(
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
){1,100} # ...one or more times
)
| . # anything else
/x
END;
/**
* @var array
*/
@ -1432,15 +1448,7 @@ class Utils
return $sUtfString;
}
$sUtfString = \preg_replace(
'/[\x00-\x08\x10\x0B\x0C\x0E-\x1F\x7F]'.
'|[\x00-\x7F][\x80-\xBF]+'.
'|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'.
'|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'.
'|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
$sReplaceOn,
$sUtfString
);
$sUtfString = \preg_replace(\MailSo\Base\Utils::$sValidUtf8Regexp, '$1', $sUtfString);
$sUtfString = \preg_replace(
'/\xE0[\x80-\x9F][\x80-\xBF]'.
@ -1450,15 +1458,16 @@ class Utils
$sUtfString = \preg_replace('/\xEF\xBF\xBD/', '?', $sUtfString);
$sNewUtfString = false;
if (\MailSo\Base\Utils::IsIconvSupported())
{
$sNewUtfString = \MailSo\Base\Utils::IconvConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
}
else if (\MailSo\Base\Utils::IsMbStringSupported())
if (false === $sNewUtfString && \MailSo\Base\Utils::IsMbStringSupported())
{
$sNewUtfString = \MailSo\Base\Utils::MbConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
}
if (false === $sNewUtfString && \MailSo\Base\Utils::IsIconvSupported())
{
$sNewUtfString = \MailSo\Base\Utils::IconvConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
}
if (false !== $sNewUtfString)
{
$sUtfString = $sNewUtfString;

View file

@ -1185,7 +1185,7 @@ class ImapClient extends \MailSo\Net\NetClient
foreach ($aResponse as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
{
if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
&& 'ESEARCH' === $oImapResponse->StatusOrIndex
&& ('ESEARCH' === $oImapResponse->StatusOrIndex || 'ESORT' === $oImapResponse->StatusOrIndex)
&& \is_array($oImapResponse->ResponseList)
&& isset($oImapResponse->ResponseList[2], $oImapResponse->ResponseList[2][0], $oImapResponse->ResponseList[2][1])
&& 'TAG' === $oImapResponse->ResponseList[2][0] && $sRequestTag === $oImapResponse->ResponseList[2][1]

View file

@ -2156,6 +2156,9 @@ class Actions
1 < \count($aOrder['Accounts']))
{
$aAccounts = \array_merge(\array_flip($aOrder['Accounts']), $aAccounts);
$aAccounts = \array_filter($aAccounts, function ($sHash) {
return 5 < \strlen($sHash);
});
}
}

View file

@ -131,9 +131,10 @@
<div class="content g-scrollbox">
<div class="content-wrapper">
<div class="listSearchDesc" data-bind="visible: '' !== messageListSearchDesc()">
<a class="btn btn-small pull-right searchCancelButton" data-bind="click: cancelSearch">
<a class="close-custom" data-bind="click: cancelSearch">&times;</a>
<!-- <a class="btn btn-small pull-right searchCancelButton" data-bind="click: cancelSearch">
<i class="icon-remove"></i>
</a>
</a>-->
<span data-bind="text: messageListSearchDesc"></span>:
</div>
<div class="listDragOver" data-bind="css: {'viewAppendArea': dragOver() && '' === messageListError() && !popupVisibility(), 'dragOverEnter': dragOverEnter }, initDom: dragOverArea">

View file

@ -11,14 +11,18 @@
<div class="modal-body">
<div class="form-horizontal">
<div class="alert" data-bind="visible: '' !== submitError()">
<button type="button" class="close" data-bind="click: function () { submitError('') }">&times;</button>
<button type="button" class="close-custom" data-bind="click: function () { submitError('') }">&times;</button>
<span data-bind="text: submitError"></span>
<div data-bind="visible: submitErrorAdditional">
<br />
<span data-bind="text: submitErrorAdditional"></span>
</div>
</div>
<br />
<div class="control-group" data-bind="css: {'error': emailError}">
<label class="i18n control-label" data-i18n-text="LOGIN/LABEL_EMAIL"></label>
<div class="controls">
<label style="margin-top: 5px;"><strong data-bind="visible: !isNew(), text: email"></strong></label>
<label style="margin-top: 5px;" data-bind="visible: !isNew()"><strong data-bind="text: email"></strong></label>
<input type="email" class="inputEmail input-large" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="visible: isNew, textInput: email, onEnter: addAccountCommand, hasfocus: emailFocus" />
</div>

View file

@ -42,7 +42,6 @@ module.exports = {
'ssm': 'window.ssm',
'key': 'window.key',
'_': 'window._',
'is': 'window.is',
'$': 'window.jQuery'
}
};