mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-02-10 07:21:04 +01:00
Mail tree phase 2 W.I.P.:
Add functionality to autoload index tree Some optimization
This commit is contained in:
parent
57a3c318ea
commit
d044e75c9c
@ -99,6 +99,7 @@ class mail_tree
|
|||||||
*/
|
*/
|
||||||
static function pathToFolderData ($_path, $_hDelimiter)
|
static function pathToFolderData ($_path, $_hDelimiter)
|
||||||
{
|
{
|
||||||
|
if (!strpos($_path, self::$delimiter)) $_path = self::$delimiter.$_path;
|
||||||
list(,$path) = explode(self::$delimiter, $_path);
|
list(,$path) = explode(self::$delimiter, $_path);
|
||||||
$path_chain = $parts = explode($_hDelimiter, $path);
|
$path_chain = $parts = explode($_hDelimiter, $path);
|
||||||
$name = array_pop($parts);
|
$name = array_pop($parts);
|
||||||
@ -127,6 +128,36 @@ class mail_tree
|
|||||||
return $hasChildren;
|
return $hasChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given tree id is account node (means root)
|
||||||
|
*
|
||||||
|
* @param type $_node a tree id node
|
||||||
|
* @return boolean returns true if the node is account node otherwise false
|
||||||
|
*/
|
||||||
|
private static function isAccountNode ($_node)
|
||||||
|
{
|
||||||
|
list(,$leaf) = explode(self::$delimiter, $_node);
|
||||||
|
if ($leaf || $_node == null) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate node level form the root
|
||||||
|
* @param type $_path tree node full path, e.g. INBOX/Drafts
|
||||||
|
*
|
||||||
|
* @return int returns node level distance from the root,
|
||||||
|
* returns false if something goes wrong
|
||||||
|
*/
|
||||||
|
private static function getNodeLevel($_path, $_delimiter = '.')
|
||||||
|
{
|
||||||
|
$parts = explode($_delimiter, $_path);
|
||||||
|
if (is_array($parts))
|
||||||
|
{
|
||||||
|
return count($parts);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getTree provides tree structure regarding to selected node
|
* getTree provides tree structure regarding to selected node
|
||||||
*
|
*
|
||||||
@ -135,10 +166,12 @@ class mail_tree
|
|||||||
* @param int|boolean $_openTopLevel = 1 Open top level folders on load if it's set to 1|true,
|
* @param int|boolean $_openTopLevel = 1 Open top level folders on load if it's set to 1|true,
|
||||||
* false|0 leaves them in closed state
|
* false|0 leaves them in closed state
|
||||||
* @param $_noCheckboxNS = false no checkbox for namesapaces makes sure to not put checkbox for namespaces node
|
* @param $_noCheckboxNS = false no checkbox for namesapaces makes sure to not put checkbox for namespaces node
|
||||||
|
* @param boolean $_subscribedOnly = false get only subscribed folders
|
||||||
|
* @param boolean $_getThemAll = false, true will get all folders of the account
|
||||||
*
|
*
|
||||||
* @return array returns an array of mail tree structure according to provided node
|
* @return array returns an array of mail tree structure according to provided node
|
||||||
*/
|
*/
|
||||||
function getTree ($_parent = null, $_profileID = '', $_openTopLevel = 1, $_noCheckboxNS = false)
|
function getTree ($_parent = null, $_profileID = '', $_openTopLevel = 1, $_noCheckboxNS = false, $_subscribedOnly= false, $_getThemAll = false)
|
||||||
{
|
{
|
||||||
//Init mail folders
|
//Init mail folders
|
||||||
$tree = array(tree::ID=> $_parent?$_parent:0,tree::CHILDREN => array());
|
$tree = array(tree::ID=> $_parent?$_parent:0,tree::CHILDREN => array());
|
||||||
@ -156,12 +189,21 @@ class mail_tree
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_parent) // Single node loader
|
// User defined folders based on account
|
||||||
|
$definedFolders = array(
|
||||||
|
'Trash' => $this->ui->mail_bo->getTrashFolder(false),
|
||||||
|
'Templates' => $this->ui->mail_bo->getTemplateFolder(false),
|
||||||
|
'Drafts' => $this->ui->mail_bo->getDraftFolder(false),
|
||||||
|
'Sent' => $this->ui->mail_bo->getSentFolder(false),
|
||||||
|
'Junk' => $this->ui->mail_bo->getJunkFolder(false),
|
||||||
|
'Outbox' => $this->ui->mail_bo->getOutboxFolder(false),
|
||||||
|
);
|
||||||
|
if ($_parent && !self::isAccountNode($_parent)) // Single node loader
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$nodeInfo = self::pathToFolderData($_parent, $hDelimiter);
|
$nodeInfo = self::pathToFolderData($_parent, $hDelimiter);
|
||||||
$folders = $this->ui->mail_bo->getFolderArrays($nodeInfo['mailbox'],false,2);
|
$folders = $this->ui->mail_bo->getFolderArrays($nodeInfo['mailbox'],false,$_getThemAll?0:2, $_subscribedOnly);
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
return self::treeLeafNoConnectionArray($_profileID, $ex->getMessage(),array($_profileID), '');
|
return self::treeLeafNoConnectionArray($_profileID, $ex->getMessage(),array($_profileID), '');
|
||||||
}
|
}
|
||||||
@ -188,132 +230,47 @@ class mail_tree
|
|||||||
}
|
}
|
||||||
else //Top Level Nodes loader
|
else //Top Level Nodes loader
|
||||||
{
|
{
|
||||||
$baseNode = array('id' => 0);
|
if (self::isAccountNode($_parent))
|
||||||
foreach(emailadmin_account::search(true, false) as $acc_id => $accObj)
|
|
||||||
{
|
{
|
||||||
if (!$accObj->is_imap()|| $acc_id != $_profileID) continue;
|
$_openTopLevel = 1;
|
||||||
$identity = emailadmin_account::identity_name($accObj,true,$GLOBALS['egw_info']['user']['acount_id']);
|
|
||||||
$baseNode = array(
|
|
||||||
tree::ID=> $acc_id,
|
|
||||||
tree::LABEL => str_replace(array('<','>'),array('[',']'),$identity),
|
|
||||||
tree::TOOLTIP => '('.$acc_id.') '.htmlspecialchars_decode($identity),
|
|
||||||
tree::IMAGE_LEAF => self::$leafImages['folderAccount'],
|
|
||||||
tree::IMAGE_FOLDER_OPEN => self::$leafImages['folderAccount'],
|
|
||||||
tree::IMAGE_FOLDER_CLOSED => self::$leafImages['folderAccount'],
|
|
||||||
'path'=> array($acc_id),
|
|
||||||
tree::CHILDREN => array(), // dynamic loading on unfold
|
|
||||||
tree::AUTOLOAD_CHILDREN => true,
|
|
||||||
'parent' => '',
|
|
||||||
tree::OPEN => $_openTopLevel,
|
|
||||||
// mark on account if Sieve is enabled
|
|
||||||
'data' => array(
|
|
||||||
'sieve' => $accObj->imapServer()->acc_sieve_enabled,
|
|
||||||
'spamfolder'=> $accObj->imapServer()->acc_folder_junk?true:false
|
|
||||||
),
|
|
||||||
tree::NOCHECKBOX => $_noCheckboxNS
|
|
||||||
);
|
|
||||||
self::setOutStructure($baseNode, $tree,self::$delimiter);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$tree = self::getAccountsRootNode($_profileID, $_noCheckboxNS, $_openTopLevel);
|
||||||
|
if (!$_profileID && !$_openTopLevel) return $tree;
|
||||||
|
}
|
||||||
|
|
||||||
//List of folders
|
//List of folders
|
||||||
$foldersList = $this->ui->mail_bo->getFolderArrays(null, true);
|
$foldersList = $this->ui->mail_bo->getFolderArrays(null, true, $_getThemAll?0:2,$_subscribedOnly);
|
||||||
// Parent node arrays
|
foreach ($foldersList as &$folder)
|
||||||
$parentNode = $parentNodes = array();
|
|
||||||
|
|
||||||
foreach ($foldersList as $index => $topFolder)
|
|
||||||
{
|
{
|
||||||
$nameSpaces = $this->ui->mail_bo->_getNameSpaces();
|
$path = $parent = $parts = explode($folder['delimiter'], $folder['MAILBOX']);
|
||||||
$noCheckbox = false;
|
array_pop($parent);
|
||||||
foreach ($nameSpaces as &$ns)
|
|
||||||
{
|
array_unshift($path, $_profileID);
|
||||||
if($_noCheckboxNS && $ns['prefix'] === $index.$hDelimiter) $noCheckbox = true;
|
|
||||||
}
|
$data = array(
|
||||||
$parentNode = array(
|
tree::ID=>$_profileID.self::$delimiter.$folder['MAILBOX'],
|
||||||
tree::ID=>$_profileID.self::$delimiter.$topFolder[$index]['MAILBOX'],
|
tree::AUTOLOAD_CHILDREN => self::nodeHasChildren($folder),
|
||||||
tree::AUTOLOAD_CHILDREN => self::nodeHasChildren($topFolder[$index]),
|
|
||||||
tree::CHILDREN =>array(),
|
tree::CHILDREN =>array(),
|
||||||
tree::LABEL =>lang($topFolder[$index]['MAILBOX']),
|
tree::LABEL =>lang($folder['MAILBOX']),
|
||||||
tree::OPEN => $_openTopLevel,
|
tree::OPEN => self::getNodeLevel($folder['MAILBOX'], $folder['delimiter']) <= $_openTopLevel?1:0,
|
||||||
tree::TOOLTIP => lang($topFolder[$index]['MAILBOX']),
|
tree::TOOLTIP => lang($folder['MAILBOX']),
|
||||||
tree::CHECKED => $topFolder[$index]['SUBSCRIBED'],
|
tree::CHECKED => $folder['SUBSCRIBED'],
|
||||||
tree::NOCHECKBOX => $noCheckbox
|
tree::NOCHECKBOX => 0,
|
||||||
|
'parent' => $parent?$_profileID.self::$delimiter.implode($folder['delimiter'], $parent):$_profileID,
|
||||||
|
'path' => $path,
|
||||||
|
'folderarray' => $folder
|
||||||
);
|
);
|
||||||
if ($index === "INBOX")
|
// Set Acl capability for INBOX
|
||||||
|
if ($folder['MAILBOX'] === "INBOX")
|
||||||
{
|
{
|
||||||
$parentNode[tree::IMAGE_LEAF] = self::$leafImages['folderHome'];
|
$data['data'] = array('acl' => $this->ui->mail_bo->icServer->queryCapability('ACL'));
|
||||||
$parentNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderHome'];
|
|
||||||
$parentNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderHome'];
|
|
||||||
}
|
}
|
||||||
if(stripos(array2string($topFolder[$index]['ATTRIBUTES']),'\noselect')!== false)
|
self::setOutStructure($data, $tree, $folder['delimiter'], true, $this->ui->mail_bo->_getNameSpaces(), $definedFolders);
|
||||||
{
|
|
||||||
$parentNode[tree::IMAGE_LEAF] = self::$leafImages['folderNoSelectClosed'];
|
|
||||||
$parentNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderNoSelectOpen'];
|
|
||||||
$parentNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderNoSelectClosed'];
|
|
||||||
}
|
|
||||||
// Save parentNodes
|
|
||||||
$parentNodes []= $index;
|
|
||||||
// Remove the parent nodes from the list
|
|
||||||
unset ($topFolder[$index]);
|
|
||||||
|
|
||||||
//$parentNode[tree::CHILDREN][] =$childrenNode;
|
|
||||||
$baseNode[tree::CHILDREN][] = $parentNode;
|
|
||||||
}
|
}
|
||||||
foreach ($parentNodes as $pIndex => $parent)
|
// Structs children of account root node. Used for mail index tree when we do autoloading on account id
|
||||||
{
|
if (self::isAccountNode($_parent)) $tree = array(tree::ID => $_parent, tree::CHILDREN => $tree[tree::CHILDREN][0][tree::CHILDREN]);
|
||||||
$childrenNodes = $childNode = array();
|
|
||||||
$definedFolders = array(
|
|
||||||
'Trash' => $this->ui->mail_bo->getTrashFolder(false),
|
|
||||||
'Templates' => $this->ui->mail_bo->getTemplateFolder(false),
|
|
||||||
'Drafts' => $this->ui->mail_bo->getDraftFolder(false),
|
|
||||||
'Sent' => $this->ui->mail_bo->getSentFolder(false),
|
|
||||||
'Junk' => $this->ui->mail_bo->getJunkFolder(false),
|
|
||||||
'Outbox' => $this->ui->mail_bo->getOutboxFolder(false),
|
|
||||||
);
|
|
||||||
// Iterate over childern of each top folder(namespaces)
|
|
||||||
foreach ($foldersList[$parent] as &$node)
|
|
||||||
{
|
|
||||||
// Skipe the parent node itself
|
|
||||||
if (is_array($foldersList[$parent][$parent]) &&
|
|
||||||
$foldersList[$parent][$parent]['MAILBOX'] === $node['MAILBOX']) continue;
|
|
||||||
|
|
||||||
$pathArr = explode($node['delimiter'], $node['MAILBOX']);
|
|
||||||
$folderName = array_pop($pathArr);
|
|
||||||
$parentPath = $_profileID.self::$delimiter.implode($pathArr,$node['delimiter']);
|
|
||||||
|
|
||||||
$nodeId = $_profileID.self::$delimiter.$node['MAILBOX'];
|
|
||||||
|
|
||||||
$childNode = array(
|
|
||||||
tree::ID => $nodeId,
|
|
||||||
tree::AUTOLOAD_CHILDREN => self::nodeHasChildren($node),
|
|
||||||
tree::CHILDREN => array(),
|
|
||||||
tree::LABEL => lang($folderName),
|
|
||||||
'parent' => $parentPath,
|
|
||||||
tree::CHECKED => $node['SUBSCRIBED']
|
|
||||||
);
|
|
||||||
|
|
||||||
if (array_search($node['MAILBOX'], $definedFolders) !== false)
|
|
||||||
{
|
|
||||||
//User defined folders icons
|
|
||||||
$childNode[tree::IMAGE_LEAF] =
|
|
||||||
$childNode[tree::IMAGE_FOLDER_OPEN] =
|
|
||||||
$childNode [tree::IMAGE_FOLDER_CLOSED] = "MailFolder".$folderName.".png";
|
|
||||||
}
|
|
||||||
elseif(stripos(array2string($node['ATTRIBUTES']),'\noselect')!== false)
|
|
||||||
{
|
|
||||||
$childNode[tree::IMAGE_LEAF] = self::$leafImages['folderNoSelectClosed'];
|
|
||||||
$childNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderNoSelectOpen'];
|
|
||||||
$childNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderNoSelectClosed'];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$childNode[tree::IMAGE_LEAF] = self::$leafImages['folderLeaf'];
|
|
||||||
$childNode[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderOpen'];
|
|
||||||
$childNode[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderClose'];
|
|
||||||
}
|
|
||||||
$childrenNodes[] = $childNode;
|
|
||||||
}
|
|
||||||
$baseNode[tree::CHILDREN][$pIndex][tree::CHILDREN] = $childrenNodes;
|
|
||||||
}
|
|
||||||
$tree[tree::CHILDREN][0] = $baseNode;
|
|
||||||
}
|
}
|
||||||
return $tree;
|
return $tree;
|
||||||
}
|
}
|
||||||
@ -329,7 +286,7 @@ class mail_tree
|
|||||||
* as clearance for access may be limited to a single branch-node of a tree
|
* as clearance for access may be limited to a single branch-node of a tree
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
static function setOutStructure($data, &$out, $del='.', $createMissingParents=true, $nameSpace=array())
|
static function setOutStructure($data, &$out, $del='.', $createMissingParents=true, $nameSpace=array(), $definedFolders= array())
|
||||||
{
|
{
|
||||||
//error_log(__METHOD__."(".array2string($data).', '.array2string($out).", '$del')");
|
//error_log(__METHOD__."(".array2string($data).', '.array2string($out).", '$del')");
|
||||||
$components = $data['path'];
|
$components = $data['path'];
|
||||||
@ -399,9 +356,92 @@ class mail_tree
|
|||||||
}
|
}
|
||||||
$parents[] = $component;
|
$parents[] = $component;
|
||||||
}
|
}
|
||||||
|
if ($data['folderarray']['delimiter'] && $data['folderarray']['MAILBOX'])
|
||||||
|
{
|
||||||
|
$path = explode($data['folderarray']['delimiter'], $data['folderarray']['MAILBOX']);
|
||||||
|
$folderName = array_pop($path);
|
||||||
|
|
||||||
|
if ($data['folderarray']['MAILBOX'] === "INBOX")
|
||||||
|
{
|
||||||
|
$data[tree::IMAGE_LEAF] = self::$leafImages['folderHome'];
|
||||||
|
$data[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderHome'];
|
||||||
|
$data[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderHome'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// User defined folders may get different icons
|
||||||
|
// plus they need to be translated too
|
||||||
|
if (array_search($data['folderarray']['MAILBOX'], $definedFolders, true) !== false)
|
||||||
|
{
|
||||||
|
$data[tree::LABEL] = lang($folderName);
|
||||||
|
$data[tree::TOOLTIP] = lang($folderName);
|
||||||
|
//User defined folders icons
|
||||||
|
$data[tree::IMAGE_LEAF] =
|
||||||
|
$data[tree::IMAGE_FOLDER_OPEN] =
|
||||||
|
$data [tree::IMAGE_FOLDER_CLOSED] = "MailFolder".$folderName.".png";
|
||||||
|
}
|
||||||
|
elseif(stripos(array2string($data['folderarray']['attributes']),'\noselect')!== false)
|
||||||
|
{
|
||||||
|
$data[tree::IMAGE_LEAF] = self::$leafImages['folderNoSelectClosed'];
|
||||||
|
$data[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderNoSelectOpen'];
|
||||||
|
$data[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderNoSelectClosed'];
|
||||||
|
}
|
||||||
|
elseif ($data['parent'])
|
||||||
|
{
|
||||||
|
$data[tree::LABEL] = $folderName;
|
||||||
|
$data[tree::TOOLTIP] = $folderName;
|
||||||
|
$data[tree::IMAGE_LEAF] = self::$leafImages['folderLeaf'];
|
||||||
|
$data[tree::IMAGE_FOLDER_OPEN] = self::$leafImages['folderOpen'];
|
||||||
|
$data[tree::IMAGE_FOLDER_CLOSED] = self::$leafImages['folderClose'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Remove extra data from tree structure
|
||||||
|
unset($data['folderarray']);
|
||||||
unset($data['path']);
|
unset($data['path']);
|
||||||
|
|
||||||
$insert['item'][] = $data;
|
$insert['item'][] = $data;
|
||||||
//error_log(__METHOD__."() leaving with out=".array2string($out));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get accounts root node, fetches all or an accounts for a user
|
||||||
|
*
|
||||||
|
* @param type $_profileID = null Null means all accounts and giving profileid means fetches node for the account
|
||||||
|
* @param type $_noCheckbox = false option to switch checkbox of
|
||||||
|
* @param type $_openTopLevel = 0 option to either start the node opened (1) or closed (0)
|
||||||
|
*
|
||||||
|
* @return array an array of baseNodes of accounts
|
||||||
|
*/
|
||||||
|
static function getAccountsRootNode($_profileID = null, $_noCheckbox = false, $_openTopLevel = 0 )
|
||||||
|
{
|
||||||
|
$roots = array(tree::ID => 0, tree::CHILDREN => array());
|
||||||
|
|
||||||
|
foreach(emailadmin_account::search(true, false) as $acc_id => $accObj)
|
||||||
|
{
|
||||||
|
if (!$accObj->is_imap()|| $_profileID && $acc_id != $_profileID) continue;
|
||||||
|
$identity = emailadmin_account::identity_name($accObj,true,$GLOBALS['egw_info']['user']['acount_id']);
|
||||||
|
// Open top level folders for active account
|
||||||
|
$openActiveAccount = $GLOBALS['egw_info']['user']['preferences']['mail']['ActiveProfileID'] == $acc_id?1:0;
|
||||||
|
|
||||||
|
$baseNode = array(
|
||||||
|
tree::ID=> $acc_id,
|
||||||
|
tree::LABEL => str_replace(array('<','>'),array('[',']'),$identity),
|
||||||
|
tree::TOOLTIP => '('.$acc_id.') '.htmlspecialchars_decode($identity),
|
||||||
|
tree::IMAGE_LEAF => self::$leafImages['folderAccount'],
|
||||||
|
tree::IMAGE_FOLDER_OPEN => self::$leafImages['folderAccount'],
|
||||||
|
tree::IMAGE_FOLDER_CLOSED => self::$leafImages['folderAccount'],
|
||||||
|
'path'=> array($acc_id),
|
||||||
|
tree::CHILDREN => array(), // dynamic loading on unfold
|
||||||
|
tree::AUTOLOAD_CHILDREN => true,
|
||||||
|
'parent' => '',
|
||||||
|
tree::OPEN => $_openTopLevel?$_openTopLevel:$openActiveAccount,
|
||||||
|
// mark on account if Sieve is enabled
|
||||||
|
'data' => array(
|
||||||
|
'sieve' => $accObj->imapServer()->acc_sieve_enabled,
|
||||||
|
'spamfolder'=> $accObj->imapServer()->acc_folder_junk?true:false
|
||||||
|
),
|
||||||
|
tree::NOCHECKBOX => $_noCheckbox
|
||||||
|
);
|
||||||
|
self::setOutStructure($baseNode, $roots,self::$delimiter);
|
||||||
|
}
|
||||||
|
return $roots;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
</grid>
|
</grid>
|
||||||
</template>
|
</template>
|
||||||
<template id="mail.index" template="" lang="" group="0" version="1.9.001">
|
<template id="mail.index" template="" lang="" group="0" version="1.9.001">
|
||||||
<tree autoloading="mail.mail_ui.ajax_foldertree" id="nm[foldertree]" onclick="app.mail.mail_changeFolder" parent_node="mail-tree_target"/>
|
<tree autoloading="mail.mail_ui.ajax_foldertree" id="nm[foldertree]" onclick="app.mail.mail_changeFolder" parent_node="mail-tree_target" onopenstart="app.mail.subscription_autoloadingStart" onopenend="app.mail.subscription_autoloadingEnd"/>
|
||||||
<html id="msg"/>
|
<html id="msg"/>
|
||||||
<buttononly id="button[mailcreate]" onclick="app.mail.mail_compose(false);" label="Compose" parent_node="mail-index_buttonmailcreate"/>
|
<buttononly id="button[mailcreate]" onclick="app.mail.mail_compose(false);" label="Compose" parent_node="mail-index_buttonmailcreate"/>
|
||||||
<hbox class="mail-index_quotabox"><progress id="nm[quotainpercent]" label="@nm[quota]" class="@nm[quotaclass]"/></hbox>
|
<hbox class="mail-index_quotabox"><progress id="nm[quotainpercent]" label="@nm[quota]" class="@nm[quotaclass]"/></hbox>
|
||||||
|
Loading…
Reference in New Issue
Block a user