diff --git a/dev/App/User.jsx b/dev/App/User.jsx index c112aece2..e9bb09fa4 100644 --- a/dev/App/User.jsx +++ b/dev/App/User.jsx @@ -46,11 +46,11 @@ import {checkTimestamp} from 'Storage/RainLoop'; import Remote from 'Remote/User/Ajax'; import Promises from 'Promises/User/Ajax'; -import EmailModel from 'Model/Email'; -import AccountModel from 'Model/Account'; -import IdentityModel from 'Model/Identity'; -import TemplateModel from 'Model/Template'; -import OpenPgpKeyModel from 'Model/OpenPgpKey'; +import {EmailModel} from 'Model/Email'; +import {AccountModel} from 'Model/Account'; +import {IdentityModel} from 'Model/Identity'; +import {TemplateModel} from 'Model/Template'; +import {OpenPgpKeyModel} from 'Model/OpenPgpKey'; import kn from 'Knoin/Knoin'; diff --git a/dev/Common/Utils.jsx b/dev/Common/Utils.jsx index 563dd09ec..078a4be9d 100644 --- a/dev/Common/Utils.jsx +++ b/dev/Common/Utils.jsx @@ -1593,7 +1593,7 @@ export function mailToHelper(mailToUrl, PopupComposeVoreModel) const email = mailToUrl.replace(/\?.+$/, ''), query = mailToUrl.replace(/^[^\?]*\?/, ''), - EmailModel = require('Model/Email'), + EmailModel = require('Model/Email').default, emailObj = new EmailModel(), fParseEmailLine = (line) => (line ? _.compact(_.map(decodeURIComponent(line).split(/[,]/), (item) => { emailObj.clear(); diff --git a/dev/External/ko.js b/dev/External/ko.js index 75fa3a634..fba4b2cf6 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -838,7 +838,7 @@ ko.bindingHandlers.emailsTags = { var Utils = require('Common/Utils'), - EmailModel = require('Model/Email'), + EmailModel = require('Model/Email').default, $oEl = $(oElement), fValue = fValueAccessor(), diff --git a/dev/Helper/Message.jsx b/dev/Helper/Message.jsx index 64177146b..ff7a7d116 100644 --- a/dev/Helper/Message.jsx +++ b/dev/Helper/Message.jsx @@ -1,100 +1,95 @@ import {isNonEmptyArray, isUnd} from 'Common/Utils'; -import EmailModel from 'Model/Email'; +import {EmailModel} from 'Model/Email'; -class MessageHelper -{ - /** - * @param {Array.} emails - * @param {boolean=} friendlyView = false - * @param {boolean=} wrapWithLink = false - * @returns {string} - */ - emailArrayToString(emails, friendlyView = false, wrapWithLink = false) { +/** + * @param {Array.} emails + * @param {boolean=} friendlyView = false + * @param {boolean=} wrapWithLink = false + * @returns {string} + */ +export function emailArrayToString(emails, friendlyView = false, wrapWithLink = false) { - let index = 0, len = 0; - const result = []; + let index = 0, len = 0; + const result = []; - if (isNonEmptyArray(emails)) + if (isNonEmptyArray(emails)) + { + for (len = emails.length; index < len; index++) { - for (len = emails.length; index < len; index++) - { - result.push(emails[index].toLine(friendlyView, wrapWithLink)); - } + result.push(emails[index].toLine(friendlyView, wrapWithLink)); } - - return result.join(', '); } - /** - * @param {Array.} emails - * @returns {string} - */ - emailArrayToStringClear(emails) { + return result.join(', '); +} - let index = 0, len = 0; - const result = []; +/** + * @param {Array.} emails + * @returns {string} + */ +export function emailArrayToStringClear(emails) { - if (isNonEmptyArray(emails)) + let index = 0, len = 0; + const result = []; + + if (isNonEmptyArray(emails)) + { + for (len = emails.length; index < len; index++) { - for (len = emails.length; index < len; index++) + if (emails[index] && emails[index].email && '' !== emails[index].name) { - if (emails[index] && emails[index].email && '' !== emails[index].name) - { - result.push(emails[index].email); - } + result.push(emails[index].email); } } - - return result.join(', '); } - /** - * @param {?Array} json - * @returns {Array.} - */ - emailArrayFromJson(json) { + return result.join(', '); +} - let index = 0, len = 0, email = null; - const result = []; +/** + * @param {?Array} json + * @returns {Array.} + */ +export function emailArrayFromJson(json) { - if (isNonEmptyArray(json)) + let index = 0, len = 0, email = null; + const result = []; + + if (isNonEmptyArray(json)) + { + for (index = 0, len = json.length; index < len; index++) { - for (index = 0, len = json.length; index < len; index++) + email = EmailModel.newInstanceFromJson(json[index]); + if (email) { - email = EmailModel.newInstanceFromJson(json[index]); - if (email) - { - result.push(email); - } + result.push(email); } } - - return result; } - /** - * @param {Array.} inputEmails - * @param {Object} unic - * @param {Array} localEmails - */ - replyHelper(inputEmails, unic, localEmails) { + return result; +} - if (inputEmails && 0 < inputEmails.length) +/** + * @param {Array.} inputEmails + * @param {Object} unic + * @param {Array} localEmails + */ +export function replyHelper(inputEmails, unic, localEmails) { + + if (inputEmails && 0 < inputEmails.length) + { + let index = 0; + const len = inputEmails.length; + + for (; index < len; index++) { - let index = 0; - const len = inputEmails.length; - - for (; index < len; index++) + if (isUnd(unic[inputEmails[index].email])) { - if (isUnd(unic[inputEmails[index].email])) - { - unic[inputEmails[index].email] = true; - localEmails.push(inputEmails[index]); - } + unic[inputEmails[index].email] = true; + localEmails.push(inputEmails[index]); } } } } - -export default new MessageHelper(); diff --git a/dev/Knoin/AbstractModel.js b/dev/Knoin/AbstractModel.js deleted file mode 100644 index c06198dad..000000000 --- a/dev/Knoin/AbstractModel.js +++ /dev/null @@ -1,41 +0,0 @@ - -var - _ = require('_'), - - Utils = require('Common/Utils'); - -/** - * @constructor - * - * @param {string} sModelName - */ -function AbstractModel(sModelName) -{ - this.sModelName = sModelName || ''; - this.disposables = []; -} - -/** - * @param {Array|Object} mInputValue - */ -AbstractModel.prototype.regDisposables = function(mInputValue) -{ - if (Utils.isArray(mInputValue)) - { - _.each(mInputValue, function(mValue) { - this.disposables.push(mValue); - }, this); - } - else if (mInputValue) - { - this.disposables.push(mInputValue); - } - -}; - -AbstractModel.prototype.onDestroy = function() -{ - Utils.disposeObject(this); -}; - -module.exports = AbstractModel; diff --git a/dev/Knoin/AbstractModel.jsx b/dev/Knoin/AbstractModel.jsx new file mode 100644 index 000000000..fb273ea9c --- /dev/null +++ b/dev/Knoin/AbstractModel.jsx @@ -0,0 +1,34 @@ + +import _ from '_'; +import {isArray, disposeObject} from 'Common/Utils'; + +class AbstractModel +{ + /** + * @param {string} modelName + */ + constructor(modelName) + { + this.sModelName = modelName || ''; + this.disposables = []; + } + + regDisposables(value) { + if (isArray(value)) + { + _.each(value, (item) => { + this.disposables.push(item); + }); + } + else if (value) + { + this.disposables.push(value); + } + } + + onDestroy() { + disposeObject(this); + } +} + +export {AbstractModel, AbstractModel as default}; diff --git a/dev/Model/Account.js b/dev/Model/Account.js deleted file mode 100644 index 6ebeea635..000000000 --- a/dev/Model/Account.js +++ /dev/null @@ -1,45 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Utils = require('Common/Utils'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - * - * @param {string} sEmail - * @param {boolean=} bCanBeDelete = true - * @param {number=} iCount = 0 - */ -function AccountModel(sEmail, bCanBeDelete, iCount) -{ - AbstractModel.call(this, 'AccountModel'); - - this.email = sEmail; - - this.count = ko.observable(iCount || 0); - - this.deleteAccess = ko.observable(false); - this.canBeDeleted = ko.observable(Utils.isUnd(bCanBeDelete) ? true : !!bCanBeDelete); - this.canBeEdit = this.canBeDeleted; -} - -_.extend(AccountModel.prototype, AbstractModel.prototype); - -/** - * @type {string} - */ -AccountModel.prototype.email = ''; - -/** - * @returns {string} - */ -AccountModel.prototype.changeAccountLink = function() -{ - return require('Common/Links').change(this.email); -}; - -module.exports = AccountModel; diff --git a/dev/Model/Account.jsx b/dev/Model/Account.jsx new file mode 100644 index 000000000..787b319d4 --- /dev/null +++ b/dev/Model/Account.jsx @@ -0,0 +1,36 @@ + +import ko from 'ko'; + +import {change} from 'Common/Links'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +class AccountModel extends AbstractModel +{ + /** + * @param {string} email + * @param {boolean=} canBeDelete = true + * @param {number=} count = 0 + */ + constructor(email, canBeDelete = true, count = 0) + { + super('AccountModel'); + + this.email = email; + + this.count = ko.observable(count); + + this.deleteAccess = ko.observable(false); + this.canBeDeleted = ko.observable(!!canBeDelete); + this.canBeEdit = this.canBeDeleted; + } + + /** + * @returns {string} + */ + changeAccountLink() { + return change(this.email); + } +} + +export {AccountModel, AccountModel as default}; diff --git a/dev/Model/Attachment.js b/dev/Model/Attachment.js deleted file mode 100644 index 79ed346dd..000000000 --- a/dev/Model/Attachment.js +++ /dev/null @@ -1,545 +0,0 @@ - -var - window = require('window'), - _ = require('_'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Globals = require('Common/Globals'), - Utils = require('Common/Utils'), - Links = require('Common/Links'), - Audio = require('Common/Audio'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - */ -function AttachmentModel() -{ - AbstractModel.call(this, 'AttachmentModel'); - - this.checked = ko.observable(false); - - this.mimeType = ''; - this.fileName = ''; - this.fileNameExt = ''; - this.fileType = Enums.FileType.Unknown; - this.estimatedSize = 0; - this.friendlySize = ''; - this.isInline = false; - this.isLinked = false; - this.isThumbnail = false; - this.cid = ''; - this.cidWithOutTags = ''; - this.contentLocation = ''; - this.download = ''; - this.folder = ''; - this.uid = ''; - this.mimeIndex = ''; - this.framed = false; -} - -_.extend(AttachmentModel.prototype, AbstractModel.prototype); - -/** - * @static - * @param {AjaxJsonAttachment} oJsonAttachment - * @returns {?AttachmentModel} - */ -AttachmentModel.newInstanceFromJson = function(oJsonAttachment) -{ - var oAttachmentModel = new AttachmentModel(); - return oAttachmentModel.initByJson(oJsonAttachment) ? oAttachmentModel : null; -}; - -AttachmentModel.prototype.mimeType = ''; -AttachmentModel.prototype.fileName = ''; -AttachmentModel.prototype.fileType = ''; -AttachmentModel.prototype.fileNameExt = ''; -AttachmentModel.prototype.estimatedSize = 0; -AttachmentModel.prototype.friendlySize = ''; -AttachmentModel.prototype.isInline = false; -AttachmentModel.prototype.isLinked = false; -AttachmentModel.prototype.isThumbnail = false; -AttachmentModel.prototype.cid = ''; -AttachmentModel.prototype.cidWithOutTags = ''; -AttachmentModel.prototype.contentLocation = ''; -AttachmentModel.prototype.download = ''; -AttachmentModel.prototype.folder = ''; -AttachmentModel.prototype.uid = ''; -AttachmentModel.prototype.mimeIndex = ''; -AttachmentModel.prototype.framed = false; - -/** - * @param {AjaxJsonAttachment} oJsonAttachment - */ -AttachmentModel.prototype.initByJson = function(oJsonAttachment) -{ - var bResult = false; - if (oJsonAttachment && 'Object/Attachment' === oJsonAttachment['@Object']) - { - this.mimeType = Utils.trim((oJsonAttachment.MimeType || '').toLowerCase()); - this.fileName = Utils.trim(oJsonAttachment.FileName); - this.estimatedSize = Utils.pInt(oJsonAttachment.EstimatedSize); - this.isInline = !!oJsonAttachment.IsInline; - this.isLinked = !!oJsonAttachment.IsLinked; - this.isThumbnail = !!oJsonAttachment.IsThumbnail; - this.cid = oJsonAttachment.CID; - this.contentLocation = oJsonAttachment.ContentLocation; - this.download = oJsonAttachment.Download; - - this.folder = oJsonAttachment.Folder; - this.uid = oJsonAttachment.Uid; - this.mimeIndex = oJsonAttachment.MimeIndex; - this.framed = !!oJsonAttachment.Framed; - - this.friendlySize = Utils.friendlySize(this.estimatedSize); - this.cidWithOutTags = this.cid.replace(/^<+/, '').replace(/>+$/, ''); - - this.fileNameExt = Utils.getFileExtension(this.fileName); - this.fileType = AttachmentModel.staticFileType(this.fileNameExt, this.mimeType); - - bResult = true; - } - - return bResult; -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.isImage = function() -{ - return Enums.FileType.Image === this.fileType; -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.isMp3 = function() -{ - return Enums.FileType.Audio === this.fileType && - 'mp3' === this.fileNameExt; -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.isOgg = function() -{ - return Enums.FileType.Audio === this.fileType && - ('oga' === this.fileNameExt || 'ogg' === this.fileNameExt); -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.isWav = function() -{ - return Enums.FileType.Audio === this.fileType && - 'wav' === this.fileNameExt; -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.hasThumbnail = function() -{ - return this.isThumbnail; -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.isText = function() -{ - return Enums.FileType.Text === this.fileType || - Enums.FileType.Eml === this.fileType || - Enums.FileType.Certificate === this.fileType || - Enums.FileType.Html === this.fileType || - Enums.FileType.Code === this.fileType; -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.isPdf = function() -{ - return Enums.FileType.Pdf === this.fileType; -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.isFramed = function() -{ - return this.framed && (Globals.data.__APP__ && Globals.data.__APP__.googlePreviewSupported()) && - !(this.isPdf() && Globals.bAllowPdfPreview) && !this.isText() && !this.isImage(); -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.hasPreview = function() -{ - return this.isImage() || (this.isPdf() && Globals.bAllowPdfPreview) || - this.isText() || this.isFramed(); -}; - -/** - * @returns {boolean} - */ -AttachmentModel.prototype.hasPreplay = function() -{ - return (Audio.supportedMp3 && this.isMp3()) || - (Audio.supportedOgg && this.isOgg()) || - (Audio.supportedWav && this.isWav()); -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.linkDownload = function() -{ - return Links.attachmentDownload(this.download); -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.linkPreview = function() -{ - return Links.attachmentPreview(this.download); -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.linkThumbnail = function() -{ - return this.hasThumbnail() ? Links.attachmentThumbnailPreview(this.download) : ''; -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.linkThumbnailPreviewStyle = function() -{ - var sLink = this.linkThumbnail(); - return '' === sLink ? '' : 'background:url(' + sLink + ')'; -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.linkFramed = function() -{ - return Links.attachmentFramed(this.download); -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.linkPreviewAsPlain = function() -{ - return Links.attachmentPreviewAsPlain(this.download); -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.linkPreviewMain = function() -{ - var sResult = ''; - switch (true) - { - case this.isImage(): - case this.isPdf() && Globals.bAllowPdfPreview: - sResult = this.linkPreview(); - break; - case this.isText(): - sResult = this.linkPreviewAsPlain(); - break; - case this.isFramed(): - sResult = this.linkFramed(); - break; - // no default - } - - return sResult; -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.generateTransferDownloadUrl = function() -{ - var sLink = this.linkDownload(); - if ('http' !== sLink.substr(0, 4)) - { - sLink = window.location.protocol + '//' + window.location.host + window.location.pathname + sLink; - } - - return this.mimeType + ':' + this.fileName + ':' + sLink; -}; - -/** - * @param {AttachmentModel} oAttachment - * @param {*} oEvent - * @returns {boolean} - */ -AttachmentModel.prototype.eventDragStart = function(oAttachment, oEvent) -{ - var oLocalEvent = oEvent.originalEvent || oEvent; - if (oAttachment && oLocalEvent && oLocalEvent.dataTransfer && oLocalEvent.dataTransfer.setData) - { - oLocalEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl()); - } - - return true; -}; - -/** - * @param {string} sExt - * @param {string} sMimeType - * @returns {string} - */ -AttachmentModel.staticFileType = _.memoize(function(sExt, sMimeType) -{ - sExt = Utils.trim(sExt).toLowerCase(); - sMimeType = Utils.trim(sMimeType).toLowerCase(); - - var - sResult = Enums.FileType.Unknown, - aMimeTypeParts = sMimeType.split('/'); - - switch (true) - { - case 'image' === aMimeTypeParts[0] || -1 < Utils.inArray(sExt, [ - 'png', 'jpg', 'jpeg', 'gif', 'bmp' - ]): - sResult = Enums.FileType.Image; - break; - case 'audio' === aMimeTypeParts[0] || -1 < Utils.inArray(sExt, [ - 'mp3', 'ogg', 'oga', 'wav' - ]): - sResult = Enums.FileType.Audio; - break; - case 'video' === aMimeTypeParts[0] || -1 < Utils.inArray(sExt, [ - 'mkv', 'avi' - ]): - sResult = Enums.FileType.Video; - break; - case -1 < Utils.inArray(sExt, [ - 'php', 'js', 'css' - ]): - sResult = Enums.FileType.Code; - break; - case 'eml' === sExt || -1 < Utils.inArray(sMimeType, [ - 'message/delivery-status', 'message/rfc822' - ]): - sResult = Enums.FileType.Eml; - break; - case ('text' === aMimeTypeParts[0] && 'html' !== aMimeTypeParts[1]) || -1 < Utils.inArray(sExt, [ - 'txt', 'log' - ]): - sResult = Enums.FileType.Text; - break; - case ('text/html' === sMimeType) || -1 < Utils.inArray(sExt, [ - 'html' - ]): - sResult = Enums.FileType.Html; - break; - case -1 < Utils.inArray(aMimeTypeParts[1], [ - 'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2', 'x-zip', 'x-7z', 'x-rar', 'x-tar', 'x-gzip', 'x-bzip', 'x-bzip2', 'x-zip-compressed', 'x-7z-compressed', 'x-rar-compressed' - ]) || -1 < Utils.inArray(sExt, [ - 'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2' - ]): - sResult = Enums.FileType.Archive; - break; - case -1 < Utils.inArray(aMimeTypeParts[1], ['pdf', 'x-pdf']) || -1 < Utils.inArray(sExt, [ - 'pdf' - ]): - sResult = Enums.FileType.Pdf; - break; - case -1 < Utils.inArray(sMimeType, [ - 'application/pgp-signature', 'application/pgp-keys' - ]) || -1 < Utils.inArray(sExt, [ - 'asc', 'pem', 'ppk' - ]): - sResult = Enums.FileType.Certificate; - break; - case -1 < Utils.inArray(sMimeType, ['application/pkcs7-signature']) || - -1 < Utils.inArray(sExt, ['p7s']): - - sResult = Enums.FileType.CertificateBin; - break; - case -1 < Utils.inArray(aMimeTypeParts[1], [ - 'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document', - 'vnd.openxmlformats-officedocument.wordprocessingml.template', - 'vnd.ms-word.document.macroEnabled.12', - 'vnd.ms-word.template.macroEnabled.12' - ]): - sResult = Enums.FileType.WordText; - break; - case -1 < Utils.inArray(aMimeTypeParts[1], [ - 'excel', 'ms-excel', 'vnd.ms-excel', - 'vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'vnd.openxmlformats-officedocument.spreadsheetml.template', - 'vnd.ms-excel.sheet.macroEnabled.12', - 'vnd.ms-excel.template.macroEnabled.12', - 'vnd.ms-excel.addin.macroEnabled.12', - 'vnd.ms-excel.sheet.binary.macroEnabled.12' - ]): - sResult = Enums.FileType.Sheet; - break; - case -1 < Utils.inArray(aMimeTypeParts[1], [ - 'powerpoint', 'ms-powerpoint', 'vnd.ms-powerpoint', - 'vnd.openxmlformats-officedocument.presentationml.presentation', - 'vnd.openxmlformats-officedocument.presentationml.template', - 'vnd.openxmlformats-officedocument.presentationml.slideshow', - 'vnd.ms-powerpoint.addin.macroEnabled.12', - 'vnd.ms-powerpoint.presentation.macroEnabled.12', - 'vnd.ms-powerpoint.template.macroEnabled.12', - 'vnd.ms-powerpoint.slideshow.macroEnabled.12' - ]): - sResult = Enums.FileType.Presentation; - break; - // no default - } - - return sResult; -}); - -/** - * @param {string} sFileType - * @returns {string} - */ -AttachmentModel.staticIconClass = _.memoize(function(sFileType) -{ - var - sText = '', - sClass = 'icon-file'; - - switch (sFileType) - { - case Enums.FileType.Text: - case Enums.FileType.Eml: - case Enums.FileType.WordText: - sClass = 'icon-file-text'; - break; - case Enums.FileType.Html: - case Enums.FileType.Code: - sClass = 'icon-file-code'; - break; - case Enums.FileType.Image: - sClass = 'icon-file-image'; - break; - case Enums.FileType.Audio: - sClass = 'icon-file-music'; - break; - case Enums.FileType.Video: - sClass = 'icon-file-movie'; - break; - case Enums.FileType.Archive: - sClass = 'icon-file-zip'; - break; - case Enums.FileType.Certificate: - case Enums.FileType.CertificateBin: - sClass = 'icon-file-certificate'; - break; - case Enums.FileType.Sheet: - sClass = 'icon-file-excel'; - break; - case Enums.FileType.Presentation: - sClass = 'icon-file-chart-graph'; - break; - case Enums.FileType.Pdf: - sText = 'pdf'; - sClass = 'icon-none'; - break; - // no default - } - - return [sClass, sText]; -}); - -/** - * @param {string} sFileType - * @returns {string} - */ -AttachmentModel.staticCombinedIconClass = function(aData) -{ - var - sClass = '', - aTypes = []; - - if (Utils.isNonEmptyArray(aData)) - { - sClass = 'icon-attachment'; - - aTypes = _.uniq(_.compact(_.map(aData, function(aItem) { - return aItem ? AttachmentModel.staticFileType( - Utils.getFileExtension(aItem[0]), aItem[1]) : ''; - }))); - - if (aTypes && 1 === aTypes.length && aTypes[0]) - { - switch (aTypes[0]) - { - case Enums.FileType.Text: - case Enums.FileType.WordText: - sClass = 'icon-file-text'; - break; - case Enums.FileType.Html: - case Enums.FileType.Code: - sClass = 'icon-file-code'; - break; - case Enums.FileType.Image: - sClass = 'icon-file-image'; - break; - case Enums.FileType.Audio: - sClass = 'icon-file-music'; - break; - case Enums.FileType.Video: - sClass = 'icon-file-movie'; - break; - case Enums.FileType.Archive: - sClass = 'icon-file-zip'; - break; - case Enums.FileType.Certificate: - case Enums.FileType.CertificateBin: - sClass = 'icon-file-certificate'; - break; - case Enums.FileType.Sheet: - sClass = 'icon-file-excel'; - break; - case Enums.FileType.Presentation: - sClass = 'icon-file-chart-graph'; - break; - // no default - } - } - } - - return sClass; -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.iconClass = function() -{ - return AttachmentModel.staticIconClass(this.fileType)[0]; -}; - -/** - * @returns {string} - */ -AttachmentModel.prototype.iconText = function() -{ - return AttachmentModel.staticIconClass(this.fileType)[1]; -}; - -module.exports = AttachmentModel; diff --git a/dev/Model/Attachment.jsx b/dev/Model/Attachment.jsx new file mode 100644 index 000000000..0b497b501 --- /dev/null +++ b/dev/Model/Attachment.jsx @@ -0,0 +1,487 @@ + +import window from 'window'; +import _ from '_'; +import ko from 'ko'; + +import {FileType} from 'Common/Enums'; +import {bAllowPdfPreview, data as GlobalsData} from 'Common/Globals'; +import {trim, pInt, inArray, isNonEmptyArray, getFileExtension, friendlySize} from 'Common/Utils'; +import {attachmentDownload, attachmentPreview, attachmentFramed, attachmentPreviewAsPlain, attachmentThumbnailPreview} from 'Common/Links'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +import Audio from 'Common/Audio'; + +/** + * @param {string} sExt + * @param {string} sMimeType + * @returns {string} + */ +export const staticFileType = _.memoize((ext, mimeType) => { + ext = trim(ext).toLowerCase(); + mimeType = trim(mimeType).toLowerCase(); + + let result = FileType.Unknown; + const mimeTypeParts = mimeType.split('/'); + + switch (true) + { + case 'image' === mimeTypeParts[0] || -1 < inArray(ext, [ + 'png', 'jpg', 'jpeg', 'gif', 'bmp' + ]): + result = FileType.Image; + break; + case 'audio' === mimeTypeParts[0] || -1 < inArray(ext, [ + 'mp3', 'ogg', 'oga', 'wav' + ]): + result = FileType.Audio; + break; + case 'video' === mimeTypeParts[0] || -1 < inArray(ext, [ + 'mkv', 'avi' + ]): + result = FileType.Video; + break; + case -1 < inArray(ext, [ + 'php', 'js', 'css' + ]): + result = FileType.Code; + break; + case 'eml' === ext || -1 < inArray(mimeType, [ + 'message/delivery-status', 'message/rfc822' + ]): + result = FileType.Eml; + break; + case ('text' === mimeTypeParts[0] && 'html' !== mimeTypeParts[1]) || -1 < inArray(ext, [ + 'txt', 'log' + ]): + result = FileType.Text; + break; + case ('text/html' === mimeType) || -1 < inArray(ext, [ + 'html' + ]): + result = FileType.Html; + break; + case -1 < inArray(mimeTypeParts[1], [ + 'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2', 'x-zip', 'x-7z', 'x-rar', 'x-tar', 'x-gzip', 'x-bzip', 'x-bzip2', 'x-zip-compressed', 'x-7z-compressed', 'x-rar-compressed' + ]) || -1 < inArray(ext, [ + 'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2' + ]): + result = FileType.Archive; + break; + case -1 < inArray(mimeTypeParts[1], ['pdf', 'x-pdf']) || -1 < inArray(ext, [ + 'pdf' + ]): + result = FileType.Pdf; + break; + case -1 < inArray(mimeType, [ + 'application/pgp-signature', 'application/pgp-keys' + ]) || -1 < inArray(ext, [ + 'asc', 'pem', 'ppk' + ]): + result = FileType.Certificate; + break; + case -1 < inArray(mimeType, ['application/pkcs7-signature']) || + -1 < inArray(ext, ['p7s']): + + result = FileType.CertificateBin; + break; + case -1 < inArray(mimeTypeParts[1], [ + 'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document', + 'vnd.openxmlformats-officedocument.wordprocessingml.template', + 'vnd.ms-word.document.macroEnabled.12', + 'vnd.ms-word.template.macroEnabled.12' + ]): + result = FileType.WordText; + break; + case -1 < inArray(mimeTypeParts[1], [ + 'excel', 'ms-excel', 'vnd.ms-excel', + 'vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'vnd.openxmlformats-officedocument.spreadsheetml.template', + 'vnd.ms-excel.sheet.macroEnabled.12', + 'vnd.ms-excel.template.macroEnabled.12', + 'vnd.ms-excel.addin.macroEnabled.12', + 'vnd.ms-excel.sheet.binary.macroEnabled.12' + ]): + result = FileType.Sheet; + break; + case -1 < inArray(mimeTypeParts[1], [ + 'powerpoint', 'ms-powerpoint', 'vnd.ms-powerpoint', + 'vnd.openxmlformats-officedocument.presentationml.presentation', + 'vnd.openxmlformats-officedocument.presentationml.template', + 'vnd.openxmlformats-officedocument.presentationml.slideshow', + 'vnd.ms-powerpoint.addin.macroEnabled.12', + 'vnd.ms-powerpoint.presentation.macroEnabled.12', + 'vnd.ms-powerpoint.template.macroEnabled.12', + 'vnd.ms-powerpoint.slideshow.macroEnabled.12' + ]): + result = FileType.Presentation; + break; + // no default + } + + return result; +}); + +/** + * @param {string} sFileType + * @returns {string} + */ +export const staticIconClass = _.memoize((fileType) => { + let + resultText = '', + resultClass = 'icon-file'; + + switch (fileType) + { + case FileType.Text: + case FileType.Eml: + case FileType.WordText: + resultClass = 'icon-file-text'; + break; + case FileType.Html: + case FileType.Code: + resultClass = 'icon-file-code'; + break; + case FileType.Image: + resultClass = 'icon-file-image'; + break; + case FileType.Audio: + resultClass = 'icon-file-music'; + break; + case FileType.Video: + resultClass = 'icon-file-movie'; + break; + case FileType.Archive: + resultClass = 'icon-file-zip'; + break; + case FileType.Certificate: + case FileType.CertificateBin: + resultClass = 'icon-file-certificate'; + break; + case FileType.Sheet: + resultClass = 'icon-file-excel'; + break; + case FileType.Presentation: + resultClass = 'icon-file-chart-graph'; + break; + case FileType.Pdf: + resultText = 'pdf'; + resultClass = 'icon-none'; + break; + // no default + } + + return [resultClass, resultText]; +}); + +/** + * @static + * @param {string} sFileType + * @returns {string} + */ +export const staticCombinedIconClass = (data) => { + let + result = '', + types = []; + + if (isNonEmptyArray(data)) + { + result = 'icon-attachment'; + types = _.uniq(_.compact(_.map(data, (item) => (item ? staticFileType(getFileExtension(item[0]), item[1]) : '')))); + + if (types && 1 === types.length && types[0]) + { + switch (types[0]) + { + case FileType.Text: + case FileType.WordText: + result = 'icon-file-text'; + break; + case FileType.Html: + case FileType.Code: + result = 'icon-file-code'; + break; + case FileType.Image: + result = 'icon-file-image'; + break; + case FileType.Audio: + result = 'icon-file-music'; + break; + case FileType.Video: + result = 'icon-file-movie'; + break; + case FileType.Archive: + result = 'icon-file-zip'; + break; + case FileType.Certificate: + case FileType.CertificateBin: + result = 'icon-file-certificate'; + break; + case FileType.Sheet: + result = 'icon-file-excel'; + break; + case FileType.Presentation: + result = 'icon-file-chart-graph'; + break; + // no default + } + } + } + + return result; +}; + +class AttachmentModel extends AbstractModel +{ + constructor() + { + super('AttachmentModel'); + + this.checked = ko.observable(false); + + this.mimeType = ''; + this.fileName = ''; + this.fileNameExt = ''; + this.fileType = FileType.Unknown; + this.estimatedSize = 0; + this.friendlySize = ''; + this.isInline = false; + this.isLinked = false; + this.isThumbnail = false; + this.cid = ''; + this.cidWithOutTags = ''; + this.contentLocation = ''; + this.download = ''; + this.folder = ''; + this.uid = ''; + this.mimeIndex = ''; + this.framed = false; + } + + /** + * @static + * @param {AjaxJsonAttachment} json + * @returns {?AttachmentModel} + */ + static newInstanceFromJson(json) { + const attachment = new AttachmentModel(); + return attachment.initByJson(json) ? attachment : null; + } + + /** + * @param {AjaxJsonAttachment} json + * @returns {boolean} + */ + initByJson(json) { + let bResult = false; + if (json && 'Object/Attachment' === json['@Object']) + { + this.mimeType = trim((json.MimeType || '').toLowerCase()); + this.fileName = trim(json.FileName); + this.estimatedSize = pInt(json.EstimatedSize); + this.isInline = !!json.IsInline; + this.isLinked = !!json.IsLinked; + this.isThumbnail = !!json.IsThumbnail; + this.cid = json.CID; + this.contentLocation = json.ContentLocation; + this.download = json.Download; + + this.folder = json.Folder; + this.uid = json.Uid; + this.mimeIndex = json.MimeIndex; + this.framed = !!json.Framed; + + this.friendlySize = friendlySize(this.estimatedSize); + this.cidWithOutTags = this.cid.replace(/^<+/, '').replace(/>+$/, ''); + + this.fileNameExt = getFileExtension(this.fileName); + this.fileType = staticFileType(this.fileNameExt, this.mimeType); + + bResult = true; + } + + return bResult; + } + + /** + * @returns {boolean} + */ + isImage() { + return FileType.Image === this.fileType; + } + + /** + * @returns {boolean} + */ + isMp3() { + return FileType.Audio === this.fileType && 'mp3' === this.fileNameExt; + } + + /** + * @returns {boolean} + */ + isOgg() { + return FileType.Audio === this.fileType && ('oga' === this.fileNameExt || 'ogg' === this.fileNameExt); + } + + /** + * @returns {boolean} + */ + isWav() { + return FileType.Audio === this.fileType && 'wav' === this.fileNameExt; + } + + /** + * @returns {boolean} + */ + hasThumbnail() { + return this.isThumbnail; + } + + /** + * @returns {boolean} + */ + isText() { + return FileType.Text === this.fileType || FileType.Eml === this.fileType || + FileType.Certificate === this.fileType || FileType.Html === this.fileType || FileType.Code === this.fileType; + } + + /** + * @returns {boolean} + */ + isPdf() { + return FileType.Pdf === this.fileType; + } + + /** + * @returns {boolean} + */ + isFramed() { + return this.framed && (GlobalsData.__APP__ && GlobalsData.__APP__.googlePreviewSupported()) && + !(this.isPdf() && bAllowPdfPreview) && !this.isText() && !this.isImage(); + } + + /** + * @returns {boolean} + */ + hasPreview() { + return this.isImage() || (this.isPdf() && bAllowPdfPreview) || this.isText() || this.isFramed(); + } + + /** + * @returns {boolean} + */ + hasPreplay() { + return (Audio.supportedMp3 && this.isMp3()) || (Audio.supportedOgg && this.isOgg()) || (Audio.supportedWav && this.isWav()); + } + + /** + * @returns {string} + */ + linkDownload() { + return attachmentDownload(this.download); + } + + /** + * @returns {string} + */ + linkPreview() { + return attachmentPreview(this.download); + } + + /** + * @returns {string} + */ + linkThumbnail() { + return this.hasThumbnail() ? attachmentThumbnailPreview(this.download) : ''; + } + + /** + * @returns {string} + */ + linkThumbnailPreviewStyle() { + const link = this.linkThumbnail(); + return '' === link ? '' : 'background:url(' + link + ')'; + } + + /** + * @returns {string} + */ + linkFramed() { + return attachmentFramed(this.download); + } + + /** + * @returns {string} + */ + linkPreviewAsPlain() { + return attachmentPreviewAsPlain(this.download); + } + + /** + * @returns {string} + */ + linkPreviewMain() { + let result = ''; + switch (true) + { + case this.isImage(): + case this.isPdf() && bAllowPdfPreview: + result = this.linkPreview(); + break; + case this.isText(): + result = this.linkPreviewAsPlain(); + break; + case this.isFramed(): + result = this.linkFramed(); + break; + // no default + } + + return result; + } + + /** + * @returns {string} + */ + generateTransferDownloadUrl() { + let link = this.linkDownload(); + if ('http' !== link.substr(0, 4)) + { + link = window.location.protocol + '//' + window.location.host + window.location.pathname + link; + } + + return this.mimeType + ':' + this.fileName + ':' + link; + } + + /** + * @param {AttachmentModel} attachment + * @param {*} event + * @returns {boolean} + */ + eventDragStart(attachment, event) { + const localEvent = event.originalEvent || event; + if (attachment && localEvent && localEvent.dataTransfer && localEvent.dataTransfer.setData) + { + localEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl()); + } + + return true; + } + + /** + * @returns {string} + */ + iconClass() { + return staticIconClass(this.fileType)[0]; + } + + /** + * @returns {string} + */ + iconText() { + return staticIconClass(this.fileType)[1]; + } +} + +export {AttachmentModel, AttachmentModel as default}; diff --git a/dev/Model/ComposeAttachment.js b/dev/Model/ComposeAttachment.js deleted file mode 100644 index 5f9128302..000000000 --- a/dev/Model/ComposeAttachment.js +++ /dev/null @@ -1,123 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Utils = require('Common/Utils'), - - AttachmentModel = require('Model/Attachment'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - * @param {string} sId - * @param {string} sFileName - * @param {?number=} nSize - * @param {boolean=} bInline - * @param {boolean=} bLinked - * @param {string=} sCID - * @param {string=} sContentLocation - */ -function ComposeAttachmentModel(sId, sFileName, nSize, bInline, bLinked, sCID, sContentLocation) -{ - AbstractModel.call(this, 'ComposeAttachmentModel'); - - this.id = sId; - this.isInline = Utils.isUnd(bInline) ? false : !!bInline; - this.isLinked = Utils.isUnd(bLinked) ? false : !!bLinked; - this.CID = Utils.isUnd(sCID) ? '' : sCID; - this.contentLocation = Utils.isUnd(sContentLocation) ? '' : sContentLocation; - this.fromMessage = false; - - this.fileName = ko.observable(sFileName); - this.size = ko.observable(Utils.isUnd(nSize) ? null : nSize); - this.tempName = ko.observable(''); - - this.progress = ko.observable(0); - this.error = ko.observable(''); - this.waiting = ko.observable(true); - this.uploading = ko.observable(false); - this.enabled = ko.observable(true); - this.complete = ko.observable(false); - - this.progressText = ko.computed(function() { - var iP = this.progress(); - return 0 === iP ? '' : '' + (98 < iP ? 100 : iP) + '%'; - }, this); - - this.progressStyle = ko.computed(function() { - var iP = this.progress(); - return 0 === iP ? '' : 'width:' + (98 < iP ? 100 : iP) + '%'; - }, this); - - this.title = ko.computed(function() { - var sError = this.error(); - return '' !== sError ? sError : this.fileName(); - }, this); - - this.friendlySize = ko.computed(function() { - var mSize = this.size(); - return null === mSize ? '' : Utils.friendlySize(this.size()); - }, this); - - this.mimeType = ko.computed(function() { - return Utils.mimeContentType(this.fileName()); - }, this); - - this.fileExt = ko.computed(function() { - return Utils.getFileExtension(this.fileName()); - }, this); - - this.regDisposables([this.progressText, this.progressStyle, this.title, this.friendlySize, this.mimeType, this.fileExt]); -} - -_.extend(ComposeAttachmentModel.prototype, AbstractModel.prototype); - -ComposeAttachmentModel.prototype.id = ''; -ComposeAttachmentModel.prototype.isInline = false; -ComposeAttachmentModel.prototype.isLinked = false; -ComposeAttachmentModel.prototype.CID = ''; -ComposeAttachmentModel.prototype.contentLocation = ''; -ComposeAttachmentModel.prototype.fromMessage = false; -ComposeAttachmentModel.prototype.cancel = Utils.noop; - -/** - * @param {AjaxJsonComposeAttachment} oJsonAttachment - * @returns {boolean} - */ -ComposeAttachmentModel.prototype.initByUploadJson = function(oJsonAttachment) -{ - var bResult = false; - if (oJsonAttachment) - { - this.fileName(oJsonAttachment.Name); - this.size(Utils.isUnd(oJsonAttachment.Size) ? 0 : Utils.pInt(oJsonAttachment.Size)); - this.tempName(Utils.isUnd(oJsonAttachment.TempName) ? '' : oJsonAttachment.TempName); - this.isInline = false; - - bResult = true; - } - - return bResult; -}; - -/** - * @returns {string} - */ -ComposeAttachmentModel.prototype.iconClass = function() -{ - return AttachmentModel.staticIconClass( - AttachmentModel.staticFileType(this.fileExt(), this.mimeType()))[0]; -}; - -/** - * @returns {string} - */ -ComposeAttachmentModel.prototype.iconText = function() -{ - return AttachmentModel.staticIconClass( - AttachmentModel.staticFileType(this.fileExt(), this.mimeType()))[1]; -}; - -module.exports = ComposeAttachmentModel; diff --git a/dev/Model/ComposeAttachment.jsx b/dev/Model/ComposeAttachment.jsx new file mode 100644 index 000000000..cff7ac021 --- /dev/null +++ b/dev/Model/ComposeAttachment.jsx @@ -0,0 +1,101 @@ + +import ko from 'ko'; +import {isUnd, pInt, friendlySize, mimeContentType, getFileExtension} from 'Common/Utils'; + +import {staticIconClass, staticFileType} from 'Model/Attachment'; +import {AbstractModel} from 'Knoin/AbstractModel'; + +class ComposeAttachmentModel extends AbstractModel +{ + /** + * @param {string} id + * @param {string} fileName + * @param {?number=} size = null + * @param {boolean=} isInline = false + * @param {boolean=} isLinked = false + * @param {string=} CID = '' + * @param {string=} contentLocation = '' + */ + constructor(id, fileName, size = null, isInline = false, isLinked = false, CID = '', contentLocation = '') + { + super('ComposeAttachmentModel'); + + this.id = id; + this.isInline = !!isInline; + this.isLinked = !!isLinked; + this.CID = CID; + this.contentLocation = contentLocation; + this.fromMessage = false; + + this.fileName = ko.observable(fileName); + this.size = ko.observable(size); + this.tempName = ko.observable(''); + + this.progress = ko.observable(0); + this.error = ko.observable(''); + this.waiting = ko.observable(true); + this.uploading = ko.observable(false); + this.enabled = ko.observable(true); + this.complete = ko.observable(false); + + this.progressText = ko.computed(() => { + const p = this.progress(); + return 0 === p ? '' : '' + (98 < p ? 100 : p) + '%'; + }); + + this.progressStyle = ko.computed(() => { + const p = this.progress(); + return 0 === p ? '' : 'width:' + (98 < p ? 100 : p) + '%'; + }); + + this.title = ko.computed(() => { + const error = this.error(); + return '' !== error ? error : this.fileName(); + }); + + this.friendlySize = ko.computed(() => { + const localSize = this.size(); + return null === localSize ? '' : friendlySize(localSize); + }); + + this.mimeType = ko.computed(() => mimeContentType(this.fileName())); + this.fileExt = ko.computed(() => getFileExtension(this.fileName())); + + this.regDisposables([this.progressText, this.progressStyle, this.title, this.friendlySize, this.mimeType, this.fileExt]); + } + + /** + * @param {AjaxJsonComposeAttachment} json + * @returns {boolean} + */ + initByUploadJson(json) { + let bResult = false; + if (json) + { + this.fileName(json.Name); + this.size(isUnd(json.Size) ? 0 : pInt(json.Size)); + this.tempName(isUnd(json.TempName) ? '' : json.TempName); + this.isInline = false; + + bResult = true; + } + + return bResult; + } + + /** + * @returns {string} + */ + iconClass() { + return staticIconClass(staticFileType(this.fileExt(), this.mimeType()))[0]; + } + + /** + * @returns {string} + */ + iconText() { + return staticIconClass(staticFileType(this.fileExt(), this.mimeType()))[1]; + } +} + +export {ComposeAttachmentModel, ComposeAttachmentModel as default}; diff --git a/dev/Model/Contact.js b/dev/Model/Contact.js deleted file mode 100644 index 977f8f8a6..000000000 --- a/dev/Model/Contact.js +++ /dev/null @@ -1,132 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Links = require('Common/Links'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - */ -function ContactModel() -{ - AbstractModel.call(this, 'ContactModel'); - - this.idContact = 0; - this.display = ''; - this.properties = []; - this.readOnly = false; - - this.focused = ko.observable(false); - this.selected = ko.observable(false); - this.checked = ko.observable(false); - this.deleted = ko.observable(false); -} - -_.extend(ContactModel.prototype, AbstractModel.prototype); - -/** - * @returns {Array|null} - */ -ContactModel.prototype.getNameAndEmailHelper = function() -{ - var - sName = '', - sEmail = ''; - - if (Utils.isNonEmptyArray(this.properties)) - { - _.each(this.properties, function(aProperty) { - if (aProperty) - { - if (Enums.ContactPropertyType.FirstName === aProperty[0]) - { - sName = Utils.trim(aProperty[1] + ' ' + sName); - } - else if (Enums.ContactPropertyType.LastName === aProperty[0]) - { - sName = Utils.trim(sName + ' ' + aProperty[1]); - } - else if ('' === sEmail && Enums.ContactPropertyType.Email === aProperty[0]) - { - sEmail = aProperty[1]; - } - } - }, this); - } - - return '' === sEmail ? null : [sEmail, sName]; -}; - -ContactModel.prototype.parse = function(oItem) -{ - var bResult = false; - if (oItem && 'Object/Contact' === oItem['@Object']) - { - this.idContact = Utils.pInt(oItem.IdContact); - this.display = Utils.pString(oItem.Display); - this.readOnly = !!oItem.ReadOnly; - - if (Utils.isNonEmptyArray(oItem.Properties)) - { - _.each(oItem.Properties, function(oProperty) { - if (oProperty && oProperty.Type && Utils.isNormal(oProperty.Value) && Utils.isNormal(oProperty.TypeStr)) - { - this.properties.push([Utils.pInt(oProperty.Type), Utils.pString(oProperty.Value), Utils.pString(oProperty.TypeStr)]); - } - }, this); - } - - bResult = true; - } - - return bResult; -}; - -/** - * @returns {string} - */ -ContactModel.prototype.srcAttr = function() -{ - return Links.emptyContactPic(); -}; - -/** - * @returns {string} - */ -ContactModel.prototype.generateUid = function() -{ - return '' + this.idContact; -}; - -/** - * @return string - */ -ContactModel.prototype.lineAsCss = function() -{ - var aResult = []; - if (this.deleted()) - { - aResult.push('deleted'); - } - if (this.selected()) - { - aResult.push('selected'); - } - if (this.checked()) - { - aResult.push('checked'); - } - if (this.focused()) - { - aResult.push('focused'); - } - - return aResult.join(' '); -}; - -module.exports = ContactModel; diff --git a/dev/Model/Contact.jsx b/dev/Model/Contact.jsx new file mode 100644 index 000000000..55c464bbf --- /dev/null +++ b/dev/Model/Contact.jsx @@ -0,0 +1,128 @@ + +import _ from '_'; +import ko from 'ko'; + +import {ContactPropertyType} from 'Common/Enums'; +import {trim, isNonEmptyArray, isNormal, pInt, pString} from 'Common/Utils'; +import {emptyContactPic} from 'Common/Links'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +class ContactModel extends AbstractModel +{ + constructor() + { + super('ContactModel'); + + this.idContact = 0; + this.display = ''; + this.properties = []; + this.readOnly = false; + + this.focused = ko.observable(false); + this.selected = ko.observable(false); + this.checked = ko.observable(false); + this.deleted = ko.observable(false); + } + + /** + * @returns {Array|null} + */ + getNameAndEmailHelper() { + let + name = '', + email = ''; + + if (isNonEmptyArray(this.properties)) + { + _.each(this.properties, (property) => { + if (property) + { + if (ContactPropertyType.FirstName === property[0]) + { + name = trim(property[1] + ' ' + name); + } + else if (ContactPropertyType.LastName === property[0]) + { + name = trim(name + ' ' + property[1]); + } + else if ('' === email && ContactPropertyType.Email === property[0]) + { + email = property[1]; + } + } + }); + } + + return '' === email ? null : [email, name]; + } + + /** + * @param {Object} oItem + * @returns {boolean} + */ + parse(json) { + let result = false; + if (json && 'Object/Contact' === json['@Object']) + { + this.idContact = pInt(json.IdContact); + this.display = pString(json.Display); + this.readOnly = !!json.ReadOnly; + + if (isNonEmptyArray(json.Properties)) + { + _.each(json.Properties, (property) => { + if (property && property.Type && isNormal(property.Value) && isNormal(property.TypeStr)) + { + this.properties.push([pInt(property.Type), pString(property.Value), pString(property.TypeStr)]); + } + }); + } + + result = true; + } + + return result; + } + + /** + * @returns {string} + */ + srcAttr() { + return emptyContactPic(); + } + + /** + * @returns {string} + */ + generateUid() { + return pString(this.idContact); + } + + /** + * @return string + */ + lineAsCss() { + const result = []; + if (this.deleted()) + { + result.push('deleted'); + } + if (this.selected()) + { + result.push('selected'); + } + if (this.checked()) + { + result.push('checked'); + } + if (this.focused()) + { + result.push('focused'); + } + + return result.join(' '); + } +} + +export {ContactModel, ContactModel as default}; diff --git a/dev/Model/ContactProperty.js b/dev/Model/ContactProperty.js deleted file mode 100644 index 49498d066..000000000 --- a/dev/Model/ContactProperty.js +++ /dev/null @@ -1,45 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - * @param {number=} iType = Enums.ContactPropertyType.Unknown - * @param {string=} sTypeStr = '' - * @param {string=} sValue = '' - * @param {boolean=} bFocused = false - * @param {string=} sPlaceholder = '' - */ -function ContactPropertyModel(iType, sTypeStr, sValue, bFocused, sPlaceholder) -{ - AbstractModel.call(this, 'ContactPropertyModel'); - - this.type = ko.observable(Utils.isUnd(iType) ? Enums.ContactPropertyType.Unknown : iType); - this.typeStr = ko.observable(Utils.isUnd(sTypeStr) ? '' : sTypeStr); - this.focused = ko.observable(Utils.isUnd(bFocused) ? false : !!bFocused); - this.value = ko.observable(Utils.pString(sValue)); - - this.placeholder = ko.observable(sPlaceholder || ''); - - this.placeholderValue = ko.computed(function() { - var value = this.placeholder(); - return value ? Translator.i18n(value) : ''; - }, this); - - this.largeValue = ko.computed(function() { - return Enums.ContactPropertyType.Note === this.type(); - }, this); - - this.regDisposables([this.placeholderValue, this.largeValue]); -} - -_.extend(ContactPropertyModel.prototype, AbstractModel.prototype); - -module.exports = ContactPropertyModel; diff --git a/dev/Model/ContactProperty.jsx b/dev/Model/ContactProperty.jsx new file mode 100644 index 000000000..e77469338 --- /dev/null +++ b/dev/Model/ContactProperty.jsx @@ -0,0 +1,41 @@ + +import ko from 'ko'; + +import {ContactPropertyType} from 'Common/Enums'; +import {pInt, pString} from 'Common/Utils'; +import {i18n} from 'Common/Translator'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +class ContactPropertyModel extends AbstractModel +{ + /** + * @param {number=} type = Enums.ContactPropertyType.Unknown + * @param {string=} typeStr = '' + * @param {string=} value = '' + * @param {boolean=} focused = false + * @param {string=} placeholder = '' + */ + constructor(type = ContactPropertyType.Unknown, typeStr = '', value = '', focused = false, placeholder = '') + { + super('ContactPropertyModel'); + + this.type = ko.observable(pInt(type)); + this.typeStr = ko.observable(pString(typeStr)); + this.focused = ko.observable(!!focused); + this.value = ko.observable(pString(value)); + + this.placeholder = ko.observable(placeholder); + + this.placeholderValue = ko.computed(() => { + const v = this.placeholder(); + return v ? i18n(v) : ''; + }); + + this.largeValue = ko.computed(() => ContactPropertyType.Note === this.type()); + + this.regDisposables([this.placeholderValue, this.largeValue]); + } +} + +export {ContactPropertyModel, ContactPropertyModel as default}; diff --git a/dev/Model/Email.js b/dev/Model/Email.js deleted file mode 100644 index cdf58c701..000000000 --- a/dev/Model/Email.js +++ /dev/null @@ -1,401 +0,0 @@ - -var Utils = require('Common/Utils'); - -/** - * @constructor - * @param {string=} sEmail - * @param {string=} sName - * @param {string=} sDkimStatus - * @param {string=} sDkimValue - */ -function EmailModel(sEmail, sName, sDkimStatus, sDkimValue) -{ - this.email = sEmail || ''; - this.name = sName || ''; - this.dkimStatus = sDkimStatus || 'none'; - this.dkimValue = sDkimValue || ''; - - this.clearDuplicateName(); -} - -/** - * @static - * @param {AjaxJsonEmail} oJsonEmail - * @returns {?EmailModel} - */ -EmailModel.newInstanceFromJson = function(oJsonEmail) -{ - var oEmailModel = new EmailModel(); - return oEmailModel.initByJson(oJsonEmail) ? oEmailModel : null; -}; - -/** - * @static - * @param {string} sLine - * @param {string=} sDelimiter = ';' - * @returns {Array} - */ -EmailModel.splitHelper = function(sLine, sDelimiter) -{ - sDelimiter = sDelimiter || ';'; - - sLine = sLine.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' '); - - var - iIndex = 0, - iLen = sLine.length, - bAt = false, - sChar = '', - sResult = ''; - - for (; iIndex < iLen; iIndex++) - { - sChar = sLine.charAt(iIndex); - switch (sChar) - { - case '@': - bAt = true; - break; - case ' ': - if (bAt) - { - bAt = false; - sResult += sDelimiter; - } - break; - // no default - } - - sResult += sChar; - } - - return sResult.split(sDelimiter); -}; - -/** - * @type {string} - */ -EmailModel.prototype.name = ''; - -/** - * @type {string} - */ -EmailModel.prototype.email = ''; - -/** - * @type {string} - */ -EmailModel.prototype.dkimStatus = 'none'; - -/** - * @type {string} - */ -EmailModel.prototype.dkimValue = ''; - -EmailModel.prototype.clear = function() -{ - this.email = ''; - this.name = ''; - - this.dkimStatus = 'none'; - this.dkimValue = ''; -}; - -/** - * @returns {boolean} - */ -EmailModel.prototype.validate = function() -{ - return '' !== this.name || '' !== this.email; -}; - -/** - * @param {boolean} bWithoutName = false - * @returns {string} - */ -EmailModel.prototype.hash = function(bWithoutName) -{ - return '#' + (bWithoutName ? '' : this.name) + '#' + this.email + '#'; -}; - -EmailModel.prototype.clearDuplicateName = function() -{ - if (this.name === this.email) - { - this.name = ''; - } -}; - -/** - * @param {string} sQuery - * @returns {boolean} - */ -EmailModel.prototype.search = function(sQuery) -{ - return -1 < (this.name + ' ' + this.email).toLowerCase().indexOf(sQuery.toLowerCase()); -}; - -/** - * @param {string} sString - */ -EmailModel.prototype.parse = function(sString) -{ - this.clear(); - - sString = Utils.trim(sString); - - var - mRegex = /(?:"([^"]+)")? ?[<]?(.*?@[^>,]+)>?,? ?/g, - mMatch = mRegex.exec(sString); - - if (mMatch) - { - this.name = mMatch[1] || ''; - this.email = mMatch[2] || ''; - - this.clearDuplicateName(); - } - else if ((/^[^@]+@[^@]+$/).test(sString)) - { - this.name = ''; - this.email = sString; - } -}; - -/** - * @param {AjaxJsonEmail} oJsonEmail - * @returns {boolean} - */ -EmailModel.prototype.initByJson = function(oJsonEmail) -{ - var bResult = false; - if (oJsonEmail && 'Object/Email' === oJsonEmail['@Object']) - { - this.name = Utils.trim(oJsonEmail.Name); - this.email = Utils.trim(oJsonEmail.Email); - this.dkimStatus = Utils.trim(oJsonEmail.DkimStatus || ''); - this.dkimValue = Utils.trim(oJsonEmail.DkimValue || ''); - - bResult = '' !== this.email; - this.clearDuplicateName(); - } - - return bResult; -}; - -/** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @param {boolean=} bEncodeHtml = false - * @returns {string} - */ -EmailModel.prototype.toLine = function(bFriendlyView, bWrapWithLink, bEncodeHtml) -{ - var sResult = ''; - if ('' !== this.email) - { - bWrapWithLink = Utils.isUnd(bWrapWithLink) ? false : !!bWrapWithLink; - bEncodeHtml = Utils.isUnd(bEncodeHtml) ? false : !!bEncodeHtml; - - if (bFriendlyView && '' !== this.name) - { - sResult = bWrapWithLink ? '') + - '" target="_blank" tabindex="-1">' + Utils.encodeHtml(this.name) + '' : - (bEncodeHtml ? Utils.encodeHtml(this.name) : this.name); - } - else - { - sResult = this.email; - if ('' !== this.name) - { - if (bWrapWithLink) - { - sResult = Utils.encodeHtml('"' + this.name + '" <') + '') + - '" target="_blank" tabindex="-1">' + - Utils.encodeHtml(sResult) + - '' + - Utils.encodeHtml('>'); - } - else - { - sResult = '"' + this.name + '" <' + sResult + '>'; - if (bEncodeHtml) - { - sResult = Utils.encodeHtml(sResult); - } - } - } - else if (bWrapWithLink) - { - sResult = '' + Utils.encodeHtml(this.email) + ''; - } - } - } - - return sResult; -}; - -/** - * @param {string} $sEmailAddress - * @returns {boolean} - */ -EmailModel.prototype.mailsoParse = function($sEmailAddress) -{ - $sEmailAddress = Utils.trim($sEmailAddress); - if ('' === $sEmailAddress) - { - return false; - } - - var - substr = function(str, start, len) { - str = Utils.pString(str); - var end = str.length; - - if (0 > start) - { - start += end; - } - - end = 'undefined' === typeof len ? end : (0 > len ? len + end : len + start); - - return start >= str.length || 0 > start || start > end ? false : str.slice(start, end); - }, - - substrReplace = function(str, replace, start, length) { - str = Utils.pString(str); - if (0 > start) - { - start += str.length; - } - - length = 'undefined' !== typeof length ? length : str.length; - if (0 > length) - { - length = length + str.length - start; - } - return str.slice(0, start) + replace.substr(0, length) + replace.slice(length) + str.slice(start + length); - }, - - $sName = '', - $sEmail = '', - $sComment = '', - - $bInName = false, - $bInAddress = false, - $bInComment = false, - - $aRegs = null, - - $iStartIndex = 0, - $iEndIndex = 0, - $iCurrentIndex = 0; - - while ($iCurrentIndex < $sEmailAddress.length) - { - switch ($sEmailAddress.substr($iCurrentIndex, 1)) - { - case '"': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInName = true; - $iStartIndex = $iCurrentIndex; - } - else if ((!$bInAddress) && (!$bInComment)) - { - $iEndIndex = $iCurrentIndex; - $sName = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInName = false; - } - break; - case '<': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - if (0 < $iCurrentIndex && 0 === $sName.length) - { - $sName = substr($sEmailAddress, 0, $iCurrentIndex); - } - - $bInAddress = true; - $iStartIndex = $iCurrentIndex; - } - break; - case '>': - if ($bInAddress) - { - $iEndIndex = $iCurrentIndex; - $sEmail = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInAddress = false; - } - break; - case '(': - if ((!$bInName) && (!$bInAddress) && (!$bInComment)) - { - $bInComment = true; - $iStartIndex = $iCurrentIndex; - } - break; - case ')': - if ($bInComment) - { - $iEndIndex = $iCurrentIndex; - $sComment = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); - $sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); - $iEndIndex = 0; - $iCurrentIndex = 0; - $iStartIndex = 0; - $bInComment = false; - } - break; - case '\\': - $iCurrentIndex += 1; - break; - // no default - } - - $iCurrentIndex += 1; - } - - if (0 === $sEmail.length) - { - $aRegs = $sEmailAddress.match(/[^@\s]+@\S+/i); - if ($aRegs && $aRegs[0]) - { - $sEmail = $aRegs[0]; - } - else - { - $sName = $sEmailAddress; - } - } - - if (0 < $sEmail.length && 0 === $sName.length && 0 === $sComment.length) - { - $sName = $sEmailAddress.replace($sEmail, ''); - } - - $sEmail = Utils.trim($sEmail).replace(/^[<]+/, '').replace(/[>]+$/, ''); - $sName = Utils.trim($sName).replace(/^["']+/, '').replace(/["']+$/, ''); - $sComment = Utils.trim($sComment).replace(/^[(]+/, '').replace(/[)]+$/, ''); - - // Remove backslash - $sName = $sName.replace(/\\\\(.)/g, '$1'); - $sComment = $sComment.replace(/\\\\(.)/g, '$1'); - - this.name = $sName; - this.email = $sEmail; - - this.clearDuplicateName(); - return true; -}; - -module.exports = EmailModel; diff --git a/dev/Model/Email.jsx b/dev/Model/Email.jsx new file mode 100644 index 000000000..4ec893c18 --- /dev/null +++ b/dev/Model/Email.jsx @@ -0,0 +1,372 @@ + +import {trim, pString, encodeHtml} from 'Common/Utils'; + +class EmailModel +{ + /** + * @param {string=} email = '' + * @param {string=} name = '' + * @param {string=} dkimStatus = 'none' + * @param {string=} dkimValue = '' + */ + constructor(email = '', name = '', dkimStatus = 'none', dkimValue = '') + { + this.email = email; + this.name = name; + this.dkimStatus = dkimStatus; + this.dkimValue = dkimValue; + + this.clearDuplicateName(); + } + + /** + * @static + * @param {AjaxJsonEmail} json + * @returns {?EmailModel} + */ + static newInstanceFromJson(json) { + const email = new EmailModel(); + return email.initByJson(json) ? email : null; + } + + /** + * @static + * @param {string} line + * @param {string=} delimiter = ';' + * @returns {Array} + */ + static splitHelper(line, delimiter = ';') { + line = line.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' '); + + let + index = 0, + len = 0, + at = false, + char = '', + result = ''; + + for (len = line.length; index < len; index++) + { + char = line.charAt(index); + switch (char) + { + case '@': + at = true; + break; + case ' ': + if (at) + { + at = false; + result += delimiter; + } + break; + // no default + } + + result += char; + } + + return result.split(delimiter); + } + + /** + * @returns {void} + */ + clear() { + this.email = ''; + this.name = ''; + + this.dkimStatus = 'none'; + this.dkimValue = ''; + } + + /** + * @returns {boolean} + */ + validate() { + return '' !== this.name || '' !== this.email; + } + + /** + * @param {boolean} withoutName = false + * @returns {string} + */ + hash(withoutName = false) { + return '#' + (withoutName ? '' : this.name) + '#' + this.email + '#'; + } + + /** + * @returns {void} + */ + clearDuplicateName() { + if (this.name === this.email) + { + this.name = ''; + } + } + + /** + * @param {string} query + * @returns {boolean} + */ + search(query) { + return -1 < (this.name + ' ' + this.email).toLowerCase().indexOf(query.toLowerCase()); + } + + /** + * @param {string} str + */ + parse(str) { + this.clear(); + + str = trim(str); + + const + regex = /(?:"([^"]+)")? ?[<]?(.*?@[^>,]+)>?,? ?/g, + match = regex.exec(str); + + if (match) + { + this.name = match[1] || ''; + this.email = match[2] || ''; + + this.clearDuplicateName(); + } + else if ((/^[^@]+@[^@]+$/).test(str)) + { + this.name = ''; + this.email = str; + } + } + + /** + * @param {AjaxJsonEmail} oJsonEmail + * @returns {boolean} + */ + initByJson(json) { + let result = false; + if (json && 'Object/Email' === json['@Object']) + { + this.name = trim(json.Name); + this.email = trim(json.Email); + this.dkimStatus = trim(json.DkimStatus || ''); + this.dkimValue = trim(json.DkimValue || ''); + + result = '' !== this.email; + this.clearDuplicateName(); + } + + return result; + } + + /** + * @param {boolean} friendlyView + * @param {boolean=} wrapWithLink = false + * @param {boolean=} useEncodeHtml = false + * @returns {string} + */ + toLine(friendlyView, wrapWithLink = false, useEncodeHtml = false) { + let result = ''; + if ('' !== this.email) + { + if (friendlyView && '' !== this.name) + { + result = wrapWithLink ? '') + + '" target="_blank" tabindex="-1">' + encodeHtml(this.name) + '' : (encodeHtml ? encodeHtml(this.name) : this.name); + } + else + { + result = this.email; + if ('' !== this.name) + { + if (wrapWithLink) + { + result = encodeHtml('"' + this.name + '" <') + '') + + '" target="_blank" tabindex="-1">' + + encodeHtml(result) + + '' + + encodeHtml('>'); + } + else + { + result = '"' + this.name + '" <' + result + '>'; + if (useEncodeHtml) + { + result = encodeHtml(result); + } + } + } + else if (wrapWithLink) + { + result = '' + encodeHtml(this.email) + ''; + } + } + } + + return result; + } + + /** + * @param {string} $sEmailAddress + * @returns {boolean} + */ + mailsoParse($sEmailAddress) { + $sEmailAddress = trim($sEmailAddress); + if ('' === $sEmailAddress) + { + return false; + } + + var + substr = function(str, start, len) { + str = pString(str); + var end = str.length; + + if (0 > start) + { + start += end; + } + + end = 'undefined' === typeof len ? end : (0 > len ? len + end : len + start); + + return start >= str.length || 0 > start || start > end ? false : str.slice(start, end); + }, + + substrReplace = function(str, replace, start, length) { + str = pString(str); + if (0 > start) + { + start += str.length; + } + + length = 'undefined' !== typeof length ? length : str.length; + if (0 > length) + { + length = length + str.length - start; + } + return str.slice(0, start) + replace.substr(0, length) + replace.slice(length) + str.slice(start + length); + }, + + $sName = '', + $sEmail = '', + $sComment = '', + + $bInName = false, + $bInAddress = false, + $bInComment = false, + + $aRegs = null, + + $iStartIndex = 0, + $iEndIndex = 0, + $iCurrentIndex = 0; + + while ($iCurrentIndex < $sEmailAddress.length) + { + switch ($sEmailAddress.substr($iCurrentIndex, 1)) + { + case '"': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInName = true; + $iStartIndex = $iCurrentIndex; + } + else if ((!$bInAddress) && (!$bInComment)) + { + $iEndIndex = $iCurrentIndex; + $sName = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInName = false; + } + break; + case '<': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + if (0 < $iCurrentIndex && 0 === $sName.length) + { + $sName = substr($sEmailAddress, 0, $iCurrentIndex); + } + + $bInAddress = true; + $iStartIndex = $iCurrentIndex; + } + break; + case '>': + if ($bInAddress) + { + $iEndIndex = $iCurrentIndex; + $sEmail = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInAddress = false; + } + break; + case '(': + if ((!$bInName) && (!$bInAddress) && (!$bInComment)) + { + $bInComment = true; + $iStartIndex = $iCurrentIndex; + } + break; + case ')': + if ($bInComment) + { + $iEndIndex = $iCurrentIndex; + $sComment = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1); + $sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1); + $iEndIndex = 0; + $iCurrentIndex = 0; + $iStartIndex = 0; + $bInComment = false; + } + break; + case '\\': + $iCurrentIndex += 1; + break; + // no default + } + + $iCurrentIndex += 1; + } + + if (0 === $sEmail.length) + { + $aRegs = $sEmailAddress.match(/[^@\s]+@\S+/i); + if ($aRegs && $aRegs[0]) + { + $sEmail = $aRegs[0]; + } + else + { + $sName = $sEmailAddress; + } + } + + if (0 < $sEmail.length && 0 === $sName.length && 0 === $sComment.length) + { + $sName = $sEmailAddress.replace($sEmail, ''); + } + + $sEmail = trim($sEmail).replace(/^[<]+/, '').replace(/[>]+$/, ''); + $sName = trim($sName).replace(/^["']+/, '').replace(/["']+$/, ''); + $sComment = trim($sComment).replace(/^[(]+/, '').replace(/[)]+$/, ''); + + // Remove backslash + $sName = $sName.replace(/\\\\(.)/g, '$1'); + $sComment = $sComment.replace(/\\\\(.)/g, '$1'); + + this.name = $sName; + this.email = $sEmail; + + this.clearDuplicateName(); + return true; + } +} + +export {EmailModel, EmailModel as default}; diff --git a/dev/Model/Filter.js b/dev/Model/Filter.js deleted file mode 100644 index 69049e4f8..000000000 --- a/dev/Model/Filter.js +++ /dev/null @@ -1,318 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Translator = require('Common/Translator'), - - Cache = require('Common/Cache'), - - FilterConditionModel = require('Model/FilterCondition'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - */ -function FilterModel() -{ - AbstractModel.call(this, 'FilterModel'); - - this.enabled = ko.observable(true); - - this.id = ''; - - this.name = ko.observable(''); - this.name.error = ko.observable(false); - this.name.focused = ko.observable(false); - - this.conditions = ko.observableArray([]); - this.conditionsType = ko.observable(Enums.FilterRulesType.Any); - - // Actions - this.actionValue = ko.observable(''); - this.actionValue.error = ko.observable(false); - - this.actionValueSecond = ko.observable(''); - this.actionValueThird = ko.observable(''); - - this.actionValueFourth = ko.observable(''); - this.actionValueFourth.error = ko.observable(false); - - this.actionMarkAsRead = ko.observable(false); - - this.actionKeep = ko.observable(true); - this.actionNoStop = ko.observable(false); - - this.actionType = ko.observable(Enums.FiltersAction.MoveTo); - - this.actionType.subscribe(function() { - this.actionValue(''); - this.actionValue.error(false); - this.actionValueSecond(''); - this.actionValueThird(''); - this.actionValueFourth(''); - this.actionValueFourth.error(false); - }, this); - - var fGetRealFolderName = function(sFolderFullNameRaw) { - var oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw); - return oFolder ? oFolder.fullName.replace( - '.' === oFolder.delimiter ? /\./ : /[\\\/]+/, ' / ') : sFolderFullNameRaw; - }; - - this.nameSub = ko.computed(function() { - - var - sResult = '', - sActionValue = this.actionValue(); - - switch (this.actionType()) - { - case Enums.FiltersAction.MoveTo: - sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_MOVE_TO', { - FOLDER: fGetRealFolderName(sActionValue) - }); - break; - case Enums.FiltersAction.Forward: - sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_FORWARD_TO', { - EMAIL: sActionValue - }); - break; - case Enums.FiltersAction.Vacation: - sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_VACATION_MESSAGE'); - break; - case Enums.FiltersAction.Reject: - sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_REJECT'); - break; - case Enums.FiltersAction.Discard: - sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_DISCARD'); - break; - // no default - } - - return sResult ? '(' + sResult + ')' : ''; - - }, this); - - this.actionTemplate = ko.computed(function() { - - var sTemplate = ''; - switch (this.actionType()) - { - case Enums.FiltersAction.Forward: - sTemplate = 'SettingsFiltersActionForward'; - break; - case Enums.FiltersAction.Vacation: - sTemplate = 'SettingsFiltersActionVacation'; - break; - case Enums.FiltersAction.Reject: - sTemplate = 'SettingsFiltersActionReject'; - break; - case Enums.FiltersAction.None: - sTemplate = 'SettingsFiltersActionNone'; - break; - case Enums.FiltersAction.Discard: - sTemplate = 'SettingsFiltersActionDiscard'; - break; - case Enums.FiltersAction.MoveTo: - default: - sTemplate = 'SettingsFiltersActionMoveToFolder'; - break; - } - - return sTemplate; - - }, this); - - this.regDisposables(this.conditions.subscribe(Utils.windowResizeCallback)); - - this.regDisposables(this.name.subscribe(function(sValue) { - this.name.error('' === sValue); - }, this)); - - this.regDisposables(this.actionValue.subscribe(function(sValue) { - this.actionValue.error('' === sValue); - }, this)); - - this.regDisposables([this.actionNoStop, this.actionTemplate]); - - this.deleteAccess = ko.observable(false); - this.canBeDeleted = ko.observable(true); -} - -_.extend(FilterModel.prototype, AbstractModel.prototype); - -FilterModel.prototype.generateID = function() -{ - this.id = Utils.fakeMd5(); -}; - -FilterModel.prototype.verify = function() -{ - if ('' === this.name()) - { - this.name.error(true); - return false; - } - - if (0 < this.conditions().length) - { - if (_.find(this.conditions(), function(oCond) { - return oCond && !oCond.verify(); - })) - { - return false; - } - } - - if ('' === this.actionValue()) - { - if (-1 < Utils.inArray(this.actionType(), [ - Enums.FiltersAction.MoveTo, - Enums.FiltersAction.Forward, - Enums.FiltersAction.Reject, - Enums.FiltersAction.Vacation - ])) - { - this.actionValue.error(true); - return false; - } - } - - if (Enums.FiltersAction.Forward === this.actionType() && - -1 === this.actionValue().indexOf('@')) - { - this.actionValue.error(true); - return false; - } - - if (Enums.FiltersAction.Vacation === this.actionType() && - '' !== this.actionValueFourth() && -1 === this.actionValueFourth().indexOf('@') - ) - { - this.actionValueFourth.error(true); - return false; - } - - this.name.error(false); - this.actionValue.error(false); - - return true; -}; - -FilterModel.prototype.toJson = function() -{ - return { - ID: this.id, - Enabled: this.enabled() ? '1' : '0', - Name: this.name(), - ConditionsType: this.conditionsType(), - Conditions: _.map(this.conditions(), function(oItem) { - return oItem.toJson(); - }), - - ActionValue: this.actionValue(), - ActionValueSecond: this.actionValueSecond(), - ActionValueThird: this.actionValueThird(), - ActionValueFourth: this.actionValueFourth(), - ActionType: this.actionType(), - - Stop: this.actionNoStop() ? '0' : '1', - Keep: this.actionKeep() ? '1' : '0', - MarkAsRead: this.actionMarkAsRead() ? '1' : '0' - }; -}; - -FilterModel.prototype.addCondition = function() -{ - this.conditions.push(new FilterConditionModel()); -}; - -FilterModel.prototype.removeCondition = function(oConditionToDelete) -{ - this.conditions.remove(oConditionToDelete); - Utils.delegateRunOnDestroy(oConditionToDelete); -}; - -FilterModel.prototype.setRecipients = function() -{ - this.actionValueFourth(require('Stores/User/Account').accountsEmails().join(', ')); -}; - -FilterModel.prototype.parse = function(oItem) -{ - var bResult = false; - if (oItem && 'Object/Filter' === oItem['@Object']) - { - this.id = Utils.pString(oItem.ID); - this.name(Utils.pString(oItem.Name)); - this.enabled(!!oItem.Enabled); - - this.conditionsType(Utils.pString(oItem.ConditionsType)); - - this.conditions([]); - - if (Utils.isNonEmptyArray(oItem.Conditions)) - { - this.conditions(_.compact(_.map(oItem.Conditions, function(aData) { - var oFilterCondition = new FilterConditionModel(); - return oFilterCondition && oFilterCondition.parse(aData) ? - oFilterCondition : null; - }))); - } - - this.actionType(Utils.pString(oItem.ActionType)); - - this.actionValue(Utils.pString(oItem.ActionValue)); - this.actionValueSecond(Utils.pString(oItem.ActionValueSecond)); - this.actionValueThird(Utils.pString(oItem.ActionValueThird)); - this.actionValueFourth(Utils.pString(oItem.ActionValueFourth)); - - this.actionNoStop(!oItem.Stop); - this.actionKeep(!!oItem.Keep); - this.actionMarkAsRead(!!oItem.MarkAsRead); - - bResult = true; - } - - return bResult; -}; - -FilterModel.prototype.cloneSelf = function() -{ - var oClone = new FilterModel(); - - oClone.id = this.id; - - oClone.enabled(this.enabled()); - - oClone.name(this.name()); - oClone.name.error(this.name.error()); - - oClone.conditionsType(this.conditionsType()); - - oClone.actionMarkAsRead(this.actionMarkAsRead()); - - oClone.actionType(this.actionType()); - - oClone.actionValue(this.actionValue()); - oClone.actionValue.error(this.actionValue.error()); - - oClone.actionValueSecond(this.actionValueSecond()); - oClone.actionValueThird(this.actionValueThird()); - oClone.actionValueFourth(this.actionValueFourth()); - - oClone.actionKeep(this.actionKeep()); - oClone.actionNoStop(this.actionNoStop()); - - oClone.conditions(_.map(this.conditions(), function(oCondition) { - return oCondition.cloneSelf(); - })); - - return oClone; -}; - -module.exports = FilterModel; diff --git a/dev/Model/Filter.jsx b/dev/Model/Filter.jsx new file mode 100644 index 000000000..53e391566 --- /dev/null +++ b/dev/Model/Filter.jsx @@ -0,0 +1,292 @@ + +import _ from '_'; +import ko from 'ko'; + +import {FilterRulesType, FiltersAction} from 'Common/Enums'; +import {pString, inArray, isNonEmptyArray, fakeMd5, delegateRunOnDestroy, windowResizeCallback} from 'Common/Utils'; +import {i18n} from 'Common/Translator'; +import {getFolderFromCacheList} from 'Common/Cache'; + +import {FilterConditionModel} from 'Model/FilterCondition'; +import {AbstractModel} from 'Knoin/AbstractModel'; + +class FilterModel extends AbstractModel +{ + constructor() + { + super('FilterModel'); + + this.enabled = ko.observable(true); + + this.id = ''; + + this.name = ko.observable(''); + this.name.error = ko.observable(false); + this.name.focused = ko.observable(false); + + this.conditions = ko.observableArray([]); + this.conditionsType = ko.observable(FilterRulesType.Any); + + // Actions + this.actionValue = ko.observable(''); + this.actionValue.error = ko.observable(false); + + this.actionValueSecond = ko.observable(''); + this.actionValueThird = ko.observable(''); + + this.actionValueFourth = ko.observable(''); + this.actionValueFourth.error = ko.observable(false); + + this.actionMarkAsRead = ko.observable(false); + + this.actionKeep = ko.observable(true); + this.actionNoStop = ko.observable(false); + + this.actionType = ko.observable(FiltersAction.MoveTo); + + this.actionType.subscribe(() => { + this.actionValue(''); + this.actionValue.error(false); + this.actionValueSecond(''); + this.actionValueThird(''); + this.actionValueFourth(''); + this.actionValueFourth.error(false); + }); + + const fGetRealFolderName = (folderFullNameRaw) => { + const folder = getFolderFromCacheList(folderFullNameRaw); + return folder ? folder.fullName.replace('.' === folder.delimiter ? /\./ : /[\\\/]+/, ' / ') : folderFullNameRaw; + }; + + this.nameSub = ko.computed(() => { + let result = ''; + const actionValue = this.actionValue(); + + switch (this.actionType()) + { + case FiltersAction.MoveTo: + result = i18n('SETTINGS_FILTERS/SUBNAME_MOVE_TO', { + FOLDER: fGetRealFolderName(actionValue) + }); + break; + case FiltersAction.Forward: + result = i18n('SETTINGS_FILTERS/SUBNAME_FORWARD_TO', { + EMAIL: actionValue + }); + break; + case FiltersAction.Vacation: + result = i18n('SETTINGS_FILTERS/SUBNAME_VACATION_MESSAGE'); + break; + case FiltersAction.Reject: + result = i18n('SETTINGS_FILTERS/SUBNAME_REJECT'); + break; + case FiltersAction.Discard: + result = i18n('SETTINGS_FILTERS/SUBNAME_DISCARD'); + break; + // no default + } + + return result ? '(' + result + ')' : ''; + }); + + this.actionTemplate = ko.computed(() => { + let result = ''; + + switch (this.actionType()) + { + case FiltersAction.Forward: + result = 'SettingsFiltersActionForward'; + break; + case FiltersAction.Vacation: + result = 'SettingsFiltersActionVacation'; + break; + case FiltersAction.Reject: + result = 'SettingsFiltersActionReject'; + break; + case FiltersAction.None: + result = 'SettingsFiltersActionNone'; + break; + case FiltersAction.Discard: + result = 'SettingsFiltersActionDiscard'; + break; + case FiltersAction.MoveTo: + default: + result = 'SettingsFiltersActionMoveToFolder'; + break; + } + + return result; + }); + + this.regDisposables(this.conditions.subscribe(windowResizeCallback)); + + this.regDisposables(this.name.subscribe((sValue) => { + this.name.error('' === sValue); + })); + + this.regDisposables(this.actionValue.subscribe((sValue) => { + this.actionValue.error('' === sValue); + })); + + this.regDisposables([this.actionNoStop, this.actionTemplate]); + + this.deleteAccess = ko.observable(false); + this.canBeDeleted = ko.observable(true); + } + + generateID() { + this.id = fakeMd5(); + } + + verify() { + if ('' === this.name()) + { + this.name.error(true); + return false; + } + + if (0 < this.conditions().length) + { + if (_.find(this.conditions(), (cond) => cond && !cond.verify())) + { + return false; + } + } + + if ('' === this.actionValue()) + { + if (-1 < inArray(this.actionType(), [ + FiltersAction.MoveTo, FiltersAction.Forward, FiltersAction.Reject, FiltersAction.Vacation + ])) + { + this.actionValue.error(true); + return false; + } + } + + if (FiltersAction.Forward === this.actionType() && + -1 === this.actionValue().indexOf('@')) + { + this.actionValue.error(true); + return false; + } + + if (FiltersAction.Vacation === this.actionType() && + '' !== this.actionValueFourth() && -1 === this.actionValueFourth().indexOf('@') + ) + { + this.actionValueFourth.error(true); + return false; + } + + this.name.error(false); + this.actionValue.error(false); + + return true; + } + + toJson() { + return { + ID: this.id, + Enabled: this.enabled() ? '1' : '0', + Name: this.name(), + ConditionsType: this.conditionsType(), + Conditions: _.map(this.conditions(), function(oItem) { + return oItem.toJson(); + }), + + ActionValue: this.actionValue(), + ActionValueSecond: this.actionValueSecond(), + ActionValueThird: this.actionValueThird(), + ActionValueFourth: this.actionValueFourth(), + ActionType: this.actionType(), + + Stop: this.actionNoStop() ? '0' : '1', + Keep: this.actionKeep() ? '1' : '0', + MarkAsRead: this.actionMarkAsRead() ? '1' : '0' + }; + } + + addCondition() { + this.conditions.push(new FilterConditionModel()); + } + + removeCondition(oConditionToDelete) { + this.conditions.remove(oConditionToDelete); + delegateRunOnDestroy(oConditionToDelete); + } + + setRecipients() { + this.actionValueFourth(require('Stores/User/Account').accountsEmails().join(', ')); + } + + parse(json) { + let result = false; + if (json && 'Object/Filter' === json['@Object']) + { + this.id = pString(json.ID); + this.name(pString(json.Name)); + this.enabled(!!json.Enabled); + + this.conditionsType(pString(json.ConditionsType)); + + this.conditions([]); + + if (isNonEmptyArray(json.Conditions)) + { + this.conditions(_.compact(_.map(json.Conditions, (aData) => { + const filterCondition = new FilterConditionModel(); + return filterCondition && filterCondition.parse(aData) ? filterCondition : null; + }))); + } + + this.actionType(pString(json.ActionType)); + + this.actionValue(pString(json.ActionValue)); + this.actionValueSecond(pString(json.ActionValueSecond)); + this.actionValueThird(pString(json.ActionValueThird)); + this.actionValueFourth(pString(json.ActionValueFourth)); + + this.actionNoStop(!json.Stop); + this.actionKeep(!!json.Keep); + this.actionMarkAsRead(!!json.MarkAsRead); + + result = true; + } + + return result; + } + + cloneSelf() { + var filter = new FilterModel(); + + filter.id = this.id; + + filter.enabled(this.enabled()); + + filter.name(this.name()); + filter.name.error(this.name.error()); + + filter.conditionsType(this.conditionsType()); + + filter.actionMarkAsRead(this.actionMarkAsRead()); + + filter.actionType(this.actionType()); + + filter.actionValue(this.actionValue()); + filter.actionValue.error(this.actionValue.error()); + + filter.actionValueSecond(this.actionValueSecond()); + filter.actionValueThird(this.actionValueThird()); + filter.actionValueFourth(this.actionValueFourth()); + + filter.actionKeep(this.actionKeep()); + filter.actionNoStop(this.actionNoStop()); + + filter.conditions(_.map(this.conditions(), (item) => item.cloneSelf())); + + return filter; + } +} + +export {FilterModel, FilterModel as default}; diff --git a/dev/Model/FilterCondition.js b/dev/Model/FilterCondition.js deleted file mode 100644 index 5799768c9..000000000 --- a/dev/Model/FilterCondition.js +++ /dev/null @@ -1,110 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - */ -function FilterConditionModel() -{ - AbstractModel.call(this, 'FilterConditionModel'); - - this.field = ko.observable(Enums.FilterConditionField.From); - this.type = ko.observable(Enums.FilterConditionType.Contains); - this.value = ko.observable(''); - this.value.error = ko.observable(false); - - this.valueSecond = ko.observable(''); - this.valueSecond.error = ko.observable(false); - - this.template = ko.computed(function() { - - var sTemplate = ''; - switch (this.field()) - { - case Enums.FilterConditionField.Size: - sTemplate = 'SettingsFiltersConditionSize'; - break; - case Enums.FilterConditionField.Header: - sTemplate = 'SettingsFiltersConditionMore'; - break; - default: - sTemplate = 'SettingsFiltersConditionDefault'; - break; - } - - return sTemplate; - - }, this); - - this.field.subscribe(function() { - this.value(''); - this.valueSecond(''); - }, this); - - this.regDisposables([this.template]); -} - -_.extend(FilterConditionModel.prototype, AbstractModel.prototype); - -FilterConditionModel.prototype.verify = function() -{ - if ('' === this.value()) - { - this.value.error(true); - return false; - } - - if (Enums.FilterConditionField.Header === this.field() && '' === this.valueSecond()) - { - this.valueSecond.error(true); - return false; - } - - return true; -}; - -FilterConditionModel.prototype.parse = function(oItem) -{ - if (oItem && oItem.Field && oItem.Type) - { - this.field(Utils.pString(oItem.Field)); - this.type(Utils.pString(oItem.Type)); - this.value(Utils.pString(oItem.Value)); - this.valueSecond(Utils.pString(oItem.ValueSecond)); - - return true; - } - - return false; -}; - -FilterConditionModel.prototype.toJson = function() -{ - return { - Field: this.field(), - Type: this.type(), - Value: this.value(), - ValueSecond: this.valueSecond() - }; -}; - -FilterConditionModel.prototype.cloneSelf = function() -{ - var oClone = new FilterConditionModel(); - - oClone.field(this.field()); - oClone.type(this.type()); - oClone.value(this.value()); - oClone.valueSecond(this.valueSecond()); - - return oClone; -}; - -module.exports = FilterConditionModel; diff --git a/dev/Model/FilterCondition.jsx b/dev/Model/FilterCondition.jsx new file mode 100644 index 000000000..43b0cf62c --- /dev/null +++ b/dev/Model/FilterCondition.jsx @@ -0,0 +1,102 @@ + +import ko from 'ko'; + +import {FilterConditionField, FilterConditionType} from 'Common/Enums'; +import {pString} from 'Common/Utils'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +class FilterConditionModel extends AbstractModel +{ + constructor() + { + super('FilterConditionModel'); + + this.field = ko.observable(FilterConditionField.From); + this.type = ko.observable(FilterConditionType.Contains); + this.value = ko.observable(''); + this.value.error = ko.observable(false); + + this.valueSecond = ko.observable(''); + this.valueSecond.error = ko.observable(false); + + this.template = ko.computed(function() { + + var sTemplate = ''; + switch (this.field()) + { + case FilterConditionField.Size: + sTemplate = 'SettingsFiltersConditionSize'; + break; + case FilterConditionField.Header: + sTemplate = 'SettingsFiltersConditionMore'; + break; + default: + sTemplate = 'SettingsFiltersConditionDefault'; + break; + } + + return sTemplate; + + }, this); + + this.field.subscribe(function() { + this.value(''); + this.valueSecond(''); + }, this); + + this.regDisposables([this.template]); + } + + verify() { + if ('' === this.value()) + { + this.value.error(true); + return false; + } + + if (FilterConditionField.Header === this.field() && '' === this.valueSecond()) + { + this.valueSecond.error(true); + return false; + } + + return true; + } + + parse(json) { + if (json && json.Field && json.Type) + { + this.field(pString(json.Field)); + this.type(pString(json.Type)); + this.value(pString(json.Value)); + this.valueSecond(pString(json.ValueSecond)); + + return true; + } + + return false; + } + + toJson() { + return { + Field: this.field(), + Type: this.type(), + Value: this.value(), + ValueSecond: this.valueSecond() + }; + } + + cloneSelf() { + const filterCond = new FilterConditionModel(); + + filterCond.field(this.field()); + filterCond.type(this.type()); + filterCond.value(this.value()); + filterCond.valueSecond(this.valueSecond()); + + return filterCond; + } +} + +export {FilterConditionModel, FilterConditionModel as default}; diff --git a/dev/Model/Folder.js b/dev/Model/Folder.js deleted file mode 100644 index 88a0cd41a..000000000 --- a/dev/Model/Folder.js +++ /dev/null @@ -1,367 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Events = require('Common/Events'), - Translator = require('Common/Translator'), - - Cache = require('Common/Cache'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - */ -function FolderModel() -{ - AbstractModel.call(this, 'FolderModel'); - - this.name = ko.observable(''); - this.fullName = ''; - this.fullNameRaw = ''; - this.fullNameHash = ''; - this.delimiter = ''; - this.namespace = ''; - this.deep = 0; - this.interval = 0; - - this.selectable = false; - this.existen = true; - - this.type = ko.observable(Enums.FolderType.User); - - this.focused = ko.observable(false); - this.selected = ko.observable(false); - this.edited = ko.observable(false); - this.collapsed = ko.observable(true); - this.subScribed = ko.observable(true); - this.checkable = ko.observable(false); - this.subFolders = ko.observableArray([]); - this.deleteAccess = ko.observable(false); - this.actionBlink = ko.observable(false).extend({'falseTimeout': 1000}); - - this.nameForEdit = ko.observable(''); - - this.privateMessageCountAll = ko.observable(0); - this.privateMessageCountUnread = ko.observable(0); - - this.collapsedPrivate = ko.observable(true); -} - -_.extend(FolderModel.prototype, AbstractModel.prototype); - -/** - * @static - * @param {AjaxJsonFolder} oJsonFolder - * @returns {?FolderModel} - */ -FolderModel.newInstanceFromJson = function(oJsonFolder) -{ - var oFolderModel = new FolderModel(); - return oFolderModel.initByJson(oJsonFolder) ? oFolderModel.initComputed() : null; -}; - -/** - * @returns {FolderModel} - */ -FolderModel.prototype.initComputed = function() -{ - var sInboxFolderName = Cache.getFolderInboxName(); - - this.isInbox = ko.computed(function() { - return Enums.FolderType.Inbox === this.type(); - }, this); - - this.hasSubScribedSubfolders = ko.computed(function() { - return !!_.find(this.subFolders(), function(oFolder) { - return (oFolder.subScribed() || oFolder.hasSubScribedSubfolders()) && !oFolder.isSystemFolder(); - }); - }, this); - - this.canBeEdited = ko.computed(function() { - return Enums.FolderType.User === this.type() && this.existen && this.selectable; - }, this); - - this.visible = ko.computed(function() { - - var - bSubScribed = this.subScribed(), - bSubFolders = this.hasSubScribedSubfolders(); - - return (bSubScribed || (bSubFolders && (!this.existen || !this.selectable))); - - }, this); - - this.isSystemFolder = ko.computed(function() { - return Enums.FolderType.User !== this.type(); - }, this); - - this.hidden = ko.computed(function() { - - var - bSystem = this.isSystemFolder(), - bSubFolders = this.hasSubScribedSubfolders(); - - return (bSystem && !bSubFolders) || (!this.selectable && !bSubFolders); - - }, this); - - this.selectableForFolderList = ko.computed(function() { - return !this.isSystemFolder() && this.selectable; - }, this); - - this.messageCountAll = ko.computed({ - 'read': this.privateMessageCountAll, - 'write': function(iValue) { - if (Utils.isPosNumeric(iValue, true)) - { - this.privateMessageCountAll(iValue); - } - else - { - this.privateMessageCountAll.valueHasMutated(); - } - }, - 'owner': this - }).extend({'notify': 'always'}); - - this.messageCountUnread = ko.computed({ - 'read': this.privateMessageCountUnread, - 'write': function(iValue) { - if (Utils.isPosNumeric(iValue, true)) - { - this.privateMessageCountUnread(iValue); - } - else - { - this.privateMessageCountUnread.valueHasMutated(); - } - }, - 'owner': this - }).extend({'notify': 'always'}); - - this.printableUnreadCount = ko.computed(function() { - var - iCount = this.messageCountAll(), - iUnread = this.messageCountUnread(), - iType = this.type(); - - if (0 < iCount) - { - if (Enums.FolderType.Draft === iType) - { - return '' + iCount; - } - else if (0 < iUnread && Enums.FolderType.Trash !== iType && Enums.FolderType.Archive !== iType && Enums.FolderType.SentItems !== iType) - { - return '' + iUnread; - } - } - - return ''; - - }, this); - - this.canBeDeleted = ko.computed(function() { - var - bSystem = this.isSystemFolder(); - return !bSystem && 0 === this.subFolders().length && sInboxFolderName !== this.fullNameRaw; - }, this); - - this.canBeSubScribed = ko.computed(function() { - return !this.isSystemFolder() && this.selectable && sInboxFolderName !== this.fullNameRaw; - }, this); - - this.canBeChecked = this.canBeSubScribed; - -// this.visible.subscribe(function() { -// Utils.timeOutAction('folder-list-folder-visibility-change', function() { -// Globals.$win.trigger('folder-list-folder-visibility-change'); -// }, 100); -// }); - - this.localName = ko.computed(function() { - - Translator.trigger(); - - var - iType = this.type(), - sName = this.name(); - - if (this.isSystemFolder()) - { - switch (iType) - { - case Enums.FolderType.Inbox: - sName = Translator.i18n('FOLDER_LIST/INBOX_NAME'); - break; - case Enums.FolderType.SentItems: - sName = Translator.i18n('FOLDER_LIST/SENT_NAME'); - break; - case Enums.FolderType.Draft: - sName = Translator.i18n('FOLDER_LIST/DRAFTS_NAME'); - break; - case Enums.FolderType.Spam: - sName = Translator.i18n('FOLDER_LIST/SPAM_NAME'); - break; - case Enums.FolderType.Trash: - sName = Translator.i18n('FOLDER_LIST/TRASH_NAME'); - break; - case Enums.FolderType.Archive: - sName = Translator.i18n('FOLDER_LIST/ARCHIVE_NAME'); - break; - // no default - } - } - - return sName; - - }, this); - - this.manageFolderSystemName = ko.computed(function() { - - Translator.trigger(); - - var - sSuffix = '', - iType = this.type(), - sName = this.name(); - - if (this.isSystemFolder()) - { - switch (iType) - { - case Enums.FolderType.Inbox: - sSuffix = '(' + Translator.i18n('FOLDER_LIST/INBOX_NAME') + ')'; - break; - case Enums.FolderType.SentItems: - sSuffix = '(' + Translator.i18n('FOLDER_LIST/SENT_NAME') + ')'; - break; - case Enums.FolderType.Draft: - sSuffix = '(' + Translator.i18n('FOLDER_LIST/DRAFTS_NAME') + ')'; - break; - case Enums.FolderType.Spam: - sSuffix = '(' + Translator.i18n('FOLDER_LIST/SPAM_NAME') + ')'; - break; - case Enums.FolderType.Trash: - sSuffix = '(' + Translator.i18n('FOLDER_LIST/TRASH_NAME') + ')'; - break; - case Enums.FolderType.Archive: - sSuffix = '(' + Translator.i18n('FOLDER_LIST/ARCHIVE_NAME') + ')'; - break; - // no default - } - } - - if ('' !== sSuffix && '(' + sName + ')' === sSuffix || '(inbox)' === sSuffix.toLowerCase()) - { - sSuffix = ''; - } - - return sSuffix; - - }, this); - - this.collapsed = ko.computed({ - 'read': function() { - return !this.hidden() && this.collapsedPrivate(); - }, - 'write': function(mValue) { - this.collapsedPrivate(mValue); - }, - 'owner': this - }); - - this.hasUnreadMessages = ko.computed(function() { - return 0 < this.messageCountUnread() && '' !== this.printableUnreadCount(); - }, this); - - this.hasSubScribedUnreadMessagesSubfolders = ko.computed(function() { - return !!_.find(this.subFolders(), function(oFolder) { - return oFolder.hasUnreadMessages() || oFolder.hasSubScribedUnreadMessagesSubfolders(); - }); - }, this); - - // subscribe - this.name.subscribe(function(sValue) { - this.nameForEdit(sValue); - }, this); - - this.edited.subscribe(function(bValue) { - if (bValue) - { - this.nameForEdit(this.name()); - } - }, this); - - this.messageCountUnread.subscribe(function(iUnread) { - if (Enums.FolderType.Inbox === this.type()) - { - Events.pub('mailbox.inbox-unread-count', [iUnread]); - } - }, this); - - return this; -}; - -FolderModel.prototype.fullName = ''; -FolderModel.prototype.fullNameRaw = ''; -FolderModel.prototype.fullNameHash = ''; -FolderModel.prototype.delimiter = ''; -FolderModel.prototype.namespace = ''; -FolderModel.prototype.deep = 0; -FolderModel.prototype.interval = 0; - -/** - * @returns {string} - */ -FolderModel.prototype.collapsedCss = function() -{ - return this.hasSubScribedSubfolders() ? - (this.collapsed() ? 'icon-right-mini e-collapsed-sign' : 'icon-down-mini e-collapsed-sign') : 'icon-none e-collapsed-sign'; -}; - -/** - * @param {AjaxJsonFolder} oJsonFolder - * @returns {boolean} - */ -FolderModel.prototype.initByJson = function(oJsonFolder) -{ - var - bResult = false, - sInboxFolderName = Cache.getFolderInboxName(); - - if (oJsonFolder && 'Object/Folder' === oJsonFolder['@Object']) - { - this.name(oJsonFolder.Name); - this.delimiter = oJsonFolder.Delimiter; - this.fullName = oJsonFolder.FullName; - this.fullNameRaw = oJsonFolder.FullNameRaw; - this.fullNameHash = oJsonFolder.FullNameHash; - this.deep = oJsonFolder.FullNameRaw.split(this.delimiter).length - 1; - this.selectable = !!oJsonFolder.IsSelectable; - this.existen = !!oJsonFolder.IsExists; - - this.subScribed(!!oJsonFolder.IsSubscribed); - this.checkable(!!oJsonFolder.Checkable); - - this.type(sInboxFolderName === this.fullNameRaw ? Enums.FolderType.Inbox : Enums.FolderType.User); - - bResult = true; - } - - return bResult; -}; - -/** - * @returns {string} - */ -FolderModel.prototype.printableFullName = function() -{ - return this.fullName.split(this.delimiter).join(' / '); -}; - -module.exports = FolderModel; diff --git a/dev/Model/Folder.jsx b/dev/Model/Folder.jsx new file mode 100644 index 000000000..2ed6747e0 --- /dev/null +++ b/dev/Model/Folder.jsx @@ -0,0 +1,313 @@ + +import _ from '_'; +import ko from 'ko'; + +import {FolderType} from 'Common/Enums'; +import {isPosNumeric} from 'Common/Utils'; +import {i18n, trigger as translatorTrigger} from 'Common/Translator'; +import {getFolderInboxName} from 'Common/Cache'; +import * as Events from 'Common/Events'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +class FolderModel extends AbstractModel +{ + constructor() + { + super('FolderModel'); + + this.name = ko.observable(''); + this.fullName = ''; + this.fullNameRaw = ''; + this.fullNameHash = ''; + this.delimiter = ''; + this.namespace = ''; + this.deep = 0; + this.interval = 0; + + this.selectable = false; + this.existen = true; + + this.type = ko.observable(FolderType.User); + + this.focused = ko.observable(false); + this.selected = ko.observable(false); + this.edited = ko.observable(false); + this.collapsed = ko.observable(true); + this.subScribed = ko.observable(true); + this.checkable = ko.observable(false); + this.subFolders = ko.observableArray([]); + this.deleteAccess = ko.observable(false); + this.actionBlink = ko.observable(false).extend({falseTimeout: 1000}); + + this.nameForEdit = ko.observable(''); + + this.privateMessageCountAll = ko.observable(0); + this.privateMessageCountUnread = ko.observable(0); + + this.collapsedPrivate = ko.observable(true); + } + + /** + * @static + * @param {AjaxJsonFolder} json + * @returns {?FolderModel} + */ + static newInstanceFromJson(json) { + const folder = new FolderModel(); + return folder.initByJson(json) ? folder.initComputed() : null; + } + + /** + * @returns {FolderModel} + */ + initComputed() { + const inboxFolderName = getFolderInboxName(); + + this.isInbox = ko.computed(() => FolderType.Inbox === this.type()); + + this.hasSubScribedSubfolders = ko.computed(function() { + return !!_.find(this.subFolders(), (oFolder) => (oFolder.subScribed() || oFolder.hasSubScribedSubfolders()) && !oFolder.isSystemFolder()); + }, this); + + this.canBeEdited = ko.computed(() => FolderType.User === this.type() && this.existen && this.selectable); + + this.visible = ko.computed(() => { + const + isSubScribed = this.subScribed(), + isSubFolders = this.hasSubScribedSubfolders(); + + return (isSubScribed || (isSubFolders && (!this.existen || !this.selectable))); + }); + + this.isSystemFolder = ko.computed(() => FolderType.User !== this.type()); + + this.hidden = ko.computed(() => { + const + isSystem = this.isSystemFolder(), + isSubFolders = this.hasSubScribedSubfolders(); + + return (isSystem && !isSubFolders) || (!this.selectable && !isSubFolders); + }); + + this.selectableForFolderList = ko.computed(() => !this.isSystemFolder() && this.selectable); + + this.messageCountAll = ko.computed({ + read: this.privateMessageCountAll, + write: (iValue) => { + if (isPosNumeric(iValue, true)) + { + this.privateMessageCountAll(iValue); + } + else + { + this.privateMessageCountAll.valueHasMutated(); + } + } + }).extend({notify: 'always'}); + + this.messageCountUnread = ko.computed({ + read: this.privateMessageCountUnread, + write: (value) => { + if (isPosNumeric(value, true)) + { + this.privateMessageCountUnread(value); + } + else + { + this.privateMessageCountUnread.valueHasMutated(); + } + } + }).extend({notify: 'always'}); + + this.printableUnreadCount = ko.computed(() => { + const + count = this.messageCountAll(), + unread = this.messageCountUnread(), + type = this.type(); + + if (0 < count) + { + if (FolderType.Draft === type) + { + return '' + count; + } + else if (0 < unread && FolderType.Trash !== type && FolderType.Archive !== type && FolderType.SentItems !== type) + { + return '' + unread; + } + } + + return ''; + }); + + this.canBeDeleted = ko.computed(() => { + const bSystem = this.isSystemFolder(); + return !bSystem && 0 === this.subFolders().length && inboxFolderName !== this.fullNameRaw; + }); + + this.canBeSubScribed = ko.computed(() => !this.isSystemFolder() && this.selectable && inboxFolderName !== this.fullNameRaw); + + this.canBeChecked = this.canBeSubScribed; + + this.localName = ko.computed(() => { + + translatorTrigger(); + + let name = this.name(); + const type = this.type(); + + if (this.isSystemFolder()) + { + switch (type) + { + case FolderType.Inbox: + name = i18n('FOLDER_LIST/INBOX_NAME'); + break; + case FolderType.SentItems: + name = i18n('FOLDER_LIST/SENT_NAME'); + break; + case FolderType.Draft: + name = i18n('FOLDER_LIST/DRAFTS_NAME'); + break; + case FolderType.Spam: + name = i18n('FOLDER_LIST/SPAM_NAME'); + break; + case FolderType.Trash: + name = i18n('FOLDER_LIST/TRASH_NAME'); + break; + case FolderType.Archive: + name = i18n('FOLDER_LIST/ARCHIVE_NAME'); + break; + // no default + } + } + + return name; + }); + + this.manageFolderSystemName = ko.computed(() => { + + translatorTrigger(); + + let suffix = ''; + const + type = this.type(), + name = this.name(); + + if (this.isSystemFolder()) + { + switch (type) + { + case FolderType.Inbox: + suffix = '(' + i18n('FOLDER_LIST/INBOX_NAME') + ')'; + break; + case FolderType.SentItems: + suffix = '(' + i18n('FOLDER_LIST/SENT_NAME') + ')'; + break; + case FolderType.Draft: + suffix = '(' + i18n('FOLDER_LIST/DRAFTS_NAME') + ')'; + break; + case FolderType.Spam: + suffix = '(' + i18n('FOLDER_LIST/SPAM_NAME') + ')'; + break; + case FolderType.Trash: + suffix = '(' + i18n('FOLDER_LIST/TRASH_NAME') + ')'; + break; + case FolderType.Archive: + suffix = '(' + i18n('FOLDER_LIST/ARCHIVE_NAME') + ')'; + break; + // no default + } + } + + if ('' !== suffix && '(' + name + ')' === suffix || '(inbox)' === suffix.toLowerCase()) + { + suffix = ''; + } + + return suffix; + }); + + this.collapsed = ko.computed({ + read: () => !this.hidden() && this.collapsedPrivate(), + write: (value) => { + this.collapsedPrivate(value); + } + }); + + this.hasUnreadMessages = ko.computed(() => 0 < this.messageCountUnread() && '' !== this.printableUnreadCount()); + + this.hasSubScribedUnreadMessagesSubfolders = ko.computed(function() { + return !!_.find(this.subFolders(), (folder) => folder.hasUnreadMessages() || folder.hasSubScribedUnreadMessagesSubfolders()); + }, this); + + // subscribe + this.name.subscribe((value) => { + this.nameForEdit(value); + }); + + this.edited.subscribe((value) => { + if (value) + { + this.nameForEdit(this.name()); + } + }); + + this.messageCountUnread.subscribe((unread) => { + if (FolderType.Inbox === this.type()) + { + Events.pub('mailbox.inbox-unread-count', [unread]); + } + }); + + return this; + } + + /** + * @returns {string} + */ + collapsedCss() { + return this.hasSubScribedSubfolders() ? + (this.collapsed() ? 'icon-right-mini e-collapsed-sign' : 'icon-down-mini e-collapsed-sign') : 'icon-none e-collapsed-sign'; + } + + /** + * @param {AjaxJsonFolder} json + * @returns {boolean} + */ + initByJson(json) { + let bResult = false; + const sInboxFolderName = getFolderInboxName(); + + if (json && 'Object/Folder' === json['@Object']) + { + this.name(json.Name); + this.delimiter = json.Delimiter; + this.fullName = json.FullName; + this.fullNameRaw = json.FullNameRaw; + this.fullNameHash = json.FullNameHash; + this.deep = json.FullNameRaw.split(this.delimiter).length - 1; + this.selectable = !!json.IsSelectable; + this.existen = !!json.IsExists; + + this.subScribed(!!json.IsSubscribed); + this.checkable(!!json.Checkable); + + this.type(sInboxFolderName === this.fullNameRaw ? FolderType.Inbox : FolderType.User); + + bResult = true; + } + + return bResult; + } + + /** + * @returns {string} + */ + printableFullName() { + return this.fullName.split(this.delimiter).join(' / '); + } +} + +export {FolderModel, FolderModel as default}; diff --git a/dev/Model/Identity.js b/dev/Model/Identity.js deleted file mode 100644 index 8211feeb2..000000000 --- a/dev/Model/Identity.js +++ /dev/null @@ -1,44 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - * @param {string} sId - * @param {string} sEmail - */ -function IdentityModel(sId, sEmail) -{ - AbstractModel.call(this, 'IdentityModel'); - - this.id = ko.observable(sId || ''); - this.email = ko.observable(sEmail); - this.name = ko.observable(''); - - this.replyTo = ko.observable(''); - this.bcc = ko.observable(''); - - this.signature = ko.observable(''); - this.signatureInsertBefore = ko.observable(false); - - this.deleteAccess = ko.observable(false); - this.canBeDeleted = ko.computed(function() { - return '' !== this.id(); - }, this); -} - -_.extend(IdentityModel.prototype, AbstractModel.prototype); - -IdentityModel.prototype.formattedName = function() -{ - var - sName = this.name(), - sEmail = this.email(); - - return ('' !== sName) ? sName + ' (' + sEmail + ')' : sEmail; -}; - -module.exports = IdentityModel; diff --git a/dev/Model/Identity.jsx b/dev/Model/Identity.jsx new file mode 100644 index 000000000..c2a427917 --- /dev/null +++ b/dev/Model/Identity.jsx @@ -0,0 +1,42 @@ + +import ko from 'ko'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +class IdentityModel extends AbstractModel +{ + /** + * @param {string} id + * @param {string} email + */ + constructor(id, email) + { + super('IdentityModel'); + + this.id = ko.observable(id || ''); + this.email = ko.observable(email); + this.name = ko.observable(''); + + this.replyTo = ko.observable(''); + this.bcc = ko.observable(''); + + this.signature = ko.observable(''); + this.signatureInsertBefore = ko.observable(false); + + this.deleteAccess = ko.observable(false); + this.canBeDeleted = ko.computed(() => '' !== this.id()); + } + + /** + * @returns {string} + */ + formattedName() { + const + name = this.name(), + email = this.email(); + + return '' !== name ? name + ' (' + email + ')' : email; + } +} + +export {IdentityModel, IdentityModel as default}; diff --git a/dev/Model/Message.js b/dev/Model/Message.js deleted file mode 100644 index 53571aa80..000000000 --- a/dev/Model/Message.js +++ /dev/null @@ -1,1013 +0,0 @@ - -var - _ = require('_'), - $ = require('$'), - ko = require('ko'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - Globals = require('Common/Globals'), - Links = require('Common/Links'), - - AttachmentModel = require('Model/Attachment'), - - MessageHelper = require('Helper/Message').default, - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - */ -function MessageModel() -{ - AbstractModel.call(this, 'MessageModel'); - - this.folderFullNameRaw = ''; - this.uid = ''; - this.hash = ''; - this.requestHash = ''; - this.subject = ko.observable(''); - this.subjectPrefix = ko.observable(''); - this.subjectSuffix = ko.observable(''); - this.size = ko.observable(0); - this.dateTimeStampInUTC = ko.observable(0); - this.priority = ko.observable(Enums.MessagePriority.Normal); - - this.proxy = false; - - this.fromEmailString = ko.observable(''); - this.fromClearEmailString = ko.observable(''); - this.toEmailsString = ko.observable(''); - this.toClearEmailsString = ko.observable(''); - - this.senderEmailsString = ko.observable(''); - this.senderClearEmailsString = ko.observable(''); - - this.emails = []; - - this.from = []; - this.to = []; - this.cc = []; - this.bcc = []; - this.replyTo = []; - this.deliveredTo = []; - - this.newForAnimation = ko.observable(false); - - this.deleted = ko.observable(false); - this.deletedMark = ko.observable(false); - this.unseen = ko.observable(false); - this.flagged = ko.observable(false); - this.answered = ko.observable(false); - this.forwarded = ko.observable(false); - this.isReadReceipt = ko.observable(false); - - this.focused = ko.observable(false); - this.selected = ko.observable(false); - this.checked = ko.observable(false); - this.hasAttachments = ko.observable(false); - this.attachmentsSpecData = ko.observableArray([]); - - this.attachmentIconClass = ko.computed(function() { - return AttachmentModel.staticCombinedIconClass( - this.hasAttachments() ? this.attachmentsSpecData() : []); - }, this); - - this.body = null; - - this.isHtml = ko.observable(false); - this.hasImages = ko.observable(false); - this.attachments = ko.observableArray([]); - - this.isPgpSigned = ko.observable(false); - this.isPgpEncrypted = ko.observable(false); - this.pgpSignedVerifyStatus = ko.observable(Enums.SignedVerifyStatus.None); - this.pgpSignedVerifyUser = ko.observable(''); - - this.priority = ko.observable(Enums.MessagePriority.Normal); - this.readReceipt = ko.observable(''); - - this.aDraftInfo = []; - this.sMessageId = ''; - this.sInReplyTo = ''; - this.sReferences = ''; - - this.hasUnseenSubMessage = ko.observable(false); - this.hasFlaggedSubMessage = ko.observable(false); - - this.threads = ko.observableArray([]); - - this.threadsLen = ko.computed(function() { - return this.threads().length; - }, this); - - this.isImportant = ko.computed(function() { - return Enums.MessagePriority.High === this.priority(); - }, this); - - this.regDisposables([this.attachmentIconClass, this.threadsLen, this.isImportant]); -} - -_.extend(MessageModel.prototype, AbstractModel.prototype); - -/** - * @static - * @param {AjaxJsonMessage} oJsonMessage - * @returns {?MessageModel} - */ -MessageModel.newInstanceFromJson = function(oJsonMessage) -{ - var oMessageModel = new MessageModel(); - return oMessageModel.initByJson(oJsonMessage) ? oMessageModel : null; -}; - -MessageModel.prototype.clear = function() -{ - this.folderFullNameRaw = ''; - this.uid = ''; - this.hash = ''; - this.requestHash = ''; - this.subject(''); - this.subjectPrefix(''); - this.subjectSuffix(''); - this.size(0); - this.dateTimeStampInUTC(0); - this.priority(Enums.MessagePriority.Normal); - - this.proxy = false; - - this.fromEmailString(''); - this.fromClearEmailString(''); - this.toEmailsString(''); - this.toClearEmailsString(''); - this.senderEmailsString(''); - this.senderClearEmailsString(''); - - this.emails = []; - - this.from = []; - this.to = []; - this.cc = []; - this.bcc = []; - this.replyTo = []; - this.deliveredTo = []; - - this.newForAnimation(false); - - this.deleted(false); - this.deletedMark(false); - this.unseen(false); - this.flagged(false); - this.answered(false); - this.forwarded(false); - this.isReadReceipt(false); - - this.selected(false); - this.checked(false); - this.hasAttachments(false); - this.attachmentsSpecData([]); - - this.body = null; - this.isHtml(false); - this.hasImages(false); - this.attachments([]); - - this.isPgpSigned(false); - this.isPgpEncrypted(false); - this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None); - this.pgpSignedVerifyUser(''); - - this.priority(Enums.MessagePriority.Normal); - this.readReceipt(''); - this.aDraftInfo = []; - this.sMessageId = ''; - this.sInReplyTo = ''; - this.sReferences = ''; - - this.threads([]); - - this.hasUnseenSubMessage(false); - this.hasFlaggedSubMessage(false); -}; - -/** - * @returns {Array} - */ -MessageModel.prototype.getRecipientsEmails = function() -{ - return this.getEmails(['to', 'cc']); -}; - -/** - * @param {Array} aProperties - * @returns {Array} - */ -MessageModel.prototype.getEmails = function(aProperties) -{ - var self = this; - return _.compact(_.uniq(_.map(_.reduce(aProperties, function(aCarry, sProperty) { - return aCarry.concat(self[sProperty]); - }, []), function(oItem) { - return oItem ? oItem.email : ''; - }))); -}; - -/** - * @returns {string} - */ -MessageModel.prototype.friendlySize = function() -{ - return Utils.friendlySize(this.size()); -}; - -MessageModel.prototype.computeSenderEmail = function() -{ - var - sSent = require('Stores/User/Folder').sentFolder(), - sDraft = require('Stores/User/Folder').draftFolder(); - - this.senderEmailsString(this.folderFullNameRaw === sSent || this.folderFullNameRaw === sDraft ? - this.toEmailsString() : this.fromEmailString()); - - this.senderClearEmailsString(this.folderFullNameRaw === sSent || this.folderFullNameRaw === sDraft ? - this.toClearEmailsString() : this.fromClearEmailString()); -}; - -/** - * @param {AjaxJsonMessage} oJsonMessage - * @returns {boolean} - */ -MessageModel.prototype.initByJson = function(oJsonMessage) -{ - var - bResult = false, - iPriority = Enums.MessagePriority.Normal; - - if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) - { - iPriority = Utils.pInt(oJsonMessage.Priority); - this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ? - iPriority : Enums.MessagePriority.Normal); - - this.folderFullNameRaw = oJsonMessage.Folder; - this.uid = oJsonMessage.Uid; - this.hash = oJsonMessage.Hash; - this.requestHash = oJsonMessage.RequestHash; - - this.proxy = !!oJsonMessage.ExternalProxy; - - this.size(Utils.pInt(oJsonMessage.Size)); - - this.from = MessageHelper.emailArrayFromJson(oJsonMessage.From); - this.to = MessageHelper.emailArrayFromJson(oJsonMessage.To); - this.cc = MessageHelper.emailArrayFromJson(oJsonMessage.Cc); - this.bcc = MessageHelper.emailArrayFromJson(oJsonMessage.Bcc); - this.replyTo = MessageHelper.emailArrayFromJson(oJsonMessage.ReplyTo); - this.deliveredTo = MessageHelper.emailArrayFromJson(oJsonMessage.DeliveredTo); - - this.subject(oJsonMessage.Subject); - if (Utils.isArray(oJsonMessage.SubjectParts)) - { - this.subjectPrefix(oJsonMessage.SubjectParts[0]); - this.subjectSuffix(oJsonMessage.SubjectParts[1]); - } - else - { - this.subjectPrefix(''); - this.subjectSuffix(this.subject()); - } - - this.dateTimeStampInUTC(Utils.pInt(oJsonMessage.DateTimeStampInUTC)); - this.hasAttachments(!!oJsonMessage.HasAttachments); - this.attachmentsSpecData(Utils.isArray(oJsonMessage.AttachmentsSpecData) ? - oJsonMessage.AttachmentsSpecData : []); - - this.fromEmailString(MessageHelper.emailArrayToString(this.from, true)); - this.fromClearEmailString(MessageHelper.emailArrayToStringClear(this.from)); - this.toEmailsString(MessageHelper.emailArrayToString(this.to, true)); - this.toClearEmailsString(MessageHelper.emailArrayToStringClear(this.to)); - - this.threads(Utils.isArray(oJsonMessage.Threads) ? oJsonMessage.Threads : []); - - this.initFlagsByJson(oJsonMessage); - this.computeSenderEmail(); - - bResult = true; - } - - return bResult; -}; - -/** - * @param {AjaxJsonMessage} oJsonMessage - * @returns {boolean} - */ -MessageModel.prototype.initUpdateByMessageJson = function(oJsonMessage) -{ - var - bResult = false, - iPriority = Enums.MessagePriority.Normal; - - if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) - { - iPriority = Utils.pInt(oJsonMessage.Priority); - this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ? - iPriority : Enums.MessagePriority.Normal); - - this.aDraftInfo = oJsonMessage.DraftInfo; - - this.sMessageId = oJsonMessage.MessageId; - this.sInReplyTo = oJsonMessage.InReplyTo; - this.sReferences = oJsonMessage.References; - - this.proxy = !!oJsonMessage.ExternalProxy; - - if (require('Stores/User/Pgp').capaOpenPGP()) - { - this.isPgpSigned(!!oJsonMessage.PgpSigned); - this.isPgpEncrypted(!!oJsonMessage.PgpEncrypted); - } - - this.hasAttachments(!!oJsonMessage.HasAttachments); - this.attachmentsSpecData(Utils.isArray(oJsonMessage.AttachmentsSpecData) ? - oJsonMessage.AttachmentsSpecData : []); - - this.foundedCIDs = Utils.isArray(oJsonMessage.FoundedCIDs) ? oJsonMessage.FoundedCIDs : []; - this.attachments(this.initAttachmentsFromJson(oJsonMessage.Attachments)); - - this.readReceipt(oJsonMessage.ReadReceipt || ''); - - this.computeSenderEmail(); - - bResult = true; - } - - return bResult; -}; - -/** - * @param {(AjaxJsonAttachment|null)} oJsonAttachments - * @returns {Array} - */ -MessageModel.prototype.initAttachmentsFromJson = function(oJsonAttachments) -{ - var - iIndex = 0, - iLen = 0, - oAttachmentModel = null, - aResult = []; - - if (oJsonAttachments && 'Collection/AttachmentCollection' === oJsonAttachments['@Object'] && - Utils.isNonEmptyArray(oJsonAttachments['@Collection'])) - { - for (iIndex = 0, iLen = oJsonAttachments['@Collection'].length; iIndex < iLen; iIndex++) - { - oAttachmentModel = AttachmentModel.newInstanceFromJson(oJsonAttachments['@Collection'][iIndex]); - if (oAttachmentModel) - { - if ('' !== oAttachmentModel.cidWithOutTags && 0 < this.foundedCIDs.length && - 0 <= Utils.inArray(oAttachmentModel.cidWithOutTags, this.foundedCIDs)) - { - oAttachmentModel.isLinked = true; - } - - aResult.push(oAttachmentModel); - } - } - } - - return aResult; -}; - -/** - * @param {AjaxJsonMessage} oJsonMessage - * @returns {boolean} - */ -MessageModel.prototype.initFlagsByJson = function(oJsonMessage) -{ - var bResult = false; - - if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object']) - { - this.unseen(!oJsonMessage.IsSeen); - this.flagged(!!oJsonMessage.IsFlagged); - this.answered(!!oJsonMessage.IsAnswered); - this.forwarded(!!oJsonMessage.IsForwarded); - this.isReadReceipt(!!oJsonMessage.IsReadReceipt); - this.deletedMark(!!oJsonMessage.IsDeleted); - - bResult = true; - } - - return bResult; -}; - -/** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @returns {string} - */ -MessageModel.prototype.fromToLine = function(bFriendlyView, bWrapWithLink) -{ - return MessageHelper.emailArrayToString(this.from, bFriendlyView, bWrapWithLink); -}; - -/** - * @returns {string} - */ -MessageModel.prototype.fromDkimData = function() -{ - var aResult = ['none', '']; - if (Utils.isNonEmptyArray(this.from) && 1 === this.from.length && - this.from[0] && this.from[0].dkimStatus) - { - aResult = [this.from[0].dkimStatus, this.from[0].dkimValue || '']; - } - - return aResult; -}; - -/** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @returns {string} - */ -MessageModel.prototype.toToLine = function(bFriendlyView, bWrapWithLink) -{ - return MessageHelper.emailArrayToString(this.to, bFriendlyView, bWrapWithLink); -}; - -/** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @returns {string} - */ -MessageModel.prototype.ccToLine = function(bFriendlyView, bWrapWithLink) -{ - return MessageHelper.emailArrayToString(this.cc, bFriendlyView, bWrapWithLink); -}; - -/** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @returns {string} - */ -MessageModel.prototype.bccToLine = function(bFriendlyView, bWrapWithLink) -{ - return MessageHelper.emailArrayToString(this.bcc, bFriendlyView, bWrapWithLink); -}; - -/** - * @param {boolean} bFriendlyView - * @param {boolean=} bWrapWithLink = false - * @returns {string} - */ -MessageModel.prototype.replyToToLine = function(bFriendlyView, bWrapWithLink) -{ - return MessageHelper.emailArrayToString(this.replyTo, bFriendlyView, bWrapWithLink); -}; - -/** - * @return string - */ -MessageModel.prototype.lineAsCss = function() -{ - var aResult = []; - if (this.deleted()) - { - aResult.push('deleted'); - } - if (this.deletedMark()) - { - aResult.push('deleted-mark'); - } - if (this.selected()) - { - aResult.push('selected'); - } - if (this.checked()) - { - aResult.push('checked'); - } - if (this.flagged()) - { - aResult.push('flagged'); - } - if (this.unseen()) - { - aResult.push('unseen'); - } - if (this.answered()) - { - aResult.push('answered'); - } - if (this.forwarded()) - { - aResult.push('forwarded'); - } - if (this.focused()) - { - aResult.push('focused'); - } - if (this.isImportant()) - { - aResult.push('important'); - } - if (this.hasAttachments()) - { - aResult.push('withAttachments'); - } - if (this.newForAnimation()) - { - aResult.push('new'); - } - if ('' === this.subject()) - { - aResult.push('emptySubject'); - } -// if (1 < this.threadsLen()) -// { -// aResult.push('hasChildrenMessage'); -// } - if (this.hasUnseenSubMessage()) - { - aResult.push('hasUnseenSubMessage'); - } - if (this.hasFlaggedSubMessage()) - { - aResult.push('hasFlaggedSubMessage'); - } - - return aResult.join(' '); -}; - -/** - * @returns {boolean} - */ -MessageModel.prototype.hasVisibleAttachments = function() -{ - return !!_.find(this.attachments(), function(oAttachment) { - return !oAttachment.isLinked; - }); -}; - -/** - * @param {string} sCid - * @returns {*} - */ -MessageModel.prototype.findAttachmentByCid = function(sCid) -{ - var - oResult = null, - aAttachments = this.attachments(); - - if (Utils.isNonEmptyArray(aAttachments)) - { - sCid = sCid.replace(/^<+/, '').replace(/>+$/, ''); - oResult = _.find(aAttachments, function(oAttachment) { - return sCid === oAttachment.cidWithOutTags; - }); - } - - return oResult || null; -}; - -/** - * @param {string} sContentLocation - * @returns {*} - */ -MessageModel.prototype.findAttachmentByContentLocation = function(sContentLocation) -{ - var - oResult = null, - aAttachments = this.attachments(); - - if (Utils.isNonEmptyArray(aAttachments)) - { - oResult = _.find(aAttachments, function(oAttachment) { - return sContentLocation === oAttachment.contentLocation; - }); - } - - return oResult || null; -}; - -/** - * @returns {string} - */ -MessageModel.prototype.messageId = function() -{ - return this.sMessageId; -}; - -/** - * @returns {string} - */ -MessageModel.prototype.inReplyTo = function() -{ - return this.sInReplyTo; -}; - -/** - * @returns {string} - */ -MessageModel.prototype.references = function() -{ - return this.sReferences; -}; - -/** - * @returns {string} - */ -MessageModel.prototype.fromAsSingleEmail = function() -{ - return Utils.isArray(this.from) && this.from[0] ? this.from[0].email : ''; -}; - -/** - * @returns {string} - */ -MessageModel.prototype.viewLink = function() -{ - return Links.messageViewLink(this.requestHash); -}; - -/** - * @returns {string} - */ -MessageModel.prototype.downloadLink = function() -{ - return Links.messageDownloadLink(this.requestHash); -}; - -/** - * @param {Object} oExcludeEmails - * @param {boolean=} bLast = false - * @returns {Array} - */ -MessageModel.prototype.replyEmails = function(oExcludeEmails, bLast) -{ - var - aResult = [], - oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails; - - MessageHelper.replyHelper(this.replyTo, oUnic, aResult); - if (0 === aResult.length) - { - MessageHelper.replyHelper(this.from, oUnic, aResult); - } - - if (0 === aResult.length && !bLast) - { - return this.replyEmails({}, true); - } - - return aResult; -}; - -/** - * @param {Object} oExcludeEmails - * @param {boolean=} bLast = false - * @returns {Array.} - */ -MessageModel.prototype.replyAllEmails = function(oExcludeEmails, bLast) -{ - var - aData = [], - aToResult = [], - aCcResult = [], - oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails; - - MessageHelper.replyHelper(this.replyTo, oUnic, aToResult); - if (0 === aToResult.length) - { - MessageHelper.replyHelper(this.from, oUnic, aToResult); - } - - MessageHelper.replyHelper(this.to, oUnic, aToResult); - MessageHelper.replyHelper(this.cc, oUnic, aCcResult); - - if (0 === aToResult.length && !bLast) - { - aData = this.replyAllEmails({}, true); - return [aData[0], aCcResult]; - } - - return [aToResult, aCcResult]; -}; - -/** - * @returns {string} - */ -MessageModel.prototype.textBodyToString = function() -{ - return this.body ? this.body.html() : ''; -}; - -/** - * @returns {string} - */ -MessageModel.prototype.attachmentsToStringLine = function() -{ - var aAttachLines = _.map(this.attachments(), function(oItem) { - return oItem.fileName + ' (' + oItem.friendlySize + ')'; - }); - - return aAttachLines && 0 < aAttachLines.length ? aAttachLines.join(', ') : ''; -}; - -/** - * @returns {Object} - */ -MessageModel.prototype.getDataForWindowPopup = function() -{ - return { - 'popupFrom': this.fromToLine(false), - 'popupTo': this.toToLine(false), - 'popupCc': this.ccToLine(false), - 'popupBcc': this.bccToLine(false), - 'popupReplyTo': this.replyToToLine(false), - 'popupSubject': this.subject(), - 'popupIsHtml': this.isHtml(), - 'popupDate': require('Common/Momentor').format(this.dateTimeStampInUTC(), 'FULL'), - 'popupAttachments': this.attachmentsToStringLine(), - 'popupBody': this.textBodyToString() - }; -}; - -/** - * @param {boolean=} bPrint = false - */ -MessageModel.prototype.viewPopupMessage = function(bPrint) -{ - this.showLazyExternalImagesInBody(); - Utils.previewMessage(this.subject(), this.body, this.isHtml(), bPrint); -}; - -MessageModel.prototype.printMessage = function() -{ - this.viewPopupMessage(true); -}; - -/** - * @returns {string} - */ -MessageModel.prototype.generateUid = function() -{ - return this.folderFullNameRaw + '/' + this.uid; -}; - -/** - * @param {MessageModel} oMessage - * @returns {MessageModel} - */ -MessageModel.prototype.populateByMessageListItem = function(oMessage) -{ - if (oMessage) - { - this.folderFullNameRaw = oMessage.folderFullNameRaw; - this.uid = oMessage.uid; - this.hash = oMessage.hash; - this.requestHash = oMessage.requestHash; - this.subject(oMessage.subject()); - } - - this.subjectPrefix(this.subjectPrefix()); - this.subjectSuffix(this.subjectSuffix()); - - if (oMessage) - { - - this.size(oMessage.size()); - this.dateTimeStampInUTC(oMessage.dateTimeStampInUTC()); - this.priority(oMessage.priority()); - - this.proxy = oMessage.proxy; - - this.fromEmailString(oMessage.fromEmailString()); - this.fromClearEmailString(oMessage.fromClearEmailString()); - this.toEmailsString(oMessage.toEmailsString()); - this.toClearEmailsString(oMessage.toClearEmailsString()); - - this.emails = oMessage.emails; - - this.from = oMessage.from; - this.to = oMessage.to; - this.cc = oMessage.cc; - this.bcc = oMessage.bcc; - this.replyTo = oMessage.replyTo; - this.deliveredTo = oMessage.deliveredTo; - - this.unseen(oMessage.unseen()); - this.flagged(oMessage.flagged()); - this.answered(oMessage.answered()); - this.forwarded(oMessage.forwarded()); - this.isReadReceipt(oMessage.isReadReceipt()); - this.deletedMark(oMessage.deletedMark()); - - this.priority(oMessage.priority()); - - this.selected(oMessage.selected()); - this.checked(oMessage.checked()); - this.hasAttachments(oMessage.hasAttachments()); - this.attachmentsSpecData(oMessage.attachmentsSpecData()); - } - - this.body = null; - - this.aDraftInfo = []; - this.sMessageId = ''; - this.sInReplyTo = ''; - this.sReferences = ''; - - if (oMessage) - { - this.threads(oMessage.threads()); - } - - this.computeSenderEmail(); - - return this; -}; - -MessageModel.prototype.showLazyExternalImagesInBody = function() -{ - if (this.body) - { - $('.lazy.lazy-inited[data-original]', this.body).each(function() { - $(this).attr('src', $(this).attr('data-original')).removeAttr('data-original'); - }); - } -}; - -MessageModel.prototype.showExternalImages = function(bLazy) -{ - if (this.body && this.body.data('rl-has-images')) - { - bLazy = Utils.isUnd(bLazy) ? false : bLazy; - - this.hasImages(false); - this.body.data('rl-has-images', false); - - var sAttr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; - $('[' + sAttr + ']', this.body).each(function() { - if (bLazy && $(this).is('img')) - { - $(this) - .addClass('lazy') - .attr('data-original', $(this).attr(sAttr)) - .removeAttr(sAttr); - } - else - { - $(this).attr('src', $(this).attr(sAttr)).removeAttr(sAttr); - } - }); - - sAttr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; - $('[' + sAttr + ']', this.body).each(function() { - var sStyle = Utils.trim($(this).attr('style')); - sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); - $(this).attr('style', sStyle + $(this).attr(sAttr)).removeAttr(sAttr); - }); - - if (bLazy) - { - $('img.lazy', this.body).addClass('lazy-inited').lazyload({ - 'threshold': 400, - 'effect': 'fadeIn', - 'skip_invisible': false, - 'container': $('.RL-MailMessageView .messageView .messageItem .content')[0] - }); - - Globals.$win.resize(); - } - - Utils.windowResize(500); - } -}; - -MessageModel.prototype.showInternalImages = function(bLazy) -{ - if (this.body && !this.body.data('rl-init-internal-images')) - { - this.body.data('rl-init-internal-images', true); - - bLazy = Utils.isUnd(bLazy) ? false : bLazy; - - var self = this; - - $('[data-x-src-cid]', this.body).each(function() { - - var oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-cid')); - if (oAttachment && oAttachment.download) - { - if (bLazy && $(this).is('img')) - { - $(this) - .addClass('lazy') - .attr('data-original', oAttachment.linkPreview()); - } - else - { - $(this).attr('src', oAttachment.linkPreview()); - } - } - }); - - $('[data-x-src-location]', this.body).each(function() { - - var oAttachment = self.findAttachmentByContentLocation($(this).attr('data-x-src-location')); - if (!oAttachment) - { - oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-location')); - } - - if (oAttachment && oAttachment.download) - { - if (bLazy && $(this).is('img')) - { - $(this) - .addClass('lazy') - .attr('data-original', oAttachment.linkPreview()); - } - else - { - $(this).attr('src', oAttachment.linkPreview()); - } - } - }); - - $('[data-x-style-cid]', this.body).each(function() { - - var - sStyle = '', - sName = '', - oAttachment = self.findAttachmentByCid($(this).attr('data-x-style-cid')); - - if (oAttachment && oAttachment.linkPreview) - { - sName = $(this).attr('data-x-style-cid-name'); - if ('' !== sName) - { - sStyle = Utils.trim($(this).attr('style')); - sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); - $(this).attr('style', sStyle + sName + ': url(\'' + oAttachment.linkPreview() + '\')'); - } - } - }); - - if (bLazy) - { - (function($oImg, oContainer) { - _.delay(function() { - $oImg.addClass('lazy-inited').lazyload({ - 'threshold': 400, - 'effect': 'fadeIn', - 'skip_invisible': false, - 'container': oContainer - }); - }, 300); - }($('img.lazy', self.body), $('.RL-MailMessageView .messageView .messageItem .content')[0])); - } - - Utils.windowResize(500); - } -}; - -MessageModel.prototype.storeDataInDom = function() -{ - if (this.body) - { - this.body.data('rl-is-html', !!this.isHtml()); - this.body.data('rl-has-images', !!this.hasImages()); - } -}; - -MessageModel.prototype.fetchDataFromDom = function() -{ - if (this.body) - { - this.isHtml(!!this.body.data('rl-is-html')); - this.hasImages(!!this.body.data('rl-has-images')); - } -}; - -MessageModel.prototype.replacePlaneTextBody = function(sPlain) -{ - if (this.body) - { - this.body.html(sPlain).addClass('b-text-part plain'); - } -}; - -/** - * @returns {string} - */ -MessageModel.prototype.flagHash = function() -{ - return [this.deleted(), this.deletedMark(), this.unseen(), this.flagged(), this.answered(), this.forwarded(), - this.isReadReceipt()].join(','); -}; - -module.exports = MessageModel; diff --git a/dev/Model/Message.jsx b/dev/Model/Message.jsx new file mode 100644 index 000000000..d34496a9b --- /dev/null +++ b/dev/Model/Message.jsx @@ -0,0 +1,918 @@ + +import _ from '_'; +import $ from '$'; +import ko from 'ko'; + +import {MessagePriority, SignedVerifyStatus} from 'Common/Enums'; + +import { + pInt, inArray, isArray, isUnd, trim, + previewMessage, windowResize, friendlySize, isNonEmptyArray +} from 'Common/Utils'; + +import {$win} from 'Common/Globals'; +import {messageViewLink, messageDownloadLink} from 'Common/Links'; + +import {emailArrayFromJson, emailArrayToStringClear, emailArrayToString, replyHelper} from 'Helper/Message'; + +import {AttachmentModel, staticCombinedIconClass} from 'Model/Attachment'; +import {AbstractModel} from 'Knoin/AbstractModel'; + +class MessageModel extends AbstractModel +{ + constructor() + { + super('MessageModel'); + + this.folderFullNameRaw = ''; + this.uid = ''; + this.hash = ''; + this.requestHash = ''; + this.subject = ko.observable(''); + this.subjectPrefix = ko.observable(''); + this.subjectSuffix = ko.observable(''); + this.size = ko.observable(0); + this.dateTimeStampInUTC = ko.observable(0); + this.priority = ko.observable(MessagePriority.Normal); + + this.proxy = false; + + this.fromEmailString = ko.observable(''); + this.fromClearEmailString = ko.observable(''); + this.toEmailsString = ko.observable(''); + this.toClearEmailsString = ko.observable(''); + + this.senderEmailsString = ko.observable(''); + this.senderClearEmailsString = ko.observable(''); + + this.emails = []; + + this.from = []; + this.to = []; + this.cc = []; + this.bcc = []; + this.replyTo = []; + this.deliveredTo = []; + + this.newForAnimation = ko.observable(false); + + this.deleted = ko.observable(false); + this.deletedMark = ko.observable(false); + this.unseen = ko.observable(false); + this.flagged = ko.observable(false); + this.answered = ko.observable(false); + this.forwarded = ko.observable(false); + this.isReadReceipt = ko.observable(false); + + this.focused = ko.observable(false); + this.selected = ko.observable(false); + this.checked = ko.observable(false); + this.hasAttachments = ko.observable(false); + this.attachmentsSpecData = ko.observableArray([]); + + this.attachmentIconClass = ko.computed(() => staticCombinedIconClass(this.hasAttachments() ? this.attachmentsSpecData() : [])); + + this.body = null; + + this.isHtml = ko.observable(false); + this.hasImages = ko.observable(false); + this.attachments = ko.observableArray([]); + + this.isPgpSigned = ko.observable(false); + this.isPgpEncrypted = ko.observable(false); + this.pgpSignedVerifyStatus = ko.observable(SignedVerifyStatus.None); + this.pgpSignedVerifyUser = ko.observable(''); + + this.priority = ko.observable(MessagePriority.Normal); + this.readReceipt = ko.observable(''); + + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; + + this.hasUnseenSubMessage = ko.observable(false); + this.hasFlaggedSubMessage = ko.observable(false); + + this.threads = ko.observableArray([]); + + this.threadsLen = ko.computed(() => this.threads().length); + this.isImportant = ko.computed(() => MessagePriority.High === this.priority()); + + this.regDisposables([this.attachmentIconClass, this.threadsLen, this.isImportant]); + } + + /** + * @static + * @param {AjaxJsonMessage} oJsonMessage + * @returns {?MessageModel} + */ + static newInstanceFromJson(json) { + const oMessageModel = new MessageModel(); + return oMessageModel.initByJson(json) ? oMessageModel : null; + } + + clear() { + this.folderFullNameRaw = ''; + this.uid = ''; + this.hash = ''; + this.requestHash = ''; + this.subject(''); + this.subjectPrefix(''); + this.subjectSuffix(''); + this.size(0); + this.dateTimeStampInUTC(0); + this.priority(MessagePriority.Normal); + + this.proxy = false; + + this.fromEmailString(''); + this.fromClearEmailString(''); + this.toEmailsString(''); + this.toClearEmailsString(''); + this.senderEmailsString(''); + this.senderClearEmailsString(''); + + this.emails = []; + + this.from = []; + this.to = []; + this.cc = []; + this.bcc = []; + this.replyTo = []; + this.deliveredTo = []; + + this.newForAnimation(false); + + this.deleted(false); + this.deletedMark(false); + this.unseen(false); + this.flagged(false); + this.answered(false); + this.forwarded(false); + this.isReadReceipt(false); + + this.selected(false); + this.checked(false); + this.hasAttachments(false); + this.attachmentsSpecData([]); + + this.body = null; + this.isHtml(false); + this.hasImages(false); + this.attachments([]); + + this.isPgpSigned(false); + this.isPgpEncrypted(false); + this.pgpSignedVerifyStatus(SignedVerifyStatus.None); + this.pgpSignedVerifyUser(''); + + this.priority(MessagePriority.Normal); + this.readReceipt(''); + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; + + this.threads([]); + + this.hasUnseenSubMessage(false); + this.hasFlaggedSubMessage(false); + } + + /** + * @param {Array} properties + * @returns {Array} + */ + getEmails(properties) { + return _.compact(_.uniq(_.map( + _.reduce(properties, (carry, property) => carry.concat(this[property]), []), + (oItem) => (oItem ? oItem.email : '') + ))); + } + + /** + * @returns {Array} + */ + getRecipientsEmails() { + return this.getEmails(['to', 'cc']); + } + + /** + * @returns {string} + */ + friendlySize() { + return friendlySize(this.size()); + } + + computeSenderEmail() { + const + sentFolder = require('Stores/User/Folder').sentFolder(), + draftFolder = require('Stores/User/Folder').draftFolder(); + + this.senderEmailsString(this.folderFullNameRaw === sentFolder || this.folderFullNameRaw === draftFolder ? + this.toEmailsString() : this.fromEmailString()); + + this.senderClearEmailsString(this.folderFullNameRaw === sentFolder || this.folderFullNameRaw === draftFolder ? + this.toClearEmailsString() : this.fromClearEmailString()); + } + + /** + * @param {AjaxJsonMessage} json + * @returns {boolean} + */ + initByJson(json) { + let + result = false, + priority = MessagePriority.Normal; + + if (json && 'Object/Message' === json['@Object']) + { + priority = pInt(json.Priority); + this.priority(-1 < inArray(priority, [MessagePriority.High, MessagePriority.Low]) ? priority : MessagePriority.Normal); + + this.folderFullNameRaw = json.Folder; + this.uid = json.Uid; + this.hash = json.Hash; + this.requestHash = json.RequestHash; + + this.proxy = !!json.ExternalProxy; + + this.size(pInt(json.Size)); + + this.from = emailArrayFromJson(json.From); + this.to = emailArrayFromJson(json.To); + this.cc = emailArrayFromJson(json.Cc); + this.bcc = emailArrayFromJson(json.Bcc); + this.replyTo = emailArrayFromJson(json.ReplyTo); + this.deliveredTo = emailArrayFromJson(json.DeliveredTo); + + this.subject(json.Subject); + if (isArray(json.SubjectParts)) + { + this.subjectPrefix(json.SubjectParts[0]); + this.subjectSuffix(json.SubjectParts[1]); + } + else + { + this.subjectPrefix(''); + this.subjectSuffix(this.subject()); + } + + this.dateTimeStampInUTC(pInt(json.DateTimeStampInUTC)); + this.hasAttachments(!!json.HasAttachments); + this.attachmentsSpecData(isArray(json.AttachmentsSpecData) ? json.AttachmentsSpecData : []); + + this.fromEmailString(emailArrayToString(this.from, true)); + this.fromClearEmailString(emailArrayToStringClear(this.from)); + this.toEmailsString(emailArrayToString(this.to, true)); + this.toClearEmailsString(emailArrayToStringClear(this.to)); + + this.threads(isArray(json.Threads) ? json.Threads : []); + + this.initFlagsByJson(json); + this.computeSenderEmail(); + + result = true; + } + + return result; + } + + /** + * @param {AjaxJsonMessage} json + * @returns {boolean} + */ + initUpdateByMessageJson(json) { + let + result = false, + priority = MessagePriority.Normal; + + if (json && 'Object/Message' === json['@Object']) + { + priority = pInt(json.Priority); + this.priority(-1 < inArray(priority, [MessagePriority.High, MessagePriority.Low]) ? + priority : MessagePriority.Normal); + + this.aDraftInfo = json.DraftInfo; + + this.sMessageId = json.MessageId; + this.sInReplyTo = json.InReplyTo; + this.sReferences = json.References; + + this.proxy = !!json.ExternalProxy; + + if (require('Stores/User/Pgp').capaOpenPGP()) + { + this.isPgpSigned(!!json.PgpSigned); + this.isPgpEncrypted(!!json.PgpEncrypted); + } + + this.hasAttachments(!!json.HasAttachments); + this.attachmentsSpecData(isArray(json.AttachmentsSpecData) ? json.AttachmentsSpecData : []); + + this.foundedCIDs = isArray(json.FoundedCIDs) ? json.FoundedCIDs : []; + this.attachments(this.initAttachmentsFromJson(json.Attachments)); + + this.readReceipt(json.ReadReceipt || ''); + + this.computeSenderEmail(); + + result = true; + } + + return result; + } + + /** + * @param {(AjaxJsonAttachment|null)} oJsonAttachments + * @returns {Array} + */ + initAttachmentsFromJson(json) { + let + index = 0, + len = 0, + attachment = null; + const result = []; + + if (json && 'Collection/AttachmentCollection' === json['@Object'] && isNonEmptyArray(json['@Collection'])) + { + for (index = 0, len = json['@Collection'].length; index < len; index++) + { + attachment = AttachmentModel.newInstanceFromJson(json['@Collection'][index]); + if (attachment) + { + if ('' !== attachment.cidWithOutTags && 0 < this.foundedCIDs.length && + 0 <= inArray(attachment.cidWithOutTags, this.foundedCIDs)) + { + attachment.isLinked = true; + } + + result.push(attachment); + } + } + } + + return result; + } + + /** + * @param {AjaxJsonMessage} json + * @returns {boolean} + */ + initFlagsByJson(json) { + let result = false; + if (json && 'Object/Message' === json['@Object']) + { + this.unseen(!json.IsSeen); + this.flagged(!!json.IsFlagged); + this.answered(!!json.IsAnswered); + this.forwarded(!!json.IsForwarded); + this.isReadReceipt(!!json.IsReadReceipt); + this.deletedMark(!!json.IsDeleted); + + result = true; + } + + return result; + } + + /** + * @param {boolean} friendlyView + * @param {boolean=} wrapWithLink = false + * @returns {string} + */ + fromToLine(friendlyView, wrapWithLink = false) { + return emailArrayToString(this.from, friendlyView, wrapWithLink); + } + + /** + * @returns {string} + */ + fromDkimData() { + let result = ['none', '']; + if (isNonEmptyArray(this.from) && 1 === this.from.length && this.from[0] && this.from[0].dkimStatus) + { + result = [this.from[0].dkimStatus, this.from[0].dkimValue || '']; + } + + return result; + } + + /** + * @param {boolean} friendlyView + * @param {boolean=} wrapWithLink = false + * @returns {string} + */ + toToLine(friendlyView, wrapWithLink = false) { + return emailArrayToString(this.to, friendlyView, wrapWithLink); + } + + /** + * @param {boolean} friendlyView + * @param {boolean=} wrapWithLink = false + * @returns {string} + */ + ccToLine(friendlyView, wrapWithLink = false) { + return emailArrayToString(this.cc, friendlyView, wrapWithLink); + } + + /** + * @param {boolean} friendlyView + * @param {boolean=} wrapWithLink = false + * @returns {string} + */ + bccToLine(friendlyView, wrapWithLink = false) { + return emailArrayToString(this.bcc, friendlyView, wrapWithLink); + } + + /** + * @param {boolean} friendlyView + * @param {boolean=} wrapWithLink = false + * @returns {string} + */ + replyToToLine(friendlyView, wrapWithLink = false) { + return emailArrayToString(this.replyTo, friendlyView, wrapWithLink); + } + + /** + * @return string + */ + lineAsCss() { + const result = []; + if (this.deleted()) + { + result.push('deleted'); + } + if (this.deletedMark()) + { + result.push('deleted-mark'); + } + if (this.selected()) + { + result.push('selected'); + } + if (this.checked()) + { + result.push('checked'); + } + if (this.flagged()) + { + result.push('flagged'); + } + if (this.unseen()) + { + result.push('unseen'); + } + if (this.answered()) + { + result.push('answered'); + } + if (this.forwarded()) + { + result.push('forwarded'); + } + if (this.focused()) + { + result.push('focused'); + } + if (this.isImportant()) + { + result.push('important'); + } + if (this.hasAttachments()) + { + result.push('withAttachments'); + } + if (this.newForAnimation()) + { + result.push('new'); + } + if ('' === this.subject()) + { + result.push('emptySubject'); + } +// if (1 < this.threadsLen()) +// { +// result.push('hasChildrenMessage'); +// } + if (this.hasUnseenSubMessage()) + { + result.push('hasUnseenSubMessage'); + } + if (this.hasFlaggedSubMessage()) + { + result.push('hasFlaggedSubMessage'); + } + + return result.join(' '); + } + + /** + * @returns {boolean} + */ + hasVisibleAttachments() { + return !!_.find(this.attachments(), (item) => !item.isLinked); + } + + /** + * @param {string} cid + * @returns {*} + */ + findAttachmentByCid(cid) { + let result = null; + const attachments = this.attachments(); + + if (isNonEmptyArray(attachments)) + { + cid = cid.replace(/^<+/, '').replace(/>+$/, ''); + result = _.find(attachments, (item) => cid === item.cidWithOutTags); + } + + return result || null; + } + + /** + * @param {string} contentLocation + * @returns {*} + */ + findAttachmentByContentLocation(contentLocation) { + let result = null; + const attachments = this.attachments(); + + if (isNonEmptyArray(attachments)) + { + result = _.find(attachments, (item) => contentLocation === item.contentLocation); + } + + return result || null; + } + + /** + * @returns {string} + */ + messageId() { + return this.sMessageId; + } + + /** + * @returns {string} + */ + inReplyTo() { + return this.sInReplyTo; + } + + /** + * @returns {string} + */ + references() { + return this.sReferences; + } + + /** + * @returns {string} + */ + fromAsSingleEmail() { + return isArray(this.from) && this.from[0] ? this.from[0].email : ''; + } + + /** + * @returns {string} + */ + viewLink() { + return messageViewLink(this.requestHash); + } + + /** + * @returns {string} + */ + downloadLink() { + return messageDownloadLink(this.requestHash); + } + + /** + * @param {Object} excludeEmails + * @param {boolean=} last = false + * @returns {Array} + */ + replyEmails(excludeEmails, last = false) { + const + result = [], + unic = isUnd(excludeEmails) ? {} : excludeEmails; + + replyHelper(this.replyTo, unic, result); + if (0 === result.length) + { + replyHelper(this.from, unic, result); + } + + if (0 === result.length && !last) + { + return this.replyEmails({}, true); + } + + return result; + } + + /** + * @param {Object} excludeEmails + * @param {boolean=} last = false + * @returns {Array.} + */ + replyAllEmails(excludeEmails, last = false) { + let data = []; + const + toResult = [], + ccResult = [], + unic = isUnd(excludeEmails) ? {} : excludeEmails; + + replyHelper(this.replyTo, unic, toResult); + if (0 === toResult.length) + { + replyHelper(this.from, unic, toResult); + } + + replyHelper(this.to, unic, toResult); + replyHelper(this.cc, unic, ccResult); + + if (0 === toResult.length && !last) + { + data = this.replyAllEmails({}, true); + return [data[0], ccResult]; + } + + return [toResult, ccResult]; + } + + /** + * @returns {string} + */ + textBodyToString() { + return this.body ? this.body.html() : ''; + } + + /** + * @returns {string} + */ + attachmentsToStringLine() { + const attachLines = _.map(this.attachments(), (item) => item.fileName + ' (' + item.friendlySize + ')'); + return attachLines && 0 < attachLines.length ? attachLines.join(', ') : ''; + } + + /** + * @param {boolean=} print = false + */ + viewPopupMessage(print = false) { + this.showLazyExternalImagesInBody(); + previewMessage(this.subject(), this.body, this.isHtml(), print); + } + + printMessage() { + this.viewPopupMessage(true); + } + + /** + * @returns {string} + */ + generateUid() { + return this.folderFullNameRaw + '/' + this.uid; + } + + /** + * @param {MessageModel} message + * @returns {MessageModel} + */ + populateByMessageListItem(message) { + if (message) + { + this.folderFullNameRaw = message.folderFullNameRaw; + this.uid = message.uid; + this.hash = message.hash; + this.requestHash = message.requestHash; + this.subject(message.subject()); + } + + this.subjectPrefix(this.subjectPrefix()); + this.subjectSuffix(this.subjectSuffix()); + + if (message) + { + this.size(message.size()); + this.dateTimeStampInUTC(message.dateTimeStampInUTC()); + this.priority(message.priority()); + + this.proxy = message.proxy; + + this.fromEmailString(message.fromEmailString()); + this.fromClearEmailString(message.fromClearEmailString()); + this.toEmailsString(message.toEmailsString()); + this.toClearEmailsString(message.toClearEmailsString()); + + this.emails = message.emails; + + this.from = message.from; + this.to = message.to; + this.cc = message.cc; + this.bcc = message.bcc; + this.replyTo = message.replyTo; + this.deliveredTo = message.deliveredTo; + + this.unseen(message.unseen()); + this.flagged(message.flagged()); + this.answered(message.answered()); + this.forwarded(message.forwarded()); + this.isReadReceipt(message.isReadReceipt()); + this.deletedMark(message.deletedMark()); + + this.priority(message.priority()); + + this.selected(message.selected()); + this.checked(message.checked()); + this.hasAttachments(message.hasAttachments()); + this.attachmentsSpecData(message.attachmentsSpecData()); + } + + this.body = null; + + this.aDraftInfo = []; + this.sMessageId = ''; + this.sInReplyTo = ''; + this.sReferences = ''; + + if (message) + { + this.threads(message.threads()); + } + + this.computeSenderEmail(); + + return this; + } + + showLazyExternalImagesInBody() { + if (this.body) + { + $('.lazy.lazy-inited[data-original]', this.body).each(function() { + $(this).attr('src', $(this).attr('data-original')).removeAttr('data-original'); + }); + } + } + + showExternalImages(lazy = false) { + if (this.body && this.body.data('rl-has-images')) + { + this.hasImages(false); + this.body.data('rl-has-images', false); + + var sAttr = this.proxy ? 'data-x-additional-src' : 'data-x-src'; + $('[' + sAttr + ']', this.body).each(function() { + if (lazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', $(this).attr(sAttr)) + .removeAttr(sAttr); + } + else + { + $(this).attr('src', $(this).attr(sAttr)).removeAttr(sAttr); + } + }); + + sAttr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url'; + $('[' + sAttr + ']', this.body).each(function() { + var sStyle = trim($(this).attr('style')); + sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; '); + $(this).attr('style', sStyle + $(this).attr(sAttr)).removeAttr(sAttr); + }); + + if (lazy) + { + $('img.lazy', this.body).addClass('lazy-inited').lazyload({ + 'threshold': 400, + 'effect': 'fadeIn', + 'skip_invisible': false, + 'container': $('.RL-MailMessageView .messageView .messageItem .content')[0] + }); + + $win.resize(); + } + + windowResize(500); + } + } + + showInternalImages(lazy = false) { + if (this.body && !this.body.data('rl-init-internal-images')) + { + this.body.data('rl-init-internal-images', true); + + var self = this; + + $('[data-x-src-cid]', this.body).each(function() { + const attachment = self.findAttachmentByCid($(this).attr('data-x-src-cid')); + if (attachment && attachment.download) + { + if (lazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', attachment.linkPreview()); + } + else + { + $(this).attr('src', attachment.linkPreview()); + } + } + }); + + $('[data-x-src-location]', this.body).each(function() { + let attachment = self.findAttachmentByContentLocation($(this).attr('data-x-src-location')); + if (!attachment) + { + attachment = self.findAttachmentByCid($(this).attr('data-x-src-location')); + } + + if (attachment && attachment.download) + { + if (lazy && $(this).is('img')) + { + $(this) + .addClass('lazy') + .attr('data-original', attachment.linkPreview()); + } + else + { + $(this).attr('src', attachment.linkPreview()); + } + } + }); + + $('[data-x-style-cid]', this.body).each(function() { + let + style = '', + name = ''; + const attachment = self.findAttachmentByCid($(this).attr('data-x-style-cid')); + + if (attachment && attachment.linkPreview) + { + name = $(this).attr('data-x-style-cid-name'); + if ('' !== name) + { + style = trim($(this).attr('style')); + style = '' === style ? '' : (';' === style.substr(-1) ? style + ' ' : style + '; '); + $(this).attr('style', style + name + ': url(\'' + attachment.linkPreview() + '\')'); + } + } + }); + + if (lazy) + { + (function($oImg, oContainer) { + _.delay(() => { + $oImg.addClass('lazy-inited').lazyload({ + 'threshold': 400, + 'effect': 'fadeIn', + 'skip_invisible': false, + 'container': oContainer + }); + }, 300); + }($('img.lazy', self.body), $('.RL-MailMessageView .messageView .messageItem .content')[0])); + } + + windowResize(500); + } + } + + storeDataInDom() { + if (this.body) + { + this.body.data('rl-is-html', !!this.isHtml()); + this.body.data('rl-has-images', !!this.hasImages()); + } + } + + fetchDataFromDom() { + if (this.body) + { + this.isHtml(!!this.body.data('rl-is-html')); + this.hasImages(!!this.body.data('rl-has-images')); + } + } + + replacePlaneTextBody(plain) { + if (this.body) + { + this.body.html(plain).addClass('b-text-part plain'); + } + } + + /** + * @returns {string} + */ + flagHash() { + return [this.deleted(), this.deletedMark(), this.unseen(), this.flagged(), this.answered(), this.forwarded(), this.isReadReceipt()].join(','); + } +} + +export {MessageModel, MessageModel as default}; diff --git a/dev/Model/MessageFull.js b/dev/Model/MessageFull.js deleted file mode 100644 index d363bbbcf..000000000 --- a/dev/Model/MessageFull.js +++ /dev/null @@ -1,80 +0,0 @@ - -var - _ = require('_'), - - Enums = require('Common/Enums'), - Utils = require('Common/Utils'), - - MessageSimpleModel = require('Model/MessageSimple'); - -/** - * @constructor - */ -function MessageFullModel() -{ - MessageSimpleModel.call(this, 'MessageFullModel'); -} - -_.extend(MessageFullModel.prototype, MessageSimpleModel.prototype); - -MessageFullModel.prototype.priority = 0; -MessageFullModel.prototype.hash = ''; -MessageFullModel.prototype.requestHash = ''; -MessageFullModel.prototype.proxy = false; -MessageFullModel.prototype.hasAttachments = false; - -MessageFullModel.prototype.clear = function() -{ - MessageSimpleModel.prototype.clear.call(this); - - this.priority = 0; - this.hash = ''; - this.requestHash = ''; - - this.proxy = false; - - this.hasAttachments = false; -}; - -/** - * @param {AjaxJsonMessage} oJson - * @returns {boolean} - */ -MessageFullModel.prototype.initByJson = function(oJson) -{ - var bResult = false; - - if (oJson && 'Object/Message' === oJson['@Object']) - { - if (MessageSimpleModel.prototype.initByJson.call(this, oJson)) - { - this.priority = Utils.pInt(oJson.Priority); - this.priority = Utils.inArray(this.priority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ? - this.priority : Enums.MessagePriority.Normal; - - this.hash = Utils.pString(oJson.Hash); - this.requestHash = Utils.pString(oJson.RequestHash); - - this.proxy = !!oJson.ExternalProxy; - - this.hasAttachments = !!oJson.HasAttachments; - - bResult = true; - } - } - - return bResult; -}; - -/** - * @static - * @param {AjaxJsonMessage} oJson - * @returns {?MessageFullModel} - */ -MessageFullModel.newInstanceFromJson = function(oJson) -{ - var oItem = oJson ? new MessageFullModel() : null; - return oItem && oItem.initByJson(oJson) ? oItem : null; -}; - -module.exports = MessageFullModel; diff --git a/dev/Model/MessageSimple.js b/dev/Model/MessageSimple.js deleted file mode 100644 index 35589a4de..000000000 --- a/dev/Model/MessageSimple.js +++ /dev/null @@ -1,167 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Utils = require('Common/Utils'), - - MessageHelper = require('Helper/Message').default, - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - * @param {string=} sSuperName - */ -function MessageSimpleModel(sSuperName) -{ - AbstractModel.call(this, sSuperName || 'MessageSimpleModel'); - - this.flagged = ko.observable(false); - this.selected = ko.observable(false); -} - -_.extend(MessageSimpleModel.prototype, AbstractModel.prototype); - -MessageSimpleModel.prototype.isSimpleMessage = true; - -MessageSimpleModel.prototype.folder = ''; -MessageSimpleModel.prototype.folderFullNameRaw = ''; - -MessageSimpleModel.prototype.uid = ''; -MessageSimpleModel.prototype.subject = ''; - -MessageSimpleModel.prototype.to = []; -MessageSimpleModel.prototype.from = []; -MessageSimpleModel.prototype.cc = []; -MessageSimpleModel.prototype.bcc = []; -MessageSimpleModel.prototype.replyTo = []; -MessageSimpleModel.prototype.deliveredTo = []; - -MessageSimpleModel.prototype.fromAsString = ''; -MessageSimpleModel.prototype.fromAsStringClear = ''; -MessageSimpleModel.prototype.toAsString = ''; -MessageSimpleModel.prototype.toAsStringClear = ''; -MessageSimpleModel.prototype.senderAsString = ''; -MessageSimpleModel.prototype.senderAsStringClear = ''; - -MessageSimpleModel.prototype.size = 0; -MessageSimpleModel.prototype.timestamp = 0; - -MessageSimpleModel.prototype.clear = function() -{ - this.folder = ''; - this.folderFullNameRaw = ''; - - this.uid = ''; - - this.subject = ''; - - this.to = []; - this.from = []; - this.cc = []; - this.bcc = []; - this.replyTo = []; - this.deliveredTo = []; - - this.fromAsString = ''; - this.fromAsStringClear = ''; - this.toAsString = ''; - this.toAsStringClear = ''; - this.senderAsString = ''; - this.senderAsStringClear = ''; - - this.size = 0; - this.timestamp = 0; - - this.flagged(false); - this.selected(false); -}; - -/** - * @param {Object} oJson - * @returns {boolean} - */ -MessageSimpleModel.prototype.initByJson = function(oJson) -{ - var bResult = false; - - if (oJson && 'Object/Message' === oJson['@Object']) - { - this.folder = Utils.pString(oJson.Folder); - this.folderFullNameRaw = this.folder; - - this.uid = Utils.pString(oJson.Uid); - - this.subject = Utils.pString(oJson.Subject); - - if (Utils.isArray(oJson.SubjectParts)) - { - this.subjectPrefix = Utils.pString(oJson.SubjectParts[0]); - this.subjectSuffix = Utils.pString(oJson.SubjectParts[1]); - } - else - { - this.subjectPrefix = ''; - this.subjectSuffix = this.subject; - } - - this.from = MessageHelper.emailArrayFromJson(oJson.From); - this.to = MessageHelper.emailArrayFromJson(oJson.To); - this.cc = MessageHelper.emailArrayFromJson(oJson.Cc); - this.bcc = MessageHelper.emailArrayFromJson(oJson.Bcc); - this.replyTo = MessageHelper.emailArrayFromJson(oJson.ReplyTo); - this.deliveredTo = MessageHelper.emailArrayFromJson(oJson.DeliveredTo); - - this.size = Utils.pInt(oJson.Size); - this.timestamp = Utils.pInt(oJson.DateTimeStampInUTC); - - this.fromAsString = MessageHelper.emailArrayToString(this.from, true); - this.fromAsStringClear = MessageHelper.emailArrayToStringClear(this.from); - - this.toAsString = MessageHelper.emailArrayToString(this.to, true); - this.toAsStringClear = MessageHelper.emailArrayToStringClear(this.to); - - this.flagged(false); - this.selected(false); - - this.populateSenderEmail(); - - bResult = true; - } - - return bResult; -}; - -MessageSimpleModel.prototype.populateSenderEmail = function(bDraftOrSentFolder) -{ - this.senderAsString = this.fromAsString; - this.senderAsStringClear = this.fromAsStringClear; - - if (bDraftOrSentFolder) - { - this.senderAsString = this.toAsString; - this.senderAsStringClear = this.toAsStringClear; - } -}; - -/** - * @returns {Array} - */ -MessageSimpleModel.prototype.threads = function() -{ - return []; -}; - -/** - * @static - * @param {Object} oJson - * @returns {?MessageSimpleModel} - */ -MessageSimpleModel.newInstanceFromJson = function(oJson) -{ - var oItem = oJson ? new MessageSimpleModel() : null; - return oItem && oItem.initByJson(oJson) ? oItem : null; -}; - -module.exports = MessageSimpleModel; diff --git a/dev/Model/OpenPgpKey.js b/dev/Model/OpenPgpKey.js deleted file mode 100644 index 99743dd2e..000000000 --- a/dev/Model/OpenPgpKey.js +++ /dev/null @@ -1,103 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Utils = require('Common/Utils'), - - PgpStore = require('Stores/User/Pgp'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - * @param {string} iIndex - * @param {string} sGuID - * @param {string} sID - * @param {array} aIDs - * @param {array} aUserIDs - * @param {array} aEmails - * @param {boolean} bIsPrivate - * @param {string} sArmor - * @param {string} sUserID - */ -function OpenPgpKeyModel(iIndex, sGuID, sID, aIDs, aUserIDs, aEmails, bIsPrivate, sArmor, sUserID) -{ - AbstractModel.call(this, 'OpenPgpKeyModel'); - - this.index = iIndex; - this.id = sID; - this.ids = Utils.isNonEmptyArray(aIDs) ? aIDs : [sID]; - this.guid = sGuID; - this.users = aUserIDs; - this.emails = aEmails; - this.armor = sArmor; - this.isPrivate = !!bIsPrivate; - - this.selectUser(sUserID); - - this.deleteAccess = ko.observable(false); -} - -_.extend(OpenPgpKeyModel.prototype, AbstractModel.prototype); - -OpenPgpKeyModel.prototype.index = 0; -OpenPgpKeyModel.prototype.id = ''; -OpenPgpKeyModel.prototype.ids = []; -OpenPgpKeyModel.prototype.guid = ''; -OpenPgpKeyModel.prototype.user = ''; -OpenPgpKeyModel.prototype.users = []; -OpenPgpKeyModel.prototype.email = ''; -OpenPgpKeyModel.prototype.emails = []; -OpenPgpKeyModel.prototype.armor = ''; -OpenPgpKeyModel.prototype.isPrivate = false; - -OpenPgpKeyModel.prototype.getNativeKey = function() -{ - var oKey = null; - try - { - oKey = PgpStore.openpgp.key.readArmored(this.armor); - if (oKey && !oKey.err && oKey.keys && oKey.keys[0]) - { - return oKey; - } - } - catch (e) - { - Utils.log(e); - } - - return null; -}; - -OpenPgpKeyModel.prototype.getNativeKeys = function() -{ - var oKey = this.getNativeKey(); - return oKey && oKey.keys ? oKey.keys : null; -}; - -OpenPgpKeyModel.prototype.select = function(sPattern, sProperty) -{ - if (this[sProperty]) - { - var index = this[sProperty].indexOf(sPattern); - if (-1 !== index) - { - this.user = this.users[index]; - this.email = this.emails[index]; - } - } -}; - -OpenPgpKeyModel.prototype.selectUser = function(sUser) -{ - this.select(sUser, 'users'); -}; - -OpenPgpKeyModel.prototype.selectEmail = function(sEmail) -{ - this.select(sEmail, 'emails'); -}; - -module.exports = OpenPgpKeyModel; diff --git a/dev/Model/OpenPgpKey.jsx b/dev/Model/OpenPgpKey.jsx new file mode 100644 index 000000000..b78cb3397 --- /dev/null +++ b/dev/Model/OpenPgpKey.jsx @@ -0,0 +1,87 @@ + +import ko from 'ko'; + +import {isNonEmptyArray, log} from 'Common/Utils'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +import PgpStore from 'Stores/User/Pgp'; + +class OpenPgpKeyModel extends AbstractModel +{ + /** + * @param {string} index + * @param {string} guID + * @param {string} ID + * @param {array} IDs + * @param {array} userIDs + * @param {array} emails + * @param {boolean} isPrivate + * @param {string} armor + * @param {string} userID + */ + constructor(index, guID, ID, IDs, userIDs, emails, isPrivate, armor, userID) + { + super('OpenPgpKeyModel'); + + this.index = index; + this.id = ID; + this.ids = isNonEmptyArray(IDs) ? IDs : [ID]; + this.guid = guID; + this.user = ''; + this.users = userIDs; + this.email = ''; + this.emails = emails; + this.armor = armor; + this.isPrivate = !!isPrivate; + + this.selectUser(userID); + + this.deleteAccess = ko.observable(false); + } + + getNativeKey() { + let key = null; + try + { + key = PgpStore.openpgp.key.readArmored(this.armor); + if (key && !key.err && key.keys && key.keys[0]) + { + return key; + } + } + catch (e) + { + log(e); + } + + return null; + } + + getNativeKeys() { + const key = this.getNativeKey(); + return key && key.keys ? key.keys : null; + } + + select(pattern, property) { + if (this[property]) + { + const index = this[property].indexOf(pattern); + if (-1 !== index) + { + this.user = this.users[index]; + this.email = this.emails[index]; + } + } + } + + selectUser(user) { + this.select(user, 'users'); + } + + selectEmail(email) { + this.select(email, 'emails'); + } +} + +export {OpenPgpKeyModel, OpenPgpKeyModel as default}; diff --git a/dev/Model/Template.js b/dev/Model/Template.js deleted file mode 100644 index aed1ac363..000000000 --- a/dev/Model/Template.js +++ /dev/null @@ -1,69 +0,0 @@ - -var - _ = require('_'), - ko = require('ko'), - - Utils = require('Common/Utils'), - - AbstractModel = require('Knoin/AbstractModel'); - -/** - * @constructor - * @param {string} sID - * @param {string} sName - * @param {string} sBody - */ -function TemplateModel(sID, sName, sBody) -{ - AbstractModel.call(this, 'TemplateModel'); - - this.id = sID; - this.name = sName; - this.body = sBody; - this.populated = true; - - this.deleteAccess = ko.observable(false); -} - -_.extend(TemplateModel.prototype, AbstractModel.prototype); - -/** - * @type {string} - */ -TemplateModel.prototype.id = ''; - -/** - * @type {string} - */ -TemplateModel.prototype.name = ''; - -/** - * @type {string} - */ -TemplateModel.prototype.body = ''; - -/** - * @type {boolean} - */ -TemplateModel.prototype.populated = true; - -/** - * @type {boolean} - */ -TemplateModel.prototype.parse = function(oItem) -{ - var bResult = false; - if (oItem && 'Object/Template' === oItem['@Object']) - { - this.id = Utils.pString(oItem.ID); - this.name = Utils.pString(oItem.Name); - this.body = Utils.pString(oItem.Body); - this.populated = !!oItem.Populated; - - bResult = true; - } - - return bResult; -}; - -module.exports = TemplateModel; diff --git a/dev/Model/Template.jsx b/dev/Model/Template.jsx new file mode 100644 index 000000000..6a3f06be8 --- /dev/null +++ b/dev/Model/Template.jsx @@ -0,0 +1,46 @@ + +import ko from 'ko'; + +import {pString} from 'Common/Utils'; + +import {AbstractModel} from 'Knoin/AbstractModel'; + +class TemplateModel extends AbstractModel +{ + /** + * @param {string} id + * @param {string} name + * @param {string} body + */ + constructor(id, name, body) + { + super('TemplateModel'); + + this.id = id; + this.name = name; + this.body = body; + this.populated = true; + + this.deleteAccess = ko.observable(false); + } + + /** + * @returns {boolean} + */ + parse(json) { + let result = false; + if (json && 'Object/Template' === json['@Object']) + { + this.id = pString(json.ID); + this.name = pString(json.Name); + this.body = pString(json.Body); + this.populated = !!json.Populated; + + result = true; + } + + return result; + } +} + +export {TemplateModel, TemplateModel as default}; diff --git a/dev/Promises/User/Populator.js b/dev/Promises/User/Populator.js index b7d96416a..787e5cdc1 100644 --- a/dev/Promises/User/Populator.js +++ b/dev/Promises/User/Populator.js @@ -13,7 +13,7 @@ var Settings = require('Storage/Settings'), Local = require('Storage/Client'), - FolderModel = require('Model/Folder'), + FolderModel = require('Model/Folder').default, AbstractBasicPromises = require('Promises/AbstractBasic'); diff --git a/dev/Settings/User/Filters.js b/dev/Settings/User/Filters.js index cfec066d1..74f945393 100644 --- a/dev/Settings/User/Filters.js +++ b/dev/Settings/User/Filters.js @@ -118,7 +118,7 @@ FiltersUserSettings.prototype.updateList = function() { var self = this, - FilterModel = require('Model/Filter'); + FilterModel = require('Model/Filter').default; if (!this.filters.loading()) { @@ -176,7 +176,7 @@ FiltersUserSettings.prototype.addFilter = function() { var self = this, - FilterModel = require('Model/Filter'), + FilterModel = require('Model/Filter').default, oNew = new FilterModel(); oNew.generateID(); diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js index e95e4851f..ecf8d491b 100644 --- a/dev/Stores/User/Message.js +++ b/dev/Stores/User/Message.js @@ -23,8 +23,8 @@ var Remote = require('Remote/User/Ajax'), - MessageModel = require('Model/Message'), - MessageHelper = require('Helper/Message').default; + MessageModel = require('Model/Message').default, + MessageHelper = require('Helper/Message'); /** * @constructor diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index bb15b17f5..491174b7d 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -32,7 +32,7 @@ var Settings = require('Storage/Settings'), Remote = require('Remote/User/Ajax'), - ComposeAttachmentModel = require('Model/ComposeAttachment'), + ComposeAttachmentModel = require('Model/ComposeAttachment').default, kn = require('Knoin/Knoin'), AbstractView = require('Knoin/AbstractView'); diff --git a/dev/View/Popup/ComposeOpenPgp.js b/dev/View/Popup/ComposeOpenPgp.js index 4a3fcd7bd..cb090f600 100644 --- a/dev/View/Popup/ComposeOpenPgp.js +++ b/dev/View/Popup/ComposeOpenPgp.js @@ -11,7 +11,7 @@ var PgpStore = require('Stores/User/Pgp'), - EmailModel = require('Model/Email'), + EmailModel = require('Model/Email').default, kn = require('Knoin/Knoin'), AbstractView = require('Knoin/AbstractView'); diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js index e4f733e6a..020013542 100644 --- a/dev/View/Popup/Contacts.js +++ b/dev/View/Popup/Contacts.js @@ -21,9 +21,9 @@ var Remote = require('Remote/User/Ajax'), - EmailModel = require('Model/Email'), - ContactModel = require('Model/Contact'), - ContactPropertyModel = require('Model/ContactProperty'), + EmailModel = require('Model/Email').default, + ContactModel = require('Model/Contact').default, + ContactPropertyModel = require('Model/ContactProperty').default, kn = require('Knoin/Knoin'), AbstractView = require('Knoin/AbstractView'); diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index 83a205507..9d60d3715 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -558,7 +558,7 @@ MessageViewMailBoxUserView.prototype.checkHeaderHeight = function() // var // sResult = '', // aTo = [], -// EmailModel = require('Model/Email'), +// EmailModel = require('Model/Email').default, // fParseEmailLine = function(sLine) { // return sLine ? _.compact(_.map([window.decodeURIComponent(sLine)], function(sItem) { // var oEmailModel = new EmailModel(); diff --git a/dev/bootstrap.jsx b/dev/bootstrap.jsx index 501e1cd1c..6a598d17d 100644 --- a/dev/bootstrap.jsx +++ b/dev/bootstrap.jsx @@ -6,7 +6,7 @@ import {$win, $html, data as GlobalsData, bMobileDevice} from 'Common/Globals'; import * as Enums from 'Common/Enums'; import * as Plugins from 'Common/Plugins'; import {i18n} from 'Common/Translator'; -import EmailModel from 'Model/Email'; +import {EmailModel} from 'Model/Email'; export default (App) => {