PreRelease 1.8.3

This commit is contained in:
RainLoop Team 2015-04-13 22:45:09 +04:00
parent 39566292af
commit 0ea982671b
40 changed files with 712 additions and 370 deletions

View file

@ -73,7 +73,7 @@
}, 50));
// TODO
// DEBUG
// Events.sub({
// 'window.resize': function () {
// window.console.log('window.resize');

View file

@ -211,7 +211,7 @@
/**
* @param {Function} fResultFunc
* @returns {boolean}
* @return {boolean}
*/
AppUser.prototype.contactsSync = function (fResultFunc)
{

View file

@ -20,58 +20,90 @@
{
var self = this;
this.obj = this.createNewObject();
this.objForNotification = this.createNewObject();
// this.userMedia = window.navigator.getUserMedia || window.navigator.webkitGetUserMedia ||
// window.navigator.mozGetUserMedia || window.navigator.msGetUserMedia;
//
// this.audioContext = window.AudioContext || window.webkitAudioContext;
// if (!this.audioContext || !window.Float32Array)
// {
// this.audioContext = null;
// this.userMedia = null;
// }
this.supported = !Globals.bMobileDevice && !Globals.bSafari &&
this.obj && '' !== this.obj.canPlayType('audio/mpeg');
this.player = this.createNewObject();
if (this.obj && this.supported)
this.supported = !Globals.bMobileDevice && !Globals.bSafari && !!this.player && !!this.player.play;
if (this.supported && this.player.canPlayType)
{
this.objForNotification.src = Links.sound('new-mail.mp3');
this.supportedMp3 = '' !== this.player.canPlayType('audio/mpeg;').replace(/no/, '');
this.supportedWav = '' !== this.player.canPlayType('audio/wav; codecs="1"').replace(/no/, '');
this.supportedOgg = '' !== this.player.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, '');
this.supportedNotification = this.supported && this.supportedMp3;
}
$(this.obj).on('ended error', function () {
if (!this.player || (!this.supportedMp3 && !this.supportedOgg && !this.supportedWav))
{
this.supported = false;
this.supportedMp3 = false;
this.supportedOgg = false;
this.supportedWav = false;
this.supportedNotification = false;
}
if (this.supported)
{
$(this.player).on('ended error', function () {
self.stop();
});
Events.sub('audio.api.stop', function () {
self.stop();
});
Events.sub('audio.api.play', function (sUrl, sName) {
self.playMp3(sUrl, sName);
});
}
}
Audio.prototype.obj = null;
Audio.prototype.objForNotification = null;
Audio.prototype.player = null;
Audio.prototype.notificator = null;
Audio.prototype.supported = false;
Audio.prototype.supportedMp3 = false;
Audio.prototype.supportedOgg = false;
Audio.prototype.supportedWav = false;
Audio.prototype.supportedNotification = false;
// Audio.prototype.record = function ()
// {
// this.getUserMedia({audio:true}, function () {
// window.console.log(arguments);
// }, function(oError) {
// window.console.log(arguments);
// });
// };
Audio.prototype.createNewObject = function ()
{
var obj = window.Audio ? new window.Audio() : null;
if (obj && obj.canPlayType)
var player = window.Audio ? new window.Audio() : null;
if (player && player.canPlayType && player.pause && player.play)
{
obj.preload = 'none';
obj.loop = false;
obj.autoplay = false;
obj.muted = false;
player.preload = 'none';
player.loop = false;
player.autoplay = false;
player.muted = false;
}
return obj;
return player;
};
Audio.prototype.paused = function ()
{
return this.supported ? !!this.obj.paused : true;
return this.supported ? !!this.player.paused : true;
};
Audio.prototype.stop = function ()
{
if (this.supported && this.obj.pause)
if (this.supported && this.player.pause)
{
this.obj.pause();
this.player.pause();
}
Events.pub('audio.stop');
@ -79,33 +111,73 @@
Audio.prototype.pause = Audio.prototype.stop;
Audio.prototype.clearName = function (sName, sExt)
{
sExt = sExt || '';
sName = Utils.isUnd(sName) ? '' : Utils.trim(sName);
if (sExt && '.' + sExt === sName.toLowerCase().substr((sExt.length + 1) * -1))
{
sName = Utils.trim(sName.substr(0, sName.length - 4));
}
if ('' === sName)
{
sName = 'audio';
}
return sName;
};
Audio.prototype.playMp3 = function (sUrl, sName)
{
if (this.supported && this.obj.play)
if (this.supported && this.supportedMp3)
{
this.obj.src = sUrl;
this.obj.play();
this.player.src = sUrl;
this.player.play();
sName = Utils.isUnd(sName) ? '' : Utils.trim(sName);
if ('.mp3' === sName.toLowerCase().substr(-4))
{
sName = Utils.trim(sName.substr(0, sName.length - 4));
}
Events.pub('audio.start', [this.clearName(sName, 'mp3'), 'mp3']);
}
};
if ('' === sName)
{
sName = 'audio';
}
Audio.prototype.playOgg = function (sUrl, sName)
{
if (this.supported && this.supportedOgg)
{
this.player.src = sUrl;
this.player.play();
Events.pub('audio.start', [sName]);
sName = this.clearName(sName, 'oga');
sName = this.clearName(sName, 'ogg');
Events.pub('audio.start', [sName, 'ogg']);
}
};
Audio.prototype.playWav = function (sUrl, sName)
{
if (this.supported && this.supportedWav)
{
this.player.src = sUrl;
this.player.play();
Events.pub('audio.start', [this.clearName(sName, 'wav'), 'wav']);
}
};
Audio.prototype.playNotification = function ()
{
if (this.supported && this.objForNotification.play)
if (this.supported && this.supportedMp3)
{
this.objForNotification.play();
if (!this.notificator)
{
this.notificator = this.createNewObject();
this.notificator.src = Links.sound('new-mail.mp3');
}
if (this.notificator && this.notificator.play)
{
this.notificator.play();
}
}
};

View file

@ -5,6 +5,26 @@
var Enums = {};
/**
* @enum {string}
*/
Enums.FileType = {
'Unknown': 'unknown',
'Text': 'text',
'Html': 'html',
'Code': 'code',
'Eml': 'eml',
'WordText': 'word-text',
'Pdf': 'pdf',
'Image': 'image',
'Audio': 'audio',
'Video': 'video',
'Sheet': 'sheet',
'Presentation': 'presentation',
'Certificate': 'certificate',
'Archive': 'archive'
};
/**
* @enum {string}
*/

View file

@ -18,6 +18,7 @@
Globals.$win = $(window);
Globals.$doc = $(window.document);
Globals.$html = $('html');
Globals.$body = $('body');
Globals.$div = $('<div></div>');
Globals.$win.__sizes = [0, 0];
@ -268,7 +269,7 @@
});
Globals.keyScopeReal.subscribe(function (sValue) {
// window.console.log('keyScope=' + sValue); // TODO
// window.console.log('keyScope=' + sValue); // DEBUG
key.setScope(sValue);
});

View file

@ -31,6 +31,9 @@
this.resize = _.throttle(_.bind(this.resize, this), 100);
this.__inited = false;
this.__initedData = null;
this.init();
}
@ -190,7 +193,7 @@
HtmlEditor.prototype.setHtml = function (sHtml, bFocus)
{
if (this.editor)
if (this.editor && this.__inited)
{
this.modeToggle(true);
@ -203,11 +206,15 @@
this.focus();
}
}
else
{
this.__initedData = [true, sHtml, bFocus];
}
};
HtmlEditor.prototype.setPlain = function (sPlain, bFocus)
{
if (this.editor)
if (this.editor && this.__inited)
{
this.modeToggle(false);
if ('plain' === this.editor.mode && this.editor.plugins.plain && this.editor.__plain)
@ -226,6 +233,10 @@
this.focus();
}
}
else
{
this.__initedData = [false, sPlain, bFocus];
}
};
HtmlEditor.prototype.init = function ()
@ -322,7 +333,20 @@
self.fOnReady();
self.__resizable = true;
self.__inited = true;
self.resize();
if (self.__initedData)
{
if (self.__initedData[0])
{
self.setHtml(self.__initedData[1], self.__initedData[2]);
}
else
{
self.setPlain(self.__initedData[1], self.__initedData[2]);
}
}
});
}
}

View file

@ -435,7 +435,7 @@
};
/**
* @returns {boolean}
* @return {boolean}
*/
Selector.prototype.autoSelect = function ()
{
@ -452,7 +452,7 @@
/**
* @param {Object} oItem
* @returns {string}
* @return {string}
*/
Selector.prototype.getItemUid = function (oItem)
{

View file

@ -144,7 +144,7 @@
/**
* @param {string} sMailToUrl
* @param {Function} PopupComposeVoreModel
* @returns {boolean}
* @return {boolean}
*/
Utils.mailToHelper = function (sMailToUrl, PopupComposeVoreModel)
{
@ -598,7 +598,7 @@
* @param {string} sTheme
* @return {string}
*/
Utils.convertThemeName = function (sTheme)
Utils.convertThemeName = _.memoize(function (sTheme)
{
if ('@custom' === sTheme.substr(-7))
{
@ -606,7 +606,7 @@
}
return Utils.trim(sTheme.replace(/[^a-zA-Z0-9]+/g, ' ').replace(/([A-Z])/g, ' $1').replace(/[\s]+/g, ' '));
};
});
/**
* @param {string} sName
@ -822,40 +822,6 @@
sText = '',
splitPlainText = function (sText)
{
var
iLen = 100,
sPrefix = '',
sSubText = '',
sResult = sText,
iSpacePos = 0,
iNewLinePos = 0
;
while (sResult.length > iLen)
{
sSubText = sResult.substring(0, iLen);
iSpacePos = sSubText.lastIndexOf(' ');
iNewLinePos = sSubText.lastIndexOf('\n');
if (-1 !== iNewLinePos)
{
iSpacePos = iNewLinePos;
}
if (-1 === iSpacePos)
{
iSpacePos = iLen;
}
sPrefix += sSubText.substring(0, iSpacePos) + '\n';
sResult = sResult.substring(iSpacePos + 1);
}
return sPrefix + sResult;
},
convertBlockquote = function (sText) {
sText = Utils.trim(sText);
sText = '> ' + sText.replace(/\n/gm, '\n> ');
@ -929,7 +895,7 @@
.replace(/&amp;/gi, '&')
;
sText = splitPlainText(Utils.trim(sText));
sText = Utils.splitPlainText(Utils.trim(sText));
iPos = 0;
iLimit = 800;

View file

@ -9,10 +9,21 @@
;
Opentip.styles.rainloop = {
'extends': 'standard',
'fixed': true,
'target': true,
'delay': 0.2,
'hideDelay': 0,
'hideEffect': 'fade',
'hideEffectDuration': 0.2,
'showEffect': 'fade',
'showEffectDuration': 0.2,
'showOn': 'mouseover click',
'removeElementsOnHide': true,
@ -26,8 +37,7 @@
Opentip.styles.rainloopTip = {
'extends': 'rainloop',
'stemLength': 3,
'stemBase': 5,
'delay': 0.4,
'group': 'rainloopTips'
};

27
dev/External/ko.js vendored
View file

@ -33,7 +33,7 @@
}
},
fUpdateKoValue = function () {
if (oEditor)
if (oEditor && oEditor.__inited)
{
fValue(oEditor.getDataWithHtmlMark());
}
@ -49,6 +49,7 @@
fValue.__updateEditorValue = fUpdateEditorValue;
fValue.subscribe(fUpdateEditorValue);
fUpdateEditorValue();
}
}
};
@ -61,6 +62,7 @@
sValue = '',
Translator = null,
$oEl = $(oElement),
fValue = fValueAccessor(),
bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'),
Globals = require('Common/Globals')
;
@ -68,7 +70,7 @@
if (!Globals.bMobileDevice || bMobile)
{
bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on');
sValue = ko.unwrap(fValueAccessor());
sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
oElement.__opentip = new Opentip(oElement, {
'style': 'rainloopTip',
@ -78,12 +80,21 @@
Globals.dropdownVisibility.subscribe(function (bV) {
if (bV) {
oElement.__opentip.deactivate();
} else {
oElement.__opentip.activate();
oElement.__opentip.hide();
}
});
if ('' === sValue)
{
oElement.__opentip.hide();
oElement.__opentip.deactivate();
oElement.__opentip.setContent('');
}
else
{
oElement.__opentip.activate();
}
if (bi18n)
{
Translator = require('Common/Translator');
@ -113,6 +124,7 @@
bi18n = true,
sValue = '',
$oEl = $(oElement),
fValue = fValueAccessor(),
bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'),
Globals = require('Common/Globals')
;
@ -120,7 +132,7 @@
if ((!Globals.bMobileDevice || bMobile) && oElement.__opentip)
{
bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on');
sValue = ko.unwrap(fValueAccessor());
sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
if (sValue)
{
@ -165,7 +177,8 @@
var
$oEl = $(oElement),
sValue = ko.unwrap(fValueAccessor()),
fValue = fValueAccessor(),
sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue),
oOpenTips = oElement.__opentip
;

View file

@ -8,6 +8,7 @@
_ = require('_'),
ko = require('ko'),
Enums = require('Common/Enums'),
Globals = require('Common/Globals'),
Utils = require('Common/Utils'),
Links = require('Common/Links'),
@ -27,6 +28,8 @@
this.mimeType = '';
this.fileName = '';
this.fileNameExt = '';
this.fileType = Enums.FileType.Unknown;
this.estimatedSize = 0;
this.friendlySize = '';
this.isInline = false;
@ -57,6 +60,8 @@
AttachmentModel.prototype.mimeType = '';
AttachmentModel.prototype.fileName = '';
AttachmentModel.prototype.fileType = '';
AttachmentModel.prototype.fileNameExt = '';
AttachmentModel.prototype.estimatedSize = 0;
AttachmentModel.prototype.friendlySize = '';
AttachmentModel.prototype.isInline = false;
@ -97,6 +102,9 @@
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;
}
@ -108,9 +116,7 @@
*/
AttachmentModel.prototype.isImage = function ()
{
return -1 < Utils.inArray(this.mimeType.toLowerCase(),
['image/png', 'image/jpg', 'image/jpeg', 'image/gif']
);
return Enums.FileType.Image === this.fileType;
};
/**
@ -118,7 +124,26 @@
*/
AttachmentModel.prototype.isMp3 = function ()
{
return Audio.supported && '.mp3' === this.fileName.toLowerCase().substr(-4);
return Enums.FileType.Audio === this.fileType &&
'mp3' === this.fileNameExt;
};
/**
* @return {boolean}
*/
AttachmentModel.prototype.isOgg = function ()
{
return Enums.FileType.Audio === this.fileType &&
('oga' === this.fileNameExt || 'ogg' === this.fileNameExt);
};
/**
* @return {boolean}
*/
AttachmentModel.prototype.isWav = function ()
{
return Enums.FileType.Audio === this.fileType &&
'wav' === this.fileNameExt;
};
/**
@ -134,8 +159,12 @@
*/
AttachmentModel.prototype.isText = function ()
{
return -1 < Utils.inArray(this.mimeType, ['application/pgp-signature', 'message/delivery-status', 'message/rfc822']) ||
('text/' === this.mimeType.substr(0, 5) && -1 === Utils.inArray(this.mimeType, ['text/html']));
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
;
};
/**
@ -143,7 +172,7 @@
*/
AttachmentModel.prototype.isPdf = function ()
{
return Globals.bAllowPdfPreview && 'application/pdf' === this.mimeType;
return Enums.FileType.Pdf === this.fileType;
};
/**
@ -152,7 +181,7 @@
AttachmentModel.prototype.isFramed = function ()
{
return this.framed && (Globals.__APP__ && Globals.__APP__.googlePreviewSupported()) &&
!this.isPdf() && !this.isText() && !this.isImage();
!(this.isPdf() && Globals.bAllowPdfPreview) && !this.isText() && !this.isImage();
};
/**
@ -160,7 +189,7 @@
*/
AttachmentModel.prototype.hasPreview = function ()
{
return this.isImage() || this.isPdf() || this.isText() || this.isFramed();
return this.isImage() || (this.isPdf() && Globals.bAllowPdfPreview) || this.isText() || this.isFramed();
};
/**
@ -168,7 +197,10 @@
*/
AttachmentModel.prototype.hasPreplay = function ()
{
return this.isMp3();
return (Audio.supportedMp3 && this.isMp3()) ||
(Audio.supportedOgg && this.isOgg()) ||
(Audio.supportedWav && this.isWav())
;
};
/**
@ -229,7 +261,7 @@
switch (true)
{
case this.isImage():
case this.isPdf():
case this.isPdf() && Globals.bAllowPdfPreview:
sResult = this.linkPreview();
break;
case this.isText():
@ -274,76 +306,85 @@
};
/**
* @param {string} sExt
* @param {string} sMimeType
* @returns {string}
* @return {string}
*/
AttachmentModel.staticIconClassHelper = function (sMimeType)
AttachmentModel.staticFileType = _.memoize(function (sExt, sMimeType)
{
sExt = Utils.trim(sExt).toLowerCase();
sMimeType = Utils.trim(sMimeType).toLowerCase();
var
sText = '',
sClass = 'icon-file',
aParts = sMimeType.split('/')
sResult = Enums.FileType.Unknown,
aMimeTypeParts = sMimeType.split('/')
;
if (aParts && aParts[1])
switch (true)
{
if ('image' === aParts[0])
{
sClass = 'icon-file-image';
}
else if ('text' === aParts[0])
{
sClass = 'icon-file-text';
}
else if ('audio' === aParts[0])
{
sClass = 'icon-file-music';
}
else if ('video' === aParts[0])
{
sClass = 'icon-file-movie';
}
else if (-1 < Utils.inArray(aParts[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']))
{
sClass = 'icon-file-zip';
}
else if (-1 < Utils.inArray(aParts[1],
['pdf', 'x-pdf']))
{
sText = 'pdf';
sClass = 'icon-none';
}
// else if (-1 < Utils.inArray(aParts[1], [
// 'exe', 'x-exe', 'x-winexe', 'bat'
// ]))
// {
// sClass = 'icon-console';
// }
else if (-1 < Utils.inArray(sMimeType, [
'application/pgp-signature', 'application/pkcs7-signature'
]))
{
sClass = 'icon-file-certificate';
}
else if (-1 < Utils.inArray(sMimeType, [
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'
]))
{
sClass = 'icon-file-text';
}
else if (-1 < Utils.inArray(aParts[1], [
]):
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/pkcs7-signature', 'application/pgp-keys'
]) || -1 < Utils.inArray(sExt, [
'asc', 'pem', 'ppk'
]):
sResult = Enums.FileType.Certificate;
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'
]))
{
sClass = 'icon-file-text';
}
else if (-1 < Utils.inArray(aParts[1], [
]):
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',
@ -351,11 +392,10 @@
'vnd.ms-excel.template.macroEnabled.12',
'vnd.ms-excel.addin.macroEnabled.12',
'vnd.ms-excel.sheet.binary.macroEnabled.12'
]))
{
sClass = 'icon-file-excel';
}
else if (-1 < Utils.inArray(aParts[1], [
]):
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',
@ -364,29 +404,140 @@
'vnd.ms-powerpoint.presentation.macroEnabled.12',
'vnd.ms-powerpoint.template.macroEnabled.12',
'vnd.ms-powerpoint.slideshow.macroEnabled.12'
]))
{
]):
sResult = Enums.FileType.Presentation;
break;
}
return sResult;
});
/**
* @param {string} sFileType
* @return {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:
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;
}
return [sClass, sText];
});
/**
* @param {string} sFileType
* @return {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:
sClass = 'icon-file-certificate';
break;
case Enums.FileType.Sheet:
sClass = 'icon-file-excel';
break;
case Enums.FileType.Presentation:
sClass = 'icon-file-chart-graph';
break;
}
}
}
return sClass;
};
/**
* @returns {string}
* @return {string}
*/
AttachmentModel.prototype.iconClass = function ()
{
return AttachmentModel.staticIconClassHelper(this.mimeType)[0];
return AttachmentModel.staticIconClass(this.fileType)[0];
};
/**
* @returns {string}
* @return {string}
*/
AttachmentModel.prototype.iconText = function ()
{
return AttachmentModel.staticIconClassHelper(this.mimeType)[1];
return AttachmentModel.staticIconClass(this.fileType)[1];
};
module.exports = AttachmentModel;

View file

@ -70,7 +70,11 @@
return Utils.mimeContentType(this.fileName());
}, this);
this.regDisposables([this.friendlySize]);
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);
@ -108,7 +112,8 @@
*/
ComposeAttachmentModel.prototype.iconClass = function ()
{
return AttachmentModel.staticIconClassHelper(this.mimeType())[0];
return AttachmentModel.staticIconClass(
AttachmentModel.staticFileType(this.fileExt(), this.mimeType()))[0];
};
/**
@ -116,7 +121,8 @@
*/
ComposeAttachmentModel.prototype.iconText = function ()
{
return AttachmentModel.staticIconClassHelper(this.mimeType())[1];
return AttachmentModel.staticIconClass(
AttachmentModel.staticFileType(this.fileExt(), this.mimeType()))[1];
};
module.exports = ComposeAttachmentModel;

View file

@ -66,7 +66,7 @@
};
/**
* @returns {boolean}
* @return {boolean}
*/
EmailModel.prototype.validate = function ()
{

View file

@ -74,30 +74,11 @@
this.selected = ko.observable(false);
this.checked = ko.observable(false);
this.hasAttachments = ko.observable(false);
this.attachmentsMainType = ko.observable('');
this.attachmentsSpecData = ko.observableArray([]);
this.attachmentIconClass = ko.computed(function () {
var sClass = '';
if (this.hasAttachments())
{
sClass = 'icon-attachment';
switch (this.attachmentsMainType())
{
case 'image':
sClass = 'icon-image';
break;
case 'archive':
sClass = 'icon-file-zip';
break;
case 'doc':
sClass = 'icon-file-text';
break;
case 'certificate':
sClass = 'icon-file-certificate';
break;
}
}
return sClass;
return AttachmentModel.staticCombinedIconClass(
this.hasAttachments() ? this.attachmentsSpecData() : []);
}, this);
this.body = null;
@ -193,7 +174,7 @@
this.selected(false);
this.checked(false);
this.hasAttachments(false);
this.attachmentsMainType('');
this.attachmentsSpecData([]);
this.body = null;
this.isHtml(false);
@ -287,7 +268,8 @@
this.dateTimeStampInUTC(Utils.pInt(oJsonMessage.DateTimeStampInUTC));
this.hasAttachments(!!oJsonMessage.HasAttachments);
this.attachmentsMainType(oJsonMessage.AttachmentsMainType);
this.attachmentsSpecData(Utils.isArray(oJsonMessage.AttachmentsSpecData) ?
oJsonMessage.AttachmentsSpecData : []);
this.fromEmailString(MessageHelper.emailArrayToString(this.from, true));
this.fromClearEmailString(MessageHelper.emailArrayToStringClear(this.from));
@ -337,7 +319,8 @@
}
this.hasAttachments(!!oJsonMessage.HasAttachments);
this.attachmentsMainType(oJsonMessage.AttachmentsMainType);
this.attachmentsSpecData(Utils.isArray(oJsonMessage.AttachmentsSpecData) ?
oJsonMessage.AttachmentsSpecData : []);
this.foundedCIDs = Utils.isArray(oJsonMessage.FoundedCIDs) ? oJsonMessage.FoundedCIDs : [];
this.attachments(this.initAttachmentsFromJson(oJsonMessage.Attachments));
@ -524,15 +507,6 @@
if (this.hasAttachments())
{
aResult.push('withAttachments');
switch (this.attachmentsMainType())
{
case 'image':
aResult.push('imageOnlyAttachments');
break;
case 'archive':
aResult.push('archiveOnlyAttachments');
break;
}
}
if (this.newForAnimation())
{
@ -797,7 +771,7 @@
};
/**
* @returns {string}
* @return {string}
*/
MessageModel.prototype.generateUid = function ()
{
@ -850,7 +824,7 @@
this.selected(oMessage.selected());
this.checked(oMessage.checked());
this.hasAttachments(oMessage.hasAttachments());
this.attachmentsMainType(oMessage.attachmentsMainType());
this.attachmentsSpecData(oMessage.attachmentsSpecData());
this.body = null;

View file

@ -29,8 +29,6 @@
MessageFullModel.prototype.requestHash = '';
MessageFullModel.prototype.proxy = false;
MessageFullModel.prototype.hasAttachments = false;
MessageFullModel.prototype.attachmentsMainType = '';
MessageFullModel.prototype.attachmentsClass = '';
MessageFullModel.prototype.clear = function ()
{
@ -43,37 +41,6 @@
this.proxy = false;
this.hasAttachments = false;
this.attachmentsMainType = '';
this.attachmentsClass = '';
};
/**
* @return {string}
*/
MessageFullModel.prototype.getAttachmentsClass = function ()
{
var sClass = '';
if (this.hasAttachments)
{
sClass = 'icon-attachment';
switch (this.attachmentsMainType)
{
case 'image':
sClass = 'icon-image';
break;
case 'archive':
sClass = 'icon-file-zip';
break;
case 'doc':
sClass = 'icon-file-text';
break;
case 'certificate':
sClass = 'icon-file-certificate';
break;
}
}
return sClass;
};
/**
@ -98,8 +65,6 @@
this.proxy = !!oJson.ExternalProxy;
this.hasAttachments = !!oJson.HasAttachments;
this.attachmentsMainType = Utils.pString(oJson.AttachmentsMainType);
this.attachmentsClass = this.getAttachmentsClass();
bResult = true;
}

View file

@ -112,6 +112,14 @@
});
};
UserAjaxUserPromises.prototype.attachmentsActions = function (sAction, aHashes, fTrigger)
{
return this.postRequest('AttachmentsActions', fTrigger, {
'Action': sAction,
'Hashes': aHashes
});
};
UserAjaxUserPromises.prototype.welcomeClose = function ()
{
return this.postRequest('WelcomeClose');

View file

@ -57,7 +57,7 @@
};
/**
* @returns {boolean}
* @return {boolean}
*/
LicensingAdminSettings.prototype.licenseIsUnlim = function ()
{
@ -65,7 +65,7 @@
};
/**
* @returns {string}
* @return {string}
*/
LicensingAdminSettings.prototype.licenseExpiredMomentValue = function ()
{

View file

@ -59,7 +59,7 @@
};
/**
* @returns {boolean}
* @return {boolean}
*/
AccountUserStore.prototype.isRootAccount = function ()
{

View file

@ -182,7 +182,7 @@
/**
* @param {boolean=} bBoot = false
* @returns {Array}
* @return {Array}
*/
FolderUserStore.prototype.getNextFolderNames = function (bBoot)
{

View file

@ -714,7 +714,7 @@
/**
* @param {Array} aList
* @returns {string}
* @return {string}
*/
MessageUserStore.prototype.calculateMessageListHash = function (aList)
{

View file

@ -142,7 +142,7 @@
NotificationUserStore.prototype.initNotificationPlayer = function ()
{
if (Audio && Audio.supported)
if (Audio && Audio.supportedNotification)
{
this.soundNotificationIsSupported(true);
}
@ -155,7 +155,7 @@
NotificationUserStore.prototype.playSoundNotification = function (bSkipSetting)
{
if (Audio && Audio.supported && (bSkipSetting ? true : this.enableSoundNotification()))
if (Audio && Audio.supportedNotification && (bSkipSetting ? true : this.enableSoundNotification()))
{
Audio.playNotification();
}

View file

@ -72,7 +72,7 @@
/**
* @param {string} sEmail
* @param {string=} sPassword
* @returns {?}
* @return {?}
*/
PgpUserStore.prototype.findPrivateKeyByEmail = function (sEmail, sPassword)
{
@ -109,7 +109,7 @@
/**
* @param {string=} sPassword
* @returns {?}
* @return {?}
*/
PgpUserStore.prototype.findSelfPrivateKey = function (sPassword)
{

View file

@ -21,6 +21,15 @@
0% {background-position: 0 0;} 100% {background-position: 60px 0;}
}
@keyframes login-form-shake {
0% {transform: translateX(0);}
12.5% {transform: translateX(-6px) rotateY(-5deg)}
37.5% {transform: translateX(5px) rotateY(4deg)}
62.5% {transform: translateX(-3px) rotateY(-2deg)}
87.5% {transform: translateX(2px) rotateY(1deg)}
100% {transform: translateX(0)}
}
html.csstransitions.rl-started-trigger.no-mobile .b-login-content .loginFormWrapper {
/*transform: scale(1.1);*/
transform: translateY(-20px);
@ -56,6 +65,14 @@ html.csstransitions.rl-started-trigger.no-mobile .b-login-content .loginFormWrap
}
}
&.cssanimations.csstransitions.no-mobile .b-login-content .errorAnimated {
animation: login-form-shake 400ms ease-in-out;
}
&.cssanimations.csstransitions.no-mobile .b-login-content .afterLoginHide {
opacity: 0;
}
/* &.csstransitions.no-mobile #rl-content {
.transition(opacity 0.3s ease-out);
}*/

View file

@ -16,7 +16,7 @@
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04), 0 1px 5px rgba(0, 0, 0, 0.1);
border-radius: 2px;
border-radius: 3px;
&.waiting {
opacity: 0.6;
@ -120,6 +120,15 @@
color: #aaa;
}
.attachmentIcon {
&.icon-none {
display: none;
}
&.icon-file-certificate {
margin-left: 15px;
}
}
.attachmentIconText {
display: inline-block;
font-size: 28px;
@ -131,15 +140,13 @@
font-style: normal;
}
.attachmentIcon.icon-none {
display: none;
}
/*
.attachmentIconParent.hasPreview.isImage {
.iconMain {
display: none;
}
}
*/
.attachmentIconParent.hasPreview:hover {
.iconPreview {

View file

@ -9,6 +9,7 @@
display: inline-block;
vertical-align: middle;
text-align: center;
perspective: 500px;
.descWrapper {

View file

@ -322,7 +322,7 @@ html.rl-no-preview-pane {
&.e-single-line .attachmentParent {
float: left;
margin: 0 5px 0 0;
margin: 0 8px 0 0;
}
.senderParent {

View file

@ -230,4 +230,4 @@ html.cssanimations {
.command.command-disabled.hide-on-disabled-command {
display:none;
}
}

View file

@ -33,6 +33,7 @@
}
.opentip-container {
z-index: 2001 !important;
.ot-content {
font-size: 13px;
@ -41,4 +42,30 @@
&.style-rainloopErrorTip .ot-content {
color: red;
}
&.ot-show-effect-none, &.ot-hide-effect-none {
transition: none !important;
}
&.ot-show-effect-fade {
transition: none;
&.ot-hidden {
opacity: 0;
}
&.ot-going-to-show {
opacity: 0;
transition: opacity 0.2s ease-in-out;
}
&.ot-showing {
opacity: 1;
transition: opacity 0.2s ease-in-out;
}
&.ot-visible {
opacity: 1;
transition: none;
}
}
}

View file

@ -34,8 +34,17 @@
this.loginError = ko.observable(false);
this.passwordError = ko.observable(false);
this.loginErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
this.loginFocus = ko.observable(false);
this.formHidden = ko.observable(false);
this.formError = ko.computed(function () {
return this.loginErrorAnimation() || this.passwordErrorAnimation();
}, this);
this.login.subscribe(function () {
this.loginError(false);
}, this);
@ -44,6 +53,14 @@
this.passwordError(false);
}, this);
this.loginError.subscribe(function (bV) {
this.loginErrorAnimation(!!bV);
}, this);
this.passwordError.subscribe(function (bV) {
this.passwordErrorAnimation(!!bV);
}, this);
this.submitRequest = ko.observable(false);
this.submitError = ko.observable('');
@ -51,6 +68,9 @@
Utils.triggerAutocompleteInputChange();
this.loginError(false);
this.passwordError(false);
this.loginError('' === Utils.trim(this.login()));
this.passwordError('' === Utils.trim(this.password()));
@ -67,6 +87,7 @@
{
if (oData.Result)
{
this.formHidden(true);
require('App/Admin').loginAndLogoutReload(true);
}
else if (oData.ErrorCode)

View file

@ -137,7 +137,7 @@
};
/**
* @returns {boolean}
* @return {boolean}
*/
ActivatePopupView.prototype.validateSubscriptionKey = function ()
{

View file

@ -995,7 +995,7 @@
*
* @param {Array} aList
* @param {boolean} bFriendly
* @returns {string}
* @return {string}
*/
ComposePopupView.prototype.emailArrayToStringLineHelper = function (aList, bFriendly)
{

View file

@ -42,6 +42,7 @@
this.additionalCode = ko.observable('');
this.additionalCode.error = ko.observable(false);
this.additionalCode.errorAnimation = ko.observable(false).extend({'falseTimeout': 500});
this.additionalCode.focused = ko.observable(false);
this.additionalCode.visibility = ko.observable(false);
this.additionalCodeSignMe = ko.observable(false);
@ -56,6 +57,16 @@
this.emailError = ko.observable(false);
this.passwordError = ko.observable(false);
this.emailErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
this.formHidden = ko.observable(false);
this.formError = ko.computed(function () {
return this.emailErrorAnimation() || this.passwordErrorAnimation() ||
(this.additionalCode.visibility() && this.additionalCode.errorAnimation());
}, this);
this.emailFocus = ko.observable(false);
this.passwordFocus = ko.observable(false);
this.submitFocus = ko.observable(false);
@ -78,6 +89,18 @@
this.additionalCode.error(false);
}, this);
this.emailError.subscribe(function (bV) {
this.emailErrorAnimation(!!bV);
}, this);
this.passwordError.subscribe(function (bV) {
this.passwordErrorAnimation(!!bV);
}, this);
this.additionalCode.error.subscribe(function (bV) {
this.additionalCode.errorAnimation(!!bV);
}, this);
this.submitRequest = ko.observable(false);
this.submitError = ko.observable('');
this.submitErrorAddidional = ko.observable('');
@ -115,16 +138,34 @@
Utils.triggerAutocompleteInputChange();
this.emailError(false);
this.passwordError(false);
this.emailError('' === Utils.trim(this.email()));
this.passwordError('' === Utils.trim(this.password()));
if (this.additionalCode.visibility())
{
this.additionalCode.error(false);
this.additionalCode.error('' === Utils.trim(this.additionalCode()));
}
if (this.emailError() || this.passwordError() || this.additionalCode.error())
if (this.emailError() || this.passwordError() ||
(this.additionalCode.visibility() && this.additionalCode.error()))
{
switch (true)
{
case this.emailError():
this.emailFocus(true);
break;
case this.passwordError():
this.passwordFocus(true);
break;
case this.additionalCode.visibility() && this.additionalCode.error():
this.additionalCode.focused(true);
break;
}
return false;
}
@ -172,10 +213,12 @@
}
else if (oData.Admin)
{
this.formHidden(true);
require('App/User').redirectToAdminPanel();
}
else
{
this.formHidden(true);
require('App/User').loginAndLogoutReload(false);
}
}
@ -339,6 +382,8 @@
if (0 === iErrorCode)
{
self.submitRequest(true);
self.formHidden(true);
require('App/User').loginAndLogoutReload(false);
}
else

View file

@ -374,7 +374,7 @@
};
/**
* @returns {string}
* @return {string}
*/
MessageListMailBoxUserView.prototype.printableMessageCountForDeletion = function ()
{

View file

@ -82,6 +82,10 @@
this.allowAttachmnetControls = ko.observable(false);
this.showAttachmnetControls = ko.observable(false);
this.downloadAsZipLoading = ko.observable(false);
this.saveToOwnCloudLoading = ko.observable(false);
this.saveToDropboxLoading = ko.observable(false);
this.showAttachmnetControls.subscribe(function (bV) {
if (this.message())
{
@ -115,12 +119,6 @@
this.moreDropdownTrigger = ko.observable(false);
this.messageDomFocused = ko.observable(false).extend({'rateLimit': 0});
// TODO
// ko.computed(function () {
// window.console.log('focus:' + AppStore.focusedState() + ', dom:' +
// this.messageDomFocused() + ', key:' + Globals.keyScope() + ' ~ ' + Globals.keyScopeReal());
// }, this).extend({'throttle': 1});
this.messageVisibility = ko.computed(function () {
return !this.messageLoadingThrottle() && !!this.message();
}, this);
@ -759,9 +757,20 @@
}
var oAttachment = ko.dataFor(this);
if (oAttachment && oAttachment.isMp3() && Audio.supported)
if (oAttachment && Audio.supported)
{
Audio.playMp3(oAttachment.linkDownload(), oAttachment.fileName);
switch (true)
{
case Audio.supportedMp3 && oAttachment.isMp3():
Audio.playMp3(oAttachment.linkDownload(), oAttachment.fileName);
break;
case Audio.supportedOgg && oAttachment.isOgg():
Audio.playOgg(oAttachment.linkDownload(), oAttachment.fileName);
break;
case Audio.supportedWav && oAttachment.isWav():
Audio.playWav(oAttachment.linkDownload(), oAttachment.fileName);
break;
}
}
})
.on('click', '.thread-list .more-threads', function (e) {
@ -1107,6 +1116,40 @@
}
};
MessageViewMailBoxUserView.prototype.getAttachmentsHashes = function ()
{
return _.compact(_.map(this.message() ? this.message().attachments() : [], function (oItem) {
return oItem && oItem.checked() ? oItem.download : '';
}));
};
MessageViewMailBoxUserView.prototype.downloadAsZip = function ()
{
var aHashes = this.getAttachmentsHashes();
if (0 < aHashes.length)
{
Promises.attachmentsActions('Zip', aHashes, this.downloadAsZipLoading);
}
};
MessageViewMailBoxUserView.prototype.saveToOwnCloud = function ()
{
var aHashes = this.getAttachmentsHashes();
if (0 < aHashes.length)
{
Promises.attachmentsActions('OwnCloud', aHashes, this.saveToOwnCloudLoading);
}
};
MessageViewMailBoxUserView.prototype.saveToDropbox = function ()
{
var aHashes = this.getAttachmentsHashes();
if (0 < aHashes.length)
{
Promises.attachmentsActions('Dropbox', aHashes, this.saveToDropboxLoading);
}
};
/**
* @param {MessageModel} oMessage
*/
@ -1119,7 +1162,7 @@
};
/**
* @returns {string}
* @return {string}
*/
MessageViewMailBoxUserView.prototype.printableCheckedMessageCount = function ()
{

View file

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

View file

@ -58,62 +58,17 @@ class AttachmentCollection extends \MailSo\Base\Collection
}
/**
* @return int
* @return array
*/
public function ImageCount()
public function SpecData()
{
$aList = $this->FilterList(function ($oAttachment) {
return $oAttachment && $oAttachment->IsImage();
return $this->MapList(function ($oAttachment) {
if ($oAttachment)
{
return array($oAttachment->FileName(true), $oAttachment->MimeType());
}
return null;
});
return \is_array($aList) ? \count($aList) : 0;
}
/**
* @return int
*/
public function ArchiveCount()
{
$aList = $this->FilterList(function ($oAttachment) {
return $oAttachment && $oAttachment->IsArchive();
});
return \is_array($aList) ? \count($aList) : 0;
}
/**
* @return int
*/
public function PdfCount()
{
$aList = $this->FilterList(function ($oAttachment) {
return $oAttachment && $oAttachment->IsPdf();
});
return \is_array($aList) ? \count($aList) : 0;
}
/**
* @return int
*/
public function DocCount()
{
$aList = $this->FilterList(function ($oAttachment) {
return $oAttachment && $oAttachment->IsDoc();
});
return \is_array($aList) ? \count($aList) : 0;
}
/**
* @return int
*/
public function CertificateCount()
{
$aList = $this->FilterList(function ($oAttachment) {
return $oAttachment && $oAttachment->IsPgpSignature();
});
return \is_array($aList) ? \count($aList) : 0;
}
}

View file

@ -2630,6 +2630,17 @@ class Actions
return $this->FalseResponse(__FUNCTION__);
}
/**
* @return array
*
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoAttachmentsActions()
{
\sleep(1);
return $this->TrueResponse(__FUNCTION__);
}
/**
* @return array
*
@ -9079,28 +9090,7 @@ class Actions
$iAttachmentsCount = $oAttachments ? $oAttachments->Count() : 0;
$mResult['HasAttachments'] = 0 < $iAttachmentsCount;
$mResult['AttachmentsMainType'] = '';
if (0 < $iAttachmentsCount)
{
switch (true)
{
case $iAttachmentsCount === $oAttachments->ImageCount():
$mResult['AttachmentsMainType'] = 'image';
break;
case $iAttachmentsCount === $oAttachments->ArchiveCount():
$mResult['AttachmentsMainType'] = 'archive';
break;
case $iAttachmentsCount === $oAttachments->PdfCount():
$mResult['AttachmentsMainType'] = 'pdf';
break;
case $iAttachmentsCount === $oAttachments->DocCount():
$mResult['AttachmentsMainType'] = 'doc';
break;
case $iAttachmentsCount === $oAttachments->CertificateCount():
$mResult['AttachmentsMainType'] = 'certificate';
break;
}
}
$mResult['AttachmentsSpecData'] = $mResult['HasAttachments'] ? $oAttachments->SpecData() : array();
$sSubject = $mResult['Subject'];
$mResult['Hash'] = \md5($mResult['Folder'].$mResult['Uid']);

View file

@ -1,14 +1,16 @@
<div class="b-login-content">
<div class="loginFormWrapper">
<div class="loginFormWrapper" data-bind="css: {'afterLoginHide': formHidden}">
<center>
<div class="alert alertError" data-bind="visible: '' !== submitError()">
<button type="button" class="close" data-bind="click: function () { submitError('') }">&times;</button>
<span data-bind="text: submitError"></span>
</div>
<form class="wrapper loginForm thm-login" action="#/" data-bind="submit: submitForm">
<div class="controls" data-bind="css: {'error': loginError}">
<form class="wrapper loginForm thm-login" action="#/" data-bind="submit: submitForm, css: {'errorAnimated': formError}">
<div class="controls" data-bind="css: {'error': loginError, 'animated': loginErrorAnimation}">
<div class="input-append">
<input type="text" class="input-block-level inputLogin checkAutocomplete" name="RainLoopAdminLogin" id="RainLoopAdminLogin"
<input type="text" class="input-block-level inputLogin checkAutocomplete"
name="RainLoopAdminLogin" id="RainLoopAdminLogin"
style="padding-right: 35px;"
autocorrect="off" autocapitalize="off" spellcheck="false" data-i18n="[placeholder]LOGIN/LABEL_LOGIN"
data-bind="textInput: login, hasFocus: loginFocus" />
<span class="add-on">
@ -16,9 +18,11 @@
</span>
</div>
</div>
<div class="controls" data-bind="css: {'error': passwordError}">
<div class="controls" data-bind="css: {'error': passwordError, 'animated': passwordErrorAnimation}">
<div class="input-append">
<input type="password" class="input-block-level inputPassword checkAutocomplete" placeholder="Password" name="RainLoopAdminPassword" id="RainLoopAdminPassword"
<input type="password" class="input-block-level inputPassword checkAutocomplete"
placeholder="Password" name="RainLoopAdminPassword" id="RainLoopAdminPassword"
style="padding-right: 35px;"
autocorrect="off" autocapitalize="off" spellcheck="false" data-i18n="[placeholder]LOGIN/LABEL_PASSWORD"
data-bind="textInput: password" />
<span class="add-on">

View file

@ -1,5 +1,5 @@
<div class="b-login-content">
<div class="loginFormWrapper">
<div class="loginFormWrapper" data-bind="css: {'afterLoginHide': formHidden}">
<center>
{{INCLUDE/BeforeLogo/PLACE}}
<!-- ko if: logoImg -->
@ -19,12 +19,13 @@
<span data-bind="text: submitErrorAddidional"></span>
</div>
</div>
<form class="wrapper loginForm thm-login" action="#/" data-bind="submit: submitForm">
<form class="wrapper loginForm thm-login" action="#/" data-bind="submit: submitForm, css: {'errorAnimated': formError}">
{{INCLUDE/TopControlGroup/PLACE}}
<div class="controls" data-bind="css: {'error': emailError}">
<div class="controls" data-bind="css: {'error': emailError, 'animated': emailErrorAnimation}">
<div class="input-append">
<input type="email" class="i18n input-block-level inputEmail checkAutocomplete"
name="RainLoopEmail" id="RainLoopEmail"
style="padding-right: 35px;"
autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="textInput: email, hasFocus: emailFocus" data-i18n="[placeholder]LOGIN/LABEL_EMAIL" />
<span class="add-on">
@ -32,9 +33,11 @@
</span>
</div>
</div>
<div class="controls" data-bind="css: {'error': passwordError}">
<div class="controls" data-bind="css: {'error': passwordError, 'animated': passwordErrorAnimation}">
<div class="input-append">
<input type="password" class="i18n input-block-level inputPassword checkAutocomplete" name="RainLoopPassword" id="RainLoopPassword"
<input type="password" class="i18n input-block-level inputPassword checkAutocomplete"
name="RainLoopPassword" id="RainLoopPassword"
style="padding-right: 35px;"
autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="textInput: password, hasFocus: passwordFocus" data-i18n="[placeholder]LOGIN/LABEL_PASSWORD" />
<span class="add-on">
@ -42,9 +45,11 @@
</span>
</div>
</div>
<div class="controls" data-bind="visible: additionalCode.visibility(), css: {'error': additionalCode.error}">
<div class="controls" data-bind="visible: additionalCode.visibility(), css: {'error': additionalCode.error, 'animated': additionalCode.errorAnimation}">
<div class="input-append">
<input type="text" class="i18n input-block-level inputAdditionalCode" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
<input type="text" class="i18n input-block-level inputAdditionalCode"
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
style="padding-right: 35px;"
data-bind="textInput: additionalCode, hasFocus: additionalCode.focused" data-i18n="[placeholder]LOGIN/LABEL_VERIFICATION_CODE" />
<span class="add-on">
<i class="icon-key"></i>

View file

@ -430,14 +430,31 @@
<i class="icon-cog controls-handle" data-bind="visible: allowAttachmnetControls() && !showAttachmnetControls(), click: function () { showAttachmnetControls(true) }"></i>
</div>
<div class="attachmentsControls"
data-bind="visible: showAttachmnetControls() && message() && message().hasVisibleAttachments()">
<i class="icon-file-zip"></i>
data-bind="visible: showAttachmnetControls() && message() && message().hasVisibleAttachments()">
<i class="icon-file-zip"
data-bind="css: {'icon-file-zip': !downloadAsZipLoading(), 'icon-spinner animated': downloadAsZipLoading()}"></i>
&nbsp;&nbsp;
<span class="g-ui-link">Download as zip</span>
<span class="g-ui-link" data-bind="click: downloadAsZip">Download as zip</span>
&nbsp;&nbsp;&nbsp;&nbsp;
<i class="icon-cloud-up"></i>
<i class="icon-cloud-up"
data-bind="css: {'icon-cloud-up': !saveToOwnCloudLoading(), 'icon-spinner animated': saveToOwnCloudLoading()}"></i>
&nbsp;&nbsp;
<span class="g-ui-link">Save to ownCloud</span>
<span class="g-ui-link" data-bind="click: saveToOwnCloud">Save to ownCloud</span>
&nbsp;&nbsp;&nbsp;&nbsp;
<i class="icon-dropbox"
data-bind="css: {'icon-dropbox': !saveToDropboxLoading(), 'icon-spinner animated': saveToDropboxLoading()}"></i>
&nbsp;&nbsp;
<span class="g-ui-link" data-bind="click: saveToDropbox">Save to Dropbox</span>
<!-- // --->
<button type="button" class="close" style="margin-right: 5px;"
data-bind="click: function () { showAttachmnetControls(false); }">×</button>
</div>