From 09334159c2ba6374d54fc11fe103b72666bb1e15 Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Thu, 4 Jun 2015 22:02:31 +0400 Subject: [PATCH] A lot small fixes --- _include.php | 9 + dev/App/Admin.js | 8 +- dev/App/User.js | 15 +- dev/External/ko.js | 46 +- dev/Model/Email.js | 43 ++ dev/Remote/User/Ajax.js | 4 +- dev/Stores/User/Message.js | 7 + dev/Styles/Ui.less | 1 - gulpfile.js | 7 +- package.json | 2 +- .../app/libraries/MailSo/Base/HtmlUtils.php | 262 ++++---- .../0.0.0/app/libraries/MailSo/Base/Utils.php | 22 +- .../v/0.0.0/app/libraries/MailSo/Config.php | 5 + .../0.0.0/app/libraries/MailSo/Log/Driver.php | 2 +- .../app/libraries/MailSo/Mail/MailClient.php | 67 +- .../app/libraries/MailSo/Mail/Message.php | 6 +- .../app/libraries/MailSo/Mime/Message.php | 2 +- .../0.0.0/app/libraries/RainLoop/Actions.php | 17 +- .../v/0.0.0/app/libraries/RainLoop/Api.php | 5 +- .../libraries/RainLoop/Common/PdoAbstract.php | 47 +- .../RainLoop/Config/AbstractConfig.php | 62 +- .../libraries/RainLoop/Config/Application.php | 4 +- .../app/libraries/RainLoop/Config/Plugin.php | 6 +- .../AddressBook/Classes/Property.php | 21 +- .../Providers/AddressBook/PdoAddressBook.php | 71 ++- .../Providers/Filters/SieveStorage.php | 6 +- rainloop/v/0.0.0/app/templates/Index.html | 15 +- rainloop/v/0.0.0/include.php | 34 +- vendors/progress.js/LICENSE | 20 + vendors/progress.js/README.md | 65 ++ vendors/progress.js/minified/progress.min.js | 11 + .../progress.js/minified/progressjs.min.css | 1 + .../minified/progressjs.rainloop.css | 62 ++ vendors/progress.js/package.json | 17 + vendors/progress.js/src/progress.js | 574 ++++++++++++++++++ vendors/progress.js/src/progressjs.css | 181 ++++++ vendors/simple-pace/simple-pace.js | 6 +- webpack.config.js | 2 +- 38 files changed, 1496 insertions(+), 239 deletions(-) create mode 100644 vendors/progress.js/LICENSE create mode 100644 vendors/progress.js/README.md create mode 100644 vendors/progress.js/minified/progress.min.js create mode 100644 vendors/progress.js/minified/progressjs.min.css create mode 100644 vendors/progress.js/minified/progressjs.rainloop.css create mode 100644 vendors/progress.js/package.json create mode 100644 vendors/progress.js/src/progress.js create mode 100644 vendors/progress.js/src/progressjs.css diff --git a/_include.php b/_include.php index eefd7e088..b615511b3 100644 --- a/_include.php +++ b/_include.php @@ -10,3 +10,12 @@ function __get_custom_data_full_path() return ''; return '/var/external-rainloop-data-folder/'; // custom data folder path } + +/** + * @return string + */ +function __get_additional_configuration_name() +{ + return ''; + return defined('APP_SITE') && 0 < strlen(APP_SITE) ? APP_SITE.'.ini' : ''; // additional configuration file name +} diff --git a/dev/App/Admin.js b/dev/App/Admin.js index cd4a42a9f..60ef8fe50 100644 --- a/dev/App/Admin.js +++ b/dev/App/Admin.js @@ -7,7 +7,7 @@ window = require('window'), _ = require('_'), ko = require('ko'), - SimplePace = require('SimplePace'), + progressJs = require('progressJs'), Enums = require('Common/Enums'), Utils = require('Common/Utils'), @@ -208,7 +208,7 @@ Remote.licensing(function (sResult, oData) { LicenseStore.licensingProcess(false); - + if (Enums.StorageResultType.Success === sResult && oData && oData.Result && Utils.isNormal(oData.Result['Expired'])) { LicenseStore.licenseValid(true); @@ -280,9 +280,9 @@ } } - if (SimplePace) + if (progressJs) { - SimplePace.set(100); + progressJs().end(); } }; diff --git a/dev/App/User.js b/dev/App/User.js index 5f68b0675..01a2881a7 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -7,7 +7,7 @@ window = require('window'), _ = require('_'), $ = require('$'), - SimplePace = require('SimplePace'), + progressJs = require('progressJs'), Tinycon = require('Tinycon'), Enums = require('Common/Enums'), @@ -255,6 +255,7 @@ { var self = this, + sTrashFolder = FolderStore.trashFolder(), sSpamFolder = FolderStore.spamFolder() ; @@ -262,11 +263,12 @@ var bSpam = sSpamFolder === oItem['To'], + bTrash = sTrashFolder === oItem['To'], bHam = !bSpam && sSpamFolder === oItem['From'] && Cache.getFolderInboxName() === oItem['To'] ; Remote.messagesMove(self.moveOrDeleteResponseHelper, oItem['From'], oItem['To'], oItem['Uid'], - bSpam ? 'SPAM' : (bHam ? 'HAM' : '')); + bSpam ? 'SPAM' : (bHam ? 'HAM' : ''), bSpam || bTrash); }); this.oMoveCache = {}; @@ -1305,9 +1307,9 @@ { kn.hideLoading(); - if (SimplePace) + if (progressJs) { - SimplePace.set(100); + progressJs().end(); } }; @@ -1332,10 +1334,9 @@ bTwitter = Settings.settingsGet('AllowTwitterSocial') ; - if (SimplePace) + if (progressJs) { - SimplePace.set(70); - SimplePace.sleep(); + progressJs().set(70); } Globals.leftPanelDisabled.subscribe(function (bValue) { diff --git a/dev/External/ko.js b/dev/External/ko.js index 131b5a8de..9fe17256c 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -811,7 +811,7 @@ 'parseOnBlur': true, 'allowDragAndDrop': true, 'focusCallback': fFocusCallback, - 'inputDelimiters': [',', ';'], + 'inputDelimiters': [',', ';', '\n'], 'autoCompleteSource': fAutoCompleteSource, // 'elementHook': function (oEl, oItem) { // if (oEl && oItem) @@ -821,23 +821,53 @@ // } // }, 'parseHook': function (aInput) { - return _.map(aInput, function (sInputValue) { + + var aResult = []; + + _.each(aInput, function (sInputValue) { var + aM = null, + aValues = [], sValue = Utils.trim(sInputValue), oEmail = null ; if ('' !== sValue) { - oEmail = new EmailModel(); - oEmail.mailsoParse(sValue); - return [oEmail.toLine(false), oEmail]; + aM = sValue.match(/[@]/g); + if (aM && 0 < aM.length) + { + sValue = sValue.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' '); + aValues = EmailModel.splitHelper(sValue, ';'); + + _.each(aValues, function (sV) { + + oEmail = new EmailModel(); + oEmail.mailsoParse(sV); + + if (oEmail.email) + { + aResult.push([oEmail.toLine(false), oEmail]); + } + else + { + aResult.push(['', null]); + } + }); + } + else + { + aResult.push([sInputValue, null]); + } + } + else + { + aResult.push([sInputValue, null]); } - - return [sValue, null]; - }); + + return aResult; }, 'change': _.bind(function (oEvent) { $oEl.data('EmailsTagsValue', oEvent.target.value); diff --git a/dev/Model/Email.js b/dev/Model/Email.js index 173ed2a80..9304c7d22 100644 --- a/dev/Model/Email.js +++ b/dev/Model/Email.js @@ -36,6 +36,49 @@ return oEmailModel.initByJson(oJsonEmail) ? oEmailModel : null; }; + /** + * @static + * @param {string} sLine + * @param {string=} sDelimiter = ';' + * @return {Array} + */ + EmailModel.splitHelper = function (sLine, sDelimiter) + { + sDelimiter = sDelimiter || ';'; + + sLine = sLine.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' '); + + var + iIndex = 0, + iLen = sLine.length, + bAt = false, + sChar = '', + sResult = '' + ; + + for (; iIndex < iLen; iIndex++) + { + sChar = sLine.charAt(iIndex); + switch (sChar) + { + case '@': + bAt = true; + break; + case ' ': + if (bAt) + { + bAt = false; + sResult += sDelimiter; + } + break; + } + + sResult += sChar; + } + + return sResult.split(sDelimiter); + }; + /** * @type {string} */ diff --git a/dev/Remote/User/Ajax.js b/dev/Remote/User/Ajax.js index e5ae6c606..b5a145b25 100644 --- a/dev/Remote/User/Ajax.js +++ b/dev/Remote/User/Ajax.js @@ -727,13 +727,15 @@ * @param {string} sToFolder * @param {Array} aUids * @param {string=} sLearning + * @param {boolean=} bMarkAsRead */ - RemoteUserAjax.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning) + RemoteUserAjax.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning, bMarkAsRead) { this.defaultRequest(fCallback, 'MessageMove', { 'FromFolder': sFolder, 'ToFolder': sToFolder, 'Uids': aUids.join(','), + 'MarkAsRead': bMarkAsRead ? '1' : '0', 'Learning': sLearning || '' }, null, '', ['MessageList']); }; diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js index 1c5de6b8a..9e7a3eed3 100644 --- a/dev/Stores/User/Message.js +++ b/dev/Stores/User/Message.js @@ -328,6 +328,8 @@ self = this, iUnseenCount = 0, oMessage = null, + sTrashFolder = FolderStore.trashFolder(), + sSpamFolder = FolderStore.spamFolder(), aMessageList = this.messageList(), oFromFolder = Cache.getFolderFromCacheList(sFromFolderFullNameRaw), oToFolder = '' === sToFolderFullNameRaw ? null : Cache.getFolderFromCacheList(sToFolderFullNameRaw || ''), @@ -359,6 +361,11 @@ if (oToFolder) { + if (sTrashFolder === oToFolder.fullNameRaw || sSpamFolder === oToFolder.fullNameRaw) + { + iUnseenCount = 0; + } + oToFolder.messageCountAll(oToFolder.messageCountAll() + aUidForRemove.length); if (0 < iUnseenCount) { diff --git a/dev/Styles/Ui.less b/dev/Styles/Ui.less index 09afa1136..53a821a38 100644 --- a/dev/Styles/Ui.less +++ b/dev/Styles/Ui.less @@ -239,7 +239,6 @@ html.cssanimations { .e-spinner .bounce2 { animation-delay: -0.16s; } - } @keyframes bouncedelay { diff --git a/gulpfile.js b/gulpfile.js index dc22784a1..51d9eb205 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -110,7 +110,8 @@ cfg.paths.css = { 'vendors/fontastic/styles.css', 'vendors/jquery-nanoscroller/nanoscroller.css', 'vendors/jquery-letterfx/jquery-letterfx.min.css', - 'vendors/simple-pace/styles.css', + 'vendors/progress.js/minified/progressjs.min.css', + 'vendors/progress.js/minified/progressjs.rainloop.css', 'vendors/inputosaurus/inputosaurus.css', 'vendors/opentip/opentip.css', 'vendors/photoswipe/photoswipe.css', @@ -127,7 +128,8 @@ cfg.paths.js = { src: [ 'vendors/json2.min.js', 'vendors/labjs/LAB.min.js', - 'vendors/simple-pace/simple-pace-1.0.min.js', + 'vendors/modernizr.js', + 'vendors/progress.js/minified/progress.min.js', 'vendors/rl/rl-1.5.min.js' ] }, @@ -153,7 +155,6 @@ cfg.paths.js = { libs: { name: 'libs.js', src: [ - 'vendors/modernizr.js', 'vendors/underscore/1.6.0/underscore-min.js', 'vendors/jquery/jquery-1.11.2.min.js', 'vendors/jquery-ui/js/jquery-ui-1.10.3.custom.min.js', diff --git a/package.json b/package.json index cb36f1de7..78156e8cd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "RainLoop", "title": "RainLoop Webmail", "version": "1.9.1", - "release": "334", + "release": "335", "description": "Simple, modern & fast web-based email client", "homepage": "http://rainloop.net", "main": "gulpfile.js", diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php index 96f9ac02d..bb9a2e419 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/HtmlUtils.php @@ -126,7 +126,7 @@ class HtmlUtils { $aRemoveTags = array( 'link', 'base', 'meta', 'title', 'script', 'bgsound', 'keygen', 'source', - 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset', 'video', 'audio' + 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset', 'video', 'audio', 'area', 'map' ); if ($bClearStyleAndHead) @@ -755,7 +755,8 @@ class HtmlUtils if ('' !== $sTagNameLower && \in_array($sTagNameLower, array('svg', 'head', 'link', 'base', 'meta', 'title', 'style', 'x-script', 'script', 'bgsound', 'keygen', 'source', - 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset', 'video', 'audio'))) + 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset', + 'video', 'audio', 'area', 'map'))) { if (isset($oElement->parentNode)) { @@ -867,7 +868,8 @@ class HtmlUtils foreach (array( 'id', 'class', 'contenteditable', 'designmode', 'formaction', - 'data-bind', 'data-reactid', 'xmlns', 'srcset' + 'data-bind', 'data-reactid', 'xmlns', 'srcset', + 'data-x-skip-style' ) as $sAttr) { @$oElement->removeAttribute($sAttr); @@ -903,27 +905,50 @@ class HtmlUtils $sAlt = $oElement->hasAttribute('alt') ? \trim($oElement->getAttribute('alt')) : ''; - $sH = $oElement->hasAttribute('height') - ? \trim($oElement->getAttribute('height')) : ''; - - $sW = $oElement->hasAttribute('width') - ? \trim($oElement->getAttribute('width')) : ''; - - $sStyles = $oElement->hasAttribute('style') - ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : ''; - - if ($oElement->hasAttribute('src')) + if ($oElement->hasAttribute('src') && '' === $sAlt) { - $aValues = array('4', '3', '2', '1', '0', '4px', '3px', '2px', '1px', '0px'); - if (('' === $sAlt && \in_array($sH, $aValues) && \in_array($sW, $aValues)) || - \preg_match('/(display:none|visibility:hidden)/i', \preg_replace('/[\s]+/', '', $sStyles))) + $aH = array( + 'email.microsoftemail.com/open', + 'github.com/notifications/beacon/', + 'mandrillapp.com/track/open', + 'list-manage.com/track/open' + ); + + $sH = $oElement->hasAttribute('height') + ? \trim($oElement->getAttribute('height')) : ''; + +// $sW = $oElement->hasAttribute('width') +// ? \trim($oElement->getAttribute('width')) : ''; + + $sStyles = $oElement->hasAttribute('style') + ? \preg_replace('/[\s]+/', '', \trim(\trim(\trim($oElement->getAttribute('style')), ';'))) : ''; + + $sSrc = \trim($oElement->getAttribute('src')); + + $bC = \in_array($sH, array('1', '0', '1px', '0px')) || + \preg_match('/(display:none|visibility:hidden|height:0|height:[01][a-z][a-z])/i', $sStyles); + + if (!$bC) { - if (isset($oElement->parentNode)) + $sSrcLower = \strtolower($sSrc); + foreach ($aH as $sLine) { - @$oElement->parentNode->removeChild($oElement); - continue; + if (false !== \strpos($sSrcLower, $sLine)) + { + $bC = true; + break; + } } } + + if ($bC) + { + $oElement->setAttribute('style', 'display:none'); + $oElement->setAttribute('data-x-skip-style', 'true'); + $oElement->setAttribute('data-x-hidden-src', $sSrc); + + $oElement->removeAttribute('src'); + } } } @@ -1002,12 +1027,14 @@ class HtmlUtils $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').\implode('; ', $aStyles)); } - if ($oElement->hasAttribute('style')) + if ($oElement->hasAttribute('style') && !$oElement->hasAttribute('data-x-skip-style')) { $oElement->setAttribute('style', \MailSo\Base\HtmlUtils::ClearStyle($oElement->getAttribute('style'), $oElement, $bHasExternals, $aFoundCIDs, $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter)); } + + $oElement->removeAttribute('data-x-skip-style'); } $sResult = $oDom->saveHTML(); @@ -1023,7 +1050,7 @@ class HtmlUtils $sResult = '
'.$sResult.'
'; $sResult = \str_replace(\MailSo\Base\HtmlUtils::$KOS, ':', $sResult); - $sResult = \preg_replace('/[\s]+/u', ' ', $sResult); + $sResult = \MailSo\Base\Utils::StripSpaces($sResult); return \trim($sResult); } @@ -1275,103 +1302,104 @@ class HtmlUtils */ public static function ConvertHtmlToPlain($sText) { - $sText = trim(stripslashes($sText)); - $sText = preg_replace('/[\s]+/', ' ', $sText); - $sText = preg_replace(array( - "/\r/", - "/[\n\t]+/", - '/]*>.*?<\/script>/i', - '/]*>.*?<\/style>/i', - '/]*>.*?<\/title>/i', - '/]*>(.+?)<\/h[123]>/i', - '/]*>(.+?)<\/h[456]>/i', - '/]*>/i', - '/]*>/i', - '/]*>(.+?)<\/b>/i', - '/]*>(.+?)<\/i>/i', - '/(]*>|<\/ul>)/i', - '/(]*>|<\/ol>)/i', - '/]*>/i', - '/]*href="([^"]+)"[^>]*>(.+?)<\/a>/i', - '/]*>/i', - '/(]*>|<\/table>)/i', - '/(]*>|<\/tr>)/i', - '/]*>(.+?)<\/td>/i', - '/]*>(.+?)<\/th>/i', - '/ /i', - '/"/i', - '/>/i', - '/</i', - '/&/i', - '/©/i', - '/™/i', - '/“/', - '/”/', - '/–/', - '/’/', - '/&/', - '/©/', - '/™/', - '/—/', - '/“/', - '/”/', - '/•/', - '/®/i', - '/•/i', - '/&[&;]+;/i', - '/'/', - '/ /' - ), array( - '', - ' ', - '', - '', - '', - "\n\n\\1\n\n", - "\n\n\\1\n\n", - "\n\n\t", - "\n", - '\\1', - '\\1', - "\n\n", - "\n\n", - "\n\t* ", - '\\2 (\\1)', - "\n------------------------------------\n", - "\n", - "\n", - "\t\\1\n", - "\t\\1\n", - ' ', - '"', - '>', - '<', - '&', - '(c)', - '(tm)', - '"', - '"', - '-', - "'", - '&', - '(c)', - '(tm)', - '--', - '"', - '"', - '*', - '(R)', - '*', - '', - '\'', - '' - ), $sText); + $sText = \trim(\stripslashes($sText)); + $sText = \MailSo\Base\Utils::StripSpaces($sText); - $sText = str_ireplace('
',"\n
", $sText); - $sText = strip_tags($sText, ''); - $sText = preg_replace("/\n\\s+\n/", "\n", $sText); - $sText = preg_replace("/[\n]{3,}/", "\n\n", $sText); + $sText = \preg_replace(array( + "/\r/", + "/[\n\t]+/", + '/]*>.*?<\/script>/i', + '/]*>.*?<\/style>/i', + '/]*>.*?<\/title>/i', + '/]*>(.+?)<\/h[123]>/i', + '/]*>(.+?)<\/h[456]>/i', + '/]*>/i', + '/]*>/i', + '/]*>(.+?)<\/b>/i', + '/]*>(.+?)<\/i>/i', + '/(]*>|<\/ul>)/i', + '/(]*>|<\/ol>)/i', + '/]*>/i', + '/]*href="([^"]+)"[^>]*>(.+?)<\/a>/i', + '/]*>/i', + '/(]*>|<\/table>)/i', + '/(]*>|<\/tr>)/i', + '/]*>(.+?)<\/td>/i', + '/]*>(.+?)<\/th>/i', + '/ /i', + '/"/i', + '/>/i', + '/</i', + '/&/i', + '/©/i', + '/™/i', + '/“/', + '/”/', + '/–/', + '/’/', + '/&/', + '/©/', + '/™/', + '/—/', + '/“/', + '/”/', + '/•/', + '/®/i', + '/•/i', + '/&[&;]+;/i', + '/'/', + '/ /' + ), array( + '', + ' ', + '', + '', + '', + "\n\n\\1\n\n", + "\n\n\\1\n\n", + "\n\n\t", + "\n", + '\\1', + '\\1', + "\n\n", + "\n\n", + "\n\t* ", + '\\2 (\\1)', + "\n------------------------------------\n", + "\n", + "\n", + "\t\\1\n", + "\t\\1\n", + ' ', + '"', + '>', + '<', + '&', + '(c)', + '(tm)', + '"', + '"', + '-', + "'", + '&', + '(c)', + '(tm)', + '--', + '"', + '"', + '*', + '(R)', + '*', + '', + '\'', + '' + ), $sText); - return trim($sText); + $sText = \str_ireplace('
',"\n
", $sText); + $sText = \strip_tags($sText, ''); + $sText = \preg_replace("/\n\\s+\n/", "\n", $sText); + $sText = \preg_replace("/[\n]{3,}/", "\n\n", $sText); + + return \trim($sText); } } diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php index 0f3a10d56..4fa3f1b4e 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Base/Utils.php @@ -550,6 +550,17 @@ END; return \MailSo\Base\Utils::IsAscii($sValue) ? \strtoupper($sValue) : $sValue; } + /** + * @param string $sValue + * + * @return string + */ + public static function StripSpaces($sValue) + { + return \MailSo\Base\Utils::Trim( + \preg_replace('/[\s]+/u', ' ', $sValue)); + } + /** * @param string $sValue * @@ -557,7 +568,7 @@ END; */ public static function IsUtf8($sValue) { - return (bool) ( \function_exists('mb_check_encoding') ? + return (bool) (\function_exists('mb_check_encoding') ? \mb_check_encoding($sValue, 'UTF-8') : \preg_match('//u', $sValue)); } @@ -1362,8 +1373,9 @@ END; */ public static function ClearFileName($sFileName) { - return \MailSo\Base\Utils::ClearNullBite(\preg_replace('/[\s]+/u', ' ', - \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sFileName))); + return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite( + \MailSo\Base\Utils::StripSpaces( + \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sFileName)))); } /** @@ -1373,8 +1385,8 @@ END; */ public static function ClearXss($sValue) { - return \MailSo\Base\Utils::ClearNullBite( - \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sValue)); + return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite( + \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sValue))); } /** diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Config.php b/rainloop/v/0.0.0/app/libraries/MailSo/Config.php index 6975e6432..add7b0a33 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Config.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Config.php @@ -56,6 +56,11 @@ class Config */ public static $LargeThreadLimit = 50; + /** + * @var bool + */ + public static $MessageAllHeaders = false; + /** * @var bool */ diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Log/Driver.php b/rainloop/v/0.0.0/app/libraries/MailSo/Log/Driver.php index cbb5312bc..755df58cb 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Log/Driver.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Log/Driver.php @@ -267,7 +267,7 @@ abstract class Driver foreach ($mDesc as &$sLine) { $sLine = \strtr($sLine, array("\r" => '\r', "\n" => '\n'.$this->sNewLine)); - $sLine = \rtrim($mDesc); + $sLine = \rtrim($sLine); } } else diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php index ffd9cb0eb..ea8665381 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php @@ -179,33 +179,41 @@ class MailClient */ private function getEnvelopeOrHeadersRequestString() { - return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK; + if (\MailSo\Config::$MessageAllHeaders) + { + return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK; + } -// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; + return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( + \MailSo\Mime\Enumerations\Header::RETURN_PATH, + \MailSo\Mime\Enumerations\Header::RECEIVED, + \MailSo\Mime\Enumerations\Header::MIME_VERSION, + \MailSo\Mime\Enumerations\Header::MESSAGE_ID, + \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, + \MailSo\Mime\Enumerations\Header::FROM_, + \MailSo\Mime\Enumerations\Header::TO_, + \MailSo\Mime\Enumerations\Header::CC, + \MailSo\Mime\Enumerations\Header::BCC, + \MailSo\Mime\Enumerations\Header::SENDER, + \MailSo\Mime\Enumerations\Header::REPLY_TO, + \MailSo\Mime\Enumerations\Header::DELIVERED_TO, + \MailSo\Mime\Enumerations\Header::IN_REPLY_TO, + \MailSo\Mime\Enumerations\Header::REFERENCES, + \MailSo\Mime\Enumerations\Header::DATE, + \MailSo\Mime\Enumerations\Header::SUBJECT, + \MailSo\Mime\Enumerations\Header::SENSITIVITY, + \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY, + \MailSo\Mime\Enumerations\Header::IMPORTANCE, + \MailSo\Mime\Enumerations\Header::X_PRIORITY, + \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO, + \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO, + \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO, + \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO, + \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS, + \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS, + ), true); // -// return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array( -// \MailSo\Mime\Enumerations\Header::RETURN_PATH, -// \MailSo\Mime\Enumerations\Header::RECEIVED, -// \MailSo\Mime\Enumerations\Header::MIME_VERSION, -// \MailSo\Mime\Enumerations\Header::MESSAGE_ID, -// \MailSo\Mime\Enumerations\Header::FROM_, -// \MailSo\Mime\Enumerations\Header::TO_, -// \MailSo\Mime\Enumerations\Header::CC, -// \MailSo\Mime\Enumerations\Header::BCC, -// \MailSo\Mime\Enumerations\Header::SENDER, -// \MailSo\Mime\Enumerations\Header::REPLY_TO, -// \MailSo\Mime\Enumerations\Header::IN_REPLY_TO, -// \MailSo\Mime\Enumerations\Header::DATE, -// \MailSo\Mime\Enumerations\Header::SUBJECT, -// \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY, -// \MailSo\Mime\Enumerations\Header::IMPORTANCE, -// \MailSo\Mime\Enumerations\Header::X_PRIORITY, -// \MailSo\Mime\Enumerations\Header::CONTENT_TYPE, -// \MailSo\Mime\Enumerations\Header::REFERENCES, -// \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO, -// \MailSo\Mime\Enumerations\Header::RECEIVED_SPF, -// \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS, -// ), true); +// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE; } /** @@ -1032,7 +1040,7 @@ class MailClient $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize'; - $sSearch = \trim(\preg_replace('/[\s]+/', ' ', $sSearch)); + $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch); $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch)); $mMatch = array(); @@ -1079,7 +1087,7 @@ class MailClient $sSearch = \str_replace($sToken, '', $sSearch); } - $sSearch = \trim(\preg_replace('/[\s]+/', ' ', $sSearch)); + $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch); } foreach ($mMatch[1] as $iIndex => $sName) @@ -1353,7 +1361,7 @@ class MailClient if ('' !== \trim($sMainText)) { - $sMainText = \trim(\trim(preg_replace('/[\s]+/', ' ', $sMainText)), '"'); + $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"'); if ($bIsGmail) { $sGmailRawSearch .= ' '.$sMainText; @@ -1690,7 +1698,8 @@ class MailClient \MailSo\Imap\Enumerations\FetchType::INTERNALDATE, \MailSo\Imap\Enumerations\FetchType::FLAGS, \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE, - $bSimple ? $this->getEnvelopeOrHeadersRequestStringForSimpleList() : + $bSimple ? + $this->getEnvelopeOrHeadersRequestStringForSimpleList() : $this->getEnvelopeOrHeadersRequestString() ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid); diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php index dd8c2cf93..0fe6d7551 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mail/Message.php @@ -620,9 +620,9 @@ class Message $this->oDeliveredTo = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::DELIVERED_TO, $bCharsetAutoDetect); $this->sInReplyTo = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::IN_REPLY_TO); - $this->sReferences = \trim(\preg_replace('/[\s]+/', ' ', - $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::REFERENCES))); - + $this->sReferences = \MailSo\Base\Utils::StripSpaces( + $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::REFERENCES)); + $sHeaderDate = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::DATE); $this->sHeaderDate = $sHeaderDate; $this->iHeaderTimeStampInUTC = \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($sHeaderDate); diff --git a/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php index 106b3e6ae..44dfa80b4 100644 --- a/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php +++ b/rainloop/v/0.0.0/app/libraries/MailSo/Mime/Message.php @@ -257,7 +257,7 @@ class Message public function SetReferences($sReferences) { $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::REFERENCES] = - \trim(\preg_replace('/[\s]+/', ' ', $sReferences)); + \MailSo\Base\Utils::StripSpaces($sReferences); return $this; } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php index ba4128cac..d521c82a3 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -4127,7 +4127,7 @@ class Actions */ private function rainLoopRepo() { - $sUrl = APP_REP_PATH; + $sUrl = APP_REPOSITORY_PATH; if ('' !== $sUrl) { $sUrl = rtrim($sUrl, '\\/').'/'; @@ -7190,12 +7190,25 @@ class Actions $sFromFolder = $this->GetActionParam('FromFolder', ''); $sToFolder = $this->GetActionParam('ToFolder', ''); $aUids = \explode(',', (string) $this->GetActionParam('Uids', '')); + $bMarkAsRead = '1' === (string) $this->GetActionParam('MarkAsRead', '0'); $aFilteredUids = \array_filter($aUids, function (&$mUid) { $mUid = (int) \trim($mUid); return 0 < $mUid; }); + if ($bMarkAsRead) + { + try + { + $this->MailClient()->MessageSetSeen($sFromFolder, $aFilteredUids, true, true); + } + catch (\Exception $oException) + { + unset($oException); + } + } + try { $this->MailClient()->MessageMove($sFromFolder, $sToFolder, $aFilteredUids, true, @@ -7259,7 +7272,7 @@ class Actions public function MainClearFileName($sFileName, $sContentType, $sMimeIndex, $iMaxLength = 250) { $sFileName = 0 === \strlen($sFileName) ? \preg_replace('/[^a-zA-Z0-9]/', '.', (empty($sMimeIndex) ? '' : $sMimeIndex.'.').$sContentType) : $sFileName; - $sClearedFileName = \preg_replace('/[\s]+/', ' ', \preg_replace('/[\.]+/', '.', $sFileName)); + $sClearedFileName = \MailSo\Base\Utils::StripSpaces(\preg_replace('/[\.]+/', '.', $sFileName)); $sExt = \MailSo\Base\Utils::GetFileExtension($sClearedFileName); if (10 < $iMaxLength && $iMaxLength < \strlen($sClearedFileName) - \strlen($sExt)) diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php index 67ba60049..d3b5eefb3 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php @@ -32,7 +32,7 @@ class Api if ($bOne) { \RainLoop\Api::SetupDefaultMailSoConfig(); - + $bOne = \RainLoop\Api::RunResult(); } } @@ -95,6 +95,9 @@ class Api \MailSo\Config::$MessageListPermanentFilter = \trim(\RainLoop\Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')); + \MailSo\Config::$MessageAllHeaders = + !!\RainLoop\Api::Config()->Get('labs', 'imap_message_all_headers', false); + \MailSo\Config::$LargeThreadLimit = (int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 50); diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php index 36dac7f96..13c5d9e59 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Common/PdoAbstract.php @@ -14,6 +14,11 @@ abstract class PdoAbstract */ protected $bExplain = false; + /** + * @var bool + */ + protected $bSqliteCollate = true; + /** * @var \MailSo\Log\Logger */ @@ -48,6 +53,18 @@ abstract class PdoAbstract return array('', '', '', ''); } + /** + * @param string $sStr1 + * @param string $sStr2 + * + * @return int + */ + public function sqliteNoCaseCollationHelper($sStr1, $sStr2) + { + $this->oLogger->WriteDump(array($sStr1, $sStr2)); + return \strcmp(\mb_strtoupper($sStr1, 'UTF-8'), \mb_strtoupper($sStr2, 'UTF-8')); + } + /** * @return \PDO * @@ -67,6 +84,7 @@ abstract class PdoAbstract $sType = $sDsn = $sDbLogin = $sDbPassword = ''; list($sType, $sDsn, $sDbLogin, $sDbPassword) = $this->getPdoAccessData(); + if (!\in_array($sType, array('mysql', 'sqlite', 'pgsql'))) { throw new \Exception('Unknown PDO SQL connection type'); @@ -82,15 +100,28 @@ abstract class PdoAbstract $oPdo = false; try { +// $bCaseFunc = false; $oPdo = @new \PDO($sDsn, $sDbLogin, $sDbPassword); if ($oPdo) { + $sPdoType = $oPdo->getAttribute(\PDO::ATTR_DRIVER_NAME); $oPdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - if ('mysql' === $sType && 'mysql' === $oPdo->getAttribute(\PDO::ATTR_DRIVER_NAME)) + + if ('mysql' === $sType && 'mysql' === $sPdoType) { $oPdo->exec('SET NAMES utf8 COLLATE utf8_general_ci'); // $oPdo->exec('SET NAMES utf8'); } +// else if ('sqlite' === $sType && 'sqlite' === $sPdoType && $this->bSqliteCollate) +// { +// if (\method_exists($oPdo, 'sqliteCreateCollation') && \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_strtoupper')) +// { +// $oPdo->sqliteCreateCollation('SQLITE_NOCASE_UTF8', array($this, 'sqliteNoCaseCollationHelper')); +// $bCaseFunc = true; +// } +// } +// +// $this->oLogger->Write('PDO:'.$sPdoType.($bCaseFunc ? '/SQLITE_NOCASE_UTF8' : '')); } } catch (\Exception $oException) @@ -156,10 +187,11 @@ abstract class PdoAbstract * @param string $sSql * @param array $aParams * @param bool $bMultiplyParams = false + * @param bool $bLogParams = false * * @return \PDOStatement|null */ - protected function prepareAndExecute($sSql, $aParams = array(), $bMultiplyParams = false) + protected function prepareAndExecute($sSql, $aParams = array(), $bMultiplyParams = false, $bLogParams = false) { if ($this->bExplain && !$bMultiplyParams) { @@ -172,16 +204,27 @@ abstract class PdoAbstract $oStmt = $this->getPDO()->prepare($sSql); if ($oStmt) { + $aLogs = array(); $aRootParams = $bMultiplyParams ? $aParams : array($aParams); foreach ($aRootParams as $aSubParams) { foreach ($aSubParams as $sName => $aValue) { + if ($bLogParams) + { + $aLogs[$sName] = $aValue[0]; + } + $oStmt->bindValue($sName, $aValue[0], $aValue[1]); } $mResult = $oStmt->execute() && !$bMultiplyParams ? $oStmt : null; } + + if ($bLogParams && $aLogs) + { + $this->writeLog('Params: '.@\json_encode($aLogs, \defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0)); + } } return $mResult; diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php index 6403e7940..43d589751 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php @@ -9,6 +9,11 @@ abstract class AbstractConfig */ private $sFile; + /** + * @var string + */ + private $sAdditionalFile; + /** * @var array */ @@ -27,12 +32,19 @@ abstract class AbstractConfig /** * @param string $sFileName * @param string $sFileHeader = '' + * @param string $sAdditionalFileName = '' * * @return void */ - public function __construct($sFileName, $sFileHeader = '') + public function __construct($sFileName, $sFileHeader = '', $sAdditionalFileName = '') { - $this->sFile = \APP_PRIVATE_DATA.'configs/'.$sFileName; + $this->sFile = \APP_PRIVATE_DATA.'configs/'.\trim($sFileName); + + $sAdditionalFileName = \trim($sAdditionalFileName); + $this->sAdditionalFile = \APP_PRIVATE_DATA.'configs/'.$sAdditionalFileName; + $this->sAdditionalFile = 0 < \strlen($sAdditionalFileName) && + \file_exists($this->sAdditionalFile) ? $this->sAdditionalFile : ''; + $this->sFileHeader = $sFileHeader; $this->aData = $this->defaultValues(); @@ -109,7 +121,7 @@ abstract class AbstractConfig */ private function cacheKey() { - return 'config:'.\sha1($this->sFile).':'; + return 'config:'.\sha1($this->sFile).':'.\sha1($this->sAdditionalFile).':'; } /** @@ -120,12 +132,17 @@ abstract class AbstractConfig if ($this->bUseApcCache) { $iMTime = @\filemtime($this->sFile); - if (\is_int($iMTime) && 0 < $iMTime) + $iMTime = \is_int($iMTime) && 0 < $iMTime ? $iMTime : 0; + + $iATime = $this->sAdditionalFile ? @\filemtime($this->sAdditionalFile) : 0; + $iATime = \is_int($iATime) && 0 < $iATime ? $iATime : 0; + + if (0 < $iMTime) { $sKey = $this->cacheKey(); - $iTime = \apc_fetch($sKey.'time'); - if ($iTime && $iMTime === (int) $iTime) + $sTimeHash = \apc_fetch($sKey.'time'); + if ($sTimeHash && $sTimeHash === \md5($iMTime.'/'.$iATime)) { $aFetchData = \apc_fetch($sKey.'data'); if (\is_array($aFetchData)) @@ -148,11 +165,16 @@ abstract class AbstractConfig if ($this->bUseApcCache) { $iMTime = @\filemtime($this->sFile); - if (\is_int($iMTime) && 0 < $iMTime) + $iMTime = \is_int($iMTime) && 0 < $iMTime ? $iMTime : 0; + + $iATime = $this->sAdditionalFile ? @\filemtime($this->sAdditionalFile) : 0; + $iATime = \is_int($iATime) && 0 < $iATime ? $iATime : 0; + + if (0 < $iMTime) { $sKey = $this->cacheKey(); - \apc_store($sKey.'time', $iMTime); + \apc_store($sKey.'time', \md5($iMTime.'/'.$iATime)); \apc_store($sKey.'data', $this->aData); return true; @@ -193,7 +215,7 @@ abstract class AbstractConfig } $aData = \RainLoop\Utils::CustomParseIniFile($this->sFile, true); - if (\is_array($aData) && 0 < count($aData)) + if (\is_array($aData) && 0 < \count($aData)) { foreach ($aData as $sSectionKey => $aSectionValue) { @@ -206,6 +228,28 @@ abstract class AbstractConfig } } + unset($aData); + + if (\file_exists($this->sAdditionalFile) && \is_readable($this->sAdditionalFile)) + { + $aSubData = \RainLoop\Utils::CustomParseIniFile($this->sAdditionalFile, true); + if (\is_array($aSubData) && 0 < \count($aSubData)) + { + foreach ($aSubData as $sSectionKey => $aSectionValue) + { + if (\is_array($aSectionValue)) + { + foreach ($aSectionValue as $sParamKey => $mParamValue) + { + $this->Set($sSectionKey, $sParamKey, $mParamValue); + } + } + } + } + + unset($aSubData); + } + $this->storeDataToCache(); return true; diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php index afda4c8f8..a910dc635 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -11,7 +11,8 @@ class Application extends \RainLoop\Config\AbstractConfig { parent::__construct('application.ini', '; RainLoop Webmail configuration file -; Please don\'t add custom parameters here, those will be overwritten'); +; Please don\'t add custom parameters here, those will be overwritten', + defined('APP_ADDITIONAL_CONFIGURATION_NAME') ? APP_ADDITIONAL_CONFIGURATION_NAME : ''); } /** @@ -321,6 +322,7 @@ Enables caching in the system'), 'imap_message_list_count_limit_trigger' => array(0), 'imap_message_list_date_filter' => array(0), 'imap_message_list_permanent_filter' => array(''), + 'imap_message_all_headers' => array(false), 'imap_large_thread_limit' => array(50), 'imap_folder_list_limit' => array(200), 'imap_show_login_alert' => array(true), diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Plugin.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Plugin.php index 294823fcb..ee7bb5caa 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Plugin.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Plugin.php @@ -25,7 +25,7 @@ class Plugin extends \RainLoop\Config\AbstractConfig */ private function convertConfigMap($aMap) { - if (0 < count($aMap)) + if (0 < \count($aMap)) { $aResultMap = array(); foreach ($aMap as /* @var $oProperty \RainLoop\Plugins\Property */ $oProperty) @@ -33,12 +33,12 @@ class Plugin extends \RainLoop\Config\AbstractConfig if ($oProperty) { $mValue = $oProperty->DefaultValue(); - $sValue = is_array($mValue) && isset($mValue[0]) ? $mValue[0] : $mValue; + $sValue = \is_array($mValue) && isset($mValue[0]) ? $mValue[0] : $mValue; $aResultMap[$oProperty->Name()] = array($sValue, ''); } } - if (0 < count($aResultMap)) + if (0 < \count($aResultMap)) { return array( 'plugin' => $aResultMap diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php index 8356d5e8d..c433f533c 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Property.php @@ -26,6 +26,11 @@ class Property */ public $Value; + /** + * @var string + */ + public $ValueLower; + /** * @var string */ @@ -54,6 +59,7 @@ class Property $this->TypeStr = ''; $this->Value = ''; + $this->ValueLower = ''; $this->ValueCustom = ''; $this->Frec = 0; @@ -120,6 +126,7 @@ class Property $this->Value = \trim($this->Value); $this->ValueCustom = \trim($this->ValueCustom); $this->TypeStr = \trim($this->TypeStr); + $this->ValueLower = ''; if (0 < \strlen($this->Value)) { @@ -131,16 +138,22 @@ class Property if ($this->IsName()) { - $this->Value = \preg_replace('/[\s]+/u', ' ', $this->Value); + $this->Value = \MailSo\Base\Utils::StripSpaces($this->Value); } - // phones clear value for searching + // lower value for searching + if (\MailSo\Base\Utils::FunctionExistsAndEnabled('mb_strtolower')) + { + $this->ValueLower = (string) @\mb_strtolower($this->Value, 'UTF-8'); + } + + // phone value for searching if ($this->IsPhone()) { - $sPhone = $this->Value; + $sPhone = \trim($this->Value); $sPhone = \preg_replace('/^[+]+/', '', $sPhone); $sPhone = \preg_replace('/[^\d]/', '', $sPhone); - $this->ValueCustom = $sPhone; + $this->ValueCustom = \trim($sPhone); } } } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php index db32a6b9e..e46eac87e 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php @@ -957,6 +957,7 @@ class PdoAddressBook ':prop_type' => array($oProp->Type, \PDO::PARAM_INT), ':prop_type_str' => array($oProp->TypeStr, \PDO::PARAM_STR), ':prop_value' => array($oProp->Value, \PDO::PARAM_STR), + ':prop_value_lower' => array($oProp->ValueLower, \PDO::PARAM_STR), ':prop_value_custom' => array($oProp->ValueCustom, \PDO::PARAM_STR), ':prop_frec' => array($iFreq, \PDO::PARAM_INT), ); @@ -965,9 +966,9 @@ class PdoAddressBook if (0 < \count($aParams)) { $sSql = 'INSERT INTO rainloop_ab_properties '. - '( id_contact, id_user, prop_type, prop_type_str, prop_value, prop_value_custom, prop_frec)'. + '( id_contact, id_user, prop_type, prop_type_str, prop_value, prop_value_lower, prop_value_custom, prop_frec)'. ' VALUES '. - '(:id_contact, :id_user, :prop_type, :prop_type_str, :prop_value, :prop_value_custom, :prop_frec)'; + '(:id_contact, :id_user, :prop_type, :prop_type_str, :prop_value, :prop_value_lower, :prop_value_custom, :prop_frec)'; $this->prepareAndExecute($sSql, $aParams, true); } @@ -1072,6 +1073,7 @@ class PdoAddressBook if (0 < \strlen($sSearch)) { $sCustomSearch = $this->specialConvertSearchValueCustomPhone($sSearch); + $sLowerSearch = $this->specialConvertSearchValueLower($sSearch, '='); $sSearchTypes = \implode(',', array( PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME, PropertyType::NICK_NAME, @@ -1079,8 +1081,10 @@ class PdoAddressBook )); $sSql = 'SELECT id_user, id_prop, id_contact FROM rainloop_ab_properties '. - 'WHERE (id_user = :id_user) AND prop_type IN ('.$sSearchTypes.') AND (prop_value LIKE :search ESCAPE \'=\''. - (0 < \strlen($sCustomSearch) ? ' OR (prop_type = '.PropertyType::PHONE.' AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : ''). + 'WHERE (id_user = :id_user) AND prop_type IN ('.$sSearchTypes.') AND ('. + 'prop_value LIKE :search ESCAPE \'=\''. +(0 < \strlen($sLowerSearch) ? ' OR (prop_value_lower <> \'\' AND prop_value_lower LIKE :search_lower ESCAPE \'=\')' : ''). +(0 < \strlen($sCustomSearch) ? ' OR (prop_type = '.PropertyType::PHONE.' AND prop_value_custom <> \'\' AND prop_value_custom LIKE :search_custom_phone)' : ''). ') GROUP BY id_contact, id_prop'; $aParams = array( @@ -1088,12 +1092,17 @@ class PdoAddressBook ':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR) ); + if (0 < \strlen($sLowerSearch)) + { + $aParams[':search_lower'] = array($sLowerSearch, \PDO::PARAM_STR); + } + if (0 < \strlen($sCustomSearch)) { $aParams[':search_custom_phone'] = array($sCustomSearch, \PDO::PARAM_STR); } - $oStmt = $this->prepareAndExecute($sSql, $aParams); + $oStmt = $this->prepareAndExecute($sSql, $aParams, false, true); if ($oStmt) { $aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC); @@ -1211,6 +1220,7 @@ class PdoAddressBook $oProperty->Type = (int) $aItem['prop_type']; $oProperty->TypeStr = isset($aItem['prop_type_str']) ? (string) $aItem['prop_type_str'] : ''; $oProperty->Value = (string) $aItem['prop_value']; + $oProperty->ValueLower = isset($aItem['prop_value_lower']) ? (string) $aItem['prop_value_lower'] : ''; $oProperty->ValueCustom = isset($aItem['prop_value_custom']) ? (string) $aItem['prop_value_custom'] : ''; $oProperty->Frec = isset($aItem['prop_frec']) ? (int) $aItem['prop_frec'] : 0; @@ -1320,6 +1330,7 @@ class PdoAddressBook $oProperty->Type = (int) $aItem['prop_type']; $oProperty->TypeStr = isset($aItem['prop_type_str']) ? (string) $aItem['prop_type_str'] : ''; $oProperty->Value = (string) $aItem['prop_value']; + $oProperty->ValueLower = isset($aItem['prop_value_lower']) ? (string) $aItem['prop_value_lower'] : ''; $oProperty->ValueCustom = isset($aItem['prop_value_custom']) ? (string) $aItem['prop_value_custom'] : ''; $oProperty->Frec = isset($aItem['prop_frec']) ? (int) $aItem['prop_frec'] : 0; @@ -1364,8 +1375,14 @@ class PdoAddressBook PropertyType::EMAIl, PropertyType::FIRST_NAME, PropertyType::LAST_NAME, PropertyType::NICK_NAME )); + $sLowerSearch = $this->specialConvertSearchValueLower($sSearch); + $sSql = 'SELECT id_contact, id_prop, prop_type, prop_value FROM rainloop_ab_properties '. - 'WHERE (id_user = :id_user) AND prop_type IN ('.$sTypes.') AND prop_value LIKE :search ESCAPE \'=\''; + 'WHERE (id_user = :id_user) AND prop_type IN ('.$sTypes.') AND ('. + 'prop_value LIKE :search ESCAPE \'=\''. +(0 < \strlen($sLowerSearch) ? ' OR (prop_value_lower <> \'\' AND prop_value_lower LIKE :search_lower ESCAPE \'=\')' : ''). + ')' + ; $aParams = array( ':id_user' => array($iUserID, \PDO::PARAM_INT), @@ -1373,6 +1390,11 @@ class PdoAddressBook ':search' => array($this->specialConvertSearchValue($sSearch, '='), \PDO::PARAM_STR) ); + if (0 < \strlen($sLowerSearch)) + { + $aParams[':search_lower'] = array($sLowerSearch, \PDO::PARAM_STR); + } + $sSql .= ' ORDER BY prop_frec DESC'; $sSql .= ' LIMIT :limit'; @@ -1547,7 +1569,7 @@ class PdoAddressBook { $oResult = \MailSo\Mime\Email::Parse(\trim($mItem)); } - catch (\Exception $oException) {} + catch (\Exception $oException) { unset($oException); } return $oResult; }, $aEmails); @@ -1837,7 +1859,7 @@ SQLITEINITIAL; break; } - if (0 < strlen($sInitial)) + if (0 < \strlen($sInitial)) { $aList = \explode(';', \trim($sInitial)); foreach ($aList as $sV) @@ -1869,17 +1891,26 @@ SQLITEINITIAL; { case 'mysql': $mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array( - 1 => $this->getInitialTablesArray($this->sDsnType) + 1 => $this->getInitialTablesArray($this->sDsnType), + 2 => array( +'ALTER TABLE rainloop_ab_properties ADD prop_value_lower varchar(255) NOT NULL DEFAULT \'\' AFTER prop_value_custom;' + ) )); break; case 'pgsql': $mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array( - 1 => $this->getInitialTablesArray($this->sDsnType) + 1 => $this->getInitialTablesArray($this->sDsnType), + 2 => array( +'ALTER TABLE rainloop_ab_properties ADD prop_value_lower text NOT NULL DEFAULT \'\';' + ) )); break; case 'sqlite': $mCache = $this->dataBaseUpgrade($this->sDsnType.'-ab-version', array( - 1 => $this->getInitialTablesArray($this->sDsnType) + 1 => $this->getInitialTablesArray($this->sDsnType), + 2 => array( +'ALTER TABLE rainloop_ab_properties ADD prop_value_lower text NOT NULL DEFAULT \'\';' + ) )); break; } @@ -1934,6 +1965,24 @@ SQLITEINITIAL; array($sEscapeSign.$sEscapeSign, $sEscapeSign.'_', $sEscapeSign.'%'), $sSearch).'%'; } + /** + * @param string $sSearch + * @param string $sEscapeSign = '=' + * + * @return string + */ + private function specialConvertSearchValueLower($sSearch, $sEscapeSign = '=') + { + if (!\MailSo\Base\Utils::FunctionExistsAndEnabled('mb_strtolower')) + { + return ''; + } + + return '%'.\str_replace(array($sEscapeSign, '_', '%'), + array($sEscapeSign.$sEscapeSign, $sEscapeSign.'_', $sEscapeSign.'%'), + (string) @\mb_strtolower($sSearch, 'UTF-8')).'%'; + } + /** * @param string $sSearch * diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters/SieveStorage.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters/SieveStorage.php index dfc15af1c..a83e8d8ef 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters/SieveStorage.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Providers/Filters/SieveStorage.php @@ -242,7 +242,7 @@ class SieveStorage implements \RainLoop\Providers\Filters\FiltersInterface $sResult .= ' "'.$this->quote($sValue).'"'; } - $sResult = \preg_replace('/[\s]+/u', ' ', $sResult); + $sResult = \MailSo\Base\Utils::StripSpaces($sResult); } } else @@ -358,8 +358,8 @@ class SieveStorage implements \RainLoop\Providers\Filters\FiltersInterface $sSubject = ''; if (0 < \strlen($sValueSecond)) { - $sSubject = ':subject "'.$this->quote( - \preg_replace('/[\s]+/u', ' ', $sValueSecond)).'" '; + $sSubject = ':subject "'. + $this->quote(\MailSo\Base\Utils::StripSpaces($sValueSecond)).'" '; } if (0 < \strlen($sValueThird) && \is_numeric($sValueThird) && 1 < (int) $sValueThird) diff --git a/rainloop/v/0.0.0/app/templates/Index.html b/rainloop/v/0.0.0/app/templates/Index.html index a93798748..081b99915 100644 --- a/rainloop/v/0.0.0/app/templates/Index.html +++ b/rainloop/v/0.0.0/app/templates/Index.html @@ -89,7 +89,10 @@ if (window.$LAB && window.rainloopAppData && window.rainloopAppData['TemplatesLink'] && window.rainloopAppData['LangLink']) { - __simplePace(10); + var oProgress = progressJs(); + + oProgress.setOptions({'theme': 'rainloop'}); + oProgress.start().set(5); window.$LAB .script(function () { @@ -98,7 +101,9 @@ ]; }) .wait(function () { - __simplePace(20); + + oProgress.set(20); + if (window.rainloopAppData['IncludeBackground']) { $('#rl-bg').attr('style', 'background-image: none !important;').backstretch( window.rainloopAppData['IncludeBackground'].replace('{{USER}}', @@ -114,20 +119,20 @@ ]; }) .wait(function () { - __simplePace(10); + oProgress.set(30); }) .script(function () { return {'src': '{{BaseAppMainScriptLink}}', 'type': 'text/javascript', 'charset': 'utf-8'}; }) .wait(function () { - __simplePace(20); + oProgress.set(50); }) .script(function () { return window.rainloopAppData['PluginsLink'] ? {'src': window.rainloopAppData['PluginsLink'], 'type': 'text/javascript', 'charset': 'utf-8'} : null; }) .wait(function () { - __simplePace(5); + oProgress.set(55); __runBoot(false); }) .script(function () { diff --git a/rainloop/v/0.0.0/include.php b/rainloop/v/0.0.0/include.php index c7b7b6f6a..f31a560e1 100644 --- a/rainloop/v/0.0.0/include.php +++ b/rainloop/v/0.0.0/include.php @@ -22,16 +22,6 @@ Options -Indexes define('APP_USE_APC_CACHE', true); - $sCustomDataPath = ''; - if (file_exists(APP_INDEX_ROOT_PATH.'include.php')) - { - include_once APP_INDEX_ROOT_PATH.'include.php'; - } - - $sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : ''; - define('APP_DATA_FOLDER_PATH', 0 === strlen($sCustomDataPath) ? APP_INDEX_ROOT_PATH.'data/' : $sCustomDataPath.'/'); - unset($sCustomDataPath); - if (function_exists('date_default_timezone_set')) { date_default_timezone_set('UTC'); @@ -53,12 +43,30 @@ Options -Indexes define('APP_MULTIPLY', 0 < strlen($sPrivateDataFolderInternalName) && APP_DEFAULT_PRIVATE_DATA_NAME !== APP_PRIVATE_DATA_NAME); define('APP_DUMMY', '********'); - define('APP_GOOGLE_ACCESS_TOKEN_PREFIX', ':GAT:'); define('APP_DEV_VERSION', '0.0.0'); + define('APP_GOOGLE_ACCESS_TOKEN_PREFIX', ':GAT:'); + define('APP_WEB_SITE', 'http://www.rainloop.net/'); define('APP_API_PATH', 'http://api.rainloop.net/'); - define('APP_REP_PATH', 'http://repository.rainloop.net/v1/'); - define('APP_REPO_CORE_FILE', 'http://repository.rainloop.net/v2/core.{{channel}}.json'); define('APP_STATUS_PATH', 'http://status.rainloop.net/'); + define('APP_REPOSITORY_PATH', 'http://repository.rainloop.net/v1/'); + define('APP_REPO_CORE_FILE', 'http://repository.rainloop.net/v2/core.{{channel}}.json'); + + $sCustomDataPath = ''; + $sCustomConfiguration = ''; + + if (file_exists(APP_INDEX_ROOT_PATH.'include.php')) + { + include_once APP_INDEX_ROOT_PATH.'include.php'; + } + + $sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : ''; + define('APP_DATA_FOLDER_PATH', 0 === strlen($sCustomDataPath) ? APP_INDEX_ROOT_PATH.'data/' : $sCustomDataPath.'/'); + unset($sCustomDataPath); + + $sCustomConfiguration = function_exists('__get_additional_configuration_name') ? trim(__get_additional_configuration_name()) : ''; + define('APP_ADDITIONAL_CONFIGURATION_NAME', $sCustomConfiguration); + unset($sCustomConfiguration); + define('APP_DATA_FOLDER_PATH_UNIX', str_replace('\\', '/', APP_DATA_FOLDER_PATH)); $sSalt = @file_get_contents(APP_DATA_FOLDER_PATH.'SALT.php'); diff --git a/vendors/progress.js/LICENSE b/vendors/progress.js/LICENSE new file mode 100644 index 000000000..5d0d36c67 --- /dev/null +++ b/vendors/progress.js/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Afshin Mehrabani (afshin.meh@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendors/progress.js/README.md b/vendors/progress.js/README.md new file mode 100644 index 000000000..d58950751 --- /dev/null +++ b/vendors/progress.js/README.md @@ -0,0 +1,65 @@ +# ProgressJS + +> ProgressJs is a JavaScript and CSS3 library which helps developers create and manage progress bars for every object on the page. + +## How To Use + +1) Include `progress.js` and `progressjs.css` in the page (use the minified version from `minified` folder for production) + +2) Execute the following JavaScript code in the page: + +```javascript +//to set progress-bar for whole page +progressJs().start(); +//or for specific element +progressJs("#targetElement").start(); +``` + + +Use other methods to increase, decrease or set an auto-increase function for your progress-bar. Furthermore, you can change the template using `setOption` method. + +## API + +Check the API and method usage with example here: https://github.com/usablica/progress.js/wiki/API + +## Build + +First, you should install `nodejs` and `npm`, then run this command: `npm install` to install all dependencies. + +Now you can run this command to minify all the static resources: + + make build + +## Roadmap +- Add `example` folder and provide examples +- More browser compatibility + mobile/tablet device support +- Add more templates + +## Release History + * **v0.1.0** - 2014-02-14 + - First version + - Increase, decrease and auto-increase functions + - Ability to design and add templates + +## Author +**Afshin Mehrabani** + +- [Twitter](https://twitter.com/afshinmeh) +- [Github](https://github.com/afshinm) +- [Personal page](http://afshinm.name/) + +## License +> Copyright (C) 2012 Afshin Mehrabani (afshin.meh@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/vendors/progress.js/minified/progress.min.js b/vendors/progress.js/minified/progress.min.js new file mode 100644 index 000000000..f7c5b41be --- /dev/null +++ b/vendors/progress.js/minified/progress.min.js @@ -0,0 +1,11 @@ +(function(l,e){"object"===typeof exports?e(exports):"function"===typeof define&&define.amd?define(["exports"],e):e(l)})(this,function(l){function e(a){this._targetElement="undefined"!=typeof a.length?a:[a];"undefined"===typeof window._progressjsId&&(window._progressjsId=1);"undefined"===typeof window._progressjsIntervals&&(window._progressjsIntervals={});this._options={theme:"blue",overlayMode:!1,considerTransition:!0}}function m(a,c){var d=this;100<=c&&(c=100);a.hasAttribute("data-progressjs")&& +setTimeout(function(){"undefined"!=typeof d._onProgressCallback&&d._onProgressCallback.call(d,a,c);var b=h(a);b.style.width=parseInt(c)+"%";var b=b.querySelector(".progressjs-percent"),g=parseInt(b.innerHTML.replace("%","")),e=parseInt(c),j=function(a,b,c){var d=Math.abs(b-c);3>d?k=30:20>d?k=20:intervanIn=1;0!=b-c&&(a.innerHTML=(f?++b:--b)+"%",setTimeout(function(){j(a,b,c)},k))},f=!0;g>e&&(f=!1);var k=10;j(b,g,e)},50)}function h(a){a=parseInt(a.getAttribute("data-progressjs"));return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="'+ +a+'"] > .progressjs-inner')}function p(a){for(var c=0,d=this._targetElement.length;cparseInt(e.style.width.replace("%",""))&&(m.call(this,b,100),l=500);(function(a,b){setTimeout(function(){a.parentNode.className+=" progressjs-end";setTimeout(function(){a.parentNode.parentNode.removeChild(a.parentNode);b.removeAttribute("data-progressjs")},1E3)},l)})(e,b)}if(window._progressjsIntervals[a])try{clearInterval(window._progressjsIntervals[a]),window._progressjsIntervals[a]=null,delete window._progressjsIntervals[a]}catch(j){}}return this}, +onbeforeend:function(a){if("function"===typeof a)this._onBeforeEndCallback=a;else throw Error("Provided callback for onbeforeend was not a function");return this},onbeforestart:function(a){if("function"===typeof a)this._onBeforeStartCallback=a;else throw Error("Provided callback for onbeforestart was not a function");return this},onprogress:function(a){if("function"===typeof a)this._onProgressCallback=a;else throw Error("Provided callback for onprogress was not a function");return this}};return l.progressJs= +n}); diff --git a/vendors/progress.js/minified/progressjs.min.css b/vendors/progress.js/minified/progressjs.min.css new file mode 100644 index 000000000..9ac739e84 --- /dev/null +++ b/vendors/progress.js/minified/progressjs.min.css @@ -0,0 +1 @@ +.progressjs-inner{width:0}.progressjs-progress{z-index:9999999}.progressjs-theme-blue .progressjs-inner{height:2px;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db}.progressjs-theme-blue.progressjs-end{-webkit-transition:opacity .2s ease-out;-moz-transition:opacity .2s ease-out;-o-transition:opacity .2s ease-out;transition:opacity .2s ease-out;opacity:0}.progressjs-theme-blue .progressjs-percent{display:none}.progressjs-theme-blueOverlay{background-color:white;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out}.progressjs-theme-blueOverlay .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db}.progressjs-theme-blueOverlay.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlay .progressjs-percent{display:none}.progressjs-theme-blueOverlay{background-color:white;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out}.progressjs-theme-blueOverlay .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db}.progressjs-theme-blueOverlay.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlay .progressjs-percent{display:none}.progressjs-theme-blueOverlayRadius{background-color:white;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;border-radius:5px}.progressjs-theme-blueOverlayRadius .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db;border-radius:5px}.progressjs-theme-blueOverlayRadius.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlayRadius .progressjs-percent{display:none}.progressjs-theme-blueOverlayRadiusHalfOpacity{background-color:white;opacity:.5;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;border-radius:5px}.progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db;border-radius:5px}.progressjs-theme-blueOverlayRadiusHalfOpacity.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-percent{display:none}.progressjs-theme-blueOverlayRadiusWithPercentBar{background-color:white;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out;border-radius:5px}.progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-inner{height:100%;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out;background-color:#3498db;border-radius:5px}.progressjs-theme-blueOverlayRadiusWithPercentBar.progressjs-end{opacity:0!important}.progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-percent{width:70px;text-align:center;height:40px;position:absolute;right:50%;margin-right:-35px;top:50%;margin-top:-20px;font-size:30px;opacity:.5}.progressjs-theme-blackRadiusInputs{height:10px;border-radius:10px;overflow:hidden}.progressjs-theme-blackRadiusInputs .progressjs-inner{height:2px;-webkit-transition:all 1s ease-out;-moz-transition:all 1s ease-out;-o-transition:all 1s ease-out;transition:all 1s ease-out;background-color:#34495e}.progressjs-theme-blackRadiusInputs.progressjs-end{-webkit-transition:opacity .2s ease-out;-moz-transition:opacity .2s ease-out;-o-transition:opacity .2s ease-out;transition:opacity .2s ease-out;opacity:0}.progressjs-theme-blackRadiusInputs .progressjs-percent{display:none} \ No newline at end of file diff --git a/vendors/progress.js/minified/progressjs.rainloop.css b/vendors/progress.js/minified/progressjs.rainloop.css new file mode 100644 index 000000000..ddc78a941 --- /dev/null +++ b/vendors/progress.js/minified/progressjs.rainloop.css @@ -0,0 +1,62 @@ +.progressjs-theme-rainloop { + z-index: 2000; +} + +.progressjs-theme-rainloop .progressjs-inner { + + background-color: #939595; + position: relative; + z-index: 2000; + height: 3px; + overflow: hidden; + + -webkit-transition: width .5s; + -moz-transition: width .5s; + -o-transition: width .5s; + transition: width .5s; +} + +.progressjs-theme-rainloop .progressjs-percent { + position: absolute; + top: 0; + left: 0; + right: -32px; + bottom: 0; + + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.3)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.3)), color-stop(0.75, rgba(255, 255, 255, 0.3)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent); + -webkit-background-size: 32px 32px; + -moz-background-size: 32px 32px; + -o-background-size: 32px 32px; + background-size: 32px 32px; + + -webkit-animation: simple-pace-stripe-animation 500ms linear infinite; + -moz-animation: simple-pace-stripe-animation 500ms linear infinite; + -ms-animation: simple-pace-stripe-animation 500ms linear infinite; + -o-animation: simple-pace-stripe-animation 500ms linear infinite; + animation: simple-pace-stripe-animation 500ms linear infinite; +} + +@-webkit-keyframes simple-pace-stripe-animation { + 0% { -webkit-transform: none; transform: none; } + 100% { -webkit-transform: translate(-32px, 0); transform: translate(-32px, 0); } +} +@-moz-keyframes simple-pace-stripe-animation { + 0% { -moz-transform: none; transform: none; } + 100% { -moz-transform: translate(-32px, 0); transform: translate(-32px, 0); } +} +@-o-keyframes simple-pace-stripe-animation { + 0% { -o-transform: none; transform: none; } + 100% { -o-transform: translate(-32px, 0); transform: translate(-32px, 0); } +} +@-ms-keyframes simple-pace-stripe-animation { + 0% { -ms-transform: none; transform: none; } + 100% { -ms-transform: translate(-32px, 0); transform: translate(-32px, 0); } +} +@keyframes simple-pace-stripe-animation { + 0% { transform: none; transform: none; } + 100% { transform: translate(-32px, 0); transform: translate(-32px, 0); } +} \ No newline at end of file diff --git a/vendors/progress.js/package.json b/vendors/progress.js/package.json new file mode 100644 index 000000000..4172afc9c --- /dev/null +++ b/vendors/progress.js/package.json @@ -0,0 +1,17 @@ +{ + "name": "Progress.js", + "description": "Themeable HTML5 progress bar library", + "version": "0.1.0", + "author": "Afshin Mehrabani ", + "repository": { + "type": "git", + "url": "https://github.com/usablica/progress.js" + }, + "devDependencies": { + "node-minify": "*" + }, + "engine": [ + "node >=0.1.90" + ], + "main": "src/progress.js" +} \ No newline at end of file diff --git a/vendors/progress.js/src/progress.js b/vendors/progress.js/src/progress.js new file mode 100644 index 000000000..40f50f37f --- /dev/null +++ b/vendors/progress.js/src/progress.js @@ -0,0 +1,574 @@ +/** + * Progress.js v0.1.0 + * https://github.com/usablica/progress.js + * MIT licensed + * + * Copyright (C) 2013 usabli.ca - Afshin Mehrabani (@afshinmeh) + */ + +(function (root, factory) { + if (typeof exports === 'object') { + // CommonJS + factory(exports); + } else if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['exports'], factory); + } else { + // Browser globals + factory(root); + } +} (this, function (exports) { + //Default config/variables + var VERSION = '0.1.0'; + + /** + * ProgressJs main class + * + * @class ProgressJs + */ + function ProgressJs(obj) { + + if (typeof obj.length != 'undefined') { + this._targetElement = obj; + } else { + this._targetElement = [obj]; + } + + if (typeof window._progressjsId === 'undefined') + window._progressjsId = 1; + + if (typeof window._progressjsIntervals === 'undefined') + window._progressjsIntervals = {}; + + this._options = { + //progress bar theme + theme: 'blue', + //overlay mode makes an overlay layer in the target element + overlayMode: false, + //to consider CSS3 transitions in events + considerTransition: true + }; + } + + /** + * Start progress for specific element(s) + * + * @api private + * @method _createContainer + */ + function _startProgress() { + + //call onBeforeStart callback + if (typeof this._onBeforeStartCallback != 'undefined') { + this._onBeforeStartCallback.call(this); + } + + //create the container for progress bar + _createContainer.call(this); + + for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) { + _setProgress.call(this, this._targetElement[i]); + } + } + + /** + * Set progress bar for specific element + * + * @api private + * @method _setProgress + * @param {Object} targetElement + */ + function _setProgress(targetElement) { + + //if the target element already as `data-progressjs`, ignore the init + if (targetElement.hasAttribute("data-progressjs")) + return; + + //get target element position + var targetElementOffset = _getOffset.call(this, targetElement); + + targetElement.setAttribute("data-progressjs", window._progressjsId); + + var progressElementContainer = document.createElement('div'); + progressElementContainer.className = 'progressjs-progress progressjs-theme-' + this._options.theme; + + + //set the position percent elements, it depends on targetElement tag + if (targetElement.tagName.toLowerCase() === 'body') { + progressElementContainer.style.position = 'fixed'; + } else { + progressElementContainer.style.position = 'absolute'; + } + + progressElementContainer.setAttribute("data-progressjs", window._progressjsId); + var progressElement = document.createElement("div"); + progressElement.className = "progressjs-inner"; + + //create an element for current percent of progress bar + var progressPercentElement = document.createElement('div'); + progressPercentElement.className = "progressjs-percent"; + progressPercentElement.innerHTML = "1%"; + + progressElement.appendChild(progressPercentElement); + + if (this._options.overlayMode && targetElement.tagName.toLowerCase() === 'body') { + //if we have `body` for target element and also overlay mode is enable, we should use a different + //position for progress bar container element + progressElementContainer.style.left = 0; + progressElementContainer.style.right = 0; + progressElementContainer.style.top = 0; + progressElementContainer.style.bottom = 0; + } else { + //set progress bar container size and offset + progressElementContainer.style.left = targetElementOffset.left + 'px'; + progressElementContainer.style.top = targetElementOffset.top + 'px'; + //if targetElement is body set to percent so it scales with browser resize + if (targetElement.nodeName == 'BODY') { + progressElementContainer.style.width = '100%'; + } else { + progressElementContainer.style.width = targetElementOffset.width + 'px'; + } + + if (this._options.overlayMode) { + progressElementContainer.style.height = targetElementOffset.height + 'px'; + } + } + + progressElementContainer.appendChild(progressElement); + + //append the element to container + var container = document.querySelector('.progressjs-container'); + container.appendChild(progressElementContainer); + + _setPercentFor(targetElement, 1); + + //and increase the progressId + ++window._progressjsId; + } + + /** + * Set percent for all elements + * + * @api private + * @method _setPercent + * @param {Number} percent + */ + function _setPercent(percent) { + for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) { + _setPercentFor.call(this, this._targetElement[i], percent); + } + } + + /** + * Set percent for specific element + * + * @api private + * @method _setPercentFor + * @param {Object} targetElement + * @param {Number} percent + */ + function _setPercentFor(targetElement, percent) { + var self = this; + + //prevent overflow! + if (percent >= 100) + percent = 100; + + if (targetElement.hasAttribute("data-progressjs")) { + //setTimeout for better CSS3 animation applying in some cases + setTimeout(function() { + + //call the onprogress callback + if (typeof self._onProgressCallback != 'undefined') { + self._onProgressCallback.call(self, targetElement, percent); + } + + var percentElement = _getPercentElement(targetElement); + percentElement.style.width = parseInt(percent) + '%'; + + var percentElement = percentElement.querySelector(".progressjs-percent"); + var existingPercent = parseInt(percentElement.innerHTML.replace('%', '')); + + //start increase/decrease the percent element with animation + (function(percentElement, existingPercent, currentPercent) { + + var increasement = true; + if (existingPercent > currentPercent) { + increasement = false; + } + + var intervalIn = 10; + function changePercentTimer(percentElement, existingPercent, currentPercent) { + //calculate the distance between two percents + var distance = Math.abs(existingPercent - currentPercent); + if (distance < 3) { + intervalIn = 30; + } else if (distance < 20) { + intervalIn = 20; + } else { + intervanIn = 1; + } + + if ((existingPercent - currentPercent) != 0) { + //set the percent + percentElement.innerHTML = (increasement ? (++existingPercent) : (--existingPercent)) + '%'; + setTimeout(function() { changePercentTimer(percentElement, existingPercent, currentPercent); }, intervalIn); + } + } + + changePercentTimer(percentElement, existingPercent, currentPercent); + + })(percentElement, existingPercent, parseInt(percent)); + + }, 50); + } + } + + /** + * Get the progress bar element + * + * @api private + * @method _getPercentElement + * @param {Object} targetElement + */ + function _getPercentElement(targetElement) { + var progressjsId = parseInt(targetElement.getAttribute('data-progressjs')); + return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="' + progressjsId + '"] > .progressjs-inner'); + } + + /** + * Auto increase the progress bar every X milliseconds + * + * @api private + * @method _autoIncrease + * @param {Number} size + * @param {Number} millisecond + */ + function _autoIncrease(size, millisecond) { + var self = this; + + var target = this._targetElement[0]; + if(!target) return; + var progressjsId = parseInt(target.getAttribute('data-progressjs')); + + if (typeof window._progressjsIntervals[progressjsId] != 'undefined') { + clearInterval(window._progressjsIntervals[progressjsId]); + } + window._progressjsIntervals[progressjsId] = setInterval(function() { + _increasePercent.call(self, size); + }, millisecond); + } + + /** + * Increase the size of progress bar + * + * @api private + * @method _increasePercent + * @param {Number} size + */ + function _increasePercent(size) { + for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) { + var currentElement = this._targetElement[i]; + if (currentElement.hasAttribute('data-progressjs')) { + var percentElement = _getPercentElement(currentElement); + var existingPercent = parseInt(percentElement.style.width.replace('%', '')); + if (existingPercent) { + _setPercentFor.call(this, currentElement, existingPercent + (size || 1)); + } + } + } + } + + /** + * Close and remove progress bar + * + * @api private + * @method _end + */ + function _end() { + + //call onBeforeEnd callback + if (typeof this._onBeforeEndCallback != 'undefined') { + if (this._options.considerTransition === true) { + //we can safety assume that all layers would be the same, so `this._targetElement[0]` is the same as `this._targetElement[1]` + _getPercentElement(this._targetElement[0]).addEventListener(whichTransitionEvent(), this._onBeforeEndCallback, false); + } else { + this._onBeforeEndCallback.call(this); + } + } + + var target = this._targetElement[0]; + if(!target) return; + var progressjsId = parseInt(target.getAttribute('data-progressjs')); + + for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) { + var currentElement = this._targetElement[i]; + var percentElement = _getPercentElement(currentElement); + + if (!percentElement) + return; + + var existingPercent = parseInt(percentElement.style.width.replace('%', '')); + + var timeoutSec = 1; + if (existingPercent < 100) { + _setPercentFor.call(this, currentElement, 100); + timeoutSec = 500; + } + + //I believe I should handle this situation with eventListener and `transitionend` event but I'm not sure + //about compatibility with IEs. Should be fixed in further versions. + (function(percentElement, currentElement) { + setTimeout(function() { + percentElement.parentNode.className += " progressjs-end"; + + setTimeout(function() { + //remove the percent element from page + percentElement.parentNode.parentNode.removeChild(percentElement.parentNode); + //and remove the attribute + currentElement.removeAttribute("data-progressjs"); + }, 1000); + }, timeoutSec); + })(percentElement, currentElement); + } + + //clean the setInterval for autoIncrease function + if (window._progressjsIntervals[progressjsId]) { + //`delete` keyword has some problems in IE + try { + clearInterval(window._progressjsIntervals[progressjsId]); + window._progressjsIntervals[progressjsId] = null; + delete window._progressjsIntervals[progressjsId]; + } catch(ex) { } + } + } + + /** + * Remove progress bar without finishing + * + * @api private + * @method _kill + */ + function _kill() { + var target = this._targetElement[0]; + if(!target) return; + var progressjsId = parseInt(target.getAttribute('data-progressjs')); + + for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) { + var currentElement = this._targetElement[i]; + var percentElement = _getPercentElement(currentElement); + + if (!percentElement) + return; + + //I believe I should handle this situation with eventListener and `transitionend` event but I'm not sure + //about compatibility with IEs. Should be fixed in further versions. + (function(percentElement, currentElement) { + percentElement.parentNode.className += " progressjs-end"; + + setTimeout(function() { + //remove the percent element from page + percentElement.parentNode.parentNode.removeChild(percentElement.parentNode); + //and remove the attribute + currentElement.removeAttribute("data-progressjs"); + }, 1000); + })(percentElement, currentElement); + } + + //clean the setInterval for autoIncrease function + if (window._progressjsIntervals[progressjsId]) { + //`delete` keyword has some problems in IE + try { + clearInterval(window._progressjsIntervals[progressjsId]); + window._progressjsIntervals[progressjsId] = null; + delete window._progressjsIntervals[progressjsId]; + } catch(ex) { } + } + } + + /** + * Create the progress bar container + * + * @api private + * @method _createContainer + */ + function _createContainer() { + //first check if we have an container already, we don't need to create it again + if (!document.querySelector(".progressjs-container")) { + var containerElement = document.createElement("div"); + containerElement.className = "progressjs-container"; + document.body.appendChild(containerElement); + } + } + + /** + * Get an element position on the page + * Thanks to `meouw`: http://stackoverflow.com/a/442474/375966 + * + * @api private + * @method _getOffset + * @param {Object} element + * @returns Element's position info + */ + function _getOffset(element) { + var elementPosition = {}; + + if (element.tagName.toLowerCase() === 'body') { + //set width + elementPosition.width = element.clientWidth; + //set height + elementPosition.height = element.clientHeight; + } else { + //set width + elementPosition.width = element.offsetWidth; + //set height + elementPosition.height = element.offsetHeight; + } + + //calculate element top and left + var _x = 0; + var _y = 0; + while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { + _x += element.offsetLeft; + _y += element.offsetTop; + element = element.offsetParent; + } + //set top + elementPosition.top = _y; + //set left + elementPosition.left = _x; + + return elementPosition; + } + + /** + * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1 + * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically + * + * @param obj1 + * @param obj2 + * @returns obj3 a new object based on obj1 and obj2 + */ + function _mergeOptions(obj1, obj2) { + var obj3 = {}; + for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; } + for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; } + return obj3; + } + + var progressJs = function (targetElm) { + if (typeof (targetElm) === 'object') { + //Ok, create a new instance + return new ProgressJs(targetElm); + + } else if (typeof (targetElm) === 'string') { + //select the target element with query selector + var targetElement = document.querySelectorAll(targetElm); + + if (targetElement) { + return new ProgressJs(targetElement); + } else { + throw new Error('There is no element with given selector.'); + } + } else { + return new ProgressJs(document.body); + } + }; + + /** + * Get correct transition callback + * Thanks @webinista: http://stackoverflow.com/a/9090128/375966 + * + * @returns transition name + */ + function whichTransitionEvent() { + var t; + var el = document.createElement('fakeelement'); + var transitions = { + 'transition': 'transitionend', + 'OTransition': 'oTransitionEnd', + 'MozTransition': 'transitionend', + 'WebkitTransition': 'webkitTransitionEnd' + } + + for (t in transitions) { + if (el.style[t] !== undefined) { + return transitions[t]; + } + } + } + + /** + * Current ProgressJs version + * + * @property version + * @type String + */ + progressJs.version = VERSION; + + //Prototype + progressJs.fn = ProgressJs.prototype = { + clone: function () { + return new ProgressJs(this); + }, + setOption: function(option, value) { + this._options[option] = value; + return this; + }, + setOptions: function(options) { + this._options = _mergeOptions(this._options, options); + return this; + }, + start: function() { + _startProgress.call(this); + return this; + }, + set: function(percent) { + _setPercent.call(this, percent); + return this; + }, + increase: function(size) { + _increasePercent.call(this, size); + return this; + }, + autoIncrease: function(size, millisecond) { + _autoIncrease.call(this, size, millisecond); + return this; + }, + end: function() { + _end.call(this); + return this; + }, + kill: function() { + _kill.call(this); + return this; + }, + onbeforeend: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._onBeforeEndCallback = providedCallback; + } else { + throw new Error('Provided callback for onbeforeend was not a function'); + } + return this; + }, + onbeforestart: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._onBeforeStartCallback = providedCallback; + } else { + throw new Error('Provided callback for onbeforestart was not a function'); + } + return this; + }, + onprogress: function(providedCallback) { + if (typeof (providedCallback) === 'function') { + this._onProgressCallback = providedCallback; + } else { + throw new Error('Provided callback for onprogress was not a function'); + } + return this; + } + }; + + exports.progressJs = progressJs; + return progressJs; +})); diff --git a/vendors/progress.js/src/progressjs.css b/vendors/progress.js/src/progressjs.css new file mode 100644 index 000000000..892bd6fbd --- /dev/null +++ b/vendors/progress.js/src/progressjs.css @@ -0,0 +1,181 @@ +.progressjs-inner { + width: 0; +} +.progressjs-progress { + z-index: 9999999; +} + +/* blue theme, like iOS 7 progress bar */ +.progressjs-theme-blue .progressjs-inner { + height: 2px; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; + background-color: #3498db; +} +.progressjs-theme-blue.progressjs-end { + -webkit-transition: opacity 0.2s ease-out; + -moz-transition: opacity 0.2s ease-out; + -o-transition: opacity 0.2s ease-out; + transition: opacity 0.2s ease-out; + opacity: 0; +} +.progressjs-theme-blue .progressjs-percent { + display: none; +} + +/* blue theme with overlay layer, no percent bar */ +.progressjs-theme-blueOverlay { + background-color: white; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +.progressjs-theme-blueOverlay .progressjs-inner { + height: 100%; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; + background-color: #3498db; +} +.progressjs-theme-blueOverlay.progressjs-end { + opacity: 0 !important; +} +.progressjs-theme-blueOverlay .progressjs-percent { + display: none; +} + +/* blue theme with overlay layer, no percent bar */ +.progressjs-theme-blueOverlay { + background-color: white; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +.progressjs-theme-blueOverlay .progressjs-inner { + height: 100%; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; + background-color: #3498db; +} +.progressjs-theme-blueOverlay.progressjs-end { + opacity: 0 !important; +} +.progressjs-theme-blueOverlay .progressjs-percent { + display: none; +} + +/* Blue theme with border radius and overlay layer */ +.progressjs-theme-blueOverlayRadius { + background-color: white; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; + border-radius: 5px; +} +.progressjs-theme-blueOverlayRadius .progressjs-inner { + height: 100%; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; + background-color: #3498db; + border-radius: 5px; +} +.progressjs-theme-blueOverlayRadius.progressjs-end { + opacity: 0 !important; +} +.progressjs-theme-blueOverlayRadius .progressjs-percent { + display: none; +} + +/* Blue theme with border radius and overlay layer */ +.progressjs-theme-blueOverlayRadiusHalfOpacity { + background-color: white; + opacity: 0.5; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; + border-radius: 5px; +} +.progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-inner { + height: 100%; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; + background-color: #3498db; + border-radius: 5px; +} +.progressjs-theme-blueOverlayRadiusHalfOpacity.progressjs-end { + opacity: 0 !important; +} +.progressjs-theme-blueOverlayRadiusHalfOpacity .progressjs-percent { + display: none; +} + +/* Blue theme with border radius, overlay layer and percent bar */ +.progressjs-theme-blueOverlayRadiusWithPercentBar { + background-color: white; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; + border-radius: 5px; +} +.progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-inner { + height: 100%; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; + background-color: #3498db; + border-radius: 5px; +} +.progressjs-theme-blueOverlayRadiusWithPercentBar.progressjs-end { + opacity: 0 !important; +} +.progressjs-theme-blueOverlayRadiusWithPercentBar .progressjs-percent { + width: 70px; + text-align: center; + height: 40px; + position: absolute; + right: 50%; + margin-right: -35px; + top: 50%; + margin-top: -20px; + font-size: 30px; + opacity: .5; +} + +.progressjs-theme-blackRadiusInputs { + height: 10px; + border-radius: 10px; + overflow: hidden; +} +.progressjs-theme-blackRadiusInputs .progressjs-inner { + height: 2px; + -webkit-transition: all 1s ease-out; + -moz-transition: all 1s ease-out; + -o-transition: all 1s ease-out; + transition: all 1s ease-out; + background-color: #34495e; +} +.progressjs-theme-blackRadiusInputs.progressjs-end { + -webkit-transition: opacity 0.2s ease-out; + -moz-transition: opacity 0.2s ease-out; + -o-transition: opacity 0.2s ease-out; + transition: opacity 0.2s ease-out; + opacity: 0; +} +.progressjs-theme-blackRadiusInputs .progressjs-percent { + display: none; +} \ No newline at end of file diff --git a/vendors/simple-pace/simple-pace.js b/vendors/simple-pace/simple-pace.js index caa462b9c..316109cdb 100644 --- a/vendors/simple-pace/simple-pace.js +++ b/vendors/simple-pace/simple-pace.js @@ -32,7 +32,7 @@ } }, 500); }; - + Bar.prototype.stopAddInterval = function () { window.clearInterval(this.addInterval); this.addInterval = 0; @@ -78,7 +78,7 @@ return this.render(); }; - + Bar.prototype.add = function (iProg) { this.progress += window.parseInt(iProg, 10); this.progress = 100 < this.progress ? 100 : this.progress; @@ -86,7 +86,7 @@ return this.render(); }; - + Bar.prototype.setSpeed = function (iSpeed, iStopProgress) { this.addSpeed = iSpeed; this.stopProgress = iStopProgress || 100; diff --git a/webpack.config.js b/webpack.config.js index 1f9f928f1..34b832653 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -29,7 +29,7 @@ module.exports = { 'JSON': 'window.JSON', 'JSEncrypt': 'window.JSEncrypt', '$LAB': 'window.$LAB', - 'SimplePace': 'window.SimplePace', + 'progressJs': 'window.progressJs', 'PhotoSwipe': 'window.PhotoSwipe', 'PhotoSwipeUI_Default': 'window.PhotoSwipeUI_Default', 'queue': 'window.queue',