Fixed strange characters in plain text mode (Firefox) (Closes #462)

This commit is contained in:
RainLoop Team 2015-02-17 16:04:03 +04:00
parent 2a90664574
commit e3064b10aa
24 changed files with 206 additions and 159 deletions

View file

@ -1151,7 +1151,6 @@
AppUser.prototype.setFolders = function (oData) AppUser.prototype.setFolders = function (oData)
{ {
var var
aList = [],
bUpdate = false, bUpdate = false,
fNormalizeFolder = function (sFolderFullNameRaw) { fNormalizeFolder = function (sFolderFullNameRaw) {
return ('' === sFolderFullNameRaw || Consts.Values.UnuseOptionValue === sFolderFullNameRaw || return ('' === sFolderFullNameRaw || Consts.Values.UnuseOptionValue === sFolderFullNameRaw ||
@ -1170,8 +1169,7 @@
AppStore.threadsAllowed(!!Settings.settingsGet('UseImapThread') && AppStore.threadsAllowed(!!Settings.settingsGet('UseImapThread') &&
oData.Result.IsThreadsSupported && true); oData.Result.IsThreadsSupported && true);
aList = this.folderResponseParseRec(Data.namespace, oData.Result['@Collection']); Data.folderList(this.folderResponseParseRec(Data.namespace, oData.Result['@Collection']));
Data.folderList(aList);
if (oData.Result['SystemFolders'] && '' === '' + if (oData.Result['SystemFolders'] && '' === '' +
Settings.settingsGet('SentFolder') + Settings.settingsGet('SentFolder') +

View file

@ -101,7 +101,7 @@
*/ */
HtmlEditor.prototype.clearSignatureSigns = function (sText) HtmlEditor.prototype.clearSignatureSigns = function (sText)
{ {
return sText.replace(/(\u0002|\u0003|\u0004|\u0005)/g, ''); return sText.replace(/(\u0002|\u0003|\u200C|\u200D)/g, '');
}; };
/** /**

View file

@ -351,7 +351,6 @@
key('up, shift+up, down, shift+down, home, end, pageup, pagedown, insert, space', sKeyScope, function (event, handler) { key('up, shift+up, down, shift+down, home, end, pageup, pagedown, insert, space', sKeyScope, function (event, handler) {
if (event && handler && handler.shortcut) if (event && handler && handler.shortcut)
{ {
// TODO
var iKey = 0; var iKey = 0;
switch (handler.shortcut) switch (handler.shortcut)
{ {

View file

@ -1009,6 +1009,10 @@
; ;
sText = sHtml sText = sHtml
// specials for signature
.replace(/\u0002\u0002/g, '\u200C\u200C')
.replace(/\u0003\u0003/g, '\u200D\u200D')
.replace(/<pre[^>]*>([\s\S\r\n]*)<\/pre>/gmi, convertPre) .replace(/<pre[^>]*>([\s\S\r\n]*)<\/pre>/gmi, convertPre)
.replace(/[\s]+/gm, ' ') .replace(/[\s]+/gm, ' ')
.replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue) .replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue)
@ -1154,6 +1158,11 @@
sPlain = aText.join("\n"); sPlain = aText.join("\n");
sPlain = sPlain sPlain = sPlain
// specials for signature
.replace(/\u200C\u200C/g, '\u0002\u0002')
.replace(/\u200D\u200D/g, '\u0003\u0003')
// .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n') // .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
.replace(/&/g, '&amp;') .replace(/&/g, '&amp;')
.replace(/>/g, '&gt;').replace(/</g, '&lt;') .replace(/>/g, '&gt;').replace(/</g, '&lt;')
@ -1693,6 +1702,20 @@
} }
}; };
Utils.substr = window.String.substr;
if ('ab'.substr(-1) !== 'b')
{
Utils.substr = function(sStr, iStart, iLength)
{
if (iStart < 0)
{
iStart = sStr.length + iStart;
}
return sStr.substr(iStart, iLength);
};
}
module.exports = Utils; module.exports = Utils;
}()); }());

View file

@ -75,6 +75,10 @@
{ {
var sInboxFolderName = Cache.getFolderInboxName(); var sInboxFolderName = Cache.getFolderInboxName();
this.isInbox = ko.computed(function () {
return Enums.FolderType.Inbox === this.type();
}, this);
this.hasSubScribedSubfolders = ko.computed(function () { this.hasSubScribedSubfolders = ko.computed(function () {
return !!_.find(this.subFolders(), function (oFolder) { return !!_.find(this.subFolders(), function (oFolder) {
return oFolder.subScribed() && !oFolder.isSystemFolder(); return oFolder.subScribed() && !oFolder.isSystemFolder();

View file

@ -4,7 +4,6 @@
'use strict'; 'use strict';
var var
window = require('window'),
_ = require('_'), _ = require('_'),
ko = require('ko'), ko = require('ko'),
@ -21,37 +20,13 @@
{ {
this.domains = DomainStore.domains; this.domains = DomainStore.domains;
this.iDomainForDeletionTimeout = 0;
this.visibility = ko.computed(function () { this.visibility = ko.computed(function () {
return this.domains.loading() ? 'visible' : 'hidden'; return this.domains.loading() ? 'visible' : 'hidden';
}, this); }, this);
this.domainForDeletion = ko.observable(null).extend({'toggleSubscribe': [this, this.domainForDeletion = ko.observable(null).deleteAccessHelper();
function (oPrev) {
if (oPrev)
{
oPrev.deleteAccess(false);
}
}, function (oNext) {
if (oNext)
{
oNext.deleteAccess(true);
this.startDomainForDeletionTimeout();
}
}
]});
} }
DomainsAdminSettings.prototype.startDomainForDeletionTimeout = function ()
{
var self = this;
window.clearInterval(this.iDomainForDeletionTimeout);
this.iDomainForDeletionTimeout = window.setTimeout(function () {
self.domainForDeletion(null);
}, 1000 * 3);
};
DomainsAdminSettings.prototype.createDomain = function () DomainsAdminSettings.prototype.createDomain = function ()
{ {
require('Knoin/Knoin').showScreenPopup(require('View/Popup/Domain')); require('Knoin/Knoin').showScreenPopup(require('View/Popup/Domain'));

View file

@ -31,11 +31,8 @@
this.serverErrorDesc = ko.observable(''); this.serverErrorDesc = ko.observable('');
this.haveChanges = ko.observable(false); this.haveChanges = ko.observable(false);
this.processText = ko.observable('');
this.saveErrorText = ko.observable(''); this.saveErrorText = ko.observable('');
this.visibility = ko.observable(false);
this.filters.subscribe(Utils.windowResizeCallback); this.filters.subscribe(Utils.windowResizeCallback);
this.serverError.subscribe(function (bValue) { this.serverError.subscribe(function (bValue) {
@ -51,14 +48,6 @@
this.filterRaw.allow = ko.observable(false); this.filterRaw.allow = ko.observable(false);
this.filterRaw.error = ko.observable(false); this.filterRaw.error = ko.observable(false);
this.processText = ko.computed(function () {
return this.filters.loading() ? Translator.i18n('SETTINGS_FILTERS/LOADING_PROCESS') : '';
}, this);
this.visibility = ko.computed(function () {
return '' === this.processText() ? 'hidden' : 'visible';
}, this);
this.filterForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend( this.filterForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend(
{'toggleSubscribeProperty': [this, 'deleteAccess']}); {'toggleSubscribeProperty': [this, 'deleteAccess']});

View file

@ -24,7 +24,7 @@
{ {
this.folderList = Data.folderList; this.folderList = Data.folderList;
this.processText = ko.computed(function () { this.loading = ko.computed(function () {
var var
bLoading = Data.foldersLoading(), bLoading = Data.foldersLoading(),
@ -33,44 +33,11 @@
bRenaming = Data.foldersRenaming() bRenaming = Data.foldersRenaming()
; ;
if (bCreating) return bLoading || bCreating || bDeleting || bRenaming;
{
return Translator.i18n('SETTINGS_FOLDERS/CREATING_PROCESS');
}
else if (bDeleting)
{
return Translator.i18n('SETTINGS_FOLDERS/DELETING_PROCESS');
}
else if (bRenaming)
{
return Translator.i18n('SETTINGS_FOLDERS/RENAMING_PROCESS');
}
else if (bLoading)
{
return Translator.i18n('SETTINGS_FOLDERS/LOADING_PROCESS');
}
return '';
}, this); }, this);
this.visibility = ko.computed(function () { this.folderForDeletion = ko.observable(null).deleteAccessHelper();
return '' === this.processText() ? 'hidden' : 'visible';
}, this);
this.folderForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this,
function (oPrev) {
if (oPrev)
{
oPrev.deleteAccess(false);
}
}, function (oNext) {
if (oNext)
{
oNext.deleteAccess(true);
}
}
]});
this.folderForEdit = ko.observable(null).extend({'toggleSubscribe': [this, this.folderForEdit = ko.observable(null).extend({'toggleSubscribe': [this,
function (oPrev) { function (oPrev) {

View file

@ -23,19 +23,7 @@
this.openpgpkeysPublic = PgpStore.openpgpkeysPublic; this.openpgpkeysPublic = PgpStore.openpgpkeysPublic;
this.openpgpkeysPrivate = PgpStore.openpgpkeysPrivate; this.openpgpkeysPrivate = PgpStore.openpgpkeysPrivate;
this.openPgpKeyForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this, this.openPgpKeyForDeletion = ko.observable(null).deleteAccessHelper();
function (oPrev) {
if (oPrev)
{
oPrev.deleteAccess(false);
}
}, function (oNext) {
if (oNext)
{
oNext.deleteAccess(true);
}
}
]});
} }
OpenPgpUserSettings.prototype.addOpenPgpKey = function () OpenPgpUserSettings.prototype.addOpenPgpKey = function ()

View file

@ -64,6 +64,13 @@
this.foldersDeleting = ko.observable(false); this.foldersDeleting = ko.observable(false);
this.foldersRenaming = ko.observable(false); this.foldersRenaming = ko.observable(false);
this.foldersListWithSingleInboxRootFolder = ko.computed(function () {
var aList = this.folderList();
return !_.find(aList, function (oFolder) {
return oFolder && !oFolder.isSystemFolder() && oFolder.visible();
});
}, this);
this.foldersChanging = ko.computed(function () { this.foldersChanging = ko.computed(function () {
var var
bLoading = this.foldersLoading(), bLoading = this.foldersLoading(),

View file

@ -165,6 +165,14 @@
.b-sub-folders.unpaddig-folder .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link { .b-sub-folders.unpaddig-folder .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link {
padding-left: @subPadding * 3 + @folderItemPadding; padding-left: @subPadding * 3 + @folderItemPadding;
} }
&.single-root-inbox .i-am-inbox.e-link {
display: none;
}
&.single-root-inbox .i-am-inbox-wrapper > .b-sub-folders .e-item .e-link {
padding-left: @folderItemPadding;
}
} }
html.rl-left-panel-disabled { html.rl-left-panel-disabled {

View file

@ -73,6 +73,10 @@ select {
line-height: 11px; line-height: 11px;
} }
.btn.btn-thin {
padding: 3px 9px;
}
.btn.btn-ellipsis { .btn.btn-ellipsis {
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;

View file

@ -116,7 +116,6 @@
if (this.editor) if (this.editor)
{ {
this.editor.setPlain('', false); this.editor.setPlain('', false);
this.editor.setReadOnly(true);
} }
}; };

View file

@ -43,6 +43,8 @@
this.folderListSystem = Data.folderListSystem; this.folderListSystem = Data.folderListSystem;
this.foldersChanging = Data.foldersChanging; this.foldersChanging = Data.foldersChanging;
this.foldersListWithSingleInboxRootFolder = Data.foldersListWithSingleInboxRootFolder;
this.leftPanelDisabled = Globals.leftPanelDisabled; this.leftPanelDisabled = Globals.leftPanelDisabled;
this.iDropOverTimer = 0; this.iDropOverTimer = 0;

View file

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

View file

@ -81,7 +81,6 @@ class Template
public function SetPopulateAlways($bPopulateAlways) public function SetPopulateAlways($bPopulateAlways)
{ {
$this->bPopulateAlways = !!$bPopulateAlways; $this->bPopulateAlways = !!$bPopulateAlways;
} }
/** /**
@ -123,12 +122,18 @@ class Template
} }
} }
return array( $aResult = array(
'ID' => $this->Id(), 'ID' => $this->Id(),
'Name' => $this->Name(), 'Name' => $this->Name(),
'Populated' => $bPopulated,
'Body' => $sBody 'Body' => $sBody
); );
if ($bAjax)
{
$aResult['Populated'] = $bPopulated;
}
return $aResult;
} }
/** /**

View file

@ -1,4 +1,5 @@
<div class="b-folders g-ui-user-select-none thm-folders" data-bind="css: {'focused': folderList.focused}"> <div class="b-folders g-ui-user-select-none thm-folders" data-bind="css: {'focused': folderList.focused,
'single-root-inbox': foldersListWithSingleInboxRootFolder}">
<div class="b-toolbar btn-toolbar"> <div class="b-toolbar btn-toolbar">
<a class="btn buttonCompose pull-left" data-tooltip-placement="bottom" <a class="btn buttonCompose pull-left" data-tooltip-placement="bottom"
data-bind="click: composeClick, tooltip: 'FOLDER_LIST/BUTTON_COMPOSE', css: {'btn-warning': composeInEdit}"> data-bind="click: composeClick, tooltip: 'FOLDER_LIST/BUTTON_COMPOSE', css: {'btn-warning': composeInEdit}">

View file

@ -1,8 +1,8 @@
<div class="e-item" data-bind="visible: visible"> <div class="e-item" data-bind="visible: visible, css: { 'i-am-inbox-wrapper': isInbox }">
<a class="e-link" data-bind="droppable: function (oEvent, oUi) { $root.messagesDrop($data, oUi); }, <a class="e-link" data-bind="droppable: function (oEvent, oUi) { $root.messagesDrop($data, oUi); },
droppableOver: function (oEvent, oUi) { $root.messagesDropOver($data, oUi); }, droppableOver: function (oEvent, oUi) { $root.messagesDropOver($data, oUi); },
droppableOut: function (oEvent, oUi) { $root.messagesDropOut($data, oUi); }, droppableOut: function (oEvent, oUi) { $root.messagesDropOut($data, oUi); },
css: { 'selected': selected() && !isSystemFolder(), 'selectable': selectableForFolderList, 'hidden' : hidden, 'print-count': hasUnreadMessages, 'unread-sub': hasSubScribedUnreadMessagesSubfolders, 'system': isSystemFolder, 'anim-action-class': actionBlink }"> css: { 'i-am-inbox': isInbox, 'selected': selected() && !isSystemFolder(), 'selectable': selectableForFolderList, 'hidden' : hidden, 'print-count': hasUnreadMessages, 'unread-sub': hasSubScribedUnreadMessagesSubfolders, 'system': isSystemFolder, 'anim-action-class': actionBlink }">
<span class="badge pull-right count" data-bind="text: printableUnreadCount"></span> <span class="badge pull-right count" data-bind="text: printableUnreadCount"></span>
<i data-bind="css: collapsedCss()"></i> <i data-bind="css: collapsedCss()"></i>
<span class="name" data-bind="text: name"></span> <span class="name" data-bind="text: name"></span>

View file

@ -59,7 +59,7 @@
<div class="message-fixed-button-toolbar clearfix" data-bind="visible: message"> <div class="message-fixed-button-toolbar clearfix" data-bind="visible: message">
<nobr> <nobr>
<div class="btn-group colored-toggle pull-right"> <div class="btn-group pull-right">
<a class="btn btn-dark-disabled-border buttonReply" data-tooltip-placement="bottom" <a class="btn btn-dark-disabled-border buttonReply" data-tooltip-placement="bottom"
data-bind="visible: 'reply' === lastReplyAction(), command: replyCommand, tooltip: 'MESSAGE/BUTTON_REPLY'"> data-bind="visible: 'reply' === lastReplyAction(), command: replyCommand, tooltip: 'MESSAGE/BUTTON_REPLY'">
<i class="icon-reply"></i> <i class="icon-reply"></i>
@ -182,6 +182,17 @@
<i class="icon-pencil icon-white"></i> <i class="icon-pencil icon-white"></i>
</a> </a>
</div> </div>
<!-- <div class="btn-group pull-right" data-bind="visible: true" style="margin-right: 5px">
<a class="btn btn-thin" data-tooltip-placement="bottom">
<i class="icon-left-middle"></i>
</a>
<a class="btn btn-thin" data-tooltip-placement="bottom">
<b>1 / 4</b>
</a>
<a class="btn btn-thin" data-tooltip-placement="bottom">
<i class="icon-right-middle"></i>
</a>
</div>-->
</nobr> </nobr>
</div> </div>

View file

@ -2,6 +2,8 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="legend"> <div class="legend">
<span class="i18n" data-i18n-text="SETTINGS_FILTERS/LEGEND_FILTERS"></span> <span class="i18n" data-i18n-text="SETTINGS_FILTERS/LEGEND_FILTERS"></span>
&nbsp;&nbsp;&nbsp;
<i class="icon-spinner animated" style="margin-top: 5px" data-bind="visible: filters.loading"></i>
</div> </div>
</div> </div>
<div class="row" data-bind="visible: inited() && !serverError()"> <div class="row" data-bind="visible: inited() && !serverError()">
@ -46,13 +48,10 @@
</div> </div>
</div> </div>
</div> </div>
<br />
<br />
<div class="row"> <div class="row">
<div class="span8"> <div class="span8">
<div class="process-place g-ui-user-select-none" data-bind="style: {'visibility': visibility }">
<i class="icon-spinner animated"></i>
&nbsp;&nbsp;
<span data-bind="text: processText"></span>
</div>
<div class="control-group" data-bind="css: {'error': filterRaw.error}, visible: inited() && filterRaw.allow() && filterRaw.active()"> <div class="control-group" data-bind="css: {'error': filterRaw.error}, visible: inited() && filterRaw.allow() && filterRaw.active()">
<div class="controls"> <div class="controls">
<pre style="word-break: break-word;" data-bind="visible: '' !== filterRaw.capa()"> <pre style="word-break: break-word;" data-bind="visible: '' !== filterRaw.capa()">

View file

@ -2,6 +2,8 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="legend"> <div class="legend">
<span class="i18n" data-i18n-text="SETTINGS_FOLDERS/LEGEND_FOLDERS"></span> <span class="i18n" data-i18n-text="SETTINGS_FOLDERS/LEGEND_FOLDERS"></span>
&nbsp;&nbsp;&nbsp;
<i class="icon-spinner animated" style="margin-top: 5px" data-bind="visible: loading"></i>
</div> </div>
</div> </div>
<a class="btn" data-bind="click: createFolder"> <a class="btn" data-bind="click: createFolder">
@ -24,11 +26,9 @@
<button type="button" class="close" data-bind="click: function () { folderList.error(''); }">&times;</button> <button type="button" class="close" data-bind="click: function () { folderList.error(''); }">&times;</button>
<span data-bind="text: folderList.error"></span> <span data-bind="text: folderList.error"></span>
</div> </div>
<div class="process-place" data-bind="style: {'visibility': visibility }"> <br />
<i class="icon-spinner animated"></i> <br />
&nbsp;&nbsp; <br />
<span data-bind="text: processText"></span>
</div>
<table class="table table-hover list-table" data-bind="i18nUpdate: folderList"> <table class="table table-hover list-table" data-bind="i18nUpdate: folderList">
<colgroup> <colgroup>
<col /> <col />

View file

@ -2,6 +2,8 @@
<div class="form-horizontal"> <div class="form-horizontal">
<div class="legend"> <div class="legend">
<span class="i18n" data-i18n-text="SETTINGS_TEMPLATES/LEGEND_TEMPLATES"></span> <span class="i18n" data-i18n-text="SETTINGS_TEMPLATES/LEGEND_TEMPLATES"></span>
&nbsp;&nbsp;&nbsp;
<i class="icon-spinner animated" style="margin-top: 5px" data-bind="visible: templates.loading"></i>
</div> </div>
</div> </div>
<a class="btn" data-bind="click: addNewTemplate"> <a class="btn" data-bind="click: addNewTemplate">
@ -9,11 +11,9 @@
&nbsp;&nbsp; &nbsp;&nbsp;
<span class="i18n" data-i18n-text="SETTINGS_TEMPLATES/BUTTON_ADD_TEMPLATE"></span> <span class="i18n" data-i18n-text="SETTINGS_TEMPLATES/BUTTON_ADD_TEMPLATE"></span>
</a> </a>
<div class="process-place" data-bind="style: {'visibility': visibility }"> <br />
<i class="icon-spinner animated"></i> <br />
&nbsp;&nbsp; <br />
<span data-bind="text: processText"></span>
</div>
<table class="table table-hover list-table templates-list" data-bind="i18nUpdate: templates"> <table class="table table-hover list-table templates-list" data-bind="i18nUpdate: templates">
<colgroup> <colgroup>
<col /> <col />

View file

@ -1,10 +1,18 @@
rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefore) rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefore)
{ {
if (!bHtml)
{
sText = sText
.replace(/\u200C\u200C/g, '\u0002\u0002')
.replace(/\u200D\u200D/g, '\u0003\u0003')
;
}
var var
sTextWithoutSignature = sText sTextWithoutSignature = sText
.replace(/\u0002\u0002[\s\S]*\u0003\u0003/gm, '') .replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, '')
.replace(/\u0004\u0004[\s\S]*\u0005\u0005/gm, ''), .replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, ''),
bEmptyText = '' === $.trim(sTextWithoutSignature), bEmptyText = '' === $.trim(sTextWithoutSignature),
sNewLine = (bHtml ? '<br />' : "\n") sNewLine = (bHtml ? '<br />' : "\n")
; ;
@ -16,23 +24,31 @@ rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefor
if (!/\u0002\u0002/gm.test(sText)) if (!/\u0002\u0002/gm.test(sText))
{ {
sText = "\u0002\u0002\u0003\u0003" + sText; sText = "\u0002\u0002\u0002\u0002" + sText;
} }
if (!/\u0004\u0004/gm.test(sText)) if (!/\u0003\u0003/gm.test(sText))
{ {
sText = sText + "\u0004\u0004\u0005\u0005"; sText = sText + "\u0003\u0003\u0003\u0003";
} }
if (bInsertBefore) if (bInsertBefore)
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0003\u0003/gm, "\u0002\u0002" + sSignature + sNewLine + "\u0003\u0003"); sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002" + sSignature + (bEmptyText ? '' : sNewLine) + "\u0002\u0002");
sText = sText.replace(/\u0004\u0004[\s\S]*\u0005\u0005/gm, "\u0004\u0004\u0005\u0005"); sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003\u0003\u0003");
} }
else else
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0003\u0003/gm, "\u0002\u0002\u0003\u0003"); sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002\u0002\u0002");
sText = sText.replace(/\u0004\u0004[\s\S]*\u0005\u0005/gm, "\u0004\u0004" + (bEmptyText ? '' : sNewLine) + sSignature + "\u0005\u0005"); sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003" + (bEmptyText ? '' : sNewLine) + sSignature + "\u0003\u0003");
}
if (!bHtml)
{
sText = sText
.replace(/\u0002\u0002/g, '\u200C\u200C')
.replace(/\u0003\u0003/g, '\u200D\u200D')
;
} }
return sText; return sText;
@ -42,40 +58,58 @@ CKEDITOR.plugins.add('signature', {
init: function(editor) { init: function(editor) {
editor.addCommand('insertSignature', { editor.addCommand('insertSignature', {
modes: { wysiwyg: 1, plain: 1 }, modes: { wysiwyg: 1, plain: 1 },
exec: function (editor, cfg) { exec: function (editor, cfg)
{
var var
bIsHtml = false, bIsHtml = false,
bInsertBefore = false, bInsertBefore = false,
sSignature = '' sSignature = '',
sResultSignature = ''
; ;
if (cfg) { if (cfg)
{
bIsHtml = undefined === cfg.isHtml ? false : !!cfg.isHtml; bIsHtml = undefined === cfg.isHtml ? false : !!cfg.isHtml;
bInsertBefore = undefined === cfg.insertBefore ? false : !!cfg.insertBefore; bInsertBefore = undefined === cfg.insertBefore ? false : !!cfg.insertBefore;
sSignature = undefined === cfg.signature ? '' : cfg.signature; sSignature = undefined === cfg.signature ? '' : cfg.signature;
} }
try { sResultSignature = sSignature;
if ('plain' === editor.mode && editor.__plain && editor.__plainUtils) {
if (bIsHtml && editor.__plainUtils.htmlToPlain) { try
sSignature = editor.__plainUtils.htmlToPlain(sSignature); {
if ('plain' === editor.mode && editor.__plain && editor.__plainUtils)
{
if (editor.__plainUtils && editor.__plainUtils.htmlToPlain)
{
if (bIsHtml)
{
sResultSignature = editor.__plainUtils.htmlToPlain(sResultSignature);
}
} }
editor.__plain.setRawData( editor.__plain.setRawData(
rl_signature_replacer(editor, rl_signature_replacer(editor,
editor.__plain.getRawData(), sSignature, false, bInsertBefore)); editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
} else { }
if (!bIsHtml && editor.__plainUtils && editor.__plainUtils.plainToHtml) { else
sSignature = editor.__plainUtils.plainToHtml(sSignature); {
if (editor.__plainUtils && editor.__plainUtils.plainToHtml)
{
if (!bIsHtml)
{
sResultSignature = editor.__plainUtils.plainToHtml(sResultSignature);
}
} }
editor.setData( editor.setData(
rl_signature_replacer(editor, rl_signature_replacer(editor,
editor.getData(), sSignature, true, bInsertBefore)); editor.getData(), sResultSignature, true, bInsertBefore));
} }
} catch (e) {} }
catch (e) {}
} }
}); });
} }

View file

@ -1,10 +1,18 @@
rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefore) rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefore)
{ {
if (!bHtml)
{
sText = sText
.replace(/\u200C\u200C/g, '\u0002\u0002')
.replace(/\u200D\u200D/g, '\u0003\u0003')
;
}
var var
sTextWithoutSignature = sText sTextWithoutSignature = sText
.replace(/\u0002\u0002[\s\S]*\u0003\u0003/gm, '') .replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, '')
.replace(/\u0004\u0004[\s\S]*\u0005\u0005/gm, ''), .replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, ''),
bEmptyText = '' === $.trim(sTextWithoutSignature), bEmptyText = '' === $.trim(sTextWithoutSignature),
sNewLine = (bHtml ? '<br />' : "\n") sNewLine = (bHtml ? '<br />' : "\n")
; ;
@ -16,23 +24,31 @@ rl_signature_replacer = function (editor, sText, sSignature, bHtml, bInsertBefor
if (!/\u0002\u0002/gm.test(sText)) if (!/\u0002\u0002/gm.test(sText))
{ {
sText = "\u0002\u0002\u0003\u0003" + sText; sText = "\u0002\u0002\u0002\u0002" + sText;
} }
if (!/\u0004\u0004/gm.test(sText)) if (!/\u0003\u0003/gm.test(sText))
{ {
sText = sText + "\u0004\u0004\u0005\u0005"; sText = sText + "\u0003\u0003\u0003\u0003";
} }
if (bInsertBefore) if (bInsertBefore)
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0003\u0003/gm, "\u0002\u0002" + sSignature + sNewLine + "\u0003\u0003"); sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002" + sSignature + (bEmptyText ? '' : sNewLine) + "\u0002\u0002");
sText = sText.replace(/\u0004\u0004[\s\S]*\u0005\u0005/gm, "\u0004\u0004\u0005\u0005"); sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003\u0003\u0003");
} }
else else
{ {
sText = sText.replace(/\u0002\u0002[\s\S]*\u0003\u0003/gm, "\u0002\u0002\u0003\u0003"); sText = sText.replace(/\u0002\u0002[\s\S]*\u0002\u0002/gm, "\u0002\u0002\u0002\u0002");
sText = sText.replace(/\u0004\u0004[\s\S]*\u0005\u0005/gm, "\u0004\u0004" + (bEmptyText ? '' : sNewLine) + sSignature + "\u0005\u0005"); sText = sText.replace(/\u0003\u0003[\s\S]*\u0003\u0003/gm, "\u0003\u0003" + (bEmptyText ? '' : sNewLine) + sSignature + "\u0003\u0003");
}
if (!bHtml)
{
sText = sText
.replace(/\u0002\u0002/g, '\u200C\u200C')
.replace(/\u0003\u0003/g, '\u200D\u200D')
;
} }
return sText; return sText;
@ -42,40 +58,58 @@ CKEDITOR.plugins.add('signature', {
init: function(editor) { init: function(editor) {
editor.addCommand('insertSignature', { editor.addCommand('insertSignature', {
modes: { wysiwyg: 1, plain: 1 }, modes: { wysiwyg: 1, plain: 1 },
exec: function (editor, cfg) { exec: function (editor, cfg)
{
var var
bIsHtml = false, bIsHtml = false,
bInsertBefore = false, bInsertBefore = false,
sSignature = '' sSignature = '',
sResultSignature = ''
; ;
if (cfg) { if (cfg)
{
bIsHtml = undefined === cfg.isHtml ? false : !!cfg.isHtml; bIsHtml = undefined === cfg.isHtml ? false : !!cfg.isHtml;
bInsertBefore = undefined === cfg.insertBefore ? false : !!cfg.insertBefore; bInsertBefore = undefined === cfg.insertBefore ? false : !!cfg.insertBefore;
sSignature = undefined === cfg.signature ? '' : cfg.signature; sSignature = undefined === cfg.signature ? '' : cfg.signature;
} }
try { sResultSignature = sSignature;
if ('plain' === editor.mode && editor.__plain && editor.__plainUtils) {
if (bIsHtml && editor.__plainUtils.htmlToPlain) { try
sSignature = editor.__plainUtils.htmlToPlain(sSignature); {
if ('plain' === editor.mode && editor.__plain && editor.__plainUtils)
{
if (editor.__plainUtils && editor.__plainUtils.htmlToPlain)
{
if (bIsHtml)
{
sResultSignature = editor.__plainUtils.htmlToPlain(sResultSignature);
}
} }
editor.__plain.setRawData( editor.__plain.setRawData(
rl_signature_replacer(editor, rl_signature_replacer(editor,
editor.__plain.getRawData(), sSignature, false, bInsertBefore)); editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
} else { }
if (!bIsHtml && editor.__plainUtils && editor.__plainUtils.plainToHtml) { else
sSignature = editor.__plainUtils.plainToHtml(sSignature); {
if (editor.__plainUtils && editor.__plainUtils.plainToHtml)
{
if (!bIsHtml)
{
sResultSignature = editor.__plainUtils.plainToHtml(sResultSignature);
}
} }
editor.setData( editor.setData(
rl_signature_replacer(editor, rl_signature_replacer(editor,
editor.getData(), sSignature, true, bInsertBefore)); editor.getData(), sResultSignature, true, bInsertBefore));
} }
} catch (e) {} }
catch (e) {}
} }
}); });
} }