mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Uploading and preparing the repository to the dev version.
Original unminified source code (dev folder - js, css, less) (fixes #6) Grunt build system Multiple identities correction (fixes #9) Compose html editor (fixes #12) New general settings - Loading Description New warning about default admin password Split general and login screen settings
This commit is contained in:
parent
afad45137e
commit
4cc2207513
846 changed files with 99453 additions and 2123 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
/.idea
|
||||||
|
/nbproject
|
||||||
|
/npm-debug.log
|
||||||
|
/node_modules
|
||||||
|
/build/dist
|
||||||
|
/build/tmp
|
||||||
|
/data
|
||||||
382
Gruntfile.js
Normal file
382
Gruntfile.js
Normal file
|
|
@ -0,0 +1,382 @@
|
||||||
|
|
||||||
|
/*jshint node: true */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = function(grunt) {
|
||||||
|
|
||||||
|
grunt.initConfig({
|
||||||
|
pkg: grunt.file.readJSON("package.json"),
|
||||||
|
less: {
|
||||||
|
development: {
|
||||||
|
files: {
|
||||||
|
"rainloop/v/<%= pkg.version %>/static/css/less.css": "dev/Styles/@Main.less"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
jshint: {
|
||||||
|
files: [
|
||||||
|
'Gruntfile.js',
|
||||||
|
'rainloop/v/<%= pkg.version %>/static/js/app.js',
|
||||||
|
'rainloop/v/<%= pkg.version %>/static/js/admin.js'
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
boss: true,
|
||||||
|
browser: true,
|
||||||
|
curly: true,
|
||||||
|
eqeqeq: true,
|
||||||
|
eqnull: true,
|
||||||
|
expr: true,
|
||||||
|
evil: true,
|
||||||
|
newcap: true,
|
||||||
|
noarg: true,
|
||||||
|
undef: true,
|
||||||
|
smarttabs: true,
|
||||||
|
sub: true,
|
||||||
|
globals: {
|
||||||
|
define: true,
|
||||||
|
window: true,
|
||||||
|
jQuery: true,
|
||||||
|
ko: true,
|
||||||
|
console: true,
|
||||||
|
moment: true,
|
||||||
|
crossroads: true,
|
||||||
|
hasher: true,
|
||||||
|
Jua: true,
|
||||||
|
_: true,
|
||||||
|
Dropbox: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uglify: {
|
||||||
|
options: {
|
||||||
|
compress: true,
|
||||||
|
mangle: true,
|
||||||
|
preserveComments: "some"
|
||||||
|
},
|
||||||
|
cookie: {
|
||||||
|
options: {
|
||||||
|
banner: "/*! jquery.cookie v1.4.0 (c) 2013 Klaus Hartl | MIT */\n",
|
||||||
|
preserveComments: "false"
|
||||||
|
},
|
||||||
|
src: "vendors/jquery-cookie/jquery.cookie.js",
|
||||||
|
dest: "vendors/jquery-cookie/jquery.cookie-1.4.0.min.js"
|
||||||
|
},
|
||||||
|
wakeup: {
|
||||||
|
options: {
|
||||||
|
banner: "/*! jQuery WakeUp plugin (c) 2013 Paul Okopny <paul.okopny@gmail.com> | MIT */\n",
|
||||||
|
preserveComments: "false"
|
||||||
|
},
|
||||||
|
src: "vendors/jquery-wakeup/jquery.wakeup.js",
|
||||||
|
dest: "vendors/jquery-wakeup/jquery.wakeup.min.js"
|
||||||
|
},
|
||||||
|
mousewheel: {
|
||||||
|
options: {
|
||||||
|
banner: "/*! jquery.mousewheel v3.1.4 (c) 2013 Brandon Aaron (http://brandon.aaron.sh) | MIT */\n",
|
||||||
|
preserveComments: "false"
|
||||||
|
},
|
||||||
|
src: "vendors/jquery-mousewheel/jquery.mousewheel.js",
|
||||||
|
dest: "vendors/jquery-mousewheel/jquery.mousewheel-3.1.4.min.js"
|
||||||
|
},
|
||||||
|
nano: {
|
||||||
|
options: {
|
||||||
|
banner: "/*! nanoScrollerJS v0.7 (c) 2013 James Florentino; modified by RainLoop Team | MIT */\n",
|
||||||
|
preserveComments: "false"
|
||||||
|
},
|
||||||
|
src: "vendors/jquery-nanoscroller/jquery.nanoscroller.js",
|
||||||
|
dest: "vendors/jquery-nanoscroller/jquery.nanoscroller-0.7.min.js"
|
||||||
|
},
|
||||||
|
pace: {
|
||||||
|
src: "vendors/simple-pace/simple-pace.js",
|
||||||
|
dest: "vendors/simple-pace/simple-pace-1.0.min.js"
|
||||||
|
},
|
||||||
|
rl: {
|
||||||
|
src: "vendors/rl/rl.js",
|
||||||
|
dest: "vendors/rl/rl-1.0.min.js"
|
||||||
|
},
|
||||||
|
min_app: {
|
||||||
|
src: "rainloop/v/<%= pkg.version %>/static/js/app.js",
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/js/app.min.js"
|
||||||
|
},
|
||||||
|
min_admin: {
|
||||||
|
src: "rainloop/v/<%= pkg.version %>/static/js/admin.js",
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/js/admin.min.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
concat: {
|
||||||
|
js_index: {
|
||||||
|
nonull: true,
|
||||||
|
src: [
|
||||||
|
"vendors/json2.min.js",
|
||||||
|
"vendors/simple-pace/simple-pace-1.0.min.js",
|
||||||
|
"vendors/rl/rl-1.0.min.js"
|
||||||
|
],
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/js/boot.js"
|
||||||
|
},
|
||||||
|
js_libs: {
|
||||||
|
nonull: true,
|
||||||
|
options: {
|
||||||
|
separator: "\n\n"
|
||||||
|
},
|
||||||
|
src: [
|
||||||
|
"vendors/modernizr.js",
|
||||||
|
"vendors/underscore/underscore-1.5.2.min.js",
|
||||||
|
"vendors/jquery-1.10.1.min.js",
|
||||||
|
"vendors/jquery-ui/js/jquery-ui-1.10.3.custom.min.js",
|
||||||
|
"vendors/jquery-cookie/jquery.cookie-1.4.0.min.js",
|
||||||
|
"vendors/jquery-mousewheel/jquery.mousewheel-3.1.4.min.js",
|
||||||
|
"vendors/jquery-scrollstop/jquery.scrollstop.min.js",
|
||||||
|
"vendors/jquery-lazyload/jquery.lazyload.min.js",
|
||||||
|
"vendors/jquery-nanoscroller/jquery.nanoscroller-0.7.min.js",
|
||||||
|
"vendors/jquery-wakeup/jquery.wakeup.min.js",
|
||||||
|
"vendors/moment/min/moment.min.js ",
|
||||||
|
"vendors/routes/signals.min.js",
|
||||||
|
"vendors/routes/hasher.min.js",
|
||||||
|
"vendors/routes/crossroads.min.js",
|
||||||
|
"vendors/knockout/knockout-3.0.0.js",
|
||||||
|
"vendors/jua/jua.min.js",
|
||||||
|
"vendors/select2-3.4.5/select2.min.js",
|
||||||
|
"vendors/jquery-magnific-popup/jquery.magnific-popup.min.js",
|
||||||
|
"vendors/bootstrap/js/bootstrap.min.js",
|
||||||
|
"dev/Common/_LibsEnd.js"
|
||||||
|
],
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/js/libs.js"
|
||||||
|
},
|
||||||
|
js_admin: {
|
||||||
|
nonull: true,
|
||||||
|
options: {
|
||||||
|
stripBanners: true,
|
||||||
|
banner: "/*! RainLoop Admin Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */\n" +
|
||||||
|
"(function (window, $, ko, crossroads, hasher, _) {\n",
|
||||||
|
footer: "\n\n}(window, jQuery, ko, crossroads, hasher, _));"
|
||||||
|
},
|
||||||
|
src: [
|
||||||
|
"dev/Common/_Begin.js",
|
||||||
|
"dev/Common/_BeginA.js",
|
||||||
|
|
||||||
|
"dev/Common/Globals.js",
|
||||||
|
"dev/Common/Constants.js",
|
||||||
|
"dev/Common/Enums.js",
|
||||||
|
"dev/Common/Utils.js",
|
||||||
|
"dev/Common/Base64.js",
|
||||||
|
"dev/Common/Knockout.js",
|
||||||
|
"dev/Common/LinkBuilder.js",
|
||||||
|
"dev/Common/Plugins.js",
|
||||||
|
|
||||||
|
"dev/Storages/LocalStorages/CookieDriver.js",
|
||||||
|
"dev/Storages/LocalStorages/LocalStorageDriver.js",
|
||||||
|
"dev/Storages/LocalStorage.js",
|
||||||
|
|
||||||
|
"dev/Knoin/AbstractBoot.js",
|
||||||
|
"dev/Knoin/AbstractViewModel.js",
|
||||||
|
"dev/Knoin/AbstractScreen.js",
|
||||||
|
"dev/Knoin/Knoin.js",
|
||||||
|
|
||||||
|
"dev/Models/EmailModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/PopupsDomainViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsPluginViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsActivateViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsLanguagesViewModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/AdminLoginViewModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/AdminMenuViewModel.js",
|
||||||
|
"dev/ViewModels/AdminPaneViewModel.js",
|
||||||
|
|
||||||
|
"dev/Admin/General.js",
|
||||||
|
"dev/Admin/Login.js",
|
||||||
|
"dev/Admin/Domains.js",
|
||||||
|
"dev/Admin/Security.js",
|
||||||
|
"dev/Admin/Social.js",
|
||||||
|
"dev/Admin/Plugins.js",
|
||||||
|
"dev/Admin/Packages.js",
|
||||||
|
"dev/Admin/Licensing.js",
|
||||||
|
|
||||||
|
"dev/Storages/AbstractData.js",
|
||||||
|
"dev/Storages/AdminData.js",
|
||||||
|
|
||||||
|
"dev/Storages/AbstractAjaxRemote.js",
|
||||||
|
"dev/Storages/AdminAjaxRemote.js",
|
||||||
|
|
||||||
|
"dev/Storages/AbstractCache.js",
|
||||||
|
"dev/Storages/AdminCache.js",
|
||||||
|
|
||||||
|
"dev/Screens/AbstractSettings.js",
|
||||||
|
|
||||||
|
"dev/Screens/AdminLogin.js",
|
||||||
|
"dev/Screens/AdminSettings.js",
|
||||||
|
|
||||||
|
"dev/Boots/AbstractApp.js",
|
||||||
|
"dev/Boots/AdminApp.js",
|
||||||
|
|
||||||
|
"dev/Common/_End.js",
|
||||||
|
"dev/Common/_CoreEnd.js"
|
||||||
|
],
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/js/admin.js"
|
||||||
|
},
|
||||||
|
js_app: {
|
||||||
|
nonull: true,
|
||||||
|
options: {
|
||||||
|
stripBanners: true,
|
||||||
|
banner: "/*! RainLoop Webmail Module (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */\n" +
|
||||||
|
"(function (window, $, ko, crossroads, hasher, moment, Jua, _) {\n",
|
||||||
|
footer: "\n\n}(window, jQuery, ko, crossroads, hasher, moment, Jua, _));"
|
||||||
|
},
|
||||||
|
src: [
|
||||||
|
"dev/Common/_Begin.js",
|
||||||
|
"dev/Common/_BeginW.js",
|
||||||
|
|
||||||
|
"dev/Common/Globals.js",
|
||||||
|
"dev/Common/Constants.js",
|
||||||
|
"dev/Common/Enums.js",
|
||||||
|
"dev/Common/Utils.js",
|
||||||
|
"dev/Common/Base64.js",
|
||||||
|
"dev/Common/Knockout.js",
|
||||||
|
"dev/Common/LinkBuilder.js",
|
||||||
|
"dev/Common/Plugins.js",
|
||||||
|
"dev/Common/HtmlEditor.js",
|
||||||
|
"dev/Common/Selector.js",
|
||||||
|
|
||||||
|
"dev/Storages/LocalStorages/CookieDriver.js",
|
||||||
|
"dev/Storages/LocalStorages/LocalStorageDriver.js",
|
||||||
|
"dev/Storages/LocalStorage.js",
|
||||||
|
|
||||||
|
"dev/Knoin/AbstractBoot.js",
|
||||||
|
"dev/Knoin/AbstractViewModel.js",
|
||||||
|
"dev/Knoin/AbstractScreen.js",
|
||||||
|
"dev/Knoin/Knoin.js",
|
||||||
|
|
||||||
|
"dev/Models/EmailModel.js",
|
||||||
|
"dev/Models/ContactModel.js",
|
||||||
|
"dev/Models/AttachmentModel.js",
|
||||||
|
"dev/Models/ComposeAttachmentModel.js",
|
||||||
|
"dev/Models/MessageModel.js",
|
||||||
|
"dev/Models/FolderModel.js",
|
||||||
|
"dev/Models/AccountModel.js",
|
||||||
|
"dev/Models/IdentityModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/PopupsFolderClearViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsFolderCreateViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsFolderSystemViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsComposeViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsContactsViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsAdvancedSearchViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsAddAccountViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsIdentityViewModel.js",
|
||||||
|
"dev/ViewModels/PopupsLanguagesViewModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/LoginViewModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/AbstractSystemDropDownViewModel.js",
|
||||||
|
"dev/ViewModels/MailBoxSystemDropDownViewModel.js",
|
||||||
|
"dev/ViewModels/SettingsSystemDropDownViewModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/MailBoxFolderListViewModel.js",
|
||||||
|
"dev/ViewModels/MailBoxMessageListViewModel.js",
|
||||||
|
"dev/ViewModels/MailBoxMessageViewViewModel.js",
|
||||||
|
|
||||||
|
"dev/ViewModels/SettingsMenuViewModel.js",
|
||||||
|
"dev/ViewModels/SettingsPaneViewModel.js",
|
||||||
|
|
||||||
|
"dev/Settings/General.js",
|
||||||
|
"dev/Settings/Personal.js",
|
||||||
|
"dev/Settings/Accounts.js",
|
||||||
|
"dev/Settings/Identities.js",
|
||||||
|
"dev/Settings/Social.js",
|
||||||
|
"dev/Settings/ChangePassword.js",
|
||||||
|
"dev/Settings/Folders.js",
|
||||||
|
"dev/Settings/Themes.js",
|
||||||
|
|
||||||
|
"dev/Storages/AbstractData.js",
|
||||||
|
"dev/Storages/WebMailData.js",
|
||||||
|
|
||||||
|
"dev/Storages/AbstractAjaxRemote.js",
|
||||||
|
"dev/Storages/WebMailAjaxRemote.js",
|
||||||
|
|
||||||
|
"dev/Storages/AbstractCache.js",
|
||||||
|
"dev/Storages/WebMailCache.js",
|
||||||
|
|
||||||
|
"dev/Screens/AbstractSettings.js",
|
||||||
|
|
||||||
|
"dev/Screens/Login.js",
|
||||||
|
"dev/Screens/MailBox.js",
|
||||||
|
"dev/Screens/Settings.js",
|
||||||
|
|
||||||
|
"dev/Boots/AbstractApp.js",
|
||||||
|
"dev/Boots/RainLoopApp.js",
|
||||||
|
|
||||||
|
"dev/Common/_End.js",
|
||||||
|
"dev/Common/_CoreEnd.js"
|
||||||
|
],
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/js/app.js"
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
nonull: true,
|
||||||
|
src: [
|
||||||
|
"vendors/jquery-ui/css/no-theme/jquery-ui-1.10.3.custom.css",
|
||||||
|
"vendors/normalize/normalize.css",
|
||||||
|
"vendors/icomoon/style.css",
|
||||||
|
"vendors/select2-3.4.5/select2.css",
|
||||||
|
"vendors/select2-3.4.5/select2-bootstrap.css",
|
||||||
|
"vendors/jquery-nanoscroller/nanoscroller.css",
|
||||||
|
"vendors/jquery-magnific-popup/magnific-popup.css",
|
||||||
|
"vendors/jquery-magnific-popup/magnific-popup-animations.css",
|
||||||
|
"vendors/simple-pace/styles.css",
|
||||||
|
"vendors/flags/flags-fixed.css",
|
||||||
|
"rainloop/v/<%= pkg.version %>/static/css/less.css"
|
||||||
|
],
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/css/app.css"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cssmin: {
|
||||||
|
css: {
|
||||||
|
src: "rainloop/v/<%= pkg.version %>/static/css/app.css",
|
||||||
|
dest: "rainloop/v/<%= pkg.version %>/static/css/app.min.css"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
js: {
|
||||||
|
options: {
|
||||||
|
nospawn: true
|
||||||
|
},
|
||||||
|
files: ["dev/**/*.js"],
|
||||||
|
tasks: ["concat:js_libs", "concat:js_admin", "concat:js_app"]
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
options: {
|
||||||
|
nospawn: true
|
||||||
|
},
|
||||||
|
files: ["dev/Styles/*.less"],
|
||||||
|
tasks: ["less", "concat:css"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
for (var key in grunt.file.readJSON('package.json').devDependencies) {
|
||||||
|
if (key !== 'grunt' && key.indexOf('grunt') === 0) {
|
||||||
|
grunt.loadNpmTasks(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// uglify
|
||||||
|
grunt.registerTask('mousewheel', ['uglify:mousewheel']);
|
||||||
|
grunt.registerTask('wakeup', ['uglify:wakeup']);
|
||||||
|
grunt.registerTask('nano', ['uglify:nano']);
|
||||||
|
grunt.registerTask('pace', ['uglify:pace']);
|
||||||
|
grunt.registerTask('rl', ['uglify:rl']);
|
||||||
|
grunt.registerTask('cookie', ['uglify:cookie']);
|
||||||
|
grunt.registerTask('rainloop', ['uglify:min_app', 'uglify:min_admin']);
|
||||||
|
// ---
|
||||||
|
|
||||||
|
grunt.registerTask('default', ['less', 'concat', 'jshint', 'cssmin', 'rainloop']);
|
||||||
|
|
||||||
|
// aliases
|
||||||
|
grunt.registerTask('ant', ['default']); // special for ant task
|
||||||
|
grunt.registerTask('u', ['uglify']);
|
||||||
|
grunt.registerTask('h', ['jshint']);
|
||||||
|
grunt.registerTask('w', ['watch']);
|
||||||
|
};
|
||||||
20
LICENSE
20
LICENSE
|
|
@ -1,25 +1,25 @@
|
||||||
Creative Commons — Attribution-NonCommercial-ShareAlike 3.0 Unported — CC BY-NC-SA 3.0
|
Creative Commons — Attribution-NonCommercial-ShareAlike 3.0 Unported — CC BY-NC-SA 3.0
|
||||||
(http://creativecommons.org/licenses/by-nc-sa/3.0/)
|
(http://creativecommons.org/licenses/by-nc-sa/3.0/)
|
||||||
|
|
||||||
You are free:
|
You are free:
|
||||||
|
|
||||||
to Share — to copy, distribute and transmit the work
|
to Share — to copy, distribute and transmit the work
|
||||||
to Remix — to adapt the work
|
to Remix — to adapt the work
|
||||||
|
|
||||||
Under the following conditions:
|
Under the following conditions:
|
||||||
|
|
||||||
Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
|
Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
|
||||||
Noncommercial — You may not use this work for commercial purposes.
|
Noncommercial — You may not use this work for commercial purposes.
|
||||||
Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
|
Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
|
||||||
|
|
||||||
With the understanding that:
|
With the understanding that:
|
||||||
|
|
||||||
Waiver — Any of the above conditions can be waived if you get permission from the copyright holder.
|
Waiver — Any of the above conditions can be waived if you get permission from the copyright holder.
|
||||||
Public Domain — Where the work or any of its elements is in the public domain under applicable law, that status is in no way affected by the license.
|
Public Domain — Where the work or any of its elements is in the public domain under applicable law, that status is in no way affected by the license.
|
||||||
|
|
||||||
Other Rights — In no way are any of the following rights affected by the license:
|
Other Rights — In no way are any of the following rights affected by the license:
|
||||||
Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
|
Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
|
||||||
The author's moral rights;
|
The author's moral rights;
|
||||||
Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights.
|
Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights.
|
||||||
|
|
||||||
Notice — For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
|
Notice — For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
|
||||||
35
_include.php
Normal file
35
_include.php
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function __get_custom_data_full_path()
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
return '/var/rainloop-data-folder/'; // custom data folder path
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $siteName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function __get_private_data_folder_internal_name($siteName)
|
||||||
|
{
|
||||||
|
return '_default_'; // default domain folder name
|
||||||
|
return $siteName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $siteName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function __get_core_install_access_site($siteName)
|
||||||
|
{
|
||||||
|
return $siteName; // allow all
|
||||||
|
|
||||||
|
return in_array($siteName, array(
|
||||||
|
'domain.com', 'domain.net'
|
||||||
|
)) ? $siteName : '';
|
||||||
|
}
|
||||||
90
dev/Admin/Domains.js
Normal file
90
dev/Admin/Domains.js
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminDomains()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.domains = oData.domains;
|
||||||
|
this.domainsLoading = oData.domainsLoading;
|
||||||
|
|
||||||
|
this.iDomainForDeletionTimeout = 0;
|
||||||
|
|
||||||
|
this.visibility = ko.computed(function () {
|
||||||
|
return oData.domainsLoading() ? 'visible' : 'hidden';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.domainForDeletion = ko.observable(null).extend({'toggleSubscribe': [this,
|
||||||
|
function (oPrev) {
|
||||||
|
if (oPrev)
|
||||||
|
{
|
||||||
|
oPrev.deleteAccess(false);
|
||||||
|
}
|
||||||
|
}, function (oNext) {
|
||||||
|
if (oNext)
|
||||||
|
{
|
||||||
|
oNext.deleteAccess(true);
|
||||||
|
this.startDomainForDeletionTimeout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminDomains, 'AdminSettingsDomains', 'Domains', 'domains');
|
||||||
|
|
||||||
|
AdminDomains.prototype.startDomainForDeletionTimeout = function ()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
window.clearInterval(this.iDomainForDeletionTimeout);
|
||||||
|
this.iDomainForDeletionTimeout = window.setTimeout(function () {
|
||||||
|
self.domainForDeletion(null);
|
||||||
|
}, 1000 * 3);
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminDomains.prototype.createDomain = function ()
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsDomainViewModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminDomains.prototype.deleteDomain = function (oDomain)
|
||||||
|
{
|
||||||
|
this.domains.remove(oDomain);
|
||||||
|
RL.remote().domainDelete(_.bind(this.onDomainListChangeRequest, this), oDomain.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminDomains.prototype.disableDomain = function (oDomain)
|
||||||
|
{
|
||||||
|
oDomain.disabled(!oDomain.disabled());
|
||||||
|
RL.remote().domainDisable(_.bind(this.onDomainListChangeRequest, this), oDomain.name, oDomain.disabled());
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminDomains.prototype.onBuild = function (oDom)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
oDom
|
||||||
|
.on('click', '.b-admin-domains-list-table .e-item .e-action', function () {
|
||||||
|
var oDomainItem = ko.dataFor(this);
|
||||||
|
if (oDomainItem)
|
||||||
|
{
|
||||||
|
RL.remote().domain(_.bind(self.onDomainLoadRequest, self), oDomainItem.name);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
RL.reloadDomainList();
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminDomains.prototype.onDomainLoadRequest = function (sResult, oData)
|
||||||
|
{
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsDomainViewModel, [oData.Result]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminDomains.prototype.onDomainListChangeRequest = function ()
|
||||||
|
{
|
||||||
|
RL.reloadDomainList();
|
||||||
|
};
|
||||||
122
dev/Admin/General.js
Normal file
122
dev/Admin/General.js
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminGeneral()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.mainLanguage = oData.mainLanguage;
|
||||||
|
this.mainTheme = oData.mainTheme;
|
||||||
|
|
||||||
|
this.language = oData.language;
|
||||||
|
this.theme = oData.theme;
|
||||||
|
|
||||||
|
this.allowThemes = oData.allowThemes;
|
||||||
|
this.allowCustomTheme = oData.allowCustomTheme;
|
||||||
|
this.allowLanguagesOnSettings = oData.allowLanguagesOnSettings;
|
||||||
|
this.allowAdditionalAccounts = oData.allowAdditionalAccounts;
|
||||||
|
this.allowIdentities = oData.allowIdentities;
|
||||||
|
|
||||||
|
this.title = ko.observable(RL.settingsGet('Title'));
|
||||||
|
this.loadingDesc = ko.observable(RL.settingsGet('LoadingDescription'));
|
||||||
|
|
||||||
|
this.themesOptions = ko.computed(function () {
|
||||||
|
return _.map(oData.themes(), function (sTheme) {
|
||||||
|
return {
|
||||||
|
'optValue': sTheme,
|
||||||
|
'optText': Utils.convertThemeName(sTheme)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.languagesOptions = ko.computed(function () {
|
||||||
|
return _.map(oData.languages(), function (sLanguage) {
|
||||||
|
return {
|
||||||
|
'optValue': sLanguage,
|
||||||
|
'optText': Utils.convertLangName(sLanguage)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.contactsSupported = RL.settingsGet('ContactsIsSupported');
|
||||||
|
this.contactsIsAllowed = RL.settingsGet('ContactsIsAllowed');
|
||||||
|
this.weakPassword = !!RL.settingsGet('WeakPassword');
|
||||||
|
|
||||||
|
this.titleTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.loadingDescTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminGeneral, 'AdminSettingsGeneral', 'General', 'general', true);
|
||||||
|
|
||||||
|
AdminGeneral.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
f1 = Utils.settingsSaveHelperSimpleFunction(self.titleTrigger, self),
|
||||||
|
f2 = Utils.settingsSaveHelperSimpleFunction(self.languageTrigger, self),
|
||||||
|
f3 = Utils.settingsSaveHelperSimpleFunction(self.themeTrigger, self),
|
||||||
|
f4 = Utils.settingsSaveHelperSimpleFunction(self.loadingDescTrigger, self)
|
||||||
|
;
|
||||||
|
|
||||||
|
self.title.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f1, {
|
||||||
|
'Title': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.loadingDesc.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f4, {
|
||||||
|
'LoadingDescription': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.language.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f2, {
|
||||||
|
'Language': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.theme.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f3, {
|
||||||
|
'Theme': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.allowCustomTheme.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'AllowCustomTheme': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.allowAdditionalAccounts.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'AllowAdditionalAccounts': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.allowIdentities.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'AllowIdentities': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.allowThemes.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'AllowThemes': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.allowLanguagesOnSettings.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'AllowLanguagesOnSettings': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
53
dev/Admin/Licensing.js
Normal file
53
dev/Admin/Licensing.js
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminLicensing()
|
||||||
|
{
|
||||||
|
this.licensing = RL.data().licensing;
|
||||||
|
this.licensingProcess = RL.data().licensingProcess;
|
||||||
|
this.licenseValid = RL.data().licenseValid;
|
||||||
|
this.licenseExpired = RL.data().licenseExpired;
|
||||||
|
this.licenseError = RL.data().licenseError;
|
||||||
|
this.licenseTrigger = RL.data().licenseTrigger;
|
||||||
|
|
||||||
|
this.adminDomain = ko.observable('');
|
||||||
|
this.subscriptionEnabled = ko.observable(!!RL.settingsGet('SubscriptionEnabled'));
|
||||||
|
|
||||||
|
this.licenseTrigger.subscribe(function () {
|
||||||
|
if (this.subscriptionEnabled())
|
||||||
|
{
|
||||||
|
RL.reloadLicensing(true);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminLicensing, 'AdminSettingsLicensing', 'Licensing', 'licensing');
|
||||||
|
|
||||||
|
AdminLicensing.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
if (this.subscriptionEnabled())
|
||||||
|
{
|
||||||
|
RL.reloadLicensing(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminLicensing.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
this.adminDomain(RL.settingsGet('AdminDomain'));
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminLicensing.prototype.showActivationForm = function ()
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsActivateViewModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
AdminLicensing.prototype.licenseExpiredMomentValue = function ()
|
||||||
|
{
|
||||||
|
var oDate = moment.unix(this.licenseExpired());
|
||||||
|
return oDate.format('LL') + ' (' + oDate.from(moment()) + ')';
|
||||||
|
};
|
||||||
53
dev/Admin/Login.js
Normal file
53
dev/Admin/Login.js
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminLogin()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.allowCustomLogin = oData.allowCustomLogin;
|
||||||
|
this.determineUserLanguage = oData.determineUserLanguage;
|
||||||
|
|
||||||
|
this.defaultDomain = ko.observable(RL.settingsGet('LoginDefaultDomain'));
|
||||||
|
|
||||||
|
this.allowLanguagesOnLogin = oData.allowLanguagesOnLogin;
|
||||||
|
this.defaultDomainTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminLogin, 'AdminSettingsLogin', 'Login', 'login');
|
||||||
|
|
||||||
|
AdminLogin.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
var f1 = Utils.settingsSaveHelperSimpleFunction(self.defaultDomainTrigger, self);
|
||||||
|
|
||||||
|
self.determineUserLanguage.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'DetermineUserLanguage': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.allowCustomLogin.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'AllowCustomLogin': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.allowLanguagesOnLogin.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(null, {
|
||||||
|
'AllowLanguagesOnLogin': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.defaultDomain.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f1, {
|
||||||
|
'LoginDefaultDomain': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
105
dev/Admin/Packages.js
Normal file
105
dev/Admin/Packages.js
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminPackages()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.packagesError = ko.observable('');
|
||||||
|
|
||||||
|
this.packages = oData.packages;
|
||||||
|
this.packagesLoading = oData.packagesLoading;
|
||||||
|
this.packagesReal = oData.packagesReal;
|
||||||
|
this.packagesMainUpdatable = oData.packagesMainUpdatable;
|
||||||
|
|
||||||
|
this.packagesCurrent = ko.computed(function () {
|
||||||
|
return _.filter(this.packages(), function (oItem) {
|
||||||
|
return oItem && '' !== oItem['installed'] && !oItem['compare'];
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.packagesAvailableForUpdate = ko.computed(function () {
|
||||||
|
return _.filter(this.packages(), function (oItem) {
|
||||||
|
return oItem && '' !== oItem['installed'] && !!oItem['compare'];
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.packagesAvailableForInstallation = ko.computed(function () {
|
||||||
|
return _.filter(this.packages(), function (oItem) {
|
||||||
|
return oItem && '' === oItem['installed'];
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.visibility = ko.computed(function () {
|
||||||
|
return oData.packagesLoading() ? 'visible' : 'hidden';
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminPackages, 'AdminSettingsPackages', 'Packages', 'packages');
|
||||||
|
|
||||||
|
AdminPackages.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
this.packagesError('');
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPackages.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
RL.reloadPackagesList();
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPackages.prototype.requestHelper = function (oPackage, bInstall)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
return function (sResult, oData) {
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
|
||||||
|
{
|
||||||
|
if (oData && oData.ErrorCode)
|
||||||
|
{
|
||||||
|
self.packagesError(Utils.getNotification(oData.ErrorCode));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.packagesError(Utils.getNotification(
|
||||||
|
bInstall ? Enums.Notification.CantInstallPackage : Enums.Notification.CantDeletePackage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_.each(RL.data().packages(), function (oItem) {
|
||||||
|
if (oItem && oPackage && oItem['loading']() && oPackage['file'] === oItem['file'])
|
||||||
|
{
|
||||||
|
oPackage['loading'](false);
|
||||||
|
oItem['loading'](false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result['Reload'])
|
||||||
|
{
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RL.reloadPackagesList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPackages.prototype.deletePackage = function (oPackage)
|
||||||
|
{
|
||||||
|
if (oPackage)
|
||||||
|
{
|
||||||
|
oPackage['loading'](true);
|
||||||
|
RL.remote().packageDelete(this.requestHelper(oPackage, false), oPackage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPackages.prototype.installPackage = function (oPackage)
|
||||||
|
{
|
||||||
|
if (oPackage)
|
||||||
|
{
|
||||||
|
oPackage['loading'](true);
|
||||||
|
RL.remote().packageInstall(this.requestHelper(oPackage, true), oPackage);
|
||||||
|
}
|
||||||
|
};
|
||||||
79
dev/Admin/Plugins.js
Normal file
79
dev/Admin/Plugins.js
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminPlugins()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.enabledPlugins = ko.observable(!!RL.settingsGet('EnabledPlugins'));
|
||||||
|
|
||||||
|
this.pluginsError = ko.observable('');
|
||||||
|
|
||||||
|
this.plugins = oData.plugins;
|
||||||
|
this.pluginsLoading = oData.pluginsLoading;
|
||||||
|
|
||||||
|
this.visibility = ko.computed(function () {
|
||||||
|
return oData.pluginsLoading() ? 'visible' : 'hidden';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.onPluginLoadRequest = _.bind(this.onPluginLoadRequest, this);
|
||||||
|
this.onPluginDisableRequest = _.bind(this.onPluginDisableRequest, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminPlugins, 'AdminSettingsPlugins', 'Plugins', 'plugins');
|
||||||
|
|
||||||
|
AdminPlugins.prototype.disablePlugin = function (oPlugin)
|
||||||
|
{
|
||||||
|
oPlugin.disabled(!oPlugin.disabled());
|
||||||
|
RL.remote().pluginDisable(this.onPluginDisableRequest, oPlugin.name, oPlugin.disabled());
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPlugins.prototype.configurePlugin = function (oPlugin)
|
||||||
|
{
|
||||||
|
RL.remote().plugin(this.onPluginLoadRequest, oPlugin.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPlugins.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
this.enabledPlugins.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'EnabledPlugins': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPlugins.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
this.pluginsError('');
|
||||||
|
RL.reloadPluginList();
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPlugins.prototype.onPluginLoadRequest = function (sResult, oData)
|
||||||
|
{
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsPluginViewModel, [oData.Result]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminPlugins.prototype.onPluginDisableRequest = function (sResult, oData)
|
||||||
|
{
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData)
|
||||||
|
{
|
||||||
|
if (!oData.Result && oData.ErrorCode)
|
||||||
|
{
|
||||||
|
if (Enums.Notification.UnsupportedPluginPackage === oData.ErrorCode && oData.ErrorMessage && '' !== oData.ErrorMessage)
|
||||||
|
{
|
||||||
|
this.pluginsError(oData.ErrorMessage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.pluginsError(Utils.getNotification(oData.ErrorCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.reloadPluginList();
|
||||||
|
};
|
||||||
89
dev/Admin/Security.js
Normal file
89
dev/Admin/Security.js
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminSecurity()
|
||||||
|
{
|
||||||
|
this.csrfProtection = ko.observable(!!RL.settingsGet('UseTokenProtection'));
|
||||||
|
this.usageStatistics = ko.observable(!!RL.settingsGet('UsageStatistics'));
|
||||||
|
|
||||||
|
this.adminLogin = ko.observable(RL.settingsGet('AdminLogin'));
|
||||||
|
this.adminPassword = ko.observable('');
|
||||||
|
this.adminPasswordNew = ko.observable('');
|
||||||
|
|
||||||
|
this.adminPasswordUpdateError = ko.observable(false);
|
||||||
|
this.adminPasswordUpdateSuccess = ko.observable(false);
|
||||||
|
|
||||||
|
this.adminPassword.subscribe(function () {
|
||||||
|
this.adminPasswordUpdateError(false);
|
||||||
|
this.adminPasswordUpdateSuccess(false);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.adminPasswordNew.subscribe(function () {
|
||||||
|
this.adminPasswordUpdateError(false);
|
||||||
|
this.adminPasswordUpdateSuccess(false);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.onNewAdminPasswordResponse = _.bind(this.onNewAdminPasswordResponse, this);
|
||||||
|
|
||||||
|
this.saveNewAdminPasswordCommand = Utils.createCommand(this, function () {
|
||||||
|
|
||||||
|
this.adminPasswordUpdateError(false);
|
||||||
|
this.adminPasswordUpdateSuccess(false);
|
||||||
|
|
||||||
|
RL.remote().saveNewAdminPassword(this.onNewAdminPasswordResponse, {
|
||||||
|
'Password': this.adminPassword(),
|
||||||
|
'NewPassword': this.adminPasswordNew()
|
||||||
|
});
|
||||||
|
|
||||||
|
}, function () {
|
||||||
|
return '' !== this.adminPassword() && '' !== this.adminPasswordNew();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminSecurity, 'AdminSettingsSecurity', 'Security', 'security');
|
||||||
|
|
||||||
|
AdminSecurity.prototype.onNewAdminPasswordResponse = function (sResult, oData)
|
||||||
|
{
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
this.adminPassword('');
|
||||||
|
this.adminPasswordNew('');
|
||||||
|
|
||||||
|
this.adminPasswordUpdateSuccess(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.adminPasswordUpdateError(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminSecurity.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
this.csrfProtection.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'TokenProtection': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.usageStatistics.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'UsageStatistics': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminSecurity.prototype.onHide = function ()
|
||||||
|
{
|
||||||
|
this.adminPassword('');
|
||||||
|
this.adminPasswordNew('');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
AdminSecurity.prototype.phpInfoLink = function ()
|
||||||
|
{
|
||||||
|
return RL.link().phpInfo();
|
||||||
|
};
|
||||||
117
dev/Admin/Social.js
Normal file
117
dev/Admin/Social.js
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AdminSocial()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.googleEnable = oData.googleEnable;
|
||||||
|
this.googleClientID = oData.googleClientID;
|
||||||
|
this.googleClientSecret = oData.googleClientSecret;
|
||||||
|
this.googleTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.googleTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
|
||||||
|
this.facebookEnable = oData.facebookEnable;
|
||||||
|
this.facebookAppID = oData.facebookAppID;
|
||||||
|
this.facebookAppSecret = oData.facebookAppSecret;
|
||||||
|
this.facebookTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.facebookTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
|
||||||
|
this.twitterEnable = oData.twitterEnable;
|
||||||
|
this.twitterConsumerKey = oData.twitterConsumerKey;
|
||||||
|
this.twitterConsumerSecret = oData.twitterConsumerSecret;
|
||||||
|
this.twitterTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.twitterTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
|
||||||
|
this.dropboxEnable = oData.dropboxEnable;
|
||||||
|
this.dropboxApiKey = oData.dropboxApiKey;
|
||||||
|
this.dropboxTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(AdminSocial, 'AdminSettingsSocial', 'Social', 'social');
|
||||||
|
|
||||||
|
AdminSocial.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
f1 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger1, self),
|
||||||
|
f2 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger2, self),
|
||||||
|
f3 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger1, self),
|
||||||
|
f4 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger2, self),
|
||||||
|
f5 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger1, self),
|
||||||
|
f6 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger2, self),
|
||||||
|
f7 = Utils.settingsSaveHelperSimpleFunction(self.dropboxTrigger1, self)
|
||||||
|
;
|
||||||
|
|
||||||
|
self.facebookEnable.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'FacebookEnable': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.facebookAppID.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f1, {
|
||||||
|
'FacebookAppID': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.facebookAppSecret.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f2, {
|
||||||
|
'FacebookAppSecret': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.twitterEnable.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'TwitterEnable': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.twitterConsumerKey.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f3, {
|
||||||
|
'TwitterConsumerKey': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.twitterConsumerSecret.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f4, {
|
||||||
|
'TwitterConsumerSecret': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.googleEnable.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'GoogleEnable': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.googleClientID.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f5, {
|
||||||
|
'GoogleClientID': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.googleClientSecret.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f6, {
|
||||||
|
'GoogleClientSecret': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.dropboxEnable.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveAdminConfig(Utils.emptyFunction, {
|
||||||
|
'DropboxEnable': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.dropboxApiKey.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveAdminConfig(f7, {
|
||||||
|
'DropboxApiKey': Utils.trim(sValue)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
227
dev/Boots/AbstractApp.js
Normal file
227
dev/Boots/AbstractApp.js
Normal file
|
|
@ -0,0 +1,227 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends KnoinAbstractBoot
|
||||||
|
*/
|
||||||
|
function AbstractApp()
|
||||||
|
{
|
||||||
|
KnoinAbstractBoot.call(this);
|
||||||
|
|
||||||
|
this.oSettings = null;
|
||||||
|
this.oPlugins = null;
|
||||||
|
this.oLink = null;
|
||||||
|
this.oLocal = null;
|
||||||
|
|
||||||
|
this.isLocalAutocomplete = true;
|
||||||
|
|
||||||
|
this.popupVisibility = ko.observable(false);
|
||||||
|
|
||||||
|
this.iframe = $('<iframe style="display:none" src="javascript:;" />').appendTo('body');
|
||||||
|
|
||||||
|
$window.on('error', function (oEvent) {
|
||||||
|
if (RL && oEvent && oEvent.originalEvent && oEvent.originalEvent.message &&
|
||||||
|
-1 === Utils.inArray(oEvent.originalEvent.message, [
|
||||||
|
'Script error.', 'Uncaught Error: Error calling method on NPObject.'
|
||||||
|
]))
|
||||||
|
{
|
||||||
|
RL.remote().jsError(
|
||||||
|
Utils.emptyFunction,
|
||||||
|
oEvent.originalEvent.message,
|
||||||
|
oEvent.originalEvent.filename,
|
||||||
|
oEvent.originalEvent.lineno,
|
||||||
|
location && location.toString ? location.toString() : '',
|
||||||
|
$html.attr('class'),
|
||||||
|
Utils.microtime() - Globals.now
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AbstractApp.prototype, KnoinAbstractBoot.prototype);
|
||||||
|
|
||||||
|
AbstractApp.prototype.oSettings = null;
|
||||||
|
AbstractApp.prototype.oLink = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sLink
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
AbstractApp.prototype.download = function (sLink)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oLink = null,
|
||||||
|
oE = null,
|
||||||
|
sUserAgent = navigator.userAgent.toLowerCase()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (sUserAgent && (sUserAgent.indexOf('chrome') > -1 || sUserAgent.indexOf('chrome') > -1))
|
||||||
|
{
|
||||||
|
oLink = document.createElement('a');
|
||||||
|
oLink['href'] = sLink;
|
||||||
|
|
||||||
|
if (document['createEvent'])
|
||||||
|
{
|
||||||
|
oE = document['createEvent']('MouseEvents');
|
||||||
|
if (oE && oE['initEvent'] && oLink['dispatchEvent'])
|
||||||
|
{
|
||||||
|
oE['initEvent']('click', true, true);
|
||||||
|
oLink['dispatchEvent'](oE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Globals.bMobileDevice)
|
||||||
|
{
|
||||||
|
window.open(sLink, '_self');
|
||||||
|
window.focus();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.iframe.attr('src', sLink);
|
||||||
|
// window.document.location.href = sLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {LinkBuilder}
|
||||||
|
*/
|
||||||
|
AbstractApp.prototype.link = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oLink)
|
||||||
|
{
|
||||||
|
this.oLink = new LinkBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {LocalStorage}
|
||||||
|
*/
|
||||||
|
AbstractApp.prototype.local = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oLocal)
|
||||||
|
{
|
||||||
|
this.oLocal = new LocalStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oLocal;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sName
|
||||||
|
* @return {?}
|
||||||
|
*/
|
||||||
|
AbstractApp.prototype.settingsGet = function (sName)
|
||||||
|
{
|
||||||
|
if (null === this.oSettings)
|
||||||
|
{
|
||||||
|
this.oSettings = Utils.isNormal(AppData) ? AppData : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.isUnd(this.oSettings[sName]) ? null : this.oSettings[sName];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {?} mValue
|
||||||
|
*/
|
||||||
|
AbstractApp.prototype.settingsSet = function (sName, mValue)
|
||||||
|
{
|
||||||
|
if (null === this.oSettings)
|
||||||
|
{
|
||||||
|
this.oSettings = Utils.isNormal(AppData) ? AppData : {};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oSettings[sName] = mValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractApp.prototype.setTitle = function (sTitle)
|
||||||
|
{
|
||||||
|
sTitle = ((0 < sTitle.length) ? sTitle + ' - ' : '') +
|
||||||
|
this.settingsGet('Title') || '';
|
||||||
|
|
||||||
|
if (sTitle !== window.document.title)
|
||||||
|
{
|
||||||
|
window.document.title = sTitle;
|
||||||
|
_.delay(function () {
|
||||||
|
window.document.title = sTitle;
|
||||||
|
}, 5);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bLogout = false
|
||||||
|
* @param {boolean=} bClose = false
|
||||||
|
*/
|
||||||
|
AbstractApp.prototype.loginAndLogoutReload = function (bLogout, bClose)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sCustomLogoutLink = Utils.pString(this.settingsGet('CustomLogoutLink')),
|
||||||
|
bInIframe = !!this.settingsGet('InIframe')
|
||||||
|
;
|
||||||
|
|
||||||
|
bLogout = Utils.isUnd(bLogout) ? false : !!bLogout;
|
||||||
|
bClose = Utils.isUnd(bClose) ? false : !!bClose;
|
||||||
|
|
||||||
|
if (bLogout && bClose && window.close)
|
||||||
|
{
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bLogout && '' !== sCustomLogoutLink && window.location.href !== sCustomLogoutLink)
|
||||||
|
{
|
||||||
|
_.delay(function () {
|
||||||
|
if (bInIframe && window.parent)
|
||||||
|
{
|
||||||
|
window.parent.location.href = sCustomLogoutLink;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.location.href = sCustomLogoutLink;
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kn.routeOff();
|
||||||
|
kn.setHash(RL.link().root(), true);
|
||||||
|
kn.routeOff();
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
if (bInIframe && window.parent)
|
||||||
|
{
|
||||||
|
window.parent.location.reload();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sQuery
|
||||||
|
* @param {number} iPage
|
||||||
|
* @param {Function} fCallback
|
||||||
|
*/
|
||||||
|
AbstractApp.prototype.getAutocomplete = function (sQuery, iPage, fCallback)
|
||||||
|
{
|
||||||
|
fCallback([], sQuery);
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractApp.prototype.bootstart = function ()
|
||||||
|
{
|
||||||
|
Utils.initOnStartOrLangChange(function () {
|
||||||
|
Utils.initNotificationLanguage();
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
Utils.windowResize();
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
248
dev/Boots/AdminApp.js
Normal file
248
dev/Boots/AdminApp.js
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractApp
|
||||||
|
*/
|
||||||
|
function AdminApp()
|
||||||
|
{
|
||||||
|
AbstractApp.call(this);
|
||||||
|
|
||||||
|
this.oData = null;
|
||||||
|
this.oRemote = null;
|
||||||
|
this.oCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AdminApp.prototype, AbstractApp.prototype);
|
||||||
|
|
||||||
|
AdminApp.prototype.oData = null;
|
||||||
|
AdminApp.prototype.oRemote = null;
|
||||||
|
AdminApp.prototype.oCache = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {AdminDataStorage}
|
||||||
|
*/
|
||||||
|
AdminApp.prototype.data = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oData)
|
||||||
|
{
|
||||||
|
this.oData = new AdminDataStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oData;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {AdminAjaxRemoteStorage}
|
||||||
|
*/
|
||||||
|
AdminApp.prototype.remote = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oRemote)
|
||||||
|
{
|
||||||
|
this.oRemote = new AdminAjaxRemoteStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oRemote;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {AdminCacheStorage}
|
||||||
|
*/
|
||||||
|
AdminApp.prototype.cache = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oCache)
|
||||||
|
{
|
||||||
|
this.oCache = new AdminCacheStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminApp.prototype.reloadDomainList = function ()
|
||||||
|
{
|
||||||
|
RL.data().domainsLoading(true);
|
||||||
|
RL.remote().domainList(function (sResult, oData) {
|
||||||
|
RL.data().domainsLoading(false);
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
var aList = _.map(oData.Result, function (bEnabled, sName) {
|
||||||
|
return {
|
||||||
|
'name': sName,
|
||||||
|
'disabled': ko.observable(!bEnabled),
|
||||||
|
'deleteAccess': ko.observable(false)
|
||||||
|
};
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
RL.data().domains(aList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminApp.prototype.reloadPluginList = function ()
|
||||||
|
{
|
||||||
|
RL.data().pluginsLoading(true);
|
||||||
|
RL.remote().pluginList(function (sResult, oData) {
|
||||||
|
RL.data().pluginsLoading(false);
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
var aList = _.map(oData.Result, function (oItem) {
|
||||||
|
return {
|
||||||
|
'name': oItem['Name'],
|
||||||
|
'disabled': ko.observable(!oItem['Enabled']),
|
||||||
|
'configured': ko.observable(!!oItem['Configured'])
|
||||||
|
};
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
RL.data().plugins(aList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminApp.prototype.reloadPackagesList = function ()
|
||||||
|
{
|
||||||
|
RL.data().packagesLoading(true);
|
||||||
|
RL.data().packagesReal(true);
|
||||||
|
|
||||||
|
RL.remote().packagesList(function (sResult, oData) {
|
||||||
|
|
||||||
|
RL.data().packagesLoading(false);
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
RL.data().packagesReal(!!oData.Result.Real);
|
||||||
|
RL.data().packagesMainUpdatable(!!oData.Result.MainUpdatable);
|
||||||
|
|
||||||
|
var
|
||||||
|
aList = [],
|
||||||
|
aLoading = {}
|
||||||
|
;
|
||||||
|
|
||||||
|
_.each(RL.data().packages(), function (oItem) {
|
||||||
|
if (oItem && oItem['loading']())
|
||||||
|
{
|
||||||
|
aLoading[oItem['file']] = oItem;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Utils.isArray(oData.Result.List))
|
||||||
|
{
|
||||||
|
aList = _.compact(_.map(oData.Result.List, function (oItem) {
|
||||||
|
if (oItem)
|
||||||
|
{
|
||||||
|
oItem['loading'] = ko.observable(!Utils.isUnd(aLoading[oItem['file']]));
|
||||||
|
return 'core' === oItem['type'] && !oItem['canBeInstalled'] ? null : oItem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.data().packages(aList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RL.data().packagesReal(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {boolean=} bForce = false
|
||||||
|
*/
|
||||||
|
AdminApp.prototype.reloadLicensing = function (bForce)
|
||||||
|
{
|
||||||
|
bForce = Utils.isUnd(bForce) ? false : !!bForce;
|
||||||
|
|
||||||
|
RL.data().licensingProcess(true);
|
||||||
|
RL.data().licenseError('');
|
||||||
|
|
||||||
|
RL.remote().licensing(function (sResult, oData) {
|
||||||
|
RL.data().licensingProcess(false);
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && Utils.isNormal(oData.Result['Expired']))
|
||||||
|
{
|
||||||
|
RL.data().licenseValid(true);
|
||||||
|
RL.data().licenseExpired(Utils.pInt(oData.Result['Expired']));
|
||||||
|
RL.data().licenseError('');
|
||||||
|
|
||||||
|
RL.data().licensing(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (oData && oData.ErrorCode && -1 < Utils.inArray(Utils.pInt(oData.ErrorCode), [
|
||||||
|
Enums.Notification.LicensingServerIsUnavailable,
|
||||||
|
Enums.Notification.LicensingExpired
|
||||||
|
]))
|
||||||
|
{
|
||||||
|
RL.data().licenseError(Utils.getNotification(Utils.pInt(oData.ErrorCode)));
|
||||||
|
RL.data().licensing(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Enums.StorageResultType.Abort === sResult)
|
||||||
|
{
|
||||||
|
RL.data().licenseError(Utils.getNotification(Enums.Notification.LicensingServerIsUnavailable));
|
||||||
|
RL.data().licensing(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RL.data().licensing(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, bForce);
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminApp.prototype.bootstart = function ()
|
||||||
|
{
|
||||||
|
AbstractApp.prototype.bootstart.call(this);
|
||||||
|
|
||||||
|
RL.data().populateDataOnStart();
|
||||||
|
|
||||||
|
kn.hideLoading();
|
||||||
|
|
||||||
|
if (!this.settingsGet('AllowAdminPanel'))
|
||||||
|
{
|
||||||
|
kn.routeOff();
|
||||||
|
kn.setHash(RL.link().root(), true);
|
||||||
|
kn.routeOff();
|
||||||
|
|
||||||
|
_.defer(function () {
|
||||||
|
window.location.href = '/';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!!this.settingsGet('Auth'))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// if (!this.settingsGet('AllowPackages') && AdminPackages)
|
||||||
|
// {
|
||||||
|
// Utils.disableSettingsViewModel(AdminPackages);
|
||||||
|
// }
|
||||||
|
|
||||||
|
kn.startScreens([AdminSettingsScreen]);
|
||||||
|
|
||||||
|
if (!Globals.bMobileDevice)
|
||||||
|
{
|
||||||
|
_.defer(function () {
|
||||||
|
Utils.initLayoutResizer('#rl-top-resizer-left', '#rl-top-resizer-right', '#rl-center',
|
||||||
|
120, 300, 200, 600, Enums.ClientSideKeyName.FolderListSize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kn.startScreens([AdminLoginScreen]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.SimplePace)
|
||||||
|
{
|
||||||
|
window.SimplePace.set(100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {AdminApp}
|
||||||
|
*/
|
||||||
|
RL = new AdminApp();
|
||||||
750
dev/Boots/RainLoopApp.js
Normal file
750
dev/Boots/RainLoopApp.js
Normal file
|
|
@ -0,0 +1,750 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractApp
|
||||||
|
*/
|
||||||
|
function RainLoopApp()
|
||||||
|
{
|
||||||
|
AbstractApp.call(this);
|
||||||
|
|
||||||
|
this.oData = null;
|
||||||
|
this.oRemote = null;
|
||||||
|
this.oCache = null;
|
||||||
|
|
||||||
|
this.iSuggestionsLimit = Utils.pInt(this.settingsGet('SuggestionsLimit'));
|
||||||
|
this.iSuggestionsLimit = 0 === this.iSuggestionsLimit ? 20 : this.iSuggestionsLimit;
|
||||||
|
|
||||||
|
this.quotaDebounce = _.debounce(this.quota, 1000 * 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(RainLoopApp.prototype, AbstractApp.prototype);
|
||||||
|
|
||||||
|
RainLoopApp.prototype.oData = null;
|
||||||
|
RainLoopApp.prototype.oRemote = null;
|
||||||
|
RainLoopApp.prototype.oCache = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {WebMailDataStorage}
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.data = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oData)
|
||||||
|
{
|
||||||
|
this.oData = new WebMailDataStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oData;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {WebMailAjaxRemoteStorage}
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.remote = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oRemote)
|
||||||
|
{
|
||||||
|
this.oRemote = new WebMailAjaxRemoteStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oRemote;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {WebMailCacheStorage}
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.cache = function ()
|
||||||
|
{
|
||||||
|
if (null === this.oCache)
|
||||||
|
{
|
||||||
|
this.oCache = new WebMailCacheStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.oCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.reloadFlagsCurrentMessageListAndMessageFromCache = function ()
|
||||||
|
{
|
||||||
|
var oCache = RL.cache();
|
||||||
|
_.each(RL.data().messageList(), function (oMessage) {
|
||||||
|
oCache.initMessageFlagsFromCache(oMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
oCache.initMessageFlagsFromCache(RL.data().message());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bDropPagePosition = false
|
||||||
|
* @param {boolean=} bDropCurrenFolderCache = false
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.reloadMessageList = function (bDropPagePosition, bDropCurrenFolderCache)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oRLData = RL.data(),
|
||||||
|
iOffset = (oRLData.messageListPage() - 1) * oRLData.messagesPerPage()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Utils.isUnd(bDropCurrenFolderCache) ? false : !!bDropCurrenFolderCache)
|
||||||
|
{
|
||||||
|
RL.cache().setFolderHash(oRLData.currentFolderFullNameRaw(), '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition)
|
||||||
|
{
|
||||||
|
oRLData.messageListPage(1);
|
||||||
|
iOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
oRLData.messageListLoading(true);
|
||||||
|
RL.remote().messageList(function (sResult, oData, bCached) {
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
oRLData.messageListError('');
|
||||||
|
oRLData.messageListLoading(false);
|
||||||
|
oRLData.setMessageList(oData, bCached);
|
||||||
|
}
|
||||||
|
else if (Enums.StorageResultType.Unload === sResult)
|
||||||
|
{
|
||||||
|
oRLData.messageListError('');
|
||||||
|
oRLData.messageListLoading(false);
|
||||||
|
}
|
||||||
|
else if (Enums.StorageResultType.Abort !== sResult)
|
||||||
|
{
|
||||||
|
oRLData.messageList([]);
|
||||||
|
oRLData.messageListLoading(false);
|
||||||
|
oRLData.messageListError(oData && oData.ErrorCode ?
|
||||||
|
Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_GET_MESSAGE_LIST')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, oRLData.currentFolderFullNameRaw(), iOffset, oRLData.messagesPerPage(), oRLData.messageListSearch());
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.recacheInboxMessageList = function ()
|
||||||
|
{
|
||||||
|
RL.remote().messageList(Utils.emptyFunction, 'INBOX', 0, RL.data().messagesPerPage(), '', true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bUseCache = true
|
||||||
|
* @param {Function=} fCallback
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.folders = function (bUseCache, fCallback)
|
||||||
|
{
|
||||||
|
this.data().foldersLoading(true);
|
||||||
|
this.remote().folders(_.bind(function (sResult, oData, bCached) {
|
||||||
|
|
||||||
|
RL.data().foldersLoading(false);
|
||||||
|
if (Enums.StorageResultType.Success === sResult)
|
||||||
|
{
|
||||||
|
this.data().setFolders(oData, bCached);
|
||||||
|
if (fCallback)
|
||||||
|
{
|
||||||
|
fCallback(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fCallback)
|
||||||
|
{
|
||||||
|
fCallback(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this), bUseCache);
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.accountsAndIdentities = function ()
|
||||||
|
{
|
||||||
|
var oRainLoopData = RL.data();
|
||||||
|
|
||||||
|
oRainLoopData.accountsLoading(true);
|
||||||
|
oRainLoopData.identitiesLoading(true);
|
||||||
|
|
||||||
|
RL.remote().accountsAndIdentities(function (sResult, oData) {
|
||||||
|
|
||||||
|
oRainLoopData.accountsLoading(false);
|
||||||
|
oRainLoopData.identitiesLoading(false);
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData.Result)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sParentEmail = RL.settingsGet('ParentEmail'),
|
||||||
|
sAccountEmail = oRainLoopData.accountEmail()
|
||||||
|
;
|
||||||
|
|
||||||
|
sParentEmail = '' === sParentEmail ? sAccountEmail : sParentEmail;
|
||||||
|
|
||||||
|
if (Utils.isArray(oData.Result['Accounts']))
|
||||||
|
{
|
||||||
|
oRainLoopData.accounts(_.map(oData.Result['Accounts'], function (sValue) {
|
||||||
|
return new AccountModel(sValue, sValue !== sParentEmail);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isArray(oData.Result['Identities']))
|
||||||
|
{
|
||||||
|
oRainLoopData.identities(_.map(oData.Result['Identities'], function (oIdentityData) {
|
||||||
|
|
||||||
|
var
|
||||||
|
sId = Utils.pString(oIdentityData['Id']),
|
||||||
|
sEmail = Utils.pString(oIdentityData['Email']),
|
||||||
|
oIdentity = new IdentityModel(sId, sEmail, sId !== sAccountEmail)
|
||||||
|
;
|
||||||
|
|
||||||
|
oIdentity.name(Utils.pString(oIdentityData['Name']));
|
||||||
|
oIdentity.replyTo(Utils.pString(oIdentityData['ReplyTo']));
|
||||||
|
oIdentity.bcc(Utils.pString(oIdentityData['Bcc']));
|
||||||
|
|
||||||
|
return oIdentity;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.quota = function ()
|
||||||
|
{
|
||||||
|
this.remote().quota(function (sResult, oData) {
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result &&
|
||||||
|
Utils.isArray(oData.Result) && 2 === oData.Result.length &&
|
||||||
|
Utils.isPosNumeric(oData.Result[0], true) && Utils.isPosNumeric(oData.Result[1], true))
|
||||||
|
{
|
||||||
|
RL.data().userQuota(Utils.pInt(oData.Result[1]) * 1024);
|
||||||
|
RL.data().userUsageSize(Utils.pInt(oData.Result[0]) * 1024);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {Array=} aList = []
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.folderInformation = function (sFolder, aList)
|
||||||
|
{
|
||||||
|
this.remote().folderInformation(function (sResult, oData) {
|
||||||
|
if (Enums.StorageResultType.Success === sResult)
|
||||||
|
{
|
||||||
|
if (oData && oData.Result && oData.Result.Hash && oData.Result.Folder)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sHash = RL.cache().getFolderHash(oData.Result.Folder),
|
||||||
|
oFolder = RL.cache().getFolderFromCacheList(oData.Result.Folder),
|
||||||
|
bCheck = false,
|
||||||
|
sUid = '',
|
||||||
|
aList = [],
|
||||||
|
bUnreadCountChange = false,
|
||||||
|
oFlags = null
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oFolder)
|
||||||
|
{
|
||||||
|
if (oData.Result.Hash)
|
||||||
|
{
|
||||||
|
RL.cache().setFolderHash(oData.Result.Folder, oData.Result.Hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isNormal(oData.Result.MessageCount))
|
||||||
|
{
|
||||||
|
oFolder.messageCountAll(oData.Result.MessageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isNormal(oData.Result.MessageUnseenCount))
|
||||||
|
{
|
||||||
|
if (Utils.pInt(oFolder.messageCountUnread()) !== Utils.pInt(oData.Result.MessageUnseenCount))
|
||||||
|
{
|
||||||
|
bUnreadCountChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
oFolder.messageCountUnread(oData.Result.MessageUnseenCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bUnreadCountChange)
|
||||||
|
{
|
||||||
|
RL.cache().clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oData.Result.Flags)
|
||||||
|
{
|
||||||
|
for (sUid in oData.Result.Flags)
|
||||||
|
{
|
||||||
|
if (oData.Result.Flags.hasOwnProperty(sUid))
|
||||||
|
{
|
||||||
|
bCheck = true;
|
||||||
|
oFlags = oData.Result.Flags[sUid];
|
||||||
|
RL.cache().storeMessageFlagsToCacheByFolderAndUid(oFolder.fullNameRaw, sUid.toString(), [
|
||||||
|
!oFlags['IsSeen'], !!oFlags['IsFlagged'], !!oFlags['IsAnswered'], !!oFlags['IsForwarded']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bCheck)
|
||||||
|
{
|
||||||
|
RL.reloadFlagsCurrentMessageListAndMessageFromCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.data().initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages);
|
||||||
|
|
||||||
|
if (oData.Result.Hash !== sHash || '' === sHash)
|
||||||
|
{
|
||||||
|
if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw())
|
||||||
|
{
|
||||||
|
RL.reloadMessageList();
|
||||||
|
}
|
||||||
|
else if ('INBOX' === oFolder.fullNameRaw)
|
||||||
|
{
|
||||||
|
RL.recacheInboxMessageList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bUnreadCountChange)
|
||||||
|
{
|
||||||
|
if (oFolder.fullNameRaw === RL.data().currentFolderFullNameRaw())
|
||||||
|
{
|
||||||
|
aList = RL.data().messageList();
|
||||||
|
if (Utils.isNonEmptyArray(aList))
|
||||||
|
{
|
||||||
|
RL.folderInformation(oFolder.fullNameRaw, aList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, sFolder, aList);
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.setMessageSeen = function (oMessage)
|
||||||
|
{
|
||||||
|
if (oMessage.unseen())
|
||||||
|
{
|
||||||
|
oMessage.unseen(false);
|
||||||
|
|
||||||
|
var oFolder = RL.cache().getFolderFromCacheList(oMessage.folderFullNameRaw);
|
||||||
|
if (oFolder)
|
||||||
|
{
|
||||||
|
oFolder.messageCountUnread(0 <= oFolder.messageCountUnread() - 1 ?
|
||||||
|
oFolder.messageCountUnread() - 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.cache().storeMessageFlagsToCache(oMessage);
|
||||||
|
RL.reloadFlagsCurrentMessageListAndMessageFromCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.remote().messageSetSeen(Utils.emptyFunction, oMessage.folderFullNameRaw, [oMessage.uid], true);
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.googleConnect = function ()
|
||||||
|
{
|
||||||
|
window.open(RL.link().socialGoogle(), 'Google', 'left=200,top=100,width=650,height=600,menubar=no,status=no,resizable=yes,scrollbars=yes');
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.twitterConnect = function ()
|
||||||
|
{
|
||||||
|
window.open(RL.link().socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=350,menubar=no,status=no,resizable=yes,scrollbars=yes');
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.facebookConnect = function ()
|
||||||
|
{
|
||||||
|
window.open(RL.link().socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bFireAllActions
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.socialUsers = function (bFireAllActions)
|
||||||
|
{
|
||||||
|
var oRainLoopData = RL.data();
|
||||||
|
|
||||||
|
if (bFireAllActions)
|
||||||
|
{
|
||||||
|
oRainLoopData.googleActions(true);
|
||||||
|
oRainLoopData.facebookActions(true);
|
||||||
|
oRainLoopData.twitterActions(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.remote().socialUsers(function (sResult, oData) {
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
oRainLoopData.googleUserName(oData.Result['Google'] || '');
|
||||||
|
oRainLoopData.facebookUserName(oData.Result['Facebook'] || '');
|
||||||
|
oRainLoopData.twitterUserName(oData.Result['Twitter'] || '');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oRainLoopData.googleUserName('');
|
||||||
|
oRainLoopData.facebookUserName('');
|
||||||
|
oRainLoopData.twitterUserName('');
|
||||||
|
}
|
||||||
|
|
||||||
|
oRainLoopData.googleLoggined('' !== oRainLoopData.googleUserName());
|
||||||
|
oRainLoopData.facebookLoggined('' !== oRainLoopData.facebookUserName());
|
||||||
|
oRainLoopData.twitterLoggined('' !== oRainLoopData.twitterUserName());
|
||||||
|
|
||||||
|
oRainLoopData.googleActions(false);
|
||||||
|
oRainLoopData.facebookActions(false);
|
||||||
|
oRainLoopData.twitterActions(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.googleDisconnect = function ()
|
||||||
|
{
|
||||||
|
RL.data().googleActions(true);
|
||||||
|
RL.remote().googleDisconnect(function () {
|
||||||
|
RL.socialUsers();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.facebookDisconnect = function ()
|
||||||
|
{
|
||||||
|
RL.data().facebookActions(true);
|
||||||
|
RL.remote().facebookDisconnect(function () {
|
||||||
|
RL.socialUsers();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.twitterDisconnect = function ()
|
||||||
|
{
|
||||||
|
RL.data().twitterActions(true);
|
||||||
|
RL.remote().twitterDisconnect(function () {
|
||||||
|
RL.socialUsers();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} aSystem
|
||||||
|
* @param {Array} aList
|
||||||
|
* @param {Array=} aDisabled
|
||||||
|
* @param {Array=} aHeaderLines
|
||||||
|
* @param {?number=} iUnDeep
|
||||||
|
* @param {Function=} fDisableCallback
|
||||||
|
* @param {Function=} fVisibleCallback
|
||||||
|
* @param {Function=} fRenameCallback
|
||||||
|
* @param {boolean=} bSystem
|
||||||
|
* @param {boolean=} bBuildUnvisible
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.folderListOptionsBuilder = function (aSystem, aList, aDisabled, aHeaderLines, iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = 0,
|
||||||
|
/**
|
||||||
|
* @type {?FolderModel}
|
||||||
|
*/
|
||||||
|
oItem = null,
|
||||||
|
sDeepPrefix = '\u00A0\u00A0\u00A0',
|
||||||
|
aResult = []
|
||||||
|
;
|
||||||
|
|
||||||
|
bSystem = !Utils.isNormal(bSystem) ? 0 < aSystem.length : bSystem;
|
||||||
|
bBuildUnvisible = Utils.isUnd(bBuildUnvisible) ? false : !!bBuildUnvisible;
|
||||||
|
iUnDeep = !Utils.isNormal(iUnDeep) ? 0 : iUnDeep;
|
||||||
|
fDisableCallback = Utils.isNormal(fDisableCallback) ? fDisableCallback : null;
|
||||||
|
fVisibleCallback = Utils.isNormal(fVisibleCallback) ? fVisibleCallback : null;
|
||||||
|
fRenameCallback = Utils.isNormal(fRenameCallback) ? fRenameCallback : null;
|
||||||
|
|
||||||
|
if (!Utils.isArray(aDisabled))
|
||||||
|
{
|
||||||
|
aDisabled = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Utils.isArray(aHeaderLines))
|
||||||
|
{
|
||||||
|
aHeaderLines = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iIndex = 0, iLen = aHeaderLines.length; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
aResult.push({
|
||||||
|
'id': aHeaderLines[iIndex][0],
|
||||||
|
'name': aHeaderLines[iIndex][1],
|
||||||
|
'disable': false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iIndex = 0, iLen = aSystem.length; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
oItem = aSystem[iIndex];
|
||||||
|
if (fVisibleCallback ? fVisibleCallback.call(null, oItem) : true)
|
||||||
|
{
|
||||||
|
aResult.push({
|
||||||
|
'id': oItem.fullNameRaw,
|
||||||
|
'system': true,
|
||||||
|
'name': fRenameCallback ? fRenameCallback.call(null, oItem) : oItem.name(),
|
||||||
|
'disable': !oItem.selectable || -1 < Utils.inArray(oItem.fullNameRaw, aDisabled) ||
|
||||||
|
(fDisableCallback ? fDisableCallback.call(null, oItem) : false)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iIndex = 0, iLen = aList.length; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
oItem = aList[iIndex];
|
||||||
|
if (!oItem.isGmailFolder && (oItem.subScribed() || !oItem.existen))
|
||||||
|
{
|
||||||
|
if (fVisibleCallback ? fVisibleCallback.call(null, oItem) : true)
|
||||||
|
{
|
||||||
|
if (Enums.FolderType.User === oItem.type() || !bSystem || (!oItem.isNamespaceFolder && 0 < oItem.subFolders().length))
|
||||||
|
{
|
||||||
|
aResult.push({
|
||||||
|
'id': oItem.fullNameRaw,
|
||||||
|
'system': false,
|
||||||
|
'name': (new window.Array(oItem.deep + 1 - iUnDeep)).join(sDeepPrefix) +
|
||||||
|
(fRenameCallback ? fRenameCallback.call(null, oItem) : oItem.name()),
|
||||||
|
'disable': !oItem.selectable || -1 < Utils.inArray(oItem.fullNameRaw, aDisabled) ||
|
||||||
|
(Enums.FolderType.User !== oItem.type()) ||
|
||||||
|
(fDisableCallback ? fDisableCallback.call(null, oItem) : false)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oItem.subScribed() && 0 < oItem.subFolders().length)
|
||||||
|
{
|
||||||
|
aResult = aResult.concat(RL.folderListOptionsBuilder([], oItem.subFolders(), aDisabled, [],
|
||||||
|
oItem.isUnpaddigFolder ? iUnDeep + 1 : iUnDeep,
|
||||||
|
fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sQuery
|
||||||
|
* @param {number} iPage
|
||||||
|
* @param {Function} fCallback
|
||||||
|
*/
|
||||||
|
RainLoopApp.prototype.getAutocomplete = function (sQuery, iPage, fCallback)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aData = []
|
||||||
|
;
|
||||||
|
|
||||||
|
RL.remote().suggestions(function (sResult, oData) {
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result && Utils.isArray(oData.Result.List))
|
||||||
|
{
|
||||||
|
aData = _.map(oData.Result.List, function (aItem) {
|
||||||
|
return aItem && aItem[0] ? new EmailModel(aItem[0], aItem[1]) : null;
|
||||||
|
});
|
||||||
|
|
||||||
|
fCallback(_.compact(aData), !!oData.Result.More);
|
||||||
|
}
|
||||||
|
else if (Enums.StorageResultType.Abort !== sResult)
|
||||||
|
{
|
||||||
|
fCallback([], false);
|
||||||
|
}
|
||||||
|
}, sQuery, iPage);
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.emailsPicsHashes = function ()
|
||||||
|
{
|
||||||
|
RL.remote().emailsPicsHashes(function (sResult, oData) {
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
RL.cache().setEmailsPicsHashesData(oData.Result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
RainLoopApp.prototype.bootstart = function ()
|
||||||
|
{
|
||||||
|
AbstractApp.prototype.bootstart.call(this);
|
||||||
|
|
||||||
|
RL.data().populateDataOnStart();
|
||||||
|
|
||||||
|
var
|
||||||
|
sCustomLoginLink = '',
|
||||||
|
sJsHash = this.settingsGet('JsHash'),
|
||||||
|
bGoogle = this.settingsGet('AllowGoogleSocial'),
|
||||||
|
bFacebook = this.settingsGet('AllowFacebookSocial'),
|
||||||
|
bTwitter = this.settingsGet('AllowTwitterSocial')
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!this.settingsGet('RemoteChangePassword'))
|
||||||
|
{
|
||||||
|
Utils.removeSettingsViewModel(SettingsChangePasswordScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.settingsGet('AllowAdditionalAccounts'))
|
||||||
|
{
|
||||||
|
Utils.removeSettingsViewModel(SettingsAccounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.settingsGet('AllowIdentities'))
|
||||||
|
{
|
||||||
|
Utils.removeSettingsViewModel(SettingsPersonal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utils.removeSettingsViewModel(SettingsIdentities);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bGoogle && !bFacebook && !bTwitter)
|
||||||
|
{
|
||||||
|
Utils.removeSettingsViewModel(SettingsSocialScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.settingsGet('AllowThemes'))
|
||||||
|
{
|
||||||
|
Utils.removeSettingsViewModel(SettingsThemes);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.initOnStartOrLangChange(function () {
|
||||||
|
|
||||||
|
$.extend(true, $.magnificPopup.defaults, {
|
||||||
|
'tClose': Utils.i18n('MAGNIFIC_POPUP/CLOSE'),
|
||||||
|
'tLoading': Utils.i18n('MAGNIFIC_POPUP/LOADING'),
|
||||||
|
'gallery': {
|
||||||
|
'tPrev': Utils.i18n('MAGNIFIC_POPUP/GALLERY_PREV'),
|
||||||
|
'tNext': Utils.i18n('MAGNIFIC_POPUP/GALLERY_NEXT'),
|
||||||
|
'tCounter': Utils.i18n('MAGNIFIC_POPUP/GALLERY_COUNTER')
|
||||||
|
},
|
||||||
|
'image': {
|
||||||
|
'tError': Utils.i18n('MAGNIFIC_POPUP/IMAGE_ERROR')
|
||||||
|
},
|
||||||
|
'ajax': {
|
||||||
|
'tError': Utils.i18n('MAGNIFIC_POPUP/AJAX_ERROR')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
if (window.SimplePace)
|
||||||
|
{
|
||||||
|
window.SimplePace.set(70);
|
||||||
|
window.SimplePace.sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!this.settingsGet('Auth'))
|
||||||
|
{
|
||||||
|
this.setTitle(Utils.i18n('TITLES/LOADING'));
|
||||||
|
|
||||||
|
this.folders(true, _.bind(function (bValue) {
|
||||||
|
|
||||||
|
kn.hideLoading();
|
||||||
|
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
|
kn.startScreens([MailBoxScreen, SettingsScreen]);
|
||||||
|
|
||||||
|
// setup maito protocol
|
||||||
|
$document.on('mousedown', '#rl-center a', function (oEvent) {
|
||||||
|
if (oEvent && 3 !== oEvent['which'])
|
||||||
|
{
|
||||||
|
var oEmailModel = null, sHref = $(this).attr('href');
|
||||||
|
if (sHref && 'mailto:' === sHref.toString().toLowerCase().substr(0, 7))
|
||||||
|
{
|
||||||
|
oEmailModel = new EmailModel();
|
||||||
|
oEmailModel.parse(window.decodeURI(sHref.toString().substr(7)));
|
||||||
|
if (oEmailModel && oEmailModel.email)
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsComposeViewModel, [Enums.ComposeType.Empty, null, [oEmailModel]]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bGoogle || bFacebook || bTwitter)
|
||||||
|
{
|
||||||
|
RL.socialUsers(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
RL.emailsPicsHashes();
|
||||||
|
|
||||||
|
RL.remote().servicesPics(function (sResult, oData) {
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
RL.cache().setServicesData(oData.Result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
Plugins.runHook('rl-start-user-screens');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kn.startScreens([LoginScreen]);
|
||||||
|
Plugins.runHook('rl-start-login-screens');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.SimplePace)
|
||||||
|
{
|
||||||
|
window.SimplePace.set(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Globals.bMobileDevice)
|
||||||
|
{
|
||||||
|
_.defer(function () {
|
||||||
|
Utils.initLayoutResizer('#rl-top-resizer-left', '#rl-top-resizer-right', '#rl-center',
|
||||||
|
120, 300, 200, 600, Enums.ClientSideKeyName.FolderListSize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}, this));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sCustomLoginLink = Utils.pString(this.settingsGet('CustomLoginLink'));
|
||||||
|
if (!sCustomLoginLink)
|
||||||
|
{
|
||||||
|
kn.hideLoading();
|
||||||
|
kn.startScreens([LoginScreen]);
|
||||||
|
|
||||||
|
Plugins.runHook('rl-start-login-screens');
|
||||||
|
|
||||||
|
if (window.SimplePace)
|
||||||
|
{
|
||||||
|
window.SimplePace.set(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kn.routeOff();
|
||||||
|
kn.setHash(RL.link().root(), true);
|
||||||
|
kn.routeOff();
|
||||||
|
|
||||||
|
_.defer(function () {
|
||||||
|
window.location.href = sCustomLoginLink;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bGoogle)
|
||||||
|
{
|
||||||
|
window['rl_' + sJsHash + '_google_service'] = function () {
|
||||||
|
RL.data().googleActions(true);
|
||||||
|
RL.socialUsers();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bFacebook)
|
||||||
|
{
|
||||||
|
window['rl_' + sJsHash + '_facebook_service'] = function () {
|
||||||
|
RL.data().facebookActions(true);
|
||||||
|
RL.socialUsers();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bTwitter)
|
||||||
|
{
|
||||||
|
window['rl_' + sJsHash + '_twitter_service'] = function () {
|
||||||
|
RL.data().twitterActions(true);
|
||||||
|
RL.socialUsers();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugins.runHook('rl-start-screens');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {RainLoopApp}
|
||||||
|
*/
|
||||||
|
RL = new RainLoopApp();
|
||||||
164
dev/Common/Base64.js
Normal file
164
dev/Common/Base64.js
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
/*jslint bitwise: true*/
|
||||||
|
// Base64 encode / decode
|
||||||
|
// http://www.webtoolkit.info/
|
||||||
|
|
||||||
|
Base64 = {
|
||||||
|
|
||||||
|
// private property
|
||||||
|
_keyStr : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
|
||||||
|
|
||||||
|
// public method for urlsafe encoding
|
||||||
|
urlsafe_encode : function (input) {
|
||||||
|
return Base64.encode(input).replace(/[+]/g, '-').replace(/[\/]/g, '_').replace(/[=]/g, '.');
|
||||||
|
},
|
||||||
|
|
||||||
|
// public method for encoding
|
||||||
|
encode : function (input) {
|
||||||
|
var
|
||||||
|
output = '',
|
||||||
|
chr1, chr2, chr3, enc1, enc2, enc3, enc4,
|
||||||
|
i = 0
|
||||||
|
;
|
||||||
|
|
||||||
|
input = Base64._utf8_encode(input);
|
||||||
|
|
||||||
|
while (i < input.length)
|
||||||
|
{
|
||||||
|
chr1 = input.charCodeAt(i++);
|
||||||
|
chr2 = input.charCodeAt(i++);
|
||||||
|
chr3 = input.charCodeAt(i++);
|
||||||
|
|
||||||
|
enc1 = chr1 >> 2;
|
||||||
|
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||||
|
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||||
|
enc4 = chr3 & 63;
|
||||||
|
|
||||||
|
if (isNaN(chr2))
|
||||||
|
{
|
||||||
|
enc3 = enc4 = 64;
|
||||||
|
}
|
||||||
|
else if (isNaN(chr3))
|
||||||
|
{
|
||||||
|
enc4 = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
output = output +
|
||||||
|
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
|
||||||
|
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
|
||||||
|
// public method for decoding
|
||||||
|
decode : function (input) {
|
||||||
|
var
|
||||||
|
output = '',
|
||||||
|
chr1, chr2, chr3, enc1, enc2, enc3, enc4,
|
||||||
|
i = 0
|
||||||
|
;
|
||||||
|
|
||||||
|
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
|
||||||
|
|
||||||
|
while (i < input.length)
|
||||||
|
{
|
||||||
|
enc1 = this._keyStr.indexOf(input.charAt(i++));
|
||||||
|
enc2 = this._keyStr.indexOf(input.charAt(i++));
|
||||||
|
enc3 = this._keyStr.indexOf(input.charAt(i++));
|
||||||
|
enc4 = this._keyStr.indexOf(input.charAt(i++));
|
||||||
|
|
||||||
|
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||||
|
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||||
|
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||||
|
|
||||||
|
output = output + String.fromCharCode(chr1);
|
||||||
|
|
||||||
|
if (enc3 !== 64)
|
||||||
|
{
|
||||||
|
output = output + String.fromCharCode(chr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc4 !== 64)
|
||||||
|
{
|
||||||
|
output = output + String.fromCharCode(chr3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Base64._utf8_decode(output);
|
||||||
|
},
|
||||||
|
|
||||||
|
// private method for UTF-8 encoding
|
||||||
|
_utf8_encode : function (string) {
|
||||||
|
|
||||||
|
string = string.replace(/\r\n/g, "\n");
|
||||||
|
|
||||||
|
var
|
||||||
|
utftext = '',
|
||||||
|
n = 0,
|
||||||
|
l = string.length,
|
||||||
|
c = 0
|
||||||
|
;
|
||||||
|
|
||||||
|
for (; n < l; n++) {
|
||||||
|
|
||||||
|
c = string.charCodeAt(n);
|
||||||
|
|
||||||
|
if (c < 128)
|
||||||
|
{
|
||||||
|
utftext += String.fromCharCode(c);
|
||||||
|
}
|
||||||
|
else if ((c > 127) && (c < 2048))
|
||||||
|
{
|
||||||
|
utftext += String.fromCharCode((c >> 6) | 192);
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utftext += String.fromCharCode((c >> 12) | 224);
|
||||||
|
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return utftext;
|
||||||
|
},
|
||||||
|
|
||||||
|
// private method for UTF-8 decoding
|
||||||
|
_utf8_decode : function (utftext) {
|
||||||
|
var
|
||||||
|
string = '',
|
||||||
|
i = 0,
|
||||||
|
c = 0,
|
||||||
|
c2 = 0,
|
||||||
|
c3 = 0
|
||||||
|
;
|
||||||
|
|
||||||
|
while ( i < utftext.length )
|
||||||
|
{
|
||||||
|
c = utftext.charCodeAt(i);
|
||||||
|
|
||||||
|
if (c < 128)
|
||||||
|
{
|
||||||
|
string += String.fromCharCode(c);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if((c > 191) && (c < 224))
|
||||||
|
{
|
||||||
|
c2 = utftext.charCodeAt(i+1);
|
||||||
|
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c2 = utftext.charCodeAt(i+1);
|
||||||
|
c3 = utftext.charCodeAt(i+2);
|
||||||
|
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||||
|
i += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*jslint bitwise: false*/
|
||||||
101
dev/Common/Constants.js
Normal file
101
dev/Common/Constants.js
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
Consts.Defaults = {};
|
||||||
|
Consts.Values = {};
|
||||||
|
Consts.DataImages = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Defaults.MessagesPerPage = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
Consts.Defaults.MessagesPerPageArray = [10, 20, 30, 50, 100/*, 150, 200, 300*/];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Defaults.DefaultAjaxTimeout = 20000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Defaults.SearchAjaxTimeout = 120000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Defaults.SendMessageAjaxTimeout = 200000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Defaults.SaveMessageAjaxTimeout = 200000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
Consts.Values.UnuseOptionValue = '__UNUSE__';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
Consts.Values.GmailFolderName = '[Gmail]';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
Consts.Values.ClientSideCookieIndexName = 'rlcsc';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Values.ImapDefaulPort = 143;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Values.ImapDefaulSecurePort = 993;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Values.SmtpDefaulPort = 25;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Values.SmtpDefaulSecurePort = 465;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Consts.Values.iMessageBodyCacheLimit = 15;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
Consts.DataImages.UserDotPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2P8DwQACgAD/il4QJ8AAAAASUVORK5CYII=';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
Consts.DataImages.TranspPic = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII=';
|
||||||
286
dev/Common/Enums.js
Normal file
286
dev/Common/Enums.js
Normal file
|
|
@ -0,0 +1,286 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
Enums.StorageResultType = {
|
||||||
|
'Success': 'success',
|
||||||
|
'Abort': 'abort',
|
||||||
|
'Error': 'error',
|
||||||
|
'Unload': 'unload'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.State = {
|
||||||
|
'Empty': 10,
|
||||||
|
'Login': 20,
|
||||||
|
'Auth': 30
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.StateType = {
|
||||||
|
'Webmail': 0,
|
||||||
|
'Admin': 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.FolderType = {
|
||||||
|
'Inbox': 10,
|
||||||
|
'SentItems': 11,
|
||||||
|
'Draft': 12,
|
||||||
|
'Trash': 13,
|
||||||
|
'Spam': 14,
|
||||||
|
'User': 99
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
Enums.LoginSignMeTypeAsString = {
|
||||||
|
'DefaultOff': 'defaultoff',
|
||||||
|
'DefaultOn': 'defaulton',
|
||||||
|
'Unused': 'unused'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.LoginSignMeType = {
|
||||||
|
'DefaultOff': 0,
|
||||||
|
'DefaultOn': 1,
|
||||||
|
'Unused': 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
Enums.ComposeType = {
|
||||||
|
'Empty': 'empty',
|
||||||
|
'Reply': 'reply',
|
||||||
|
'ReplyAll': 'replyall',
|
||||||
|
'Forward': 'forward',
|
||||||
|
'ForwardAsAttachment': 'forward-as-attachment',
|
||||||
|
'Draft': 'draft'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.UploadErrorCode = {
|
||||||
|
'Normal': 0,
|
||||||
|
'FileIsTooBig': 1,
|
||||||
|
'FilePartiallyUploaded': 2,
|
||||||
|
'FileNoUploaded': 3,
|
||||||
|
'MissingTempFolder': 4,
|
||||||
|
'FileOnSaveingError': 5,
|
||||||
|
'FileType': 98,
|
||||||
|
'Unknown': 99
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.SetSystemFoldersNotification = {
|
||||||
|
'None': 0,
|
||||||
|
'Sent': 1,
|
||||||
|
'Draft': 2,
|
||||||
|
'Spam': 3,
|
||||||
|
'Trash': 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.ClientSideKeyName = {
|
||||||
|
'FoldersLashHash': 0,
|
||||||
|
'MessagesInboxLastHash': 1,
|
||||||
|
'MailBoxListSize': 2,
|
||||||
|
'ExpandedFolders': 3,
|
||||||
|
'FolderListSize': 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.EventKeyCode = {
|
||||||
|
'Backspace': 8,
|
||||||
|
'Enter': 13,
|
||||||
|
'Esc': 27,
|
||||||
|
'PageUp': 33,
|
||||||
|
'PageDown': 34,
|
||||||
|
'Left': 37,
|
||||||
|
'Right': 39,
|
||||||
|
'Up': 38,
|
||||||
|
'Down': 40,
|
||||||
|
'End': 35,
|
||||||
|
'Home': 36,
|
||||||
|
'Insert': 45,
|
||||||
|
'Delete': 46,
|
||||||
|
'A': 65,
|
||||||
|
'S': 83
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.MessageSetAction = {
|
||||||
|
'SetSeen': 0,
|
||||||
|
'UnsetSeen': 1,
|
||||||
|
'SetFlag': 2,
|
||||||
|
'UnsetFlag': 3
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.MessageSelectAction = {
|
||||||
|
'All': 0,
|
||||||
|
'None': 1,
|
||||||
|
'Invert': 2,
|
||||||
|
'Unseen': 3,
|
||||||
|
'Seen': 4,
|
||||||
|
'Flagged': 5,
|
||||||
|
'Unflagged': 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.DesktopNotifications = {
|
||||||
|
'Allowed': 0,
|
||||||
|
'NotAllowed': 1,
|
||||||
|
'Denied': 2,
|
||||||
|
'NotSupported': 9
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.MessagePriority = {
|
||||||
|
'Low': 5,
|
||||||
|
'Normal': 3,
|
||||||
|
'High': 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
Enums.EditorDefaultType = {
|
||||||
|
'Html': 'Html',
|
||||||
|
'Plain': 'Plain'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
Enums.CustomThemeType = {
|
||||||
|
'Light': 'Light',
|
||||||
|
'Dark': 'Dark'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.ServerSecure = {
|
||||||
|
'None': 0,
|
||||||
|
'SSL': 1,
|
||||||
|
'TLS': 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.SearchDateType = {
|
||||||
|
'All': -1,
|
||||||
|
'Days3': 3,
|
||||||
|
'Days7': 7,
|
||||||
|
'Month': 30
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.EmailType = {
|
||||||
|
'Defailt': 0,
|
||||||
|
'Facebook': 1,
|
||||||
|
'Google': 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.SaveSettingsStep = {
|
||||||
|
'Animate': -2,
|
||||||
|
'Idle': -1,
|
||||||
|
'TrueResult': 1,
|
||||||
|
'FalseResult': 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
Enums.InterfaceAnimation = {
|
||||||
|
'None': 'None',
|
||||||
|
'Normal': 'Normal',
|
||||||
|
'Full': 'Full'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
Enums.Notification = {
|
||||||
|
'InvalidToken': 101,
|
||||||
|
'AuthError': 102,
|
||||||
|
'AccessError': 103,
|
||||||
|
'ConnectionError': 104,
|
||||||
|
'CaptchaError': 105,
|
||||||
|
'SocialFacebookLoginAccessDisable': 106,
|
||||||
|
'SocialTwitterLoginAccessDisable': 107,
|
||||||
|
'SocialGoogleLoginAccessDisable': 108,
|
||||||
|
'DomainNotAllowed': 109,
|
||||||
|
'AccountNotAllowed': 110,
|
||||||
|
|
||||||
|
'CantGetMessageList': 201,
|
||||||
|
'CantGetMessage': 202,
|
||||||
|
'CantDeleteMessage': 203,
|
||||||
|
'CantMoveMessage': 204,
|
||||||
|
|
||||||
|
'CantSaveMessage': 301,
|
||||||
|
'CantSendMessage': 302,
|
||||||
|
'InvalidRecipients': 303,
|
||||||
|
|
||||||
|
'CantCreateFolder': 400,
|
||||||
|
'CantRenameFolder': 401,
|
||||||
|
'CantDeleteFolder': 402,
|
||||||
|
'CantSubscribeFolder': 403,
|
||||||
|
'CantUnsubscribeFolder': 404,
|
||||||
|
'CantDeleteNonEmptyFolder': 405,
|
||||||
|
|
||||||
|
'CantSaveSettings': 501,
|
||||||
|
'CantSavePluginSettings': 502,
|
||||||
|
|
||||||
|
'DomainAlreadyExists': 601,
|
||||||
|
|
||||||
|
'CantInstallPackage': 701,
|
||||||
|
'CantDeletePackage': 702,
|
||||||
|
'InvalidPluginPackage': 703,
|
||||||
|
'UnsupportedPluginPackage': 704,
|
||||||
|
|
||||||
|
'LicensingServerIsUnavailable': 710,
|
||||||
|
'LicensingExpired': 711,
|
||||||
|
'LicensingBanned': 712,
|
||||||
|
|
||||||
|
'DemoSendMessageError': 750,
|
||||||
|
|
||||||
|
'AccountAlreadyExists': 801,
|
||||||
|
|
||||||
|
'MailServerError': 901,
|
||||||
|
'UnknownNotification': 999,
|
||||||
|
'UnknownError': 999
|
||||||
|
};
|
||||||
67
dev/Common/Globals.js
Normal file
67
dev/Common/Globals.js
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?}
|
||||||
|
*/
|
||||||
|
Globals.now = (new Date()).getTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?}
|
||||||
|
*/
|
||||||
|
Globals.minuteTick = ko.observable(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?}
|
||||||
|
*/
|
||||||
|
Globals.fiveMinuteTick = ko.observable(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?}
|
||||||
|
*/
|
||||||
|
Globals.langChangeTick = ko.observable(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Globals.iAjaxErrorCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Globals.iTokenErrorCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Globals.iMessageBodyCacheCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
Globals.bUnload = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
Globals.sUserAgent = (navigator.userAgent || '').toLowerCase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
Globals.bIsiOSDevice = -1 < Globals.sUserAgent.indexOf('iphone') || -1 < Globals.sUserAgent.indexOf('ipod') || -1 < Globals.sUserAgent.indexOf('ipad');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
Globals.bIsAndroidDevice = -1 < Globals.sUserAgent.indexOf('android');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
Globals.bMobileDevice = Globals.bIsiOSDevice || Globals.bIsAndroidDevice;
|
||||||
|
|
||||||
|
Globals.bDisableNanoScroll = Globals.bMobileDevice;
|
||||||
|
|
||||||
|
Globals.bAnimationSupported = !Globals.bMobileDevice && $html.hasClass('csstransitions');
|
||||||
|
|
||||||
|
Globals.sAnimationType = '';
|
||||||
897
dev/Common/HtmlEditor.js
Normal file
897
dev/Common/HtmlEditor.js
Normal file
|
|
@ -0,0 +1,897 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function HtmlEditor(oTextAreaElem, oHtmlAreaElem, oToolBarElement, oOptions)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oDefOptions = {
|
||||||
|
'DisableHtml': false,
|
||||||
|
'onSwitch': false,
|
||||||
|
'LangSwitcherConferm': 'EDITOR_TEXT_SWITCHER_CONFIRM',
|
||||||
|
'LangSwitcherTextLabel': 'EDITOR_SWITCHER_TEXT_LABEL',
|
||||||
|
'LangSwitcherHtmlLabel': 'EDITOR_SWITCHER_HTML_LABEL'
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
this.bIe = !!/msie/.test(navigator.userAgent.toLowerCase());
|
||||||
|
|
||||||
|
oOptions = $.extend(oDefOptions, Utils.isUnd(oOptions) ? {} : oOptions);
|
||||||
|
|
||||||
|
this.oOptions = oOptions;
|
||||||
|
this.bOnlyPlain = !!this.oOptions.DisableHtml;
|
||||||
|
this.fOnSwitch = this.oOptions.onSwitch;
|
||||||
|
|
||||||
|
this.textarea = $(oTextAreaElem).empty().addClass('editorTextArea');
|
||||||
|
this.htmlarea = $(oHtmlAreaElem).empty().addClass('editorHtmlArea').prop('contentEditable', 'true');
|
||||||
|
this.toolbar = $(oToolBarElement).empty().addClass('editorToolbar');
|
||||||
|
|
||||||
|
HtmlEditor.htmlInitEditor.apply(this);
|
||||||
|
HtmlEditor.htmlInitToolbar.apply(this);
|
||||||
|
HtmlEditor.htmlAttachEditorEvents.apply(this);
|
||||||
|
|
||||||
|
if (this.bOnlyPlain)
|
||||||
|
{
|
||||||
|
this.toolbar.hide();
|
||||||
|
// this.switchToPlain(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} mA
|
||||||
|
* @param {string} mB
|
||||||
|
* @param {string} mC
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.initLanguage = function (mA, mB, mC)
|
||||||
|
{
|
||||||
|
this.oOptions.LangSwitcherConferm = mA;
|
||||||
|
this.oOptions.LangSwitcherTextLabel = mB;
|
||||||
|
this.oOptions.LangSwitcherHtmlLabel = mC;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} mA
|
||||||
|
* @param {boolean=} mB
|
||||||
|
* @param {string=} mC
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.execCom = function (mA, mB, mC)
|
||||||
|
{
|
||||||
|
if (window.document)
|
||||||
|
{
|
||||||
|
window.document.execCommand(mA, mB || false, mC || null);
|
||||||
|
this.updateTextArea();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.getEditorSelection = function () {
|
||||||
|
var mSelection = null;
|
||||||
|
if (window.getSelection)
|
||||||
|
{
|
||||||
|
mSelection = window.getSelection();
|
||||||
|
}
|
||||||
|
else if (window.document.getSelection)
|
||||||
|
{
|
||||||
|
mSelection = window.document.getSelection();
|
||||||
|
}
|
||||||
|
else if (window.document.selection)
|
||||||
|
{
|
||||||
|
mSelection = window.document.selection;
|
||||||
|
}
|
||||||
|
return mSelection;
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.getEditorRange = function () {
|
||||||
|
var oSelection = this.getEditorSelection();
|
||||||
|
if (!oSelection || 0 === oSelection.rangeCount)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (oSelection.getRangeAt) ? oSelection.getRangeAt(0) : oSelection.createRange();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} mA
|
||||||
|
* @param {boolean=} mB
|
||||||
|
* @param {string=} mC
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.ec = function (mA, mB, mC)
|
||||||
|
{
|
||||||
|
this.execCom(mA, mB, mC);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} iHeading
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.heading = function (iHeading)
|
||||||
|
{
|
||||||
|
this.ec('formatblock', false, (this.bIe) ? 'Heading ' + iHeading : 'h' + iHeading);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sSrc
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.insertImage = function (sSrc)
|
||||||
|
{
|
||||||
|
if (this.isHtml() && !this.bOnlyPlain)
|
||||||
|
{
|
||||||
|
this.htmlarea.focus();
|
||||||
|
this.ec('insertImage', false, sSrc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.focus = function ()
|
||||||
|
{
|
||||||
|
if (this.isHtml() && !this.bOnlyPlain)
|
||||||
|
{
|
||||||
|
this.htmlarea.focus();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.textarea.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sType
|
||||||
|
* @param {string} sColor
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.setcolor = function (sType, sColor)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oRange = null,
|
||||||
|
sCmd = ''
|
||||||
|
;
|
||||||
|
|
||||||
|
if (this.bIe && !document['addEventListener'])
|
||||||
|
{
|
||||||
|
oRange = this.getEditorRange();
|
||||||
|
if (oRange)
|
||||||
|
{
|
||||||
|
oRange.execCommand(('forecolor' === sType) ? 'ForeColor' : 'BackColor', false, sColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this.bIe)
|
||||||
|
{
|
||||||
|
sCmd = ('forecolor' === sType) ? 'ForeColor' : 'BackColor';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sCmd = ('forecolor' === sType) ? 'foreColor' : 'backColor';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ec(sCmd, false, sColor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.isHtml = function ()
|
||||||
|
{
|
||||||
|
return (true === this.bOnlyPlain) ? false : this.textarea.is(':hidden');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.toHtmlString = function ()
|
||||||
|
{
|
||||||
|
return this.editor.innerHTML;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.toString = function ()
|
||||||
|
{
|
||||||
|
return this.editor.innerText;
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.updateTextArea = function ()
|
||||||
|
{
|
||||||
|
this.textarea.val(this.toHtmlString());
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.updateHtmlArea = function ()
|
||||||
|
{
|
||||||
|
this.editor.innerHTML = this.textarea.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sInnerText
|
||||||
|
* @param {boolean} bIsHtml
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.setRawText = function (sInnerText, bIsHtml)
|
||||||
|
{
|
||||||
|
if (bIsHtml && !this.bOnlyPlain)
|
||||||
|
{
|
||||||
|
if (!this.isHtml())
|
||||||
|
{
|
||||||
|
this.textarea.val('');
|
||||||
|
this.switchToHtml();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.textarea.val(sInnerText.toString());
|
||||||
|
this.updateHtmlArea();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.textarea.val(sInnerText.toString());
|
||||||
|
this.updateHtmlArea();
|
||||||
|
this.switchToPlain(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.clear = function ()
|
||||||
|
{
|
||||||
|
this.textarea.val('');
|
||||||
|
this.editor.innerHTML = '';
|
||||||
|
|
||||||
|
if (this.bOnlyPlain)
|
||||||
|
{
|
||||||
|
this.toolbar.hide();
|
||||||
|
this.switchToPlain(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.switchToHtml();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.getTextForRequest = function ()
|
||||||
|
{
|
||||||
|
if (this.isHtml())
|
||||||
|
{
|
||||||
|
this.updateTextArea();
|
||||||
|
return this.textarea.val();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.textarea.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bWrap
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.getTextFromHtml = function (bWrap)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sText = '',
|
||||||
|
sQuoteChar = '> ',
|
||||||
|
|
||||||
|
convertBlockquote = function () {
|
||||||
|
if (arguments && 1 < arguments.length)
|
||||||
|
{
|
||||||
|
var sText = Utils.trim(arguments[1])
|
||||||
|
.replace(/__bq__start__([\s\S\n\r]*)__bq__end__/gm, convertBlockquote)
|
||||||
|
;
|
||||||
|
|
||||||
|
sText = '\n' + sQuoteChar + Utils.trim(sText).replace(/\n/gm, '\n' + sQuoteChar) + '\n>\n';
|
||||||
|
|
||||||
|
return sText.replace(/\n([> ]+)/gm, function () {
|
||||||
|
return (arguments && 1 < arguments.length) ? '\n' + Utils.trim(arguments[1].replace(/[\s]/, '')) + ' ' : '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
convertDivs = function () {
|
||||||
|
if (arguments && 1 < arguments.length)
|
||||||
|
{
|
||||||
|
var sText = Utils.trim(arguments[1]);
|
||||||
|
if (0 < sText.length)
|
||||||
|
{
|
||||||
|
sText = sText.replace(/<div[^>]*>([\s\S]*)<\/div>/gmi, convertDivs);
|
||||||
|
sText = '\n' + Utils.trim(sText) + '\n';
|
||||||
|
}
|
||||||
|
return sText;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
convertLinks = function () {
|
||||||
|
if (arguments && 1 < arguments.length)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sName = Utils.trim(arguments[1])
|
||||||
|
// sHref = Utils.trim(arguments[0].replace(/<a [\s\S]*href[ ]?=[ ]?["']?([^"']+).+<\/a>/gmi, '$1'))
|
||||||
|
;
|
||||||
|
|
||||||
|
return sName;
|
||||||
|
// sName = (0 === Utils.trim(sName).length) ? '' : sName;
|
||||||
|
// sHref = ('mailto:' === sHref.substr(0, 7)) ? '' : sHref;
|
||||||
|
// sHref = ('http' === sHref.substr(0, 4)) ? sHref : '';
|
||||||
|
// sHref = (sName === sHref) ? '' : sHref;
|
||||||
|
// sHref = (0 < sHref.length) ? ' (' + sHref + ') ' : '';
|
||||||
|
// return (0 < sName.length) ? sName + sHref : sName;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
bWrap = Utils.isUnd(bWrap) ? true : !!bWrap;
|
||||||
|
|
||||||
|
sText = this.toHtmlString()
|
||||||
|
.replace(/[\s]+/gm, ' ')
|
||||||
|
.replace(/<br\s?\/?>/gmi, '\n')
|
||||||
|
.replace(/<\/h\d>/gi, '\n')
|
||||||
|
.replace(/<\/p>/gi, '\n\n')
|
||||||
|
.replace(/<\/li>/gi, '\n')
|
||||||
|
.replace(/<\/td>/gi, '\n')
|
||||||
|
.replace(/<\/tr>/gi, '\n')
|
||||||
|
.replace(/<hr[^>]*>/gmi, '\n_______________________________\n\n')
|
||||||
|
.replace(/<img [^>]*>/gmi, '')
|
||||||
|
.replace(/<div[^>]*>([\s\S]*)<\/div>/gmi, convertDivs)
|
||||||
|
.replace(/<blockquote[^>]*>/gmi, '\n__bq__start__\n')
|
||||||
|
.replace(/<\/blockquote>/gmi, '\n__bq__end__\n')
|
||||||
|
.replace(/<a [^>]*>([\s\S]*?)<\/a>/gmi, convertLinks)
|
||||||
|
.replace(/ /gi, ' ')
|
||||||
|
.replace(/<[^>]*>/gm, '')
|
||||||
|
.replace(/>/gi, '>')
|
||||||
|
.replace(/</gi, '<')
|
||||||
|
.replace(/&/gi, '&')
|
||||||
|
.replace(/&\w{2,6};/gi, '')
|
||||||
|
;
|
||||||
|
|
||||||
|
return (bWrap ? Utils.splitPlainText(sText) : sText)
|
||||||
|
.replace(/\n[ \t]+/gm, '\n')
|
||||||
|
.replace(/[\n]{3,}/gm, '\n\n')
|
||||||
|
.replace(/__bq__start__([\s\S]*)__bq__end__/gm, convertBlockquote)
|
||||||
|
.replace(/__bq__start__/gm, '')
|
||||||
|
.replace(/__bq__end__/gm, '')
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.getHtmlFromText = function ()
|
||||||
|
{
|
||||||
|
return Utils.convertPlainTextToHtml(this.textarea.val());
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.switchToggle = function ()
|
||||||
|
{
|
||||||
|
if (this.isHtml())
|
||||||
|
{
|
||||||
|
this.switchToPlain();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.switchToHtml();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bWithConfirm
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.switchToPlain = function (bWithConfirm)
|
||||||
|
{
|
||||||
|
bWithConfirm = Utils.isUnd(bWithConfirm) ? true : bWithConfirm;
|
||||||
|
|
||||||
|
var
|
||||||
|
sText = this.getTextFromHtml(),
|
||||||
|
fSwitch = _.bind(function (bValue) {
|
||||||
|
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
|
this.toolbar.addClass('editorHideToolbar');
|
||||||
|
$('.editorSwitcher', this.toolbar).text(this.switcherLinkText(false));
|
||||||
|
|
||||||
|
this.textarea.val(sText);
|
||||||
|
this.textarea.show();
|
||||||
|
// this.textarea.css({'display': ''});
|
||||||
|
this.htmlarea.hide();
|
||||||
|
if (this.fOnSwitch)
|
||||||
|
{
|
||||||
|
this.fOnSwitch(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, this)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!bWithConfirm || 0 === Utils.trim(sText).length)
|
||||||
|
{
|
||||||
|
fSwitch(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fSwitch(window.confirm(this.oOptions.LangSwitcherConferm));
|
||||||
|
// Utils.dialogConfirm(this.oOptions.LangSwitcherConferm, fSwitch);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} bIsPlain
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.switcherLinkText = function (bIsPlain)
|
||||||
|
{
|
||||||
|
return (bIsPlain) ? this.oOptions.LangSwitcherTextLabel : this.oOptions.LangSwitcherHtmlLabel;
|
||||||
|
// return (bIsPlain) ? '« ' + 'EDITOR_TEXT_SWITCHER_PLAINT_TEXT' : 'EDITOR_TEXT_SWITCHER_RICH_FORMATTING' + ' »';
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.prototype.switchToHtml = function ()
|
||||||
|
{
|
||||||
|
this.toolbar.removeClass('editorHideToolbar');
|
||||||
|
$('.editorSwitcher', this.toolbar).text(this.switcherLinkText(true));
|
||||||
|
|
||||||
|
this.textarea.val(this.getHtmlFromText());
|
||||||
|
this.updateHtmlArea();
|
||||||
|
this.textarea.hide();
|
||||||
|
this.htmlarea.show();
|
||||||
|
// this.htmlarea.css({'display': ''});
|
||||||
|
|
||||||
|
if (this.fOnSwitch)
|
||||||
|
{
|
||||||
|
this.fOnSwitch(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {string} sTitle
|
||||||
|
*/
|
||||||
|
HtmlEditor.prototype.addButton = function (sName, sTitle)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
$('<div />').addClass('editorToolbarButtom').append($('<a tabindex="-1" href="javascript:void(0);"></a>').addClass(sName)).attr('title', sTitle).click(function (oEvent) {
|
||||||
|
if (!Utils.isUnd(HtmlEditor.htmlFunctions[sName]))
|
||||||
|
{
|
||||||
|
HtmlEditor.htmlFunctions[sName].apply(self, [$(this), oEvent]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.alert(sName);
|
||||||
|
}
|
||||||
|
}).appendTo(this.toolbar);
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.htmlInitToolbar = function ()
|
||||||
|
{
|
||||||
|
if (!this.bOnlyPlain)
|
||||||
|
{
|
||||||
|
// this.addButton('fontname', 'Select font');
|
||||||
|
this.addButton('bold', 'Bold');
|
||||||
|
this.addButton('italic', 'Italic');
|
||||||
|
this.addButton('underline', 'Underline');
|
||||||
|
this.addButton('strikethrough', 'Strikethrough');
|
||||||
|
|
||||||
|
this.addButton('removeformat', 'removeformat');
|
||||||
|
|
||||||
|
this.addButton('justifyleft', 'justifyleft');
|
||||||
|
this.addButton('justifycenter', 'justifycenter');
|
||||||
|
this.addButton('justifyright', 'justifyright');
|
||||||
|
|
||||||
|
this.addButton('horizontalrule', 'horizontalrule');
|
||||||
|
|
||||||
|
this.addButton('orderedlist', 'orderedlist');
|
||||||
|
this.addButton('unorderedlist', 'unorderedlist');
|
||||||
|
|
||||||
|
this.addButton('indent', 'indent');
|
||||||
|
this.addButton('outdent', 'outdent');
|
||||||
|
|
||||||
|
this.addButton('forecolor', 'forecolor');
|
||||||
|
// this.addButton('backcolor', 'backcolor');
|
||||||
|
|
||||||
|
(function ($, that) {
|
||||||
|
|
||||||
|
$('<span />').addClass('editorSwitcher').text(that.switcherLinkText(true)).click(function () {
|
||||||
|
that.switchToggle();
|
||||||
|
}).appendTo(that.toolbar);
|
||||||
|
|
||||||
|
}($, this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.htmlInitEditor = function ()
|
||||||
|
{
|
||||||
|
this.editor = this.htmlarea[0];
|
||||||
|
this.editor.innerHTML = this.textarea.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.htmlAttachEditorEvents = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
|
||||||
|
fIsImage = function (oItem) {
|
||||||
|
return oItem && oItem.type && 0 === oItem.type.indexOf('image/');
|
||||||
|
},
|
||||||
|
|
||||||
|
// fUpdateHtmlArea = function () {
|
||||||
|
// self.updateHtmlArea();
|
||||||
|
// },
|
||||||
|
//
|
||||||
|
// fUpdateTextArea = function () {
|
||||||
|
// self.updateTextArea();
|
||||||
|
// },
|
||||||
|
|
||||||
|
fHandleFileSelect = function (oEvent) {
|
||||||
|
|
||||||
|
oEvent = (oEvent && oEvent.originalEvent ?
|
||||||
|
oEvent.originalEvent : oEvent) || window.event;
|
||||||
|
|
||||||
|
if (oEvent)
|
||||||
|
{
|
||||||
|
oEvent.stopPropagation();
|
||||||
|
oEvent.preventDefault();
|
||||||
|
|
||||||
|
var
|
||||||
|
oReader = null,
|
||||||
|
oFile = null,
|
||||||
|
aFiles = (oEvent.files || (oEvent.dataTransfer ? oEvent.dataTransfer.files : null))
|
||||||
|
;
|
||||||
|
|
||||||
|
if (aFiles && 1 === aFiles.length && fIsImage(aFiles[0]))
|
||||||
|
{
|
||||||
|
oFile = aFiles[0];
|
||||||
|
|
||||||
|
oReader = new window.FileReader();
|
||||||
|
oReader.onload = (function (oLocalFile) {
|
||||||
|
return function (oEvent) {
|
||||||
|
self.insertImage(oEvent.target.result, oLocalFile.name);
|
||||||
|
};
|
||||||
|
}(oFile));
|
||||||
|
|
||||||
|
oReader.readAsDataURL(oFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.htmlarea.removeClass('editorDragOver');
|
||||||
|
},
|
||||||
|
|
||||||
|
fHandleDragLeave = function () {
|
||||||
|
self.htmlarea.removeClass('editorDragOver');
|
||||||
|
},
|
||||||
|
|
||||||
|
fHandleDragOver = function (oEvent) {
|
||||||
|
oEvent.stopPropagation();
|
||||||
|
oEvent.preventDefault();
|
||||||
|
|
||||||
|
self.htmlarea.addClass('editorDragOver');
|
||||||
|
},
|
||||||
|
|
||||||
|
fHandlePaste = function (oEvent) {
|
||||||
|
|
||||||
|
var oClipboardData = oEvent && oEvent.clipboardData ? oEvent.clipboardData :
|
||||||
|
(oEvent && oEvent.originalEvent && oEvent.originalEvent.clipboardData ? oEvent.originalEvent.clipboardData : null);
|
||||||
|
|
||||||
|
if (oClipboardData && oClipboardData.items)
|
||||||
|
{
|
||||||
|
_.each(oClipboardData.items, function (oItem) {
|
||||||
|
if (fIsImage(oItem) && oItem['getAsFile']) {
|
||||||
|
var oReader = null, oFile = oItem['getAsFile']();
|
||||||
|
if (oFile)
|
||||||
|
{
|
||||||
|
oReader = new window.FileReader();
|
||||||
|
oReader.onload = (function (oLocalFile) {
|
||||||
|
return function (oEvent) {
|
||||||
|
self.insertImage(oEvent.target.result, oLocalFile.name);
|
||||||
|
};
|
||||||
|
}(oFile));
|
||||||
|
|
||||||
|
oReader.readAsDataURL(oFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!this.bOnlyPlain)
|
||||||
|
{
|
||||||
|
// this.textarea.on('click keyup keydown mousedown blur', fUpdateHtmlArea);
|
||||||
|
// this.htmlarea.on('click keyup keydown mousedown blur', fUpdateTextArea);
|
||||||
|
//
|
||||||
|
if (window.File && window.FileReader && window.FileList)
|
||||||
|
{
|
||||||
|
this.htmlarea.bind('dragover', fHandleDragOver);
|
||||||
|
this.htmlarea.bind('dragleave', fHandleDragLeave);
|
||||||
|
this.htmlarea.bind('drop', fHandleFileSelect);
|
||||||
|
this.htmlarea.bind('paste', fHandlePaste);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HtmlEditor.htmlColorPickerColors = (function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
aMaps = [],
|
||||||
|
aColors = [],
|
||||||
|
iIndex = 0,
|
||||||
|
iIndexSub = 0,
|
||||||
|
iIndexSubSub = 0,
|
||||||
|
iLen = 0,
|
||||||
|
sMap = ''
|
||||||
|
;
|
||||||
|
|
||||||
|
for (iIndex = 0; iIndex < 256; iIndex += 85)
|
||||||
|
{
|
||||||
|
sMap = iIndex.toString(16);
|
||||||
|
aMaps.push(1 === sMap.length ? '0' + sMap : sMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
iLen = aMaps.length;
|
||||||
|
for (iIndex = 0; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
for (iIndexSub = 0; iIndexSub < iLen; iIndexSub++)
|
||||||
|
{
|
||||||
|
for (iIndexSubSub = 0; iIndexSubSub < iLen; iIndexSubSub++)
|
||||||
|
{
|
||||||
|
aColors.push('#' + aMaps[iIndex] + '' + aMaps[iIndexSub] + '' + aMaps[iIndexSubSub]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aColors;
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
HtmlEditor.htmlFontPicker = (function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
jqDoc = $(window.document),
|
||||||
|
bIsAppented = false,
|
||||||
|
oFontPickerHolder = $('<div style="position: absolute;" class="editorFontStylePicker"><div class="editorFpFonts"></div></div>'),
|
||||||
|
oFonts = oFontPickerHolder.find('.editorFpFonts'),
|
||||||
|
fCurrentFunc = function () {}
|
||||||
|
;
|
||||||
|
|
||||||
|
$.each(['Arial', 'Arial Black', 'Courier New', 'Tahoma', 'Times New Roman', 'Verdana'], function (iIndex, sFont) {
|
||||||
|
oFonts.append(
|
||||||
|
$('<a href="javascript:void(0);" tabindex="-1" class="editorFpFont" style="font-family: ' + sFont + ';">' + sFont + '</a>').click(function () {
|
||||||
|
fCurrentFunc(sFont);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
oFonts.append('<br />');
|
||||||
|
});
|
||||||
|
|
||||||
|
oFontPickerHolder.hide();
|
||||||
|
|
||||||
|
return function (oClickObject, fSelectFunc, oTollbar) {
|
||||||
|
|
||||||
|
if (!bIsAppented)
|
||||||
|
{
|
||||||
|
oFontPickerHolder.appendTo(oTollbar);
|
||||||
|
bIsAppented = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fCurrentFunc = fSelectFunc;
|
||||||
|
|
||||||
|
jqDoc.unbind('click.fpNamespace');
|
||||||
|
window.setTimeout(function () {
|
||||||
|
jqDoc.one('click.fpNamespace', function () {
|
||||||
|
oFontPickerHolder.hide();
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
var oPos = $(oClickObject).position();
|
||||||
|
oFontPickerHolder
|
||||||
|
.css('top', (5 + oPos.top + $(oClickObject).height()) + 'px')
|
||||||
|
.css('left', oPos.left + 'px')
|
||||||
|
.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
HtmlEditor.htmlColorPicker = (function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
jqDoc = $(window.document),
|
||||||
|
bIsAppented = false,
|
||||||
|
oColorPickerHolder = $('<div style="position: absolute;" class="editorColorPicker"><div class="editorCpColors"></div></div>'),
|
||||||
|
oColors = oColorPickerHolder.find('.editorCpColors'),
|
||||||
|
fCurrentFunc = function () {}
|
||||||
|
;
|
||||||
|
|
||||||
|
$.each(HtmlEditor.htmlColorPickerColors, function (iIndex, sColor) {
|
||||||
|
oColors.append('<a href="javascript:void(0);" tabindex="-1" class="editorCpColor" style="background-color: ' + sColor + ';"></a>');
|
||||||
|
});
|
||||||
|
|
||||||
|
oColorPickerHolder.hide();
|
||||||
|
|
||||||
|
$('.editorCpColor', oColors).click(function (oEvent) {
|
||||||
|
|
||||||
|
var
|
||||||
|
iIndex = 1,
|
||||||
|
sSelectedColor = '#000000',
|
||||||
|
sRgbString = $(oEvent.target).css('background-color'),
|
||||||
|
aParts = sRgbString.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (aParts !== null)
|
||||||
|
{
|
||||||
|
delete (aParts[0]);
|
||||||
|
for (; iIndex <= 3; ++iIndex)
|
||||||
|
{
|
||||||
|
aParts[iIndex] = Utils.pInt(aParts[iIndex]).toString(16);
|
||||||
|
if (1 === aParts[iIndex].length)
|
||||||
|
{
|
||||||
|
aParts[iIndex] = '0' + aParts[iIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sSelectedColor = '#' + aParts.join('');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sSelectedColor = sRgbString;
|
||||||
|
}
|
||||||
|
|
||||||
|
fCurrentFunc(sSelectedColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
return function (oClickObject, fSelectFunc, oTollbar) {
|
||||||
|
|
||||||
|
if (!bIsAppented)
|
||||||
|
{
|
||||||
|
oColorPickerHolder.appendTo(oTollbar);
|
||||||
|
bIsAppented = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var oPos = $(oClickObject).position();
|
||||||
|
fCurrentFunc = fSelectFunc;
|
||||||
|
|
||||||
|
jqDoc.unbind('click.cpNamespace');
|
||||||
|
window.setTimeout(function () {
|
||||||
|
jqDoc.one('click.cpNamespace', function () {
|
||||||
|
oColorPickerHolder.hide();
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
oColorPickerHolder
|
||||||
|
.css('top', (5 + oPos.top + $(oClickObject).height()) + 'px')
|
||||||
|
.css('left', oPos.left + 'px')
|
||||||
|
.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
||||||
|
|
||||||
|
/* ----------- */
|
||||||
|
|
||||||
|
HtmlEditor.htmlFunctions = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'bold': function ()
|
||||||
|
{
|
||||||
|
this.ec('bold');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'italic': function ()
|
||||||
|
{
|
||||||
|
this.ec('italic');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'underline': function ()
|
||||||
|
{
|
||||||
|
this.ec('underline');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'strikethrough': function ()
|
||||||
|
{
|
||||||
|
this.ec('strikethrough');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'indent': function ()
|
||||||
|
{
|
||||||
|
this.ec('indent');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'outdent': function ()
|
||||||
|
{
|
||||||
|
this.ec('outdent');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'justifyleft': function ()
|
||||||
|
{
|
||||||
|
this.ec('justifyLeft');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'justifycenter': function ()
|
||||||
|
{
|
||||||
|
this.ec('justifyCenter');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'justifyright': function ()
|
||||||
|
{
|
||||||
|
this.ec('justifyRight');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'horizontalrule': function ()
|
||||||
|
{
|
||||||
|
this.ec('insertHorizontalRule', false, 'ht');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'removeformat': function ()
|
||||||
|
{
|
||||||
|
this.ec('removeFormat');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'orderedlist': function ()
|
||||||
|
{
|
||||||
|
this.ec('insertorderedlist');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'unorderedlist': function ()
|
||||||
|
{
|
||||||
|
this.ec('insertunorderedlist');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'forecolor': function (oClickObject)
|
||||||
|
{
|
||||||
|
HtmlEditor.htmlColorPicker(oClickObject, _.bind(function (sValue) {
|
||||||
|
this.setcolor('forecolor', sValue);
|
||||||
|
}, this), this.toolbar);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'backcolor': function (oClickObject)
|
||||||
|
{
|
||||||
|
HtmlEditor.htmlColorPicker(oClickObject, _.bind(function (sValue) {
|
||||||
|
this.setcolor('backcolor', sValue);
|
||||||
|
}, this), this.toolbar);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {HtmlEditor}
|
||||||
|
*/
|
||||||
|
'fontname': function (oClickObject)
|
||||||
|
{
|
||||||
|
HtmlEditor.htmlFontPicker(oClickObject, _.bind(function (sValue) {
|
||||||
|
this.ec('fontname', false, sValue);
|
||||||
|
}, this), this.toolbar);
|
||||||
|
}
|
||||||
|
};
|
||||||
787
dev/Common/Knockout.js
Normal file
787
dev/Common/Knockout.js
Normal file
|
|
@ -0,0 +1,787 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
ko.bindingHandlers.tooltip = {
|
||||||
|
'init': function (oElement, fValueAccessor) {
|
||||||
|
if (!Globals.bMobileDevice)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sClass = $(oElement).data('tooltip-class') || '',
|
||||||
|
sPlacement = $(oElement).data('tooltip-placement') || 'top'
|
||||||
|
;
|
||||||
|
|
||||||
|
$(oElement).tooltip({
|
||||||
|
'delay': {
|
||||||
|
'show': 500,
|
||||||
|
'hide': 100
|
||||||
|
},
|
||||||
|
'html': true,
|
||||||
|
'placement': sPlacement,
|
||||||
|
'trigger': 'hover',
|
||||||
|
'title': function () {
|
||||||
|
return '<span class="tooltip-class ' + sClass + '">' +
|
||||||
|
Utils.i18n(ko.utils.unwrapObservable(fValueAccessor())) + '</span>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.tooltip2 = {
|
||||||
|
'init': function (oElement, fValueAccessor) {
|
||||||
|
var
|
||||||
|
sClass = $(oElement).data('tooltip-class') || '',
|
||||||
|
sPlacement = $(oElement).data('tooltip-placement') || 'top'
|
||||||
|
;
|
||||||
|
$(oElement).tooltip({
|
||||||
|
'delay': {
|
||||||
|
'show': 500,
|
||||||
|
'hide': 100
|
||||||
|
},
|
||||||
|
'html': true,
|
||||||
|
'placement': sPlacement,
|
||||||
|
'title': function () {
|
||||||
|
return '<span class="tooltip-class ' + sClass + '">' + fValueAccessor()() + '</span>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.dropdown = {
|
||||||
|
'init': function (oElement) {
|
||||||
|
$(oElement).closest('.dropdown').on('click', '.e-item', function () {
|
||||||
|
$(oElement).dropdown('toggle');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.popover = {
|
||||||
|
'init': function (oElement, fValueAccessor) {
|
||||||
|
$(oElement).popover(ko.utils.unwrapObservable(fValueAccessor()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.resizecrop = {
|
||||||
|
'init': function (oElement) {
|
||||||
|
$(oElement).addClass('resizecrop').resizecrop({
|
||||||
|
'width': '100',
|
||||||
|
'height': '100',
|
||||||
|
'wrapperCSS': {
|
||||||
|
'border-radius': '10px'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
fValueAccessor()();
|
||||||
|
$(oElement).resizecrop({
|
||||||
|
'width': '100',
|
||||||
|
'height': '100'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.onEnter = {
|
||||||
|
'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
|
||||||
|
$(oElement).on('keypress', function (oEvent) {
|
||||||
|
if (oEvent && 13 === window.parseInt(oEvent.keyCode, 10))
|
||||||
|
{
|
||||||
|
$(oElement).trigger('change');
|
||||||
|
fValueAccessor().call(oViewModel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.onEsc = {
|
||||||
|
'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
|
||||||
|
$(oElement).on('keypress', function (oEvent) {
|
||||||
|
if (oEvent && 27 === window.parseInt(oEvent.keyCode, 10))
|
||||||
|
{
|
||||||
|
$(oElement).trigger('change');
|
||||||
|
fValueAccessor().call(oViewModel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.modal = {
|
||||||
|
'init': function (oElement, fValueAccessor) {
|
||||||
|
$(oElement).modal({
|
||||||
|
'keyboard': false,
|
||||||
|
'show': ko.utils.unwrapObservable(fValueAccessor())
|
||||||
|
}).on('hidden', function () {
|
||||||
|
fValueAccessor()(false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
var bValue = ko.utils.unwrapObservable(fValueAccessor());
|
||||||
|
$(oElement).modal(bValue ? 'show' : 'hide');
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
$(oElement).toggleClass('popup-active', bValue);
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.i18nInit = {
|
||||||
|
'init': function (oElement) {
|
||||||
|
Utils.i18nToNode(oElement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.i18nUpdate = {
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
ko.utils.unwrapObservable(fValueAccessor());
|
||||||
|
Utils.i18nToNode(oElement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.link = {
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
$(oElement).attr('href', ko.utils.unwrapObservable(fValueAccessor()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.title = {
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
$(oElement).attr('title', ko.utils.unwrapObservable(fValueAccessor()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.textF = {
|
||||||
|
'init': function (oElement, fValueAccessor) {
|
||||||
|
$(oElement).text(ko.utils.unwrapObservable(fValueAccessor()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.initDom = {
|
||||||
|
'init': function (oElement, fValueAccessor) {
|
||||||
|
fValueAccessor()(oElement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.initResizeTrigger = {
|
||||||
|
'init': function (oElement, fValueAccessor) {
|
||||||
|
var aValues = ko.utils.unwrapObservable(fValueAccessor());
|
||||||
|
$(oElement).css({
|
||||||
|
'height': aValues[1],
|
||||||
|
'min-height': aValues[1]
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
var
|
||||||
|
aValues = ko.utils.unwrapObservable(fValueAccessor()),
|
||||||
|
iValue = Utils.pInt(aValues[1]),
|
||||||
|
iSize = 0,
|
||||||
|
iOffset = $(oElement).offset().top
|
||||||
|
;
|
||||||
|
|
||||||
|
if (0 < iOffset)
|
||||||
|
{
|
||||||
|
iOffset += Utils.pInt(aValues[2]);
|
||||||
|
iSize = $window.height() - iOffset;
|
||||||
|
|
||||||
|
if (iValue < iSize)
|
||||||
|
{
|
||||||
|
iValue = iSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(oElement).css({
|
||||||
|
'height': iValue,
|
||||||
|
'min-height': iValue
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.appendDom = {
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
$(oElement).hide().empty().append(ko.utils.unwrapObservable(fValueAccessor())).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.draggable = {
|
||||||
|
'init': function (oElement, fValueAccessor, fAllBindingsAccessor) {
|
||||||
|
|
||||||
|
if (!Globals.bMobileDevice)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
iTriggerZone = 100,
|
||||||
|
iScrollSpeed = 3,
|
||||||
|
fAllValueFunc = fAllBindingsAccessor(),
|
||||||
|
sDroppableSelector = fAllValueFunc && fAllValueFunc['droppableSelector'] ? fAllValueFunc['droppableSelector'] : '',
|
||||||
|
oConf = {
|
||||||
|
'distance': 20,
|
||||||
|
'handle': '.dragHandle',
|
||||||
|
'cursorAt': {'top': 22, 'left': 3},
|
||||||
|
'refreshPositions': true,
|
||||||
|
'scroll': true
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (sDroppableSelector)
|
||||||
|
{
|
||||||
|
oConf['drag'] = function (oEvent) {
|
||||||
|
|
||||||
|
$(sDroppableSelector).each(function () {
|
||||||
|
var
|
||||||
|
moveUp = null,
|
||||||
|
moveDown = null,
|
||||||
|
$this = $(this),
|
||||||
|
oOffset = $this.offset(),
|
||||||
|
bottomPos = oOffset.top + $this.height()
|
||||||
|
;
|
||||||
|
|
||||||
|
window.clearInterval($this.data('timerScroll'));
|
||||||
|
$this.data('timerScroll', false);
|
||||||
|
|
||||||
|
if (oEvent.pageX >= oOffset.left && oEvent.pageX <= oOffset.left + $this.width())
|
||||||
|
{
|
||||||
|
if (oEvent.pageY >= bottomPos - iTriggerZone && oEvent.pageY <= bottomPos)
|
||||||
|
{
|
||||||
|
moveUp = function() {
|
||||||
|
$this.scrollTop($this.scrollTop() + iScrollSpeed);
|
||||||
|
Utils.windowResize();
|
||||||
|
};
|
||||||
|
|
||||||
|
$this.data('timerScroll', window.setInterval(moveUp, 10));
|
||||||
|
moveUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oEvent.pageY >= oOffset.top && oEvent.pageY <= oOffset.top + iTriggerZone)
|
||||||
|
{
|
||||||
|
moveDown = function() {
|
||||||
|
$this.scrollTop($this.scrollTop() - iScrollSpeed);
|
||||||
|
Utils.windowResize();
|
||||||
|
};
|
||||||
|
|
||||||
|
$this.data('timerScroll', window.setInterval(moveDown, 10));
|
||||||
|
moveDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
oConf['stop'] = function() {
|
||||||
|
$(sDroppableSelector).each(function () {
|
||||||
|
window.clearInterval($(this).data('timerScroll'));
|
||||||
|
$(this).data('timerScroll', false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
oConf['helper'] = function (oEvent) {
|
||||||
|
return fValueAccessor()(oEvent && oEvent.target ? ko.dataFor(oEvent.target) : null);
|
||||||
|
};
|
||||||
|
|
||||||
|
$(oElement).draggable(oConf).on('mousedown', function () {
|
||||||
|
Utils.removeInFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.droppable = {
|
||||||
|
'init': function (oElement, fValueAccessor, fAllBindingsAccessor) {
|
||||||
|
|
||||||
|
if (!Globals.bMobileDevice)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
fValueFunc = fValueAccessor(),
|
||||||
|
fAllValueFunc = fAllBindingsAccessor(),
|
||||||
|
fOverCallback = fAllValueFunc && fAllValueFunc['droppableOver'] ? fAllValueFunc['droppableOver'] : null,
|
||||||
|
fOutCallback = fAllValueFunc && fAllValueFunc['droppableOut'] ? fAllValueFunc['droppableOut'] : null,
|
||||||
|
oConf = {
|
||||||
|
'tolerance': 'pointer',
|
||||||
|
'hoverClass': 'droppableHover'
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (fValueFunc)
|
||||||
|
{
|
||||||
|
oConf['drop'] = function (oEvent, oUi) {
|
||||||
|
fValueFunc(oEvent, oUi);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fOverCallback)
|
||||||
|
{
|
||||||
|
oConf['over'] = function (oEvent, oUi) {
|
||||||
|
fOverCallback(oEvent, oUi);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fOutCallback)
|
||||||
|
{
|
||||||
|
oConf['out'] = function (oEvent, oUi) {
|
||||||
|
fOutCallback(oEvent, oUi);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
$(oElement).droppable(oConf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.nano = {
|
||||||
|
'init': function (oElement) {
|
||||||
|
if (!Globals.bDisableNanoScroll)
|
||||||
|
{
|
||||||
|
$(oElement)
|
||||||
|
.addClass('nano')
|
||||||
|
.nanoScroller({
|
||||||
|
'iOSNativeScrolling': false,
|
||||||
|
'preventPageScrolling': true
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.saveTrigger1 = {
|
||||||
|
'init': function (oElement) {
|
||||||
|
|
||||||
|
var $oEl = $(oElement);
|
||||||
|
|
||||||
|
$oEl.data('save-trigger-type', $oEl.is('input[type=text]') ? 'input' : 'custom');
|
||||||
|
|
||||||
|
if ('custom' === $oEl.data('save-trigger-type'))
|
||||||
|
{
|
||||||
|
$oEl.append(
|
||||||
|
' <i class="icon-spinner-2 animated"></i><i class="icon-remove error"></i><i class="icon-ok success"></i>'
|
||||||
|
).addClass('settings-saved-trigger');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$oEl.addClass('settings-saved-trigger-input');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
var
|
||||||
|
mValue = ko.utils.unwrapObservable(fValueAccessor()),
|
||||||
|
$oEl = $(oElement),
|
||||||
|
bCustom = 'custom' === $oEl.data('save-trigger-type'),
|
||||||
|
sSuffix = bCustom ? '' : '-input'
|
||||||
|
;
|
||||||
|
|
||||||
|
switch (mValue.toString())
|
||||||
|
{
|
||||||
|
case '1':
|
||||||
|
$oEl
|
||||||
|
.find('.sst-animated' + sSuffix + ',.sst-error' + sSuffix).hide().removeClass('sst-visible' + sSuffix)
|
||||||
|
.end()
|
||||||
|
.find('.sst-success' + sSuffix).show().addClass('sst-visible' + sSuffix)
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
$oEl
|
||||||
|
.find('.sst-animated' + sSuffix + ',.sst-success' + sSuffix).hide().removeClass('sst-visible' + sSuffix)
|
||||||
|
.end()
|
||||||
|
.find('.sst-error' + sSuffix).show().addClass('sst-visible' + sSuffix)
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
case '-2':
|
||||||
|
$oEl
|
||||||
|
.find('.sst-error' + sSuffix + ',.sst-success' + sSuffix).hide().removeClass('sst-visible' + sSuffix)
|
||||||
|
.end()
|
||||||
|
.find('.sst-animated' + sSuffix).show().addClass('sst-visible' + sSuffix)
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$oEl
|
||||||
|
.find('.sst-animated' + sSuffix).hide()
|
||||||
|
.end()
|
||||||
|
.find('.sst-error' + sSuffix + ',.sst-success' + sSuffix).removeClass('sst-visible' + sSuffix)
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.saveTrigger = {
|
||||||
|
'init': function (oElement) {
|
||||||
|
|
||||||
|
var $oEl = $(oElement);
|
||||||
|
|
||||||
|
$oEl.data('save-trigger-type', $oEl.is('input[type=text],select,textarea') ? 'input' : 'custom');
|
||||||
|
|
||||||
|
if ('custom' === $oEl.data('save-trigger-type'))
|
||||||
|
{
|
||||||
|
$oEl.append(
|
||||||
|
' <i class="icon-spinner-2 animated"></i><i class="icon-remove error"></i><i class="icon-ok success"></i>'
|
||||||
|
).addClass('settings-saved-trigger');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$oEl.addClass('settings-saved-trigger-input');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
var
|
||||||
|
mValue = ko.utils.unwrapObservable(fValueAccessor()),
|
||||||
|
$oEl = $(oElement)
|
||||||
|
;
|
||||||
|
|
||||||
|
if ('custom' === $oEl.data('save-trigger-type'))
|
||||||
|
{
|
||||||
|
switch (mValue.toString())
|
||||||
|
{
|
||||||
|
case '1':
|
||||||
|
$oEl
|
||||||
|
.find('.animated,.error').hide().removeClass('visible')
|
||||||
|
.end()
|
||||||
|
.find('.success').show().addClass('visible')
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
$oEl
|
||||||
|
.find('.animated,.success').hide().removeClass('visible')
|
||||||
|
.end()
|
||||||
|
.find('.error').show().addClass('visible')
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
case '-2':
|
||||||
|
$oEl
|
||||||
|
.find('.error,.success').hide().removeClass('visible')
|
||||||
|
.end()
|
||||||
|
.find('.animated').show().addClass('visible')
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$oEl
|
||||||
|
.find('.animated').hide()
|
||||||
|
.end()
|
||||||
|
.find('.error,.success').removeClass('visible')
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (mValue.toString())
|
||||||
|
{
|
||||||
|
case '1':
|
||||||
|
$oEl.addClass('success').removeClass('error');
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
$oEl.addClass('error').removeClass('success');
|
||||||
|
break;
|
||||||
|
case '-2':
|
||||||
|
// $oEl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$oEl.removeClass('error success');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.select2 = {
|
||||||
|
'init': function(oElement, fValueAccessor) {
|
||||||
|
|
||||||
|
var
|
||||||
|
iTimer = 0,
|
||||||
|
iTimeout = 100,
|
||||||
|
oMatch = null,
|
||||||
|
oReg = new window.RegExp(/[a-zA-Z0-9\.\-_]+@[a-zA-Z0-9\.\-_]+/),
|
||||||
|
oReg2 = new window.RegExp(/(.+) [<]?([^\s<@]+@[a-zA-Z0-9\.\-_]+)[>]?/),
|
||||||
|
sEmptyTranslateFunction = function () {
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @param {{term:string, callback:Function, matcher:Function}} oCall
|
||||||
|
*/
|
||||||
|
fLazyAutocomplete = function (oCall) {
|
||||||
|
|
||||||
|
RL.getAutocomplete(oCall['term'], oCall['page'], function (aData, bMore) {
|
||||||
|
oCall.callback({
|
||||||
|
'more': !!bMore,
|
||||||
|
'results': _.map(aData, function (oEmailItem) {
|
||||||
|
var sName = oEmailItem.toLine(false);
|
||||||
|
return {
|
||||||
|
'id': sName,
|
||||||
|
'text': sName,
|
||||||
|
'c': oEmailItem
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
$(oElement).addClass('ko-select2').select2({
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{term:string, callback:Function, matcher:Function}} oCall
|
||||||
|
*/
|
||||||
|
'query': function (oCall) {
|
||||||
|
if (!oCall)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (RL.isLocalAutocomplete && false)
|
||||||
|
// {
|
||||||
|
// fLazyAutocomplete(oCall);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
if (0 === iTimer)
|
||||||
|
{
|
||||||
|
fLazyAutocomplete(oCall);
|
||||||
|
iTimer = window.setTimeout(Utils.emptyFunction, iTimeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.clearInterval(iTimer);
|
||||||
|
iTimer = window.setTimeout(function () {
|
||||||
|
fLazyAutocomplete(oCall);
|
||||||
|
}, iTimeout);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
'formatSelection': function (oItem, oContainer) {
|
||||||
|
var sR = oItem && oItem.c ? oItem.c.select2Selection(oContainer) : oItem.text;
|
||||||
|
if (null !== sR)
|
||||||
|
{
|
||||||
|
return sR;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'formatResult': function (oItem, oContainer, oQuery, fEscapeMarkup) {
|
||||||
|
var sR = oItem && oItem.c ? oItem.c.select2Result(oContainer) : '';
|
||||||
|
return '' === sR ? fEscapeMarkup(oItem.text) : sR;
|
||||||
|
},
|
||||||
|
'createSearchChoice': function (sTerm, aList) {
|
||||||
|
return 0 === aList.length && oReg.test(sTerm) ? {
|
||||||
|
'id': sTerm,
|
||||||
|
'text': sTerm
|
||||||
|
} : null;
|
||||||
|
},
|
||||||
|
'formatNoMatches': sEmptyTranslateFunction,
|
||||||
|
'formatSearching': function () {
|
||||||
|
return Utils.i18n('SUGGESTIONS/SEARCHING_DESC');
|
||||||
|
},
|
||||||
|
'formatInputTooShort': sEmptyTranslateFunction,
|
||||||
|
'formatSelectionTooBig': sEmptyTranslateFunction,
|
||||||
|
'multiple': true,
|
||||||
|
'tokenSeparators': [',', ';'],
|
||||||
|
'minimumInputLength': 2,
|
||||||
|
'selectOnBlur': false,
|
||||||
|
'closeOnSelect': true,
|
||||||
|
'openOnEnter': false
|
||||||
|
});
|
||||||
|
|
||||||
|
ko.utils.domNodeDisposal.addDisposeCallback(oElement, function() {
|
||||||
|
$(oElement).select2('destroy');
|
||||||
|
});
|
||||||
|
|
||||||
|
$(oElement).on('change', function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
aTags = $(this).select2('data'),
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = aTags.length,
|
||||||
|
oItem = null,
|
||||||
|
aResult = []
|
||||||
|
;
|
||||||
|
|
||||||
|
for (; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
oItem = aTags[iIndex];
|
||||||
|
if (oItem && oItem.id)
|
||||||
|
{
|
||||||
|
if (!oItem.c)
|
||||||
|
{
|
||||||
|
oItem.c = new EmailModel();
|
||||||
|
oMatch = oReg2.exec(Utils.trim(oItem.id));
|
||||||
|
if (oMatch && !Utils.isUnd(oMatch[2]))
|
||||||
|
{
|
||||||
|
oItem.c.name = oMatch[1];
|
||||||
|
oItem.c.email = oMatch[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oItem.c.email = oItem.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aResult.push(oItem.c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fValueAccessor()(aResult);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
|
||||||
|
var
|
||||||
|
aTags = ko.utils.unwrapObservable(fValueAccessor()),
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = aTags.length,
|
||||||
|
oItem = null,
|
||||||
|
sName = '',
|
||||||
|
aResult = []
|
||||||
|
;
|
||||||
|
|
||||||
|
for (; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
oItem = aTags[iIndex];
|
||||||
|
sName = oItem.toLine(false);
|
||||||
|
|
||||||
|
aResult.push({
|
||||||
|
'id': sName,
|
||||||
|
'text': sName,
|
||||||
|
'c': oItem
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(oElement).select2('data', aResult);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.bindingHandlers.command = {
|
||||||
|
'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
|
||||||
|
var
|
||||||
|
jqElement = $(oElement),
|
||||||
|
oCommand = fValueAccessor()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!oCommand || !oCommand.enabled || !oCommand.canExecute)
|
||||||
|
{
|
||||||
|
throw new Error('You are not using command function');
|
||||||
|
}
|
||||||
|
|
||||||
|
jqElement.addClass('command');
|
||||||
|
ko.bindingHandlers[jqElement.is('form') ? 'submit' : 'click'].init.apply(oViewModel, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
'update': function (oElement, fValueAccessor) {
|
||||||
|
|
||||||
|
var
|
||||||
|
bResult = true,
|
||||||
|
jqElement = $(oElement),
|
||||||
|
oCommand = fValueAccessor()
|
||||||
|
;
|
||||||
|
|
||||||
|
bResult = oCommand.enabled();
|
||||||
|
jqElement.toggleClass('command-not-enabled', !bResult);
|
||||||
|
|
||||||
|
if (bResult)
|
||||||
|
{
|
||||||
|
bResult = oCommand.canExecute();
|
||||||
|
jqElement.toggleClass('command-can-not-be-execute', !bResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
jqElement.toggleClass('command-disabled disable disabled', !bResult);
|
||||||
|
|
||||||
|
if (jqElement.is('input') || jqElement.is('button'))
|
||||||
|
{
|
||||||
|
jqElement.prop('disabled', !bResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.extenders.trimmer = function (oTarget)
|
||||||
|
{
|
||||||
|
var oResult = ko.computed({
|
||||||
|
'read': oTarget,
|
||||||
|
'write': function (sNewValue) {
|
||||||
|
oTarget(Utils.trim(sNewValue.toString()));
|
||||||
|
},
|
||||||
|
'owner': this
|
||||||
|
});
|
||||||
|
|
||||||
|
oResult(oTarget());
|
||||||
|
return oResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.extenders.reversible = function (oTarget)
|
||||||
|
{
|
||||||
|
var mValue = oTarget();
|
||||||
|
|
||||||
|
oTarget.commit = function ()
|
||||||
|
{
|
||||||
|
mValue = oTarget();
|
||||||
|
};
|
||||||
|
|
||||||
|
oTarget.reverse = function ()
|
||||||
|
{
|
||||||
|
oTarget(mValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
oTarget.commitedValue = function ()
|
||||||
|
{
|
||||||
|
return mValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
return oTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.extenders.toggleSubscribe = function (oTarget, oOptions)
|
||||||
|
{
|
||||||
|
oTarget.subscribe(oOptions[1], oOptions[0], 'beforeChange');
|
||||||
|
oTarget.subscribe(oOptions[2], oOptions[0]);
|
||||||
|
|
||||||
|
return oTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.extenders.falseTimeout = function (oTarget, iOption)
|
||||||
|
{
|
||||||
|
oTarget.iTimeout = 0;
|
||||||
|
oTarget.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
|
window.clearTimeout(oTarget.iTimeout);
|
||||||
|
oTarget.iTimeout = window.setTimeout(function () {
|
||||||
|
oTarget(false);
|
||||||
|
oTarget.iTimeout = 0;
|
||||||
|
}, Utils.pInt(iOption));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return oTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.observable.fn.validateEmail = function ()
|
||||||
|
{
|
||||||
|
this.hasError = ko.observable(false);
|
||||||
|
|
||||||
|
this.subscribe(function (sValue) {
|
||||||
|
sValue = Utils.trim(sValue);
|
||||||
|
this.hasError('' !== sValue && !(/^[^@\s]+@[^@\s]+$/.test(sValue)));
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.valueHasMutated();
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.observable.fn.validateSimpleEmail = function ()
|
||||||
|
{
|
||||||
|
this.hasError = ko.observable(false);
|
||||||
|
|
||||||
|
this.subscribe(function (sValue) {
|
||||||
|
sValue = Utils.trim(sValue);
|
||||||
|
this.hasError('' !== sValue && !(/^.+@.+$/.test(sValue)));
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.valueHasMutated();
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
ko.observable.fn.validateFunc = function (fFunc)
|
||||||
|
{
|
||||||
|
this.hasFuncError = ko.observable(false);
|
||||||
|
|
||||||
|
if (Utils.isFunc(fFunc))
|
||||||
|
{
|
||||||
|
this.subscribe(function (sValue) {
|
||||||
|
this.hasFuncError(!fFunc(sValue));
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.valueHasMutated();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
274
dev/Common/LinkBuilder.js
Normal file
274
dev/Common/LinkBuilder.js
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LinkBuilder()
|
||||||
|
{
|
||||||
|
this.sBase = '#/';
|
||||||
|
this.sCdnStaticDomain = RL.settingsGet('CdnStaticDomain');
|
||||||
|
this.sVersion = RL.settingsGet('Version');
|
||||||
|
this.sSpecSuffix = RL.settingsGet('AuthAccountHash') || '0';
|
||||||
|
|
||||||
|
this.sServer = (RL.settingsGet('IndexFile') || './') + '?';
|
||||||
|
this.sCdnStaticDomain = '' === this.sCdnStaticDomain ? this.sCdnStaticDomain :
|
||||||
|
('/' === this.sCdnStaticDomain.substr(-1) ? this.sCdnStaticDomain : this.sCdnStaticDomain + '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.root = function ()
|
||||||
|
{
|
||||||
|
return this.sBase;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sDownload
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.attachmentDownload = function (sDownload)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Raw/' + this.sSpecSuffix + '/Download/' + sDownload;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sDownload
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.attachmentPreview = function (sDownload)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Raw/' + this.sSpecSuffix + '/View/' + sDownload;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sDownload
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.attachmentPreviewAsPlain = function (sDownload)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Raw/' + this.sSpecSuffix + '/ViewAsPlain/' + sDownload;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.upload = function ()
|
||||||
|
{
|
||||||
|
return this.sServer + '/Upload/' + this.sSpecSuffix + '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.uploadBackground = function ()
|
||||||
|
{
|
||||||
|
return this.sServer + '/UploadBackground/' + this.sSpecSuffix + '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.append = function ()
|
||||||
|
{
|
||||||
|
return this.sServer + '/Append/' + this.sSpecSuffix + '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sEmail
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.change = function (sEmail)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Change/' + this.sSpecSuffix + '/' + window.encodeURIComponent(sEmail) + '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string=} sAdd
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.ajax = function (sAdd)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Ajax/' + this.sSpecSuffix + '/' + sAdd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sRequestHash
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.messageViewLink = function (sRequestHash)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Raw/' + this.sSpecSuffix + '/ViewAsPlain/' + sRequestHash;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sRequestHash
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.messageDownloadLink = function (sRequestHash)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Raw/' + this.sSpecSuffix + '/Download/' + sRequestHash;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.inbox = function ()
|
||||||
|
{
|
||||||
|
return this.sBase + 'mailbox/Inbox';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string=} sScreenName
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.settings = function (sScreenName)
|
||||||
|
{
|
||||||
|
var sResult = this.sBase + 'settings';
|
||||||
|
if (!Utils.isUnd(sScreenName) && '' !== sScreenName)
|
||||||
|
{
|
||||||
|
sResult += '/' + sScreenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sScreenName
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.admin = function (sScreenName)
|
||||||
|
{
|
||||||
|
var sResult = this.sBase;
|
||||||
|
switch (sScreenName) {
|
||||||
|
case 'AdminDomains':
|
||||||
|
sResult += 'domains';
|
||||||
|
break;
|
||||||
|
case 'AdminSecurity':
|
||||||
|
sResult += 'security';
|
||||||
|
break;
|
||||||
|
case 'AdminLicensing':
|
||||||
|
sResult += 'licensing';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {number=} iPage
|
||||||
|
* @param {string=} sSearch
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.mailBox = function (sFolder, iPage, sSearch)
|
||||||
|
{
|
||||||
|
iPage = Utils.isNormal(iPage) ? Utils.pInt(iPage) : 1;
|
||||||
|
sSearch = Utils.pString(sSearch);
|
||||||
|
|
||||||
|
var sResult = this.sBase + 'mailbox/';
|
||||||
|
if ('' !== sFolder)
|
||||||
|
{
|
||||||
|
sResult += encodeURI(sFolder);
|
||||||
|
}
|
||||||
|
if (1 < iPage)
|
||||||
|
{
|
||||||
|
sResult = sResult.replace(/[\/]+$/, '');
|
||||||
|
sResult += '/p' + iPage;
|
||||||
|
}
|
||||||
|
if ('' !== sSearch)
|
||||||
|
{
|
||||||
|
sResult = sResult.replace(/[\/]+$/, '');
|
||||||
|
sResult += '/' + encodeURI(sSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.phpInfo = function ()
|
||||||
|
{
|
||||||
|
return this.sServer + 'Info';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sLang
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.langLink = function (sLang)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Lang/0/' + encodeURI(sLang) + '/' + this.sVersion + '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sHash
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.getUserPicUrlFromHash = function (sHash)
|
||||||
|
{
|
||||||
|
return this.sServer + '/Raw/' + this.sSpecSuffix + '/UserPic/' + sHash + '/' + this.sVersion + '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.emptyContactPic = function ()
|
||||||
|
{
|
||||||
|
return ('' === this.sCdnStaticDomain ? 'rainloop/v/' : this.sCdnStaticDomain) +
|
||||||
|
this.sVersion + '/static/css/images/empty-contact.png';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFileName
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.sound = function (sFileName)
|
||||||
|
{
|
||||||
|
return ('' === this.sCdnStaticDomain ? 'rainloop/v/' : this.sCdnStaticDomain) +
|
||||||
|
this.sVersion + '/static/sounds/' + sFileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sTheme
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.themePreviewLink = function (sTheme)
|
||||||
|
{
|
||||||
|
return ('' === this.sCdnStaticDomain ? 'rainloop/v/' : this.sCdnStaticDomain) +
|
||||||
|
this.sVersion + '/themes/' + encodeURI(sTheme) + '/images/preview.png';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.notificationMailIcon = function ()
|
||||||
|
{
|
||||||
|
return ('' === this.sCdnStaticDomain ? 'rainloop/v/' : this.sCdnStaticDomain) +
|
||||||
|
this.sVersion + '/static/css/images/icom-message-notification.png';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.socialGoogle = function ()
|
||||||
|
{
|
||||||
|
return this.sServer + 'SocialGoogle' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : '');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.socialTwitter = function ()
|
||||||
|
{
|
||||||
|
return this.sServer + 'SocialTwitter' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : '');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
LinkBuilder.prototype.socialFacebook = function ()
|
||||||
|
{
|
||||||
|
return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSpecSuffix + '/' : '');
|
||||||
|
};
|
||||||
95
dev/Common/Plugins.js
Normal file
95
dev/Common/Plugins.js
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
Plugins.oViewModelsHooks = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
Plugins.oSimpleHooks = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {Function} ViewModel
|
||||||
|
*/
|
||||||
|
Plugins.regViewModelHook = function (sName, ViewModel)
|
||||||
|
{
|
||||||
|
if (ViewModel)
|
||||||
|
{
|
||||||
|
ViewModel.__hookName = sName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {Function} fCallback
|
||||||
|
*/
|
||||||
|
Plugins.addHook = function (sName, fCallback)
|
||||||
|
{
|
||||||
|
if (Utils.isFunc(fCallback))
|
||||||
|
{
|
||||||
|
if (!Utils.isArray(Plugins.oSimpleHooks[sName]))
|
||||||
|
{
|
||||||
|
Plugins.oSimpleHooks[sName] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugins.oSimpleHooks[sName].push(fCallback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {Array=} aArguments
|
||||||
|
*/
|
||||||
|
Plugins.runHook = function (sName, aArguments)
|
||||||
|
{
|
||||||
|
if (Utils.isArray(Plugins.oSimpleHooks[sName]))
|
||||||
|
{
|
||||||
|
aArguments = aArguments || [];
|
||||||
|
|
||||||
|
_.each(Plugins.oSimpleHooks[sName], function (fCallback) {
|
||||||
|
fCallback.apply(null, aArguments);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sName
|
||||||
|
* @return {?}
|
||||||
|
*/
|
||||||
|
Plugins.mainSettingsGet = function (sName)
|
||||||
|
{
|
||||||
|
return RL ? RL.settingsGet(sName) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} fCallback
|
||||||
|
* @param {string} sAction
|
||||||
|
* @param {Object=} oParameters
|
||||||
|
* @param {?number=} iTimeout
|
||||||
|
* @param {string=} sGetAdd = ''
|
||||||
|
* @param {Array=} aAbortActions = []
|
||||||
|
*/
|
||||||
|
Plugins.remoteRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions)
|
||||||
|
{
|
||||||
|
if (RL)
|
||||||
|
{
|
||||||
|
RL.remote().defaultRequest(fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sPluginSection
|
||||||
|
* @param {string} sName
|
||||||
|
* @return {?}
|
||||||
|
*/
|
||||||
|
Plugins.settingsGet = function (sPluginSection, sName)
|
||||||
|
{
|
||||||
|
var oPlugin = Plugins.mainSettingsGet('Plugins');
|
||||||
|
oPlugin = oPlugin && Utils.isUnd(oPlugin[sPluginSection]) ? null : oPlugin[sPluginSection];
|
||||||
|
return oPlugin ? (Utils.isUnd(oPlugin[sName]) ? null : oPlugin[sName]) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
525
dev/Common/Selector.js
Normal file
525
dev/Common/Selector.js
Normal file
|
|
@ -0,0 +1,525 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {koProperty} oKoList
|
||||||
|
* @param {koProperty} oKoSelectedItem
|
||||||
|
* @param {string} sItemSelector
|
||||||
|
* @param {string} sItemSelectedSelector
|
||||||
|
* @param {string} sItemCheckedSelector
|
||||||
|
*/
|
||||||
|
function Selector(oKoList, oKoSelectedItem, sItemSelector, sItemSelectedSelector, sItemCheckedSelector)
|
||||||
|
{
|
||||||
|
this.list = oKoList;
|
||||||
|
this.selectedItem = oKoSelectedItem;
|
||||||
|
|
||||||
|
this.selectedItem.extend({'toggleSubscribe': [null,
|
||||||
|
function (oPrev) {
|
||||||
|
if (oPrev)
|
||||||
|
{
|
||||||
|
oPrev.selected(false);
|
||||||
|
}
|
||||||
|
}, function (oNext) {
|
||||||
|
if (oNext)
|
||||||
|
{
|
||||||
|
oNext.selected(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
|
||||||
|
this.oContentVisible = null;
|
||||||
|
this.oContentScrollable = null;
|
||||||
|
|
||||||
|
this.sItemSelector = sItemSelector;
|
||||||
|
this.sItemSelectedSelector = sItemSelectedSelector;
|
||||||
|
this.sItemCheckedSelector = sItemCheckedSelector;
|
||||||
|
|
||||||
|
this.sLastUid = '';
|
||||||
|
this.oCallbacks = {};
|
||||||
|
this.iSelectTimer = 0;
|
||||||
|
this.bUseKeyboard = true;
|
||||||
|
|
||||||
|
this.emptyFunction = function () {};
|
||||||
|
|
||||||
|
this.useItemSelectCallback = true;
|
||||||
|
this.throttleSelection = false;
|
||||||
|
|
||||||
|
this.selectedItem.subscribe(function (oItem) {
|
||||||
|
if (this.useItemSelectCallback)
|
||||||
|
{
|
||||||
|
if (this.throttleSelection)
|
||||||
|
{
|
||||||
|
this.throttleSelection = false;
|
||||||
|
this.selectItemCallbacksThrottle(oItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.selectItemCallbacks(oItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
aCheckedCache = [],
|
||||||
|
mSelected = null
|
||||||
|
;
|
||||||
|
|
||||||
|
this.list.subscribe(function () {
|
||||||
|
var self = this, aItems = this.list();
|
||||||
|
if (Utils.isArray(aItems))
|
||||||
|
{
|
||||||
|
_.each(aItems, function (oItem) {
|
||||||
|
if (oItem.checked())
|
||||||
|
{
|
||||||
|
aCheckedCache.push(self.getItemUid(oItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === mSelected && oItem.selected())
|
||||||
|
{
|
||||||
|
mSelected = self.getItemUid(oItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, this, 'beforeChange');
|
||||||
|
|
||||||
|
this.list.subscribe(function (aItems) {
|
||||||
|
|
||||||
|
this.useItemSelectCallback = false;
|
||||||
|
|
||||||
|
this.selectedItem(null);
|
||||||
|
|
||||||
|
if (Utils.isArray(aItems))
|
||||||
|
{
|
||||||
|
var self = this, iLen = aCheckedCache.length;
|
||||||
|
_.each(aItems, function (oItem) {
|
||||||
|
if (0 < iLen && -1 < Utils.inArray(self.getItemUid(oItem), aCheckedCache))
|
||||||
|
{
|
||||||
|
oItem.checked(true);
|
||||||
|
iLen--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== mSelected && mSelected === self.getItemUid(oItem))
|
||||||
|
{
|
||||||
|
oItem.selected(true);
|
||||||
|
mSelected = null;
|
||||||
|
|
||||||
|
self.selectedItem(oItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.useItemSelectCallback = true;
|
||||||
|
|
||||||
|
aCheckedCache = [];
|
||||||
|
mSelected = null;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.list.setSelectedByUid = function (sUid) {
|
||||||
|
self.selectByUid(sUid, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.selectItemCallbacksThrottle = _.debounce(this.selectItemCallbacks, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector.prototype.selectItemCallbacks = function (oItem)
|
||||||
|
{
|
||||||
|
(this.oCallbacks['onItemSelect'] || this.emptyFunction)(oItem);
|
||||||
|
};
|
||||||
|
|
||||||
|
Selector.prototype.init = function (oContentVisible, oContentScrollable)
|
||||||
|
{
|
||||||
|
this.oContentVisible = oContentVisible;
|
||||||
|
this.oContentScrollable = oContentScrollable;
|
||||||
|
|
||||||
|
if (this.oContentVisible && this.oContentScrollable)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this
|
||||||
|
;
|
||||||
|
|
||||||
|
$(this.oContentVisible)
|
||||||
|
.on('click', this.sItemSelector, function (oEvent) {
|
||||||
|
self.actionClick(ko.dataFor(this), oEvent);
|
||||||
|
}).on('click', this.sItemCheckedSelector, function (oEvent) {
|
||||||
|
var oItem = ko.dataFor(this);
|
||||||
|
if (oItem)
|
||||||
|
{
|
||||||
|
if (oEvent && oEvent.shiftKey)
|
||||||
|
{
|
||||||
|
self.actionClick(oItem, oEvent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.sLastUid = self.getItemUid(oItem);
|
||||||
|
if (oItem.selected())
|
||||||
|
{
|
||||||
|
oItem.checked(false);
|
||||||
|
self.selectedItem(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oItem.checked(!oItem.checked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
$(window.document).on('keydown', function (oEvent) {
|
||||||
|
var bResult = true;
|
||||||
|
if (oEvent && self.bUseKeyboard && !Utils.inFocus())
|
||||||
|
{
|
||||||
|
if (-1 < Utils.inArray(oEvent.keyCode, [Enums.EventKeyCode.Up, Enums.EventKeyCode.Down, Enums.EventKeyCode.Insert,
|
||||||
|
Enums.EventKeyCode.Home, Enums.EventKeyCode.End, Enums.EventKeyCode.PageUp, Enums.EventKeyCode.PageDown]))
|
||||||
|
{
|
||||||
|
self.newSelectPosition(oEvent.keyCode, oEvent.shiftKey);
|
||||||
|
bResult = false;
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.Delete === oEvent.keyCode && !oEvent.ctrlKey && !oEvent.shiftKey)
|
||||||
|
{
|
||||||
|
if (self.oCallbacks['onDelete'])
|
||||||
|
{
|
||||||
|
self.oCallbacks['onDelete']();
|
||||||
|
}
|
||||||
|
|
||||||
|
bResult = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bResult;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Selector.prototype.selectByUid = function (mUid, bUseCallback)
|
||||||
|
{
|
||||||
|
bUseCallback = Utils.isUnd(bUseCallback) ? true : !!bUseCallback;
|
||||||
|
this.useItemSelectCallback = bUseCallback;
|
||||||
|
|
||||||
|
var
|
||||||
|
oItem = _.find(this.list(), function (oItem) {
|
||||||
|
return mUid === this.getItemUid(oItem);
|
||||||
|
}, this)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oItem)
|
||||||
|
{
|
||||||
|
this.selectedItem(oItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.useItemSelectCallback = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Selector.prototype.useKeyboard = function (bValue)
|
||||||
|
{
|
||||||
|
this.bUseKeyboard = !!bValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oItem
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
Selector.prototype.getItemUid = function (oItem)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sUid = '',
|
||||||
|
fGetItemUidCallback = this.oCallbacks['onItemGetUid'] || null
|
||||||
|
;
|
||||||
|
|
||||||
|
if (fGetItemUidCallback && oItem)
|
||||||
|
{
|
||||||
|
sUid = fGetItemUidCallback(oItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sUid.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} iEventKeyCode
|
||||||
|
* @param {boolean} bShiftKey
|
||||||
|
*/
|
||||||
|
Selector.prototype.newSelectPosition = function (iEventKeyCode, bShiftKey)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
iIndex = 0,
|
||||||
|
iPageStep = 10,
|
||||||
|
bNext = false,
|
||||||
|
bStop = false,
|
||||||
|
oResult = null,
|
||||||
|
aList = this.list(),
|
||||||
|
iListLen = aList ? aList.length : 0,
|
||||||
|
oSelected = this.selectedItem()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (0 < iListLen)
|
||||||
|
{
|
||||||
|
if (!oSelected)
|
||||||
|
{
|
||||||
|
if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode || Enums.EventKeyCode.Home === iEventKeyCode || Enums.EventKeyCode.PageUp === iEventKeyCode)
|
||||||
|
{
|
||||||
|
oResult = aList[0];
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.End === iEventKeyCode || Enums.EventKeyCode.PageDown === iEventKeyCode)
|
||||||
|
{
|
||||||
|
oResult = aList[aList.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (oSelected)
|
||||||
|
{
|
||||||
|
if (Enums.EventKeyCode.Down === iEventKeyCode || Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Insert === iEventKeyCode)
|
||||||
|
{
|
||||||
|
_.each(aList, function (oItem) {
|
||||||
|
if (!bStop)
|
||||||
|
{
|
||||||
|
switch (iEventKeyCode) {
|
||||||
|
case Enums.EventKeyCode.Up:
|
||||||
|
if (oSelected === oItem)
|
||||||
|
{
|
||||||
|
bStop = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oResult = oItem;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Enums.EventKeyCode.Down:
|
||||||
|
case Enums.EventKeyCode.Insert:
|
||||||
|
if (bNext)
|
||||||
|
{
|
||||||
|
oResult = oItem;
|
||||||
|
bStop = true;
|
||||||
|
}
|
||||||
|
else if (oSelected === oItem)
|
||||||
|
{
|
||||||
|
bNext = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.Home === iEventKeyCode || Enums.EventKeyCode.End === iEventKeyCode)
|
||||||
|
{
|
||||||
|
if (Enums.EventKeyCode.Home === iEventKeyCode)
|
||||||
|
{
|
||||||
|
oResult = aList[0];
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.End === iEventKeyCode)
|
||||||
|
{
|
||||||
|
oResult = aList[aList.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.PageDown === iEventKeyCode)
|
||||||
|
{
|
||||||
|
for (; iIndex < iListLen; iIndex++)
|
||||||
|
{
|
||||||
|
if (oSelected === aList[iIndex])
|
||||||
|
{
|
||||||
|
iIndex += iPageStep;
|
||||||
|
iIndex = iListLen - 1 < iIndex ? iListLen - 1 : iIndex;
|
||||||
|
oResult = aList[iIndex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.PageUp === iEventKeyCode)
|
||||||
|
{
|
||||||
|
for (iIndex = iListLen; iIndex >= 0; iIndex--)
|
||||||
|
{
|
||||||
|
if (oSelected === aList[iIndex])
|
||||||
|
{
|
||||||
|
iIndex -= iPageStep;
|
||||||
|
iIndex = 0 > iIndex ? 0 : iIndex;
|
||||||
|
oResult = aList[iIndex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oResult)
|
||||||
|
{
|
||||||
|
if (oSelected)
|
||||||
|
{
|
||||||
|
if (bShiftKey)
|
||||||
|
{
|
||||||
|
if (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode)
|
||||||
|
{
|
||||||
|
oSelected.checked(!oSelected.checked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.Insert === iEventKeyCode)
|
||||||
|
{
|
||||||
|
oSelected.checked(!oSelected.checked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.throttleSelection = true;
|
||||||
|
this.selectedItem(oResult);
|
||||||
|
this.throttleSelection = true;
|
||||||
|
|
||||||
|
if (0 !== this.iSelectTimer)
|
||||||
|
{
|
||||||
|
window.clearTimeout(this.iSelectTimer);
|
||||||
|
this.iSelectTimer = window.setTimeout(function () {
|
||||||
|
self.iSelectTimer = 0;
|
||||||
|
self.actionClick(oResult);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.iSelectTimer = window.setTimeout(function () {
|
||||||
|
self.iSelectTimer = 0;
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
this.actionClick(oResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollToSelected();
|
||||||
|
}
|
||||||
|
else if (oSelected)
|
||||||
|
{
|
||||||
|
if (bShiftKey && (Enums.EventKeyCode.Up === iEventKeyCode || Enums.EventKeyCode.Down === iEventKeyCode))
|
||||||
|
{
|
||||||
|
oSelected.checked(!oSelected.checked());
|
||||||
|
}
|
||||||
|
else if (Enums.EventKeyCode.Insert === iEventKeyCode)
|
||||||
|
{
|
||||||
|
oSelected.checked(!oSelected.checked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
Selector.prototype.scrollToSelected = function ()
|
||||||
|
{
|
||||||
|
if (!this.oContentVisible || !this.oContentScrollable)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var
|
||||||
|
iOffset = 20,
|
||||||
|
oSelected = $(this.sItemSelectedSelector, this.oContentScrollable),
|
||||||
|
oPos = oSelected.position(),
|
||||||
|
iVisibleHeight = this.oContentVisible.height(),
|
||||||
|
iSelectedHeight = oSelected.outerHeight()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oPos && (oPos.top < 0 || oPos.top + iSelectedHeight > iVisibleHeight))
|
||||||
|
{
|
||||||
|
if (oPos.top < 0)
|
||||||
|
{
|
||||||
|
this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iOffset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iSelectedHeight + iOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Selector.prototype.eventClickFunction = function (oItem, oEvent)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sUid = this.getItemUid(oItem),
|
||||||
|
iIndex = 0,
|
||||||
|
iLength = 0,
|
||||||
|
oListItem = null,
|
||||||
|
sLineUid = '',
|
||||||
|
bChangeRange = false,
|
||||||
|
bIsInRange = false,
|
||||||
|
aList = [],
|
||||||
|
bChecked = false
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oEvent && oEvent.shiftKey)
|
||||||
|
{
|
||||||
|
if ('' !== sUid && '' !== this.sLastUid && sUid !== this.sLastUid)
|
||||||
|
{
|
||||||
|
aList = this.list();
|
||||||
|
bChecked = oItem.checked();
|
||||||
|
|
||||||
|
for (iIndex = 0, iLength = aList.length; iIndex < iLength; iIndex++)
|
||||||
|
{
|
||||||
|
oListItem = aList[iIndex];
|
||||||
|
sLineUid = this.getItemUid(oListItem);
|
||||||
|
|
||||||
|
bChangeRange = false;
|
||||||
|
if (sLineUid === this.sLastUid || sLineUid === sUid)
|
||||||
|
{
|
||||||
|
bChangeRange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bChangeRange)
|
||||||
|
{
|
||||||
|
bIsInRange = !bIsInRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bIsInRange || bChangeRange)
|
||||||
|
{
|
||||||
|
oListItem.checked(bChecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sLastUid = '' === sUid ? '' : sUid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Object} oItem
|
||||||
|
* @param {Object=} oEvent
|
||||||
|
*/
|
||||||
|
Selector.prototype.actionClick = function (oItem, oEvent)
|
||||||
|
{
|
||||||
|
if (oItem)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
bClick = true,
|
||||||
|
sUid = this.getItemUid(oItem)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oEvent)
|
||||||
|
{
|
||||||
|
if (oEvent.shiftKey)
|
||||||
|
{
|
||||||
|
bClick = false;
|
||||||
|
if ('' === this.sLastUid)
|
||||||
|
{
|
||||||
|
this.sLastUid = sUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
oItem.checked(!oItem.checked());
|
||||||
|
this.eventClickFunction(oItem, oEvent);
|
||||||
|
}
|
||||||
|
else if (oEvent.ctrlKey)
|
||||||
|
{
|
||||||
|
bClick = false;
|
||||||
|
this.sLastUid = sUid;
|
||||||
|
|
||||||
|
oItem.checked(!oItem.checked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bClick)
|
||||||
|
{
|
||||||
|
this.selectedItem(oItem);
|
||||||
|
this.sLastUid = sUid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Selector.prototype.on = function (sEventName, fCallback)
|
||||||
|
{
|
||||||
|
this.oCallbacks[sEventName] = fCallback;
|
||||||
|
};
|
||||||
1343
dev/Common/Utils.js
Normal file
1343
dev/Common/Utils.js
Normal file
File diff suppressed because it is too large
Load diff
71
dev/Common/_Begin.js
Normal file
71
dev/Common/_Begin.js
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
Consts = {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
Enums = {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
NotificationI18N = {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object.<Function>}
|
||||||
|
*/
|
||||||
|
Utils = {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object.<Function>}
|
||||||
|
*/
|
||||||
|
Plugins = {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object.<Function>}
|
||||||
|
*/
|
||||||
|
Base64 = {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
Globals = {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
ViewModels = {
|
||||||
|
'settings': [],
|
||||||
|
'settings-removed': [],
|
||||||
|
'settings-disabled': []
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {*}
|
||||||
|
*/
|
||||||
|
kn = null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
AppData = window['rainloopAppData'] || {},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
I18n = window['rainloopI18N'] || {},
|
||||||
|
|
||||||
|
$html = $('html'),
|
||||||
|
|
||||||
|
$window = $(window),
|
||||||
|
|
||||||
|
$document = $(window.document),
|
||||||
|
|
||||||
|
NotificationClass = window.Notification && window.Notification.requestPermission ? window.Notification : null
|
||||||
|
;
|
||||||
6
dev/Common/_BeginA.js
Normal file
6
dev/Common/_BeginA.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*jshint onevar: false*/
|
||||||
|
/**
|
||||||
|
* @type {?AdminApp}
|
||||||
|
*/
|
||||||
|
var RL = null;
|
||||||
|
/*jshint onevar: true*/
|
||||||
6
dev/Common/_BeginW.js
Normal file
6
dev/Common/_BeginW.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*jshint onevar: false*/
|
||||||
|
/**
|
||||||
|
* @type {?RainLoopApp}
|
||||||
|
*/
|
||||||
|
var RL = null;
|
||||||
|
/*jshint onevar: true*/
|
||||||
3
dev/Common/_BootEnd.js
Normal file
3
dev/Common/_BootEnd.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
if (window.SimplePace) {
|
||||||
|
window.SimplePace.add(10);
|
||||||
|
}
|
||||||
3
dev/Common/_CoreEnd.js
Normal file
3
dev/Common/_CoreEnd.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
if (window.SimplePace) {
|
||||||
|
window.SimplePace.add(10);
|
||||||
|
}
|
||||||
57
dev/Common/_End.js
Normal file
57
dev/Common/_End.js
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile');
|
||||||
|
|
||||||
|
$window.keydown(Utils.killCtrlAandS).keyup(Utils.killCtrlAandS);
|
||||||
|
$window.unload(function () {
|
||||||
|
Globals.bUnload = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// export
|
||||||
|
window.rl = window.rl || {};
|
||||||
|
window.rl.addHook = Plugins.addHook;
|
||||||
|
window.rl.settingsGet = Plugins.mainSettingsGet;
|
||||||
|
window.rl.remoteRequest = Plugins.remoteRequest;
|
||||||
|
window.rl.pluginSettingsGet = Plugins.settingsGet;
|
||||||
|
window.rl.addSettingsViewModel = Utils.addSettingsViewModel;
|
||||||
|
window.rl.createCommand = Utils.createCommand;
|
||||||
|
|
||||||
|
window.rl.EmailModel = EmailModel;
|
||||||
|
window.rl.Enums = Enums;
|
||||||
|
|
||||||
|
window['__RLBOOT'] = function (fCall) {
|
||||||
|
|
||||||
|
// boot
|
||||||
|
$(function () {
|
||||||
|
|
||||||
|
if (window['rainloopTEMPLATES'] && window['rainloopTEMPLATES'][0])
|
||||||
|
{
|
||||||
|
$('#rl-templates').html(window['rainloopTEMPLATES'][0]);
|
||||||
|
|
||||||
|
window.setInterval(function () {
|
||||||
|
Globals.minuteTick(!Globals.minuteTick());
|
||||||
|
}, 1000 * 60);
|
||||||
|
|
||||||
|
window.setInterval(function () {
|
||||||
|
Globals.fiveMinuteTick(!Globals.fiveMinuteTick());
|
||||||
|
}, 1000 * 60 * 5);
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
window['rainloopAppData'] = {};
|
||||||
|
window['rainloopI18N'] = {};
|
||||||
|
window['rainloopTEMPLATES'] = {};
|
||||||
|
|
||||||
|
kn.setBoot(RL).bootstart();
|
||||||
|
|
||||||
|
$html.addClass('rl-started');
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fCall(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
window['__RLBOOT'] = null;
|
||||||
|
});
|
||||||
|
};
|
||||||
3
dev/Common/_LibsEnd.js
Normal file
3
dev/Common/_LibsEnd.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
if (window.SimplePace) {
|
||||||
|
window.SimplePace.add(20);
|
||||||
|
}
|
||||||
14
dev/Knoin/AbstractBoot.js
Normal file
14
dev/Knoin/AbstractBoot.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function KnoinAbstractBoot()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
KnoinAbstractBoot.prototype.bootstart = function ()
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
77
dev/Knoin/AbstractScreen.js
Normal file
77
dev/Knoin/AbstractScreen.js
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sScreenName
|
||||||
|
* @param {?=} aViewModels = []
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function KnoinAbstractScreen(sScreenName, aViewModels)
|
||||||
|
{
|
||||||
|
this.sScreenName = sScreenName;
|
||||||
|
this.aViewModels = Utils.isArray(aViewModels) ? aViewModels : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
KnoinAbstractScreen.prototype.oCross = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
KnoinAbstractScreen.prototype.sScreenName = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
KnoinAbstractScreen.prototype.aViewModels = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
KnoinAbstractScreen.prototype.viewModels = function ()
|
||||||
|
{
|
||||||
|
return this.aViewModels;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
KnoinAbstractScreen.prototype.screenName = function ()
|
||||||
|
{
|
||||||
|
return this.sScreenName;
|
||||||
|
};
|
||||||
|
|
||||||
|
KnoinAbstractScreen.prototype.routes = function ()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {?Object}
|
||||||
|
*/
|
||||||
|
KnoinAbstractScreen.prototype.__cross = function ()
|
||||||
|
{
|
||||||
|
return this.oCross;
|
||||||
|
};
|
||||||
|
|
||||||
|
KnoinAbstractScreen.prototype.__start = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aRoutes = this.routes(),
|
||||||
|
oRoute = null,
|
||||||
|
fMatcher = null
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(aRoutes))
|
||||||
|
{
|
||||||
|
fMatcher = _.bind(this.onRoute || Utils.emptyFunction, this);
|
||||||
|
oRoute = crossroads.create();
|
||||||
|
|
||||||
|
_.each(aRoutes, function (aItem) {
|
||||||
|
oRoute.addRoute(aItem[0], fMatcher).rules = aItem[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
this.oCross = oRoute;
|
||||||
|
}
|
||||||
|
};
|
||||||
61
dev/Knoin/AbstractViewModel.js
Normal file
61
dev/Knoin/AbstractViewModel.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string=} sPosition = ''
|
||||||
|
* @param {string=} sTemplate = ''
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function KnoinAbstractViewModel(sPosition, sTemplate)
|
||||||
|
{
|
||||||
|
this.sPosition = Utils.pString(sPosition);
|
||||||
|
this.sTemplate = Utils.pString(sTemplate);
|
||||||
|
|
||||||
|
this.viewModelName = '';
|
||||||
|
this.viewModelVisibility = ko.observable(false);
|
||||||
|
if ('Popups' === this.sPosition)
|
||||||
|
{
|
||||||
|
this.modalVisibility = ko.observable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.viewModelDom = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
KnoinAbstractViewModel.prototype.sPosition = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
KnoinAbstractViewModel.prototype.sTemplate = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
KnoinAbstractViewModel.prototype.viewModelName = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?}
|
||||||
|
*/
|
||||||
|
KnoinAbstractViewModel.prototype.viewModelDom = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
KnoinAbstractViewModel.prototype.viewModelTemplate = function ()
|
||||||
|
{
|
||||||
|
return this.sTemplate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
KnoinAbstractViewModel.prototype.viewModelPosition = function ()
|
||||||
|
{
|
||||||
|
return this.sPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
KnoinAbstractViewModel.prototype.cancelCommand = KnoinAbstractViewModel.prototype.closeCommand = function ()
|
||||||
|
{
|
||||||
|
};
|
||||||
382
dev/Knoin/Knoin.js
Normal file
382
dev/Knoin/Knoin.js
Normal file
|
|
@ -0,0 +1,382 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function Knoin()
|
||||||
|
{
|
||||||
|
this.sDefaultScreenName = '';
|
||||||
|
this.oScreens = {};
|
||||||
|
this.oBoot = null;
|
||||||
|
this.oCurrentScreen = null;
|
||||||
|
|
||||||
|
this.popupVisibility = ko.observable(false);
|
||||||
|
|
||||||
|
this.popupVisibility.subscribe(function (bValue) {
|
||||||
|
if (RL)
|
||||||
|
{
|
||||||
|
RL.popupVisibility(bValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Knoin.prototype.sDefaultScreenName = '';
|
||||||
|
Knoin.prototype.oScreens = {};
|
||||||
|
Knoin.prototype.oBoot = null;
|
||||||
|
Knoin.prototype.oCurrentScreen = null;
|
||||||
|
|
||||||
|
Knoin.prototype.showLoading = function ()
|
||||||
|
{
|
||||||
|
$('#rl-loading').show();
|
||||||
|
};
|
||||||
|
|
||||||
|
Knoin.prototype.hideLoading = function ()
|
||||||
|
{
|
||||||
|
$('#rl-loading').hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
Knoin.prototype.routeOff = function ()
|
||||||
|
{
|
||||||
|
hasher.changed.active = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Knoin.prototype.routeOn = function ()
|
||||||
|
{
|
||||||
|
hasher.changed.active = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oBoot
|
||||||
|
* @return {Knoin}
|
||||||
|
*/
|
||||||
|
Knoin.prototype.setBoot = function (oBoot)
|
||||||
|
{
|
||||||
|
if (Utils.isNormal(oBoot))
|
||||||
|
{
|
||||||
|
this.oBoot = oBoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sScreenName
|
||||||
|
* @return {?Object}
|
||||||
|
*/
|
||||||
|
Knoin.prototype.screen = function (sScreenName)
|
||||||
|
{
|
||||||
|
return ('' !== sScreenName && !Utils.isUnd(this.oScreens[sScreenName])) ? this.oScreens[sScreenName] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?} oViewModel
|
||||||
|
* @param {string} sDelegateName
|
||||||
|
* @param {Array=} aParameters
|
||||||
|
*/
|
||||||
|
Knoin.prototype.delegateRun = function (oViewModel, sDelegateName, aParameters)
|
||||||
|
{
|
||||||
|
if (oViewModel && oViewModel[sDelegateName])
|
||||||
|
{
|
||||||
|
oViewModel[sDelegateName].apply(oViewModel, Utils.isArray(aParameters) ? aParameters : []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} ViewModelClass
|
||||||
|
* @param {Object=} oScreen
|
||||||
|
*/
|
||||||
|
Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
|
||||||
|
{
|
||||||
|
if (ViewModelClass && !ViewModelClass.__builded)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oViewModel = new ViewModelClass(oScreen),
|
||||||
|
sPosition = oViewModel.viewModelPosition(),
|
||||||
|
oViewModelPlace = $('#rl-content #rl-' + sPosition.toLowerCase()),
|
||||||
|
oViewModelDom = null
|
||||||
|
;
|
||||||
|
|
||||||
|
ViewModelClass.__builded = true;
|
||||||
|
ViewModelClass.__vm = oViewModel;
|
||||||
|
oViewModel.data = RL.data();
|
||||||
|
|
||||||
|
oViewModel.viewModelName = ViewModelClass.__name;
|
||||||
|
|
||||||
|
if (oViewModelPlace && 1 === oViewModelPlace.length)
|
||||||
|
{
|
||||||
|
oViewModelDom = $('<div>').addClass('rl-view-model').addClass('RL-' + oViewModel.viewModelTemplate()).hide().attr('data-bind',
|
||||||
|
'template: {name: "' + oViewModel.viewModelTemplate() + '"}, i18nInit: true');
|
||||||
|
|
||||||
|
oViewModelDom.appendTo(oViewModelPlace);
|
||||||
|
oViewModel.viewModelDom = oViewModelDom;
|
||||||
|
ViewModelClass.__dom = oViewModelDom;
|
||||||
|
|
||||||
|
if ('Popups' === sPosition)
|
||||||
|
{
|
||||||
|
oViewModel.cancelCommand = oViewModel.closeCommand = Utils.createCommand(oViewModel, function () {
|
||||||
|
kn.hideScreenPopup(ViewModelClass);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugins.runHook('view-model-pre-build', [ViewModelClass.__name, oViewModel, oViewModelDom]);
|
||||||
|
|
||||||
|
ko.applyBindings(oViewModel, oViewModelDom[0]);
|
||||||
|
this.delegateRun(oViewModel, 'onBuild', [oViewModelDom]);
|
||||||
|
|
||||||
|
Plugins.runHook('view-model-post-build', [ViewModelClass.__name, oViewModel, oViewModelDom]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utils.log('Cannot find view model position: ' + sPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ViewModelClass ? ViewModelClass.__vm : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oViewModel
|
||||||
|
* @param {Object} oViewModelDom
|
||||||
|
*/
|
||||||
|
Knoin.prototype.applyExternal = function (oViewModel, oViewModelDom)
|
||||||
|
{
|
||||||
|
if (oViewModel && oViewModelDom)
|
||||||
|
{
|
||||||
|
ko.applyBindings(oViewModel, oViewModelDom);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} ViewModelClassToHide
|
||||||
|
*/
|
||||||
|
Knoin.prototype.hideScreenPopup = function (ViewModelClassToHide)
|
||||||
|
{
|
||||||
|
if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom)
|
||||||
|
{
|
||||||
|
ViewModelClassToHide.__dom.hide();
|
||||||
|
ViewModelClassToHide.__vm.modalVisibility(false);
|
||||||
|
this.delegateRun(ViewModelClassToHide.__vm, 'onHide');
|
||||||
|
this.popupVisibility(false);
|
||||||
|
|
||||||
|
_.defer(function () {
|
||||||
|
ViewModelClassToHide.__dom.find('.ko-select2').select2('close');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} ViewModelClassToShow
|
||||||
|
* @param {Array=} aParameters
|
||||||
|
*/
|
||||||
|
Knoin.prototype.showScreenPopup = function (ViewModelClassToShow, aParameters)
|
||||||
|
{
|
||||||
|
if (ViewModelClassToShow)
|
||||||
|
{
|
||||||
|
this.buildViewModel(ViewModelClassToShow);
|
||||||
|
|
||||||
|
if (ViewModelClassToShow.__vm && ViewModelClassToShow.__dom)
|
||||||
|
{
|
||||||
|
ViewModelClassToShow.__dom.show();
|
||||||
|
ViewModelClassToShow.__vm.modalVisibility(true);
|
||||||
|
this.delegateRun(ViewModelClassToShow.__vm, 'onShow', aParameters || []);
|
||||||
|
this.popupVisibility(true);
|
||||||
|
|
||||||
|
Plugins.runHook('view-model-on-show', [ViewModelClassToShow.__name, ViewModelClassToShow.__vm, aParameters || []]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sScreenName
|
||||||
|
* @param {string} sSubPart
|
||||||
|
*/
|
||||||
|
Knoin.prototype.screenOnRoute = function (sScreenName, sSubPart)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
oScreen = null,
|
||||||
|
oCross = null
|
||||||
|
;
|
||||||
|
|
||||||
|
if ('' === Utils.pString(sScreenName))
|
||||||
|
{
|
||||||
|
sScreenName = this.sDefaultScreenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' !== sScreenName)
|
||||||
|
{
|
||||||
|
oScreen = this.screen(sScreenName);
|
||||||
|
if (!oScreen)
|
||||||
|
{
|
||||||
|
oScreen = this.screen(this.sDefaultScreenName);
|
||||||
|
if (oScreen)
|
||||||
|
{
|
||||||
|
sSubPart = sScreenName + '/' + sSubPart;
|
||||||
|
sScreenName = this.sDefaultScreenName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oScreen && oScreen.__started)
|
||||||
|
{
|
||||||
|
if (!oScreen.__builded)
|
||||||
|
{
|
||||||
|
oScreen.__builded = true;
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(oScreen.viewModels()))
|
||||||
|
{
|
||||||
|
_.each(oScreen.viewModels(), function (ViewModelClass) {
|
||||||
|
this.buildViewModel(ViewModelClass, oScreen);
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.delegateRun(oScreen, 'onBuild');
|
||||||
|
}
|
||||||
|
|
||||||
|
_.defer(function () {
|
||||||
|
|
||||||
|
// hide screen
|
||||||
|
if (self.oCurrentScreen)
|
||||||
|
{
|
||||||
|
self.delegateRun(self.oCurrentScreen, 'onHide');
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(self.oCurrentScreen.viewModels()))
|
||||||
|
{
|
||||||
|
_.each(self.oCurrentScreen.viewModels(), function (ViewModelClass) {
|
||||||
|
|
||||||
|
if (ViewModelClass.__vm && ViewModelClass.__dom &&
|
||||||
|
'Popups' !== ViewModelClass.__vm.viewModelPosition())
|
||||||
|
{
|
||||||
|
ViewModelClass.__dom.hide();
|
||||||
|
ViewModelClass.__vm.viewModelVisibility(false);
|
||||||
|
self.delegateRun(ViewModelClass.__vm, 'onHide');
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --
|
||||||
|
|
||||||
|
self.oCurrentScreen = oScreen;
|
||||||
|
|
||||||
|
// show screen
|
||||||
|
if (self.oCurrentScreen)
|
||||||
|
{
|
||||||
|
|
||||||
|
self.delegateRun(self.oCurrentScreen, 'onShow');
|
||||||
|
|
||||||
|
Plugins.runHook('screen-on-show', [self.oCurrentScreen.screenName(), self.oCurrentScreen]);
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(self.oCurrentScreen.viewModels()))
|
||||||
|
{
|
||||||
|
_.each(self.oCurrentScreen.viewModels(), function (ViewModelClass) {
|
||||||
|
|
||||||
|
if (ViewModelClass.__vm && ViewModelClass.__dom &&
|
||||||
|
'Popups' !== ViewModelClass.__vm.viewModelPosition())
|
||||||
|
{
|
||||||
|
ViewModelClass.__dom.show();
|
||||||
|
ViewModelClass.__vm.viewModelVisibility(true);
|
||||||
|
self.delegateRun(ViewModelClass.__vm, 'onShow');
|
||||||
|
|
||||||
|
Plugins.runHook('view-model-on-show', [ViewModelClass.__name, ViewModelClass.__vm]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --
|
||||||
|
|
||||||
|
oCross = oScreen.__cross();
|
||||||
|
if (oCross)
|
||||||
|
{
|
||||||
|
oCross.parse(sSubPart);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} aScreensClasses
|
||||||
|
*/
|
||||||
|
Knoin.prototype.startScreens = function (aScreensClasses)
|
||||||
|
{
|
||||||
|
_.each(aScreensClasses, function (CScreen) {
|
||||||
|
|
||||||
|
var
|
||||||
|
oScreen = new CScreen(),
|
||||||
|
sScreenName = oScreen ? oScreen.screenName() : ''
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oScreen && '' !== sScreenName)
|
||||||
|
{
|
||||||
|
if ('' === this.sDefaultScreenName)
|
||||||
|
{
|
||||||
|
this.sDefaultScreenName = sScreenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oScreens[sScreenName] = oScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
|
||||||
|
_.each(this.oScreens, function (oScreen) {
|
||||||
|
if (oScreen && !oScreen.__started && oScreen.__start)
|
||||||
|
{
|
||||||
|
oScreen.__started = true;
|
||||||
|
oScreen.__start();
|
||||||
|
|
||||||
|
Plugins.runHook('screen-pre-start', [oScreen.screenName(), oScreen]);
|
||||||
|
this.delegateRun(oScreen, 'onStart');
|
||||||
|
Plugins.runHook('screen-post-start', [oScreen.screenName(), oScreen]);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
var oCross = crossroads.create();
|
||||||
|
oCross.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/, _.bind(this.screenOnRoute, this));
|
||||||
|
|
||||||
|
hasher.initialized.add(oCross.parse, oCross);
|
||||||
|
hasher.changed.add(oCross.parse, oCross);
|
||||||
|
hasher.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sHash
|
||||||
|
* @param {boolean=} bSilence = false
|
||||||
|
* @param {boolean=} bReplace = false
|
||||||
|
*/
|
||||||
|
Knoin.prototype.setHash = function (sHash, bSilence, bReplace)
|
||||||
|
{
|
||||||
|
sHash = '#' === sHash.substr(0, 1) ? sHash.substr(1) : sHash;
|
||||||
|
sHash = '/' === sHash.substr(0, 1) ? sHash.substr(1) : sHash;
|
||||||
|
|
||||||
|
bReplace = Utils.isUnd(bReplace) ? false : !!bReplace;
|
||||||
|
|
||||||
|
if (Utils.isUnd(bSilence) ? false : !!bSilence)
|
||||||
|
{
|
||||||
|
hasher.changed.active = false;
|
||||||
|
hasher[bReplace ? 'replaceHash' : 'setHash'](sHash);
|
||||||
|
hasher.changed.active = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hasher.changed.active = true;
|
||||||
|
hasher[bReplace ? 'replaceHash' : 'setHash'](sHash);
|
||||||
|
hasher.setHash(sHash);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Knoin}
|
||||||
|
*/
|
||||||
|
Knoin.prototype.bootstart = function ()
|
||||||
|
{
|
||||||
|
if (this.oBoot && this.oBoot.bootstart)
|
||||||
|
{
|
||||||
|
this.oBoot.bootstart();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
kn = new Knoin();
|
||||||
23
dev/Models/AccountModel.js
Normal file
23
dev/Models/AccountModel.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sEmail
|
||||||
|
* @param {boolean=} bCanBeDelete = true
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AccountModel(sEmail, bCanBeDelete)
|
||||||
|
{
|
||||||
|
this.email = sEmail;
|
||||||
|
this.deleteAccess = ko.observable(false);
|
||||||
|
this.canBeDalete = ko.observable(bCanBeDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountModel.prototype.email = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
AccountModel.prototype.changeAccountLink = function ()
|
||||||
|
{
|
||||||
|
return RL.link().change(this.email);
|
||||||
|
};
|
||||||
228
dev/Models/AttachmentModel.js
Normal file
228
dev/Models/AttachmentModel.js
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AttachmentModel()
|
||||||
|
{
|
||||||
|
this.mimeType = '';
|
||||||
|
this.fileName = '';
|
||||||
|
this.estimatedSize = 0;
|
||||||
|
this.friendlySize = '';
|
||||||
|
this.isInline = false;
|
||||||
|
this.isLinked = false;
|
||||||
|
this.cid = '';
|
||||||
|
this.cidWithOutTags = '';
|
||||||
|
this.contentLocation = '';
|
||||||
|
this.download = '';
|
||||||
|
this.folder = '';
|
||||||
|
this.uid = '';
|
||||||
|
this.mimeIndex = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {AjaxJsonAttachment} oJsonAttachment
|
||||||
|
* @return {?AttachmentModel}
|
||||||
|
*/
|
||||||
|
AttachmentModel.newInstanceFromJson = function (oJsonAttachment)
|
||||||
|
{
|
||||||
|
var oAttachmentModel = new AttachmentModel();
|
||||||
|
return oAttachmentModel.initByJson(oJsonAttachment) ? oAttachmentModel : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentModel.prototype.mimeType = '';
|
||||||
|
AttachmentModel.prototype.fileName = '';
|
||||||
|
AttachmentModel.prototype.estimatedSize = 0;
|
||||||
|
AttachmentModel.prototype.friendlySize = '';
|
||||||
|
AttachmentModel.prototype.isInline = false;
|
||||||
|
AttachmentModel.prototype.isLinked = false;
|
||||||
|
AttachmentModel.prototype.cid = '';
|
||||||
|
AttachmentModel.prototype.cidWithOutTags = '';
|
||||||
|
AttachmentModel.prototype.contentLocation = '';
|
||||||
|
AttachmentModel.prototype.download = '';
|
||||||
|
AttachmentModel.prototype.folder = '';
|
||||||
|
AttachmentModel.prototype.uid = '';
|
||||||
|
AttachmentModel.prototype.mimeIndex = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AjaxJsonAttachment} oJsonAttachment
|
||||||
|
*/
|
||||||
|
AttachmentModel.prototype.initByJson = function (oJsonAttachment)
|
||||||
|
{
|
||||||
|
var bResult = false;
|
||||||
|
if (oJsonAttachment && 'Object/Attachment' === oJsonAttachment['@Object'])
|
||||||
|
{
|
||||||
|
this.mimeType = oJsonAttachment.MimeType;
|
||||||
|
this.fileName = oJsonAttachment.FileName;
|
||||||
|
this.estimatedSize = Utils.pInt(oJsonAttachment.EstimatedSize);
|
||||||
|
this.isInline = !!oJsonAttachment.IsInline;
|
||||||
|
this.isLinked = !!oJsonAttachment.IsLinked;
|
||||||
|
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.friendlySize = Utils.friendlySize(this.estimatedSize);
|
||||||
|
this.cidWithOutTags = this.cid.replace(/^<+/, '').replace(/>+$/, '');
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
AttachmentModel.prototype.isImage = function ()
|
||||||
|
{
|
||||||
|
return -1 < Utils.inArray(this.mimeType.toLowerCase(),
|
||||||
|
['image/png', 'image/jpg', 'image/jpeg', 'image/gif']
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
AttachmentModel.prototype.isText = function ()
|
||||||
|
{
|
||||||
|
return 'text/' === this.mimeType.substr(0, 5);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
AttachmentModel.prototype.linkDownload = function ()
|
||||||
|
{
|
||||||
|
return RL.link().attachmentDownload(this.download);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
AttachmentModel.prototype.linkPreview = function ()
|
||||||
|
{
|
||||||
|
return RL.link().attachmentPreview(this.download);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
AttachmentModel.prototype.linkPreviewAsPlain = function ()
|
||||||
|
{
|
||||||
|
return RL.link().attachmentPreviewAsPlain(this.download);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {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
|
||||||
|
* @return {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;
|
||||||
|
};
|
||||||
|
|
||||||
|
AttachmentModel.prototype.iconClass = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aParts = this.mimeType.toLocaleString().split('/'),
|
||||||
|
sClass = 'icon-file'
|
||||||
|
;
|
||||||
|
|
||||||
|
if (aParts && aParts[1])
|
||||||
|
{
|
||||||
|
if ('image' === aParts[0])
|
||||||
|
{
|
||||||
|
sClass = 'icon-image';
|
||||||
|
}
|
||||||
|
else if ('text' === aParts[0])
|
||||||
|
{
|
||||||
|
sClass = 'icon-file-xml';
|
||||||
|
}
|
||||||
|
else if ('audio' === aParts[0])
|
||||||
|
{
|
||||||
|
sClass = 'icon-music';
|
||||||
|
}
|
||||||
|
else if ('video' === aParts[0])
|
||||||
|
{
|
||||||
|
sClass = 'icon-film';
|
||||||
|
}
|
||||||
|
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']))
|
||||||
|
{
|
||||||
|
sClass = 'icon-file-pdf';
|
||||||
|
}
|
||||||
|
else if (-1 < Utils.inArray(aParts[1], [
|
||||||
|
'exe', 'x-exe', 'x-winexe', 'bat'
|
||||||
|
]))
|
||||||
|
{
|
||||||
|
sClass = 'icon-console';
|
||||||
|
}
|
||||||
|
else if (-1 < Utils.inArray(aParts[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-word';
|
||||||
|
}
|
||||||
|
else if (-1 < Utils.inArray(aParts[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'
|
||||||
|
]))
|
||||||
|
{
|
||||||
|
sClass = 'icon-file-excel';
|
||||||
|
}
|
||||||
|
else if (-1 < Utils.inArray(aParts[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'
|
||||||
|
]))
|
||||||
|
{
|
||||||
|
sClass = 'icon-file-powerpoint';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sClass;
|
||||||
|
};
|
||||||
63
dev/Models/ComposeAttachmentModel.js
Normal file
63
dev/Models/ComposeAttachmentModel.js
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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)
|
||||||
|
{
|
||||||
|
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('');
|
||||||
|
this.error = ko.observable('');
|
||||||
|
this.waiting = ko.observable(true);
|
||||||
|
this.uploading = ko.observable(false);
|
||||||
|
this.enabled = ko.observable(true);
|
||||||
|
|
||||||
|
this.friendlySize = ko.computed(function () {
|
||||||
|
var mSize = this.size();
|
||||||
|
return null === mSize ? '' : Utils.friendlySize(this.size());
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.emptyFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AjaxJsonComposeAttachment} oJsonAttachment
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
73
dev/Models/ContactModel.js
Normal file
73
dev/Models/ContactModel.js
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function ContactModel()
|
||||||
|
{
|
||||||
|
this.idContact = 0;
|
||||||
|
this.imageHash = '';
|
||||||
|
this.listName = '';
|
||||||
|
this.name = '';
|
||||||
|
this.emails = [];
|
||||||
|
|
||||||
|
this.checked = ko.observable(false);
|
||||||
|
this.selected = ko.observable(false);
|
||||||
|
this.deleted = ko.observable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactModel.prototype.parse = function (oItem)
|
||||||
|
{
|
||||||
|
var bResult = false;
|
||||||
|
if (oItem && 'Object/Contact' === oItem['@Object'])
|
||||||
|
{
|
||||||
|
this.idContact = Utils.pInt(oItem['IdContact']);
|
||||||
|
this.listName = Utils.pString(oItem['ListName']);
|
||||||
|
this.name = Utils.pString(oItem['Name']);
|
||||||
|
this.emails = Utils.isNonEmptyArray(oItem['Emails']) ? oItem['Emails'] : [];
|
||||||
|
this.imageHash = Utils.pString(oItem['ImageHash']);
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
ContactModel.prototype.srcAttr = function ()
|
||||||
|
{
|
||||||
|
return '' === this.imageHash ? RL.link().emptyContactPic() :
|
||||||
|
RL.link().getUserPicUrlFromHash(this.imageHash);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
ContactModel.prototype.generateUid = function ()
|
||||||
|
{
|
||||||
|
return '' + this.idContact;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
ContactModel.prototype.lineAsCcc = function ()
|
||||||
|
{
|
||||||
|
var aResult = [];
|
||||||
|
if (this.deleted())
|
||||||
|
{
|
||||||
|
aResult.push('deleted');
|
||||||
|
}
|
||||||
|
if (this.selected())
|
||||||
|
{
|
||||||
|
aResult.push('selected');
|
||||||
|
}
|
||||||
|
if (this.checked())
|
||||||
|
{
|
||||||
|
aResult.push('checked');
|
||||||
|
}
|
||||||
|
|
||||||
|
return aResult.join(' ');
|
||||||
|
};
|
||||||
240
dev/Models/EmailModel.js
Normal file
240
dev/Models/EmailModel.js
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string=} sEmail
|
||||||
|
* @param {string=} sName
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function EmailModel(sEmail, sName)
|
||||||
|
{
|
||||||
|
this.email = sEmail || '';
|
||||||
|
this.name = sName || '';
|
||||||
|
this.privateType = null;
|
||||||
|
|
||||||
|
this.clearDuplicateName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {AjaxJsonEmail} oJsonEmail
|
||||||
|
* @return {?EmailModel}
|
||||||
|
*/
|
||||||
|
EmailModel.newInstanceFromJson = function (oJsonEmail)
|
||||||
|
{
|
||||||
|
var oEmailModel = new EmailModel();
|
||||||
|
return oEmailModel.initByJson(oJsonEmail) ? oEmailModel : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.name = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.email = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {(number|null)}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.privateType = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.validate = function ()
|
||||||
|
{
|
||||||
|
return '' !== this.name || '' !== this.email;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} bWithoutName = false
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.hash = function (bWithoutName)
|
||||||
|
{
|
||||||
|
return '#' + (bWithoutName ? '' : this.name) + '#' + this.email + '#';
|
||||||
|
};
|
||||||
|
|
||||||
|
EmailModel.prototype.clearDuplicateName = function ()
|
||||||
|
{
|
||||||
|
if (this.name === this.email)
|
||||||
|
{
|
||||||
|
this.name = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.type = function ()
|
||||||
|
{
|
||||||
|
if (null === this.privateType)
|
||||||
|
{
|
||||||
|
if (this.email && '@facebook.com' === this.email.substr(-13))
|
||||||
|
{
|
||||||
|
this.privateType = Enums.EmailType.Facebook;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === this.privateType)
|
||||||
|
{
|
||||||
|
this.privateType = Enums.EmailType.Default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.privateType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sQuery
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.search = function (sQuery)
|
||||||
|
{
|
||||||
|
return -1 < (this.name + ' ' + this.email).toLowerCase().indexOf(sQuery.toLowerCase());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sString
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.parse = function (sString)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
* @return {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);
|
||||||
|
|
||||||
|
bResult = '' !== this.email;
|
||||||
|
this.clearDuplicateName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} bFriendlyView
|
||||||
|
* @param {boolean=} bWrapWithLink = false
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.toLine = function (bFriendlyView, bWrapWithLink)
|
||||||
|
{
|
||||||
|
var sResult = '';
|
||||||
|
if ('' !== this.email)
|
||||||
|
{
|
||||||
|
bWrapWithLink = Utils.isUnd(bWrapWithLink) ? false : !!bWrapWithLink;
|
||||||
|
if (bFriendlyView && '' !== this.name)
|
||||||
|
{
|
||||||
|
sResult = bWrapWithLink ? '<a href="mailto:' + Utils.encodeHtml('"' + this.name + '" <' + this.email + '>') +
|
||||||
|
'" target="_blank" tabindex="-1">' + Utils.encodeHtml(this.name) + '</a>' : this.name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sResult = this.email;
|
||||||
|
if ('' !== this.name)
|
||||||
|
{
|
||||||
|
if (bWrapWithLink)
|
||||||
|
{
|
||||||
|
sResult = Utils.encodeHtml('"' + this.name + '" <') +
|
||||||
|
'<a href="mailto:' + Utils.encodeHtml('"' + this.name + '" <' + this.email + '>') + '" target="_blank" tabindex="-1">' + Utils.encodeHtml(sResult) + '</a>' + Utils.encodeHtml('>');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sResult = '"' + this.name + '" <' + sResult + '>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bWrapWithLink)
|
||||||
|
{
|
||||||
|
sResult = '<a href="mailto:' + Utils.encodeHtml(this.email) + '" target="_blank" tabindex="-1">' + Utils.encodeHtml(this.email) + '</a>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.select2Result = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sResult = '',
|
||||||
|
sImg = RL.cache().getUserPic(this.email)
|
||||||
|
;
|
||||||
|
|
||||||
|
if ('' !== sImg)
|
||||||
|
{
|
||||||
|
sResult += '<img class="select2-user-pic pull-left" src="' + Utils.encodeHtml(sImg) + '" />';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sResult += '<img class="select2-user-pic pull-left" src="' + RL.link().emptyContactPic() + '" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Enums.EmailType.Facebook === this.type())
|
||||||
|
{
|
||||||
|
sResult += '' + (0 < this.name.length ? this.name : this.email);
|
||||||
|
sResult += '<i class="icon-facebook pull-right select2-icon-result" />';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sResult += '' + (0 < this.name.length ? this.email + ' <span class="select2-subname">(' + this.name + ')</span>' : this.email);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sResult + '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oContainer
|
||||||
|
* @return {string|null}
|
||||||
|
*/
|
||||||
|
EmailModel.prototype.select2Selection = function (oContainer)
|
||||||
|
{
|
||||||
|
var sResult = '';
|
||||||
|
if (Enums.EmailType.Facebook === this.type())
|
||||||
|
{
|
||||||
|
sResult = 0 < this.name.length ? this.name : this.email;
|
||||||
|
if ('' !== sResult)
|
||||||
|
{
|
||||||
|
$('<pan>').text(sResult).appendTo(oContainer);
|
||||||
|
oContainer.append('<i class="icon-facebook select2-icon"></i>');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sResult = 0 < this.name.length ? this.name + ' (' + this.email + ')' : this.email;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sResult;
|
||||||
|
};
|
||||||
305
dev/Models/FolderModel.js
Normal file
305
dev/Models/FolderModel.js
Normal file
|
|
@ -0,0 +1,305 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function FolderModel()
|
||||||
|
{
|
||||||
|
this.name = ko.observable('');
|
||||||
|
this.fullName = '';
|
||||||
|
this.fullNameRaw = '';
|
||||||
|
this.fullNameHash = '';
|
||||||
|
this.delimiter = '';
|
||||||
|
this.namespace = '';
|
||||||
|
this.deep = 0;
|
||||||
|
|
||||||
|
this.selectable = false;
|
||||||
|
this.existen = true;
|
||||||
|
|
||||||
|
this.isNamespaceFolder = false;
|
||||||
|
this.isGmailFolder = false;
|
||||||
|
this.isUnpaddigFolder = false;
|
||||||
|
|
||||||
|
this.type = ko.observable(Enums.FolderType.User);
|
||||||
|
|
||||||
|
this.selected = ko.observable(false);
|
||||||
|
this.edited = ko.observable(false);
|
||||||
|
this.collapsed = ko.observable(true);
|
||||||
|
this.subScribed = ko.observable(true);
|
||||||
|
this.subFolders = ko.observableArray([]);
|
||||||
|
this.deleteAccess = ko.observable(false);
|
||||||
|
this.actionBlink = ko.observable(false).extend({'falseTimeout': 1000});
|
||||||
|
|
||||||
|
this.nameForEdit = ko.observable('');
|
||||||
|
|
||||||
|
this.name.subscribe(function (sValue) {
|
||||||
|
this.nameForEdit(sValue);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.edited.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
|
this.nameForEdit(this.name());
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.canBeEdited = ko.computed(function () {
|
||||||
|
return Enums.FolderType.User === this.type();
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.privateMessageCountAll = ko.observable(0);
|
||||||
|
this.privateMessageCountUnread = ko.observable(0);
|
||||||
|
|
||||||
|
this.collapsedPrivate = ko.observable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {AjaxJsonFolder} oJsonFolder
|
||||||
|
* @return {?FolderModel}
|
||||||
|
*/
|
||||||
|
FolderModel.newInstanceFromJson = function (oJsonFolder)
|
||||||
|
{
|
||||||
|
var oFolderModel = new FolderModel();
|
||||||
|
return oFolderModel.initByJson(oJsonFolder) ? oFolderModel.initComputed() : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {FolderModel}
|
||||||
|
*/
|
||||||
|
FolderModel.prototype.initComputed = function ()
|
||||||
|
{
|
||||||
|
this.hasSubScribedSubfolders = ko.computed(function () {
|
||||||
|
return !!_.find(this.subFolders(), function (oFolder) {
|
||||||
|
return oFolder.subScribed();
|
||||||
|
});
|
||||||
|
}, 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 this.isGmailFolder || (bSystem && this.isNamespaceFolder) || (bSystem && !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
|
||||||
|
});
|
||||||
|
|
||||||
|
this.messageCountUnread = ko.computed({
|
||||||
|
'read': this.privateMessageCountUnread,
|
||||||
|
'write': function (iValue) {
|
||||||
|
if (Utils.isPosNumeric(iValue, true))
|
||||||
|
{
|
||||||
|
this.privateMessageCountUnread(iValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.privateMessageCountUnread.valueHasMutated();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'owner': this
|
||||||
|
});
|
||||||
|
|
||||||
|
this.printableUnreadCount = ko.computed(function () {
|
||||||
|
var
|
||||||
|
iCount = this.messageCountAll(),
|
||||||
|
iUnread = this.messageCountUnread(),
|
||||||
|
iType = this.type()
|
||||||
|
;
|
||||||
|
// return 0 < iUnread ? '' + iUnread : '';
|
||||||
|
// return 0 < iUnread && 'INBOX' === this.fullNameRaw ? '' + iUnread : '';
|
||||||
|
return 0 < iUnread && (Enums.FolderType.Inbox === iType || Enums.FolderType.Spam === iType) ? '' + iUnread :
|
||||||
|
(0 < iCount && Enums.FolderType.Draft === iType ? '' + iCount : '');
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.canBeDeleted = ko.computed(function () {
|
||||||
|
var
|
||||||
|
bSystem = this.isSystemFolder()
|
||||||
|
;
|
||||||
|
return !bSystem && 0 === this.subFolders().length && 'INBOX' !== this.fullNameRaw;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.canBeSubScribed = ko.computed(function () {
|
||||||
|
return !this.isSystemFolder() && this.selectable && 'INBOX' !== this.fullNameRaw;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.visible.subscribe(function () {
|
||||||
|
Utils.timeOutAction('folder-list-folder-visibility-change', function () {
|
||||||
|
$window.trigger('folder-list-folder-visibility-change');
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.localName = ko.computed(function () {
|
||||||
|
|
||||||
|
Globals.langChangeTick();
|
||||||
|
|
||||||
|
var
|
||||||
|
iType = this.type(),
|
||||||
|
sName = this.name()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (this.isSystemFolder())
|
||||||
|
{
|
||||||
|
switch (iType)
|
||||||
|
{
|
||||||
|
case Enums.FolderType.Inbox:
|
||||||
|
sName = Utils.i18n('FOLDER_LIST/INBOX_NAME');
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.SentItems:
|
||||||
|
sName = Utils.i18n('FOLDER_LIST/SENT_NAME');
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.Draft:
|
||||||
|
sName = Utils.i18n('FOLDER_LIST/DRAFTS_NAME');
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.Spam:
|
||||||
|
sName = Utils.i18n('FOLDER_LIST/SPAM_NAME');
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.Trash:
|
||||||
|
sName = Utils.i18n('FOLDER_LIST/TRASH_NAME');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sName;
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.manageFolderSystemName = ko.computed(function () {
|
||||||
|
|
||||||
|
Globals.langChangeTick();
|
||||||
|
|
||||||
|
var
|
||||||
|
sSuffix = '',
|
||||||
|
iType = this.type(),
|
||||||
|
sName = this.name()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (this.isSystemFolder())
|
||||||
|
{
|
||||||
|
switch (iType)
|
||||||
|
{
|
||||||
|
case Enums.FolderType.Inbox:
|
||||||
|
sSuffix = '(' + Utils.i18n('FOLDER_LIST/INBOX_NAME') + ')';
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.SentItems:
|
||||||
|
sSuffix = '(' + Utils.i18n('FOLDER_LIST/SENT_NAME') + ')';
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.Draft:
|
||||||
|
sSuffix = '(' + Utils.i18n('FOLDER_LIST/DRAFTS_NAME') + ')';
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.Spam:
|
||||||
|
sSuffix = '(' + Utils.i18n('FOLDER_LIST/SPAM_NAME') + ')';
|
||||||
|
break;
|
||||||
|
case Enums.FolderType.Trash:
|
||||||
|
sSuffix = '(' + Utils.i18n('FOLDER_LIST/TRASH_NAME') + ')';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
FolderModel.prototype.fullName = '';
|
||||||
|
FolderModel.prototype.fullNameRaw = '';
|
||||||
|
FolderModel.prototype.fullNameHash = '';
|
||||||
|
FolderModel.prototype.delimiter = '';
|
||||||
|
FolderModel.prototype.namespace = '';
|
||||||
|
FolderModel.prototype.deep = 0;
|
||||||
|
|
||||||
|
FolderModel.prototype.isNamespaceFolder = false;
|
||||||
|
FolderModel.prototype.isGmailFolder = false;
|
||||||
|
FolderModel.prototype.isUnpaddigFolder = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
FolderModel.prototype.collapsedCss = function ()
|
||||||
|
{
|
||||||
|
return this.hasSubScribedSubfolders() ?
|
||||||
|
(this.collapsed() ? 'icon-arrow-right-3 e-collapsed-sign' : 'icon-arrow-down-3 e-collapsed-sign') : 'icon-none e-collapsed-sign';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AjaxJsonFolder} oJsonFolder
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
FolderModel.prototype.initByJson = function (oJsonFolder)
|
||||||
|
{
|
||||||
|
var bResult = false;
|
||||||
|
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.IsExisten;
|
||||||
|
|
||||||
|
this.subScribed(!!oJsonFolder.IsSubscribed);
|
||||||
|
this.type('INBOX' === this.fullNameRaw ? Enums.FolderType.Inbox : Enums.FolderType.User);
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
FolderModel.prototype.printableFullName = function ()
|
||||||
|
{
|
||||||
|
return this.fullName.split(this.delimiter).join(' / ');
|
||||||
|
};
|
||||||
37
dev/Models/IdentityModel.js
Normal file
37
dev/Models/IdentityModel.js
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sId
|
||||||
|
* @param {string} sEmail
|
||||||
|
* @param {boolean=} bCanBeDelete = true
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function IdentityModel(sId, sEmail, bCanBeDelete)
|
||||||
|
{
|
||||||
|
this.id = sId;
|
||||||
|
this.email = ko.observable(sEmail);
|
||||||
|
this.name = ko.observable('');
|
||||||
|
this.replyTo = ko.observable('');
|
||||||
|
this.bcc = ko.observable('');
|
||||||
|
|
||||||
|
this.deleteAccess = ko.observable(false);
|
||||||
|
this.canBeDalete = ko.observable(bCanBeDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentityModel.prototype.formattedName = function ()
|
||||||
|
{
|
||||||
|
var sName = this.name();
|
||||||
|
return '' === sName ? this.email() : sName + ' <' + this.email() + '>';
|
||||||
|
};
|
||||||
|
|
||||||
|
IdentityModel.prototype.formattedNameForCompose = function ()
|
||||||
|
{
|
||||||
|
var sName = this.name();
|
||||||
|
return '' === sName ? this.email() : sName + ' (' + this.email() + ')';
|
||||||
|
};
|
||||||
|
|
||||||
|
IdentityModel.prototype.formattedNameForEmail = function ()
|
||||||
|
{
|
||||||
|
var sName = this.name();
|
||||||
|
return '' === sName ? this.email() : '"' + Utils.quoteName(sName) + '" <' + this.email() + '>';
|
||||||
|
};
|
||||||
897
dev/Models/MessageModel.js
Normal file
897
dev/Models/MessageModel.js
Normal file
|
|
@ -0,0 +1,897 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function MessageModel()
|
||||||
|
{
|
||||||
|
this.folderFullNameRaw = '';
|
||||||
|
this.uid = '';
|
||||||
|
this.requestHash = '';
|
||||||
|
this.subject = ko.observable('');
|
||||||
|
this.size = ko.observable(0);
|
||||||
|
this.dateTimeStampInUTC = ko.observable(0);
|
||||||
|
this.priority = ko.observable(Enums.MessagePriority.Normal);
|
||||||
|
|
||||||
|
this.fromEmailString = ko.observable('');
|
||||||
|
this.toEmailsString = ko.observable('');
|
||||||
|
this.senderEmailsString = ko.observable('');
|
||||||
|
|
||||||
|
this.prefetched = false;
|
||||||
|
|
||||||
|
this.emails = [];
|
||||||
|
|
||||||
|
this.from = [];
|
||||||
|
this.to = [];
|
||||||
|
this.cc = [];
|
||||||
|
this.bcc = [];
|
||||||
|
this.replyTo = [];
|
||||||
|
|
||||||
|
this.newForAnimation = ko.observable(false);
|
||||||
|
|
||||||
|
this.deleted = ko.observable(false);
|
||||||
|
this.unseen = ko.observable(false);
|
||||||
|
this.flagged = ko.observable(false);
|
||||||
|
this.answered = ko.observable(false);
|
||||||
|
this.forwarded = ko.observable(false);
|
||||||
|
|
||||||
|
this.selected = ko.observable(false);
|
||||||
|
this.checked = ko.observable(false);
|
||||||
|
this.hasAttachments = ko.observable(false);
|
||||||
|
this.attachmentsMainType = ko.observable('');
|
||||||
|
|
||||||
|
this.moment = ko.observable(moment());
|
||||||
|
|
||||||
|
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';
|
||||||
|
break;
|
||||||
|
case 'pdf':
|
||||||
|
sClass = 'icon-file-pdf';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sClass;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.fullFormatDateValue = ko.computed(function () {
|
||||||
|
return MessageModel.calculateFullFromatDateValue(this.dateTimeStampInUTC());
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.fullFormatDateValue = ko.computed(function () {
|
||||||
|
return MessageModel.calculateFullFromatDateValue(this.dateTimeStampInUTC());
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.momentDate = Utils.createMomentDate(this);
|
||||||
|
this.momentShortDate = Utils.createMomentShortDate(this);
|
||||||
|
|
||||||
|
this.dateTimeStampInUTC.subscribe(function (iValue) {
|
||||||
|
var iNow = moment().unix();
|
||||||
|
this.moment(moment.unix(iNow < iValue ? iNow : iValue));
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.body = null;
|
||||||
|
this.isRtl = ko.observable(false);
|
||||||
|
this.isHtml = ko.observable(false);
|
||||||
|
this.hasImages = ko.observable(false);
|
||||||
|
this.attachments = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.priority = ko.observable(Enums.MessagePriority.Normal);
|
||||||
|
this.aDraftInfo = [];
|
||||||
|
this.sMessageId = '';
|
||||||
|
this.sInReplyTo = '';
|
||||||
|
this.sReferences = '';
|
||||||
|
|
||||||
|
this.parentUid = ko.observable(0);
|
||||||
|
this.threads = ko.observableArray([]);
|
||||||
|
this.threadsLen = ko.observable(0);
|
||||||
|
this.hasUnseenSubMessage = ko.observable(false);
|
||||||
|
this.hasFlaggedSubMessage = ko.observable(false);
|
||||||
|
|
||||||
|
this.lastInCollapsedThread = ko.observable(false);
|
||||||
|
this.lastInCollapsedThreadLoading = ko.observable(false);
|
||||||
|
|
||||||
|
this.threadsLenResult = ko.computed(function () {
|
||||||
|
var iCount = this.threadsLen();
|
||||||
|
return 0 === this.parentUid() && 0 < iCount ? iCount + 1 : '';
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {AjaxJsonMessage} oJsonMessage
|
||||||
|
* @return {?MessageModel}
|
||||||
|
*/
|
||||||
|
MessageModel.newInstanceFromJson = function (oJsonMessage)
|
||||||
|
{
|
||||||
|
var oMessageModel = new MessageModel();
|
||||||
|
return oMessageModel.initByJson(oJsonMessage) ? oMessageModel : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {number} iTimeStampInUTC
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.calculateFullFromatDateValue = function (iTimeStampInUTC)
|
||||||
|
{
|
||||||
|
return moment.unix(iTimeStampInUTC).format('LLL');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {Array} aEmail
|
||||||
|
* @param {boolean=} bFriendlyView
|
||||||
|
* @param {boolean=} bWrapWithLink = false
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.emailsToLine = function (aEmail, bFriendlyView, bWrapWithLink)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aResult = [],
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = 0
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(aEmail))
|
||||||
|
{
|
||||||
|
for (iIndex = 0, iLen = aEmail.length; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
aResult.push(aEmail[iIndex].toLine(bFriendlyView, bWrapWithLink));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aResult.join(', ');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {?Array} aJsonEmails
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
MessageModel.initEmailsFromJson = function (aJsonEmails)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = 0,
|
||||||
|
oEmailModel = null,
|
||||||
|
aResult = []
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(aJsonEmails))
|
||||||
|
{
|
||||||
|
for (iIndex = 0, iLen = aJsonEmails.length; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
oEmailModel = EmailModel.newInstanceFromJson(aJsonEmails[iIndex]);
|
||||||
|
if (oEmailModel)
|
||||||
|
{
|
||||||
|
aResult.push(oEmailModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @static
|
||||||
|
* @param {Array.<EmailModel>} aMessageEmails
|
||||||
|
* @param {Object} oLocalUnic
|
||||||
|
* @param {Array} aLocalEmails
|
||||||
|
*/
|
||||||
|
MessageModel.replyHelper = function (aMessageEmails, oLocalUnic, aLocalEmails)
|
||||||
|
{
|
||||||
|
if (aMessageEmails && 0 < aMessageEmails.length)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = aMessageEmails.length
|
||||||
|
;
|
||||||
|
|
||||||
|
for (; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
if (Utils.isUnd(oLocalUnic[aMessageEmails[iIndex].email]))
|
||||||
|
{
|
||||||
|
oLocalUnic[aMessageEmails[iIndex].email] = true;
|
||||||
|
aLocalEmails.push(aMessageEmails[iIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AjaxJsonMessage} oJsonMessage
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.initByJson = function (oJsonMessage)
|
||||||
|
{
|
||||||
|
var bResult = false;
|
||||||
|
if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object'])
|
||||||
|
{
|
||||||
|
this.folderFullNameRaw = oJsonMessage.Folder;
|
||||||
|
this.uid = oJsonMessage.Uid;
|
||||||
|
this.requestHash = oJsonMessage.RequestHash;
|
||||||
|
|
||||||
|
this.prefetched = false;
|
||||||
|
|
||||||
|
this.size(Utils.pInt(oJsonMessage.Size));
|
||||||
|
|
||||||
|
this.from = MessageModel.initEmailsFromJson(oJsonMessage.From);
|
||||||
|
this.to = MessageModel.initEmailsFromJson(oJsonMessage.To);
|
||||||
|
this.cc = MessageModel.initEmailsFromJson(oJsonMessage.Cc);
|
||||||
|
this.bcc = MessageModel.initEmailsFromJson(oJsonMessage.Bcc);
|
||||||
|
this.replyTo = MessageModel.initEmailsFromJson(oJsonMessage.ReplyTo);
|
||||||
|
|
||||||
|
this.subject(oJsonMessage.Subject);
|
||||||
|
this.dateTimeStampInUTC(Utils.pInt(oJsonMessage.DateTimeStampInUTC));
|
||||||
|
this.hasAttachments(!!oJsonMessage.HasAttachments);
|
||||||
|
this.attachmentsMainType(oJsonMessage.AttachmentsMainType);
|
||||||
|
|
||||||
|
this.fromEmailString(MessageModel.emailsToLine(this.from, true));
|
||||||
|
this.toEmailsString(MessageModel.emailsToLine(this.to, true));
|
||||||
|
|
||||||
|
this.parentUid(Utils.pInt(oJsonMessage.ParentThread));
|
||||||
|
this.threads(Utils.isArray(oJsonMessage.Threads) ? oJsonMessage.Threads : []);
|
||||||
|
this.threadsLen(Utils.pInt(oJsonMessage.ThreadsLen));
|
||||||
|
|
||||||
|
this.initFlagsByJson(oJsonMessage);
|
||||||
|
this.computeSenderEmail();
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageModel.prototype.computeSenderEmail = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sSent = RL.data().sentFolder(),
|
||||||
|
sDraft = RL.data().draftFolder()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.senderEmailsString(this.folderFullNameRaw === sSent || this.folderFullNameRaw === sDraft ?
|
||||||
|
this.toEmailsString() : this.fromEmailString());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AjaxJsonMessage} oJsonMessage
|
||||||
|
* @return {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.hasAttachments(!!oJsonMessage.HasAttachments);
|
||||||
|
this.attachmentsMainType(oJsonMessage.AttachmentsMainType);
|
||||||
|
|
||||||
|
this.foundedCIDs = Utils.isArray(oJsonMessage.FoundedCIDs) ? oJsonMessage.FoundedCIDs : [];
|
||||||
|
this.attachments(this.initAttachmentsFromJson(oJsonMessage.Attachments));
|
||||||
|
|
||||||
|
this.computeSenderEmail();
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {(AjaxJsonAttachment|null)} oJsonAttachments
|
||||||
|
* @return {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
|
||||||
|
* @return {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);
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} bFriendlyView
|
||||||
|
* @param {boolean=} bWrapWithLink = false
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.fromToLine = function (bFriendlyView, bWrapWithLink)
|
||||||
|
{
|
||||||
|
return MessageModel.emailsToLine(this.from, bFriendlyView, bWrapWithLink);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} bFriendlyView
|
||||||
|
* @param {boolean=} bWrapWithLink = false
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.toToLine = function (bFriendlyView, bWrapWithLink)
|
||||||
|
{
|
||||||
|
return MessageModel.emailsToLine(this.to, bFriendlyView, bWrapWithLink);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} bFriendlyView
|
||||||
|
* @param {boolean=} bWrapWithLink = false
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.ccToLine = function (bFriendlyView, bWrapWithLink)
|
||||||
|
{
|
||||||
|
return MessageModel.emailsToLine(this.cc, bFriendlyView, bWrapWithLink);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} bFriendlyView
|
||||||
|
* @param {boolean=} bWrapWithLink = false
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.bccToLine = function (bFriendlyView, bWrapWithLink)
|
||||||
|
{
|
||||||
|
return MessageModel.emailsToLine(this.bcc, bFriendlyView, bWrapWithLink);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.lineAsCcc = function ()
|
||||||
|
{
|
||||||
|
var aResult = [];
|
||||||
|
if (this.deleted())
|
||||||
|
{
|
||||||
|
aResult.push('deleted');
|
||||||
|
}
|
||||||
|
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.hasAttachments())
|
||||||
|
{
|
||||||
|
aResult.push('withAttachments');
|
||||||
|
switch (this.attachmentsMainType())
|
||||||
|
{
|
||||||
|
case 'image':
|
||||||
|
aResult.push('imageOnlyAttachments');
|
||||||
|
break;
|
||||||
|
case 'archive':
|
||||||
|
aResult.push('archiveOnlyAttachments');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.newForAnimation())
|
||||||
|
{
|
||||||
|
aResult.push('new');
|
||||||
|
}
|
||||||
|
if ('' === this.subject())
|
||||||
|
{
|
||||||
|
aResult.push('emptySubject');
|
||||||
|
}
|
||||||
|
if (0 < this.parentUid())
|
||||||
|
{
|
||||||
|
aResult.push('hasParentMessage');
|
||||||
|
}
|
||||||
|
if (0 < this.threadsLen() && 0 === this.parentUid())
|
||||||
|
{
|
||||||
|
aResult.push('hasChildrenMessage');
|
||||||
|
}
|
||||||
|
if (this.hasUnseenSubMessage())
|
||||||
|
{
|
||||||
|
aResult.push('hasUnseenSubMessage');
|
||||||
|
}
|
||||||
|
if (this.hasFlaggedSubMessage())
|
||||||
|
{
|
||||||
|
aResult.push('hasFlaggedSubMessage');
|
||||||
|
}
|
||||||
|
|
||||||
|
return aResult.join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.hasVisibleAttachments = function ()
|
||||||
|
{
|
||||||
|
return !!_.find(this.attachments(), function (oAttachment) {
|
||||||
|
return !oAttachment.isLinked;
|
||||||
|
});
|
||||||
|
// return 0 < this.attachments().length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sCid
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.messageId = function ()
|
||||||
|
{
|
||||||
|
return this.sMessageId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.inReplyTo = function ()
|
||||||
|
{
|
||||||
|
return this.sInReplyTo;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.references = function ()
|
||||||
|
{
|
||||||
|
return this.sReferences;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.fromAsSingleEmail = function ()
|
||||||
|
{
|
||||||
|
return Utils.isArray(this.from) && this.from[0] ? this.from[0].email : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.viewLink = function ()
|
||||||
|
{
|
||||||
|
return RL.link().messageViewLink(this.requestHash);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.downloadLink = function ()
|
||||||
|
{
|
||||||
|
return RL.link().messageDownloadLink(this.requestHash);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oExcludeEmails
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.replyEmails = function (oExcludeEmails)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aResult = [],
|
||||||
|
oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails
|
||||||
|
;
|
||||||
|
|
||||||
|
MessageModel.replyHelper(this.replyTo, oUnic, aResult);
|
||||||
|
if (0 === aResult.length)
|
||||||
|
{
|
||||||
|
MessageModel.replyHelper(this.from, oUnic, aResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return aResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oExcludeEmails
|
||||||
|
* @return {Array.<Array>}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.replyAllEmails = function (oExcludeEmails)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aToResult = [],
|
||||||
|
aCcResult = [],
|
||||||
|
oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails
|
||||||
|
;
|
||||||
|
|
||||||
|
MessageModel.replyHelper(this.replyTo, oUnic, aToResult);
|
||||||
|
if (0 === aToResult.length)
|
||||||
|
{
|
||||||
|
MessageModel.replyHelper(this.from, oUnic, aToResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageModel.replyHelper(this.to, oUnic, aToResult);
|
||||||
|
MessageModel.replyHelper(this.cc, oUnic, aCcResult);
|
||||||
|
|
||||||
|
return [aToResult, aCcResult];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.textBodyToString = function ()
|
||||||
|
{
|
||||||
|
return this.body ? this.body.html() : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.attachmentsToStringLine = function ()
|
||||||
|
{
|
||||||
|
var aAttachLines = _.map(this.attachments(), function (oItem) {
|
||||||
|
return oItem.fileName + ' (' + oItem.friendlySize + ')';
|
||||||
|
});
|
||||||
|
|
||||||
|
return aAttachLines && 0 < aAttachLines.length ? aAttachLines.join(', ') : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.getDataForWindowPopup = function ()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
'popupFrom': this.fromToLine(false),
|
||||||
|
'popupTo': this.toToLine(false),
|
||||||
|
'popupCc': this.ccToLine(false),
|
||||||
|
'popupBcc': this.bccToLine(false),
|
||||||
|
'popupSubject': this.subject(),
|
||||||
|
'popupDate': this.fullFormatDateValue(),
|
||||||
|
'popupAttachments': this.attachmentsToStringLine(),
|
||||||
|
'popupBody': this.textBodyToString()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean=} bPrint = false
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.viewPopupMessage = function (bPrint)
|
||||||
|
{
|
||||||
|
Utils.windowPopupKnockout(this.getDataForWindowPopup(), 'PopupsWindowSimpleMessage', this.subject(), function (oPopupWin) {
|
||||||
|
if (oPopupWin && oPopupWin.document && oPopupWin.document.body)
|
||||||
|
{
|
||||||
|
$('img.lazy', oPopupWin.document.body).each(function (iIndex, oImg) {
|
||||||
|
|
||||||
|
var
|
||||||
|
$oImg = $(oImg),
|
||||||
|
sOrig = $oImg.data('original'),
|
||||||
|
sSrc = $oImg.attr('src')
|
||||||
|
;
|
||||||
|
|
||||||
|
if (0 <= iIndex && sOrig && !sSrc)
|
||||||
|
{
|
||||||
|
$oImg.attr('src', sOrig);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bPrint)
|
||||||
|
{
|
||||||
|
window.setTimeout(function () {
|
||||||
|
oPopupWin.print();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageModel.prototype.printMessage = function ()
|
||||||
|
{
|
||||||
|
this.viewPopupMessage(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.generateUid = function ()
|
||||||
|
{
|
||||||
|
return this.folderFullNameRaw + '/' + this.uid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {MessageModel} oMessage
|
||||||
|
* @return {MessageModel}
|
||||||
|
*/
|
||||||
|
MessageModel.prototype.populateByMessageListItem = function (oMessage)
|
||||||
|
{
|
||||||
|
this.folderFullNameRaw = oMessage.folderFullNameRaw;
|
||||||
|
this.uid = oMessage.uid;
|
||||||
|
this.requestHash = oMessage.requestHash;
|
||||||
|
this.subject(oMessage.subject());
|
||||||
|
this.size(oMessage.size());
|
||||||
|
this.dateTimeStampInUTC(oMessage.dateTimeStampInUTC());
|
||||||
|
this.priority(oMessage.priority());
|
||||||
|
|
||||||
|
this.fromEmailString(oMessage.fromEmailString());
|
||||||
|
this.toEmailsString(oMessage.toEmailsString());
|
||||||
|
|
||||||
|
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.unseen(oMessage.unseen());
|
||||||
|
this.flagged(oMessage.flagged());
|
||||||
|
this.answered(oMessage.answered());
|
||||||
|
this.forwarded(oMessage.forwarded());
|
||||||
|
|
||||||
|
this.selected(oMessage.selected());
|
||||||
|
this.checked(oMessage.checked());
|
||||||
|
this.hasAttachments(oMessage.hasAttachments());
|
||||||
|
this.attachmentsMainType(oMessage.attachmentsMainType());
|
||||||
|
|
||||||
|
this.moment(oMessage.moment());
|
||||||
|
|
||||||
|
this.body = null;
|
||||||
|
// this.isRtl(oMessage.isRtl());
|
||||||
|
// this.isHtml(false);
|
||||||
|
// this.hasImages(false);
|
||||||
|
// this.attachments([]);
|
||||||
|
|
||||||
|
this.priority(Enums.MessagePriority.Normal);
|
||||||
|
this.aDraftInfo = [];
|
||||||
|
this.sMessageId = '';
|
||||||
|
this.sInReplyTo = '';
|
||||||
|
this.sReferences = '';
|
||||||
|
|
||||||
|
this.parentUid(oMessage.parentUid());
|
||||||
|
this.threads(oMessage.threads());
|
||||||
|
this.threadsLen(oMessage.threadsLen());
|
||||||
|
|
||||||
|
this.computeSenderEmail();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
$('[data-x-src]', this.body).each(function () {
|
||||||
|
if (bLazy && $(this).is('img'))
|
||||||
|
{
|
||||||
|
$(this)
|
||||||
|
.addClass('lazy')
|
||||||
|
.attr('data-original', $(this).attr('data-x-src'))
|
||||||
|
.removeAttr('data-x-src')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$(this).attr('src', $(this).attr('data-x-src')).removeAttr('data-x-src');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('[data-x-style-url]', this.body).each(function () {
|
||||||
|
var sStyle = Utils.trim($(this).attr('style'));
|
||||||
|
sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; ');
|
||||||
|
$(this).attr('style', sStyle + $(this).attr('data-x-style-url')).removeAttr('data-x-style-url');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bLazy)
|
||||||
|
{
|
||||||
|
$('img.lazy', this.body).addClass('lazy-inited').lazyload({
|
||||||
|
'threshold' : 400,
|
||||||
|
'effect' : 'fadeIn',
|
||||||
|
'skip_invisible' : false,
|
||||||
|
'container': $('.RL-MailMessageView .messageView .messageItem .content')[0]
|
||||||
|
});
|
||||||
|
|
||||||
|
$window.resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.windowResize(500);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageModel.prototype.showInternalImages = function (bLazy)
|
||||||
|
{
|
||||||
|
if (this.body && !this.body.data('rl-init-internal-images'))
|
||||||
|
{
|
||||||
|
bLazy = Utils.isUnd(bLazy) ? false : bLazy;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.body.data('rl-init-internal-images', true);
|
||||||
|
|
||||||
|
$('[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);
|
||||||
|
}
|
||||||
|
};
|
||||||
178
dev/Screens/AbstractSettings.js
Normal file
178
dev/Screens/AbstractSettings.js
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} aViewModels
|
||||||
|
* @constructor
|
||||||
|
* @extends KnoinAbstractScreen
|
||||||
|
*/
|
||||||
|
function AbstractSettings(aViewModels)
|
||||||
|
{
|
||||||
|
KnoinAbstractScreen.call(this, 'settings', aViewModels);
|
||||||
|
|
||||||
|
this.menu = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.oCurrentSubScreen = null;
|
||||||
|
this.oViewModelPlace = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AbstractSettings.prototype, KnoinAbstractScreen.prototype);
|
||||||
|
|
||||||
|
AbstractSettings.prototype.onRoute = function (sSubName)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
oSettingsScreen = null,
|
||||||
|
RoutedSettingsViewModel = null,
|
||||||
|
oViewModelPlace = null,
|
||||||
|
oViewModelDom = null
|
||||||
|
;
|
||||||
|
|
||||||
|
RoutedSettingsViewModel = _.find(ViewModels['settings'], function (SettingsViewModel) {
|
||||||
|
return SettingsViewModel && SettingsViewModel.__rlSettingsData &&
|
||||||
|
sSubName === SettingsViewModel.__rlSettingsData.Route;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (RoutedSettingsViewModel)
|
||||||
|
{
|
||||||
|
if (_.find(ViewModels['settings-removed'], function (DisabledSettingsViewModel) {
|
||||||
|
return DisabledSettingsViewModel && DisabledSettingsViewModel === RoutedSettingsViewModel;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
RoutedSettingsViewModel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RoutedSettingsViewModel && _.find(ViewModels['settings-disabled'], function (DisabledSettingsViewModel) {
|
||||||
|
return DisabledSettingsViewModel && DisabledSettingsViewModel === RoutedSettingsViewModel;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
RoutedSettingsViewModel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RoutedSettingsViewModel)
|
||||||
|
{
|
||||||
|
if (RoutedSettingsViewModel.__builded && RoutedSettingsViewModel.__vm)
|
||||||
|
{
|
||||||
|
oSettingsScreen = RoutedSettingsViewModel.__vm;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oViewModelPlace = this.oViewModelPlace;
|
||||||
|
if (oViewModelPlace && 1 === oViewModelPlace.length)
|
||||||
|
{
|
||||||
|
RoutedSettingsViewModel = /** @type {?Function} */ RoutedSettingsViewModel;
|
||||||
|
oSettingsScreen = new RoutedSettingsViewModel();
|
||||||
|
|
||||||
|
oViewModelDom = $('<div></div>').addClass('rl-settings-view-model').hide().attr('data-bind',
|
||||||
|
'template: {name: "' + RoutedSettingsViewModel.__rlSettingsData.Template + '"}, i18nInit: true');
|
||||||
|
|
||||||
|
oViewModelDom.appendTo(oViewModelPlace);
|
||||||
|
|
||||||
|
oSettingsScreen.data = RL.data();
|
||||||
|
oSettingsScreen.viewModelDom = oViewModelDom;
|
||||||
|
|
||||||
|
oSettingsScreen.__rlSettingsData = RoutedSettingsViewModel.__rlSettingsData;
|
||||||
|
|
||||||
|
RoutedSettingsViewModel.__dom = oViewModelDom;
|
||||||
|
RoutedSettingsViewModel.__builded = true;
|
||||||
|
RoutedSettingsViewModel.__vm = oSettingsScreen;
|
||||||
|
|
||||||
|
ko.applyBindings(oSettingsScreen, oViewModelDom[0]);
|
||||||
|
kn.delegateRun(oSettingsScreen, 'onBuild', [oViewModelDom]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utils.log('Cannot find sub settings view model position: SettingsSubScreen');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oSettingsScreen)
|
||||||
|
{
|
||||||
|
_.defer(function () {
|
||||||
|
// hide
|
||||||
|
if (self.oCurrentSubScreen)
|
||||||
|
{
|
||||||
|
kn.delegateRun(self.oCurrentSubScreen, 'onHide');
|
||||||
|
self.oCurrentSubScreen.viewModelDom.hide();
|
||||||
|
}
|
||||||
|
// --
|
||||||
|
|
||||||
|
self.oCurrentSubScreen = oSettingsScreen;
|
||||||
|
|
||||||
|
// show
|
||||||
|
if (self.oCurrentSubScreen)
|
||||||
|
{
|
||||||
|
self.oCurrentSubScreen.viewModelDom.show();
|
||||||
|
kn.delegateRun(self.oCurrentSubScreen, 'onShow');
|
||||||
|
|
||||||
|
_.each(self.menu(), function (oItem) {
|
||||||
|
oItem.selected(oSettingsScreen && oSettingsScreen.__rlSettingsData && oItem.route === oSettingsScreen.__rlSettingsData.Route);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#rl-content .b-settings .b-content .content').scrollTop(0);
|
||||||
|
}
|
||||||
|
// --
|
||||||
|
|
||||||
|
Utils.windowResize();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kn.setHash(RL.link().settings(), false, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractSettings.prototype.onHide = function ()
|
||||||
|
{
|
||||||
|
if (this.oCurrentSubScreen && this.oCurrentSubScreen.viewModelDom)
|
||||||
|
{
|
||||||
|
kn.delegateRun(this.oCurrentSubScreen, 'onHide');
|
||||||
|
this.oCurrentSubScreen.viewModelDom.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractSettings.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
_.each(ViewModels['settings'], function (SettingsViewModel) {
|
||||||
|
if (SettingsViewModel && SettingsViewModel.__rlSettingsData &&
|
||||||
|
!_.find(ViewModels['settings-removed'], function (RemoveSettingsViewModel) {
|
||||||
|
return RemoveSettingsViewModel && RemoveSettingsViewModel === SettingsViewModel;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
this.menu.push({
|
||||||
|
'route': SettingsViewModel.__rlSettingsData.Route,
|
||||||
|
'label': SettingsViewModel.__rlSettingsData.Label,
|
||||||
|
'selected': ko.observable(false),
|
||||||
|
'disabled': !!_.find(ViewModels['settings-disabled'], function (DisabledSettingsViewModel) {
|
||||||
|
return DisabledSettingsViewModel && DisabledSettingsViewModel === SettingsViewModel;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.oViewModelPlace = $('#rl-content #rl-settings-subscreen');
|
||||||
|
};
|
||||||
|
|
||||||
|
AbstractSettings.prototype.routes = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
DefaultViewModel = _.find(ViewModels['settings'], function (SettingsViewModel) {
|
||||||
|
return SettingsViewModel && SettingsViewModel.__rlSettingsData && SettingsViewModel.__rlSettingsData['IsDefault'];
|
||||||
|
}),
|
||||||
|
sDefaultRoute = DefaultViewModel ? DefaultViewModel.__rlSettingsData['Route'] : 'general',
|
||||||
|
oRules = {
|
||||||
|
'subname': /^(.*)$/,
|
||||||
|
'normalize_': function (oRequest, oVals) {
|
||||||
|
oVals.subname = Utils.isUnd(oVals.subname) ? sDefaultRoute : Utils.pString(oVals.subname);
|
||||||
|
return [oVals.subname];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
return [
|
||||||
|
['{subname}/', oRules],
|
||||||
|
['{subname}', oRules],
|
||||||
|
['', oRules]
|
||||||
|
];
|
||||||
|
};
|
||||||
17
dev/Screens/AdminLogin.js
Normal file
17
dev/Screens/AdminLogin.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends KnoinAbstractScreen
|
||||||
|
*/
|
||||||
|
function AdminLoginScreen()
|
||||||
|
{
|
||||||
|
KnoinAbstractScreen.call(this, 'login', [AdminLoginViewModel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AdminLoginScreen.prototype, KnoinAbstractScreen.prototype);
|
||||||
|
|
||||||
|
AdminLoginScreen.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
RL.setTitle('');
|
||||||
|
};
|
||||||
22
dev/Screens/AdminSettings.js
Normal file
22
dev/Screens/AdminSettings.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractSettings
|
||||||
|
*/
|
||||||
|
function AdminSettingsScreen()
|
||||||
|
{
|
||||||
|
AbstractSettings.call(this, [
|
||||||
|
AdminMenuViewModel,
|
||||||
|
AdminPaneViewModel
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AdminSettingsScreen.prototype, AbstractSettings.prototype);
|
||||||
|
|
||||||
|
AdminSettingsScreen.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
// AbstractSettings.prototype.onShow.call(this);
|
||||||
|
|
||||||
|
RL.setTitle('');
|
||||||
|
};
|
||||||
17
dev/Screens/Login.js
Normal file
17
dev/Screens/Login.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends KnoinAbstractScreen
|
||||||
|
*/
|
||||||
|
function LoginScreen()
|
||||||
|
{
|
||||||
|
KnoinAbstractScreen.call(this, 'login', [LoginViewModel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(LoginScreen.prototype, KnoinAbstractScreen.prototype);
|
||||||
|
|
||||||
|
LoginScreen.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
RL.setTitle(Utils.i18n('TITLES/LOGIN'));
|
||||||
|
};
|
||||||
165
dev/Screens/MailBox.js
Normal file
165
dev/Screens/MailBox.js
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends KnoinAbstractScreen
|
||||||
|
*/
|
||||||
|
function MailBoxScreen()
|
||||||
|
{
|
||||||
|
KnoinAbstractScreen.call(this, 'mailbox', [
|
||||||
|
MailBoxSystemDropDownViewModel,
|
||||||
|
MailBoxFolderListViewModel,
|
||||||
|
MailBoxMessageListViewModel,
|
||||||
|
MailBoxMessageViewViewModel
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.oLastRoute = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(MailBoxScreen.prototype, KnoinAbstractScreen.prototype);
|
||||||
|
|
||||||
|
MailBoxScreen.prototype.oLastRoute = {};
|
||||||
|
|
||||||
|
MailBoxScreen.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
var sEmail = RL.data().accountEmail();
|
||||||
|
RL.setTitle(('' === sEmail ? '' : sEmail + ' - ') + Utils.i18n('TITLES/MAILBOX'));
|
||||||
|
};
|
||||||
|
|
||||||
|
MailBoxScreen.prototype.onRoute = function (sFolderHash, iPage, sSearch)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oData = RL.data(),
|
||||||
|
sFolderFullNameRaw = RL.cache().getFolderFullNameRaw(sFolderHash),
|
||||||
|
oFolder = RL.cache().getFolderFromCacheList(sFolderFullNameRaw)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oFolder)
|
||||||
|
{
|
||||||
|
oData
|
||||||
|
.currentFolder(oFolder)
|
||||||
|
.messageListPage(iPage)
|
||||||
|
.messageListSearch(sSearch)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!oData.usePreviewPane() && oData.message())
|
||||||
|
{
|
||||||
|
oData.message(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.reloadMessageList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MailBoxScreen.prototype.onStart = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oData = RL.data(),
|
||||||
|
fResizeFunction = function () {
|
||||||
|
Utils.windowResize();
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (RL.settingsGet('AllowAdditionalAccounts') || RL.settingsGet('AllowIdentities'))
|
||||||
|
{
|
||||||
|
RL.accountsAndIdentities();
|
||||||
|
}
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
RL.quota();
|
||||||
|
}, 1000 * 5);
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
if ('INBOX' !== oData.currentFolderFullNameRaw())
|
||||||
|
{
|
||||||
|
RL.folderInformation('INBOX');
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
var sFolder = RL.data().spamFolder();
|
||||||
|
if (sFolder !== oData.currentFolderFullNameRaw())
|
||||||
|
{
|
||||||
|
RL.folderInformation(sFolder);
|
||||||
|
}
|
||||||
|
}, 1500);
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
var sFolder = RL.data().draftFolder();
|
||||||
|
if (sFolder !== oData.currentFolderFullNameRaw())
|
||||||
|
{
|
||||||
|
RL.folderInformation(sFolder);
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
RL.remote().appDelayStart(Utils.emptyFunction);
|
||||||
|
}, 1000 * 35);
|
||||||
|
|
||||||
|
window.setInterval(function () {
|
||||||
|
RL.folderInformation('INBOX');
|
||||||
|
}, 1000 * 60 * 2);
|
||||||
|
|
||||||
|
window.setInterval(function () {
|
||||||
|
RL.quota();
|
||||||
|
}, 1000 * 60 * 5);
|
||||||
|
|
||||||
|
$html.toggleClass('rl-no-preview-pane', !oData.usePreviewPane());
|
||||||
|
|
||||||
|
oData.folderList.subscribe(fResizeFunction);
|
||||||
|
oData.messageList.subscribe(fResizeFunction);
|
||||||
|
oData.message.subscribe(fResizeFunction);
|
||||||
|
|
||||||
|
oData.usePreviewPane.subscribe(function (bValue) {
|
||||||
|
$html.toggleClass('rl-no-preview-pane', !bValue);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
MailBoxScreen.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
if (!Globals.bMobileDevice)
|
||||||
|
{
|
||||||
|
_.defer(function () {
|
||||||
|
Utils.initLayoutResizer('#rl-resizer-left', '#rl-resizer-right', '#rl-right',
|
||||||
|
350, 800, 350, 350, Enums.ClientSideKeyName.MailBoxListSize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MailBoxScreen.prototype.routes = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
fNormS = function (oRequest, oVals) {
|
||||||
|
oVals[0] = Utils.pString(oVals[0]);
|
||||||
|
oVals[1] = Utils.pInt(oVals[1]);
|
||||||
|
oVals[1] = 0 >= oVals[1] ? 1 : oVals[1];
|
||||||
|
oVals[2] = Utils.pString(oVals[2]);
|
||||||
|
|
||||||
|
if ('' === oRequest)
|
||||||
|
{
|
||||||
|
oVals[0] = 'Inbox';
|
||||||
|
oVals[1] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [decodeURI(oVals[0]), oVals[1], decodeURI(oVals[2])];
|
||||||
|
},
|
||||||
|
fNormD = function (oRequest, oVals) {
|
||||||
|
oVals[0] = Utils.pString(oVals[0]);
|
||||||
|
oVals[1] = Utils.pString(oVals[1]);
|
||||||
|
|
||||||
|
if ('' === oRequest)
|
||||||
|
{
|
||||||
|
oVals[0] = 'Inbox';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [decodeURI(oVals[0]), 1, decodeURI(oVals[1])];
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
return [
|
||||||
|
[/^([a-zA-Z0-9]+)\/p([1-9][0-9]*)\/(.+)\/?$/, {'normalize_': fNormS}],
|
||||||
|
[/^([a-zA-Z0-9]+)\/p([1-9][0-9]*)\/?$/, {'normalize_': fNormS}],
|
||||||
|
[/^([a-zA-Z0-9]+)\/(.+)\/?$/, {'normalize_': fNormD}],
|
||||||
|
[/^([^\/]*)$/, {'normalize_': fNormS}]
|
||||||
|
];
|
||||||
|
};
|
||||||
29
dev/Screens/Settings.js
Normal file
29
dev/Screens/Settings.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractSettings
|
||||||
|
*/
|
||||||
|
function SettingsScreen()
|
||||||
|
{
|
||||||
|
AbstractSettings.call(this, [
|
||||||
|
SettingsSystemDropDownViewModel,
|
||||||
|
SettingsMenuViewModel,
|
||||||
|
SettingsPaneViewModel
|
||||||
|
]);
|
||||||
|
|
||||||
|
Utils.initOnStartOrLangChange(function () {
|
||||||
|
this.sSettingsTitle = Utils.i18n('TITLES/SETTINGS');
|
||||||
|
}, this, function () {
|
||||||
|
RL.setTitle(this.sSettingsTitle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(SettingsScreen.prototype, AbstractSettings.prototype);
|
||||||
|
|
||||||
|
SettingsScreen.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
// AbstractSettings.prototype.onShow.call(this);
|
||||||
|
|
||||||
|
RL.setTitle(this.sSettingsTitle);
|
||||||
|
};
|
||||||
67
dev/Settings/Accounts.js
Normal file
67
dev/Settings/Accounts.js
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsAccounts()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.accounts = oData.accounts;
|
||||||
|
|
||||||
|
this.processText = ko.computed(function () {
|
||||||
|
return oData.accountsLoading() ? Utils.i18n('SETTINGS_ACCOUNTS/LOADING_PROCESS') : '';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.visibility = ko.computed(function () {
|
||||||
|
return '' === this.processText() ? 'hidden' : 'visible';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.accountForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this,
|
||||||
|
function (oPrev) {
|
||||||
|
if (oPrev)
|
||||||
|
{
|
||||||
|
oPrev.deleteAccess(false);
|
||||||
|
}
|
||||||
|
}, function (oNext) {
|
||||||
|
if (oNext)
|
||||||
|
{
|
||||||
|
oNext.deleteAccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsAccounts, 'SettingsAccounts', 'SETTINGS_LABELS/LABEL_ACCOUNTS_NAME', 'accounts');
|
||||||
|
|
||||||
|
SettingsAccounts.prototype.addNewAccount = function ()
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsAddAccountViewModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {AccountModel} oAccountToRemove
|
||||||
|
*/
|
||||||
|
SettingsAccounts.prototype.deleteAccount = function (oAccountToRemove)
|
||||||
|
{
|
||||||
|
if (oAccountToRemove && oAccountToRemove.deleteAccess())
|
||||||
|
{
|
||||||
|
this.accountForDeletion(null);
|
||||||
|
|
||||||
|
var
|
||||||
|
fRemoveAccount = function (oAccount) {
|
||||||
|
return oAccountToRemove === oAccount;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oAccountToRemove)
|
||||||
|
{
|
||||||
|
this.accounts.remove(fRemoveAccount);
|
||||||
|
|
||||||
|
RL.remote().accountDelete(function () {
|
||||||
|
RL.accountsAndIdentities();
|
||||||
|
}, oAccountToRemove.email);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
65
dev/Settings/ChangePassword.js
Normal file
65
dev/Settings/ChangePassword.js
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsChangePasswordScreen()
|
||||||
|
{
|
||||||
|
this.changeProcess = ko.observable(false);
|
||||||
|
|
||||||
|
this.passwordUpdateError = ko.observable(false);
|
||||||
|
this.passwordUpdateSuccess = ko.observable(false);
|
||||||
|
|
||||||
|
this.currentPassword = ko.observable('');
|
||||||
|
this.newPassword = ko.observable('');
|
||||||
|
|
||||||
|
this.currentPassword.subscribe(function () {
|
||||||
|
this.passwordUpdateError(false);
|
||||||
|
this.passwordUpdateSuccess(false);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.newPassword.subscribe(function () {
|
||||||
|
this.passwordUpdateError(false);
|
||||||
|
this.passwordUpdateSuccess(false);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.saveNewPasswordCommand = Utils.createCommand(this, function () {
|
||||||
|
|
||||||
|
this.changeProcess(true);
|
||||||
|
|
||||||
|
this.passwordUpdateError(false);
|
||||||
|
this.passwordUpdateSuccess(false);
|
||||||
|
|
||||||
|
RL.remote().changePassword(this.onChangePasswordResponse, this.currentPassword(), this.newPassword());
|
||||||
|
|
||||||
|
}, function () {
|
||||||
|
return !this.changeProcess() && '' !== this.currentPassword() && '' !== this.newPassword();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onChangePasswordResponse = _.bind(this.onChangePasswordResponse, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsChangePasswordScreen, 'SettingsChangePassword', 'SETTINGS_LABELS/LABEL_CHANGE_PASSWORD_NAME', 'change-password');
|
||||||
|
|
||||||
|
SettingsChangePasswordScreen.prototype.onHide = function ()
|
||||||
|
{
|
||||||
|
this.changeProcess(false);
|
||||||
|
this.currentPassword('');
|
||||||
|
this.newPassword('');
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsChangePasswordScreen.prototype.onChangePasswordResponse = function (sResult, oData)
|
||||||
|
{
|
||||||
|
this.changeProcess(false);
|
||||||
|
if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
|
||||||
|
{
|
||||||
|
this.currentPassword('');
|
||||||
|
this.newPassword('');
|
||||||
|
|
||||||
|
this.passwordUpdateSuccess(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.passwordUpdateError(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
196
dev/Settings/Folders.js
Normal file
196
dev/Settings/Folders.js
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsFolders()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.foldersListError = oData.foldersListError;
|
||||||
|
this.folderList = oData.folderList;
|
||||||
|
|
||||||
|
this.processText = ko.computed(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
oData = RL.data(),
|
||||||
|
bLoading = oData.foldersLoading(),
|
||||||
|
bCreating = oData.foldersCreating(),
|
||||||
|
bDeleting = oData.foldersDeleting(),
|
||||||
|
bRenaming = oData.foldersRenaming()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (bCreating)
|
||||||
|
{
|
||||||
|
return Utils.i18n('SETTINGS_FOLDERS/CREATING_PROCESS');
|
||||||
|
}
|
||||||
|
else if (bDeleting)
|
||||||
|
{
|
||||||
|
return Utils.i18n('SETTINGS_FOLDERS/DELETING_PROCESS');
|
||||||
|
}
|
||||||
|
else if (bRenaming)
|
||||||
|
{
|
||||||
|
return Utils.i18n('SETTINGS_FOLDERS/RENAMING_PROCESS');
|
||||||
|
}
|
||||||
|
else if (bLoading)
|
||||||
|
{
|
||||||
|
return Utils.i18n('SETTINGS_FOLDERS/LOADING_PROCESS');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.visibility = ko.computed(function () {
|
||||||
|
return '' === this.processText() ? 'hidden' : 'visible';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.folderForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this,
|
||||||
|
function (oPrev) {
|
||||||
|
if (oPrev)
|
||||||
|
{
|
||||||
|
oPrev.deleteAccess(false);
|
||||||
|
}
|
||||||
|
}, function (oNext) {
|
||||||
|
if (oNext)
|
||||||
|
{
|
||||||
|
oNext.deleteAccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
|
||||||
|
this.folderForEdit = ko.observable(null).extend({'toggleSubscribe': [this,
|
||||||
|
function (oPrev) {
|
||||||
|
if (oPrev)
|
||||||
|
{
|
||||||
|
oPrev.edited(false);
|
||||||
|
}
|
||||||
|
}, function (oNext) {
|
||||||
|
if (oNext && oNext.canBeEdited())
|
||||||
|
{
|
||||||
|
oNext.edited(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
|
||||||
|
this.useImapSubscribe = !!RL.settingsGet('UseImapSubscribe');
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsFolders, 'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders');
|
||||||
|
|
||||||
|
SettingsFolders.prototype.folderEditOnEnter = function (oFolder)
|
||||||
|
{
|
||||||
|
var sEditName = oFolder ? Utils.trim(oFolder.nameForEdit()) : '';
|
||||||
|
if ('' !== sEditName && oFolder.name() !== sEditName)
|
||||||
|
{
|
||||||
|
RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, '');
|
||||||
|
|
||||||
|
RL.data().foldersRenaming(true);
|
||||||
|
RL.remote().folderRename(function (sResult, oData) {
|
||||||
|
|
||||||
|
RL.data().foldersRenaming(false);
|
||||||
|
if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
|
||||||
|
{
|
||||||
|
RL.data().foldersListError(
|
||||||
|
oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_RENAME_FOLDER'));
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.folders(false);
|
||||||
|
|
||||||
|
}, oFolder.fullNameRaw, sEditName);
|
||||||
|
|
||||||
|
RL.cache().removeFolderFromCacheList(oFolder.fullNameRaw);
|
||||||
|
|
||||||
|
oFolder.name(sEditName);
|
||||||
|
}
|
||||||
|
|
||||||
|
oFolder.edited(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsFolders.prototype.folderEditOnEsc = function (oFolder)
|
||||||
|
{
|
||||||
|
if (oFolder)
|
||||||
|
{
|
||||||
|
oFolder.edited(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsFolders.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
RL.data().foldersListError('');
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsFolders.prototype.createFolder = function ()
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsFolderCreateViewModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsFolders.prototype.systemFolder = function ()
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsFolderSystemViewModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsFolders.prototype.deleteFolder = function (oFolderToRemove)
|
||||||
|
{
|
||||||
|
if (oFolderToRemove && oFolderToRemove.canBeDeleted() && oFolderToRemove.deleteAccess() &&
|
||||||
|
0 === oFolderToRemove.privateMessageCountAll())
|
||||||
|
{
|
||||||
|
this.folderForDeletion(null);
|
||||||
|
|
||||||
|
var
|
||||||
|
fRemoveFolder = function (oFolder) {
|
||||||
|
|
||||||
|
if (oFolderToRemove === oFolder)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
oFolder.subFolders.remove(fRemoveFolder);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oFolderToRemove)
|
||||||
|
{
|
||||||
|
RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, '');
|
||||||
|
|
||||||
|
RL.data().folderList.remove(fRemoveFolder);
|
||||||
|
|
||||||
|
RL.data().foldersDeleting(true);
|
||||||
|
RL.remote().folderDelete(function (sResult, oData) {
|
||||||
|
|
||||||
|
RL.data().foldersDeleting(false);
|
||||||
|
if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
|
||||||
|
{
|
||||||
|
RL.data().foldersListError(
|
||||||
|
oData && oData.ErrorCode ? Utils.getNotification(oData.ErrorCode) : Utils.i18n('NOTIFICATIONS/CANT_DELETE_FOLDER'));
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.folders(false);
|
||||||
|
|
||||||
|
}, oFolderToRemove.fullNameRaw);
|
||||||
|
|
||||||
|
RL.cache().removeFolderFromCacheList(oFolderToRemove.fullNameRaw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (0 < oFolderToRemove.privateMessageCountAll())
|
||||||
|
{
|
||||||
|
RL.data().foldersListError(Utils.getNotification(Enums.Notification.CantDeleteNonEmptyFolder));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsFolders.prototype.subscribeFolder = function (oFolder)
|
||||||
|
{
|
||||||
|
RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, '');
|
||||||
|
RL.remote().folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, true);
|
||||||
|
|
||||||
|
oFolder.subScribed(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsFolders.prototype.unSubscribeFolder = function (oFolder)
|
||||||
|
{
|
||||||
|
RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, '');
|
||||||
|
RL.remote().folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, false);
|
||||||
|
|
||||||
|
oFolder.subScribed(false);
|
||||||
|
};
|
||||||
155
dev/Settings/General.js
Normal file
155
dev/Settings/General.js
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsGeneral()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.mainLanguage = oData.mainLanguage;
|
||||||
|
this.mainMessagesPerPage = oData.mainMessagesPerPage;
|
||||||
|
this.mainMessagesPerPageArray = Consts.Defaults.MessagesPerPageArray;
|
||||||
|
this.editorDefaultType = oData.editorDefaultType;
|
||||||
|
this.showImages = oData.showImages;
|
||||||
|
this.interfaceAnimation = oData.interfaceAnimation;
|
||||||
|
this.useDesktopNotifications = oData.useDesktopNotifications;
|
||||||
|
this.threading = oData.threading;
|
||||||
|
this.useThreads = oData.useThreads;
|
||||||
|
this.replySameFolder = oData.replySameFolder;
|
||||||
|
this.usePreviewPane = oData.usePreviewPane;
|
||||||
|
this.useCheckboxesInList = oData.useCheckboxesInList;
|
||||||
|
this.allowLanguagesOnSettings = oData.allowLanguagesOnSettings;
|
||||||
|
|
||||||
|
this.isDesktopNotificationsSupported = ko.computed(function () {
|
||||||
|
return Enums.DesktopNotifications.NotSupported !== oData.desktopNotificationsPermisions();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.isDesktopNotificationsDenied = ko.computed(function () {
|
||||||
|
return Enums.DesktopNotifications.NotSupported === oData.desktopNotificationsPermisions() ||
|
||||||
|
Enums.DesktopNotifications.Denied === oData.desktopNotificationsPermisions();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.mainLanguageFullName = ko.computed(function () {
|
||||||
|
return Utils.convertLangName(this.mainLanguage());
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100});
|
||||||
|
this.mppTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
|
||||||
|
this.isAnimationSupported = Globals.bAnimationSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsGeneral, 'SettingsGeneral', 'SETTINGS_LABELS/LABEL_GENERAL_NAME', 'general', true);
|
||||||
|
|
||||||
|
SettingsGeneral.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
oData = RL.data(),
|
||||||
|
f1 = Utils.settingsSaveHelperSimpleFunction(self.mppTrigger, self)
|
||||||
|
;
|
||||||
|
|
||||||
|
oData.language.subscribe(function (sValue) {
|
||||||
|
|
||||||
|
self.languageTrigger(Enums.SaveSettingsStep.Animate);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
'url': RL.link().langLink(sValue),
|
||||||
|
'dataType': 'script',
|
||||||
|
'cache': true
|
||||||
|
}).done(function() {
|
||||||
|
Utils.i18nToDoc();
|
||||||
|
self.languageTrigger(Enums.SaveSettingsStep.TrueResult);
|
||||||
|
}).fail(function() {
|
||||||
|
self.languageTrigger(Enums.SaveSettingsStep.FalseResult);
|
||||||
|
}).always(function() {
|
||||||
|
_.delay(function () {
|
||||||
|
self.languageTrigger(Enums.SaveSettingsStep.Idle);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'Language': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.editorDefaultType.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'EditorDefaultType': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.messagesPerPage.subscribe(function (iValue) {
|
||||||
|
RL.remote().saveSettings(f1, {
|
||||||
|
'MPP': iValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.showImages.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'ShowImages': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.interfaceAnimation.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'InterfaceAnimation': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.useDesktopNotifications.subscribe(function (bValue) {
|
||||||
|
Utils.timeOutAction('SaveDesktopNotifications', function () {
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'DesktopNotifications': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.replySameFolder.subscribe(function (bValue) {
|
||||||
|
Utils.timeOutAction('SaveReplySameFolder', function () {
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'ReplySameFolder': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.useThreads.subscribe(function (bValue) {
|
||||||
|
|
||||||
|
oData.messageList([]);
|
||||||
|
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'UseThreads': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.usePreviewPane.subscribe(function (bValue) {
|
||||||
|
|
||||||
|
oData.messageList([]);
|
||||||
|
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'UsePreviewPane': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.useCheckboxesInList.subscribe(function (bValue) {
|
||||||
|
RL.remote().saveSettings(Utils.emptyFunction, {
|
||||||
|
'UseCheckboxesInList': bValue ? '1' : '0'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsGeneral.prototype.onShow = function ()
|
||||||
|
{
|
||||||
|
RL.data().desktopNotifications.valueHasMutated();
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsGeneral.prototype.selectLanguage = function ()
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsLanguagesViewModel);
|
||||||
|
};
|
||||||
109
dev/Settings/Identities.js
Normal file
109
dev/Settings/Identities.js
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsIdentities()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.identities = oData.identities;
|
||||||
|
|
||||||
|
this.legent = ko.computed(function () {
|
||||||
|
return Utils.i18n('SETTINGS_IDENTITIES/LEGEND_IDENTITIES_FOR', {'EMAIL': oData.accountEmail()});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.processText = ko.computed(function () {
|
||||||
|
return oData.identitiesLoading() ? Utils.i18n('SETTINGS_IDENTITIES/LOADING_PROCESS') : '';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.visibility = ko.computed(function () {
|
||||||
|
return '' === this.processText() ? 'hidden' : 'visible';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.identityForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [this,
|
||||||
|
function (oPrev) {
|
||||||
|
if (oPrev)
|
||||||
|
{
|
||||||
|
oPrev.deleteAccess(false);
|
||||||
|
}
|
||||||
|
}, function (oNext) {
|
||||||
|
if (oNext)
|
||||||
|
{
|
||||||
|
oNext.deleteAccess(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
|
||||||
|
this.signature = oData.signature;
|
||||||
|
this.signatureTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsIdentities, 'SettingsIdentities', 'SETTINGS_LABELS/LABEL_IDENTITIES_NAME', 'identities');
|
||||||
|
|
||||||
|
SettingsIdentities.prototype.addNewIdentity = function ()
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsIdentityViewModel);
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsIdentities.prototype.editIdentity = function (oIdentity)
|
||||||
|
{
|
||||||
|
kn.showScreenPopup(PopupsIdentityViewModel, [oIdentity]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {IdentityModel} oIdentityToRemove
|
||||||
|
*/
|
||||||
|
SettingsIdentities.prototype.deleteIdentity = function (oIdentityToRemove)
|
||||||
|
{
|
||||||
|
if (oIdentityToRemove && oIdentityToRemove.deleteAccess())
|
||||||
|
{
|
||||||
|
this.identityForDeletion(null);
|
||||||
|
|
||||||
|
var
|
||||||
|
fRemoveFolder = function (oIdentity) {
|
||||||
|
return oIdentityToRemove === oIdentity;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oIdentityToRemove)
|
||||||
|
{
|
||||||
|
this.identities.remove(fRemoveFolder);
|
||||||
|
|
||||||
|
RL.remote().identityDelete(function () {
|
||||||
|
RL.accountsAndIdentities();
|
||||||
|
}, oIdentityToRemove.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsIdentities.prototype.onBuild = function (oDom)
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
oDom
|
||||||
|
.on('click', '.identity-item .e-action', function () {
|
||||||
|
var oIdentityItem = ko.dataFor(this);
|
||||||
|
if (oIdentityItem)
|
||||||
|
{
|
||||||
|
self.editIdentity(oIdentityItem);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
oData = RL.data(),
|
||||||
|
f1 = Utils.settingsSaveHelperSimpleFunction(self.signatureTrigger, self)
|
||||||
|
;
|
||||||
|
|
||||||
|
oData.signature.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(f1, {
|
||||||
|
'Signature': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
52
dev/Settings/Personal.js
Normal file
52
dev/Settings/Personal.js
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsPersonal()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.displayName = oData.displayName;
|
||||||
|
this.replyTo = oData.replyTo;
|
||||||
|
this.signature = oData.signature;
|
||||||
|
|
||||||
|
this.nameTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.replyTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
this.signatureTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsPersonal, 'SettingsPersonal', 'SETTINGS_LABELS/LABEL_PERSONAL_NAME', 'personal');
|
||||||
|
|
||||||
|
SettingsPersonal.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
var self = this;
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
oData = RL.data(),
|
||||||
|
f1 = Utils.settingsSaveHelperSimpleFunction(self.nameTrigger, self),
|
||||||
|
f2 = Utils.settingsSaveHelperSimpleFunction(self.replyTrigger, self),
|
||||||
|
f3 = Utils.settingsSaveHelperSimpleFunction(self.signatureTrigger, self)
|
||||||
|
;
|
||||||
|
|
||||||
|
oData.displayName.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(f1, {
|
||||||
|
'DisplayName': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.replyTo.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(f2, {
|
||||||
|
'ReplyTo': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
oData.signature.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(f3, {
|
||||||
|
'Signature': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
};
|
||||||
68
dev/Settings/Social.js
Normal file
68
dev/Settings/Social.js
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsSocialScreen()
|
||||||
|
{
|
||||||
|
var oData = RL.data();
|
||||||
|
|
||||||
|
this.googleEnable = oData.googleEnable;
|
||||||
|
|
||||||
|
this.googleActions = oData.googleActions;
|
||||||
|
this.googleLoggined = oData.googleLoggined;
|
||||||
|
this.googleUserName = oData.googleUserName;
|
||||||
|
|
||||||
|
this.facebookEnable = oData.facebookEnable;
|
||||||
|
|
||||||
|
this.facebookActions = oData.facebookActions;
|
||||||
|
this.facebookLoggined = oData.facebookLoggined;
|
||||||
|
this.facebookUserName = oData.facebookUserName;
|
||||||
|
|
||||||
|
this.twitterEnable = oData.twitterEnable;
|
||||||
|
|
||||||
|
this.twitterActions = oData.twitterActions;
|
||||||
|
this.twitterLoggined = oData.twitterLoggined;
|
||||||
|
this.twitterUserName = oData.twitterUserName;
|
||||||
|
|
||||||
|
this.connectGoogle = Utils.createCommand(this, function () {
|
||||||
|
if (!this.googleLoggined())
|
||||||
|
{
|
||||||
|
RL.googleConnect();
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
return !this.googleLoggined() && !this.googleActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.disconnectGoogle = Utils.createCommand(this, function () {
|
||||||
|
RL.googleDisconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connectFacebook = Utils.createCommand(this, function () {
|
||||||
|
if (!this.facebookLoggined())
|
||||||
|
{
|
||||||
|
RL.facebookConnect();
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
return !this.facebookLoggined() && !this.facebookActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.disconnectFacebook = Utils.createCommand(this, function () {
|
||||||
|
RL.facebookDisconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connectTwitter = Utils.createCommand(this, function () {
|
||||||
|
if (!this.twitterLoggined())
|
||||||
|
{
|
||||||
|
RL.twitterConnect();
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
return !this.twitterLoggined() && !this.twitterActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.disconnectTwitter = Utils.createCommand(this, function () {
|
||||||
|
RL.twitterDisconnect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsSocialScreen, 'SettingsSocial', 'SETTINGS_LABELS/LABEL_SOCIAL_NAME', 'social');
|
||||||
216
dev/Settings/Themes.js
Normal file
216
dev/Settings/Themes.js
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SettingsThemes()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
oData = RL.data()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.mainTheme = oData.mainTheme;
|
||||||
|
this.customThemeType = ko.observable(RL.settingsGet('CustomThemeType'));
|
||||||
|
this.customThemeImg = ko.observable(RL.settingsGet('CustomThemeImg'));
|
||||||
|
|
||||||
|
this.themesObjects = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.customThemeUploaderProgress = ko.observable(false);
|
||||||
|
this.customThemeUploaderButton = ko.observable(null);
|
||||||
|
|
||||||
|
this.showCustomThemeConfig = ko.computed(function () {
|
||||||
|
return 'Custom' === this.mainTheme();
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.showCustomThemeConfig.subscribe(function () {
|
||||||
|
Utils.windowResize();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100});
|
||||||
|
|
||||||
|
this.oLastAjax = null;
|
||||||
|
this.iTimer = 0;
|
||||||
|
|
||||||
|
RL.data().theme.subscribe(function (sValue) {
|
||||||
|
|
||||||
|
_.each(this.themesObjects(), function (oTheme) {
|
||||||
|
oTheme.selected(sValue === oTheme.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
var
|
||||||
|
oThemeLink = $('#rlThemeLink'),
|
||||||
|
oThemeStyle = $('#rlThemeStyle'),
|
||||||
|
sUrl = oThemeLink.attr('href')
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!sUrl)
|
||||||
|
{
|
||||||
|
sUrl = oThemeStyle.attr('data-href');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sUrl)
|
||||||
|
{
|
||||||
|
sUrl = sUrl.toString().replace(/\/-\/[^\/]+\/\-\//, '/-/' + sValue + '/-/');
|
||||||
|
sUrl = sUrl.toString().replace(/\/Css\/[^\/]+\/User\//, '/Css/' + ('Custom' === sValue && window.__rlah ? window.__rlah() || '0' : '0') + '/User/');
|
||||||
|
|
||||||
|
if ('Json/' !== sUrl.substring(sUrl.length - 5, sUrl.length))
|
||||||
|
{
|
||||||
|
sUrl += 'Json/';
|
||||||
|
}
|
||||||
|
|
||||||
|
window.clearTimeout(self.iTimer);
|
||||||
|
self.themeTrigger(Enums.SaveSettingsStep.Animate);
|
||||||
|
|
||||||
|
if (this.oLastAjax && this.oLastAjax.abort)
|
||||||
|
{
|
||||||
|
this.oLastAjax.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oLastAjax = $.ajax({
|
||||||
|
'url': sUrl,
|
||||||
|
'dataType': 'json'
|
||||||
|
}).done(function(aData) {
|
||||||
|
if (aData && Utils.isArray(aData) && 2 === aData.length)
|
||||||
|
{
|
||||||
|
if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0]))
|
||||||
|
{
|
||||||
|
oThemeStyle = $('<style id="rlThemeStyle"></style>');
|
||||||
|
oThemeLink.after(oThemeStyle);
|
||||||
|
oThemeLink.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oThemeStyle && oThemeStyle[0])
|
||||||
|
{
|
||||||
|
oThemeStyle.attr('data-href', sUrl).attr('data-theme', aData[0]).text(aData[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.themeTrigger(Enums.SaveSettingsStep.TrueResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
}).always(function() {
|
||||||
|
|
||||||
|
self.iTimer = window.setTimeout(function () {
|
||||||
|
self.themeTrigger(Enums.SaveSettingsStep.Idle);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
self.oLastAjax = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.remote().saveSettings(null, {
|
||||||
|
'Theme': sValue
|
||||||
|
});
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.addSettingsViewModel(SettingsThemes, 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes');
|
||||||
|
|
||||||
|
SettingsThemes.prototype.removeCustomThemeImg = function ()
|
||||||
|
{
|
||||||
|
this.customThemeImg('');
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsThemes.prototype.onBuild = function ()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
sCurrentTheme = RL.data().theme()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.themesObjects(_.map(RL.data().themes(), function (sTheme) {
|
||||||
|
return {
|
||||||
|
'name': sTheme,
|
||||||
|
'nameDisplay': Utils.convertThemeName(sTheme),
|
||||||
|
'selected': ko.observable(sTheme === sCurrentTheme),
|
||||||
|
'themePreviewSrc': RL.link().themePreviewLink(sTheme)
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
_.delay(function () {
|
||||||
|
|
||||||
|
self.customThemeType.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(function () {
|
||||||
|
RL.data().theme.valueHasMutated();
|
||||||
|
}, {
|
||||||
|
'CustomThemeType': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.customThemeImg.subscribe(function (sValue) {
|
||||||
|
RL.remote().saveSettings(function () {
|
||||||
|
RL.data().theme.valueHasMutated();
|
||||||
|
}, {
|
||||||
|
'CustomThemeImg': sValue
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
this.initCustomThemeUploader();
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsThemes.prototype.initCustomThemeUploader = function ()
|
||||||
|
{
|
||||||
|
if (this.customThemeUploaderButton())
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oJua = new Jua({
|
||||||
|
'action': RL.link().uploadBackground(),
|
||||||
|
'name': 'uploader',
|
||||||
|
'queueSize': 1,
|
||||||
|
'multipleSizeLimit': 1,
|
||||||
|
'disableFolderDragAndDrop': true,
|
||||||
|
'clickElement': this.customThemeUploaderButton(),
|
||||||
|
'onSelect': _.bind(function (sId, oData) {
|
||||||
|
|
||||||
|
var
|
||||||
|
sFileName = Utils.isUnd(oData.FileName) ? '' : oData.FileName.toString(),
|
||||||
|
sFileNameExt = sFileName.substring(sFileName.length - 4, sFileName.length),
|
||||||
|
mSize = Utils.isNormal(oData.Size) ? Utils.pInt(oData.Size) : null
|
||||||
|
;
|
||||||
|
|
||||||
|
if (-1 === Utils.inArray(sFileNameExt, ['jpeg', '.jpg', '.png']))
|
||||||
|
{
|
||||||
|
window.alert(Utils.i18n('SETTINGS_THEMES/ERROR_FILE_TYPE_ERROR'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1024 * 1024 < mSize)
|
||||||
|
{
|
||||||
|
window.alert(Utils.i18n('SETTINGS_THEMES/ERROR_FILE_IS_TOO_BIG'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}, this),
|
||||||
|
|
||||||
|
'onStart': _.bind(function () {
|
||||||
|
this.customThemeUploaderProgress(true);
|
||||||
|
}, this),
|
||||||
|
|
||||||
|
'onComplete': _.bind(function (sId, bResult, oData) {
|
||||||
|
if (!bResult || !oData || !oData.Result)
|
||||||
|
{
|
||||||
|
window.alert(
|
||||||
|
oData && oData.ErrorCode ? Utils.getUploadErrorDescByCode(oData.ErrorCode) : Utils.getUploadErrorDescByCode(Enums.UploadErrorCode.Unknown)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.customThemeImg(oData.Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.customThemeUploaderProgress(false);
|
||||||
|
}, this)
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
return !!oJua;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
249
dev/Storages/AbstractAjaxRemote.js
Normal file
249
dev/Storages/AbstractAjaxRemote.js
Normal file
|
|
@ -0,0 +1,249 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AbstractAjaxRemoteStorage()
|
||||||
|
{
|
||||||
|
this.oRequests = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractAjaxRemoteStorage.prototype.oRequests = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sRequestAction
|
||||||
|
* @param {string} sType
|
||||||
|
* @param {?AjaxJsonDefaultResponse} oData
|
||||||
|
* @param {boolean} bCached
|
||||||
|
* @param {*=} oRequestParameters
|
||||||
|
*/
|
||||||
|
AbstractAjaxRemoteStorage.prototype.defaultResponse = function (fCallback, sRequestAction, sType, oData, bCached, oRequestParameters)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
fCall = function () {
|
||||||
|
if (Enums.StorageResultType.Success !== sType && Globals.bUnload)
|
||||||
|
{
|
||||||
|
sType = Enums.StorageResultType.Unload;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Success === sType && oData && !oData.Result)
|
||||||
|
{
|
||||||
|
if (oData && -1 < Utils.inArray(oData.ErrorCode, [
|
||||||
|
Enums.Notification.AuthError, Enums.Notification.AccessError,
|
||||||
|
Enums.Notification.ConnectionError, Enums.Notification.DomainNotAllowed, Enums.Notification.AccountNotAllowed,
|
||||||
|
Enums.Notification.MailServerError, Enums.Notification.UnknownNotification, Enums.Notification.UnknownError
|
||||||
|
]))
|
||||||
|
{
|
||||||
|
Globals.iAjaxErrorCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oData && Enums.Notification.InvalidToken === oData.ErrorCode)
|
||||||
|
{
|
||||||
|
Globals.iTokenErrorCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (10 < Globals.iTokenErrorCount)
|
||||||
|
{
|
||||||
|
RL.loginAndLogoutReload(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oData.Logout || 7 < Globals.iAjaxErrorCount)
|
||||||
|
{
|
||||||
|
if (window.__rlah_clear)
|
||||||
|
{
|
||||||
|
window.__rlah_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.loginAndLogoutReload(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Enums.StorageResultType.Success === sType && oData && oData.Result)
|
||||||
|
{
|
||||||
|
Globals.iAjaxErrorCount = 0;
|
||||||
|
Globals.iTokenErrorCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fCallback)
|
||||||
|
{
|
||||||
|
Plugins.runHook('ajax-default-response', [sRequestAction, Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oRequestParameters]);
|
||||||
|
|
||||||
|
fCallback(
|
||||||
|
sType,
|
||||||
|
Enums.StorageResultType.Success === sType ? oData : null,
|
||||||
|
bCached,
|
||||||
|
sRequestAction,
|
||||||
|
oRequestParameters
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
switch (sType)
|
||||||
|
{
|
||||||
|
case 'success':
|
||||||
|
sType = Enums.StorageResultType.Success;
|
||||||
|
break;
|
||||||
|
case 'abort':
|
||||||
|
sType = Enums.StorageResultType.Abort;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sType = Enums.StorageResultType.Error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Enums.StorageResultType.Error === sType)
|
||||||
|
{
|
||||||
|
_.delay(fCall, 300);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fCall();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fResultCallback
|
||||||
|
* @param {Object} oParameters
|
||||||
|
* @param {?number=} iTimeOut = 20000
|
||||||
|
* @param {string=} sGetAdd = ''
|
||||||
|
* @param {Array=} aAbortActions = []
|
||||||
|
* @return {jQuery.jqXHR}
|
||||||
|
*/
|
||||||
|
AbstractAjaxRemoteStorage.prototype.ajaxRequest = function (fResultCallback, oParameters, iTimeOut, sGetAdd, aAbortActions)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
bPost = '' === sGetAdd,
|
||||||
|
oHeaders = {},
|
||||||
|
iStart = (new window.Date()).getTime(),
|
||||||
|
oDefAjax = null,
|
||||||
|
sAction = ''
|
||||||
|
;
|
||||||
|
|
||||||
|
oParameters = oParameters || {};
|
||||||
|
iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : 20000;
|
||||||
|
sGetAdd = Utils.isUnd(sGetAdd) ? '' : Utils.pString(sGetAdd);
|
||||||
|
aAbortActions = Utils.isArray(aAbortActions) ? aAbortActions : [];
|
||||||
|
|
||||||
|
sAction = oParameters.Action || '';
|
||||||
|
|
||||||
|
if (sAction && 0 < aAbortActions.length)
|
||||||
|
{
|
||||||
|
_.each(aAbortActions, function (sActionToAbort) {
|
||||||
|
if (self.oRequests[sActionToAbort])
|
||||||
|
{
|
||||||
|
self.oRequests[sActionToAbort].__aborted = true;
|
||||||
|
if (self.oRequests[sActionToAbort].abort)
|
||||||
|
{
|
||||||
|
self.oRequests[sActionToAbort].abort();
|
||||||
|
}
|
||||||
|
self.oRequests[sActionToAbort] = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bPost)
|
||||||
|
{
|
||||||
|
oParameters['XToken'] = RL.settingsGet('Token');
|
||||||
|
}
|
||||||
|
|
||||||
|
oDefAjax = $.ajax({
|
||||||
|
'type': bPost ? 'POST' : 'GET',
|
||||||
|
'url': RL.link().ajax(sGetAdd) ,
|
||||||
|
'async': true,
|
||||||
|
'dataType': 'json',
|
||||||
|
'data': bPost ? oParameters : {},
|
||||||
|
'headers': oHeaders,
|
||||||
|
'timeout': iTimeOut,
|
||||||
|
'global': true
|
||||||
|
});
|
||||||
|
|
||||||
|
oDefAjax.always(function (oData, sType) {
|
||||||
|
|
||||||
|
var bCached = false;
|
||||||
|
if (oData && oData['Time'])
|
||||||
|
{
|
||||||
|
bCached = Utils.pInt(oData['Time']) > (new window.Date()).getTime() - iStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sAction && self.oRequests[sAction])
|
||||||
|
{
|
||||||
|
if (self.oRequests[sAction].__aborted)
|
||||||
|
{
|
||||||
|
sType = 'abort';
|
||||||
|
}
|
||||||
|
|
||||||
|
self.oRequests[sAction] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.defaultResponse(fResultCallback, sAction, sType, oData, bCached, oParameters);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sAction && 0 < aAbortActions.length && -1 < Utils.inArray(sAction, aAbortActions))
|
||||||
|
{
|
||||||
|
if (this.oRequests[sAction])
|
||||||
|
{
|
||||||
|
this.oRequests[sAction].__aborted = true;
|
||||||
|
if (this.oRequests[sAction].abort)
|
||||||
|
{
|
||||||
|
this.oRequests[sAction].abort();
|
||||||
|
}
|
||||||
|
this.oRequests[sAction] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oRequests[sAction] = oDefAjax;
|
||||||
|
}
|
||||||
|
|
||||||
|
return oDefAjax;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sAction
|
||||||
|
* @param {Object=} oParameters
|
||||||
|
* @param {?number=} iTimeout
|
||||||
|
* @param {string=} sGetAdd = ''
|
||||||
|
* @param {Array=} aAbortActions = []
|
||||||
|
*/
|
||||||
|
AbstractAjaxRemoteStorage.prototype.defaultRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions)
|
||||||
|
{
|
||||||
|
oParameters = oParameters || {};
|
||||||
|
oParameters.Action = sAction;
|
||||||
|
|
||||||
|
sGetAdd = Utils.pString(sGetAdd);
|
||||||
|
|
||||||
|
Plugins.runHook('ajax-default-request', [sAction, oParameters, sGetAdd]);
|
||||||
|
|
||||||
|
this.ajaxRequest(fCallback, oParameters,
|
||||||
|
Utils.isUnd(iTimeout) ? Consts.Defaults.DefaultAjaxTimeout : Utils.pInt(iTimeout), sGetAdd, aAbortActions);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
AbstractAjaxRemoteStorage.prototype.noop = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Noop');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sMessage
|
||||||
|
* @param {string} sFileName
|
||||||
|
* @param {number} iLineNo
|
||||||
|
* @param {string} sLocation
|
||||||
|
* @param {string} sHtmlCapa
|
||||||
|
* @param {number} iTime
|
||||||
|
*/
|
||||||
|
AbstractAjaxRemoteStorage.prototype.jsError = function (fCallback, sMessage, sFileName, iLineNo, sLocation, sHtmlCapa, iTime)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'JsError', {
|
||||||
|
'Message': sMessage,
|
||||||
|
'FileName': sFileName,
|
||||||
|
'LineNo': iLineNo,
|
||||||
|
'Location': sLocation,
|
||||||
|
'HtmlCapa': sHtmlCapa,
|
||||||
|
'TimeOnPage': iTime
|
||||||
|
});
|
||||||
|
};
|
||||||
67
dev/Storages/AbstractCache.js
Normal file
67
dev/Storages/AbstractCache.js
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AbstractCacheStorage()
|
||||||
|
{
|
||||||
|
this.oEmailsPicsHashes = {};
|
||||||
|
this.oServices = {};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
AbstractCacheStorage.prototype.oEmailsPicsHashes = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
AbstractCacheStorage.prototype.oServices = {};
|
||||||
|
|
||||||
|
AbstractCacheStorage.prototype.clear = function ()
|
||||||
|
{
|
||||||
|
this.oServices = {};
|
||||||
|
this.oEmailsPicsHashes = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sEmail
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
AbstractCacheStorage.prototype.getUserPic = function (sEmail)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sUrl = '',
|
||||||
|
sService = '',
|
||||||
|
sEmailLower = sEmail.toLowerCase(),
|
||||||
|
sPicHash = Utils.isUnd(this.oEmailsPicsHashes[sEmail]) ? '' : this.oEmailsPicsHashes[sEmail]
|
||||||
|
;
|
||||||
|
|
||||||
|
if ('' === sPicHash)
|
||||||
|
{
|
||||||
|
sService = sEmailLower.substr(sEmail.indexOf('@') + 1);
|
||||||
|
sUrl = '' !== sService && this.oServices[sService] ? this.oServices[sService] : '';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sUrl = RL.link().getUserPicUrlFromHash(sPicHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sUrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oData
|
||||||
|
*/
|
||||||
|
AbstractCacheStorage.prototype.setServicesData = function (oData)
|
||||||
|
{
|
||||||
|
this.oServices = oData;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} oData
|
||||||
|
*/
|
||||||
|
AbstractCacheStorage.prototype.setEmailsPicsHashesData = function (oData)
|
||||||
|
{
|
||||||
|
this.oEmailsPicsHashes = oData;
|
||||||
|
};
|
||||||
70
dev/Storages/AbstractData.js
Normal file
70
dev/Storages/AbstractData.js
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function AbstractData()
|
||||||
|
{
|
||||||
|
Utils.initDataConstructorBySettings(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractData.prototype.populateDataOnStart = function()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aLanguages = RL.settingsGet('Languages'),
|
||||||
|
aThemes = RL.settingsGet('Themes')
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Utils.isArray(aLanguages))
|
||||||
|
{
|
||||||
|
this.languages(aLanguages);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isArray(aThemes))
|
||||||
|
{
|
||||||
|
this.themes(aThemes);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mainLanguage(RL.settingsGet('Language'));
|
||||||
|
this.mainTheme(RL.settingsGet('Theme'));
|
||||||
|
|
||||||
|
this.allowCustomTheme(!!RL.settingsGet('AllowCustomTheme'));
|
||||||
|
this.allowAdditionalAccounts(!!RL.settingsGet('AllowAdditionalAccounts'));
|
||||||
|
this.allowIdentities(!!RL.settingsGet('AllowIdentities'));
|
||||||
|
this.determineUserLanguage(!!RL.settingsGet('DetermineUserLanguage'));
|
||||||
|
|
||||||
|
this.allowThemes(!!RL.settingsGet('AllowThemes'));
|
||||||
|
this.allowCustomLogin(!!RL.settingsGet('AllowCustomLogin'));
|
||||||
|
this.allowLanguagesOnLogin(!!RL.settingsGet('AllowLanguagesOnLogin'));
|
||||||
|
this.allowLanguagesOnSettings(!!RL.settingsGet('AllowLanguagesOnSettings'));
|
||||||
|
|
||||||
|
this.editorDefaultType(RL.settingsGet('EditorDefaultType'));
|
||||||
|
this.showImages(!!RL.settingsGet('ShowImages'));
|
||||||
|
this.interfaceAnimation(RL.settingsGet('InterfaceAnimation'));
|
||||||
|
|
||||||
|
this.mainMessagesPerPage(RL.settingsGet('MPP'));
|
||||||
|
|
||||||
|
this.desktopNotifications(!!RL.settingsGet('DesktopNotifications'));
|
||||||
|
this.useThreads(!!RL.settingsGet('UseThreads'));
|
||||||
|
this.replySameFolder(!!RL.settingsGet('ReplySameFolder'));
|
||||||
|
this.usePreviewPane(!!RL.settingsGet('UsePreviewPane'));
|
||||||
|
this.useCheckboxesInList(!!RL.settingsGet('UseCheckboxesInList'));
|
||||||
|
|
||||||
|
this.facebookEnable(!!RL.settingsGet('AllowFacebookSocial'));
|
||||||
|
this.facebookAppID(RL.settingsGet('FacebookAppID'));
|
||||||
|
this.facebookAppSecret(RL.settingsGet('FacebookAppSecret'));
|
||||||
|
|
||||||
|
this.twitterEnable(!!RL.settingsGet('AllowTwitterSocial'));
|
||||||
|
this.twitterConsumerKey(RL.settingsGet('TwitterConsumerKey'));
|
||||||
|
this.twitterConsumerSecret(RL.settingsGet('TwitterConsumerSecret'));
|
||||||
|
|
||||||
|
this.googleEnable(!!RL.settingsGet('AllowGoogleSocial'));
|
||||||
|
this.googleClientID(RL.settingsGet('GoogleClientID'));
|
||||||
|
this.googleClientSecret(RL.settingsGet('GoogleClientSecret'));
|
||||||
|
|
||||||
|
this.dropboxEnable(!!RL.settingsGet('AllowDropboxSocial'));
|
||||||
|
this.dropboxApiKey(RL.settingsGet('DropboxApiKey'));
|
||||||
|
|
||||||
|
this.contactsIsSupported(!!RL.settingsGet('ContactsIsSupported'));
|
||||||
|
this.contactsIsAllowed(!!RL.settingsGet('ContactsIsAllowed'));
|
||||||
|
};
|
||||||
236
dev/Storages/AdminAjaxRemote.js
Normal file
236
dev/Storages/AdminAjaxRemote.js
Normal file
|
|
@ -0,0 +1,236 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractAjaxRemoteStorage
|
||||||
|
*/
|
||||||
|
function AdminAjaxRemoteStorage()
|
||||||
|
{
|
||||||
|
AbstractAjaxRemoteStorage.call(this);
|
||||||
|
|
||||||
|
this.oRequests = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AdminAjaxRemoteStorage.prototype, AbstractAjaxRemoteStorage.prototype);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sLogin
|
||||||
|
* @param {string} sPassword
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.adminLogin = function (fCallback, sLogin, sPassword)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminLogin', {
|
||||||
|
'Login': sLogin,
|
||||||
|
'Password': sPassword
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.adminLogout = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminLogout');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {?} oData
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.saveAdminConfig = function (fCallback, oData)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminSettingsUpdate', oData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.domainList = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminDomainList');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.pluginList = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminPluginList');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.packagesList = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminPackagesList');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Object} oPackage
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.packageInstall = function (fCallback, oPackage)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminPackageInstall', {
|
||||||
|
'Id': oPackage.id,
|
||||||
|
'Type': oPackage.type,
|
||||||
|
'File': oPackage.file
|
||||||
|
}, 60000);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Object} oPackage
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.packageDelete = function (fCallback, oPackage)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminPackageDelete', {
|
||||||
|
'Id': oPackage.id
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sName
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.domain = function (fCallback, sName)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminDomainLoad', {
|
||||||
|
'Name': sName
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sName
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.plugin = function (fCallback, sName)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminPluginLoad', {
|
||||||
|
'Name': sName
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sName
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.domainDelete = function (fCallback, sName)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminDomainDelete', {
|
||||||
|
'Name': sName
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {boolean} bDisabled
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.domainDisable = function (fCallback, sName, bDisabled)
|
||||||
|
{
|
||||||
|
return this.defaultRequest(fCallback, 'AdminDomainDisable', {
|
||||||
|
'Name': sName,
|
||||||
|
'Disabled': !!bDisabled ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Object} oConfig
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.pluginSettingsUpdate = function (fCallback, oConfig)
|
||||||
|
{
|
||||||
|
return this.defaultRequest(fCallback, 'AdminPluginSettingsUpdate', oConfig);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {boolean} bForce
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.licensing = function (fCallback, bForce)
|
||||||
|
{
|
||||||
|
return this.defaultRequest(fCallback, 'AdminLicensing', {
|
||||||
|
'Force' : bForce ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sDomain
|
||||||
|
* @param {string} sKey
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.licensingActivate = function (fCallback, sDomain, sKey)
|
||||||
|
{
|
||||||
|
return this.defaultRequest(fCallback, 'AdminLicensingActivate', {
|
||||||
|
'Domain' : sDomain,
|
||||||
|
'Key' : sKey
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {boolean} bDisabled
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.pluginDisable = function (fCallback, sName, bDisabled)
|
||||||
|
{
|
||||||
|
return this.defaultRequest(fCallback, 'AdminPluginDisable', {
|
||||||
|
'Name': sName,
|
||||||
|
'Disabled': !!bDisabled ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminAjaxRemoteStorage.prototype.createOrUpdateDomain = function (fCallback,
|
||||||
|
bCreate, sName, sIncHost, iIncPort, sIncSecure, bIncShortLogin,
|
||||||
|
sOutHost, iOutPort, sOutSecure, bOutShortLogin, bOutAuth, sWhiteList)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminDomainSave', {
|
||||||
|
'Create': bCreate ? '1' : '0',
|
||||||
|
'Name': sName,
|
||||||
|
'IncHost': sIncHost,
|
||||||
|
'IncPort': iIncPort,
|
||||||
|
'IncSecure': sIncSecure,
|
||||||
|
'IncShortLogin': bIncShortLogin ? '1' : '0',
|
||||||
|
'OutHost': sOutHost,
|
||||||
|
'OutPort': iOutPort,
|
||||||
|
'OutSecure': sOutSecure,
|
||||||
|
'OutShortLogin': bOutShortLogin ? '1' : '0',
|
||||||
|
'OutAuth': bOutAuth ? '1' : '0',
|
||||||
|
'WhiteList': sWhiteList
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
AdminAjaxRemoteStorage.prototype.testConnectionForDomain = function (fCallback,
|
||||||
|
sIncHost, iIncPort, sIncSecure,
|
||||||
|
sOutHost, iOutPort, sOutSecure, bOutAuth)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminDomainTest', {
|
||||||
|
'IncHost': sIncHost,
|
||||||
|
'IncPort': iIncPort,
|
||||||
|
'IncSecure': sIncSecure,
|
||||||
|
'OutHost': sOutHost,
|
||||||
|
'OutPort': iOutPort,
|
||||||
|
'OutSecure': sOutSecure,
|
||||||
|
'OutAuth': bOutAuth ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {?} oData
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.saveNewAdminPassword = function (fCallback, oData)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminPasswordUpdate', oData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
AdminAjaxRemoteStorage.prototype.adminPing = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AdminPing');
|
||||||
|
};
|
||||||
12
dev/Storages/AdminCache.js
Normal file
12
dev/Storages/AdminCache.js
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractCacheStorage
|
||||||
|
*/
|
||||||
|
function AdminCacheStorage()
|
||||||
|
{
|
||||||
|
AbstractCacheStorage.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AdminCacheStorage.prototype, AbstractCacheStorage.prototype);
|
||||||
36
dev/Storages/AdminData.js
Normal file
36
dev/Storages/AdminData.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractData
|
||||||
|
*/
|
||||||
|
function AdminDataStorage()
|
||||||
|
{
|
||||||
|
AbstractData.call(this);
|
||||||
|
|
||||||
|
this.domainsLoading = ko.observable(false).extend({'throttle': 100});
|
||||||
|
this.domains = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.pluginsLoading = ko.observable(false).extend({'throttle': 100});
|
||||||
|
this.plugins = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.packagesReal = ko.observable(true);
|
||||||
|
this.packagesMainUpdatable = ko.observable(true);
|
||||||
|
this.packagesLoading = ko.observable(false).extend({'throttle': 100});
|
||||||
|
this.packages = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.licensing = ko.observable(false);
|
||||||
|
this.licensingProcess = ko.observable(false);
|
||||||
|
this.licenseValid = ko.observable(false);
|
||||||
|
this.licenseExpired = ko.observable(0);
|
||||||
|
this.licenseError = ko.observable('');
|
||||||
|
|
||||||
|
this.licenseTrigger = ko.observable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(AdminDataStorage.prototype, AbstractData.prototype);
|
||||||
|
|
||||||
|
AdminDataStorage.prototype.populateDataOnStart = function()
|
||||||
|
{
|
||||||
|
AbstractData.prototype.populateDataOnStart.call(this);
|
||||||
|
};
|
||||||
44
dev/Storages/LocalStorage.js
Normal file
44
dev/Storages/LocalStorage.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LocalStorage()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
sStorages = [
|
||||||
|
LocalStorageDriver,
|
||||||
|
CookieDriver
|
||||||
|
],
|
||||||
|
NextStorageDriver = _.find(sStorages, function (NextStorageDriver) {
|
||||||
|
return NextStorageDriver.supported();
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
if (NextStorageDriver)
|
||||||
|
{
|
||||||
|
NextStorageDriver = /** @type {?Function} */ NextStorageDriver;
|
||||||
|
this.oDriver = new NextStorageDriver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalStorage.prototype.oDriver = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} iKey
|
||||||
|
* @param {*} mData
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
LocalStorage.prototype.set = function (iKey, mData)
|
||||||
|
{
|
||||||
|
return this.oDriver ? this.oDriver.set('p' + iKey, mData) : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} iKey
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
LocalStorage.prototype.get = function (iKey)
|
||||||
|
{
|
||||||
|
return this.oDriver ? this.oDriver.get('p' + iKey) : null;
|
||||||
|
};
|
||||||
75
dev/Storages/LocalStorages/CookieDriver.js
Normal file
75
dev/Storages/LocalStorages/CookieDriver.js
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function CookieDriver()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CookieDriver.supported = function ()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sKey
|
||||||
|
* @param {*} mData
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
CookieDriver.prototype.set = function (sKey, mData)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
mCokieValue = $.cookie(Consts.Values.ClientSideCookieIndexName),
|
||||||
|
bResult = false,
|
||||||
|
mResult = null
|
||||||
|
;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
|
||||||
|
if (!mResult)
|
||||||
|
{
|
||||||
|
mResult = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
mResult[sKey] = mData;
|
||||||
|
$.cookie(Consts.Values.ClientSideCookieIndexName, JSON.stringify(mResult), {
|
||||||
|
'expires': 30
|
||||||
|
});
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
catch (oException) {}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sKey
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
CookieDriver.prototype.get = function (sKey)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
mCokieValue = $.cookie(Consts.Values.ClientSideCookieIndexName),
|
||||||
|
mResult = null
|
||||||
|
;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
|
||||||
|
if (mResult && !Utils.isUnd(mResult[sKey]))
|
||||||
|
{
|
||||||
|
mResult = mResult[sKey];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (oException) {}
|
||||||
|
|
||||||
|
return mResult;
|
||||||
|
};
|
||||||
73
dev/Storages/LocalStorages/LocalStorageDriver.js
Normal file
73
dev/Storages/LocalStorages/LocalStorageDriver.js
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LocalStorageDriver()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalStorageDriver.supported = function ()
|
||||||
|
{
|
||||||
|
return !!window.localStorage;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sKey
|
||||||
|
* @param {*} mData
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
LocalStorageDriver.prototype.set = function (sKey, mData)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
mCokieValue = window.localStorage[Consts.Values.ClientSideCookieIndexName] || null,
|
||||||
|
bResult = false,
|
||||||
|
mResult = null
|
||||||
|
;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
|
||||||
|
if (!mResult)
|
||||||
|
{
|
||||||
|
mResult = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
mResult[sKey] = mData;
|
||||||
|
window.localStorage[Consts.Values.ClientSideCookieIndexName] = JSON.stringify(mResult);
|
||||||
|
|
||||||
|
bResult = true;
|
||||||
|
}
|
||||||
|
catch (oException) {}
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sKey
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
LocalStorageDriver.prototype.get = function (sKey)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
mCokieValue = window.localStorage[Consts.Values.ClientSideCookieIndexName] || null,
|
||||||
|
mResult = null
|
||||||
|
;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mResult = null === mCokieValue ? null : JSON.parse(mCokieValue);
|
||||||
|
if (mResult && !Utils.isUnd(mResult[sKey]))
|
||||||
|
{
|
||||||
|
mResult = mResult[sKey];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (oException) {}
|
||||||
|
|
||||||
|
return mResult;
|
||||||
|
};
|
||||||
660
dev/Storages/WebMailAjaxRemote.js
Normal file
660
dev/Storages/WebMailAjaxRemote.js
Normal file
|
|
@ -0,0 +1,660 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractAjaxRemoteStorage
|
||||||
|
*/
|
||||||
|
function WebMailAjaxRemoteStorage()
|
||||||
|
{
|
||||||
|
AbstractAjaxRemoteStorage.call(this);
|
||||||
|
|
||||||
|
this.oRequests = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(WebMailAjaxRemoteStorage.prototype, AbstractAjaxRemoteStorage.prototype);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {boolean=} bUseCache = true
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.folders = function (fCallback, bUseCache)
|
||||||
|
{
|
||||||
|
var sFoldersHash = RL.data().lastFoldersHash;
|
||||||
|
|
||||||
|
bUseCache = Utils.isUnd(bUseCache) ? false : !!bUseCache;
|
||||||
|
if (bUseCache && '' !== sFoldersHash)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Folders', {}, null, 'Folders/' + RL.data().projectHash() + '-' + sFoldersHash, ['Folders']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Folders', {}, null, '', ['Folders']);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sEmail
|
||||||
|
* @param {string} sLogin
|
||||||
|
* @param {string} sPassword
|
||||||
|
* @param {boolean} bSignMe
|
||||||
|
* @param {string=} sLanguage
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Login', {
|
||||||
|
'Email': sEmail,
|
||||||
|
'Login': sLogin,
|
||||||
|
'Password': sPassword,
|
||||||
|
'Language': sLanguage || '',
|
||||||
|
'SignMe': bSignMe ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sEmail
|
||||||
|
* @param {string} sLogin
|
||||||
|
* @param {string} sPassword
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.accountAdd = function (fCallback, sEmail, sLogin, sPassword)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AccountAdd', {
|
||||||
|
'Email': sEmail,
|
||||||
|
'Login': sLogin,
|
||||||
|
'Password': sPassword
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sEmailToDelete
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.accountDelete = function (fCallback, sEmailToDelete)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AccountDelete', {
|
||||||
|
'EmailToDelete': sEmailToDelete
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sId
|
||||||
|
* @param {string} sEmail
|
||||||
|
* @param {string} sName
|
||||||
|
* @param {string} sReplyTo
|
||||||
|
* @param {string} sBcc
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'IdentityUpdate', {
|
||||||
|
'Id': sId,
|
||||||
|
'Email': sEmail,
|
||||||
|
'Name': sName,
|
||||||
|
'ReplyTo': sReplyTo,
|
||||||
|
'Bcc': sBcc
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sIdToDelete
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.identityDelete = function (fCallback, sIdToDelete)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'IdentityDelete', {
|
||||||
|
'IdToDelete': sIdToDelete
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.accountsAndIdentities = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AccountsAndIdentities');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {number=} iOffset = 0
|
||||||
|
* @param {number=} iLimit = 20
|
||||||
|
* @param {string=} sSearch = ''
|
||||||
|
* @param {boolean=} bSilent = false
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, bSilent)
|
||||||
|
{
|
||||||
|
sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
|
||||||
|
|
||||||
|
var
|
||||||
|
oData = RL.data(),
|
||||||
|
sFolderHash = RL.cache().getFolderHash(sFolderFullNameRaw)
|
||||||
|
;
|
||||||
|
|
||||||
|
bSilent = Utils.isUnd(bSilent) ? false : !!bSilent;
|
||||||
|
iOffset = Utils.isUnd(iOffset) ? 0 : Utils.pInt(iOffset);
|
||||||
|
iLimit = Utils.isUnd(iOffset) ? 20 : Utils.pInt(iLimit);
|
||||||
|
sSearch = Utils.pString(sSearch);
|
||||||
|
|
||||||
|
if ('' !== sFolderHash)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageList', {},
|
||||||
|
'' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout,
|
||||||
|
'MessageList/' + Base64.urlsafe_encode([
|
||||||
|
sFolderFullNameRaw,
|
||||||
|
iOffset,
|
||||||
|
iLimit,
|
||||||
|
sSearch,
|
||||||
|
oData.projectHash(),
|
||||||
|
sFolderHash,
|
||||||
|
'INBOX' === sFolderFullNameRaw ? RL.cache().getFolderUidNext(sFolderFullNameRaw) : '',
|
||||||
|
oData.threading() && oData.useThreads() ? '1' : '0',
|
||||||
|
oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : ''
|
||||||
|
].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageList', {
|
||||||
|
'Folder': sFolderFullNameRaw,
|
||||||
|
'Offset': iOffset,
|
||||||
|
'Limit': iLimit,
|
||||||
|
'Search': sSearch,
|
||||||
|
'UidNext': 'INBOX' === sFolderFullNameRaw ? RL.cache().getFolderUidNext(sFolderFullNameRaw) : '',
|
||||||
|
'UseThreads': RL.data().threading() && RL.data().useThreads() ? '1' : '0',
|
||||||
|
'ExpandedThreadUid': oData.threading() && sFolderFullNameRaw === oData.messageListThreadFolder() ? oData.messageListThreadUids().join(',') : ''
|
||||||
|
}, '' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout, '', bSilent ? [] : ['MessageList']);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Array} aDownloads
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.messageUploadAttachments = function (fCallback, aDownloads)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageUploadAttachments', {
|
||||||
|
'Attachments': aDownloads
|
||||||
|
}, 999000);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {number} iUid
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.message = function (fCallback, sFolderFullNameRaw, iUid)
|
||||||
|
{
|
||||||
|
sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
|
||||||
|
iUid = Utils.pInt(iUid);
|
||||||
|
|
||||||
|
if (RL.cache().getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Message', {}, null,
|
||||||
|
'Message/' + Base64.urlsafe_encode([
|
||||||
|
sFolderFullNameRaw,
|
||||||
|
iUid,
|
||||||
|
RL.data().projectHash(),
|
||||||
|
RL.data().threading() && RL.data().useThreads() ? '1' : '0'
|
||||||
|
].join(String.fromCharCode(0))), ['Message']);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Array} aExternals
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.composeUploadExternals = function (fCallback, aExternals)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'ComposeUploadExternals', {
|
||||||
|
'Externals': aExternals
|
||||||
|
}, 999000);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {Array=} aList = []
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.folderInformation = function (fCallback, sFolder, aList)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
bRequest = true,
|
||||||
|
oCache = RL.cache(),
|
||||||
|
aUids = []
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Utils.isArray(aList) && 0 < aList.length)
|
||||||
|
{
|
||||||
|
bRequest = false;
|
||||||
|
_.each(aList, function (oMessageListItem) {
|
||||||
|
if (!oCache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, oMessageListItem.uid))
|
||||||
|
{
|
||||||
|
aUids.push(oMessageListItem.uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 < oMessageListItem.threads().length)
|
||||||
|
{
|
||||||
|
_.each(oMessageListItem.threads(), function (sUid) {
|
||||||
|
if (!oCache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, sUid))
|
||||||
|
{
|
||||||
|
aUids.push(sUid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (0 < aUids.length)
|
||||||
|
{
|
||||||
|
bRequest = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bRequest)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'FolderInformation', {
|
||||||
|
'Folder': sFolder,
|
||||||
|
'FlagsUids': Utils.isArray(aUids) ? aUids.join(',') : '',
|
||||||
|
'UidNext': 'INBOX' === sFolder ? RL.cache().getFolderUidNext(sFolder) : ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (RL.data().useThreads())
|
||||||
|
{
|
||||||
|
RL.reloadFlagsCurrentMessageListAndMessageFromCache();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.logout = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Logout');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {Array} aUids
|
||||||
|
* @param {boolean} bSetFlagged
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageSetFlagged', {
|
||||||
|
'Folder': sFolderFullNameRaw,
|
||||||
|
'Uids': aUids.join(','),
|
||||||
|
'SetAction': bSetFlagged ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {Array} aUids
|
||||||
|
* @param {boolean} bSetSeen
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageSetSeen', {
|
||||||
|
'Folder': sFolderFullNameRaw,
|
||||||
|
'Uids': aUids.join(','),
|
||||||
|
'SetAction': bSetSeen ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {boolean} bSetSeen
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageSetSeenToAll', {
|
||||||
|
'Folder': sFolderFullNameRaw,
|
||||||
|
'SetAction': bSetSeen ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sMessageFolder
|
||||||
|
* @param {string} sMessageUid
|
||||||
|
* @param {string} sMessageID
|
||||||
|
* @param {string} sDraftFolder
|
||||||
|
* @param {string} sFrom
|
||||||
|
* @param {string} sTo
|
||||||
|
* @param {string} sCc
|
||||||
|
* @param {string} sBcc
|
||||||
|
* @param {string} sSubject
|
||||||
|
* @param {boolean} bTextIsHtml
|
||||||
|
* @param {string} sText
|
||||||
|
* @param {Array} aAttachments
|
||||||
|
* @param {(Array|null)} aDraftInfo
|
||||||
|
* @param {string} sInReplyTo
|
||||||
|
* @param {string} sReferences
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.saveMessage = function (fCallback, sMessageFolder, sMessageUid, sMessageID, sDraftFolder,
|
||||||
|
sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SaveMessage', {
|
||||||
|
'MessageFolder': sMessageFolder,
|
||||||
|
'MessageUid': sMessageUid,
|
||||||
|
'MessageID': sMessageID,
|
||||||
|
'DraftFolder': sDraftFolder,
|
||||||
|
'From': sFrom,
|
||||||
|
'To': sTo,
|
||||||
|
'Cc': sCc,
|
||||||
|
'Bcc': sBcc,
|
||||||
|
'Subject': sSubject,
|
||||||
|
'TextIsHtml': bTextIsHtml ? '1' : '0',
|
||||||
|
'Text': sText,
|
||||||
|
'DraftInfo': aDraftInfo,
|
||||||
|
'InReplyTo': sInReplyTo,
|
||||||
|
'References': sReferences,
|
||||||
|
'Attachments': aAttachments
|
||||||
|
}, Consts.Defaults.SaveMessageAjaxTimeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sMessageFolder
|
||||||
|
* @param {string} sMessageUid
|
||||||
|
* @param {string} sMessageID
|
||||||
|
* @param {string} sSentFolder
|
||||||
|
* @param {string} sFrom
|
||||||
|
* @param {string} sTo
|
||||||
|
* @param {string} sCc
|
||||||
|
* @param {string} sBcc
|
||||||
|
* @param {string} sSubject
|
||||||
|
* @param {boolean} bTextIsHtml
|
||||||
|
* @param {string} sText
|
||||||
|
* @param {Array} aAttachments
|
||||||
|
* @param {(Array|null)} aDraftInfo
|
||||||
|
* @param {string} sInReplyTo
|
||||||
|
* @param {string} sReferences
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.sendMessage = function (fCallback, sMessageFolder, sMessageUid, sMessageID, sSentFolder,
|
||||||
|
sFrom, sTo, sCc, sBcc, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SendMessage', {
|
||||||
|
'MessageFolder': sMessageFolder,
|
||||||
|
'MessageUid': sMessageUid,
|
||||||
|
'MessageID': sMessageID,
|
||||||
|
'SentFolder': sSentFolder,
|
||||||
|
'From': sFrom,
|
||||||
|
'To': sTo,
|
||||||
|
'Cc': sCc,
|
||||||
|
'Bcc': sBcc,
|
||||||
|
'Subject': sSubject,
|
||||||
|
'TextIsHtml': bTextIsHtml ? '1' : '0',
|
||||||
|
'Text': sText,
|
||||||
|
'DraftInfo': aDraftInfo,
|
||||||
|
'InReplyTo': sInReplyTo,
|
||||||
|
'References': sReferences,
|
||||||
|
'Attachments': aAttachments
|
||||||
|
}, Consts.Defaults.SendMessageAjaxTimeout);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Object} oData
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.saveSystemFolders = function (fCallback, oData)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Object} oData
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.saveSettings = function (fCallback, oData)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SettingsUpdate', oData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sPrevPassword
|
||||||
|
* @param {string} sNewPassword
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'ChangePassword', {
|
||||||
|
'PrevPassword': sPrevPassword,
|
||||||
|
'NewPassword': sNewPassword
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sNewFolderName
|
||||||
|
* @param {string} sParentName
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.folderCreate = function (fCallback, sNewFolderName, sParentName)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'FolderCreate', {
|
||||||
|
'Folder': sNewFolderName,
|
||||||
|
'Parent': sParentName
|
||||||
|
}, null, '', ['Folders']);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.folderDelete = function (fCallback, sFolderFullNameRaw)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'FolderDelete', {
|
||||||
|
'Folder': sFolderFullNameRaw
|
||||||
|
}, null, '', ['Folders']);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sPrevFolderFullNameRaw
|
||||||
|
* @param {string} sNewFolderName
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.folderRename = function (fCallback, sPrevFolderFullNameRaw, sNewFolderName)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'FolderRename', {
|
||||||
|
'Folder': sPrevFolderFullNameRaw,
|
||||||
|
'NewFolderName': sNewFolderName
|
||||||
|
}, null, '', ['Folders']);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.folderClear = function (fCallback, sFolderFullNameRaw)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'FolderClear', {
|
||||||
|
'Folder': sFolderFullNameRaw
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {boolean} bSubscribe
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'FolderSubscribe', {
|
||||||
|
'Folder': sFolderFullNameRaw,
|
||||||
|
'Subscribe': bSubscribe ? '1' : '0'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {string} sToFolder
|
||||||
|
* @param {Array} aUids
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageMove', {
|
||||||
|
'FromFolder': sFolder,
|
||||||
|
'ToFolder': sToFolder,
|
||||||
|
'Uids': aUids.join(',')
|
||||||
|
}, null, '', ['MessageList', 'Message']);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {Array} aUids
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.messagesDelete = function (fCallback, sFolder, aUids)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'MessageDelete', {
|
||||||
|
'Folder': sFolder,
|
||||||
|
'Uids': aUids.join(',')
|
||||||
|
}, null, '', ['MessageList', 'Message']);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.appDelayStart = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'AppDelayStart');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.quota = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Quota');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sSearch
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.contacts = function (fCallback, sSearch)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Contacts', {
|
||||||
|
'Search': sSearch
|
||||||
|
}, null, '', ['Contacts']);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.contactSave = function (fCallback, sRequestUid, sUid, sName, sEmail, sImageData)
|
||||||
|
{
|
||||||
|
sUid = Utils.trim(sUid);
|
||||||
|
this.defaultRequest(fCallback, 'ContactSave', {
|
||||||
|
'RequestUid': sRequestUid,
|
||||||
|
'Uid': sUid,
|
||||||
|
'Name': sName,
|
||||||
|
'Email': sEmail,
|
||||||
|
'ImageData': sImageData
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {Array} aUids
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.contactsDelete = function (fCallback, aUids)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'ContactsDelete', {
|
||||||
|
'Uids': aUids.join(',')
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
* @param {string} sQuery
|
||||||
|
* @param {number} iPage
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.suggestions = function (fCallback, sQuery, iPage)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'Suggestions', {
|
||||||
|
'Query': sQuery,
|
||||||
|
'Page': iPage
|
||||||
|
}, null, '', ['Suggestions']);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.servicesPics = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'ServicesPics');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.emailsPicsHashes = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'EmailsPicsHashes');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.facebookUser = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SocialFacebookUserInformation');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.facebookDisconnect = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SocialFacebookDisconnect');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.twitterUser = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SocialTwitterUserInformation');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.twitterDisconnect = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SocialTwitterDisconnect');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.googleUser = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SocialGoogleUserInformation');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.googleDisconnect = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SocialGoogleDisconnect');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Function} fCallback
|
||||||
|
*/
|
||||||
|
WebMailAjaxRemoteStorage.prototype.socialUsers = function (fCallback)
|
||||||
|
{
|
||||||
|
this.defaultRequest(fCallback, 'SocialUsers');
|
||||||
|
};
|
||||||
|
|
||||||
318
dev/Storages/WebMailCache.js
Normal file
318
dev/Storages/WebMailCache.js
Normal file
|
|
@ -0,0 +1,318 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractCacheStorage
|
||||||
|
*/
|
||||||
|
function WebMailCacheStorage()
|
||||||
|
{
|
||||||
|
AbstractCacheStorage.call(this);
|
||||||
|
|
||||||
|
this.oFoldersCache = {};
|
||||||
|
this.oFoldersNamesCache = {};
|
||||||
|
this.oFolderHashCache = {};
|
||||||
|
this.oFolderUidNextCache = {};
|
||||||
|
this.oMessageListHashCache = {};
|
||||||
|
this.oMessageFlagsCache = {};
|
||||||
|
this.oNewMessage = {};
|
||||||
|
this.oRequestedMessage = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(WebMailCacheStorage.prototype, AbstractCacheStorage.prototype);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oFoldersCache = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oFoldersNamesCache = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oFolderHashCache = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oFolderUidNextCache = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oMessageListHashCache = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oMessageFlagsCache = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oBodies = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oNewMessage = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.oRequestedMessage = {};
|
||||||
|
|
||||||
|
WebMailCacheStorage.prototype.clear = function ()
|
||||||
|
{
|
||||||
|
AbstractCacheStorage.prototype.clear.call(this);
|
||||||
|
|
||||||
|
this.oFoldersCache = {};
|
||||||
|
this.oFoldersNamesCache = {};
|
||||||
|
this.oFolderHashCache = {};
|
||||||
|
this.oFolderUidNextCache = {};
|
||||||
|
this.oMessageListHashCache = {};
|
||||||
|
this.oMessageFlagsCache = {};
|
||||||
|
this.oBodies = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {string} sUid
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.getMessageKey = function (sFolderFullNameRaw, sUid)
|
||||||
|
{
|
||||||
|
return sFolderFullNameRaw + '#' + sUid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {string} sUid
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.addRequestedMessage = function (sFolder, sUid)
|
||||||
|
{
|
||||||
|
this.oRequestedMessage[this.getMessageKey(sFolder, sUid)] = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {string} sUid
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.hasRequestedMessage = function (sFolder, sUid)
|
||||||
|
{
|
||||||
|
return true === this.oRequestedMessage[this.getMessageKey(sFolder, sUid)];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {string} sUid
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.addNewMessageCache = function (sFolderFullNameRaw, sUid)
|
||||||
|
{
|
||||||
|
this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {string} sUid
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.hasNewMessageAndRemoveFromCache = function (sFolderFullNameRaw, sUid)
|
||||||
|
{
|
||||||
|
if (this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)])
|
||||||
|
{
|
||||||
|
this.oNewMessage[this.getMessageKey(sFolderFullNameRaw, sUid)] = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
WebMailCacheStorage.prototype.clearNewMessageCache = function ()
|
||||||
|
{
|
||||||
|
this.oNewMessage = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderHash
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.getFolderFullNameRaw = function (sFolderHash)
|
||||||
|
{
|
||||||
|
return '' !== sFolderHash && this.oFoldersNamesCache[sFolderHash] ? this.oFoldersNamesCache[sFolderHash] : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderHash
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.setFolderFullNameRaw = function (sFolderHash, sFolderFullNameRaw)
|
||||||
|
{
|
||||||
|
this.oFoldersNamesCache[sFolderHash] = sFolderFullNameRaw;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.getFolderHash = function (sFolderFullNameRaw)
|
||||||
|
{
|
||||||
|
return '' !== sFolderFullNameRaw && this.oFolderHashCache[sFolderFullNameRaw] ? this.oFolderHashCache[sFolderFullNameRaw] : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {string} sFolderHash
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.setFolderHash = function (sFolderFullNameRaw, sFolderHash)
|
||||||
|
{
|
||||||
|
this.oFolderHashCache[sFolderFullNameRaw] = sFolderHash;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.getFolderUidNext = function (sFolderFullNameRaw)
|
||||||
|
{
|
||||||
|
return '' !== sFolderFullNameRaw && this.oFolderUidNextCache[sFolderFullNameRaw] ? this.oFolderUidNextCache[sFolderFullNameRaw] : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {string} sUidNext
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.setFolderUidNext = function (sFolderFullNameRaw, sUidNext)
|
||||||
|
{
|
||||||
|
this.oFolderUidNextCache[sFolderFullNameRaw] = sUidNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @return {?FolderModel}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.getFolderFromCacheList = function (sFolderFullNameRaw)
|
||||||
|
{
|
||||||
|
return '' !== sFolderFullNameRaw && this.oFoldersCache[sFolderFullNameRaw] ? this.oFoldersCache[sFolderFullNameRaw] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
* @param {?FolderModel} oFolder
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.setFolderToCacheList = function (sFolderFullNameRaw, oFolder)
|
||||||
|
{
|
||||||
|
this.oFoldersCache[sFolderFullNameRaw] = oFolder;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullNameRaw
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.removeFolderFromCacheList = function (sFolderFullNameRaw)
|
||||||
|
{
|
||||||
|
this.setFolderToCacheList(sFolderFullNameRaw, null);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullName
|
||||||
|
* @param {string} sUid
|
||||||
|
* @return {?Array}
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.getMessageFlagsFromCache = function (sFolderFullName, sUid)
|
||||||
|
{
|
||||||
|
return this.oMessageFlagsCache[sFolderFullName] && this.oMessageFlagsCache[sFolderFullName][sUid] ?
|
||||||
|
this.oMessageFlagsCache[sFolderFullName][sUid] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullName
|
||||||
|
* @param {string} sUid
|
||||||
|
* @param {Array} aFlagsCache
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.setMessageFlagsToCache = function (sFolderFullName, sUid, aFlagsCache)
|
||||||
|
{
|
||||||
|
if (!this.oMessageFlagsCache[sFolderFullName])
|
||||||
|
{
|
||||||
|
this.oMessageFlagsCache[sFolderFullName] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oMessageFlagsCache[sFolderFullName][sUid] = aFlagsCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sFolderFullName
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.clearMessageFlagsFromCacheByFolder = function (sFolderFullName)
|
||||||
|
{
|
||||||
|
this.oMessageFlagsCache[sFolderFullName] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {(MessageModel|null)} oMessage
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.initMessageFlagsFromCache = function (oMessage)
|
||||||
|
{
|
||||||
|
if (oMessage)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
self = this,
|
||||||
|
aFlags = this.getMessageFlagsFromCache(oMessage.folderFullNameRaw, oMessage.uid),
|
||||||
|
mUnseenSubUid = null,
|
||||||
|
mFlaggedSubUid = null
|
||||||
|
;
|
||||||
|
|
||||||
|
if (aFlags && 4 === aFlags.length)
|
||||||
|
{
|
||||||
|
oMessage.unseen(aFlags[0]);
|
||||||
|
oMessage.flagged(aFlags[1]);
|
||||||
|
oMessage.answered(aFlags[2]);
|
||||||
|
oMessage.forwarded(aFlags[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 < oMessage.threads().length)
|
||||||
|
{
|
||||||
|
mUnseenSubUid = _.find(oMessage.threads(), function (iSubUid) {
|
||||||
|
var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid);
|
||||||
|
return aFlags && 4 === aFlags.length && !!aFlags[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
mFlaggedSubUid = _.find(oMessage.threads(), function (iSubUid) {
|
||||||
|
var aFlags = self.getMessageFlagsFromCache(oMessage.folderFullNameRaw, iSubUid);
|
||||||
|
return aFlags && 4 === aFlags.length && !!aFlags[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
oMessage.hasUnseenSubMessage(mUnseenSubUid && 0 < Utils.pInt(mUnseenSubUid));
|
||||||
|
oMessage.hasFlaggedSubMessage(mFlaggedSubUid && 0 < Utils.pInt(mFlaggedSubUid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {(MessageModel|null)} oMessage
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.storeMessageFlagsToCache = function (oMessage)
|
||||||
|
{
|
||||||
|
if (oMessage)
|
||||||
|
{
|
||||||
|
this.setMessageFlagsToCache(
|
||||||
|
oMessage.folderFullNameRaw,
|
||||||
|
oMessage.uid,
|
||||||
|
[oMessage.unseen(), oMessage.flagged(), oMessage.answered(), oMessage.forwarded()]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @param {string} sFolder
|
||||||
|
* @param {string} sUid
|
||||||
|
* @param {Array} aFlags
|
||||||
|
*/
|
||||||
|
WebMailCacheStorage.prototype.storeMessageFlagsToCacheByFolderAndUid = function (sFolder, sUid, aFlags)
|
||||||
|
{
|
||||||
|
if (Utils.isArray(aFlags) && 4 === aFlags.length)
|
||||||
|
{
|
||||||
|
this.setMessageFlagsToCache(sFolder, sUid, aFlags);
|
||||||
|
}
|
||||||
|
};
|
||||||
896
dev/Storages/WebMailData.js
Normal file
896
dev/Storages/WebMailData.js
Normal file
|
|
@ -0,0 +1,896 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends AbstractData
|
||||||
|
*/
|
||||||
|
function WebMailDataStorage()
|
||||||
|
{
|
||||||
|
AbstractData.call(this);
|
||||||
|
|
||||||
|
var
|
||||||
|
fRemoveSystemFolderType = function (observable) {
|
||||||
|
return function () {
|
||||||
|
var oFolder = RL.cache().getFolderFromCacheList(observable());
|
||||||
|
if (oFolder)
|
||||||
|
{
|
||||||
|
oFolder.type(Enums.FolderType.User);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
fSetSystemFolderType = function (iType) {
|
||||||
|
return function (sValue) {
|
||||||
|
var oFolder = RL.cache().getFolderFromCacheList(sValue);
|
||||||
|
if (oFolder)
|
||||||
|
{
|
||||||
|
oFolder.type(iType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
this.devEmail = '';
|
||||||
|
this.devLogin = '';
|
||||||
|
this.devPassword = '';
|
||||||
|
|
||||||
|
this.accountEmail = ko.observable('');
|
||||||
|
this.accountLogin = ko.observable('');
|
||||||
|
this.projectHash = ko.observable('');
|
||||||
|
|
||||||
|
this.threading = ko.observable(false);
|
||||||
|
this.lastFoldersHash = '';
|
||||||
|
|
||||||
|
this.remoteSuggestions = false;
|
||||||
|
this.remoteChangePassword = false;
|
||||||
|
|
||||||
|
// system folders
|
||||||
|
this.sentFolder = ko.observable('');
|
||||||
|
this.draftFolder = ko.observable('');
|
||||||
|
this.spamFolder = ko.observable('');
|
||||||
|
this.trashFolder = ko.observable('');
|
||||||
|
|
||||||
|
this.sentFolder.subscribe(fRemoveSystemFolderType(this.sentFolder), this, 'beforeChange');
|
||||||
|
this.draftFolder.subscribe(fRemoveSystemFolderType(this.draftFolder), this, 'beforeChange');
|
||||||
|
this.spamFolder.subscribe(fRemoveSystemFolderType(this.spamFolder), this, 'beforeChange');
|
||||||
|
this.trashFolder.subscribe(fRemoveSystemFolderType(this.trashFolder), this, 'beforeChange');
|
||||||
|
|
||||||
|
this.sentFolder.subscribe(fSetSystemFolderType(Enums.FolderType.SentItems), this);
|
||||||
|
this.draftFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Draft), this);
|
||||||
|
this.spamFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Spam), this);
|
||||||
|
this.trashFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Trash), this);
|
||||||
|
|
||||||
|
this.draftFolderNotEnabled = ko.computed(function () {
|
||||||
|
return '' === this.draftFolder() || Consts.Values.UnuseOptionValue === this.draftFolder();
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// personal
|
||||||
|
this.displayName = ko.observable('');
|
||||||
|
this.signature = ko.observable('');
|
||||||
|
this.replyTo = ko.observable('');
|
||||||
|
|
||||||
|
// accounts
|
||||||
|
this.accounts = ko.observableArray([]);
|
||||||
|
this.accountsLoading = ko.observable(false).extend({'throttle': 100});
|
||||||
|
|
||||||
|
// identities
|
||||||
|
this.identities = ko.observableArray([]);
|
||||||
|
this.identitiesLoading = ko.observable(false).extend({'throttle': 100});
|
||||||
|
|
||||||
|
// folders
|
||||||
|
this.namespace = '';
|
||||||
|
this.folderList = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.foldersListError = ko.observable('');
|
||||||
|
|
||||||
|
this.foldersLoading = ko.observable(false);
|
||||||
|
this.foldersCreating = ko.observable(false);
|
||||||
|
this.foldersDeleting = ko.observable(false);
|
||||||
|
this.foldersRenaming = ko.observable(false);
|
||||||
|
|
||||||
|
this.currentFolder = ko.observable(null).extend({'toggleSubscribe': [null,
|
||||||
|
function (oPrev) {
|
||||||
|
if (oPrev)
|
||||||
|
{
|
||||||
|
oPrev.selected(false);
|
||||||
|
}
|
||||||
|
}, function (oNext) {
|
||||||
|
if (oNext)
|
||||||
|
{
|
||||||
|
oNext.selected(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
|
||||||
|
this.currentFolderFullNameRaw = ko.computed(function () {
|
||||||
|
return this.currentFolder() ? this.currentFolder().fullNameRaw : '';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.currentFolderFullName = ko.computed(function () {
|
||||||
|
return this.currentFolder() ? this.currentFolder().fullName : '';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.currentFolderFullNameHash = ko.computed(function () {
|
||||||
|
return this.currentFolder() ? this.currentFolder().fullNameHash : '';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.currentFolderName = ko.computed(function () {
|
||||||
|
return this.currentFolder() ? this.currentFolder().name() : '';
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.folderListSystemNames = ko.computed(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
aList = ['INBOX'],
|
||||||
|
aFolders = this.folderList(),
|
||||||
|
sSentFolder = this.sentFolder(),
|
||||||
|
sDraftFolder = this.draftFolder(),
|
||||||
|
sSpamFolder = this.spamFolder(),
|
||||||
|
sTrashFolder = this.trashFolder()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (Utils.isArray(aFolders) && 0 < aFolders.length)
|
||||||
|
{
|
||||||
|
if ('' !== sSentFolder && Consts.Values.UnuseOptionValue !== sSentFolder)
|
||||||
|
{
|
||||||
|
aList.push(sSentFolder);
|
||||||
|
}
|
||||||
|
if ('' !== sDraftFolder && Consts.Values.UnuseOptionValue !== sDraftFolder)
|
||||||
|
{
|
||||||
|
aList.push(sDraftFolder);
|
||||||
|
}
|
||||||
|
if ('' !== sSpamFolder && Consts.Values.UnuseOptionValue !== sSpamFolder)
|
||||||
|
{
|
||||||
|
aList.push(sSpamFolder);
|
||||||
|
}
|
||||||
|
if ('' !== sTrashFolder && Consts.Values.UnuseOptionValue !== sTrashFolder)
|
||||||
|
{
|
||||||
|
aList.push(sTrashFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aList;
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.folderListSystem = ko.computed(function () {
|
||||||
|
return _.compact(_.map(this.folderListSystemNames(), function (sName) {
|
||||||
|
return RL.cache().getFolderFromCacheList(sName);
|
||||||
|
}));
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.folderMenuForMove = ko.computed(function () {
|
||||||
|
return RL.folderListOptionsBuilder(this.folderListSystem(), this.folderList(), [
|
||||||
|
this.currentFolderFullNameRaw()
|
||||||
|
], null, null, null, null, function (oItem) {
|
||||||
|
return oItem ? oItem.localName() : '';
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// message list
|
||||||
|
this.staticMessageList = [];
|
||||||
|
|
||||||
|
this.messageList = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.messageListCount = ko.observable(0);
|
||||||
|
this.messageListSearch = ko.observable('');
|
||||||
|
this.messageListPage = ko.observable(1);
|
||||||
|
|
||||||
|
this.messageListThreadFolder = ko.observable('');
|
||||||
|
this.messageListThreadUids = ko.observableArray([]);
|
||||||
|
|
||||||
|
this.messageListThreadFolder.subscribe(function () {
|
||||||
|
this.messageListThreadUids([]);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageListEndSearch = ko.observable('');
|
||||||
|
this.messageListEndFolder = ko.observable('');
|
||||||
|
|
||||||
|
this.messageListPageCount = ko.computed(function () {
|
||||||
|
var iPage = Math.ceil(this.messageListCount() / this.messagesPerPage());
|
||||||
|
return 0 === iPage ? 1 : iPage;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.mainMessageListSearch = ko.computed({
|
||||||
|
'read': this.messageListSearch,
|
||||||
|
'write': function (sValue) {
|
||||||
|
kn.setHash(RL.link().mailBox(
|
||||||
|
this.currentFolderFullNameHash(), 1, Utils.trim(sValue.toString())
|
||||||
|
));
|
||||||
|
},
|
||||||
|
'owner': this
|
||||||
|
});
|
||||||
|
|
||||||
|
this.messageListError = ko.observable('');
|
||||||
|
|
||||||
|
this.messageListLoading = ko.observable(false);
|
||||||
|
this.messageListIsNotCompleted = ko.observable(false);
|
||||||
|
this.messageListCompleteLoadingThrottle = ko.observable(false).extend({'throttle': 200});
|
||||||
|
|
||||||
|
this.messageListCompleteLoading = ko.computed(function () {
|
||||||
|
var
|
||||||
|
bOne = this.messageListLoading(),
|
||||||
|
bTwo = this.messageListIsNotCompleted()
|
||||||
|
;
|
||||||
|
return bOne || bTwo;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageListCompleteLoading.subscribe(function (bValue) {
|
||||||
|
this.messageListCompleteLoadingThrottle(bValue);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageList.subscribe(_.debounce(function (aList) {
|
||||||
|
_.each(aList, function (oItem) {
|
||||||
|
if (oItem.newForAnimation())
|
||||||
|
{
|
||||||
|
oItem.newForAnimation(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 500));
|
||||||
|
|
||||||
|
// message preview
|
||||||
|
this.staticMessageList = new MessageModel();
|
||||||
|
this.message = ko.observable(null);
|
||||||
|
this.messageLoading = ko.observable(false);
|
||||||
|
this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50});
|
||||||
|
|
||||||
|
this.messageLoading.subscribe(function (bValue) {
|
||||||
|
this.messageLoadingThrottle(bValue);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageFullScreenMode = ko.observable(false);
|
||||||
|
|
||||||
|
this.messageError = ko.observable('');
|
||||||
|
|
||||||
|
this.messagesBodiesDom = ko.observable(null);
|
||||||
|
|
||||||
|
this.messagesBodiesDom.subscribe(function (oDom) {
|
||||||
|
if (oDom && !(oDom instanceof jQuery))
|
||||||
|
{
|
||||||
|
this.messagesBodiesDom($(oDom));
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageActiveDom = ko.observable(null);
|
||||||
|
|
||||||
|
this.isMessageSelected = ko.computed(function () {
|
||||||
|
return null !== this.message();
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.currentMessage = ko.observable(null);
|
||||||
|
|
||||||
|
this.message.subscribe(function (oMessage) {
|
||||||
|
if (null === oMessage)
|
||||||
|
{
|
||||||
|
this.currentMessage(null);
|
||||||
|
this.hideMessageBodies();
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageListChecked = ko.computed(function () {
|
||||||
|
return _.filter(this.messageList(), function (oMessage) {
|
||||||
|
return oMessage.checked();
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageListCheckedOrSelected = ko.computed(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
aChecked = this.messageListChecked(),
|
||||||
|
oSelectedMessage = this.currentMessage()
|
||||||
|
;
|
||||||
|
|
||||||
|
return _.union(aChecked, oSelectedMessage ? [oSelectedMessage] : []);
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageListCheckedUids = ko.computed(function () {
|
||||||
|
var aList = [];
|
||||||
|
_.each(this.messageListChecked(), function (oMessage) {
|
||||||
|
if (oMessage)
|
||||||
|
{
|
||||||
|
aList.push(oMessage.uid);
|
||||||
|
if (0 < oMessage.threadsLen() && 0 === oMessage.parentUid() && oMessage.lastInCollapsedThread())
|
||||||
|
{
|
||||||
|
aList = _.union(aList, oMessage.threads());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return aList;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.messageListCheckedOrSelectedUidsWithSubMails = ko.computed(function () {
|
||||||
|
var aList = [];
|
||||||
|
_.each(this.messageListCheckedOrSelected(), function (oMessage) {
|
||||||
|
if (oMessage)
|
||||||
|
{
|
||||||
|
aList.push(oMessage.uid);
|
||||||
|
if (0 < oMessage.threadsLen() && 0 === oMessage.parentUid() && oMessage.lastInCollapsedThread())
|
||||||
|
{
|
||||||
|
aList = _.union(aList, oMessage.threads());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return aList;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// quota
|
||||||
|
this.userQuota = ko.observable(0);
|
||||||
|
this.userUsageSize = ko.observable(0);
|
||||||
|
this.userUsageProc = ko.computed(function () {
|
||||||
|
|
||||||
|
var
|
||||||
|
iQuota = this.userQuota(),
|
||||||
|
iUsed = this.userUsageSize()
|
||||||
|
;
|
||||||
|
|
||||||
|
return 0 < iQuota ? Math.ceil((iUsed / iQuota) * 100) : 0;
|
||||||
|
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// other
|
||||||
|
this.useKeyboardShortcuts = ko.observable(true);
|
||||||
|
|
||||||
|
// google
|
||||||
|
this.googleActions = ko.observable(false);
|
||||||
|
this.googleLoggined = ko.observable(false);
|
||||||
|
this.googleUserName = ko.observable('');
|
||||||
|
|
||||||
|
// facebook
|
||||||
|
this.facebookActions = ko.observable(false);
|
||||||
|
this.facebookLoggined = ko.observable(false);
|
||||||
|
this.facebookUserName = ko.observable('');
|
||||||
|
|
||||||
|
// twitter
|
||||||
|
this.twitterActions = ko.observable(false);
|
||||||
|
this.twitterLoggined = ko.observable(false);
|
||||||
|
this.twitterUserName = ko.observable('');
|
||||||
|
|
||||||
|
this.customThemeType = ko.observable(Enums.CustomThemeType.Light);
|
||||||
|
|
||||||
|
this.purgeMessageBodyCacheThrottle = _.throttle(this.purgeMessageBodyCache, 1000 * 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.extend(WebMailDataStorage.prototype, AbstractData.prototype);
|
||||||
|
|
||||||
|
WebMailDataStorage.prototype.purgeMessageBodyCache = function()
|
||||||
|
{
|
||||||
|
var
|
||||||
|
iCount = 0,
|
||||||
|
oMessagesBodiesDom = null,
|
||||||
|
iEnd = Globals.iMessageBodyCacheCount - Consts.Values.iMessageBodyCacheLimit
|
||||||
|
;
|
||||||
|
|
||||||
|
if (0 < iEnd)
|
||||||
|
{
|
||||||
|
oMessagesBodiesDom = this.messagesBodiesDom();
|
||||||
|
if (oMessagesBodiesDom)
|
||||||
|
{
|
||||||
|
oMessagesBodiesDom.find('.rl-cache-class').each(function () {
|
||||||
|
var oItem = $(this);
|
||||||
|
if (iEnd > oItem.data('rl-cache-count'))
|
||||||
|
{
|
||||||
|
oItem.addClass('rl-cache-purge');
|
||||||
|
iCount++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (0 < iCount)
|
||||||
|
{
|
||||||
|
_.delay(function () {
|
||||||
|
oMessagesBodiesDom.find('.rl-cache-purge').remove();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WebMailDataStorage.prototype.populateDataOnStart = function()
|
||||||
|
{
|
||||||
|
AbstractData.prototype.populateDataOnStart.call(this);
|
||||||
|
|
||||||
|
this.accountEmail(RL.settingsGet('Email'));
|
||||||
|
this.accountLogin(RL.settingsGet('Login'));
|
||||||
|
this.projectHash(RL.settingsGet('ProjectHash'));
|
||||||
|
|
||||||
|
this.displayName(RL.settingsGet('DisplayName'));
|
||||||
|
this.replyTo(RL.settingsGet('ReplyTo'));
|
||||||
|
this.signature(RL.settingsGet('Signature'));
|
||||||
|
|
||||||
|
this.lastFoldersHash = RL.local().get(Enums.ClientSideKeyName.FoldersLashHash) || '';
|
||||||
|
|
||||||
|
this.remoteSuggestions = !!RL.settingsGet('RemoteSuggestions');
|
||||||
|
this.remoteChangePassword = !!RL.settingsGet('RemoteChangePassword');
|
||||||
|
|
||||||
|
this.devEmail = RL.settingsGet('DevEmail');
|
||||||
|
this.devLogin = RL.settingsGet('DevLogin');
|
||||||
|
this.devPassword = RL.settingsGet('DevPassword');
|
||||||
|
};
|
||||||
|
|
||||||
|
WebMailDataStorage.prototype.initUidNextAndNewMessages = function (sFolder, sUidNext, aNewMessages)
|
||||||
|
{
|
||||||
|
if ('INBOX' === sFolder && Utils.isNormal(sUidNext) && sUidNext !== '')
|
||||||
|
{
|
||||||
|
if (Utils.isArray(aNewMessages) && 0 < aNewMessages.length)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oCache = RL.cache(),
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = aNewMessages.length,
|
||||||
|
fNotificationHelper = function (sImageSrc, sTitle, sText)
|
||||||
|
{
|
||||||
|
var oNotification = null;
|
||||||
|
if (NotificationClass && RL.data().useDesktopNotifications())
|
||||||
|
{
|
||||||
|
oNotification = new NotificationClass(sTitle, {
|
||||||
|
'body': sText,
|
||||||
|
'icon': sImageSrc
|
||||||
|
});
|
||||||
|
|
||||||
|
if (oNotification)
|
||||||
|
{
|
||||||
|
if (oNotification.show)
|
||||||
|
{
|
||||||
|
oNotification.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout((function (oLocalNotifications) {
|
||||||
|
return function () {
|
||||||
|
if (oLocalNotifications.cancel)
|
||||||
|
{
|
||||||
|
oLocalNotifications.cancel();
|
||||||
|
}
|
||||||
|
else if (oLocalNotifications.close)
|
||||||
|
{
|
||||||
|
oLocalNotifications.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}(oNotification)), 7000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
_.each(aNewMessages, function (oItem) {
|
||||||
|
oCache.addNewMessageCache(sFolder, oItem.Uid);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (3 < iLen)
|
||||||
|
{
|
||||||
|
fNotificationHelper(
|
||||||
|
RL.link().notificationMailIcon(),
|
||||||
|
RL.data().accountEmail(),
|
||||||
|
Utils.i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
|
||||||
|
'COUNT': iLen
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
fNotificationHelper(
|
||||||
|
RL.link().notificationMailIcon(),
|
||||||
|
MessageModel.emailsToLine(MessageModel.initEmailsFromJson(aNewMessages[iIndex].From), false),
|
||||||
|
aNewMessages[iIndex].Subject
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.cache().setFolderUidNext(sFolder, sUidNext);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} sNamespace
|
||||||
|
* @param {Array} aFolders
|
||||||
|
* @param {boolean} bCached
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
WebMailDataStorage.prototype.folderResponseParseRec = function (sNamespace, aFolders, bCached)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = 0,
|
||||||
|
oFolder = null,
|
||||||
|
oCacheFolder = null,
|
||||||
|
sFolderFullNameRaw = '',
|
||||||
|
aSubFolders = [],
|
||||||
|
aList = []
|
||||||
|
;
|
||||||
|
|
||||||
|
bCached = !!bCached;
|
||||||
|
|
||||||
|
for (iIndex = 0, iLen = aFolders.length; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
oFolder = aFolders[iIndex];
|
||||||
|
if (oFolder)
|
||||||
|
{
|
||||||
|
sFolderFullNameRaw = oFolder.FullNameRaw;
|
||||||
|
|
||||||
|
oCacheFolder = RL.cache().getFolderFromCacheList(sFolderFullNameRaw);
|
||||||
|
if (!oCacheFolder)
|
||||||
|
{
|
||||||
|
oCacheFolder = FolderModel.newInstanceFromJson(oFolder);
|
||||||
|
if (oCacheFolder)
|
||||||
|
{
|
||||||
|
RL.cache().setFolderToCacheList(sFolderFullNameRaw, oCacheFolder);
|
||||||
|
RL.cache().setFolderFullNameRaw(oCacheFolder.fullNameHash, sFolderFullNameRaw);
|
||||||
|
|
||||||
|
oCacheFolder.isGmailFolder = Consts.Values.GmailFolderName.toLowerCase() === sFolderFullNameRaw.toLowerCase();
|
||||||
|
if ('' !== sNamespace && sNamespace === oCacheFolder.fullNameRaw + oCacheFolder.delimiter)
|
||||||
|
{
|
||||||
|
oCacheFolder.isNamespaceFolder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oCacheFolder.isNamespaceFolder || oCacheFolder.isGmailFolder)
|
||||||
|
{
|
||||||
|
oCacheFolder.isUnpaddigFolder = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oCacheFolder)
|
||||||
|
{
|
||||||
|
oCacheFolder.collapsed(!Utils.isFolderExpanded(oCacheFolder.fullNameHash));
|
||||||
|
|
||||||
|
if (!bCached && oFolder.Extended)
|
||||||
|
{
|
||||||
|
if (oFolder.Extended.Hash)
|
||||||
|
{
|
||||||
|
RL.cache().setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isNormal(oFolder.Extended.MessageCount))
|
||||||
|
{
|
||||||
|
oCacheFolder.messageCountAll(oFolder.Extended.MessageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isNormal(oFolder.Extended.MessageUnseenCount))
|
||||||
|
{
|
||||||
|
oCacheFolder.messageCountUnread(oFolder.Extended.MessageUnseenCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aSubFolders = oFolder['SubFolders'];
|
||||||
|
if (aSubFolders && 'Collection/FolderCollection' === aSubFolders['@Object'] &&
|
||||||
|
aSubFolders['@Collection'] && Utils.isArray(aSubFolders['@Collection']))
|
||||||
|
{
|
||||||
|
oCacheFolder.subFolders(
|
||||||
|
this.folderResponseParseRec(sNamespace, aSubFolders['@Collection'], bCached));
|
||||||
|
}
|
||||||
|
|
||||||
|
aList.push(oCacheFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aList;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {*} oData
|
||||||
|
* @param {boolean=} bCached = false
|
||||||
|
*/
|
||||||
|
WebMailDataStorage.prototype.setFolders = function (oData, bCached)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
aList = [],
|
||||||
|
bUpdate = false,
|
||||||
|
oRLData = RL.data(),
|
||||||
|
aFolders = oRLData.folderList(),
|
||||||
|
bFoldersFirst = 0 === aFolders.length,
|
||||||
|
fNormalizeFolder = function (sFolderFullNameRaw) {
|
||||||
|
return ('' === sFolderFullNameRaw || Consts.Values.UnuseOptionValue === sFolderFullNameRaw ||
|
||||||
|
null !== RL.cache().getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : '';
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oData && oData.Result && 'Collection/FolderCollection' === oData.Result['@Object'] &&
|
||||||
|
oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection']))
|
||||||
|
{
|
||||||
|
if (!Utils.isUnd(oData.Result.Namespace))
|
||||||
|
{
|
||||||
|
oRLData.namespace = oData.Result.Namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.threading(!!RL.settingsGet('UseImapThread') && oData.Result.IsThreadsSupported && true);
|
||||||
|
|
||||||
|
aList = this.folderResponseParseRec(oRLData.namespace, oData.Result['@Collection'], !!bCached);
|
||||||
|
oRLData.folderList(aList);
|
||||||
|
|
||||||
|
if (oData.Result['SystemFolders'] &&
|
||||||
|
'' === '' + RL.settingsGet('SentFolder') + RL.settingsGet('DraftFolder') +
|
||||||
|
RL.settingsGet('SpamFolder') + RL.settingsGet('TrashFolder'))
|
||||||
|
{
|
||||||
|
// TODO Magic Numbers
|
||||||
|
RL.settingsSet('SentFolder', oData.Result['SystemFolders'][2] || null);
|
||||||
|
RL.settingsSet('DraftFolder', oData.Result['SystemFolders'][3] || null);
|
||||||
|
RL.settingsSet('SpamFolder', oData.Result['SystemFolders'][4] || null);
|
||||||
|
RL.settingsSet('TrashFolder', oData.Result['SystemFolders'][5] || null);
|
||||||
|
|
||||||
|
bUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
oRLData.sentFolder(fNormalizeFolder(RL.settingsGet('SentFolder')));
|
||||||
|
oRLData.draftFolder(fNormalizeFolder(RL.settingsGet('DraftFolder')));
|
||||||
|
oRLData.spamFolder(fNormalizeFolder(RL.settingsGet('SpamFolder')));
|
||||||
|
oRLData.trashFolder(fNormalizeFolder(RL.settingsGet('TrashFolder')));
|
||||||
|
|
||||||
|
if (bUpdate)
|
||||||
|
{
|
||||||
|
RL.remote().saveSystemFolders(Utils.emptyFunction, {
|
||||||
|
'SentFolder': oRLData.sentFolder(),
|
||||||
|
'DraftFolder': oRLData.draftFolder(),
|
||||||
|
'SpamFolder': oRLData.spamFolder(),
|
||||||
|
'TrashFolder': oRLData.trashFolder()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bCached)
|
||||||
|
{
|
||||||
|
RL.local().set(Enums.ClientSideKeyName.FoldersLashHash, oData.Result.FoldersHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bFoldersFirst && bCached)
|
||||||
|
{
|
||||||
|
RL.folders(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WebMailDataStorage.prototype.hideMessageBodies = function ()
|
||||||
|
{
|
||||||
|
var oMessagesBodiesDom = this.messagesBodiesDom();
|
||||||
|
if (oMessagesBodiesDom)
|
||||||
|
{
|
||||||
|
oMessagesBodiesDom.find('.b-text-part').hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WebMailDataStorage.prototype.setMessage = function (oData, bCached)
|
||||||
|
{
|
||||||
|
var
|
||||||
|
bIsHtml = false,
|
||||||
|
bHasExternals = false,
|
||||||
|
bHasInternals = false,
|
||||||
|
oBody = null,
|
||||||
|
oTextBody = null,
|
||||||
|
sId = '',
|
||||||
|
oMessagesBodiesDom = this.messagesBodiesDom(),
|
||||||
|
oMessage = this.message()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (oData && oMessage && oData.Result && 'Object/Message' === oData.Result['@Object'] &&
|
||||||
|
oMessage.folderFullNameRaw === oData.Result.Folder && oMessage.uid === oData.Result.Uid)
|
||||||
|
{
|
||||||
|
this.messageError('');
|
||||||
|
|
||||||
|
oMessage.initUpdateByMessageJson(oData.Result);
|
||||||
|
RL.cache().addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
|
||||||
|
|
||||||
|
if (!bCached)
|
||||||
|
{
|
||||||
|
oMessage.initFlagsByJson(oData.Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
oMessagesBodiesDom = oMessagesBodiesDom && oMessagesBodiesDom[0] ? oMessagesBodiesDom : null;
|
||||||
|
if (oMessagesBodiesDom)
|
||||||
|
{
|
||||||
|
sId = 'rl-' + oMessage.requestHash.replace(/[^a-zA-Z0-9]/g, '');
|
||||||
|
oTextBody = oMessagesBodiesDom.find('#' + sId);
|
||||||
|
if (!oTextBody || !oTextBody[0])
|
||||||
|
{
|
||||||
|
bHasExternals = !!oData.Result.HasExternals;
|
||||||
|
bHasInternals = !!oData.Result.HasInternals;
|
||||||
|
|
||||||
|
oBody = $('<div id="' + sId + '" />').hide().addClass('rl-cache-class');
|
||||||
|
oBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
|
||||||
|
|
||||||
|
if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html)
|
||||||
|
{
|
||||||
|
bIsHtml = true;
|
||||||
|
oBody.html(oData.Result.Html.toString()).addClass('b-text-part html');
|
||||||
|
}
|
||||||
|
else if (Utils.isNormal(oData.Result.Plain) && '' !== oData.Result.Plain)
|
||||||
|
{
|
||||||
|
bIsHtml = false;
|
||||||
|
oBody.html(oData.Result.Plain.toString()).addClass('b-text-part plain');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bIsHtml = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oData.Result.Rtl)
|
||||||
|
{
|
||||||
|
oBody.data('rl-is-rtl', true);
|
||||||
|
oBody.addClass('rtl-text-part');
|
||||||
|
}
|
||||||
|
|
||||||
|
oMessagesBodiesDom.append(oBody);
|
||||||
|
|
||||||
|
oBody.data('rl-is-html', bIsHtml);
|
||||||
|
oBody.data('rl-has-images', bHasExternals);
|
||||||
|
|
||||||
|
oMessage.isRtl(!!oBody.data('rl-is-rtl'));
|
||||||
|
oMessage.isHtml(!!oBody.data('rl-is-html'));
|
||||||
|
oMessage.hasImages(!!oBody.data('rl-has-images'));
|
||||||
|
oMessage.body = oBody;
|
||||||
|
|
||||||
|
if (bHasInternals)
|
||||||
|
{
|
||||||
|
oMessage.showInternalImages(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oMessage.hasImages() && this.showImages())
|
||||||
|
{
|
||||||
|
oMessage.showExternalImages(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.purgeMessageBodyCacheThrottle();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oTextBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
|
||||||
|
|
||||||
|
oMessage.isRtl(!!oTextBody.data('rl-is-rtl'));
|
||||||
|
oMessage.isHtml(!!oTextBody.data('rl-is-html'));
|
||||||
|
oMessage.hasImages(!!oTextBody.data('rl-has-images'));
|
||||||
|
oMessage.body = oTextBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messageActiveDom(oMessage.body);
|
||||||
|
|
||||||
|
this.hideMessageBodies();
|
||||||
|
oMessage.body.show();
|
||||||
|
|
||||||
|
if (oBody)
|
||||||
|
{
|
||||||
|
Utils.initBlockquoteSwitcher(oBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RL.cache().initMessageFlagsFromCache(oMessage);
|
||||||
|
if (oMessage.unseen())
|
||||||
|
{
|
||||||
|
RL.setMessageSeen(oMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.windowResize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
WebMailDataStorage.prototype.setMessageList = function (oData, bCached)
|
||||||
|
{
|
||||||
|
if (oData && oData.Result && 'Collection/MessageCollection' === oData.Result['@Object'] &&
|
||||||
|
oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection']))
|
||||||
|
{
|
||||||
|
var
|
||||||
|
oRainLoopData = RL.data(),
|
||||||
|
oCache = RL.cache(),
|
||||||
|
mLastCollapsedThreadUids = null,
|
||||||
|
iIndex = 0,
|
||||||
|
iLen = 0,
|
||||||
|
iCount = 0,
|
||||||
|
iOffset = 0,
|
||||||
|
aList = [],
|
||||||
|
aStaticList = oRainLoopData.staticMessageList,
|
||||||
|
oJsonMessage = null,
|
||||||
|
oMessage = null,
|
||||||
|
oFolder = null,
|
||||||
|
iNewCount = 0,
|
||||||
|
bUnreadCountChange = false
|
||||||
|
;
|
||||||
|
|
||||||
|
iCount = Utils.pInt(oData.Result.MessageResultCount);
|
||||||
|
iOffset = Utils.pInt(oData.Result.Offset);
|
||||||
|
|
||||||
|
if (Utils.isNonEmptyArray(oData.Result.LastCollapsedThreadUids))
|
||||||
|
{
|
||||||
|
mLastCollapsedThreadUids = oData.Result.LastCollapsedThreadUids;
|
||||||
|
}
|
||||||
|
|
||||||
|
oFolder = RL.cache().getFolderFromCacheList(
|
||||||
|
Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
|
||||||
|
|
||||||
|
if (oFolder && !bCached)
|
||||||
|
{
|
||||||
|
RL.cache().setFolderHash(oData.Result.Folder, oData.Result.FolderHash);
|
||||||
|
|
||||||
|
if (Utils.isNormal(oData.Result.MessageCount))
|
||||||
|
{
|
||||||
|
oFolder.messageCountAll(oData.Result.MessageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.isNormal(oData.Result.MessageUnseenCount))
|
||||||
|
{
|
||||||
|
if (Utils.pInt(oFolder.messageCountUnread()) !== Utils.pInt(oData.Result.MessageUnseenCount))
|
||||||
|
{
|
||||||
|
bUnreadCountChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
oFolder.messageCountUnread(oData.Result.MessageUnseenCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bUnreadCountChange && oFolder)
|
||||||
|
{
|
||||||
|
RL.cache().clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (iIndex = 0, iLen = oData.Result['@Collection'].length; iIndex < iLen; iIndex++)
|
||||||
|
{
|
||||||
|
oJsonMessage = oData.Result['@Collection'][iIndex];
|
||||||
|
if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object'])
|
||||||
|
{
|
||||||
|
oMessage = aStaticList[iIndex];
|
||||||
|
if (!oMessage || !oMessage.initByJson(oJsonMessage))
|
||||||
|
{
|
||||||
|
oMessage = MessageModel.newInstanceFromJson(oJsonMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oMessage)
|
||||||
|
{
|
||||||
|
if (oCache.hasNewMessageAndRemoveFromCache(oMessage.folderFullNameRaw, oMessage.uid) && 5 >= iNewCount)
|
||||||
|
{
|
||||||
|
iNewCount++;
|
||||||
|
oMessage.newForAnimation(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
oMessage.deleted(false);
|
||||||
|
|
||||||
|
if (bCached)
|
||||||
|
{
|
||||||
|
RL.cache().initMessageFlagsFromCache(oMessage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RL.cache().storeMessageFlagsToCache(oMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
oMessage.lastInCollapsedThread(mLastCollapsedThreadUids && -1 < Utils.inArray(Utils.pInt(oMessage.uid), mLastCollapsedThreadUids) ? true : false);
|
||||||
|
|
||||||
|
aList.push(oMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oRainLoopData.messageListCount(iCount);
|
||||||
|
oRainLoopData.messageListSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : '');
|
||||||
|
oRainLoopData.messageListEndSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : '');
|
||||||
|
oRainLoopData.messageListEndFolder(Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
|
||||||
|
oRainLoopData.messageListPage(Math.ceil((iOffset / oRainLoopData.messagesPerPage()) + 1));
|
||||||
|
|
||||||
|
oRainLoopData.messageList(aList);
|
||||||
|
oRainLoopData.messageListIsNotCompleted(false);
|
||||||
|
|
||||||
|
oMessage = oRainLoopData.message();
|
||||||
|
if (oMessage && oRainLoopData.messageList.setSelectedByUid)
|
||||||
|
{
|
||||||
|
oRainLoopData.messageList.setSelectedByUid(oMessage.generateUid());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aStaticList.length < aList.length)
|
||||||
|
{
|
||||||
|
oRainLoopData.staticMessageList = aList;
|
||||||
|
}
|
||||||
|
|
||||||
|
oCache.clearNewMessageCache();
|
||||||
|
|
||||||
|
if (oFolder && (bCached || bUnreadCountChange || RL.data().useThreads()))
|
||||||
|
{
|
||||||
|
RL.folderInformation(oFolder.fullNameRaw, aList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RL.data().messageListCount(0);
|
||||||
|
RL.data().messageList([]);
|
||||||
|
RL.data().messageListError(Utils.getNotification(
|
||||||
|
oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantGetMessageList
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
73
dev/Styles/@Main.less
Normal file
73
dev/Styles/@Main.less
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* RainLoop Webmail (c) RainLoop Team | Licensed under CC BY-NC-SA 3.0 */
|
||||||
|
|
||||||
|
@import "../../vendors/bootstrap/less/variables.less";
|
||||||
|
@import "../../vendors/bootstrap/less/mixins.less";
|
||||||
|
|
||||||
|
@import "_Values.less";
|
||||||
|
|
||||||
|
@import "../../vendors/bootstrap/less/scaffolding.less";
|
||||||
|
@import "../../vendors/bootstrap/less/grid.less";
|
||||||
|
@import "../../vendors/bootstrap/less/layouts.less";
|
||||||
|
|
||||||
|
@import "../../vendors/bootstrap/less/type.less";
|
||||||
|
@import "../../vendors/bootstrap/less/code.less";
|
||||||
|
@import "../../vendors/bootstrap/less/forms.less";
|
||||||
|
@import "../../vendors/bootstrap/less/tables.less";
|
||||||
|
|
||||||
|
@import "../../vendors/bootstrap/less/dropdowns.less";
|
||||||
|
@import "../../vendors/bootstrap/less/wells.less";
|
||||||
|
@import "../../vendors/bootstrap/less/component-animations.less";
|
||||||
|
@import "../../vendors/bootstrap/less/close.less";
|
||||||
|
|
||||||
|
@import "../../vendors/bootstrap/less/buttons.less";
|
||||||
|
@import "../../vendors/bootstrap/less/button-groups.less";
|
||||||
|
@import "../../vendors/bootstrap/less/alerts.less";
|
||||||
|
|
||||||
|
@import "../../vendors/bootstrap/less/modals.less";
|
||||||
|
@import "../../vendors/bootstrap/less/tooltip.less";
|
||||||
|
@import "../../vendors/bootstrap/less/popovers.less";
|
||||||
|
@import "../../vendors/bootstrap/less/labels-badges.less";
|
||||||
|
@import "../../vendors/bootstrap/less/progress-bars.less";
|
||||||
|
@import "../../vendors/bootstrap/less/utilities.less";
|
||||||
|
|
||||||
|
@import "_IcoMoonToBoot.less";
|
||||||
|
@import "_BootstrapFix.less";
|
||||||
|
@import "_Select2Fix.less";
|
||||||
|
|
||||||
|
@import "Ui.less";
|
||||||
|
@import "Main.less";
|
||||||
|
@import "Layout.less";
|
||||||
|
@import "Scroll.less";
|
||||||
|
@import "SystemDropDown.less";
|
||||||
|
@import "Login.less";
|
||||||
|
@import "FolderList.less";
|
||||||
|
@import "FolderClear.less";
|
||||||
|
@import "FolderCreate.less";
|
||||||
|
@import "FolderSystem.less";
|
||||||
|
@import "Languages.less";
|
||||||
|
@import "AddAccount.less";
|
||||||
|
@import "Identity.less";
|
||||||
|
@import "AdvancedSearch.less";
|
||||||
|
@import "MessageList.less";
|
||||||
|
@import "MessageView.less";
|
||||||
|
@import "Contacts.less";
|
||||||
|
@import "Compose.less";
|
||||||
|
@import "Admin.less";
|
||||||
|
@import "AdminGeneral.less";
|
||||||
|
@import "AdminDomains.less";
|
||||||
|
@import "AdminDomain.less";
|
||||||
|
@import "AdminPackages.less";
|
||||||
|
@import "AdminPlugins.less";
|
||||||
|
@import "AdminPlugin.less";
|
||||||
|
@import "Activate.less";
|
||||||
|
@import "Settings.less";
|
||||||
|
@import "SettingsPersonal.less";
|
||||||
|
@import "SettingsGeneral.less";
|
||||||
|
@import "SettingsAccounts.less";
|
||||||
|
@import "SettingsIdentities.less";
|
||||||
|
@import "SettingsFolders.less";
|
||||||
|
@import "SettingsThemes.less";
|
||||||
|
|
||||||
|
@import "Animations.less";
|
||||||
|
@import "Editor.less";
|
||||||
|
@import "_End.less";
|
||||||
12
dev/Styles/Activate.less
Normal file
12
dev/Styles/Activate.less
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
.popups {
|
||||||
|
.b-activate-content {
|
||||||
|
width: 700px;
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-inline {
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
dev/Styles/AddAccount.less
Normal file
7
dev/Styles/AddAccount.less
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
.popups {
|
||||||
|
.b-account-add-content {
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
dev/Styles/Admin.less
Normal file
101
dev/Styles/Admin.less
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
|
||||||
|
.b-admin-left {
|
||||||
|
|
||||||
|
.b-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 34px;
|
||||||
|
padding: 8px 0 0 @rlLowMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px + @rlLowMargin + 10px;
|
||||||
|
bottom: @rlLowMargin;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-admin-menu {
|
||||||
|
|
||||||
|
.e-item {
|
||||||
|
overflow: hidden;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-link {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 29px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
z-index: 1;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
background-color: transparent;
|
||||||
|
color: #888;
|
||||||
|
|
||||||
|
padding: 4px 10px;
|
||||||
|
|
||||||
|
outline: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-item.selectable .e-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-item.selectable {
|
||||||
|
&:hover .e-link, &.selected .e-link {
|
||||||
|
background-color: #555;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-admin-right {
|
||||||
|
|
||||||
|
.b-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 34px;
|
||||||
|
padding: 8px @rlLowMargin;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px + @rlLowMargin;
|
||||||
|
bottom: @rlLowMargin;
|
||||||
|
left: 0;
|
||||||
|
right: @rlLowMargin;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
background-color: #fff;
|
||||||
|
border: @rlMainBorderSize solid @rlMainDarkColor;
|
||||||
|
|
||||||
|
.box-shadow(@rlMainShadow);
|
||||||
|
.border-radius(@rlMainBorderRadius);
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-settings-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
dev/Styles/AdminDomain.less
Normal file
43
dev/Styles/AdminDomain.less
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
.b-domain-content {
|
||||||
|
|
||||||
|
&.modal {
|
||||||
|
width: 645px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 1300px;
|
||||||
|
height: 390px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.domain-edit .modal-body {
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.domain-white-list-page .modal-body {
|
||||||
|
left: -640px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-desc {
|
||||||
|
color: red;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testing-done {
|
||||||
|
.imap-header, .smtp-header {
|
||||||
|
color: green;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.testing-error {
|
||||||
|
.imap-header, .smtp-header {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
dev/Styles/AdminDomains.less
Normal file
60
dev/Styles/AdminDomains.less
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
.b-admin-domains {
|
||||||
|
.process-place {
|
||||||
|
width: 600px;
|
||||||
|
padding: 14px 0;
|
||||||
|
text-align: center;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-admin-domains-list-table {
|
||||||
|
|
||||||
|
width: 600px;
|
||||||
|
|
||||||
|
.e-item {
|
||||||
|
|
||||||
|
.e-action {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.domain-name {
|
||||||
|
display: inline-block;
|
||||||
|
word-break: break-all;
|
||||||
|
.box-sizing(border-box);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled .domain-name {
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-delete {
|
||||||
|
margin-right: 15px;
|
||||||
|
visibility: hidden;
|
||||||
|
.opacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-access {
|
||||||
|
&.button-delete {
|
||||||
|
visibility: visible;
|
||||||
|
margin-right: 0;
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-domain, .disable-domain {
|
||||||
|
cursor: pointer;
|
||||||
|
.opacity(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled .disable-domain {
|
||||||
|
.opacity(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-domain, .disable-domain {
|
||||||
|
&:hover {
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
dev/Styles/AdminGeneral.less
Normal file
4
dev/Styles/AdminGeneral.less
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
.b-admin-general {
|
||||||
|
}
|
||||||
|
|
||||||
43
dev/Styles/AdminPackages.less
Normal file
43
dev/Styles/AdminPackages.less
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
.b-admin-packages {
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
width: 650px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-place {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-admin-packages-list-table {
|
||||||
|
|
||||||
|
width: 700px;
|
||||||
|
|
||||||
|
.e-item {
|
||||||
|
|
||||||
|
.package-img {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package-name.core {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.package-desc {
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-action {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package-release-parent, .package-actions-parent {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.package-actions-parent {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
dev/Styles/AdminPlugin.less
Normal file
30
dev/Styles/AdminPlugin.less
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
.b-plugin-content {
|
||||||
|
|
||||||
|
&.modal {
|
||||||
|
width: 660px;
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.information {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #ddd;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 25px;
|
||||||
|
width: 30px;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 400px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
dev/Styles/AdminPlugins.less
Normal file
40
dev/Styles/AdminPlugins.less
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
.b-admin-plugins {
|
||||||
|
.process-place {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-admin-plugins-list-table {
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
.opacity(50);
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-item {
|
||||||
|
.e-action {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plugin-img {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
.plugin-img, .plugin-name {
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
.disable-plugin {
|
||||||
|
.opacity(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-admin-plugin-property {
|
||||||
|
.help-block {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
dev/Styles/AdvancedSearch.less
Normal file
16
dev/Styles/AdvancedSearch.less
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
.popups {
|
||||||
|
.b-advanced-search-content {
|
||||||
|
&.modal {
|
||||||
|
width: 750px;
|
||||||
|
.control-label {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
margin-left: 110px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
179
dev/Styles/Animations.less
Normal file
179
dev/Styles/Animations.less
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
|
||||||
|
.rl-strip-animation(@rgba, @stripOpacity) {
|
||||||
|
background-image: -webkit-linear-gradient(135deg, rgba(@rgba, @rgba, @rgba, @stripOpacity) 25%, transparent 25%,
|
||||||
|
transparent 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 75%,
|
||||||
|
transparent 75%, transparent);
|
||||||
|
background-image: -moz-linear-gradient(135deg, rgba(@rgba, @rgba, @rgba, @stripOpacity) 25%, transparent 25%,
|
||||||
|
transparent 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 75%,
|
||||||
|
transparent 75%, transparent);
|
||||||
|
background-image: -ms-linear-gradient(135deg, rgba(@rgba, @rgba, @rgba, @stripOpacity) 25%, transparent 25%,
|
||||||
|
transparent 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 75%,
|
||||||
|
transparent 75%, transparent);
|
||||||
|
background-image: -o-linear-gradient(135deg, rgba(@rgba, @rgba, @rgba, @stripOpacity) 25%, transparent 25%,
|
||||||
|
transparent 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 75%,
|
||||||
|
transparent 75%, transparent);
|
||||||
|
background-image: linear-gradient(135deg, rgba(@rgba, @rgba, @rgba, @stripOpacity) 25%, transparent 25%,
|
||||||
|
transparent 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 50%, rgba(@rgba, @rgba, @rgba, @stripOpacity) 75%,
|
||||||
|
transparent 75%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes highlight-folder-row {
|
||||||
|
0% {transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
@-moz-keyframes highlight-folder-row {
|
||||||
|
0% { -moz-transform: scale(1); } 50% { -moz-transform: scale(1.1); } 100% { -moz-transform: scale(1); }
|
||||||
|
}
|
||||||
|
@-webkit-keyframes highlight-folder-row {
|
||||||
|
0% { -webkit-transform: scale(1); } 50% { -webkit-transform: scale(1.1); } 100% { -webkit-transform: scale(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes textLoadingAnimationKeyFrame {
|
||||||
|
0% { opacity: 1; } 33% { opacity: 0; } 100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes textLoadingAnimationKeyFrame {
|
||||||
|
0% { opacity: 1; } 33% { opacity: 0; } 100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes textLoadingAnimationKeyFrame {
|
||||||
|
0% { opacity: 1; } 33% { opacity: 0; } 100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes animate-stripes {
|
||||||
|
0% {background-position: 0 0;} 100% {background-position: 60px 0;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes animate-stripes {
|
||||||
|
0% {background-position: 0 0;} 100% {background-position: 60px 0;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animate-stripes {
|
||||||
|
0% {background-position: 0 0;} 100% {background-position: 60px 0;}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rl-anim {
|
||||||
|
|
||||||
|
&.rgba.cssanimations.backgroundsize .e-strip-animation {
|
||||||
|
-webkit-background-size: 60px 60px;
|
||||||
|
-moz-background-size: 60px 60px;
|
||||||
|
background-size: 60px 60px;
|
||||||
|
|
||||||
|
.rl-strip-animation(0, 0.1);
|
||||||
|
|
||||||
|
-webkit-animation: animate-stripes 2s linear infinite;
|
||||||
|
-moz-animation: animate-stripes 2s linear infinite;
|
||||||
|
animation: animate-stripes 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .b-settings-folders {
|
||||||
|
.folder-item {
|
||||||
|
.button-delete {
|
||||||
|
.transition(all 0.2s linear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .b-settings-accounts {
|
||||||
|
.account-item {
|
||||||
|
.button-delete {
|
||||||
|
.transition(all 0.2s linear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .b-settings-identities {
|
||||||
|
.identity-item {
|
||||||
|
.button-delete {
|
||||||
|
.transition(all 0.2s linear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .b-admin-domains {
|
||||||
|
.e-item {
|
||||||
|
.button-delete {
|
||||||
|
.transition(all 0.2s linear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .b-compose {
|
||||||
|
.button-delete {
|
||||||
|
.transition(margin-left 0.2s linear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cssanimations .b-folders .e-item .anim-action-class {
|
||||||
|
-webkit-animation: highlight-folder-row 0.5s linear;
|
||||||
|
-moz-animation: highlight-folder-row 0.5s linear;
|
||||||
|
animation: highlight-folder-row 0.5s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .messageList {
|
||||||
|
.messageListItem {
|
||||||
|
.transition(max-height 400ms ease);
|
||||||
|
}
|
||||||
|
.listDragOver {
|
||||||
|
.transition(all 400ms ease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .b-list-content {
|
||||||
|
.e-contact-item {
|
||||||
|
.transition(max-height 400ms ease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .modal.b-domain-content {
|
||||||
|
.modal-body {
|
||||||
|
.transition(left 500ms ease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.csstransitions .modal-open .popups .modal {
|
||||||
|
-webkit-transform-origin: 50% 50%;
|
||||||
|
-moz-transform-origin: 50% 50%;
|
||||||
|
-o-transform-origin: 50% 50%;
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
|
||||||
|
.transition(~"0.3s all cubic-bezier(0.250, 0.460, 0.450, 0.940)");
|
||||||
|
.scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-open .popups .popup-active.modal {
|
||||||
|
-webkit-transform: none;
|
||||||
|
-moz-transform: none;
|
||||||
|
-o-transform: none;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.cssanimations .b-compose.loading .b-header-toolbar {
|
||||||
|
-webkit-background-size: 60px 60px;
|
||||||
|
-moz-background-size: 60px 60px;
|
||||||
|
background-size: 60px 60px;
|
||||||
|
|
||||||
|
.rl-strip-animation(255, 0.2);
|
||||||
|
|
||||||
|
-webkit-animation: animate-stripes 2s linear infinite;
|
||||||
|
-moz-animation: animate-stripes 2s linear infinite;
|
||||||
|
animation: animate-stripes 2s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLoadingAnimationD1, .textLoadingAnimationD2, .textLoadingAnimationD3 {
|
||||||
|
-webkit-animation: textLoadingAnimationKeyFrame 1s linear infinite 0s;
|
||||||
|
-moz-animation: textLoadingAnimationKeyFrame 1s linear infinite 0s;
|
||||||
|
animation: textLoadingAnimationKeyFrame 1s linear infinite 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLoadingAnimationD2 {
|
||||||
|
-webkit-animation-delay: 0.3s;
|
||||||
|
-moz-animation-delay: 0.3s;
|
||||||
|
animation-delay: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLoadingAnimationD3 {
|
||||||
|
-webkit-animation-delay: 0.6s;
|
||||||
|
-moz-animation-delay: 0.6s;
|
||||||
|
animation-delay: 0.6s;
|
||||||
|
}
|
||||||
177
dev/Styles/Compose.less
Normal file
177
dev/Styles/Compose.less
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
|
||||||
|
.b-compose {
|
||||||
|
|
||||||
|
&.modal {
|
||||||
|
|
||||||
|
width: 850px;
|
||||||
|
margin: 10px auto;
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-header-toolbar {
|
||||||
|
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
background-color: @rlMainDarkColor;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
background-color: #333;
|
||||||
|
background-color: rgba(0,0,0,0.8) !important;
|
||||||
|
|
||||||
|
.close {
|
||||||
|
color: #fff;
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.disable {
|
||||||
|
&.button-delete {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-save, .button-delete, .saved-text {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disable.button-delete {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-header {
|
||||||
|
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
background-color: #eee;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.e-identity {
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
&.multiply {
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 1px dashed #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-row {
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-delimiter-row {
|
||||||
|
line-height: 2px;
|
||||||
|
height: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-label {
|
||||||
|
text-align: right;
|
||||||
|
width: 1%;
|
||||||
|
min-width: 70px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-value {
|
||||||
|
|
||||||
|
padding: 2px 0px;
|
||||||
|
|
||||||
|
textarea, input[type="text"] {
|
||||||
|
width: 98%;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.select2-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-desc {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-appachments {
|
||||||
|
|
||||||
|
.b-attacment {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-attacment-in-process {
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 20px;
|
||||||
|
|
||||||
|
.uploading {
|
||||||
|
display: none;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.uploading .uploading {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-progress {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error .namedStr {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
float: left;
|
||||||
|
padding-right: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-attachment-button {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-attachment-place {
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
height: 120px;
|
||||||
|
border: 2px #777 dashed;
|
||||||
|
line-height: 119px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 300;
|
||||||
|
left: 20px;
|
||||||
|
right: 20px;
|
||||||
|
font-size: 24px;
|
||||||
|
|
||||||
|
&.drag-and-drop-over {
|
||||||
|
background: #777;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editorTextArea, .editorHtmlArea {
|
||||||
|
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
font-family: Arial, Verdana, Geneva, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: separate;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border: 0;
|
||||||
|
border-left: solid 2px #444;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin: 5px 0;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
303
dev/Styles/Contacts.less
Normal file
303
dev/Styles/Contacts.less
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
|
||||||
|
@contacts-popup-left-width: 250px;
|
||||||
|
|
||||||
|
.b-contacts-content {
|
||||||
|
|
||||||
|
&.modal {
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 900px;
|
||||||
|
min-height: 300px;
|
||||||
|
max-height: 700px;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
overflow: auto;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-header-toolbar {
|
||||||
|
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
background-color: @rlMainDarkColor;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
background-color: #333;
|
||||||
|
background-color: rgba(0,0,0,0.8) !important;
|
||||||
|
|
||||||
|
.close {
|
||||||
|
color: #fff;
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-new-message {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
.button-delete {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-list-toopbar {
|
||||||
|
padding: 0;
|
||||||
|
height: 45px;
|
||||||
|
text-align: center;
|
||||||
|
width: @contacts-popup-left-width;
|
||||||
|
.box-shadow(inset 0 -1px 0 #ccc);
|
||||||
|
|
||||||
|
.e-search {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-list-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 45px;
|
||||||
|
bottom: 60px;
|
||||||
|
left: 0;
|
||||||
|
width: @contacts-popup-left-width;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listClear {
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 13px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listEmptyList, .listEmptyListLoading, .listEmptySearchList {
|
||||||
|
color: #999;
|
||||||
|
text-align: center;
|
||||||
|
padding: 60px 10px;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hideContactListCheckbox {
|
||||||
|
.checkedParent, .checkboxCkeckAll {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.sidebarParent {
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-contact-foreach {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-contact-item {
|
||||||
|
position: relative;
|
||||||
|
height: 45px;
|
||||||
|
max-height: 45px;
|
||||||
|
line-height: 45px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
margin: 0px;
|
||||||
|
border: 0px solid transparent;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
.delimiter {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #999;
|
||||||
|
.opacity(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarParent {
|
||||||
|
display: inline-block;
|
||||||
|
width: 6px;
|
||||||
|
background-color: #eee;
|
||||||
|
float: left;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.deleted {
|
||||||
|
max-height: 0px;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkedParent {
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
padding: 0 8px 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nameParent {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: #333;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nameParent, .emailParent {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayName, .displayEmail {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayImg {
|
||||||
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
z-index: 101;
|
||||||
|
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: #69A8F5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 102;
|
||||||
|
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: #398CF2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-view-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 60px;
|
||||||
|
left: @contacts-popup-left-width;
|
||||||
|
right: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
background-color: #fff;
|
||||||
|
border-left: 1px solid #ddd;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-contact-view-desc {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding-top: 120px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-part {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.control-label {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-wrapper {
|
||||||
|
margin-left: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-row {
|
||||||
|
padding: 10px 0;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactEmptyValueClick, .contactValueClick, .contactValueInput {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 28px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactEmptyValueClick, .contactValueClick {
|
||||||
|
color: #ddd;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 5px 0 0 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactValueInput {
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactEmptyValueClick {
|
||||||
|
border-bottom: 1px dashed #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactValueClick {
|
||||||
|
color: #555;
|
||||||
|
border-bottom: 11px dashed transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactValueClick:hover {
|
||||||
|
color: #000;
|
||||||
|
border-bottom: 1px dashed #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contactValueInput {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasError {
|
||||||
|
.contactValueClick, .contactValueInput {
|
||||||
|
color: #ee5f5b;
|
||||||
|
border: 1px solid #ee5f5b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-save-contact {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-contact-item {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 55px;
|
||||||
|
max-height: 60px;
|
||||||
|
line-height: 22px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
margin: 0px;
|
||||||
|
border: 0px solid transparent;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
173
dev/Styles/Editor.less
Normal file
173
dev/Styles/Editor.less
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
.editorToolbar {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
line-height: 19px;
|
||||||
|
|
||||||
|
&.editorHideToolbar .editorToolbarButtom {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editorSwitcher {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editorToolbarButtom {
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 3px;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
border: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
|
||||||
|
cursor: default;
|
||||||
|
background: url('@{editor-sprite}');
|
||||||
|
|
||||||
|
&.bold { background-position: 0 0; }
|
||||||
|
&.italic { background-position: -16px 0; }
|
||||||
|
&.underline { background-position: -32px 0; }
|
||||||
|
&.strikethrough { background-position: -48px 0; }
|
||||||
|
&.link { background-position: -64px 0; }
|
||||||
|
&.unlink { background-position: -80px 0; }
|
||||||
|
&.orderedlist { background-position: -96px 0; }
|
||||||
|
&.unorderedlist { background-position: -112px 0; }
|
||||||
|
&.image { background-position: -128px 0; }
|
||||||
|
|
||||||
|
&.h1 { background-position: 0 -16px;}
|
||||||
|
&.h2 { background-position: -16px -16px;}
|
||||||
|
&.h3 { background-position: -32px -16px;}
|
||||||
|
&.h4 { background-position: -48px -16px;}
|
||||||
|
&.h5 { background-position: -64px -16px;}
|
||||||
|
&.h6 { background-position: -80px -16px;}
|
||||||
|
|
||||||
|
&.subscript { background-position: -96px -16px;}
|
||||||
|
&.superscript { background-position: -112px -16px;}
|
||||||
|
&.indent { background-position: -128px -16px;}
|
||||||
|
&.outdent { background-position: -144px -16px;}
|
||||||
|
&.horizontalrule { background-position: -160px -16px;}
|
||||||
|
&.p { background-position: -176px -16px;}
|
||||||
|
|
||||||
|
&.justifyleft { background-position: 0 -32px;}
|
||||||
|
&.justifycenter { background-position: -16px -32px;}
|
||||||
|
&.justifyright { background-position: -32px -32px;}
|
||||||
|
&.increasefontsize { background-position: -48px -32px;}
|
||||||
|
&.decreasefontsize { background-position: -64px -32px;}
|
||||||
|
&.forecolor { background-position: -80px -32px;}
|
||||||
|
&.backcolor { background-position: -80px -32px;}
|
||||||
|
&.removeformat { background-position: -144px 0;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.textAreaParent {
|
||||||
|
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
.editorHtmlArea {
|
||||||
|
|
||||||
|
.box-sizing(border-box);
|
||||||
|
|
||||||
|
border: 0px !important;
|
||||||
|
overflow: auto;
|
||||||
|
overflow-y: scroll;
|
||||||
|
font-family: arial, sans-serif;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 16px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
|
||||||
|
padding-left: 40px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style-type: disc !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
padding-left: 40px;
|
||||||
|
li {
|
||||||
|
list-style-type: decimal !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: solid 2px #444;
|
||||||
|
margin-left: 5px;
|
||||||
|
padding-left: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.editorDragOver {
|
||||||
|
background: #ffffef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editorTextArea {
|
||||||
|
.box-sizing(border-box);
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
border: 0px !important;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 16px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editorColorPicker {
|
||||||
|
|
||||||
|
.editorCpColors {
|
||||||
|
|
||||||
|
float: left;
|
||||||
|
margin: 0;
|
||||||
|
clear: both;
|
||||||
|
width: 128px;
|
||||||
|
border: 1px solid #000;
|
||||||
|
backgroud: #000;
|
||||||
|
|
||||||
|
.editorCpColor {
|
||||||
|
border: 1px solid #fff;
|
||||||
|
float: left;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editorSwitcher {
|
||||||
|
.g-ui-link;
|
||||||
|
.pull-right;
|
||||||
|
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editorFontStylePicker {
|
||||||
|
|
||||||
|
.editorFpFonts {
|
||||||
|
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #000;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
.editorFpFont {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
dev/Styles/FolderClear.less
Normal file
7
dev/Styles/FolderClear.less
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
.popups {
|
||||||
|
.b-folder-clear-content {
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
dev/Styles/FolderCreate.less
Normal file
7
dev/Styles/FolderCreate.less
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
.popups {
|
||||||
|
.b-folder-create-content {
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
141
dev/Styles/FolderList.less
Normal file
141
dev/Styles/FolderList.less
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
|
||||||
|
@folderItemPadding: 10px;
|
||||||
|
@subPadding: 15px;
|
||||||
|
|
||||||
|
.b-folders {
|
||||||
|
|
||||||
|
.b-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 30px;
|
||||||
|
padding: 10px 10px 0 @rlLowMargin;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px + @rlLowMargin;
|
||||||
|
bottom: @rlLowMargin + @rlBottomMargin;
|
||||||
|
// left: @rlLowMargin;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
// padding: 5px;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-list-delimiter {
|
||||||
|
margin: 10px;
|
||||||
|
border-top: 0px solid #000;
|
||||||
|
border-bottom: 1px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-item {
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.e-link {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
height: 34px;
|
||||||
|
line-height: 34px;
|
||||||
|
background-color: transparent;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: grey;
|
||||||
|
cursor: not-allowed;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
padding: 0;
|
||||||
|
padding-left: @folderItemPadding;
|
||||||
|
padding-right: @folderItemPadding;
|
||||||
|
|
||||||
|
outline: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&.selectable {
|
||||||
|
|
||||||
|
color: #000;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover, &.selected, &.droppableHover {
|
||||||
|
background-color: #555;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.system {
|
||||||
|
cursor: default;
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
display: none;
|
||||||
|
margin-top: 5px;
|
||||||
|
line-height: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.print-count {
|
||||||
|
font-weight: bold;
|
||||||
|
.count {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-collapsed-sign {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 22px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden.e-link {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-sub-folders.collapsed {
|
||||||
|
max-height: 0;
|
||||||
|
height: 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-folder-system-item {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-sub-folders .e-item .e-link {
|
||||||
|
padding-left: @subPadding * 1 + @folderItemPadding;
|
||||||
|
}
|
||||||
|
.b-sub-folders.unpaddig-folder .e-item .e-link {
|
||||||
|
padding-left: @folderItemPadding;
|
||||||
|
}
|
||||||
|
.b-sub-folders .b-sub-folders .e-item .e-link {
|
||||||
|
padding-left: @subPadding * 2 + @folderItemPadding;
|
||||||
|
}
|
||||||
|
.b-sub-folders.unpaddig-folder .b-sub-folders .e-item .e-link {
|
||||||
|
padding-left: @subPadding * 1 + @folderItemPadding;
|
||||||
|
}
|
||||||
|
.b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link {
|
||||||
|
padding-left: @subPadding * 3 + @folderItemPadding;
|
||||||
|
}
|
||||||
|
.b-sub-folders.unpaddig-folder .b-sub-folders .b-sub-folders .e-item .e-link {
|
||||||
|
padding-left: @subPadding * 2 + @folderItemPadding;
|
||||||
|
}
|
||||||
|
.b-sub-folders .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link {
|
||||||
|
padding-left: @subPadding * 4 + @folderItemPadding;
|
||||||
|
}
|
||||||
|
.b-sub-folders.unpaddig-folder .b-sub-folders .b-sub-folders .b-sub-folders .e-item .e-link {
|
||||||
|
padding-left: @subPadding * 3 + @folderItemPadding;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
dev/Styles/FolderSystem.less
Normal file
10
dev/Styles/FolderSystem.less
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
.popups {
|
||||||
|
.b-folder-system-content {
|
||||||
|
&.modal {
|
||||||
|
z-index: 1102;
|
||||||
|
}
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
dev/Styles/Identity.less
Normal file
12
dev/Styles/Identity.less
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
.popups {
|
||||||
|
.b-identity-content {
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textEmail {
|
||||||
|
margin-top: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
dev/Styles/Languages.less
Normal file
34
dev/Styles/Languages.less
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
.popups {
|
||||||
|
.b-languages-content {
|
||||||
|
|
||||||
|
&.modal {
|
||||||
|
z-index: 1103;
|
||||||
|
width: 520px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.exp {
|
||||||
|
width: 521px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 5px 15px;
|
||||||
|
margin: 2px 5px;
|
||||||
|
width: 200px;
|
||||||
|
background-color: #fff;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item:hover {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
123
dev/Styles/Layout.less
Normal file
123
dev/Styles/Layout.less
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
|
||||||
|
#rl-content {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-center {
|
||||||
|
.g-ui-absolute-reset;
|
||||||
|
min-width: 900px;
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-top {
|
||||||
|
.g-ui-absolute-reset;
|
||||||
|
bottom: auto;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-bottom {
|
||||||
|
.g-ui-absolute-reset;
|
||||||
|
top: auto;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-left {
|
||||||
|
.g-ui-absolute-reset;
|
||||||
|
|
||||||
|
right: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-right {
|
||||||
|
.g-ui-absolute-reset;
|
||||||
|
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-resizer-right {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 35%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-resizer-left {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 65%;
|
||||||
|
min-width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-top-resizer-right {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: @rlLeftWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-top-resizer-left {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: auto;
|
||||||
|
// width: @rlLeftWidth;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.mobile {
|
||||||
|
#rl-top-resizer-left {
|
||||||
|
width: @rlLeftWidth - 60;
|
||||||
|
}
|
||||||
|
#rl-top-resizer-right {
|
||||||
|
left: @rlLeftWidth - 60;
|
||||||
|
}
|
||||||
|
#rl-resizer-left {
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
#rl-resizer-right {
|
||||||
|
left: 350px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html.rl-no-preview-pane {
|
||||||
|
|
||||||
|
#rl-resizer-left {
|
||||||
|
right: @rlBottomMargin !important;
|
||||||
|
width: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-resizer-right {
|
||||||
|
left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-right .ui-resizable-handle {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-loading, #rl-loading-error {
|
||||||
|
position: absolute;
|
||||||
|
font: 30px Tahoma;
|
||||||
|
top: 50%;
|
||||||
|
width: 100%;
|
||||||
|
height: 65px;
|
||||||
|
margin: 0;
|
||||||
|
margin-top: -60px;
|
||||||
|
background-color: transparent;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center 50px;
|
||||||
|
background-image: url('@{rlLoaderBlack}');
|
||||||
|
text-align: center;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-loading-error {
|
||||||
|
background-image: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
96
dev/Styles/Login.less
Normal file
96
dev/Styles/Login.less
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
|
||||||
|
.rl-view-model {
|
||||||
|
&.RL-Login, &.RL-LoginNew, &.RL-AdminLogin {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-login-content {
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: -230px;
|
||||||
|
|
||||||
|
.loginFormWrapper {
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
width: 380px;
|
||||||
|
|
||||||
|
.loginForm {
|
||||||
|
background-color: #efefef;
|
||||||
|
text-align: left;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-label {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
padding: 40px 40px 10px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#recaptcha_image img {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
.border-radius(3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputLoginForm, .inputEmail, .inputLogin, .inputPassword {
|
||||||
|
font-size: 18px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signMeLabel {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-append .add-on {
|
||||||
|
position: relative;
|
||||||
|
height: 30px;
|
||||||
|
background: none;
|
||||||
|
margin-left: -35px;
|
||||||
|
z-index: 1000;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-append .add-on i {
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 29px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-group.error .add-on i {
|
||||||
|
color: #b94a48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonLogin {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loginAfter {
|
||||||
|
display: inline-block;
|
||||||
|
height: 90%;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flag-selector {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
dev/Styles/Main.less
Normal file
54
dev/Styles/Main.less
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
font-family: Arial, Verdana, Geneva, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #e3e3e3;
|
||||||
|
font-family: Arial, Verdana, Geneva, sans-serif;
|
||||||
|
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
option:disabled {
|
||||||
|
color: #aaa;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
body:before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
top: -10px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
z-index: 100;
|
||||||
|
.box-shadow(0px 0px 10px rgba(0,0,0,.6));
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
select:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.mobile * {
|
||||||
|
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||||
|
}
|
||||||
523
dev/Styles/MessageList.less
Normal file
523
dev/Styles/MessageList.less
Normal file
|
|
@ -0,0 +1,523 @@
|
||||||
|
html.rl-no-preview-pane {
|
||||||
|
|
||||||
|
.messageList.message-selected {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageList {
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 30px;
|
||||||
|
padding: 10px @rlMainBorderSize;
|
||||||
|
min-width: 280px;
|
||||||
|
z-index: 102;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 29px;
|
||||||
|
padding: 10px;
|
||||||
|
min-width: 300px;
|
||||||
|
z-index: 101;
|
||||||
|
|
||||||
|
background-color: #eee;
|
||||||
|
// #gradient > .vertical(#f4f4f4, #dfdfdf);
|
||||||
|
|
||||||
|
.border-bottom-right-radius(@rlMainBorderRadius);
|
||||||
|
.border-bottom-left-radius(@rlMainBorderRadius);
|
||||||
|
|
||||||
|
.e-quota {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
.e-quota:hover {
|
||||||
|
border-bottom: 1px dashed #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputSearch {
|
||||||
|
width: 258px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.buttonMoreSearch {
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-message-list-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: @rlBottomMargin;
|
||||||
|
|
||||||
|
border: @rlMainBorderSize solid @rlMainDarkColor;
|
||||||
|
|
||||||
|
.box-shadow(@rlMainShadow);
|
||||||
|
.border-radius(@rlMainBorderRadius);
|
||||||
|
z-index: 101;
|
||||||
|
}
|
||||||
|
|
||||||
|
.second-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 29px;
|
||||||
|
padding: 10px 8px 10px 11px;
|
||||||
|
min-width: 280px;
|
||||||
|
z-index: 101;
|
||||||
|
|
||||||
|
background-color: #eee;
|
||||||
|
// #gradient > .vertical(#f4f4f4, #dfdfdf);
|
||||||
|
|
||||||
|
.border-top-right-radius(@rlMainBorderRadius);
|
||||||
|
.border-top-left-radius(@rlMainBorderRadius);
|
||||||
|
|
||||||
|
.checkboxCkeckAll {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainDelimiter {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1px;
|
||||||
|
z-index: 101;
|
||||||
|
background-color: #bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbarDelimiter {
|
||||||
|
top: 49px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerDelimiter {
|
||||||
|
bottom: 49px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
bottom: 50px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 101;
|
||||||
|
min-width: 300px;
|
||||||
|
|
||||||
|
.box-sizing(border-box);
|
||||||
|
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listClear {
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listEmptyList, .listEmptyListLoading, .listDragOver, .listError, .listEmptySearchList {
|
||||||
|
color: #999;
|
||||||
|
text-align: center;
|
||||||
|
padding: 60px 10px;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 30px;
|
||||||
|
|
||||||
|
.e-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.listDragOver {
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listDragOver.viewAppendArea {
|
||||||
|
max-height: 120px;
|
||||||
|
padding: 30px 10px;
|
||||||
|
}
|
||||||
|
.listDragOver.dragOverEnter {
|
||||||
|
background-color: #e0fdda;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listError {
|
||||||
|
color: #DA4F49;
|
||||||
|
}
|
||||||
|
|
||||||
|
.listSearchDesc {
|
||||||
|
font-size: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delimiter {
|
||||||
|
display: block;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageListItem:last-child {
|
||||||
|
border-bottom: 1px solid #e5e5e5;
|
||||||
|
&.selected {
|
||||||
|
border-bottom: 1px solid #bfd5ef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullThreadsParent {
|
||||||
|
height: 25px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageListItem {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 52px;
|
||||||
|
max-height: 60px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 21px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
margin: 0px;
|
||||||
|
border: 0px solid transparent;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
|
||||||
|
.delimiter {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
height: 1px;
|
||||||
|
background-color: #999;
|
||||||
|
.opacity(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebarParent {
|
||||||
|
display: inline-block;
|
||||||
|
width: 6px;
|
||||||
|
background-color: #eee;
|
||||||
|
float: left;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line {
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line .wrapper {
|
||||||
|
line-height: 25px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.new {
|
||||||
|
max-height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.deleted {
|
||||||
|
max-height: 0px;
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkedParent {
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
margin-top: 11px;
|
||||||
|
padding: 0 8px 0 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line .checkedParent {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flagParent {
|
||||||
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
padding: 0 8px 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line .flagParent {
|
||||||
|
float: left;
|
||||||
|
padding: 0 8px 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateParent {
|
||||||
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 5px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line .dateParent {
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachmentParent {
|
||||||
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
margin: 2px 8px 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line .attachmentParent {
|
||||||
|
float: left;
|
||||||
|
margin: 0 5px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.senderParent {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.threadsCountParent {
|
||||||
|
display: inline;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #eee;
|
||||||
|
padding: 1px 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
.border-radius(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.threadsCountParent.lastSelected {
|
||||||
|
background-color: #999;
|
||||||
|
border-color: #999;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.threadsCountParent:hover {
|
||||||
|
border-color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line .senderParent {
|
||||||
|
display: inline-block;
|
||||||
|
text-overflow: none;
|
||||||
|
width: 200px;
|
||||||
|
float: left;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectParent {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.e-single-line .subjectParent {
|
||||||
|
}
|
||||||
|
|
||||||
|
.senderParent, .subjectParent, .dateParent {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectParent .emptySubjectText {
|
||||||
|
display: none;
|
||||||
|
font-style: italic;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.emptySubject .subjectParent {
|
||||||
|
.subject {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.emptySubjectText {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sender, .subject {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachment {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flagOff, .flagOn, .flagOnHalf {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flagOff {
|
||||||
|
.opacity(50);
|
||||||
|
&:hover {
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flagOn, .flagOnHalf {
|
||||||
|
display: none;
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replyFlag, .forwardFlag {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.answered .replyFlag {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.forwarded .forwardFlag {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.withAttachments .attachment {
|
||||||
|
display: inline-block;
|
||||||
|
color: #666;
|
||||||
|
text-shadow: 0px 1px 0px #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unseen {
|
||||||
|
background-color: #FFFFD9;
|
||||||
|
.sender, .subject {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: orange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hasUnseenSubMessage {
|
||||||
|
background-color: #FFFFD9;
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: lighten(orange, 30%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hasParentMessage {
|
||||||
|
background-color: #ecf0f1;
|
||||||
|
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: #bdc3c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unseen {
|
||||||
|
background-color: darken(#ecf0f1, 5%);
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: darken(#bdc3c7, 30%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: lighten(#398CF2, 10%) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: #DFEFFF;
|
||||||
|
z-index: 102;
|
||||||
|
|
||||||
|
.sidebarParent {
|
||||||
|
background-color: #398CF2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delimiter {
|
||||||
|
background-color: #398CF2;
|
||||||
|
.opacity(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .messageListItem .delimiter {
|
||||||
|
background-color: #398CF2;
|
||||||
|
.opacity(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hasFlaggedSubMessage {
|
||||||
|
.flagOff, .flagOn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.flagOnHalf {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.flagged {
|
||||||
|
.flagOff, .flagOnHalf {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.flagOn {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hideMessageListCheckbox {
|
||||||
|
.checkedParent, .checkboxCkeckAll {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.sidebarParent {
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagenator {
|
||||||
|
|
||||||
|
.page {
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
color: #999;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 24px;
|
||||||
|
padding: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover .pageNumber {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.current .pageNumber {
|
||||||
|
font-size: 28px;
|
||||||
|
color: #333;
|
||||||
|
border-bottom: 2px solid #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggablePlace {
|
||||||
|
z-index: 10002;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #333;
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
padding: 4px 10px;
|
||||||
|
min-width: 30px;
|
||||||
|
height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
381
dev/Styles/MessageView.less
Normal file
381
dev/Styles/MessageView.less
Normal file
|
|
@ -0,0 +1,381 @@
|
||||||
|
|
||||||
|
html.rl-no-preview-pane {
|
||||||
|
|
||||||
|
.messageView {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&.message-selected {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageView {
|
||||||
|
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 30px;
|
||||||
|
padding: 10px 0;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-content {
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
margin: 0;
|
||||||
|
top: 50px + @rlLowMargin;
|
||||||
|
bottom: @rlLowMargin + @rlBottomMargin;
|
||||||
|
right: @rlLowMargin;
|
||||||
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: @rlLowBorderSize solid @rlMainDarkColor;
|
||||||
|
border-left: 0px;
|
||||||
|
.border-top-right-radius(@rlLowBorderRadius);
|
||||||
|
.border-bottom-right-radius(@rlLowBorderRadius);
|
||||||
|
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
.b-message-view-desc {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding-top: 120px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-message-view-desc.error {
|
||||||
|
color: #DA4F49;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageItem {
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
overflow: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
.border-radius(@rlLowBorderRadius);
|
||||||
|
|
||||||
|
.emptySubjectText {
|
||||||
|
display: none;
|
||||||
|
font-style: italic;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.emptySubject .emptySubjectText {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonUp, .buttonUnFull, .buttonFull {
|
||||||
|
display: inline-block;
|
||||||
|
position: fixed;
|
||||||
|
right: 30px;
|
||||||
|
top: 90px;
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 30px;
|
||||||
|
background-color: transparent;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #333;
|
||||||
|
color: #333;
|
||||||
|
z-index: 2;
|
||||||
|
cursor: pointer;
|
||||||
|
.border-radius(5px);
|
||||||
|
.opacity(30);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.opacity(80);
|
||||||
|
border-color: #000;
|
||||||
|
background-color: #888;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonUp {
|
||||||
|
right: 70px;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonUnFull {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageItemHeader {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
border-top: 0px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.date {
|
||||||
|
}
|
||||||
|
|
||||||
|
.fromPic {
|
||||||
|
display: inline-block;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
float: left;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 0 5px 0 0;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 10px;
|
||||||
|
.box-sizing(border-box);
|
||||||
|
}
|
||||||
|
|
||||||
|
.subjectParent {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.senderParent {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageButtons {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.informationShort {
|
||||||
|
margin-left: 15px;
|
||||||
|
a {
|
||||||
|
.g-ui-link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.informationFull {
|
||||||
|
margin-top: 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
color: grey;
|
||||||
|
padding-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-loading {
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.showImages {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #eee;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachmentsPlace {
|
||||||
|
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.attachmentList {
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
.attachmentItem {
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
max-width: 170px;
|
||||||
|
min-width: 60px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
list-style: none;
|
||||||
|
line-height: 24px;
|
||||||
|
border: 2px solid grey;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 1px 1px 5px #ccc;
|
||||||
|
box-shadow: 1px 1px 5px rgba(0,0,0,0.1);
|
||||||
|
|
||||||
|
.border-radius(6px);
|
||||||
|
|
||||||
|
.attachmentIcon {
|
||||||
|
font-size: 23px;
|
||||||
|
width: 23px;
|
||||||
|
height: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachmentPreview {
|
||||||
|
color: #999;
|
||||||
|
margin: 0px 5px;
|
||||||
|
}
|
||||||
|
.attachmentPreview:hover {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rlBlockquoteSwitcher {
|
||||||
|
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #999;
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 14px;
|
||||||
|
line-height: 14px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 10px 0px;
|
||||||
|
|
||||||
|
.opacity(50);
|
||||||
|
&:hover {
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bodyText {
|
||||||
|
|
||||||
|
color: #000;
|
||||||
|
font-family: arial, sans-serif;
|
||||||
|
|
||||||
|
.b-text-part {
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: blue;
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:visited {
|
||||||
|
color: #609;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: separate;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 2px solid #000;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rl-bq-switcher.hidden-bq {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.rtl-text-part {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.html {
|
||||||
|
.mailso-body {
|
||||||
|
margin: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.plain {
|
||||||
|
|
||||||
|
padding: 15px;
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
font-family: arial, sans-serif;
|
||||||
|
background: #fff;
|
||||||
|
border: none;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 2px solid blue;
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote blockquote {
|
||||||
|
border-left: 2px solid green;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote blockquote blockquote {
|
||||||
|
border-left: 2px solid red;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html.rl-no-preview-pane .messageView {
|
||||||
|
.toolbar {
|
||||||
|
padding-left: @rlMainBorderSize;
|
||||||
|
}
|
||||||
|
.b-content {
|
||||||
|
top: 50px;
|
||||||
|
bottom: @rlBottomMargin;
|
||||||
|
right: @rlBottomMargin;
|
||||||
|
border: @rlMainBorderSize solid @rlMainDarkColor;
|
||||||
|
.box-shadow(@rlMainShadow);
|
||||||
|
.border-radius(@rlMainBorderRadius);
|
||||||
|
|
||||||
|
.buttonUp, .buttonUnFull, .buttonFull {
|
||||||
|
top: 70px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html.cssanimations.rl-anim .line-loading {
|
||||||
|
height: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html.rl-message-fullscreen {
|
||||||
|
|
||||||
|
#rl-left, #rl-bottom {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rl-right {
|
||||||
|
.RL-MailMessageList, .RL-SettingsPane, .RL-SystemDropDown, .RL-MailMessageView .messageView .toolbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageView .b-content {
|
||||||
|
position: fixed;
|
||||||
|
margin: 5px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 10000;
|
||||||
|
|
||||||
|
.buttonUp, .buttonUnFull {
|
||||||
|
display: inline-block;
|
||||||
|
top: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonFull {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
dev/Styles/Scroll.less
Normal file
29
dev/Styles/Scroll.less
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
height: 10px;
|
||||||
|
width: 10px;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-button {
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb, ::-webkit-scrollbar-track {
|
||||||
|
background-color: transparent;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border-width: 1px 1px 1px 6px;
|
||||||
|
min-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #bbb;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-corner {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
/**/
|
||||||
99
dev/Styles/Settings.less
Normal file
99
dev/Styles/Settings.less
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
|
||||||
|
.b-settins-left {
|
||||||
|
|
||||||
|
.b-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 34px;
|
||||||
|
padding: 8px 0 0 @rlLowMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px + @rlLowMargin + 10px;
|
||||||
|
bottom: @rlLowMargin;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-settings-menu {
|
||||||
|
|
||||||
|
.e-item {
|
||||||
|
overflow: hidden;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-link {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 29px;
|
||||||
|
font-size: 18px;
|
||||||
|
z-index: 1;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
background-color: transparent;
|
||||||
|
color: #888;
|
||||||
|
|
||||||
|
padding: 4px 10px;
|
||||||
|
|
||||||
|
outline: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-item.selectable .e-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-item.selectable {
|
||||||
|
&:hover .e-link, &.selected .e-link {
|
||||||
|
background-color: #555;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-settins-right {
|
||||||
|
|
||||||
|
.b-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 34px;
|
||||||
|
padding: 8px 5px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px + @rlLowMargin;
|
||||||
|
bottom: @rlLowMargin;
|
||||||
|
left: 0;
|
||||||
|
right: @rlLowMargin;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
background-color: #fff;
|
||||||
|
border: @rlMainBorderSize solid @rlMainDarkColor;
|
||||||
|
.box-shadow(@rlMainShadow);
|
||||||
|
.border-radius(@rlMainBorderRadius);
|
||||||
|
|
||||||
|
.content {
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-settings-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
55
dev/Styles/SettingsAccounts.less
Normal file
55
dev/Styles/SettingsAccounts.less
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
|
||||||
|
.b-settings-accounts {
|
||||||
|
|
||||||
|
.process-place {
|
||||||
|
text-align: center;
|
||||||
|
width: 600px;
|
||||||
|
padding: 14px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-table {
|
||||||
|
|
||||||
|
width: 600px;
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 4px 8px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-img {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-name {
|
||||||
|
display: inline-block;
|
||||||
|
word-break: break-all;
|
||||||
|
.box-sizing(border-box);
|
||||||
|
line-height: 22px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-item {
|
||||||
|
|
||||||
|
.button-delete {
|
||||||
|
margin-right: 15px;
|
||||||
|
margin-top: 5px;
|
||||||
|
visibility: hidden;
|
||||||
|
.opacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-access {
|
||||||
|
&.button-delete {
|
||||||
|
visibility: visible;
|
||||||
|
margin-right: 0;
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-account {
|
||||||
|
cursor: pointer;
|
||||||
|
.opacity(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
104
dev/Styles/SettingsFolders.less
Normal file
104
dev/Styles/SettingsFolders.less
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
|
||||||
|
.folderPaddingHelper(@i) {
|
||||||
|
(~".folder-padding.deep-@{i}") {
|
||||||
|
width: 15px * @i + 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-settings-folders {
|
||||||
|
|
||||||
|
&.ignore-folder-subscribe {
|
||||||
|
.subscribe-folder, .unsubscribe-folder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-place {
|
||||||
|
text-align: center;
|
||||||
|
width: 600px;
|
||||||
|
padding: 14px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folders-list-error {
|
||||||
|
width: 550px;
|
||||||
|
margin: 10px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-table {
|
||||||
|
|
||||||
|
width: 600px;
|
||||||
|
|
||||||
|
.e-action {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 4px 8px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-padding {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-name {
|
||||||
|
display: inline-block;
|
||||||
|
word-break: break-all;
|
||||||
|
.box-sizing(border-box);
|
||||||
|
margin-left: 7px;
|
||||||
|
line-height: 22px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-system-name {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 22px;
|
||||||
|
color: #999;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-name.can-be-edited:hover {
|
||||||
|
border-bottom: 1px dashed #333;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-name-input {
|
||||||
|
border-width: 1px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-item {
|
||||||
|
|
||||||
|
.button-delete {
|
||||||
|
margin-right: 15px;
|
||||||
|
margin-top: 5px;
|
||||||
|
visibility: hidden;
|
||||||
|
.opacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-access {
|
||||||
|
&.button-delete {
|
||||||
|
visibility: visible;
|
||||||
|
margin-right: 0;
|
||||||
|
.opacity(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-folder, .subscribe-folder, .unsubscribe-folder {
|
||||||
|
cursor: pointer;
|
||||||
|
.opacity(60);
|
||||||
|
}
|
||||||
|
|
||||||
|
.unsubscribe-folder {
|
||||||
|
.opacity(25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.folderPaddingHelper(1);
|
||||||
|
.folderPaddingHelper(2);
|
||||||
|
.folderPaddingHelper(3);
|
||||||
|
.folderPaddingHelper(4);
|
||||||
|
.folderPaddingHelper(5);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue