mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Optimizations
Added "[labs]imap_folder_list_limit" setting (optimization)
This commit is contained in:
parent
833f40c115
commit
7ef9ebb45f
22 changed files with 878 additions and 32 deletions
|
|
@ -75,8 +75,8 @@
|
||||||
var bResult = false;
|
var bResult = false;
|
||||||
if (oJsonAttachment && 'Object/Attachment' === oJsonAttachment['@Object'])
|
if (oJsonAttachment && 'Object/Attachment' === oJsonAttachment['@Object'])
|
||||||
{
|
{
|
||||||
this.mimeType = (oJsonAttachment.MimeType || '').toLowerCase();
|
this.mimeType = Utils.trim((oJsonAttachment.MimeType || '').toLowerCase());
|
||||||
this.fileName = oJsonAttachment.FileName;
|
this.fileName = Utils.trim(oJsonAttachment.FileName);
|
||||||
this.estimatedSize = Utils.pInt(oJsonAttachment.EstimatedSize);
|
this.estimatedSize = Utils.pInt(oJsonAttachment.EstimatedSize);
|
||||||
this.isInline = !!oJsonAttachment.IsInline;
|
this.isInline = !!oJsonAttachment.IsInline;
|
||||||
this.isLinked = !!oJsonAttachment.IsLinked;
|
this.isLinked = !!oJsonAttachment.IsLinked;
|
||||||
|
|
@ -122,8 +122,8 @@
|
||||||
*/
|
*/
|
||||||
AttachmentModel.prototype.isText = function ()
|
AttachmentModel.prototype.isText = function ()
|
||||||
{
|
{
|
||||||
return 'text/' === this.mimeType.substr(0, 5) &&
|
return -1 < Utils.inArray(this.mimeType, ['application/pgp-signature']) ||
|
||||||
-1 === Utils.inArray(this.mimeType, ['text/html']);
|
('text/' === this.mimeType.substr(0, 5) && -1 === Utils.inArray(this.mimeType, ['text/html']));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -267,9 +267,12 @@
|
||||||
*/
|
*/
|
||||||
AttachmentModel.staticIconClassHelper = function (sMimeType)
|
AttachmentModel.staticIconClassHelper = function (sMimeType)
|
||||||
{
|
{
|
||||||
|
sMimeType = Utils.trim(sMimeType).toLowerCase();
|
||||||
|
|
||||||
var
|
var
|
||||||
aParts = sMimeType.toLocaleString().split('/'),
|
sText = '',
|
||||||
sClass = 'icon-file'
|
sClass = 'icon-file',
|
||||||
|
aParts = sMimeType.split('/')
|
||||||
;
|
;
|
||||||
|
|
||||||
if (aParts && aParts[1])
|
if (aParts && aParts[1])
|
||||||
|
|
@ -295,17 +298,24 @@
|
||||||
{
|
{
|
||||||
sClass = 'icon-file-zip';
|
sClass = 'icon-file-zip';
|
||||||
}
|
}
|
||||||
// else if (-1 < Utils.inArray(aParts[1],
|
else if (-1 < Utils.inArray(aParts[1],
|
||||||
// ['pdf', 'x-pdf']))
|
['pdf', 'x-pdf']))
|
||||||
// {
|
{
|
||||||
// sClass = 'icon-file-pdf';
|
sText = 'pdf'
|
||||||
// }
|
sClass = 'icon-none';
|
||||||
|
}
|
||||||
// else if (-1 < Utils.inArray(aParts[1], [
|
// else if (-1 < Utils.inArray(aParts[1], [
|
||||||
// 'exe', 'x-exe', 'x-winexe', 'bat'
|
// 'exe', 'x-exe', 'x-winexe', 'bat'
|
||||||
// ]))
|
// ]))
|
||||||
// {
|
// {
|
||||||
// sClass = 'icon-console';
|
// sClass = 'icon-console';
|
||||||
// }
|
// }
|
||||||
|
else if (-1 < Utils.inArray(sMimeType, [
|
||||||
|
'application/pgp-signature'
|
||||||
|
]))
|
||||||
|
{
|
||||||
|
sClass = 'icon-file-certificate';
|
||||||
|
}
|
||||||
else if (-1 < Utils.inArray(aParts[1], [
|
else if (-1 < Utils.inArray(aParts[1], [
|
||||||
'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document',
|
'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
'vnd.openxmlformats-officedocument.wordprocessingml.template',
|
'vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||||
|
|
@ -342,7 +352,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sClass;
|
return [sClass, sText];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -350,7 +360,15 @@
|
||||||
*/
|
*/
|
||||||
AttachmentModel.prototype.iconClass = function ()
|
AttachmentModel.prototype.iconClass = function ()
|
||||||
{
|
{
|
||||||
return AttachmentModel.staticIconClassHelper(this.mimeType);
|
return AttachmentModel.staticIconClassHelper(this.mimeType)[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
AttachmentModel.prototype.iconText = function ()
|
||||||
|
{
|
||||||
|
return AttachmentModel.staticIconClassHelper(this.mimeType)[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = AttachmentModel;
|
module.exports = AttachmentModel;
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,9 @@
|
||||||
case 'doc':
|
case 'doc':
|
||||||
sClass = 'icon-file-text';
|
sClass = 'icon-file-text';
|
||||||
break;
|
break;
|
||||||
|
case 'certificate':
|
||||||
|
sClass = 'icon-file-certificate';
|
||||||
|
break;
|
||||||
// case 'pdf':
|
// case 'pdf':
|
||||||
// sClass = 'icon-file-pdf';
|
// sClass = 'icon-file-pdf';
|
||||||
// break;
|
// break;
|
||||||
|
|
@ -628,6 +631,10 @@
|
||||||
{
|
{
|
||||||
aResult.push('focused');
|
aResult.push('focused');
|
||||||
}
|
}
|
||||||
|
if (this.isImportant())
|
||||||
|
{
|
||||||
|
aResult.push('important');
|
||||||
|
}
|
||||||
if (this.hasAttachments())
|
if (this.hasAttachments())
|
||||||
{
|
{
|
||||||
aResult.push('withAttachments');
|
aResult.push('withAttachments');
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,17 @@ html.rl-no-preview-pane {
|
||||||
background-color: #ccc !important;
|
background-color: #ccc !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.importantMark {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
color:red;
|
||||||
|
margin-right:5px
|
||||||
|
}
|
||||||
|
|
||||||
|
&.important .importantMark {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
&.e-single-line {
|
&.e-single-line {
|
||||||
height: 35px;
|
height: 35px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -309,6 +309,21 @@ html.rl-no-preview-pane {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.attachmentIconText {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 28px;
|
||||||
|
width: 60px;
|
||||||
|
height: 56px;
|
||||||
|
color: #aaa;
|
||||||
|
line-height: 56px;
|
||||||
|
text-align: center;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.attachmentIcon.icon-none {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.attachmentIconParent.hasPreview:hover {
|
.attachmentIconParent.hasPreview:hover {
|
||||||
.iconPreview {
|
.iconPreview {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,15 @@
|
||||||
|
|
||||||
animation: rotation .8s infinite linear;
|
animation: rotation .8s infinite linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.big {
|
||||||
|
|
||||||
|
height: 13px;
|
||||||
|
width: 13px;
|
||||||
|
|
||||||
|
margin-top: -2px;
|
||||||
|
margin-left: -2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html.no-cssanimations .icon-spinner {
|
html.no-cssanimations .icon-spinner {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
'placement': 'top',
|
'placement': 'top',
|
||||||
'trigger': 'hover',
|
'trigger': 'hover',
|
||||||
'title': 'About',
|
'title': 'About',
|
||||||
|
'container': 'body',
|
||||||
'content': function () {
|
'content': function () {
|
||||||
return self.readme();
|
return self.readme();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -900,6 +900,13 @@
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
|
this.dragOver.subscribe(function (bValue) {
|
||||||
|
if (bValue)
|
||||||
|
{
|
||||||
|
this.selector.scrollToTop();
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
oJua
|
oJua
|
||||||
.on('onDragEnter', _.bind(function () {
|
.on('onDragEnter', _.bind(function () {
|
||||||
this.dragOverEnter(true);
|
this.dragOverEnter(true);
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,7 @@ cfg.paths.js = {
|
||||||
'vendors/routes/hasher.min.js',
|
'vendors/routes/hasher.min.js',
|
||||||
'vendors/routes/crossroads.min.js',
|
'vendors/routes/crossroads.min.js',
|
||||||
'vendors/knockout/knockout-3.2.0.js',
|
'vendors/knockout/knockout-3.2.0.js',
|
||||||
|
// 'vendors/knockout-punches/knockout.punches.min.js',
|
||||||
'vendors/knockout-projections/knockout-projections-1.0.0.min.js',
|
'vendors/knockout-projections/knockout-projections-1.0.0.min.js',
|
||||||
'vendors/knockout-sortable/knockout-sortable.min.js',
|
'vendors/knockout-sortable/knockout-sortable.min.js',
|
||||||
'vendors/ssm/ssm.min.js',
|
'vendors/ssm/ssm.min.js',
|
||||||
|
|
|
||||||
|
|
@ -608,7 +608,8 @@ class ImapClient extends \MailSo\Net\NetClient
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $aResult
|
* @param array $aResult
|
||||||
* @param bool $bIsSubscribeList
|
* @param string $sStatus
|
||||||
|
* @param bool $bUseListStatus = false
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,14 @@ class Attachment
|
||||||
return $this->oBodyStructure ? $this->oBodyStructure->IsDoc() : false;
|
return $this->oBodyStructure ? $this->oBodyStructure->IsDoc() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function IsPgpSignature()
|
||||||
|
{
|
||||||
|
return $this->oBodyStructure ? $this->oBodyStructure->IsPgpSignature() : false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \MailSo\Mail\Attachment
|
* @return \MailSo\Mail\Attachment
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -104,4 +104,16 @@ class AttachmentCollection extends \MailSo\Base\Collection
|
||||||
|
|
||||||
return \is_array($aList) ? \count($aList) : 0;
|
return \is_array($aList) ? \count($aList) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function CertificateCount()
|
||||||
|
{
|
||||||
|
$aList = $this->FilterList(function ($oAttachment) {
|
||||||
|
return $oAttachment && $oAttachment->IsPgpSignature();
|
||||||
|
});
|
||||||
|
|
||||||
|
return \is_array($aList) ? \count($aList) : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,11 @@ class FolderCollection extends \MailSo\Base\Collection
|
||||||
*/
|
*/
|
||||||
public $IsThreadsSupported;
|
public $IsThreadsSupported;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $Optimized;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
|
|
@ -48,6 +53,7 @@ class FolderCollection extends \MailSo\Base\Collection
|
||||||
$this->FoldersHash = '';
|
$this->FoldersHash = '';
|
||||||
$this->SystemFolders = array();
|
$this->SystemFolders = array();
|
||||||
$this->IsThreadsSupported = false;
|
$this->IsThreadsSupported = false;
|
||||||
|
$this->Optimized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1914,7 +1914,8 @@ class MailClient
|
||||||
|
|
||||||
if (1 < $iMessageCount)
|
if (1 < $iMessageCount)
|
||||||
{
|
{
|
||||||
if ($bMessageListOptimization || 0 === \MailSo\Config::$MessageListDateFilter)
|
if (0 === \MailSo\Config::$MessageListDateFilter &&
|
||||||
|
($bMessageListOptimization || !$bUseSortIfSupported))
|
||||||
{
|
{
|
||||||
$aIndexOrUids = \array_reverse(\range(1, $iMessageCount));
|
$aIndexOrUids = \array_reverse(\range(1, $iMessageCount));
|
||||||
}
|
}
|
||||||
|
|
@ -2013,19 +2014,140 @@ class MailClient
|
||||||
return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null;
|
return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $aMailFoldersHelper
|
||||||
|
* @param int $iOptimizationLimit = 0
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function folerListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0)
|
||||||
|
{
|
||||||
|
// optimization
|
||||||
|
if (10 < $iOptimizationLimit && $iOptimizationLimit < \count($aMailFoldersHelper))
|
||||||
|
{
|
||||||
|
if ($this->oLogger)
|
||||||
|
{
|
||||||
|
$this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$iForeachLimit = 1;
|
||||||
|
|
||||||
|
$aFilteredNames = array(
|
||||||
|
'inbox',
|
||||||
|
'sent', 'outbox', 'sentmail',
|
||||||
|
'drafts',
|
||||||
|
'junk', 'spam',
|
||||||
|
'trash', 'bin',
|
||||||
|
'archive', 'allmail', 'all',
|
||||||
|
'starred', 'flagged', 'important'
|
||||||
|
);
|
||||||
|
|
||||||
|
$aNewMailFoldersHelper = array();
|
||||||
|
|
||||||
|
$iCountLimit = $iForeachLimit;
|
||||||
|
foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
|
||||||
|
{
|
||||||
|
// normal and subscribed only
|
||||||
|
if ($oFolder && ($oFolder->IsSubscribed() || \in_array(\strtolower($oFolder->NameRaw()), $aFilteredNames)))
|
||||||
|
{
|
||||||
|
$aNewMailFoldersHelper[] = $oFolder;
|
||||||
|
|
||||||
|
$aMailFoldersHelper[$iIndex] = null;
|
||||||
|
$iCountLimit--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 > $iCountLimit)
|
||||||
|
{
|
||||||
|
if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iCountLimit = $iForeachLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$iCountLimit = $iForeachLimit;
|
||||||
|
if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
|
||||||
|
{
|
||||||
|
// name filter
|
||||||
|
foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
|
||||||
|
{
|
||||||
|
if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw()))
|
||||||
|
{
|
||||||
|
$aNewMailFoldersHelper[] = $oFolder;
|
||||||
|
|
||||||
|
$aMailFoldersHelper[$iIndex] = null;
|
||||||
|
$iCountLimit--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 > $iCountLimit)
|
||||||
|
{
|
||||||
|
if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iCountLimit = $iForeachLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$iCountLimit = $iForeachLimit;
|
||||||
|
if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
|
||||||
|
{
|
||||||
|
// other
|
||||||
|
foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
|
||||||
|
{
|
||||||
|
if ($oFolder)
|
||||||
|
{
|
||||||
|
$aNewMailFoldersHelper[] = $oFolder;
|
||||||
|
|
||||||
|
$aMailFoldersHelper[$iIndex] = null;
|
||||||
|
$iCountLimit--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 > $iCountLimit)
|
||||||
|
{
|
||||||
|
if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$iCountLimit = $iForeachLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$aMailFoldersHelper = $aNewMailFoldersHelper;
|
||||||
|
|
||||||
|
if ($this->oLogger)
|
||||||
|
{
|
||||||
|
$this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $aMailFoldersHelper;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $sParent = ''
|
* @param string $sParent = ''
|
||||||
* @param string $sListPattern = '*'
|
* @param string $sListPattern = '*'
|
||||||
* @param bool $bUseListSubscribeStatus = false
|
* @param bool $bUseListSubscribeStatus = false
|
||||||
|
* @param int $iOptimizationLimit = 0
|
||||||
*
|
*
|
||||||
* @return \MailSo\Mail\FolderCollection|false
|
* @return \MailSo\Mail\FolderCollection|false
|
||||||
*/
|
*/
|
||||||
public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true)
|
public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0)
|
||||||
{
|
{
|
||||||
$oFolderCollection = false;
|
$oFolderCollection = false;
|
||||||
|
|
||||||
$aFolders = $this->oImapClient->FolderList($sParent, $sListPattern);
|
|
||||||
|
|
||||||
$aSubscribedFolders = null;
|
$aSubscribedFolders = null;
|
||||||
if ($bUseListSubscribeStatus)
|
if ($bUseListSubscribeStatus)
|
||||||
{
|
{
|
||||||
|
|
@ -2046,7 +2168,11 @@ class MailClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$aFolders = $this->oImapClient->FolderList($sParent, $sListPattern);
|
||||||
|
|
||||||
|
$bOptimized = false;
|
||||||
$aMailFoldersHelper = null;
|
$aMailFoldersHelper = null;
|
||||||
|
|
||||||
if (\is_array($aFolders))
|
if (\is_array($aFolders))
|
||||||
{
|
{
|
||||||
$aMailFoldersHelper = array();
|
$aMailFoldersHelper = array();
|
||||||
|
|
@ -2058,12 +2184,19 @@ class MailClient
|
||||||
$oImapFolder->IsInbox()
|
$oImapFolder->IsInbox()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$iCount = \count($aMailFoldersHelper);
|
||||||
|
$aMailFoldersHelper = $this->folerListOptimization($aMailFoldersHelper, $iOptimizationLimit);
|
||||||
|
|
||||||
|
$bOptimized = $iCount !== \count($aMailFoldersHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\is_array($aMailFoldersHelper))
|
if (\is_array($aMailFoldersHelper))
|
||||||
{
|
{
|
||||||
$oFolderCollection = FolderCollection::NewInstance();
|
$oFolderCollection = FolderCollection::NewInstance();
|
||||||
$oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper);
|
$oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper);
|
||||||
|
|
||||||
|
$oFolderCollection->Optimized = $bOptimized;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oFolderCollection)
|
if ($oFolderCollection)
|
||||||
|
|
|
||||||
|
|
@ -4334,7 +4334,8 @@ class Actions
|
||||||
if (null === $oFolderCollection)
|
if (null === $oFolderCollection)
|
||||||
{
|
{
|
||||||
$oFolderCollection = $this->MailClient()->Folders('', '*',
|
$oFolderCollection = $this->MailClient()->Folders('', '*',
|
||||||
!!$this->Config()->Get('labs', 'use_imap_list_subscribe', true)
|
!!$this->Config()->Get('labs', 'use_imap_list_subscribe', true),
|
||||||
|
(int) $this->Config()->Get('labs', 'imap_folder_list_limit', 200)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4694,7 +4695,7 @@ class Actions
|
||||||
*/
|
*/
|
||||||
public function DoMessageList()
|
public function DoMessageList()
|
||||||
{
|
{
|
||||||
// sleep(2);
|
// \sleep(2);
|
||||||
// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
|
// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
|
||||||
|
|
||||||
$sFolder = '';
|
$sFolder = '';
|
||||||
|
|
@ -4708,7 +4709,7 @@ class Actions
|
||||||
$sRawKey = $this->GetActionParam('RawKey', '');
|
$sRawKey = $this->GetActionParam('RawKey', '');
|
||||||
$aValues = $this->getDecodedClientRawKeyValue($sRawKey, 9);
|
$aValues = $this->getDecodedClientRawKeyValue($sRawKey, 9);
|
||||||
|
|
||||||
if (is_array($aValues) && 9 === count($aValues))
|
if (\is_array($aValues) && 9 === \count($aValues))
|
||||||
{
|
{
|
||||||
$sFolder =(string) $aValues[0];
|
$sFolder =(string) $aValues[0];
|
||||||
$iOffset = (int) $aValues[1];
|
$iOffset = (int) $aValues[1];
|
||||||
|
|
@ -4753,7 +4754,7 @@ class Actions
|
||||||
|
|
||||||
$aExpandedThreadUid = \array_map(function ($sValue) {
|
$aExpandedThreadUid = \array_map(function ($sValue) {
|
||||||
$sValue = \trim($sValue);
|
$sValue = \trim($sValue);
|
||||||
return is_numeric($sValue) ? (int) $sValue : 0;
|
return \is_numeric($sValue) ? (int) $sValue : 0;
|
||||||
}, $aExpandedThreadUid);
|
}, $aExpandedThreadUid);
|
||||||
|
|
||||||
$aExpandedThreadUid = \array_filter($aExpandedThreadUid, function ($iValue) {
|
$aExpandedThreadUid = \array_filter($aExpandedThreadUid, function ($iValue) {
|
||||||
|
|
@ -8115,6 +8116,9 @@ class Actions
|
||||||
case $iAttachmentsCount === $oAttachments->DocCount():
|
case $iAttachmentsCount === $oAttachments->DocCount():
|
||||||
$mResult['AttachmentsMainType'] = 'doc';
|
$mResult['AttachmentsMainType'] = 'doc';
|
||||||
break;
|
break;
|
||||||
|
case $iAttachmentsCount === $oAttachments->CertificateCount():
|
||||||
|
$mResult['AttachmentsMainType'] = 'certificate';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8382,6 +8386,7 @@ class Actions
|
||||||
'Folder' => $mResponse->FolderName,
|
'Folder' => $mResponse->FolderName,
|
||||||
'FolderHash' => $mResponse->FolderHash,
|
'FolderHash' => $mResponse->FolderHash,
|
||||||
'UidNext' => $mResponse->UidNext,
|
'UidNext' => $mResponse->UidNext,
|
||||||
|
'Optimized' => $mResponse->Optimized,
|
||||||
'NewMessages' => $this->responseObject($mResponse->NewMessages),
|
'NewMessages' => $this->responseObject($mResponse->NewMessages),
|
||||||
'LastCollapsedThreadUids' => $mResponse->LastCollapsedThreadUids,
|
'LastCollapsedThreadUids' => $mResponse->LastCollapsedThreadUids,
|
||||||
'Offset' => $mResponse->Offset,
|
'Offset' => $mResponse->Offset,
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class Application extends \RainLoop\Config\AbstractConfig
|
||||||
$sConfigPassword = (string) $this->Get('security', 'admin_password', '');
|
$sConfigPassword = (string) $this->Get('security', 'admin_password', '');
|
||||||
|
|
||||||
return 0 < \strlen($sPassword) &&
|
return 0 < \strlen($sPassword) &&
|
||||||
($sPassword === $sConfigPassword || \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword);
|
(($sPassword === $sConfigPassword && '12345' === $sConfigPassword) || \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -193,11 +193,6 @@ Examples:
|
||||||
'enable' => array(false, 'Special option required for development purposes')
|
'enable' => array(false, 'Special option required for development purposes')
|
||||||
),
|
),
|
||||||
|
|
||||||
'version' => array(
|
|
||||||
'current' => array(''),
|
|
||||||
'saved' => array('')
|
|
||||||
),
|
|
||||||
|
|
||||||
'social' => array(
|
'social' => array(
|
||||||
'google_enable' => array(false, 'Google'),
|
'google_enable' => array(false, 'Google'),
|
||||||
'google_enable_auth' => array(false),
|
'google_enable_auth' => array(false),
|
||||||
|
|
@ -271,6 +266,7 @@ Enables caching in the system'),
|
||||||
'imap_message_list_count_limit_trigger' => array(0),
|
'imap_message_list_count_limit_trigger' => array(0),
|
||||||
'imap_message_list_date_filter' => array(0),
|
'imap_message_list_date_filter' => array(0),
|
||||||
'imap_large_thread_limit' => array(100),
|
'imap_large_thread_limit' => array(100),
|
||||||
|
'imap_folder_list_limit' => array(200),
|
||||||
'smtp_show_server_errors' => array(false),
|
'smtp_show_server_errors' => array(false),
|
||||||
'curl_proxy' => array(''),
|
'curl_proxy' => array(''),
|
||||||
'curl_proxy_auth' => array(''),
|
'curl_proxy_auth' => array(''),
|
||||||
|
|
@ -287,6 +283,11 @@ Enables caching in the system'),
|
||||||
'use_local_proxy_for_external_images' => array(false),
|
'use_local_proxy_for_external_images' => array(false),
|
||||||
'dev_email' => array(''),
|
'dev_email' => array(''),
|
||||||
'dev_password' => array('')
|
'dev_password' => array('')
|
||||||
|
),
|
||||||
|
|
||||||
|
'version' => array(
|
||||||
|
'current' => array(''),
|
||||||
|
'saved' => array('')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="subjectParent actionHandle dragHandle">
|
<div class="subjectParent actionHandle dragHandle">
|
||||||
<b style="color:red;margin-right:5px" data-bind="visible: isImportant">!</b>
|
<b class="importantMark">!</b>
|
||||||
<span class="subject emptySubjectText" data-bind="text: $root.emptySubjectValue"></span>
|
<span class="subject emptySubjectText" data-bind="text: $root.emptySubjectValue"></span>
|
||||||
<span class="subject-prefix" data-bind="text: subjectPrefix"></span><span class="subject-suffix" data-bind="text: subjectSuffix"></span>
|
<span class="subject-prefix" data-bind="text: subjectPrefix"></span><span class="subject-suffix" data-bind="text: subjectSuffix"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="subjectParent actionHandle dragHandle">
|
<div class="subjectParent actionHandle dragHandle">
|
||||||
<b style="color:red;margin-right:5px" data-bind="visible: isImportant">!</b>
|
<b class="importantMark">!</b>
|
||||||
<span class="subject emptySubjectText" data-bind="text: $root.emptySubjectValue"></span>
|
<span class="subject emptySubjectText" data-bind="text: $root.emptySubjectValue"></span>
|
||||||
<span class="subject-prefix" data-bind="text: subjectPrefix"></span><span class="subject-suffix" data-bind="text: subjectSuffix"></span>
|
<span class="subject-prefix" data-bind="text: subjectPrefix"></span><span class="subject-suffix" data-bind="text: subjectSuffix"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -308,12 +308,14 @@
|
||||||
<div class="hidePreview">
|
<div class="hidePreview">
|
||||||
<div class="iconMain">
|
<div class="iconMain">
|
||||||
<i class="attachmentIcon attachmentMainIcon" data-bind="css: iconClass()"></i>
|
<i class="attachmentIcon attachmentMainIcon" data-bind="css: iconClass()"></i>
|
||||||
|
<i class="attachmentIconText attachmentMainIconText" data-bind="text: iconText()"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="showPreview">
|
<div class="showPreview">
|
||||||
<a data-bind="css: {'attachmentImagePreview': isImage()}, attr: {'href': linkPreviewMain(), 'data-index': $index}" target="_blank">
|
<a data-bind="css: {'attachmentImagePreview': isImage()}, attr: {'href': linkPreviewMain(), 'data-index': $index}" target="_blank">
|
||||||
<div class="iconMain">
|
<div class="iconMain">
|
||||||
<i class="attachmentIcon attachmentMainIcon" data-bind="css: iconClass()"></i>
|
<i class="attachmentIcon attachmentMainIcon" data-bind="css: iconClass()"></i>
|
||||||
|
<i class="attachmentIconText attachmentMainIconText" data-bind="text: iconText()"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="iconBG" data-bind="attr: { 'style': linkThumbnailPreviewStyle() }"></div>
|
<div class="iconBG" data-bind="attr: { 'style': linkThumbnailPreviewStyle() }"></div>
|
||||||
<div class="iconPreview">
|
<div class="iconPreview">
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="modal hide b-compose" data-backdrop="static" data-bind="modal: modalVisibility, css: {'loading': saving() || sending()}">
|
<div class="modal hide b-compose" data-backdrop="static" data-bind="modal: modalVisibility, css: {'loading': saving() || sending()}">
|
||||||
<div class="modal-header b-header-toolbar g-ui-user-select-none">
|
<div class="modal-header b-header-toolbar g-ui-user-select-none">
|
||||||
<a class="btn btn-large button-send" data-bind="command: sendCommand, css: {'btn-danger': sendError, 'btn-warning': sendSuccessButSaveError }">
|
<a class="btn btn-large button-send" data-bind="command: sendCommand, css: {'btn-danger': sendError, 'btn-warning': sendSuccessButSaveError }">
|
||||||
<i data-bind="css: {'icon-paper-plane': !sending(), 'icon-spinner animated': sending(), 'icon-white': sendError() || sendSuccessButSaveError()}"></i>
|
<i data-bind="css: {'icon-paper-plane': !sending(), 'icon-spinner animated big': sending(), 'icon-white': sendError() || sendSuccessButSaveError()}"></i>
|
||||||
|
|
||||||
<span class="i18n" data-i18n-text="COMPOSE/BUTTON_SEND"></span>
|
<span class="i18n" data-i18n-text="COMPOSE/BUTTON_SEND"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
589
vendors/knockout-punches/knockout.punches.js
vendored
Normal file
589
vendors/knockout-punches/knockout.punches.js
vendored
Normal file
|
|
@ -0,0 +1,589 @@
|
||||||
|
/**
|
||||||
|
* @license Knockout.Punches
|
||||||
|
* Enhanced binding syntaxes for Knockout 3+
|
||||||
|
* (c) Michael Best
|
||||||
|
* License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
* Version 0.5.0
|
||||||
|
*/
|
||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as an anonymous module.
|
||||||
|
define(['knockout'], factory);
|
||||||
|
} else {
|
||||||
|
// Browser globals
|
||||||
|
factory(ko);
|
||||||
|
}
|
||||||
|
}(function(ko) {
|
||||||
|
|
||||||
|
// Add a preprocess function to a binding handler.
|
||||||
|
function addBindingPreprocessor(bindingKeyOrHandler, preprocessFn) {
|
||||||
|
return chainPreprocessor(getOrCreateHandler(bindingKeyOrHandler), 'preprocess', preprocessFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These utility functions are separated out because they're also used by
|
||||||
|
// preprocessBindingProperty
|
||||||
|
|
||||||
|
// Get the binding handler or create a new, empty one
|
||||||
|
function getOrCreateHandler(bindingKeyOrHandler) {
|
||||||
|
return typeof bindingKeyOrHandler === 'object' ? bindingKeyOrHandler :
|
||||||
|
(ko.getBindingHandler(bindingKeyOrHandler) || (ko.bindingHandlers[bindingKeyOrHandler] = {}));
|
||||||
|
}
|
||||||
|
// Add a preprocess function
|
||||||
|
function chainPreprocessor(obj, prop, fn) {
|
||||||
|
if (obj[prop]) {
|
||||||
|
// If the handler already has a preprocess function, chain the new
|
||||||
|
// one after the existing one. If the previous function in the chain
|
||||||
|
// returns a falsy value (to remove the binding), the chain ends. This
|
||||||
|
// method allows each function to modify and return the binding value.
|
||||||
|
var previousFn = obj[prop];
|
||||||
|
obj[prop] = function(value, binding, addBinding) {
|
||||||
|
value = previousFn.call(this, value, binding, addBinding);
|
||||||
|
if (value)
|
||||||
|
return fn.call(this, value, binding, addBinding);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
obj[prop] = fn;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a preprocessNode function to the binding provider. If a
|
||||||
|
// function already exists, chain the new one after it. This calls
|
||||||
|
// each function in the chain until one modifies the node. This
|
||||||
|
// method allows only one function to modify the node.
|
||||||
|
function addNodePreprocessor(preprocessFn) {
|
||||||
|
var provider = ko.bindingProvider.instance;
|
||||||
|
if (provider.preprocessNode) {
|
||||||
|
var previousPreprocessFn = provider.preprocessNode;
|
||||||
|
provider.preprocessNode = function(node) {
|
||||||
|
var newNodes = previousPreprocessFn.call(this, node);
|
||||||
|
if (!newNodes)
|
||||||
|
newNodes = preprocessFn.call(this, node);
|
||||||
|
return newNodes;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
provider.preprocessNode = preprocessFn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addBindingHandlerCreator(matchRegex, callbackFn) {
|
||||||
|
var oldGetHandler = ko.getBindingHandler;
|
||||||
|
ko.getBindingHandler = function(bindingKey) {
|
||||||
|
var match;
|
||||||
|
return oldGetHandler(bindingKey) || ((match = bindingKey.match(matchRegex)) && callbackFn(match, bindingKey));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create shortcuts to commonly used ko functions
|
||||||
|
var ko_unwrap = ko.unwrap;
|
||||||
|
|
||||||
|
// Create "punches" object and export utility functions
|
||||||
|
var ko_punches = ko.punches = {
|
||||||
|
utils: {
|
||||||
|
addBindingPreprocessor: addBindingPreprocessor,
|
||||||
|
addNodePreprocessor: addNodePreprocessor,
|
||||||
|
addBindingHandlerCreator: addBindingHandlerCreator,
|
||||||
|
|
||||||
|
// previous names retained for backwards compitibility
|
||||||
|
setBindingPreprocessor: addBindingPreprocessor,
|
||||||
|
setNodePreprocessor: addNodePreprocessor
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ko_punches.enableAll = function () {
|
||||||
|
// Enable interpolation markup
|
||||||
|
enableInterpolationMarkup();
|
||||||
|
enableAttributeInterpolationMarkup();
|
||||||
|
|
||||||
|
// Enable auto-namspacing of attr, css, event, and style
|
||||||
|
enableAutoNamespacedSyntax('attr');
|
||||||
|
enableAutoNamespacedSyntax('css');
|
||||||
|
enableAutoNamespacedSyntax('event');
|
||||||
|
enableAutoNamespacedSyntax('style');
|
||||||
|
|
||||||
|
// Enable filter syntax for text, html, and attr
|
||||||
|
enableTextFilter('text');
|
||||||
|
enableTextFilter('html');
|
||||||
|
addDefaultNamespacedBindingPreprocessor('attr', filterPreprocessor);
|
||||||
|
|
||||||
|
// Enable wrapped callbacks for click, submit, event, optionsAfterRender, and template options
|
||||||
|
enableWrappedCallback('click');
|
||||||
|
enableWrappedCallback('submit');
|
||||||
|
enableWrappedCallback('optionsAfterRender');
|
||||||
|
addDefaultNamespacedBindingPreprocessor('event', wrappedCallbackPreprocessor);
|
||||||
|
addBindingPropertyPreprocessor('template', 'beforeRemove', wrappedCallbackPreprocessor);
|
||||||
|
addBindingPropertyPreprocessor('template', 'afterAdd', wrappedCallbackPreprocessor);
|
||||||
|
addBindingPropertyPreprocessor('template', 'afterRender', wrappedCallbackPreprocessor);
|
||||||
|
};
|
||||||
|
// Convert input in the form of `expression | filter1 | filter2:arg1:arg2` to a function call format
|
||||||
|
// with filters accessed as ko.filters.filter1, etc.
|
||||||
|
function filterPreprocessor(input) {
|
||||||
|
// Check if the input contains any | characters; if not, just return
|
||||||
|
if (input.indexOf('|') === -1)
|
||||||
|
return input;
|
||||||
|
|
||||||
|
// Split the input into tokens, in which | and : are individual tokens, quoted strings are ignored, and all tokens are space-trimmed
|
||||||
|
var tokens = input.match(/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'|\|\||[|:]|[^\s|:"'][^|:"']*[^\s|:"']|[^\s|:"']/g);
|
||||||
|
if (tokens && tokens.length > 1) {
|
||||||
|
// Append a line so that we don't need a separate code block to deal with the last item
|
||||||
|
tokens.push('|');
|
||||||
|
input = tokens[0];
|
||||||
|
var lastToken, token, inFilters = false, nextIsFilter = false;
|
||||||
|
for (var i = 1, token; token = tokens[i]; ++i) {
|
||||||
|
if (token === '|') {
|
||||||
|
if (inFilters) {
|
||||||
|
if (lastToken === ':')
|
||||||
|
input += "undefined";
|
||||||
|
input += ')';
|
||||||
|
}
|
||||||
|
nextIsFilter = true;
|
||||||
|
inFilters = true;
|
||||||
|
} else {
|
||||||
|
if (nextIsFilter) {
|
||||||
|
input = "ko.filters['" + token + "'](" + input;
|
||||||
|
} else if (inFilters && token === ':') {
|
||||||
|
if (lastToken === ':')
|
||||||
|
input += "undefined";
|
||||||
|
input += ",";
|
||||||
|
} else {
|
||||||
|
input += token;
|
||||||
|
}
|
||||||
|
nextIsFilter = false;
|
||||||
|
}
|
||||||
|
lastToken = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the filter preprocessor for a specific binding
|
||||||
|
function enableTextFilter(bindingKeyOrHandler) {
|
||||||
|
addBindingPreprocessor(bindingKeyOrHandler, filterPreprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
var filters = {};
|
||||||
|
|
||||||
|
// Convert value to uppercase
|
||||||
|
filters.uppercase = function(value) {
|
||||||
|
return String.prototype.toUpperCase.call(ko_unwrap(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert value to lowercase
|
||||||
|
filters.lowercase = function(value) {
|
||||||
|
return String.prototype.toLowerCase.call(ko_unwrap(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return default value if the input value is empty or null
|
||||||
|
filters['default'] = function (value, defaultValue) {
|
||||||
|
value = ko_unwrap(value);
|
||||||
|
if (typeof value === "function") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return trim(value) === '' ? defaultValue : value;
|
||||||
|
}
|
||||||
|
return value == null || value.length == 0 ? defaultValue : value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return the value with the search string replaced with the replacement string
|
||||||
|
filters.replace = function(value, search, replace) {
|
||||||
|
return String.prototype.replace.call(ko_unwrap(value), search, replace);
|
||||||
|
};
|
||||||
|
|
||||||
|
filters.fit = function(value, length, replacement, trimWhere) {
|
||||||
|
value = ko_unwrap(value);
|
||||||
|
if (length && ('' + value).length > length) {
|
||||||
|
replacement = '' + (replacement || '...');
|
||||||
|
length = length - replacement.length;
|
||||||
|
value = '' + value;
|
||||||
|
switch (trimWhere) {
|
||||||
|
case 'left':
|
||||||
|
return replacement + value.slice(-length);
|
||||||
|
case 'middle':
|
||||||
|
var leftLen = Math.ceil(length / 2);
|
||||||
|
return value.substr(0, leftLen) + replacement + value.slice(leftLen-length);
|
||||||
|
default:
|
||||||
|
return value.substr(0, length) + replacement;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert a model object to JSON
|
||||||
|
filters.json = function(rootObject, space, replacer) { // replacer and space are optional
|
||||||
|
return ko.toJSON(rootObject, replacer, space);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Format a number using the browser's toLocaleString
|
||||||
|
filters.number = function(value) {
|
||||||
|
return (+ko_unwrap(value)).toLocaleString();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export the filters object for general access
|
||||||
|
ko.filters = filters;
|
||||||
|
|
||||||
|
// Export the preprocessor functions
|
||||||
|
ko_punches.textFilter = {
|
||||||
|
preprocessor: filterPreprocessor,
|
||||||
|
enableForBinding: enableTextFilter
|
||||||
|
};
|
||||||
|
// Support dynamically-created, namespaced bindings. The binding key syntax is
|
||||||
|
// "namespace.binding". Within a certain namespace, we can dynamically create the
|
||||||
|
// handler for any binding. This is particularly useful for bindings that work
|
||||||
|
// the same way, but just set a different named value, such as for element
|
||||||
|
// attributes or CSS classes.
|
||||||
|
var namespacedBindingMatch = /([^\.]+)\.(.+)/, namespaceDivider = '.';
|
||||||
|
addBindingHandlerCreator(namespacedBindingMatch, function (match, bindingKey) {
|
||||||
|
var namespace = match[1],
|
||||||
|
namespaceHandler = ko.bindingHandlers[namespace];
|
||||||
|
if (namespaceHandler) {
|
||||||
|
var bindingName = match[2],
|
||||||
|
handlerFn = namespaceHandler.getNamespacedHandler || defaultGetNamespacedHandler,
|
||||||
|
handler = handlerFn.call(namespaceHandler, bindingName, namespace, bindingKey);
|
||||||
|
ko.bindingHandlers[bindingKey] = handler;
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Knockout's built-in bindings "attr", "event", "css" and "style" include the idea of
|
||||||
|
// namespaces, representing it using a single binding that takes an object map of names
|
||||||
|
// to values. This default handler translates a binding of "namespacedName: value"
|
||||||
|
// to "namespace: {name: value}" to automatically support those built-in bindings.
|
||||||
|
function defaultGetNamespacedHandler(name, namespace, namespacedName) {
|
||||||
|
var handler = ko.utils.extend({}, this);
|
||||||
|
function setHandlerFunction(funcName) {
|
||||||
|
if (handler[funcName]) {
|
||||||
|
handler[funcName] = function(element, valueAccessor) {
|
||||||
|
function subValueAccessor() {
|
||||||
|
var result = {};
|
||||||
|
result[name] = valueAccessor();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
var args = Array.prototype.slice.call(arguments, 0);
|
||||||
|
args[1] = subValueAccessor;
|
||||||
|
return ko.bindingHandlers[namespace][funcName].apply(this, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set new init and update functions that wrap the originals
|
||||||
|
setHandlerFunction('init');
|
||||||
|
setHandlerFunction('update');
|
||||||
|
// Clear any preprocess function since preprocessing of the new binding would need to be different
|
||||||
|
if (handler.preprocess)
|
||||||
|
handler.preprocess = null;
|
||||||
|
if (ko.virtualElements.allowedBindings[namespace])
|
||||||
|
ko.virtualElements.allowedBindings[namespacedName] = true;
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a preprocess function for every generated namespace.x binding. This can
|
||||||
|
// be called multiple times for the same binding, and the preprocess functions will
|
||||||
|
// be chained. If the binding has a custom getNamespacedHandler method, make sure that
|
||||||
|
// it's set before this function is used.
|
||||||
|
function addDefaultNamespacedBindingPreprocessor(namespace, preprocessFn) {
|
||||||
|
var handler = ko.getBindingHandler(namespace);
|
||||||
|
if (handler) {
|
||||||
|
var previousHandlerFn = handler.getNamespacedHandler || defaultGetNamespacedHandler;
|
||||||
|
handler.getNamespacedHandler = function() {
|
||||||
|
return addBindingPreprocessor(previousHandlerFn.apply(this, arguments), preprocessFn);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoNamespacedPreprocessor(value, binding, addBinding) {
|
||||||
|
if (value.charAt(0) !== "{")
|
||||||
|
return value;
|
||||||
|
|
||||||
|
// Handle two-level binding specified as "binding: {key: value}" by parsing inner
|
||||||
|
// object and converting to "binding.key: value"
|
||||||
|
var subBindings = ko.expressionRewriting.parseObjectLiteral(value);
|
||||||
|
ko.utils.arrayForEach(subBindings, function(keyValue) {
|
||||||
|
addBinding(binding + namespaceDivider + keyValue.key, keyValue.value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the namespaced preprocessor for a specific binding
|
||||||
|
function enableAutoNamespacedSyntax(bindingKeyOrHandler) {
|
||||||
|
addBindingPreprocessor(bindingKeyOrHandler, autoNamespacedPreprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the preprocessor functions
|
||||||
|
ko_punches.namespacedBinding = {
|
||||||
|
defaultGetHandler: defaultGetNamespacedHandler,
|
||||||
|
setDefaultBindingPreprocessor: addDefaultNamespacedBindingPreprocessor, // for backwards compat.
|
||||||
|
addDefaultBindingPreprocessor: addDefaultNamespacedBindingPreprocessor,
|
||||||
|
preprocessor: autoNamespacedPreprocessor,
|
||||||
|
enableForBinding: enableAutoNamespacedSyntax
|
||||||
|
};
|
||||||
|
// Wrap a callback function in an anonymous function so that it is called with the appropriate
|
||||||
|
// "this" value.
|
||||||
|
function wrappedCallbackPreprocessor(val) {
|
||||||
|
// Matches either an isolated identifier or something ending with a property accessor
|
||||||
|
if (/^([$_a-z][$\w]*|.+(\.\s*[$_a-z][$\w]*|\[.+\]))$/i.test(val)) {
|
||||||
|
return 'function(_x,_y,_z){return(' + val + ')(_x,_y,_z);}';
|
||||||
|
} else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the wrappedCallback preprocessor for a specific binding
|
||||||
|
function enableWrappedCallback(bindingKeyOrHandler) {
|
||||||
|
addBindingPreprocessor(bindingKeyOrHandler, wrappedCallbackPreprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the preprocessor functions
|
||||||
|
ko_punches.wrappedCallback = {
|
||||||
|
preprocessor: wrappedCallbackPreprocessor,
|
||||||
|
enableForBinding: enableWrappedCallback
|
||||||
|
};
|
||||||
|
// Attach a preprocess function to a specific property of a binding. This allows you to
|
||||||
|
// preprocess binding "options" using the same preprocess functions that work for bindings.
|
||||||
|
function addBindingPropertyPreprocessor(bindingKeyOrHandler, property, preprocessFn) {
|
||||||
|
var handler = getOrCreateHandler(bindingKeyOrHandler);
|
||||||
|
if (!handler._propertyPreprocessors) {
|
||||||
|
// Initialize the binding preprocessor
|
||||||
|
chainPreprocessor(handler, 'preprocess', propertyPreprocessor);
|
||||||
|
handler._propertyPreprocessors = {};
|
||||||
|
}
|
||||||
|
// Add the property preprocess function
|
||||||
|
chainPreprocessor(handler._propertyPreprocessors, property, preprocessFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In order to preprocess a binding property, we have to preprocess the binding itself.
|
||||||
|
// This preprocess function splits up the binding value and runs each property's preprocess
|
||||||
|
// function if it's set.
|
||||||
|
function propertyPreprocessor(value, binding, addBinding) {
|
||||||
|
if (value.charAt(0) !== "{")
|
||||||
|
return value;
|
||||||
|
|
||||||
|
var subBindings = ko.expressionRewriting.parseObjectLiteral(value),
|
||||||
|
resultStrings = [],
|
||||||
|
propertyPreprocessors = this._propertyPreprocessors || {};
|
||||||
|
ko.utils.arrayForEach(subBindings, function(keyValue) {
|
||||||
|
var prop = keyValue.key, propVal = keyValue.value;
|
||||||
|
if (propertyPreprocessors[prop]) {
|
||||||
|
propVal = propertyPreprocessors[prop](propVal, prop, addBinding);
|
||||||
|
}
|
||||||
|
if (propVal) {
|
||||||
|
resultStrings.push("'" + prop + "':" + propVal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return "{" + resultStrings.join(",") + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the preprocessor functions
|
||||||
|
ko_punches.preprocessBindingProperty = {
|
||||||
|
setPreprocessor: addBindingPropertyPreprocessor, // for backwards compat.
|
||||||
|
addPreprocessor: addBindingPropertyPreprocessor
|
||||||
|
};
|
||||||
|
// Wrap an expression in an anonymous function so that it is called when the event happens
|
||||||
|
function makeExpressionCallbackPreprocessor(args) {
|
||||||
|
return function expressionCallbackPreprocessor(val) {
|
||||||
|
return 'function('+args+'){return(' + val + ');}';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventExpressionPreprocessor = makeExpressionCallbackPreprocessor("$data,$event");
|
||||||
|
|
||||||
|
// Set the expressionCallback preprocessor for a specific binding
|
||||||
|
function enableExpressionCallback(bindingKeyOrHandler, args) {
|
||||||
|
var args = Array.prototype.slice.call(arguments, 1).join();
|
||||||
|
addBindingPreprocessor(bindingKeyOrHandler, makeExpressionCallbackPreprocessor(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the preprocessor functions
|
||||||
|
ko_punches.expressionCallback = {
|
||||||
|
makePreprocessor: makeExpressionCallbackPreprocessor,
|
||||||
|
eventPreprocessor: eventExpressionPreprocessor,
|
||||||
|
enableForBinding: enableExpressionCallback
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create an "on" namespace for events to use the expression method
|
||||||
|
ko.bindingHandlers.on = {
|
||||||
|
getNamespacedHandler: function(eventName) {
|
||||||
|
var handler = ko.getBindingHandler('event' + namespaceDivider + eventName);
|
||||||
|
return addBindingPreprocessor(handler, eventExpressionPreprocessor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Performance comparison at http://jsperf.com/markup-interpolation-comparison
|
||||||
|
function parseInterpolationMarkup(textToParse, outerTextCallback, expressionCallback) {
|
||||||
|
function innerParse(text) {
|
||||||
|
var innerMatch = text.match(/^([\s\S]*)}}([\s\S]*?)\{\{([\s\S]*)$/);
|
||||||
|
if (innerMatch) {
|
||||||
|
innerParse(innerMatch[1]);
|
||||||
|
outerTextCallback(innerMatch[2]);
|
||||||
|
expressionCallback(innerMatch[3]);
|
||||||
|
} else {
|
||||||
|
expressionCallback(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var outerMatch = textToParse.match(/^([\s\S]*?)\{\{([\s\S]*)}}([\s\S]*)$/);
|
||||||
|
if (outerMatch) {
|
||||||
|
outerTextCallback(outerMatch[1]);
|
||||||
|
innerParse(outerMatch[2]);
|
||||||
|
outerTextCallback(outerMatch[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function trim(string) {
|
||||||
|
return string == null ? '' :
|
||||||
|
string.trim ?
|
||||||
|
string.trim() :
|
||||||
|
string.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function interpolationMarkupPreprocessor(node) {
|
||||||
|
// only needs to work with text nodes
|
||||||
|
if (node.nodeType === 3 && node.nodeValue && node.nodeValue.indexOf('{{') !== -1 && (node.parentNode || {}).nodeName != "TEXTAREA") {
|
||||||
|
var nodes = [];
|
||||||
|
function addTextNode(text) {
|
||||||
|
if (text)
|
||||||
|
nodes.push(document.createTextNode(text));
|
||||||
|
}
|
||||||
|
function wrapExpr(expressionText) {
|
||||||
|
if (expressionText)
|
||||||
|
nodes.push.apply(nodes, ko_punches_interpolationMarkup.wrapExpression(expressionText, node));
|
||||||
|
}
|
||||||
|
parseInterpolationMarkup(node.nodeValue, addTextNode, wrapExpr)
|
||||||
|
|
||||||
|
if (nodes.length) {
|
||||||
|
if (node.parentNode) {
|
||||||
|
for (var i = 0, n = nodes.length, parent = node.parentNode; i < n; ++i) {
|
||||||
|
parent.insertBefore(nodes[i], node);
|
||||||
|
}
|
||||||
|
parent.removeChild(node);
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ko.virtualElements.allowedBindings.html) {
|
||||||
|
// Virtual html binding
|
||||||
|
// SO Question: http://stackoverflow.com/a/15348139
|
||||||
|
var overridden = ko.bindingHandlers.html.update;
|
||||||
|
ko.bindingHandlers.html.update = function (element, valueAccessor) {
|
||||||
|
if (element.nodeType === 8) {
|
||||||
|
var html = ko_unwrap(valueAccessor());
|
||||||
|
if (html != null) {
|
||||||
|
var parsedNodes = ko.utils.parseHtmlFragment('' + html);
|
||||||
|
ko.virtualElements.setDomNodeChildren(element, parsedNodes);
|
||||||
|
} else {
|
||||||
|
ko.virtualElements.emptyNode(element);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
overridden(element, valueAccessor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ko.virtualElements.allowedBindings.html = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapExpression(expressionText, node) {
|
||||||
|
var ownerDocument = node ? node.ownerDocument : document,
|
||||||
|
closeComment = true,
|
||||||
|
binding,
|
||||||
|
firstChar = expressionText[0],
|
||||||
|
lastChar = expressionText[expressionText.length - 1],
|
||||||
|
result = [],
|
||||||
|
matches;
|
||||||
|
|
||||||
|
if (firstChar === '#') {
|
||||||
|
if (lastChar === '/') {
|
||||||
|
binding = expressionText.slice(1, -1);
|
||||||
|
} else {
|
||||||
|
binding = expressionText.slice(1);
|
||||||
|
closeComment = false;
|
||||||
|
}
|
||||||
|
if (matches = binding.match(/^([^,"'{}()\/:[\]\s]+)\s+([^\s:].*)/)) {
|
||||||
|
binding = matches[1] + ':' + matches[2];
|
||||||
|
}
|
||||||
|
} else if (firstChar === '/') {
|
||||||
|
// replace only with a closing comment
|
||||||
|
} else if (firstChar === '{' && lastChar === '}') {
|
||||||
|
binding = "html:" + trim(expressionText.slice(1, -1));
|
||||||
|
} else {
|
||||||
|
binding = "text:" + trim(expressionText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding)
|
||||||
|
result.push(ownerDocument.createComment("ko " + binding));
|
||||||
|
if (closeComment)
|
||||||
|
result.push(ownerDocument.createComment("/ko"));
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
function enableInterpolationMarkup() {
|
||||||
|
addNodePreprocessor(interpolationMarkupPreprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the preprocessor functions
|
||||||
|
var ko_punches_interpolationMarkup = ko_punches.interpolationMarkup = {
|
||||||
|
preprocessor: interpolationMarkupPreprocessor,
|
||||||
|
enable: enableInterpolationMarkup,
|
||||||
|
wrapExpression: wrapExpression
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var dataBind = 'data-bind';
|
||||||
|
function attributeInterpolationMarkerPreprocessor(node) {
|
||||||
|
if (node.nodeType === 1 && node.attributes.length) {
|
||||||
|
var dataBindAttribute = node.getAttribute(dataBind);
|
||||||
|
for (var attrs = ko.utils.arrayPushAll([], node.attributes), n = attrs.length, i = 0; i < n; ++i) {
|
||||||
|
var attr = attrs[i];
|
||||||
|
if (attr.specified && attr.name != dataBind && attr.value.indexOf('{{') !== -1) {
|
||||||
|
var parts = [], attrValue = '';
|
||||||
|
function addText(text) {
|
||||||
|
if (text)
|
||||||
|
parts.push('"' + text.replace(/"/g, '\\"') + '"');
|
||||||
|
}
|
||||||
|
function addExpr(expressionText) {
|
||||||
|
if (expressionText) {
|
||||||
|
attrValue = expressionText;
|
||||||
|
parts.push('ko.unwrap(' + expressionText + ')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseInterpolationMarkup(attr.value, addText, addExpr);
|
||||||
|
|
||||||
|
if (parts.length > 1) {
|
||||||
|
attrValue = '""+' + parts.join('+');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrValue) {
|
||||||
|
var attrName = attr.name.toLowerCase();
|
||||||
|
var attrBinding = ko_punches_attributeInterpolationMarkup.attributeBinding(attrName, attrValue, node) || attributeBinding(attrName, attrValue, node);
|
||||||
|
if (!dataBindAttribute) {
|
||||||
|
dataBindAttribute = attrBinding
|
||||||
|
} else {
|
||||||
|
dataBindAttribute += ',' + attrBinding;
|
||||||
|
}
|
||||||
|
node.setAttribute(dataBind, dataBindAttribute);
|
||||||
|
// Using removeAttribute instead of removeAttributeNode because IE clears the
|
||||||
|
// class if you use removeAttributeNode to remove the id.
|
||||||
|
node.removeAttribute(attr.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function attributeBinding(name, value, node) {
|
||||||
|
if (ko.getBindingHandler(name)) {
|
||||||
|
return name + ':' + value;
|
||||||
|
} else {
|
||||||
|
return 'attr.' + name + ':' + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableAttributeInterpolationMarkup() {
|
||||||
|
addNodePreprocessor(attributeInterpolationMarkerPreprocessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ko_punches_attributeInterpolationMarkup = ko_punches.attributeInterpolationMarkup = {
|
||||||
|
preprocessor: attributeInterpolationMarkerPreprocessor,
|
||||||
|
enable: enableAttributeInterpolationMarkup,
|
||||||
|
attributeBinding: attributeBinding
|
||||||
|
};
|
||||||
|
|
||||||
|
return ko_punches;
|
||||||
|
}));
|
||||||
20
vendors/knockout-punches/knockout.punches.min.js
vendored
Normal file
20
vendors/knockout-punches/knockout.punches.min.js
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
Knockout.Punches
|
||||||
|
Enhanced binding syntaxes for Knockout 3+
|
||||||
|
(c) Michael Best
|
||||||
|
License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
Version 0.5.0
|
||||||
|
*/
|
||||||
|
(function(c){"function"===typeof define&&define.amd?define(["knockout"],c):c(ko)})(function(c){function k(a,b){return u(B(a),"preprocess",b)}function B(a){return"object"===typeof a?a:c.getBindingHandler(a)||(c.bindingHandlers[a]={})}function u(a,b,d){if(a[b]){var g=a[b];a[b]=function(a,b,c){if(a=g.call(this,a,b,c))return d.call(this,a,b,c)}}else a[b]=d;return a}function r(a){var b=c.bindingProvider.instance;if(b.preprocessNode){var d=b.preprocessNode;b.preprocessNode=function(b){var c=d.call(this,
|
||||||
|
b);c||(c=a.call(this,b));return c}}else b.preprocessNode=a}function D(a,b){var d=c.getBindingHandler;c.getBindingHandler=function(g){var c;return d(g)||(c=g.match(a))&&b(c,g)}}function v(a){if(-1===a.indexOf("|"))return a;var b=a.match(/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'|\|\||[|:]|[^\s|:"'][^|:"']*[^\s|:"']|[^\s|:"']/g);if(b&&1<b.length){b.push("|");a=b[0];for(var d,c,e=!1,f=!1,C=1;c=b[C];++C)"|"===c?(e&&(":"===d&&(a+="undefined"),a+=")"),e=f=!0):(f?a="ko.filters['"+c+"']("+a:e&&":"===c?(":"===d&&(a+=
|
||||||
|
"undefined"),a+=","):a+=c,f=!1),d=c}return a}function w(a){k(a,v)}function x(a,b,d){function g(d){e[d]&&(e[d]=function(g,e){var h=Array.prototype.slice.call(arguments,0);h[1]=function(){var b={};b[a]=e();return b};return c.bindingHandlers[b][d].apply(this,h)})}var e=c.utils.extend({},this);g("init");g("update");e.preprocess&&(e.preprocess=null);c.virtualElements.allowedBindings[b]&&(c.virtualElements.allowedBindings[d]=!0);return e}function s(a,b){var d=c.getBindingHandler(a);if(d){var g=d.getNamespacedHandler||
|
||||||
|
x;d.getNamespacedHandler=function(){return k(g.apply(this,arguments),b)}}}function E(a,b,d){if("{"!==a.charAt(0))return a;a=c.expressionRewriting.parseObjectLiteral(a);c.utils.arrayForEach(a,function(a){d(b+F+a.key,a.value)})}function p(a){k(a,E)}function m(a){return/^([$_a-z][$\w]*|.+(\.\s*[$_a-z][$\w]*|\[.+\]))$/i.test(a)?"function(_x,_y,_z){return("+a+")(_x,_y,_z);}":a}function t(a){k(a,m)}function q(a,b,d){a=B(a);a._propertyPreprocessors||(u(a,"preprocess",N),a._propertyPreprocessors={});u(a._propertyPreprocessors,
|
||||||
|
b,d)}function N(a,b,d){if("{"!==a.charAt(0))return a;a=c.expressionRewriting.parseObjectLiteral(a);var g=[],e=this._propertyPreprocessors||{};c.utils.arrayForEach(a,function(a){var b=a.key;a=a.value;e[b]&&(a=e[b](a,b,d));a&&g.push("'"+b+"':"+a)});return"{"+g.join(",")+"}"}function y(a){return function(b){return"function("+a+"){return("+b+");}"}}function G(a,b,d){function c(a){var f=a.match(/^([\s\S]*)}}([\s\S]*?)\{\{([\s\S]*)$/);f?(c(f[1]),b(f[2]),d(f[3])):d(a)}if(a=a.match(/^([\s\S]*?)\{\{([\s\S]*)}}([\s\S]*)$/))b(a[1]),
|
||||||
|
c(a[2]),b(a[3])}function z(a){return null==a?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}function H(a){if(3===a.nodeType&&a.nodeValue&&-1!==a.nodeValue.indexOf("{{")&&"TEXTAREA"!=(a.parentNode||{}).nodeName){var b=[];G(a.nodeValue,function(a){a&&b.push(document.createTextNode(a))},function(d){d&&b.push.apply(b,O.wrapExpression(d,a))});if(b.length){if(a.parentNode){for(var d=0,c=b.length,e=a.parentNode;d<c;++d)e.insertBefore(b[d],a);e.removeChild(a)}return b}}}function I(){r(H)}
|
||||||
|
function J(a){if(1===a.nodeType&&a.attributes.length)for(var b=a.getAttribute(A),d=c.utils.arrayPushAll([],a.attributes),g=d.length,e=0;e<g;++e){var f=d[e];if(f.specified&&f.name!=A&&-1!==f.value.indexOf("{{")){var h=[],n="";G(f.value,function(a){a&&h.push('"'+a.replace(/"/g,'\\"')+'"')},function(a){a&&(n=a,h.push("ko.unwrap("+a+")"))});1<h.length&&(n='""+'+h.join("+"));if(n){var k=f.name.toLowerCase(),k=P.attributeBinding(k,n,a)||K(k,n,a),b=b?b+(","+k):k;a.setAttribute(A,b);a.removeAttribute(f.name)}}}}
|
||||||
|
function K(a,b,d){return c.getBindingHandler(a)?a+":"+b:"attr."+a+":"+b}function L(){r(J)}var l=c.unwrap,h=c.punches={utils:{addBindingPreprocessor:k,addNodePreprocessor:r,addBindingHandlerCreator:D,setBindingPreprocessor:k,setNodePreprocessor:r}};h.enableAll=function(){I();L();p("attr");p("css");p("event");p("style");w("text");w("html");s("attr",v);t("click");t("submit");t("optionsAfterRender");s("event",m);q("template","beforeRemove",m);q("template","afterAdd",m);q("template","afterRender",m)};
|
||||||
|
c.filters={uppercase:function(a){return String.prototype.toUpperCase.call(l(a))},lowercase:function(a){return String.prototype.toLowerCase.call(l(a))},"default":function(a,b){a=l(a);return"function"===typeof a?a:"string"===typeof a?""===z(a)?b:a:null==a||0==a.length?b:a},replace:function(a,b,d){return String.prototype.replace.call(l(a),b,d)},fit:function(a,b,d,c){a=l(a);if(b&&(""+a).length>b)switch(d=""+(d||"..."),b-=d.length,a=""+a,c){case "left":return d+a.slice(-b);case "middle":return c=Math.ceil(b/
|
||||||
|
2),a.substr(0,c)+d+a.slice(c-b);default:return a.substr(0,b)+d}else return a},json:function(a,b,d){return c.toJSON(a,d,b)},number:function(a){return(+l(a)).toLocaleString()}};h.textFilter={preprocessor:v,enableForBinding:w};var F=".";D(/([^\.]+)\.(.+)/,function(a,b){var d=a[1],g=c.bindingHandlers[d];if(g)return d=(g.getNamespacedHandler||x).call(g,a[2],d,b),c.bindingHandlers[b]=d});h.namespacedBinding={defaultGetHandler:x,setDefaultBindingPreprocessor:s,addDefaultBindingPreprocessor:s,preprocessor:E,
|
||||||
|
enableForBinding:p};h.wrappedCallback={preprocessor:m,enableForBinding:t};h.preprocessBindingProperty={setPreprocessor:q,addPreprocessor:q};var M=y("$data,$event");h.expressionCallback={makePreprocessor:y,eventPreprocessor:M,enableForBinding:function(a,b){b=Array.prototype.slice.call(arguments,1).join();k(a,y(b))}};c.bindingHandlers.on={getNamespacedHandler:function(a){a=c.getBindingHandler("event"+F+a);return k(a,M)}};if(!c.virtualElements.allowedBindings.html){var Q=c.bindingHandlers.html.update;
|
||||||
|
c.bindingHandlers.html.update=function(a,b){if(8===a.nodeType){var d=l(b());null!=d?(d=c.utils.parseHtmlFragment(""+d),c.virtualElements.setDomNodeChildren(a,d)):c.virtualElements.emptyNode(a)}else Q(a,b)};c.virtualElements.allowedBindings.html=!0}var O=h.interpolationMarkup={preprocessor:H,enable:I,wrapExpression:function(a,b){var d=b?b.ownerDocument:document,c=!0,e,f=a[0],h=a[a.length-1],k=[];if("#"===f){if("/"===h?e=a.slice(1,-1):(e=a.slice(1),c=!1),f=e.match(/^([^,"'{}()\/:[\]\s]+)\s+([^\s:].*)/))e=
|
||||||
|
f[1]+":"+f[2]}else"/"!==f&&(e="{"===f&&"}"===h?"html:"+z(a.slice(1,-1)):"text:"+z(a));e&&k.push(d.createComment("ko "+e));c&&k.push(d.createComment("/ko"));return k}},A="data-bind",P=h.attributeInterpolationMarkup={preprocessor:J,enable:L,attributeBinding:K};return h});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue