Compare commits
304 Commits
support/1.
...
1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad6f5c97c4 | ||
|
|
552ffd79b1 | ||
|
|
aae8ca7b8b | ||
|
|
13c636cab6 | ||
|
|
cc40fc5d91 | ||
|
|
bddfdb4a28 | ||
|
|
6bc639c6ce | ||
|
|
9b8ae03413 | ||
|
|
17f00198d3 | ||
|
|
5041ec2e0c | ||
|
|
ee4f7e5b6a | ||
|
|
cbb40b85dc | ||
|
|
9aca772209 | ||
|
|
c4db9cd84e | ||
|
|
205e80f8a5 | ||
|
|
06e9bd0c25 | ||
|
|
1c812f8b34 | ||
|
|
f3c5759721 | ||
|
|
69368a39cb | ||
|
|
ab5849b3cd | ||
|
|
1ab796bd40 | ||
|
|
c1221054b4 | ||
|
|
3bd681bc9d | ||
|
|
b33989ec62 | ||
|
|
b3121eebae | ||
|
|
7d8971139b | ||
|
|
04f20860dc | ||
|
|
8f21b9dabb | ||
|
|
eb89610465 | ||
|
|
13f4e90ee6 | ||
|
|
29f1dd5a69 | ||
|
|
a7e937ec58 | ||
|
|
bc2a8a8c4a | ||
|
|
c9b0a2b561 | ||
|
|
5fcea9bf69 | ||
|
|
3b42c86f46 | ||
|
|
038fe30fbe | ||
|
|
aa95e51e00 | ||
|
|
6a78c7dcc2 | ||
|
|
17aa1d1fc0 | ||
|
|
24244f1bac | ||
|
|
f7be35848c | ||
|
|
1aa7ff14fe | ||
|
|
c33a508376 | ||
|
|
37ec8b12f3 | ||
|
|
dde3efc0c7 | ||
|
|
54f3dec7a9 | ||
|
|
6be497ee7d | ||
|
|
5d9d44dc5e | ||
|
|
d547394ba2 | ||
|
|
ace0a3e278 | ||
|
|
dd9cb27971 | ||
|
|
a3dc8ab3d7 | ||
|
|
496bf386be | ||
|
|
c337616fea | ||
|
|
186ba76092 | ||
|
|
20a06c9212 | ||
|
|
e515dfb434 | ||
|
|
2ee85dd407 | ||
|
|
6df6e4a9cc | ||
|
|
c74c955973 | ||
|
|
a3a4fd0a75 | ||
|
|
c7f3ac0361 | ||
|
|
21002574ce | ||
|
|
64cae5b58b | ||
|
|
cc1105ff60 | ||
|
|
71655f0632 | ||
|
|
6e4e5be35d | ||
|
|
872a424a78 | ||
|
|
612c355e03 | ||
|
|
ffa9b21364 | ||
|
|
180311fd0a | ||
|
|
16b7714139 | ||
|
|
c6865cf63d | ||
|
|
905d9b5931 | ||
|
|
0850370275 | ||
|
|
38591f444e | ||
|
|
ae36aa1f74 | ||
|
|
264af56591 | ||
|
|
0a2c9d0e37 | ||
|
|
9d9d53c967 | ||
|
|
54315f41e4 | ||
|
|
a04e7ea375 | ||
|
|
795296e6e3 | ||
|
|
98ac85c098 | ||
|
|
e53c07393c | ||
|
|
48d66447b7 | ||
|
|
54b4f67ed6 | ||
|
|
9836797da9 | ||
|
|
931a260435 | ||
|
|
2a6d36b9cd | ||
|
|
9420c14c13 | ||
|
|
272807ba56 | ||
|
|
d05ea1863c | ||
|
|
6c8e021727 | ||
|
|
266135b1b9 | ||
|
|
02fc610a18 | ||
|
|
e2aa3cc69f | ||
|
|
de516c0ce4 | ||
|
|
92ac1fe2ca | ||
|
|
cc7844ea10 | ||
|
|
22bdc02b1b | ||
|
|
e8586515e3 | ||
|
|
071a30d928 | ||
|
|
488f1c47bf | ||
|
|
c15976f148 | ||
|
|
6f8e2e60ce | ||
|
|
b7b8da0848 | ||
|
|
2f1803b3b6 | ||
|
|
58e61c9d6b | ||
|
|
ddd98b9335 | ||
|
|
278b84ee38 | ||
|
|
c0764bce74 | ||
|
|
7cf0e2f747 | ||
|
|
c7e8627679 | ||
|
|
1c7d5b8fd2 | ||
|
|
18217e4adb | ||
|
|
1357e7e225 | ||
|
|
a941c2d14e | ||
|
|
cb55a75bcf | ||
|
|
1e20253229 | ||
|
|
53a48dc8e0 | ||
|
|
2ad9d69396 | ||
|
|
74baca3a7b | ||
|
|
2bd8700c90 | ||
|
|
51bd6cdf97 | ||
|
|
b02021a4ff | ||
|
|
96f3350029 | ||
|
|
e2e4c53b0d | ||
|
|
9c6605f7e7 | ||
|
|
f481652666 | ||
|
|
212389f43e | ||
|
|
f68680ada1 | ||
|
|
6859326646 | ||
|
|
a129c9814f | ||
|
|
05ee0caec2 | ||
|
|
6fff9d6a20 | ||
|
|
d2955557bf | ||
|
|
aa00cd9ae7 | ||
|
|
aa9d9ed578 | ||
|
|
9bd6fa61c5 | ||
|
|
f16997fb2d | ||
|
|
f4c1cf0818 | ||
|
|
01dd63f623 | ||
|
|
3393808c7a | ||
|
|
772c892b15 | ||
|
|
435d943f47 | ||
|
|
eab1060f8e | ||
|
|
cb8774370f | ||
|
|
23b1d15b64 | ||
|
|
61727aca02 | ||
|
|
8cfebdf723 | ||
|
|
506702c50b | ||
|
|
b9de1df6a8 | ||
|
|
a7175007be | ||
|
|
5d8acbb41a | ||
|
|
3ccbeac996 | ||
|
|
1643ba8e9c | ||
|
|
768dbd8946 | ||
|
|
c2d02a2394 | ||
|
|
b26f2738f6 | ||
|
|
781ec7e33a | ||
|
|
d09db3a920 | ||
|
|
998a8692cb | ||
|
|
b83ac447e8 | ||
|
|
6688f1811e | ||
|
|
ec26750b58 | ||
|
|
0f0abc0501 | ||
|
|
9ad6f2c994 | ||
|
|
abab47558b | ||
|
|
f3147be8f6 | ||
|
|
af185b79c8 | ||
|
|
3fc686e403 | ||
|
|
f5ea073c2b | ||
|
|
aa6d7578d1 | ||
|
|
05338caa23 | ||
|
|
a6ac78d7c1 | ||
|
|
9bcf78bfd6 | ||
|
|
9c97df5186 | ||
|
|
c2a8fd4e09 | ||
|
|
c8b6ec08e7 | ||
|
|
4293230416 | ||
|
|
bfddec242b | ||
|
|
ee3652acad | ||
|
|
5baa213e6a | ||
|
|
ca8ea8dd02 | ||
|
|
308d2626a9 | ||
|
|
8cab8dd7b7 | ||
|
|
0a5e37c592 | ||
|
|
72326435ce | ||
|
|
ca9f17d6e1 | ||
|
|
ff89c4d424 | ||
|
|
fa3b7ce545 | ||
|
|
c85feb7cea | ||
|
|
d50f812694 | ||
|
|
c7e27a836a | ||
|
|
c8a1380bef | ||
|
|
7732c9bc6a | ||
|
|
82c57972c6 | ||
|
|
0cc0c820a5 | ||
|
|
9150a569a7 | ||
|
|
3c76b90a48 | ||
|
|
5f2a5d9cfa | ||
|
|
4e40702809 | ||
|
|
a2b8813628 | ||
|
|
751ab5a4b4 | ||
|
|
b6bcade4c0 | ||
|
|
d6be6ca92c | ||
|
|
9024e0b2db | ||
|
|
ecca1aa070 | ||
|
|
3fde682653 | ||
|
|
aee8a98d84 | ||
|
|
3ab670e8c2 | ||
|
|
1fc7ce3b81 | ||
|
|
e8c44951a1 | ||
|
|
c11ca679d4 | ||
|
|
46781c349f | ||
|
|
189b802452 | ||
|
|
6b7687c80b | ||
|
|
906abd5fe6 | ||
|
|
0c539aada9 | ||
|
|
a3611f7f63 | ||
|
|
d62d6e14c8 | ||
|
|
4cd4d91225 | ||
|
|
5257287421 | ||
|
|
7e60a9fce7 | ||
|
|
b80cc36fb5 | ||
|
|
0e75824247 | ||
|
|
7470c8e72e | ||
|
|
a04f0ee816 | ||
|
|
d37244e6e2 | ||
|
|
82c4f43c4f | ||
|
|
1c2c244273 | ||
|
|
a991a84a8e | ||
|
|
532912984d | ||
|
|
265ef1e1ce | ||
|
|
70ad369ad6 | ||
|
|
723685b4cb | ||
|
|
061711afc8 | ||
|
|
8b6a8f02a4 | ||
|
|
893ec0f097 | ||
|
|
7c9d4c76a9 | ||
|
|
52fb63c0ee | ||
|
|
8a547bf104 | ||
|
|
0019ab216a | ||
|
|
8d52cd3a58 | ||
|
|
c7fbe56423 | ||
|
|
5ff5ea71de | ||
|
|
6297526da6 | ||
|
|
56ac89f6a6 | ||
|
|
aa46ab1a67 | ||
|
|
645b02b2d1 | ||
|
|
b2c5f183ec | ||
|
|
c6b60731d8 | ||
|
|
fd2f40f070 | ||
|
|
9fef41404f | ||
|
|
017aec3ae8 | ||
|
|
2ae4aca687 | ||
|
|
692fd91801 | ||
|
|
12ec9c3ba1 | ||
|
|
ac5e40f4ed | ||
|
|
f44afb8ee6 | ||
|
|
9e01277e49 | ||
|
|
73dc5eb922 | ||
|
|
a5091d9af0 | ||
|
|
a573d3cfa0 | ||
|
|
c4b7497770 | ||
|
|
1964658584 | ||
|
|
077b7be2a4 | ||
|
|
22c6df1a7a | ||
|
|
54d5497f0a | ||
|
|
9d2a8d0a67 | ||
|
|
20024729ec | ||
|
|
43315f50ea | ||
|
|
46edbbbd2b | ||
|
|
dc3713f0ea | ||
|
|
01a4a04364 | ||
|
|
7384191fb6 | ||
|
|
b8c930016f | ||
|
|
5d37201391 | ||
|
|
2c8963784c | ||
|
|
c42fa13b92 | ||
|
|
c02d62044c | ||
|
|
7bcb4ed3b2 | ||
|
|
834e9c48e1 | ||
|
|
ddfc84db6a | ||
|
|
b4a7d0b86c | ||
|
|
02cafd0e0b | ||
|
|
f5891a531e | ||
|
|
4681b03646 | ||
|
|
733953ac99 | ||
|
|
4837984ac3 | ||
|
|
4efd93defe | ||
|
|
35f7d143b8 | ||
|
|
d48fd1a12e | ||
|
|
a0900cd732 | ||
|
|
64b4922499 | ||
|
|
4574126428 | ||
|
|
9704dd8e35 | ||
|
|
f8d794bc93 | ||
|
|
5c7c7b98ee | ||
|
|
3826c1f886 | ||
|
|
58844b04ef | ||
|
|
178f7f3426 |
@@ -265,7 +265,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetName() == "Administrator")
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
{
|
||||
// Looks dirty, but ok that's THE ONE
|
||||
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
|
||||
@@ -538,41 +538,35 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
|
||||
// Support drastic data model changes: no organization class !
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
$iContactId = 0;
|
||||
// Support drastic data model changes: no organization class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
|
||||
{
|
||||
$oOrg = new Organization();
|
||||
$oOrg->Set('name', 'My Company/Department');
|
||||
$oOrg->Set('code', 'SOMECODE');
|
||||
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iOrgId = 0;
|
||||
|
||||
// Support drastic data model changes: no Person class (or not writable)!
|
||||
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
|
||||
{
|
||||
$oContact = new Person();
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
||||
{
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
}
|
||||
}
|
||||
|
||||
// Support drastic data model changes: no Person class !
|
||||
if (MetaModel::IsValidClass('Person'))
|
||||
{
|
||||
$oContact = new Person();
|
||||
$oContact->Set('name', 'My last name');
|
||||
$oContact->Set('first_name', 'My first name');
|
||||
if (MetaModel::IsValidAttCode('Person', 'org_id'))
|
||||
{
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iContactId = 0;
|
||||
}
|
||||
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('login', $sAdminUser);
|
||||
$oUser->Set('password', $sAdminPwd);
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid'))
|
||||
if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
|
||||
{
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
}
|
||||
@@ -604,7 +598,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
protected $m_aProfiles; // id -> object
|
||||
protected $m_aUserProfiles; // userid,profileid -> object
|
||||
protected $m_aUserOrgs; // userid,orgid -> object
|
||||
protected $m_aUserOrgs; // userid -> orgid
|
||||
|
||||
// Those arrays could be completed on demand (inheriting parent permissions)
|
||||
protected $m_aClassActionGrants = null; // profile, class, action -> actiongrantid (or false if NO, or null/missing if undefined)
|
||||
@@ -613,6 +607,11 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
|
||||
protected $m_aObjectActionGrants = array();
|
||||
|
||||
protected function GetUserOrgs($oUser, $sClass)
|
||||
{
|
||||
return @$this->m_aUserOrgs[$oUser->GetKey()];
|
||||
}
|
||||
|
||||
public function ResetCache()
|
||||
{
|
||||
// Loaded by Load cache
|
||||
@@ -684,7 +683,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$this->m_aUserOrgs = array();
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
$this->m_aUserOrgs[$oUserOrg->Get('userid')][$oUserOrg->Get('allowed_org_id')] = $oUserOrg;
|
||||
$this->m_aUserOrgs[$oUserOrg->Get('userid')][] = $oUserOrg->Get('allowed_org_id');
|
||||
}
|
||||
|
||||
$this->m_aClassStimulusGrants = array();
|
||||
@@ -751,17 +750,24 @@ exit;
|
||||
|
||||
// Determine how to position the objects of this class
|
||||
//
|
||||
if ($sClass == 'Organization')
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (($sClass == 'Organization') || is_subclass_of($sClass, 'Organization'))
|
||||
{
|
||||
$sAttCode = 'id';
|
||||
}
|
||||
elseif (is_callable("$sClass::MapContextParam"))
|
||||
elseif (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = eval("return $sClass::MapContextParam('org_id');"); // Returns null when there is no mapping for this parameter
|
||||
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
||||
|
||||
if ($sAttCode == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
// Skip silently. The data model checker will tell you something about this...
|
||||
return true;
|
||||
}
|
||||
}
|
||||
elseif(MetaModel::IsValidAttCode($sClass, 'org_id'))
|
||||
{
|
||||
@@ -773,23 +779,61 @@ exit;
|
||||
// All of them are visible
|
||||
return true;
|
||||
}
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
|
||||
// Position the user
|
||||
//
|
||||
@$aUserOrgs = $this->m_aUserOrgs[$oUser->GetKey()];
|
||||
if (!isset($aUserOrgs) || count($aUserOrgs) == 0)
|
||||
$aUserOrgs = $this->GetUserOrgs($oUser, $sClass);
|
||||
if (is_null($aUserOrgs) || count($aUserOrgs) == 0)
|
||||
{
|
||||
// No position means 'Everywhere'
|
||||
return true;
|
||||
}
|
||||
|
||||
$aIds = array_keys($aUserOrgs);
|
||||
$oListExpr = ListExpression::FromScalars($aIds);
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
$oListExpr = ListExpression::FromScalars($aUserOrgs);
|
||||
|
||||
// Check if the condition points to a hierarchical key
|
||||
$bConditionAdded = false;
|
||||
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
// Filtering on the objects themselves
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sClass);
|
||||
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
$oRootFilter = new DBObjectSearch($sClass);
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oRootFilter->AddConditionExpression($oCondition);
|
||||
$oFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
|
||||
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
$oRootFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oExpression = new FieldExpression('id', $oAttDef->GetTargetClass());
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oRootFilter->AddConditionExpression($oCondition);
|
||||
$oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oHKFilter->AddCondition_PointingTo($oRootFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
|
||||
$oFilter->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$bConditionAdded)
|
||||
{
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
}
|
||||
return $oFilter;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetName() == "Administrator")
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
{
|
||||
// Looks dirty, but ok that's THE ONE
|
||||
$oPage->p(Dict::S('UI:UserManagement:AdminProfile+'));
|
||||
|
||||
@@ -45,11 +45,13 @@ class ajax_page extends WebPage
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
$this->m_sReadyScript = "";
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
//$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$this->m_sCurrentTabContainer = '';
|
||||
$this->m_sCurrentTab = '';
|
||||
$this->m_aTabs = array();
|
||||
$this->sContentType = 'text/html';
|
||||
$this->sContentDisposition = 'inline';
|
||||
}
|
||||
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
@@ -92,11 +94,18 @@ class ajax_page extends WebPage
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
if (!empty($this->sContentType))
|
||||
{
|
||||
$this->add_header('Content-type: '.$this->sContentType);
|
||||
}
|
||||
if (!empty($this->sContentDisposition))
|
||||
{
|
||||
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
|
||||
}
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
|
||||
if (count($this->m_aTabs) > 0)
|
||||
{
|
||||
$this->add_ready_script(
|
||||
@@ -165,7 +174,15 @@ EOF
|
||||
|
||||
$s_captured_output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
echo $this->s_content;
|
||||
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
|
||||
{
|
||||
// inline content != attachment && html => filter all scripts for malicious XSS scripts
|
||||
echo self::FilterXSS($this->s_content);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $this->s_content;
|
||||
}
|
||||
//echo $this->s_deferred_content;
|
||||
if (count($this->a_scripts) > 0)
|
||||
{
|
||||
@@ -176,7 +193,7 @@ EOF
|
||||
if (!empty($this->s_deferred_content))
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo "\$('body').append('".$this->s_deferred_content."');\n";
|
||||
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (!empty($this->m_sReadyScript))
|
||||
@@ -187,7 +204,7 @@ EOF
|
||||
}
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo $s_captured_output;
|
||||
echo self::FilterXSS($s_captured_output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +229,20 @@ EOF
|
||||
parent::add($sHtml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
|
||||
* This is useful to add hidden content, DIVs or FORMs that should not
|
||||
* be embedded into each other.
|
||||
*/
|
||||
public function add_at_the_end($s_html, $sId = '')
|
||||
{
|
||||
if ($sId != '')
|
||||
{
|
||||
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
|
||||
}
|
||||
$this->s_deferred_content .= $s_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a script to be executed when the DOM is ready (typical JQuery use)
|
||||
@@ -220,9 +251,6 @@ EOF
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
// Does nothing in ajax rendered content.. for now...
|
||||
// Maybe we should add this as a simple <script> tag at the end of the output
|
||||
// considering that at this time everything in the page is "ready"...
|
||||
$this->m_sReadyScript .= $sScript;
|
||||
}
|
||||
|
||||
@@ -236,6 +264,10 @@ EOF
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
|
||||
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
require_once(APPROOT.'/application/sqlblock.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.rule.class.inc.php');
|
||||
//require_once(APPROOT.'/application/menunode.class.inc.php');
|
||||
|
||||
@@ -24,6 +24,43 @@
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/utils.inc.php");
|
||||
|
||||
/**
|
||||
* Interface for directing end-users to the relevant application
|
||||
*/
|
||||
interface iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard iTop application: UI.php
|
||||
*/
|
||||
class iTopStandardURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sPage = DBObject::ComputeStandardUIPage($sClass);
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard Portal application
|
||||
*/
|
||||
class PortalURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to store and manipulate the parameters that make the application's context
|
||||
*
|
||||
@@ -54,7 +91,7 @@ class ApplicationContext
|
||||
*/
|
||||
protected function ReadContext()
|
||||
{
|
||||
if (empty(self::$aDefaultValues))
|
||||
if (!isset(self::$aDefaultValues))
|
||||
{
|
||||
self::$aDefaultValues = array();
|
||||
$aContext = utils::ReadParam('c', array());
|
||||
@@ -126,7 +163,7 @@ class ApplicationContext
|
||||
$sContext = "";
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"$sValue\" />\n";
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
return $sContext;
|
||||
}
|
||||
@@ -166,5 +203,101 @@ class ApplicationContext
|
||||
unset($this->aValues[$sParamName]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given object with the default values provided by the context
|
||||
*/
|
||||
public function InitObjectFromContext(DBObject &$oObj)
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
foreach($this->GetNames() as $key)
|
||||
{
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
$value = $this->GetCurrentValue($key, null);
|
||||
if (!is_null($value))
|
||||
{
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static $m_sUrlMakerClass = null;
|
||||
|
||||
/**
|
||||
* Set the current application url provider
|
||||
* @param sClass string Class implementing iDBObjectURLMaker
|
||||
* @return void
|
||||
*/
|
||||
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
|
||||
{
|
||||
$sPrevious = self::GetUrlMakerClass();
|
||||
|
||||
self::$m_sUrlMakerClass = $sClass;
|
||||
$_SESSION['UrlMakerClass'] = $sClass;
|
||||
|
||||
return $sPrevious;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current application url provider
|
||||
* @return string the name of the class
|
||||
*/
|
||||
public static function GetUrlMakerClass()
|
||||
{
|
||||
if (is_null(self::$m_sUrlMakerClass))
|
||||
{
|
||||
if (isset($_SESSION['UrlMakerClass']))
|
||||
{
|
||||
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
|
||||
}
|
||||
}
|
||||
return self::$m_sUrlMakerClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current application url provider
|
||||
* @return string the name of the class
|
||||
*/
|
||||
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
if (is_null($sUrlMakerClass))
|
||||
{
|
||||
$sUrlMakerClass = self::GetUrlMakerClass();
|
||||
}
|
||||
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
|
||||
if (strlen($sUrl) > 0)
|
||||
{
|
||||
if ($bWithNavigationContext)
|
||||
{
|
||||
return $sUrl."&".$oAppContext->GetForLink();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -178,36 +178,6 @@ class DisplayBlock
|
||||
public function Display(WebPage $oPage, $sId, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add($this->GetDisplay($oPage, $sId, $aExtraParams));
|
||||
/*
|
||||
$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
|
||||
$aExtraParams['block_id'] = $sId;
|
||||
if (!$this->m_bAsynchronous)
|
||||
{
|
||||
// render now
|
||||
$oPage->add("<div id=\"$sId\" class=\"display_block\">\n");
|
||||
$this->RenderContent($oPage, $aExtraParams);
|
||||
$oPage->add("</div>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// render it as an Ajax (asynchronous) call
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$oPage->add("<div id=\"$sId\" class=\"display_block loading\">\n");
|
||||
$oPage->p("<img src=\"../images/indicator_arrows.gif\"> Loading...");
|
||||
$oPage->add("</div>\n");
|
||||
$oPage->add('
|
||||
<script language="javascript">
|
||||
$.post("ajax.render.php?style='.$this->m_sStyle.'",
|
||||
{ operation: "ajax", filter: "$sFilter" },
|
||||
function(data){
|
||||
$("#'.$sId.'").empty();
|
||||
$("#'.$sId.'").append(data);
|
||||
$("#'.$sId.'").removeClass("loading");
|
||||
}
|
||||
);
|
||||
</script>'); // TO DO: add support for $aExtraParams in asynchronous/Ajax mode
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public function GetDisplay(WebPage $oPage, $sId, $aExtraParams = array())
|
||||
@@ -262,41 +232,20 @@ class DisplayBlock
|
||||
$sHtml .= "<div id=\"$sId\" class=\"display_block loading\">\n";
|
||||
$sHtml .= $oPage->GetP("<img src=\"../images/indicator_arrows.gif\"> ".Dict::S('UI:Loading'));
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= '
|
||||
<script language="javascript">
|
||||
$oPage->add_script('
|
||||
$.post("ajax.render.php?style='.$this->m_sStyle.'",
|
||||
{ operation: "ajax", filter: "'.$sFilter.'", extra_params: "'.$sExtraParams.'" },
|
||||
function(data){
|
||||
$("#'.$sId.'").empty();
|
||||
$("#'.$sId.'").append(data);
|
||||
$("#'.$sId.'").removeClass("loading");
|
||||
// Check each "listResults" table for a checkbox in the first column and make the first column sortable only if it does not contain a checkbox in the header
|
||||
$("#'.$sId.'".listResults").each( function()
|
||||
{
|
||||
var table = $(this);
|
||||
var id = $(this).parent();
|
||||
var checkbox = (table.find(\'th:first :checkbox\').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, do not make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: [\'myZebra\', \'truncatedList\']} ); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: [\'myZebra\', \'truncatedList\']} ); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
</script>';
|
||||
');
|
||||
}
|
||||
if ($bAutoReload)
|
||||
{
|
||||
$sHtml .= '
|
||||
<script language="javascript">
|
||||
setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');
|
||||
</script>';
|
||||
$oPage->add_script('setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
@@ -331,9 +280,10 @@ class DisplayBlock
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass));
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
foreach($oAppContext->GetNames() as $sContextParam)
|
||||
{
|
||||
eval("\$sParamCode = $sClass::MapContextParam('$sContextParam');"); //Map context parameter to the value/filter code depending on the class
|
||||
$sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class
|
||||
if (!is_null($sParamCode))
|
||||
{
|
||||
$sParamValue = $oAppContext->GetCurrentValue($sContextParam, null);
|
||||
@@ -345,7 +295,7 @@ class DisplayBlock
|
||||
}
|
||||
foreach($aFilterCodes as $sFilterCode)
|
||||
{
|
||||
$sExternalFilterValue = utils::ReadParam($sFilterCode, '');
|
||||
$sExternalFilterValue = utils::ReadParam($sFilterCode, '', false, 'raw_data');
|
||||
$condition = null;
|
||||
if (isset($aExtraParams[$sFilterCode]))
|
||||
{
|
||||
@@ -361,11 +311,33 @@ class DisplayBlock
|
||||
|
||||
if (!is_null($condition))
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator
|
||||
$this->AddCondition($sFilterCode, $condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
$aOrderBy = array();
|
||||
if (isset($aExtraParams['order_by']))
|
||||
{
|
||||
// Convert the string describing the order_by parameter into an array
|
||||
// The syntax is +attCode1,-attCode2
|
||||
// attCode1 => ascending, attCode2 => descending
|
||||
$aTemp = explode(',', $aExtraParams['order_by']);
|
||||
foreach($aTemp as $sTemp)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match('/^([+-])?(.+)$/', $sTemp, $aMatches))
|
||||
{
|
||||
$bAscending = true;
|
||||
if ($aMatches[1] == '-')
|
||||
{
|
||||
$bAscending = false;
|
||||
}
|
||||
$aOrderBy[$aMatches[2]] = $bAscending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, $aOrderBy, $aQueryParams);
|
||||
}
|
||||
switch($this->m_sStyle)
|
||||
{
|
||||
@@ -375,6 +347,7 @@ class DisplayBlock
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
$sLabels = array();
|
||||
$iTotalCount = $this->m_oSet->Count();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
@@ -395,12 +368,14 @@ class DisplayBlock
|
||||
foreach($aGroupBy as $sValue => $iCount)
|
||||
{
|
||||
$aData[] = array ( 'group' => $sLabels[$sValue],
|
||||
'value' => "<a href=\"./UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group' => array('label' => MetaModel::GetLabel($this->m_oFilter->GetClass(), $sGroupByField), 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))
|
||||
);
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
$sHtml .= $oPage->GetP(Dict::Format($sFormat, $iTotalCount));
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aData);
|
||||
}
|
||||
else
|
||||
@@ -574,7 +549,7 @@ class DisplayBlock
|
||||
}
|
||||
}
|
||||
|
||||
$sHtml .= $oPage->GetP("<a href=\"./UI.php?operation=new&class=$sClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
$sHtml .= $oPage->GetP("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -610,7 +585,7 @@ class DisplayBlock
|
||||
$sDefaults .= '&'.urlencode($sName).'='.urlencode($sValue);
|
||||
}
|
||||
}
|
||||
$sHtml .= $oPage->GetP("<a href=\"../pages/UI.php?operation=modify_links&class=$sClass&sParams&link_attr=".$aExtraParams['link_attr']."&id=".$aExtraParams['object_id']."&target_class=$sTargetClass&addObjects=true$sDefaults\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
$sHtml .= $oPage->GetP("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=modify_links&class=$sClass&sParams&link_attr=".$aExtraParams['link_attr']."&id=".$aExtraParams['object_id']."&target_class=$sTargetClass&addObjects=true$sDefaults\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -635,7 +610,7 @@ class DisplayBlock
|
||||
$sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null);
|
||||
if (!is_null($sContextParamValue) && ! empty($sContextParamValue) && MetaModel::IsValidFilterCode($sClass, $sFilterCode))
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $sContextParamValue); // Use the default 'loose' operator
|
||||
$this->AddCondition($sFilterCode, $sContextParamValue);
|
||||
}
|
||||
}
|
||||
$aQueryParams = array();
|
||||
@@ -646,7 +621,7 @@ class DisplayBlock
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
}
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = '../pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">';
|
||||
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;');
|
||||
$sHtml .= MetaModel::GetName($sClass).': '.$iCount.'</a></p>';
|
||||
@@ -654,9 +629,9 @@ class DisplayBlock
|
||||
$sHtml .= '<p>';
|
||||
if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY))
|
||||
{
|
||||
$sHtml .= "<a href=\"../pages/UI.php?operation=new&class={$sClass}&$sParams\">".Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($sClass))."</a><br/>\n";
|
||||
$sHtml .= "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class={$sClass}&$sParams\">".Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($sClass))."</a><br/>\n";
|
||||
}
|
||||
$sHtml .= "<a href=\"../pages/UI.php?operation=search_form&class={$sClass}&$sParams\">".Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass))."</a>\n";
|
||||
$sHtml .= "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search_form&class={$sClass}&$sParams\">".Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass))."</a>\n";
|
||||
$sHtml .= '</p>';
|
||||
break;
|
||||
|
||||
@@ -677,7 +652,7 @@ class DisplayBlock
|
||||
$sContextParamValue = $oAppContext->GetCurrentValue($sFilterCode, null);
|
||||
if (!is_null($sContextParamValue) && ! empty($sContextParamValue) && MetaModel::IsValidFilterCode($sClass, $sFilterCode))
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $sContextParamValue); // Use the default 'loose' operator
|
||||
$this->AddCondition($sFilterCode, $sContextParamValue);
|
||||
}
|
||||
}
|
||||
$aQueryParams = array();
|
||||
@@ -700,14 +675,14 @@ class DisplayBlock
|
||||
$oFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$aCounts[$sStateValue] = $oSet->Count();
|
||||
$aStateLabels[$sStateValue] = Dict::S("Class:".$oAttDef->GetHostClass()."/Attribute:$sStateAttrCode/Value:$sStateValue");
|
||||
$aStateLabels[$sStateValue] = $oAttDef->GetValueLabel($sStateValue);
|
||||
if ($aCounts[$sStateValue] == 0)
|
||||
{
|
||||
$aCounts[$sStateValue] = '-';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHyperlink = '../pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$oFilter->serialize();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$oFilter->serialize();
|
||||
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
|
||||
}
|
||||
}
|
||||
@@ -716,18 +691,11 @@ class DisplayBlock
|
||||
$sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>';
|
||||
// Title & summary
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = '../pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>';
|
||||
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
|
||||
break;
|
||||
|
||||
case 'bare_details':
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
$sHtml .= $oObj->GetBareProperties($oPage);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'csv':
|
||||
$sHtml .= "<textarea style=\"width:95%;height:98%\">\n";
|
||||
$sHtml .= cmdbAbstractObject::GetSetAsCSV($this->m_oSet);
|
||||
@@ -764,6 +732,12 @@ EOF
|
||||
|
||||
case 'open_flash_chart':
|
||||
static $iChartCounter = 0;
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
if (!empty($sContext))
|
||||
{
|
||||
$sContext = '&'.$sContext;
|
||||
}
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sTitle = isset($aExtraParams['chart_title']) ? $aExtraParams['chart_title'] : '';
|
||||
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
|
||||
@@ -772,13 +746,58 @@ EOF
|
||||
$sHtml .= "<div id=\"my_chart_{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n";
|
||||
$oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }");
|
||||
$oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
|
||||
{\"data-file\":\"".urlencode("../pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
|
||||
{\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle&id=$sId&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
|
||||
$iChartCounter++;
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
}
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
$aLabels = array();
|
||||
$idx = 0;
|
||||
$aURLs = array();
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$oDrillDownFilter = clone $this->m_oFilter;
|
||||
$oDrillDownFilter->AddCondition($sGroupByField, $sValue, '=');
|
||||
$aURLs[$idx] = $oDrillDownFilter->serialize();
|
||||
$idx++;
|
||||
}
|
||||
$sURLList = '';
|
||||
foreach($aURLs as $index => $sURL)
|
||||
{
|
||||
$sURLList .= "\taURLs[$index] = '".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html{$sContext}&filter=".addslashes($sURL)."';\n";
|
||||
}
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function ofc_drill_down_{$sId}(index)
|
||||
{
|
||||
var aURLs = new Array();
|
||||
{$sURLList}
|
||||
window.location.href=aURLs[index];
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'open_flash_chart_ajax':
|
||||
require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
|
||||
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
|
||||
$sId = utils::ReadParam('id', '');
|
||||
|
||||
$oChart = new open_flash_chart();
|
||||
switch($sChartType)
|
||||
@@ -805,12 +824,15 @@ EOF
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
$aLabels = array();
|
||||
$maxValue = 0;
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$aData[] = $iValue;
|
||||
$oBarValue = new bar_value($iValue);
|
||||
$oBarValue->on_click("ofc_drill_down_$sId");
|
||||
$aData[] = $oBarValue;
|
||||
if ($iValue > $maxValue) $maxValue = $iValue;
|
||||
$aLabels[] = $sValue;
|
||||
}
|
||||
$maxValue = max($aData);
|
||||
$oYAxis = new y_axis();
|
||||
$aMagicValues = array(1,2,5,10);
|
||||
$iMultiplier = 1;
|
||||
@@ -869,7 +891,9 @@ EOF
|
||||
$aData = array();
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$aData[] = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
|
||||
$PieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
|
||||
$PieValue->on_click("ofc_drill_down_$sId");
|
||||
$aData[] = $PieValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -894,6 +918,43 @@ EOF
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a condition (restriction) to the current DBObjectSearch on which the display block is based
|
||||
* taking into account the hierarchical keys for which the condition is based on the 'below' operator
|
||||
*/
|
||||
protected function AddCondition($sFilterCode, $condition)
|
||||
{
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$bConditionAdded = false;
|
||||
|
||||
// If the condition is an external key with a class having a hierarchy, use a "below" criteria
|
||||
if (MetaModel::IsValidAttCode($sClass, $sFilterCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sFilterCode);
|
||||
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($oAttDef->GetTargetClass());
|
||||
|
||||
if ($sHierarchicalKeyCode !== false)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oFilter->AddCondition('id', $condition);
|
||||
$oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass());
|
||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
|
||||
$this->m_oFilter->AddCondition_PointingTo($oHKFilter, $sFilterCode);
|
||||
$bConditionAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In all other cases, just add the condition directly
|
||||
if (!$bConditionAdded)
|
||||
{
|
||||
$this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -973,7 +1034,7 @@ class HistoryBlock extends DisplayBlock
|
||||
$aValues = array();
|
||||
foreach($aChanges as $aChange)
|
||||
{
|
||||
$aValues[] = array('date' => $aChange['date'], 'userinfo' => $aChange['userinfo'], 'log' => "<ul><li>".implode('</li><li>', $aChange['log'])."</li></ul>");
|
||||
$aValues[] = array('date' => $aChange['date'], 'userinfo' => htmlentities($aChange['userinfo'], ENT_QUOTES, 'UTF-8'), 'log' => "<ul><li>".implode('</li><li>', $aChange['log'])."</li></ul>");
|
||||
}
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
||||
return $sHtml;
|
||||
@@ -996,11 +1057,17 @@ class MenuBlock extends DisplayBlock
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
if (!empty($sContext))
|
||||
{
|
||||
$sContext = '&'.$sContext;
|
||||
}
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$oSet = new CMDBObjectSet($this->m_oFilter);
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilterDesc = $this->m_oFilter->ToOql();
|
||||
$aActions = array();
|
||||
$sUIPage = cmdbAbstractObject::ComputeUIPage($sClass);
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
|
||||
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
// 1:n links, populate the target object as a default value when creating a new linked object
|
||||
if (isset($aExtraParams['target_attr']))
|
||||
{
|
||||
@@ -1019,7 +1086,7 @@ class MenuBlock extends DisplayBlock
|
||||
case 0:
|
||||
// No object in the set, the only possible action is "new"
|
||||
$bIsModifyAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES);
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "../page/$sUIPage?operation=new&class=$sClass&$sContext{$sDefault}"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@@ -1032,10 +1099,9 @@ class MenuBlock extends DisplayBlock
|
||||
// Just one object in the set, possible actions are "new / clone / modify and delete"
|
||||
if (!isset($aExtraParams['link_attr']))
|
||||
{
|
||||
$sUrl = utils::GetAbsoluteUrl(false);
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Modify'), 'url' => "../pages/$sUIPage?operation=modify&class=$sClass&id=$id&$sContext#"); }
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "../pages/$sUIPage?operation=new&class=$sClass&$sContext{$sDefault}"); }
|
||||
if ($bIsDeleteAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Delete'), 'url' => "../pages/$sUIPage?operation=delete&class=$sClass&id=$id&$sContext"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:Modify'] = array ('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify&class=$sClass&id=$id{$sContext}#"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsDeleteAllowed) { $aActions['UI:Menu:Delete'] = array ('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=delete&class=$sClass&id=$id{$sContext}"); }
|
||||
// Transitions / Stimuli
|
||||
$aTransitions = $oObj->EnumTransitions();
|
||||
if (count($aTransitions))
|
||||
@@ -1048,7 +1114,7 @@ class MenuBlock extends DisplayBlock
|
||||
switch($iActionAllowed)
|
||||
{
|
||||
case UR_ALLOWED_YES:
|
||||
$aActions[] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "../pages/UI.php?operation=stimulus&stimulus=$sStimulusCode&class=$sClass&id=$id&$sContext");
|
||||
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus=$sStimulusCode&class=$sClass&id=$id{$sContext}");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1063,23 +1129,14 @@ class MenuBlock extends DisplayBlock
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach($aRelations as $sRelationCode)
|
||||
{
|
||||
$aActions[] = array ('label' => MetaModel::GetRelationVerbUp($sRelationCode), 'url' => "../pages/$sUIPage?operation=swf_navigator&relation=$sRelationCode&class=$sClass&id=$id&$sContext");
|
||||
$aActions[$sRelationCode] = array ('label' => MetaModel::GetRelationVerbUp($sRelationCode), 'url' => "{$sRootUrl}pages/$sUIPage?operation=swf_navigator&relation=$sRelationCode&class=$sClass&id=$id{$sContext}");
|
||||
}
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
// Static menus: Email this page & CSV Export
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".$oObj->GetName()."&body=".urlencode("$sUrl?operation=details&class=$sClass&id=$id&$sContext"));
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "../pages/$sUIPage?operation=search&filter=$sFilter&format=csv&$sContext");
|
||||
}
|
||||
else
|
||||
{
|
||||
// List of links, the only actions are 'Add...' and 'Manage...'
|
||||
$id = $aExtraParams['object_id'];
|
||||
$sTargetAttr = $aExtraParams['target_attr'];
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Add'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&addObjects=true&$sContext"); }
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Manage'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&sContext"); }
|
||||
$sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=$sFilter&format=csv{$sContext}");
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
@@ -1087,7 +1144,7 @@ class MenuBlock extends DisplayBlock
|
||||
$oSet->Rewind();
|
||||
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl)
|
||||
{
|
||||
$aActions[] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1105,17 +1162,16 @@ class MenuBlock extends DisplayBlock
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Add'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&addObjects=true&$sContext"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:Manage'), 'url' => "../pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&sContext"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:Add'] = array ('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id&addObjects=true{$sContext}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:Manage'] = array ('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify_links&class=$sClass&link_attr=".$aExtraParams['link_attr']."&target_class=$sTargetClass&id=$id{$sContext}"); }
|
||||
//if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
// many objects in the set, possible actions are: new / modify all / delete all
|
||||
$sUrl = utils::GetAbsoluteUrl();
|
||||
if ($bIsModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "../pages/$sUIPage?operation=new&class=$sClass&$sContext{$sDefault}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "../pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=$sFilter&sContext"); }
|
||||
if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "../pages/$sUIPage?operation=select_for_deletion&filter=$sFilter&$sContext"); }
|
||||
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=$sFilter{$sContext}"); }
|
||||
if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=$sFilter{$sContext}"); }
|
||||
|
||||
// Stimuli
|
||||
$aStates = MetaModel::EnumStates($sClass);
|
||||
@@ -1146,7 +1202,7 @@ class MenuBlock extends DisplayBlock
|
||||
{
|
||||
case UR_ALLOWED_YES:
|
||||
case UR_ALLOWED_DEPENDS:
|
||||
$aActions[] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "../pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=$sFilter&$sContext");
|
||||
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=$sFilter{$sContext}");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1157,8 +1213,9 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".$oSet->GetFilter()->__DescribeHTML()."&body=".urlencode("$sUrl?operation=search&filter=$sFilter&$sContext"));
|
||||
$aActions[] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "../pages/$sUIPage?operation=search&filter=$sFilter&format=csv&$sContext");
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=$sFilter{$sContext}"));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=$sFilter&format=csv{$sContext}");
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
@@ -1166,24 +1223,67 @@ class MenuBlock extends DisplayBlock
|
||||
$oSet->Rewind();
|
||||
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl)
|
||||
{
|
||||
$aActions[] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
foreach ($aActions as $aAction)
|
||||
$aFavoriteActions = array();
|
||||
$aCallSpec = array($sClass, 'GetShortcutActions');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
|
||||
if (empty($aAction['url']))
|
||||
$aShortcutActions = call_user_func($aCallSpec, $sClass);
|
||||
foreach ($aActions as $key => $aAction)
|
||||
{
|
||||
$sHtml .= "<li>{$aAction['label']}</li>\n";
|
||||
if (in_array($key, $aShortcutActions))
|
||||
{
|
||||
$aFavoriteActions[] = $aAction;
|
||||
unset($aActions[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aShortcutActions = array();
|
||||
}
|
||||
|
||||
if (count($aFavoriteActions) > 0)
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
}
|
||||
$sPrevUrl = '';
|
||||
foreach ($aActions as $key => $aAction)
|
||||
{
|
||||
if (in_array($key, $aShortcutActions))
|
||||
{
|
||||
$aFavoriteActions[] = $aAction;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass>{$aAction['label']}</a></li>\n";
|
||||
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
|
||||
if (empty($aAction['url']))
|
||||
{
|
||||
if ($sPrevUrl != '') // Don't output consecutively two separators...
|
||||
{
|
||||
$sHtml .= "<li>{$aAction['label']}</li>\n";
|
||||
}
|
||||
$sPrevUrl = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass>{$aAction['label']}</a></li>\n";
|
||||
$sPrevUrl = $aAction['url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml .= "</ul>\n</li>\n</ul></div>\n";
|
||||
$sHtml .= "</ul>\n</li>\n</ul></div>";
|
||||
foreach(array_reverse($aFavoriteActions) as $aAction)
|
||||
{
|
||||
$sHtml .= "<div class=\"actions_button\"><a href='{$aAction['url']}'>{$aAction['label']}</a></div>";
|
||||
}
|
||||
static $bPopupScript = false;
|
||||
if (!$bPopupScript)
|
||||
{
|
||||
@@ -1204,9 +1304,11 @@ class MenuBlock extends DisplayBlock
|
||||
$sSeparator = '<hr class="menu-separator"/>';
|
||||
if (count($aActions) > 0) // Make sure that the separator is not the first item in the menu
|
||||
{
|
||||
if ($aActions[count($aActions)-1]['label'] != $sSeparator) // Make sure there are no 2 consecutive separators
|
||||
$aKeys = array_keys($aActions);
|
||||
$sLastKey = array_pop($aKeys);
|
||||
if ($aActions[$sLastKey]['label'] != $sSeparator) // Make sure there are no 2 consecutive separators
|
||||
{
|
||||
$aActions[] = array('label' => $sSeparator, 'url' => '');
|
||||
$aActions['sep_'.(count($aActions)-1)] = array('label' => $sSeparator, 'url' => '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,32 +39,33 @@ class iTopWebPage extends NiceWebPage
|
||||
private $m_sMessage;
|
||||
private $m_sInitScript;
|
||||
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->m_sCurrentTabContainer = '';
|
||||
$this->m_sCurrentTab = '';
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
|
||||
ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
|
||||
|
||||
$this->m_sCurrentTabContainer = '';
|
||||
$this->m_sCurrentTab = '';
|
||||
$this->m_aTabs = array();
|
||||
$this->m_sMenu = "";
|
||||
$this->m_sMessage = '';
|
||||
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sExtraParams = $oAppContext->GetForLink();
|
||||
// $this->m_currentOrganization = $currentOrganization;
|
||||
$sAppContext = addslashes($sExtraParams);
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$this->add_linked_stylesheet("../css/jquery.treeview.css");
|
||||
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
|
||||
// $this->add_linked_stylesheet("../css/date.picker.css");
|
||||
$this->add_linked_script('../js/jquery.layout.min.js');
|
||||
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
|
||||
// $this->add_linked_script("../js/jquery.dimensions.js");
|
||||
$this->add_linked_script("../js/jquery.tablehover.js");
|
||||
$this->add_linked_script("../js/jquery.treeview.js");
|
||||
$this->add_linked_script("../js/jquery.autocomplete.js");
|
||||
$this->add_linked_script("../js/jquery.positionBy.js");
|
||||
$this->add_linked_script("../js/jquery.popupmenu.js");
|
||||
$this->add_linked_script("../js/date.js");
|
||||
// $this->add_linked_script("../js/jquery.date.picker.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.min.js");
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../js/utils.js");
|
||||
@@ -72,6 +73,7 @@ class iTopWebPage extends NiceWebPage
|
||||
$this->add_linked_script("../js/ckeditor/ckeditor.js");
|
||||
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
|
||||
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
|
||||
$this->m_sInitScript =
|
||||
<<< EOF
|
||||
try
|
||||
@@ -144,7 +146,7 @@ class iTopWebPage extends NiceWebPage
|
||||
// that the tabs aren't changed on click, and any custom event name can be
|
||||
// specified. Note that if you define a callback for the 'select' event, it
|
||||
// will be executed for the selected tab whenever the hash changes.
|
||||
tabs.tabs({ event: 'change' });
|
||||
tabs.tabs({ event: 'change'});
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
@@ -286,26 +288,22 @@ EOF
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Shortcut menu actions
|
||||
$('.actions_button a').click( function() {
|
||||
aMatches = /#(.*)$/.exec(window.location.href);
|
||||
if (aMatches != null)
|
||||
{
|
||||
currentHash = aMatches[1];
|
||||
if ( /#(.*)$/.test(this.href))
|
||||
{
|
||||
this.href = this.href.replace(/#(.*)$/, '#'+currentHash);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// End of Tabs handling
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
// Check each 'listResults' table for a checkbox in the first column and make the first column sortable only if it does not contain a checkbox in the header
|
||||
$(".listResults").each( function()
|
||||
{
|
||||
var table = $(this);
|
||||
var id = $(this).parent();
|
||||
var checkbox = (table.find('th:first :checkbox').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
$(".date-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
@@ -368,10 +366,6 @@ EOF
|
||||
// }
|
||||
// }
|
||||
|
||||
function formatItem(row) {
|
||||
return row[0];
|
||||
}
|
||||
|
||||
function goBack()
|
||||
{
|
||||
window.history.back();
|
||||
@@ -379,22 +373,23 @@ EOF
|
||||
|
||||
function BackToDetails(sClass, id, sDefaultUrl)
|
||||
{
|
||||
window.bInCancel = true;
|
||||
if (id > 0)
|
||||
{
|
||||
window.location.href = './UI.php?operation=details&class='+sClass+'&id='+id;
|
||||
window.location.href = AddAppContext(GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=details&class='+sClass+'&id='+id);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.location.href = sDefaultUrl;
|
||||
window.location.href = sDefaultUrl; // Already contains the context...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function BackToList(sClass)
|
||||
{
|
||||
window.location.href = './UI.php?operation=search_oql&oql_class='+sClass+'&oql_clause=WHERE id=0';
|
||||
window.location.href = AddAppContext(GetAbsoluteUrlAppRoot()+'pages/UI.php?operation=search_oql&oql_class='+sClass+'&oql_clause=WHERE id=0');
|
||||
}
|
||||
|
||||
|
||||
function ShowDebug()
|
||||
{
|
||||
if ($('#rawOutput > div').html() != '')
|
||||
@@ -403,6 +398,25 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
|
||||
var oUserPreferences = $sUserPrefs;
|
||||
|
||||
// For disabling the CKEditor at init time when the corresponding textarea is disabled !
|
||||
@@ -443,11 +457,22 @@ EOF
|
||||
{
|
||||
// List of visible Organizations
|
||||
$iCount = 0;
|
||||
$oSet = null;
|
||||
if (MetaModel::IsValidClass('Organization'))
|
||||
{
|
||||
// Display the list of *favorite* organizations... but keeping in mind what is the real number of organizations
|
||||
$aFavoriteOrgs = appUserPreferences::GetPref('favorite_orgs', null);
|
||||
$oSearchFilter = new DBObjectSearch('Organization');
|
||||
$oSet = new CMDBObjectSet($oSearchFilter);
|
||||
$iCount = $oSet->Count();
|
||||
$iCount = $oSet->Count(); // total number of existing Orgs
|
||||
|
||||
// Now get the list of Orgs to be displayed in the menu
|
||||
$oSearchFilter = DBObjectSearch::FromOQL(ApplicationMenu::GetFavoriteSiloQuery());
|
||||
if (!empty($aFavoriteOrgs))
|
||||
{
|
||||
$oSearchFilter->AddCondition('id', $aFavoriteOrgs, 'IN');
|
||||
}
|
||||
$oSet = new CMDBObjectSet($oSearchFilter); // List of favorite orgs
|
||||
}
|
||||
switch($iCount)
|
||||
{
|
||||
@@ -464,10 +489,12 @@ EOF
|
||||
break;
|
||||
|
||||
default:
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iCurrentOrganization = $oAppContext->GetCurrentValue('org_id');
|
||||
$sHtml = '<div id="SiloSelection">';
|
||||
$sHtml .= '<form style="display:inline" action="'.$_SERVER['PHP_SELF'].'"><select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
$sHtml .= '<form style="display:inline" action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">'; //<select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
/*
|
||||
$sSelected = ($iCurrentOrganization == '') ? ' selected' : '';
|
||||
$sHtml .= '<option value=""'.$sSelected.'>'.Dict::S('UI:AllOrganizations').'</option>';
|
||||
while($oOrg = $oSet->Fetch())
|
||||
@@ -485,10 +512,16 @@ EOF
|
||||
$sHtml .= '<option title="'.$oOrg->GetName().'" value="'.$oOrg->GetKey().'"'.$sSelected.'>'.$oOrg->GetName().'</option>';
|
||||
}
|
||||
$sHtml .= '</select>';
|
||||
*/
|
||||
$sFavoriteOrgs = '';
|
||||
$oWidget = new UIExtKeyWidget('Organization', 'org_id');
|
||||
$sHtml .= $oWidget->Display($this, 50, false, '', $oSet, $iCurrentOrganization, 'org_id', false, 'c[org_id]', '', array('iFieldSize' => 20, 'sDefaultValue' => Dict::S('UI:AllOrganizations')), $bSearchMode = true);
|
||||
$this->add_ready_script('$("#org_id").bind("extkeychange", function() { $("#SiloSelection form").submit(); } )');
|
||||
$this->add_ready_script("$('#label_org_id').click( function() { $(this).val(''); $('#org_id').val(''); return true; } );\n");
|
||||
// Add other dimensions/context information to this form
|
||||
// $oAppContext = new ApplicationContext();
|
||||
$oAppContext->Reset('org_id'); // org_id is handled above and we want to be able to change it here !
|
||||
$sHtml .= $oAppContext->GetForForm();
|
||||
$oAppContext->Reset('menu'); // don't pass the menu, since a menu may expect more parameters
|
||||
$sHtml .= $oAppContext->GetForForm(); // Pass what remains, if anything...
|
||||
$sHtml .= '</form>';
|
||||
$sHtml .= '</div>';
|
||||
}
|
||||
@@ -509,6 +542,7 @@ EOF
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$sForm = $this->GetSiloSelectionForm();
|
||||
$this->DisplayMenu(); // Compute the menu
|
||||
|
||||
// Put here the 'ready scripts' that must be executed after all others
|
||||
@@ -517,6 +551,9 @@ EOF
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
// the event now, to handle the hash the page may have loaded with.
|
||||
$(window).trigger( 'hashchange' );
|
||||
|
||||
// Some table are sort-able, some are not, let's fix this
|
||||
$('table.listResults').each( function() { FixTableSorter($(this)); } );
|
||||
|
||||
EOF
|
||||
);
|
||||
@@ -532,7 +569,7 @@ EOF
|
||||
// Make sure that Internet Explorer renders the page using its latest/highest/greatest standards !
|
||||
echo "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<title>{$this->s_title}</title>\n";
|
||||
echo "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
echo $this->get_base_tag();
|
||||
// Stylesheets MUST be loaded before any scripts otherwise
|
||||
// jQuery scripts may face some spurious problems (like failing on a 'reload')
|
||||
@@ -586,7 +623,7 @@ EOF
|
||||
}
|
||||
echo "</style>\n";
|
||||
}
|
||||
echo "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"./opensearch.xml.php\" />\n";
|
||||
echo "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"".utils::GetAbsoluteUrlAppRoot()."opensearch.xml.php\" />\n";
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
|
||||
@@ -596,7 +633,6 @@ EOF
|
||||
|
||||
|
||||
|
||||
|
||||
// Render the revision number
|
||||
if (ITOP_REVISION == '$WCREV$')
|
||||
{
|
||||
@@ -610,7 +646,7 @@ EOF
|
||||
}
|
||||
|
||||
// Render the text of the global search form
|
||||
$sText = Utils::ReadParam('text', '');
|
||||
$sText = htmlentities(utils::ReadParam('text', '', false, 'raw_data'), ENT_QUOTES, 'UTF-8');
|
||||
$sOnClick = "";
|
||||
if (empty($sText))
|
||||
{
|
||||
@@ -619,10 +655,7 @@ EOF
|
||||
// 2) clicking on it will erase it
|
||||
$sText = Dict::S("UI:YourSearch");
|
||||
$sOnClick = " onclick=\"this.value='';this.onclick=null;\"";
|
||||
}
|
||||
|
||||
$sForm = $this->GetSiloSelectionForm();
|
||||
|
||||
}
|
||||
// Render the tabs in the page (if any)
|
||||
foreach($this->m_aTabs as $sTabContainerName => $m_aTabs)
|
||||
{
|
||||
@@ -664,15 +697,16 @@ EOF
|
||||
}
|
||||
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/onOffBtn.png\"><ul>";
|
||||
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/preferences.php\">".Dict::S('UI:Preferences')."</a></li>\n";
|
||||
|
||||
if (utils::CanLogOff() && UserRights::CanLogOff())
|
||||
if (utils::CanLogOff())
|
||||
{
|
||||
//$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=logoff\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"../pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
}
|
||||
if (UserRights::CanChangePassword())
|
||||
{
|
||||
$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";
|
||||
}
|
||||
$sLogOffMenu .= "</ul>\n</li>\n</ul></span>\n";
|
||||
|
||||
@@ -716,16 +750,16 @@ EOF
|
||||
echo '<div id="left-pane" class="ui-layout-west">';
|
||||
echo '<!-- Beginning of the left pane -->';
|
||||
echo ' <div id="header-logo">';
|
||||
echo ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.$sVersionString.'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
echo ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
echo ' </div>';
|
||||
echo ' <div class="header-menu">';
|
||||
echo ' <div class="icon ui-state-default ui-corner-all"><span id="tPinMenu" class="ui-icon ui-icon-pin-w">pin</span></div>';
|
||||
echo ' <div style="text-align:center;">'.$sForm.'</div>';
|
||||
echo ' <div style="text-align:center;">'.self::FilterXSS($sForm).'</div>';
|
||||
echo ' </div>';
|
||||
echo ' <div id="menu" class="ui-layout-content">';
|
||||
echo ' <div id="inner_menu">';
|
||||
echo ' <div id="accordion">';
|
||||
echo $this->m_sMenu;
|
||||
echo self::FilterXSS($this->m_sMenu);
|
||||
echo ' <!-- Beginning of the accordion menu -->';
|
||||
echo ' <!-- End of the accordion menu-->';
|
||||
echo ' </div>';
|
||||
@@ -737,74 +771,26 @@ EOF
|
||||
|
||||
echo '<div class="ui-layout-center">';
|
||||
echo ' <div id="top-bar" style="width:100%">';
|
||||
echo $sApplicationBanner;
|
||||
echo ' <div id="global-search"><form action="../pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="'.$sText.'"'.$sOnClick.'/></td>';
|
||||
echo self::FilterXSS($sApplicationBanner);
|
||||
echo ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="'.$sText.'"'.$sOnClick.'/></td>';
|
||||
echo '<td><input type="image" src="../images/searchBtn.png"/></a></td>';
|
||||
echo '<td><a style="background:transparent;" href="'.$sOnlineHelpUrl.'" target="_blank"><img style="border:0;padding-left:20px;padding-right:10px;" title="'.Dict::S('UI:Help').'" src="../images/help.png"/></td>';
|
||||
echo '<td style="padding-right:20px;padding-left:10px;">'.$sLogOffMenu.'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
echo '<td style="padding-right:20px;padding-left:10px;">'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
//echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
echo ' </div>';
|
||||
echo ' <div class="ui-layout-content">';
|
||||
echo ' <!-- Beginning of page content -->';
|
||||
echo $this->s_content;
|
||||
echo self::FilterXSS($this->s_content);
|
||||
echo ' <!-- End of page content -->';
|
||||
echo ' </div>';
|
||||
echo '</div>';
|
||||
/*
|
||||
echo "<div class=\"iTopLogo\" title=\"$sVersionString\"><span>iTop</span></div>\n";
|
||||
//echo "<div id=\"GlobalSearch\"><div style=\"border: 1px solid #999; padding:1px; background-color:#fff;\"><img src=\"../images/magnifier.gif\"/><input style=\"border:0\" type=\"text\" size=\"15\" title=\"Global Search\"></input></div></div>\n";
|
||||
$sText = Utils::ReadParam('text', '');
|
||||
$sOnClick = "";
|
||||
if (empty($sText))
|
||||
{
|
||||
// if no search text is supplied then
|
||||
// 1) the search text is filled with "your search"
|
||||
// 2) clicking on it will erase it
|
||||
$sText = Dict::S("UI:YourSearch");
|
||||
$sOnClick = " onclick=\"this.value='';this.onclick=null;\"";
|
||||
}
|
||||
$sUserName = UserRights::GetUser();
|
||||
$sIsAdmin = UserRights::IsAdministrator() ? '(Administrator)' : '';
|
||||
if (UserRights::IsAdministrator())
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage+Admin', $sUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName);
|
||||
}
|
||||
$sLogOffBtn = Dict::S('UI:Button:Logoff');
|
||||
$sSearchBtn = Dict::S('UI:Button:GlobalSearch');
|
||||
echo "<div id=\"Login\" style=\"position:absolute; top:18px; right:16px; width:600px;\">{$sLogonMessage} ";
|
||||
echo "<form action=\"../pages/UI.php\" method=\"post\" style=\"display:inline\">\n";
|
||||
echo "<input type=\"submit\" value=\"$sLogOffBtn\" />\n";
|
||||
echo "<input type=\"hidden\" name=\"loginop\" value=\"logoff\" />\n";
|
||||
echo "</form>\n";
|
||||
echo "<form action=\"../pages/UI.php\" style=\"display:inline\"><div style=\"padding:1px; background-color:#fff;display:inline;\"><img src=\"../images/magnifier.gif\"/><input style=\"border:0\" type=\"text\" size=\"15\" title=\"Global Search\" name=\"text\" value=\"$sText\"$sOnClick></input></div><input type=\"submit\" value=\"$sSearchBtn\" />
|
||||
<input type=\"hidden\" name=\"operation\" value=\"full_text\" /></form>\n";
|
||||
echo "</div>\n";
|
||||
|
||||
echo "</div>\n";
|
||||
|
||||
// Display the menu
|
||||
echo "<div id=\"MySplitter\">\n";
|
||||
echo " <div id=\"LeftPane\">\n";
|
||||
echo $this->m_sMenu;
|
||||
echo " </div> <!-- LeftPane -->\n";
|
||||
|
||||
echo "<div id=\"RightPane\">\n";
|
||||
|
||||
|
||||
// Display the page's content
|
||||
echo $this->s_content;
|
||||
|
||||
*/
|
||||
// Add the captured output
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">$s_captured_output</div></div>\n";
|
||||
echo "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">".self::FilterXSS($s_captured_output)."</div></div>\n";
|
||||
}
|
||||
echo "<div id=\"at_the_end\">".$this->s_deferred_content."</div>";
|
||||
echo "<div id=\"at_the_end\">".self::FilterXSS($this->s_deferred_content)."</div>";
|
||||
// echo $this->s_deferred_content;
|
||||
echo "<div style=\"display:none\" title=\"ex2\" id=\"ex2\">Please wait...</div>\n"; // jqModal Window
|
||||
echo "<div style=\"display:none\" title=\"dialog\" id=\"ModalDlg\"></div>";
|
||||
@@ -919,6 +905,43 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
* @return mixed The current state of the 'html' output
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
if (!empty($this->m_sCurrentTabContainer) && !empty($this->m_sCurrentTab))
|
||||
{
|
||||
$iOffset = isset($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer][$this->m_sCurrentTab]): 0;
|
||||
return array('tc' => $this->m_sCurrentTabContainer, 'tab' => $this->m_sCurrentTab, 'offset' => $iOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::start_capture();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
if (is_array($offset))
|
||||
{
|
||||
$sCaptured = substr($this->m_aTabs[$offset['tc']][$offset['tab']], $offset['offset']);
|
||||
$this->m_aTabs[$offset['tc']][$offset['tab']] = substr($this->m_aTabs[$offset['tc']][$offset['tab']], 0, $offset['offset']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = parent::end_capture($offset);
|
||||
}
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message to be displayed in the 'admin-banner' section at the top of the page
|
||||
*/
|
||||
|
||||
@@ -48,7 +48,7 @@ class iTopWizardWebPage extends iTopWebPage
|
||||
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
|
||||
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
|
||||
}
|
||||
$sWizardHeader = "<div class=\"wizHeader\"><h1>{$this->s_title}</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
|
||||
$sWizardHeader = "<div class=\"wizHeader\"><h1>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
|
||||
$this->s_content = "$sWizardHeader<div class=\"wizContainer\">".$this->s_content."</div>";
|
||||
parent::output();
|
||||
}
|
||||
|
||||
@@ -27,8 +27,9 @@ require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
/**
|
||||
* Web page used for displaying the login form
|
||||
*/
|
||||
|
||||
class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct("iTop Login");
|
||||
@@ -92,6 +93,12 @@ EOF
|
||||
{
|
||||
switch($sLoginType)
|
||||
{
|
||||
case 'cas':
|
||||
utils::InitCASClient();
|
||||
// force CAS authentication
|
||||
phpCAS::forceAuthentication(); // Will redirect the user and exit since the user is not yet authenticated
|
||||
break;
|
||||
|
||||
case 'basic':
|
||||
case 'url':
|
||||
$this->add_header('WWW-Authenticate: Basic realm="'.Dict::Format('UI:iTopVersion:Short', ITOP_VERSION));
|
||||
@@ -103,8 +110,8 @@ EOF
|
||||
case 'external':
|
||||
case 'form':
|
||||
default: // In case the settings get messed up...
|
||||
$sAuthUser = utils::ReadParam('auth_user', '');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '');
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
|
||||
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
|
||||
$this->add("<div id=\"login-logo\"><a href=\"http://www.combodo.com/itop\"><img title=\"$sVersionShort\" src=\"../images/itop-logo-external.png\"></a></div>\n");
|
||||
@@ -120,8 +127,8 @@ EOF
|
||||
}
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table width=\"100%\">\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"$sAuthUser\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"$sAuthPwd\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"".htmlentities($sAuthPwd, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n");
|
||||
@@ -133,8 +140,7 @@ EOF
|
||||
|
||||
public function DisplayChangePwdForm($bFailedLogin = false)
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '');
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
|
||||
$sInconsistenPwdMsg = Dict::S('UI:Login:RetypePwdDoesNotMatch');
|
||||
@@ -216,10 +222,8 @@ EOF
|
||||
{
|
||||
if (self::SecureConnectionRequired() && !self::IsConnectionSecure())
|
||||
{
|
||||
// Non secured URL... redirect to a secured one
|
||||
$sUrl = Utils::GetAbsoluteUrl(true /* query string */, true /* force HTTPS */);
|
||||
header("Location: $sUrl");
|
||||
exit;
|
||||
// Non secured URL... request for a secure connection
|
||||
throw new Exception('Secure connection required!');
|
||||
}
|
||||
|
||||
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
|
||||
@@ -241,10 +245,82 @@ EOF
|
||||
$sLoginType = $aAllowedLoginTypes[$index];
|
||||
switch($sLoginType)
|
||||
{
|
||||
case 'cas':
|
||||
utils::InitCASClient();
|
||||
// check CAS authentication
|
||||
if (phpCAS::isAuthenticated())
|
||||
{
|
||||
// Check is a membership is required
|
||||
$sCASMemberships = MetaModel::GetConfig()->Get('cas_memberof');
|
||||
$bFound = false;
|
||||
if (!empty($sCASMemberships))
|
||||
{
|
||||
if (phpCAS::hasAttribute('memberOf'))
|
||||
{
|
||||
// A list of groups is specified, the user must a be member of (at least) one of them to pass
|
||||
$aCASMemberships = array();
|
||||
$aTmp = explode(';', $sCASMemberships);
|
||||
setlocale(LC_ALL, "en_US.utf8"); // !!! WARNING: this is needed to have the iconv //TRANSLIT working fine below !!!
|
||||
foreach($aTmp as $sGroupName)
|
||||
{
|
||||
$aCASMemberships[] = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Just in case remove accents and spaces...
|
||||
}
|
||||
|
||||
$aMemberOf = phpCAS::getAttribute('memberOf');
|
||||
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
|
||||
$aFilteredGroupNames = array();
|
||||
foreach($aMemberOf as $sGroupName)
|
||||
{
|
||||
$sGroupName = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Remove accents and spaces as well
|
||||
$aFilteredGroupNames[] = $sGroupName;
|
||||
if (in_array($sGroupName, $aCASMemberships))
|
||||
{
|
||||
$bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!$bFound)
|
||||
{
|
||||
phpCAS :: log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too bad, the user is not part of any of the group => not allowed
|
||||
phpCAS :: log("No 'memberOf' attribute found for user ".phpCAS::getUser().". Are you using the SAML protocol (S1) ?");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No membership required, anybody will pass
|
||||
$bFound = true;
|
||||
}
|
||||
|
||||
if ($bFound)
|
||||
{
|
||||
$sAuthUser = phpCAS::getUser();
|
||||
$sAuthPwd = '';
|
||||
$sLoginMode = 'cas';
|
||||
$sAuthentication = 'external';
|
||||
}
|
||||
else
|
||||
{
|
||||
// The user is not part of the allowed groups, => log out
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
|
||||
$sCASLogoutUrl = MetaModel::GetConfig()->Get('cas_logout_redirect_service');
|
||||
if (empty($sCASLogoutUrl))
|
||||
{
|
||||
$sCASLogoutUrl = $sUrl;
|
||||
}
|
||||
phpCAS::logoutWithRedirectService($sCASLogoutUrl); // Redirects to the CAS logout page
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'form':
|
||||
// iTop standard mode: form based authentication
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '');
|
||||
$sAuthPwd = utils::ReadPostedParam('auth_pwd', '');
|
||||
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
|
||||
$sAuthPwd = utils::ReadPostedParam('auth_pwd', '', 'raw_data');
|
||||
if ($sAuthUser != '')
|
||||
{
|
||||
$sLoginMode = 'form';
|
||||
@@ -284,10 +360,10 @@ EOF
|
||||
|
||||
case 'url':
|
||||
// Credentials passed directly in the url
|
||||
$sAuthUser = utils::ReadParam('auth_user', '');
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
if ($sAuthUser != '')
|
||||
{
|
||||
$sAuthPwd = utils::ReadParam('auth_pwd', '');
|
||||
$sAuthPwd = utils::ReadParam('auth_pwd', '', false, 'raw_data');
|
||||
$sLoginMode = 'url';
|
||||
}
|
||||
break;
|
||||
@@ -316,6 +392,7 @@ EOF
|
||||
{
|
||||
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sAuthentication))
|
||||
{
|
||||
//echo "Check Credentials returned false for user $sAuthUser!";
|
||||
self::ResetSession();
|
||||
$oPage = new LoginWebPage();
|
||||
$oPage->DisplayLoginForm( $sLoginMode, true /* failed attempt */);
|
||||
@@ -394,8 +471,8 @@ EOF
|
||||
{
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
UserRights::Login($sAuthUser); // Set the user's language
|
||||
$sOldPwd = utils::ReadPostedParam('old_pwd');
|
||||
$sNewPwd = utils::ReadPostedParam('new_pwd');
|
||||
$sOldPwd = utils::ReadPostedParam('old_pwd', 'raw_data');
|
||||
$sNewPwd = utils::ReadPostedParam('new_pwd', 'raw_data');
|
||||
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
|
||||
{
|
||||
$oPage = new LoginWebPage();
|
||||
@@ -412,14 +489,14 @@ EOF
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
|
||||
$oP->p("<a href=\"../pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
|
||||
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
|
||||
$oP->output();
|
||||
exit;
|
||||
}
|
||||
elseif ( (!$bIsAllowedToPortalUsers) && (UserRights::IsPortalUser()))
|
||||
{
|
||||
// No rights to be here, redirect to the portal
|
||||
header('Location: ../portal/index.php');
|
||||
header('Location: '.utils::GetAbsoluteUrlAppRoot().'portal/index.php');
|
||||
}
|
||||
return $sMessage;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,27 @@ class ApplicationMenu
|
||||
{
|
||||
static $aRootMenus = array();
|
||||
static $aMenusIndex = array();
|
||||
static $sFavoriteSiloQuery = 'SELECT Organization';
|
||||
|
||||
/**
|
||||
* Set the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @param $sOQL string The OQL query returning a list of Organization objects
|
||||
* @return none
|
||||
*/
|
||||
static public function SetFavoriteSiloQuery($sOQL)
|
||||
{
|
||||
self::$sFavoriteSiloQuery = $sOQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @return string The OQL query returning a list of Organization objects
|
||||
*/
|
||||
static public function GetFavoriteSiloQuery()
|
||||
{
|
||||
return self::$sFavoriteSiloQuery;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function to add a menu entry into the application, can be called during the definition
|
||||
@@ -327,7 +348,7 @@ abstract class MenuNode
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$aExtraParams['c[menu]'] = $this->GetIndex();
|
||||
return $this->AddParams('../pages/UI.php', $aExtraParams);
|
||||
return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -652,7 +673,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$sHyperlink = '../pages/UI.php?operation=new&class='.$this->sClass;
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$this->sClass;
|
||||
$aExtraParams['c[menu]'] = $this->GetIndex();
|
||||
return $this->AddParams($sHyperlink, $aExtraParams);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,18 @@
|
||||
require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
require_once(APPROOT."/application/applicationcontext.class.inc.php");
|
||||
require_once(APPROOT."/application/user.preferences.class.inc.php");
|
||||
|
||||
define('BUTTON_CANCEL', 1);
|
||||
define('BUTTON_BACK', 2);
|
||||
define('BUTTON_NEXT', 4);
|
||||
define('BUTTON_FINISH', 8);
|
||||
|
||||
define('PARAM_ARROW_SEP', '_x_');
|
||||
|
||||
class TransactionException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Web page with some associated CSS and scripts (jquery) for a fancier display
|
||||
* of the Portal web page
|
||||
@@ -35,16 +47,21 @@ class PortalWebPage extends NiceWebPage
|
||||
/**
|
||||
* Portal menu
|
||||
*/
|
||||
protected $m_sWelcomeMsg;
|
||||
protected $m_aMenuButtons;
|
||||
|
||||
public function __construct($sTitle, $sAlternateStyleSheet = '')
|
||||
{
|
||||
$this->m_sWelcomeMsg = '';
|
||||
$this->m_aMenuButtons = array();
|
||||
parent::__construct($sTitle);
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$this->add_linked_stylesheet("../css/jquery.treeview.css");
|
||||
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
|
||||
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sAppContext = addslashes($oAppContext->GetForLink());
|
||||
if ($sAlternateStyleSheet != '')
|
||||
{
|
||||
$this->add_linked_stylesheet("../portal/$sAlternateStyleSheet/portal.css");
|
||||
@@ -62,10 +79,12 @@ class PortalWebPage extends NiceWebPage
|
||||
$this->add_linked_script("../js/jquery.popupmenu.js");
|
||||
$this->add_linked_script("../js/date.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.min.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../js/utils.js");
|
||||
$this->add_linked_script("../js/forms-json-utils.js");
|
||||
$this->add_linked_script("../js/swfobject.js");
|
||||
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
try
|
||||
@@ -106,8 +125,6 @@ try
|
||||
}
|
||||
});
|
||||
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
$(".listResults").tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$(".date-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
@@ -117,7 +134,7 @@ try
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
});
|
||||
$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
|
||||
//$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
|
||||
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry').toggle(); });
|
||||
}
|
||||
catch(err)
|
||||
@@ -140,19 +157,67 @@ EOF
|
||||
return bResult;
|
||||
}
|
||||
|
||||
function GoBack()
|
||||
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
var form = $('#request_form');
|
||||
var step = $('input[name=step]');
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
|
||||
function GoBack(sFormId)
|
||||
{
|
||||
var form = $('#'+sFormId);
|
||||
var step_back = $('input[name=step_back]');
|
||||
|
||||
form.unbind('submit'); // De-activate validation
|
||||
step.val(step.val() -2); // To go Back one step: next step is x, current step is x-1, previous step is x-2
|
||||
|
||||
step_back.val(1);
|
||||
form.submit(); // Go
|
||||
}
|
||||
|
||||
function GoHome()
|
||||
{
|
||||
var form = $('FORM');
|
||||
form.unbind('submit'); // De-activate validation
|
||||
window.location.href = '?operation=';
|
||||
return false;
|
||||
}
|
||||
|
||||
function SetWizardNextStep(sStep)
|
||||
{
|
||||
var next_step = $('input[id=next_step]');
|
||||
next_step.val(sStep);
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a welcome message (optional)
|
||||
*/
|
||||
public function SetWelcomeMessage($sMsg)
|
||||
{
|
||||
$this->m_sWelcomeMsg = $sMsg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a button to the portal's main menu
|
||||
@@ -161,17 +226,594 @@ EOF
|
||||
{
|
||||
$this->m_aMenuButtons[] = array('id' => $sId, 'label' => $sLabel, 'hyperlink' => $sHyperlink);
|
||||
}
|
||||
|
||||
var $m_bEnableDisconnectButton = true;
|
||||
public function EnableDisconnectButton($bEnable)
|
||||
{
|
||||
$this->m_bEnableDisconnectButton = $bEnable;
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$sMenu = '';
|
||||
$this->AddMenuButton('logoff', 'Portal:Disconnect', '../pages/logoff.php'); // This menu is always present and is the last one
|
||||
if ($this->m_bEnableDisconnectButton)
|
||||
{
|
||||
$this->AddMenuButton('logoff', 'Portal:Disconnect', utils::GetAbsoluteUrlAppRoot().'pages/logoff.php'); // This menu is always present and is the last one
|
||||
}
|
||||
foreach($this->m_aMenuButtons as $aMenuItem)
|
||||
{
|
||||
$sMenu .= "<a class=\"button\" id=\"{$aMenuItem['id']}\" href=\"{$aMenuItem['hyperlink']}\"><span>".Dict::S($aMenuItem['label'])."</span></a>";
|
||||
}
|
||||
$this->s_content = '<div id="portal"><div id="banner"><div id="logo"></div>'.$sMenu.'</div><div id="content">'.$this->s_content.'</div></div>';
|
||||
$this->s_content = '<div id="portal"><div id="welcome">'.$this->m_sWelcomeMsg.'</div><div id="banner"><div id="logo"></div><div id="menu">'.$sMenu.'</div></div><div id="content">'.$this->s_content.'</div></div>';
|
||||
parent::output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a list of objects, without any hyperlink (except for the object's details)
|
||||
* @param DBObjectSet $oSet The set of objects to display
|
||||
* @param Array $aZList The ZList (list of field codes) to use for the tabular display
|
||||
* @param String $sEmptyListMessage Message displayed whenever the list is empty
|
||||
* @return string The HTML text representing the list
|
||||
*/
|
||||
public function DisplaySet($oSet, $aZList, $sEmptyListMessage = '')
|
||||
{
|
||||
if ($oSet->Count() > 0)
|
||||
{
|
||||
$sClass = $oSet->GetClass();
|
||||
if (is_subclass_of($sClass, 'cmdbAbstractObject'))
|
||||
{
|
||||
// Home-made and very limited display of an object set
|
||||
|
||||
//
|
||||
//$oSet->Seek(0);// juste pour que le warning soit moins crado
|
||||
//$oSet->Fetch();// juste pour que le warning soit moins crado
|
||||
//
|
||||
|
||||
$this->add("<div id=\"listOf$sClass\">\n");
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => "listOf$sClass", 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
$this->add("</div>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Home-made and very limited display of an object set
|
||||
$aAttribs = array();
|
||||
$aValues = array();
|
||||
$aAttribs['key'] = array('label' => MetaModel::GetName($sClass), 'description' => '');
|
||||
foreach($aZList as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aAttribs[$sAttCode] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
|
||||
}
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
|
||||
$aRow['key'] = '<a href="./index.php?operation=details&class='.get_class($oObj).'&id='.$oObj->GetKey().'">'.$oObj->GetName().'</a>';
|
||||
$sHilightClass = $oObj->GetHilightClass();
|
||||
if ($sHilightClass != '')
|
||||
{
|
||||
$aRow['@class'] = $sHilightClass;
|
||||
}
|
||||
foreach($aZList as $sAttCode)
|
||||
{
|
||||
$aRow[$sAttCode] = $oObj->GetAsHTML($sAttCode);
|
||||
}
|
||||
$aValues[$oObj->GetKey()] = $aRow;
|
||||
}
|
||||
$this->table($aAttribs, $aValues);
|
||||
}
|
||||
}
|
||||
elseif (strlen($sEmptyListMessage) > 0)
|
||||
{
|
||||
$this->add($sEmptyListMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the attributes of an object (no title, no form)
|
||||
* @param Object $oObj Any kind of object
|
||||
* @param aAttList The list of attributes to display
|
||||
* @return void
|
||||
*/
|
||||
public function DisplayObjectDetails($oObj, $aAttList)
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
$aDetails = array();
|
||||
foreach($aAttList as $sAttCode)
|
||||
{
|
||||
$iFlags = $oObj->GetAttributeFlags($sAttCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
if ( (!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) )
|
||||
{
|
||||
// Don't display linked set and non-visible attributes (in this state)
|
||||
$sDisplayValue = $oObj->GetAsHTML($sAttCode);
|
||||
$aDetails[] = array('label' => '<span title="'.MetaModel::GetDescription($sClass, $sAttCode).'">'.MetaModel::GetLabel($sClass, $sAttCode).'</span>', 'value' => $sDisplayValue);
|
||||
}
|
||||
}
|
||||
$this->details($aDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* DisplayObjectLinkset
|
||||
* @param Object $oObj Any kind of object
|
||||
* @param $sLinkSetAttCode The attribute code of the link set attribute to display
|
||||
* @param $sRemoteAttCode The external key on the linked class, pointing to the remote objects
|
||||
* @param $aZList The list of attribute of the remote object
|
||||
* @param $sEmptyListMessage The message to display if the list is empty
|
||||
* @return void
|
||||
*/
|
||||
public function DisplayObjectLinkset($oObj, $sLinkSetAttCode, $sRemoteAttCode, $aZList, $sEmptyListMessage = '', $oSearchRestriction = null)
|
||||
{
|
||||
if (empty($sEmptyListMessage))
|
||||
{
|
||||
$sEmptyListMessage = Dict::S('UI:Search:NoObjectFound');
|
||||
}
|
||||
|
||||
$oLinkSet = $oObj->Get($sLinkSetAttCode);
|
||||
if ($oLinkSet->Count() > 0)
|
||||
{
|
||||
$sClass = $oLinkSet->GetClass();
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($sClass, $sRemoteAttCode);
|
||||
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
|
||||
|
||||
if (is_null($oSearchRestriction))
|
||||
{
|
||||
$oObjSearch = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObjSearch = $oSearchRestriction;
|
||||
}
|
||||
$oObjSearch->AddCondition_ReferencedBy($oLinkSet->GetFilter(), $sRemoteAttCode);
|
||||
|
||||
$aExtraParams = array('menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList));
|
||||
$oBlock = new DisplayBlock($oObjSearch, 'list', false);
|
||||
$oBlock->Display($this, 1, $aExtraParams);
|
||||
}
|
||||
elseif (strlen($sEmptyListMessage) > 0)
|
||||
{
|
||||
$this->add($sEmptyListMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, $sFieldName = null)
|
||||
{
|
||||
if (is_null($sFieldName))
|
||||
{
|
||||
$sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec);
|
||||
}
|
||||
|
||||
$iPos = strpos($sAttSpec, '->');
|
||||
if ($iPos !== false)
|
||||
{
|
||||
$sAttCode = substr($sAttSpec, 0, $iPos);
|
||||
$sSubSpec = substr($sAttSpec, $iPos + 2);
|
||||
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
throw new Exception("Invalid attribute code '$sClass/$sAttCode' in search specification '$sAttSpec'");
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetLinkedClass();
|
||||
}
|
||||
elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Attribute specification '$sAttSpec', '$sAttCode' should be either a link set or an external key");
|
||||
}
|
||||
$this->DisplaySearchField($sTargetClass, $sSubSpec, $aExtraParams, $sPrefix, $sFieldName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// $sAttSpec is an attribute code
|
||||
//
|
||||
$this->add('<span style="white-space: nowrap;padding:5px;display:inline-block;">');
|
||||
$sFilterValue = '';
|
||||
$sFilterValue = utils::ReadParam($sPrefix.$sFieldName, '', false, 'raw_data');
|
||||
$sFilterOpCode = null; // Use the default 'loose' OpCode
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttSpec);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass));
|
||||
|
||||
$iFieldSize = $oAttDef->GetMaxSize();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> ");
|
||||
//$oWidget = UIExtKeyWidget::DIsplayFromAttCode($sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, '', $sPrefix, '');
|
||||
//$this->add($oWidget->Display($this, $aExtraParams, true /* bSearchMode */));
|
||||
$aExtKeyParams = $aExtraParams;
|
||||
$aExtKeyParams['iFieldSize'] = $oAttDef->GetMaxSize();
|
||||
$aExtKeyParams['iMinChars'] = $oAttDef->GetMinAutoCompleteChars();
|
||||
// DisplayFromAttCode($this, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
|
||||
$sHtml = UIExtKeyWidget::DisplayFromAttCode($this, $sAttSpec, $sClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sPrefix.$sFieldName, false, $sPrefix.$sFieldName, $sPrefix, $aExtKeyParams, true);
|
||||
$this->add($sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedValues = MetaModel::GetAllowedValues_flt($sClass, $sAttSpec, $aExtraParams);
|
||||
if (is_null($aAllowedValues))
|
||||
{
|
||||
// Any value is possible, display an input box
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> <input class=\"textSearch\" name=\"$sPrefix$sFieldName\" value=\"$sFilterValue\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Enum field or external key, display a combo
|
||||
$sValue = "<select name=\"$sPrefix$sFieldName\">\n";
|
||||
$sValue .= "<option value=\"\">".Dict::S('UI:SearchValue:Any')."</option>\n";
|
||||
foreach($aAllowedValues as $key => $value)
|
||||
{
|
||||
if ($sFilterValue == $key)
|
||||
{
|
||||
$sSelected = ' selected';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = '';
|
||||
}
|
||||
$sValue .= "<option value=\"$key\"$sSelected>$value</option>\n";
|
||||
}
|
||||
$sValue .= "</select>\n";
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> $sValue\n");
|
||||
}
|
||||
}
|
||||
unset($aExtraParams[$sFieldName]);
|
||||
$this->add('</span> ');
|
||||
|
||||
$sTip = $oAttDef->GetHelpOnSmartSearch();
|
||||
if (strlen($sTip) > 0)
|
||||
{
|
||||
$sTip = addslashes($sTip);
|
||||
$sTip = str_replace(array("\n", "\r"), " ", $sTip);
|
||||
// :input does represent in form visible input (INPUT, SELECT, TEXTAREA)
|
||||
$this->add_ready_script("$(':input[name={$sPrefix}$sFieldName]').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function DisplaySearchForm($sClass, $aAttList, $aExtraParams, $sPrefix, $bClosed = true)
|
||||
{
|
||||
$sCSSClass = ($bClosed) ? 'DrawerClosed' : '';
|
||||
$this->add("<div id=\"ds_$sPrefix\" class=\"SearchDrawer $sCSSClass\">\n");
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_$sPrefix").click( function() {
|
||||
$("#ds_$sPrefix").slideToggle('normal', function() { $("#ds_$sPrefix").parent().resize(); } );
|
||||
$("#dh_$sPrefix").toggleClass('open');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
$this->add("<form id=\"search_$sClass\" action=\"\" method=\"post\">\n"); // Don't use $_SERVER['SCRIPT_NAME'] since the form may be called asynchronously (from ajax.php)
|
||||
// $this->add("<h2>".Dict::Format('UI:SearchFor_Class_Objects', 'xxxxxx')."</h2>\n");
|
||||
$this->add("<p>\n");
|
||||
foreach($aAttList as $sAttSpec)
|
||||
{
|
||||
//$oAppContext->Reset($sAttSpec); // Make sure the same parameter will not be passed twice
|
||||
$this->DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix);
|
||||
}
|
||||
$this->add("</p>\n");
|
||||
$this->add("<p align=\"right\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Search')."\"></p>\n");
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
$this->add("<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n");
|
||||
}
|
||||
// $this->add($oAppContext->GetForForm());
|
||||
$this->add("</form>\n");
|
||||
$this->add("</div>\n");
|
||||
$this->add("<div class=\"HRDrawer\"></div>\n");
|
||||
$this->add("<div id=\"dh_$sPrefix\" class=\"DrawerHandle\">".Dict::S('UI:SearchToggle')."</div>\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read parameters from the page
|
||||
* Parameters that were absent from the page's parameters are not set in the resulting hash array
|
||||
* @input string $sMethod Either get or post
|
||||
* @return Hash Array of name => value corresponding to the parameters that were passed to the page
|
||||
*/
|
||||
public function ReadAllParams($sParamList, $sPrefix = 'attr_')
|
||||
{
|
||||
$aParams = explode(',', $sParamList);
|
||||
$aValues = array();
|
||||
foreach($aParams as $sName)
|
||||
{
|
||||
$sName = trim($sName);
|
||||
$value = utils::ReadParam($sPrefix.$sName, null, false, 'raw_data');
|
||||
if (!is_null($value))
|
||||
{
|
||||
$aValues[$sName] = $value;
|
||||
}
|
||||
}
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a list of parameters as hidden fields
|
||||
* Example: attr_dummy[-123][id] = "blah"
|
||||
* @param Hash $aParameters Array name => value for the parameters
|
||||
* @param Array $aExclude The list of parameters that must not be handled this way (probably already in the visible part of the form)
|
||||
* @return void
|
||||
*/
|
||||
protected function DumpHiddenParamsInternal($sName, $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
foreach($value as $sKey => $item)
|
||||
{
|
||||
$this->DumpHiddenParamsInternal($sName.'['.$sKey.']', $item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->Add("<input type=\"hidden\" name=\"$sName\" value=\"$value\">");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a list of parameters as hidden field into the current page
|
||||
* (must be called when inside a form)
|
||||
* @param Hash $aParameters Array name => value for the parameters
|
||||
* @param Array $aExclude The list of parameters that must not be handled this way (probably already in the visible part of the form)
|
||||
* @return void
|
||||
*/
|
||||
public function DumpHiddenParams($aParameters, $aExclude = null, $sPrefix = 'attr_')
|
||||
{
|
||||
foreach($aParameters as $sAttCode => $value)
|
||||
{
|
||||
if (is_null($aExclude) || !in_array($sAttCode, $aExclude))
|
||||
{
|
||||
$this->DumpHiddenParamsInternal($sPrefix.$sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function PostedParamsToFilter($sClass, $aAttList, $sPrefix)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$iCountParams = 0;
|
||||
foreach($aAttList as $sAttSpec)
|
||||
{
|
||||
$sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec);
|
||||
$value = utils::ReadPostedParam($sPrefix.$sFieldName, null, 'raw_data');
|
||||
if (!is_null($value) && strlen($value) > 0)
|
||||
{
|
||||
$oFilter->AddConditionAdvanced($sAttSpec, $value);
|
||||
$iCountParams++;
|
||||
}
|
||||
}
|
||||
if ($iCountParams == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $oFilter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the object form POSTED arguments, and writes it into the DB (applies a stimuli if requested)
|
||||
* @param DBObject $oObj The object to update
|
||||
* $param array $aAttList If set, this will limit the list of updated attributes
|
||||
* @return void
|
||||
*/
|
||||
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
|
||||
{
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
|
||||
if (!utils::IsTransactionValid($sTransactionId))
|
||||
{
|
||||
throw new TransactionException();
|
||||
}
|
||||
|
||||
$sClass = get_class($oObj);
|
||||
|
||||
$sStimulus = trim(utils::ReadPostedParam('apply_stimulus', ''));
|
||||
$sTargetState = '';
|
||||
if (!empty($sStimulus))
|
||||
{
|
||||
// Compute the target state
|
||||
|
||||
$aTransitions = $oObj->EnumTransitions();
|
||||
if (!isset($aTransitions[$sStimulus]))
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
|
||||
}
|
||||
$sTargetState = $aTransitions[$sStimulus]['target_state'];
|
||||
}
|
||||
|
||||
$oObj->UpdateObjectFromPostedForm('' /* form prefix */, $aAttList, $sTargetState);
|
||||
|
||||
// Optional: apply a stimulus
|
||||
//
|
||||
if (!empty($sStimulus))
|
||||
{
|
||||
if (!$oObj->ApplyStimulus($sStimulus))
|
||||
{
|
||||
throw new Exception("Cannot apply stimulus '$sStimulus' to {$oObj->GetName()}");
|
||||
}
|
||||
}
|
||||
|
||||
// Record the change
|
||||
//
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
$oMyChange->Set("date", time());
|
||||
$sUserString = CMDBChange::GetCurrentUserName();
|
||||
$oMyChange->Set("userinfo", $sUserString);
|
||||
$iChangeId = $oMyChange->DBInsert();
|
||||
$oObj->DBUpdateTracked($oMyChange);
|
||||
|
||||
// Trigger ?
|
||||
//
|
||||
$aClasses = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL);
|
||||
$sClassList = implode(", ", CMDBSource::Quote($aClasses));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN ($sClassList)"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($oObj->ToArgs('this'));
|
||||
}
|
||||
|
||||
$this->p("<h1>".Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())."</h1>\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the object of the specified Class/ID.
|
||||
* @param WebPage $oP The current page
|
||||
* @return DBObject The found object, or throws an exception in case of failure
|
||||
*/
|
||||
public function FindObjectFromArgs($aAllowedClasses = null)
|
||||
{
|
||||
$sClass = utils::ReadParam('class', '', true, 'class');
|
||||
$iId = utils::ReadParam('id', 0, true, 'integer');
|
||||
|
||||
if (empty($sClass))
|
||||
{
|
||||
throw new Exception("Missing argument 'class'");
|
||||
}
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
throw new Exception("Wrong value for argument 'class': $sClass");
|
||||
}
|
||||
if ($iId == 0)
|
||||
{
|
||||
throw new Exception("Missing argument 'id'");
|
||||
}
|
||||
|
||||
if(!is_null($aAllowedClasses))
|
||||
{
|
||||
$bAllowed = false;
|
||||
foreach($aAllowedClasses as $sParentClass)
|
||||
{
|
||||
if (MetaModel::IsParentClass($sParentClass, $sClass))
|
||||
{
|
||||
$bAllowed = true;
|
||||
}
|
||||
}
|
||||
if (!$bAllowed)
|
||||
{
|
||||
throw new Exception("Class '$sClass not allowed in this implementation'");
|
||||
}
|
||||
}
|
||||
|
||||
$oObj = MetaModel::GetObject($sClass, $iId, false);
|
||||
if (!is_object($oObj))
|
||||
{
|
||||
throw new Exception("Could not find the object $sClass/$iId");
|
||||
}
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
var $m_sWizardId = null;
|
||||
|
||||
public function WizardFormStart($sId = '', $sNextStep = null, $bAttachment = false, $sMethod = 'post')
|
||||
{
|
||||
$this->m_sWizardId = $sId;
|
||||
|
||||
// multipart... needed for file upload
|
||||
$this->add("<form id=\"{$this->m_sWizardId}\" method=\"$sMethod\" enctype=\"multipart/form-data\">\n");
|
||||
|
||||
$aPreviousSteps = $this->GetWizardStepHistory();
|
||||
if (utils::ReadParam('step_back', 0) == 1)
|
||||
{
|
||||
// Back into the past history
|
||||
array_pop($aPreviousSteps);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Moving forward
|
||||
array_push($aPreviousSteps, utils::ReadParam('next_step'));
|
||||
}
|
||||
|
||||
$sStepHistory = implode(',', $aPreviousSteps);
|
||||
$this->add("<input type=\"hidden\" id=\"step_history\" name=\"step_history\" value=\"$sStepHistory\">");
|
||||
|
||||
if (!is_null($sNextStep))
|
||||
{
|
||||
$this->add("<input type=\"hidden\" id=\"next_step\" name=\"next_step\" value=\"$sNextStep\">");
|
||||
}
|
||||
$this->add("<input type=\"hidden\" id=\"step_back\" name=\"step_back\" value=\"0\">");
|
||||
|
||||
$sTransactionId = utils::GetNewTransactionId();
|
||||
$this->SetTransactionId($sTransactionId);
|
||||
$this->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"$sTransactionId\">\n");
|
||||
$this->add_ready_script("$(window).unload(function() { OnUnload('$sTransactionId') } );\n");
|
||||
}
|
||||
|
||||
public function WizardFormButtons($iButtonFlags)
|
||||
{
|
||||
$aButtons = array();
|
||||
if ($iButtonFlags & BUTTON_CANCEL)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_cancel\" type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"GoHome();\">";
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_BACK)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_back\" type=\"submit\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoBack('{$this->m_sWizardId}');\">";
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_NEXT)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_next\" type=\"submit\" value=\"".Dict::S('UI:Button:Next')."\">";
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_FINISH)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_finish\" type=\"submit\" value=\"".Dict::S('UI:Button:Finish')."\">";
|
||||
}
|
||||
|
||||
$this->add('<div id="buttons">');
|
||||
$this->add(implode('', $aButtons));
|
||||
$this->add('</div>');
|
||||
}
|
||||
|
||||
public function WizardFormEnd()
|
||||
{
|
||||
$this->add("</form>\n");
|
||||
}
|
||||
|
||||
public function GetWizardStep()
|
||||
{
|
||||
if (utils::ReadParam('step_back', 0) == 1)
|
||||
{
|
||||
// Take the value into the history - one level above
|
||||
$aPreviousSteps = $this->GetWizardStepHistory();
|
||||
array_pop($aPreviousSteps);
|
||||
return end($aPreviousSteps);
|
||||
}
|
||||
else
|
||||
{
|
||||
return utils::ReadParam('next_step');
|
||||
}
|
||||
}
|
||||
|
||||
protected function GetWizardStepHistory()
|
||||
{
|
||||
$sRawHistory = trim(utils::ReadParam('step_history', '', false, 'raw_data'));
|
||||
if (strlen($sRawHistory) == 0)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
else
|
||||
{
|
||||
return explode(',', $sRawHistory);
|
||||
}
|
||||
}
|
||||
|
||||
public function WizardCheckSelectionOnSubmit($sMessageIfNoSelection)
|
||||
{
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
$('#{$this->m_sWizardId}').submit(function() {
|
||||
return CheckSelection('$sMessageIfNoSelection');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
430
application/sqlblock.class.inc.php
Normal file
@@ -0,0 +1,430 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* SqlBlock - display tables or charts, given an SQL query - use cautiously!
|
||||
*
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
|
||||
|
||||
/**
|
||||
* Helper class to design optimized dashboards, based on an SQL query
|
||||
*
|
||||
*/
|
||||
class SqlBlock
|
||||
{
|
||||
protected $m_sQuery;
|
||||
protected $m_aColumns;
|
||||
protected $m_sTitle;
|
||||
protected $m_sType;
|
||||
|
||||
public function __construct($sQuery, $aColumns, $sTitle, $sType)
|
||||
{
|
||||
$this->m_sQuery = $sQuery;
|
||||
$this->m_aColumns = $aColumns;
|
||||
$this->m_sTitle = $sTitle;
|
||||
$this->m_sType = $sType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a SqlBlock object from an XML template
|
||||
/*
|
||||
*
|
||||
* <sqlblock>
|
||||
* <sql>SELECT date_format(start_date, '%d') AS Date, count(*) AS Count FROM ticket WHERE DATE_SUB(NOW(), INTERVAL 15 DAY) < start_date AND finalclass = 'UserIssue' GROUP BY date_format(start_date, '%d')</sql>
|
||||
* <type>table</type>
|
||||
* <title>UserRequest:Overview-Title</title>
|
||||
* <column>
|
||||
* <name>Date</name>
|
||||
* <label>UserRequest:Overview-Date</label>
|
||||
* <drilldown></drilldown>
|
||||
* </column>
|
||||
* <column>
|
||||
* <name>Count</name>
|
||||
* <label>UserRequest:Overview-Count</label>
|
||||
* <drilldown>SELECT UserIssue WHERE date_format(start_date, '%d') = :Date</drilldown>
|
||||
* </column>
|
||||
* </sqlblock>
|
||||
*
|
||||
* Tags
|
||||
* - sql: a (My)SQL query. Do not forget to use html entities (e.g. < for <)
|
||||
* - type: table (default), bars or pie. If bars or pie is selected only the two first columns are taken into account.
|
||||
* - title: optional title, typed in clear or given as a dictionnary entry
|
||||
* - column: specification of a column (not displayed if omitted)
|
||||
* - column / name: name of the column in the SQL query (use aliases)
|
||||
* - column / label: label, typed in clear or given as a dictionnary entry
|
||||
* - column / drilldown: NOT IMPLEMENTED YET - OQL with parameters corresponding to column names (in the query)
|
||||
*
|
||||
* @param $sTemplate string The XML template
|
||||
* @return DisplayBlock The DisplayBlock object, or null if the template is invalid
|
||||
*/
|
||||
public static function FromTemplate($sTemplate)
|
||||
{
|
||||
$oXml = simplexml_load_string('<root>'.$sTemplate.'</root>', 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
if (false)
|
||||
{
|
||||
// Debug
|
||||
echo "<pre>\n";
|
||||
print_r($oXml);
|
||||
echo "</pre>\n";
|
||||
}
|
||||
|
||||
if (isset($oXml->title))
|
||||
{
|
||||
$sTitle = (string)$oXml->title;
|
||||
}
|
||||
if (isset($oXml->type))
|
||||
{
|
||||
$sType = (string)$oXml->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sType = 'table';
|
||||
}
|
||||
if (!isset($oXml->sql))
|
||||
{
|
||||
throw new Exception('Missing tag "sql" in sqlblock');
|
||||
}
|
||||
$sQuery = (string)$oXml->sql;
|
||||
|
||||
$aColumns = array();
|
||||
if (isset($oXml->column))
|
||||
{
|
||||
foreach ($oXml->column AS $oColumnData)
|
||||
{
|
||||
if (!isset($oColumnData->name))
|
||||
{
|
||||
throw new Exception("Missing tag 'name' in sqlblock/column");
|
||||
}
|
||||
$sName = (string) $oColumnData->name;
|
||||
if (strlen($sName) == 0)
|
||||
{
|
||||
throw new Exception("Empty tag 'name' in sqlblock/column");
|
||||
}
|
||||
|
||||
$aColumns[$sName] = array();
|
||||
if (isset($oColumnData->label))
|
||||
{
|
||||
$sLabel = (string)$oColumnData->label;
|
||||
if (strlen($sLabel) > 0)
|
||||
{
|
||||
$aColumns[$sName]['label'] = Dict::S($sLabel);
|
||||
}
|
||||
}
|
||||
if (isset($oColumnData->drilldown))
|
||||
{
|
||||
$sDrillDown = (string)$oColumnData->drilldown;
|
||||
if (strlen($sDrillDown) > 0)
|
||||
{
|
||||
$aColumns[$sName]['drilldown'] = $sDrillDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new SqlBlock($sQuery, $aColumns, $sTitle, $sType);
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
if (empty($aExtraParams['currentId']))
|
||||
{
|
||||
$sId = 'sqlblock_'.$oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
|
||||
}
|
||||
else
|
||||
{
|
||||
$sId = $aExtraParams['currentId'];
|
||||
}
|
||||
// $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
|
||||
|
||||
$res = CMDBSource::Query($this->m_sQuery);
|
||||
$aQueryCols = CMDBSource::GetColumns($res);
|
||||
|
||||
// Prepare column definitions (check + give default values)
|
||||
//
|
||||
foreach($this->m_aColumns as $sName => $aColumnData)
|
||||
{
|
||||
if (!in_array($sName, $aQueryCols))
|
||||
{
|
||||
throw new Exception("Unknown column name '$sName' in sqlblock column");
|
||||
}
|
||||
if (!isset($aColumnData['label']))
|
||||
{
|
||||
$this->m_aColumns[$sName]['label'] = $sName;
|
||||
}
|
||||
if (isset($aColumnData['drilldown']) && !empty($aColumnData['drilldown']))
|
||||
{
|
||||
// Check if the OQL is valid
|
||||
try
|
||||
{
|
||||
$this->m_aColumns[$sName]['filter'] = DBObjectSearch::FromOQL($aColumnData['drilldown']);
|
||||
}
|
||||
catch(OQLException $e)
|
||||
{
|
||||
unset($aColumnData['drilldown']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($this->m_sTitle) > 0)
|
||||
{
|
||||
$oPage->add("<h2>".Dict::S($this->m_sTitle)."</h2>\n");
|
||||
}
|
||||
|
||||
switch ($this->m_sType)
|
||||
{
|
||||
case 'bars':
|
||||
case 'pie':
|
||||
$aColNames = array_keys($this->m_aColumns);
|
||||
$sXColName = $aColNames[0];
|
||||
$sYColName = $aColNames[1];
|
||||
$aData = array();
|
||||
$aRows = array();
|
||||
while($aRow = CMDBSource::FetchArray($res))
|
||||
{
|
||||
$aData[$aRow[$sXColName]] = $aRow[$sYColName];
|
||||
$aRows[$aRow[$sXColName]] = $aRow;
|
||||
}
|
||||
$this->RenderChart($oPage, $sId, $aData, $this->m_aColumns[$sYColName]['drilldown'], $aRows);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'table':
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
if (!empty($sContext))
|
||||
{
|
||||
$sContext = '&'.$sContext;
|
||||
}
|
||||
$aDisplayConfig = array();
|
||||
foreach($this->m_aColumns as $sName => $aColumnData)
|
||||
{
|
||||
$aDisplayConfig[$sName] = array('label' => $aColumnData['label'], 'description' => '');
|
||||
}
|
||||
|
||||
$aDisplayData = array();
|
||||
while($aRow = CMDBSource::FetchArray($res))
|
||||
{
|
||||
$aSQLColNames = array_keys($aRow);
|
||||
$aDisplayRow = array();
|
||||
foreach($this->m_aColumns as $sName => $aColumnData)
|
||||
{
|
||||
if (isset($aColumnData['filter']))
|
||||
{
|
||||
$sFilter = $aColumnData['drilldown'];
|
||||
$sClass = $aColumnData['filter']->GetClass();
|
||||
$sFilter = str_replace('SELECT '.$sClass, '', $sFilter);
|
||||
foreach($aSQLColNames as $sColName)
|
||||
{
|
||||
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRow[$sColName] )."'", $sFilter);
|
||||
}
|
||||
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&oql_clause='.urlencode($sFilter).'&format=html'.$sContext;
|
||||
$aDisplayRow[$sName] = '<a href="'.$sURL.'">'.$aRow[$sName]."</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aDisplayRow[$sName] = $aRow[$sName];
|
||||
}
|
||||
}
|
||||
$aDisplayData[] = $aDisplayRow;
|
||||
}
|
||||
$oPage->table($aDisplayConfig, $aDisplayData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
protected function RenderChart($oPage, $sId, $aValues, $sDrillDown = '', $aRows = array())
|
||||
{
|
||||
// 1- Compute Open Flash Chart data
|
||||
//
|
||||
$aValueKeys = array();
|
||||
$index = 0;
|
||||
if ((count($aValues) > 0) && ($sDrillDown != ''))
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sDrillDown);
|
||||
$sClass = $oFilter->GetClass();
|
||||
$sOQLClause = str_replace('SELECT '.$sClass, '', $sDrillDown);
|
||||
$aSQLColNames = array_keys(current($aRows)); // Read the list of columns from the current (i.e. first) element of the array
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&format=html&'.$oAppContext->GetForLink().'&oql_clause=';
|
||||
}
|
||||
$aURLs = array();
|
||||
foreach($aValues as $key => $value)
|
||||
{
|
||||
// Make sure that values are integers (so that max() will work....)
|
||||
// and build an array of STRING with the keys (numeric keys are transformed into string by PHP :-(
|
||||
$aValues[$key] = (int)$value;
|
||||
$aValueKeys[] = (string)$key;
|
||||
|
||||
// Build the custom query for the 'drill down' on each element
|
||||
if ($sDrillDown != '')
|
||||
{
|
||||
$sFilter = $sOQLClause;
|
||||
foreach($aSQLColNames as $sColName)
|
||||
{
|
||||
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRows[$key][$sColName] )."'", $sFilter);
|
||||
$aURLs[$index] = $sURL.urlencode($sFilter);
|
||||
}
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
||||
$oChart = new open_flash_chart();
|
||||
|
||||
if ($this->m_sType == 'bars')
|
||||
{
|
||||
$oChartElement = new bar_glass();
|
||||
|
||||
if (count($aValues) > 0)
|
||||
{
|
||||
$maxValue = max($aValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
$maxValue = 1;
|
||||
}
|
||||
$oYAxis = new y_axis();
|
||||
$aMagicValues = array(1,2,5,10);
|
||||
$iMultiplier = 1;
|
||||
$index = 0;
|
||||
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
|
||||
while($maxValue > $iTop)
|
||||
{
|
||||
$index++;
|
||||
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
|
||||
if (($index % count($aMagicValues)) == 0)
|
||||
{
|
||||
$iMultiplier = $iMultiplier * 10;
|
||||
}
|
||||
}
|
||||
//echo "oYAxis->set_range(0, $iTop, $iMultiplier);\n";
|
||||
$oYAxis->set_range(0, $iTop, $iMultiplier);
|
||||
$oChart->set_y_axis( $oYAxis );
|
||||
$aBarValues = array();
|
||||
foreach($aValues as $iValue)
|
||||
{
|
||||
$oBarValue = new bar_value($iValue);
|
||||
$oBarValue->on_click("ofc_drilldown_{$sId}");
|
||||
$aBarValues[] = $oBarValue;
|
||||
}
|
||||
$oChartElement->set_values($aBarValues);
|
||||
//$oChartElement->set_values(array_values($aValues));
|
||||
$oXAxis = new x_axis();
|
||||
$oXLabels = new x_axis_labels();
|
||||
// set them vertical
|
||||
$oXLabels->set_vertical();
|
||||
// set the label text
|
||||
$oXLabels->set_labels($aValueKeys);
|
||||
// Add the X Axis Labels to the X Axis
|
||||
$oXAxis->set_labels( $oXLabels );
|
||||
$oChart->set_x_axis( $oXAxis );
|
||||
}
|
||||
else
|
||||
{
|
||||
$oChartElement = new pie();
|
||||
$oChartElement->set_start_angle( 35 );
|
||||
$oChartElement->set_animate( true );
|
||||
$oChartElement->set_tooltip( '#label# - #val# (#percent#)' );
|
||||
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
|
||||
|
||||
$aData = array();
|
||||
foreach($aValues as $sValue => $iValue)
|
||||
{
|
||||
$oPieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
|
||||
$oPieValue->on_click("ofc_drilldown_{$sId}");
|
||||
$aData[] = $oPieValue;
|
||||
}
|
||||
|
||||
$oChartElement->set_values( $aData );
|
||||
$oChart->x_axis = null;
|
||||
}
|
||||
|
||||
// Title given in HTML
|
||||
//$oTitle = new title($this->m_sTitle);
|
||||
//$oChart->set_title($oTitle);
|
||||
$oChart->set_bg_colour('#FFFFFF');
|
||||
$oChart->add_element( $oChartElement );
|
||||
|
||||
$sData = $oChart->toPrettyString();
|
||||
$sData = json_encode($sData);
|
||||
|
||||
// 2- Declare the Javascript function that will render the chart data\
|
||||
//
|
||||
$oPage->add_script(
|
||||
<<< EOF
|
||||
function ofc_get_data_{$sId}()
|
||||
{
|
||||
return $sData;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
if (count($aURLs) > 0)
|
||||
{
|
||||
$sURLList = '';
|
||||
foreach($aURLs as $index => $sURL)
|
||||
{
|
||||
$sURLList .= "\taURLs[$index] = '".addslashes($sURL)."';\n";
|
||||
}
|
||||
|
||||
$oPage->add_script(
|
||||
<<< EOF
|
||||
function ofc_drilldown_{$sId}(index)
|
||||
{
|
||||
var aURLs = new Array();
|
||||
{$sURLList}
|
||||
var sURL = aURLs[index];
|
||||
|
||||
window.location.href = sURL; // Navigate !
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
// 3- Insert the Open Flash chart
|
||||
//
|
||||
$oPage->add("<div id=\"$sId\"><div>\n");
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
swfobject.embedSWF( "../images/open-flash-chart.swf",
|
||||
"{$sId}",
|
||||
"100%", "300","9.0.0",
|
||||
"expressInstall.swf",
|
||||
{"get-data":"ofc_get_data_{$sId}", "id":"{$sId}"},
|
||||
{'wmode': 'transparent'}
|
||||
);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -35,7 +35,7 @@ class DisplayTemplate
|
||||
|
||||
public function __construct($sTemplate)
|
||||
{
|
||||
$this->m_aTags = array('itopblock', 'itopcheck', 'itoptabs', 'itoptab', 'itoptoggle', 'itopstring');
|
||||
$this->m_aTags = array('itopblock', 'itopcheck', 'itoptabs', 'itoptab', 'itoptoggle', 'itopstring', 'sqlblock');
|
||||
$this->m_sTemplate = $sTemplate;
|
||||
}
|
||||
|
||||
@@ -203,6 +203,12 @@ class DisplayTemplate
|
||||
$oPage->add(Dict::S($sContent));
|
||||
break;
|
||||
|
||||
case 'sqlblock':
|
||||
$oBlock = SqlBlock::FromTemplate($sContent);
|
||||
$oBlock->RenderContent($oPage);
|
||||
break;
|
||||
|
||||
|
||||
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
|
||||
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
|
||||
break;
|
||||
@@ -227,7 +233,6 @@ class DisplayTemplate
|
||||
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = \'$class$\'</itopblock>
|
||||
</div>
|
||||
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT NetworkDevice AS d WHERE d.id = $id$</itopblock>
|
||||
<itoptabs>
|
||||
<itoptab name="Interfaces">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
|
||||
@@ -248,6 +253,140 @@ class DisplayTemplate
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special type of template for displaying the details of an object
|
||||
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
|
||||
* are available in such a template:
|
||||
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
|
||||
* $attribute_code->label()$ The label of an attribute
|
||||
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
|
||||
*/
|
||||
class ObjectDetailsTemplate extends DisplayTemplate
|
||||
{
|
||||
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
|
||||
{
|
||||
parent::__construct($sTemplate);
|
||||
$this->m_oObj = $oObj;
|
||||
$this->m_sPrefix = $sFormPrefix;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
|
||||
{
|
||||
$aTemplateFields = array();
|
||||
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
|
||||
$aTemplateFields = $aMatches[1];
|
||||
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
$aTemplateFields = array_merge($aTemplateFields, $aMatches[1]);
|
||||
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
|
||||
$aFieldsMap = array();
|
||||
|
||||
$sClass = get_class($this->m_oObj);
|
||||
// Renders the fields used in the template
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
|
||||
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
|
||||
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
|
||||
if (in_array($sAttCode, $aTemplateFields))
|
||||
{
|
||||
if ($this->m_oObj->IsNew())
|
||||
{
|
||||
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
|
||||
}
|
||||
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
|
||||
{
|
||||
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
|
||||
}
|
||||
|
||||
if ($iFlags & OPT_ATT_HIDDEN)
|
||||
{
|
||||
$aParams['this->label('.$sAttCode.')'] = '';
|
||||
$aParams['this->field('.$sAttCode.')'] = '';
|
||||
$aParams['this->comments('.$sAttCode.')'] = '';
|
||||
$aParams['this->'.$sAttCode] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
|
||||
{
|
||||
|
||||
// Check if the attribute is not read-only because of a synchro...
|
||||
$aReasons = array();
|
||||
$sSynchroIcon = '';
|
||||
if ($iFlags & OPT_ATT_SLAVE)
|
||||
{
|
||||
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sSynchroIcon = " <img id=\"synchro_$sInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
|
||||
}
|
||||
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
// Attribute is read-only
|
||||
$sHTMLValue = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetAsHTML($sAttCode);
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.htmlentities($this->m_oObj->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/></span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
|
||||
}
|
||||
|
||||
|
||||
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) //TODO: check the data synchro status...
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
|
||||
$this->m_oObj->Get($sAttCode),
|
||||
$this->m_oObj->GetEditValue($sAttCode),
|
||||
$iInputId, // InputID
|
||||
'',
|
||||
$iFlags,
|
||||
array('this' => $this->m_oObj) // aArgs
|
||||
).'</span>';
|
||||
$aFieldsMap[$sAttCode] = $iInputId;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams['this->field('.$sAttCode.')'] = $this->m_oObj->GetAsHTML($sAttCode);
|
||||
}
|
||||
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the PlugIns used in the template
|
||||
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
|
||||
$aPlugInProperties = $aMatches[1];
|
||||
foreach($aPlugInProperties as $sPlugInClass)
|
||||
{
|
||||
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
|
||||
if ($oInstance != null) // Safety check...
|
||||
{
|
||||
$offset = $oPage->start_capture();
|
||||
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
|
||||
$sContent = $oPage->end_capture($offset);
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
|
||||
}
|
||||
}
|
||||
|
||||
$offset = $oPage->start_capture();
|
||||
parent::Render($oPage, $aParams);
|
||||
$sContent = $oPage->end_capture($offset);
|
||||
// Remove empty table rows in case some attributes are hidden...
|
||||
$sContent = preg_replace('/<tr[^>]*>\s*(<td[^>]*>\s*<\\/td>)+\s*<\\/tr>/im', '', $sContent);
|
||||
$oPage->add($sContent);
|
||||
return $aFieldsMap;
|
||||
}
|
||||
}
|
||||
|
||||
//DisplayTemplate::UnitTest();
|
||||
|
||||
?>
|
||||
|
||||
@@ -38,11 +38,11 @@ class privUITransaction
|
||||
// Strictly speaking, the two lines below should be grouped together
|
||||
// by a critical section
|
||||
// sem_acquire($rSemIdentified);
|
||||
$id = 1 + count($_SESSION['transactions']);
|
||||
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
|
||||
$_SESSION['transactions'][$id] = true;
|
||||
// sem_release($rSemIdentified);
|
||||
|
||||
return sprintf("%d", $id);
|
||||
return (string)$id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,27 +63,32 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UIExtKeyWidget
|
||||
{
|
||||
protected static $iWidgetIndex = 0;
|
||||
protected $sAttCode;
|
||||
protected $sNameSuffix;
|
||||
protected $iId;
|
||||
protected $sTitle;
|
||||
protected $sTargetClass;
|
||||
|
||||
public function __construct($sAttCode, $sClass, $sTitle, $aAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
|
||||
{
|
||||
self::$iWidgetIndex++;
|
||||
$this->sAttCode = $sAttCode;
|
||||
$this->sClass = $sClass;
|
||||
$this->oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$this->sNameSuffix = $sNameSuffix;
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
$bAllowTargetCreation = $oAttDef->AllowTargetCreation();
|
||||
if (!$bSearchMode)
|
||||
{
|
||||
$sDisplayStyle = $oAttDef->GetDisplayStyle();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisplayStyle = 'select'; // In search mode, always use a drop-down list
|
||||
}
|
||||
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId);
|
||||
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, $bSearchMode, $sDisplayStyle);
|
||||
}
|
||||
|
||||
public function __construct($sTargetClass, $iInputId)
|
||||
{
|
||||
$this->sTargetClass = $sTargetClass;
|
||||
$this->iId = $iInputId;
|
||||
$this->aAllowedValues = $aAllowedValues;
|
||||
$this->value = $value;
|
||||
$this->sFieldPrefix = $sFieldPrefix;
|
||||
$this->sTargetClass = $this->oAttDef->GetTargetClass();
|
||||
$this->sTitle = $sTitle;
|
||||
$this->sFormPrefix = $sFormPrefix;
|
||||
$this->bMandatory = $bMandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,115 +97,172 @@ class UIExtKeyWidget
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, $aArgs = array(), $bSearchMode = false)
|
||||
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = false, $sDisplayStyle = 'select')
|
||||
{
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $this->oAttDef->AllowTargetCreation());
|
||||
$bCreate = (!$bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sAttrFieldPrefix = ($bSearchMode) ? '' : 'attr_';
|
||||
|
||||
$sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
|
||||
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
|
||||
if($bSearchMode)
|
||||
{
|
||||
$sWizHelper = 'null';
|
||||
$sWizHelperJSON = "''";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sWizHelper = 'oWizardHelper'.$this->sFormPrefix;
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$sWizHelperJSON = $sWizHelper.'.ToJSON()';
|
||||
}
|
||||
if (count($this->aAllowedValues) < $this->oAttDef->GetMaximumComboLength())
|
||||
if (is_null($oAllowedValues))
|
||||
{
|
||||
// Few choices, use a normal 'select'
|
||||
$sSelectMode = 'true';
|
||||
|
||||
$sHelpText = $this->oAttDef->GetHelpOnEdition();
|
||||
|
||||
// In case there are no valid values, the select will be empty, thus blocking the user from validating the form
|
||||
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" id=\"$this->iId\">\n";
|
||||
if ($bSearchMode)
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
elseif ($oAllowedValues->Count() < $iMaxComboLength)
|
||||
{
|
||||
// Discrete list of values, use a SELECT or RADIO buttons depending on the config
|
||||
switch($sDisplayStyle)
|
||||
{
|
||||
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SearchValue:Any')."</option>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
|
||||
}
|
||||
foreach($this->aAllowedValues as $key => $display_value)
|
||||
{
|
||||
if ((count($this->aAllowedValues) == 1) && ($this->bMandatory == 'true') )
|
||||
case 'radio':
|
||||
case 'radio_horizontal':
|
||||
case 'radio_vertical':
|
||||
$sValidationField = "<span id=\"v_{$this->iId}\"></span>";
|
||||
$sHTMLValue = '';
|
||||
$bVertical = ($sDisplayStyle != 'radio_horizontal');
|
||||
$bExtensions = false;
|
||||
$oAllowedValues->Rewind();
|
||||
$aAllowedValues = array();
|
||||
while($oObj = $oAllowedValues->Fetch())
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = ' selected';
|
||||
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
|
||||
}
|
||||
$sHTMLValue = $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", $bMandatory, $bVertical, $sValidationField);
|
||||
$aEventsList[] ='change';
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
default:
|
||||
$sSelectMode = 'true';
|
||||
|
||||
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
|
||||
|
||||
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
|
||||
if ($bSearchMode)
|
||||
{
|
||||
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
|
||||
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($this->value == $key) ? ' selected' : '';
|
||||
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "</select>\n";
|
||||
$oPage->add_ready_script(
|
||||
$oAllowedValues->Rewind();
|
||||
while($oObj = $oAllowedValues->Fetch())
|
||||
{
|
||||
$key = $oObj->GetKey();
|
||||
$display_value = $oObj->GetName();
|
||||
|
||||
if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = ' selected';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($value == $key) ? ' selected' : '';
|
||||
}
|
||||
$sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
|
||||
}
|
||||
$sHTMLValue .= "</select>\n";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, $sWizHelper);
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
|
||||
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
|
||||
|
||||
EOF
|
||||
);
|
||||
);
|
||||
} // Switch
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too many choices, use an autocomplete
|
||||
$sSelectMode = 'false';
|
||||
|
||||
if ($this->oAttDef->IsNull($this->value)) // Null values are displayed as ''
|
||||
if (is_null($value) || ($value == 0)) // Null values are displayed as ''
|
||||
{
|
||||
$sDisplayValue = '';
|
||||
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisplayValue = $this->GetObjectName($this->value);
|
||||
$sDisplayValue = $this->GetObjectName($value);
|
||||
}
|
||||
$sFormPrefix = $this->sFormPrefix;
|
||||
$iMinChars = $this->oAttDef->GetMinAutoCompleteChars();
|
||||
$iFieldSize = $this->oAttDef->GetMaxSize();
|
||||
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
|
||||
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 30; //@@@ $this->oAttDef->GetMaxSize();
|
||||
|
||||
// the input for the auto-complete
|
||||
$sHTMLValue = "<input count=\"".count($this->aAllowedValues)."\" type=\"text\" id=\"label_$this->iId\" size=\"30\" maxlength=\"$iFieldSize\" value=\"$sDisplayValue\"/> ";
|
||||
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.Search();\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;\" src=\"../images/mini_search.gif\" /></a> ";
|
||||
$sHTMLValue = "<input count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" size=\"$iFieldSize\" value=\"$sDisplayValue\"/> ";
|
||||
$sHTMLValue .= "<img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif\" onClick=\"oACWidget_{$this->iId}.Search();\"/> ";
|
||||
|
||||
// another hidden input to store & pass the object's Id
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$this->sFieldPrefix}{$this->sAttCode}{$this->sNameSuffix}\" value=\"$this->value\" />\n";
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"$value\" />\n";
|
||||
|
||||
// Scripts to start the autocomplete and bind some events to it
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sClass}', '{$this->sAttCode}', '{$this->sNameSuffix}', $sSelectMode, $sWizHelper);
|
||||
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper);
|
||||
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
|
||||
$('#label_$this->iId').autocomplete('./ajax.render.php', { scroll:true, minChars:{$iMinChars}, formatItem:formatItem, autoFill:false, matchContains:true, keyHolder:'#{$this->iId}', extraParams:{operation:'autocomplete', sclass:'{$this->sClass}',attCode:'{$this->sAttCode}'}});
|
||||
$('#label_$this->iId').blur(function() { $(this).search(); } );
|
||||
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter', json: function() { return $sWizHelperJSON; } }});
|
||||
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
|
||||
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
|
||||
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
|
||||
if ($('#ac_dlg_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_dlg_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
//$oPage->add_at_the_end($this->GetSearchDialog($oPage)); // To prevent adding forms inside the main form
|
||||
$oPage->add_at_the_end('<div id="ac_dlg_'.$this->iId.'"></div>'); // The place where to download the search dialog is outside of the main form (to prevent nested forms)
|
||||
|
||||
}
|
||||
if ($bCreate)
|
||||
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
|
||||
{
|
||||
$sHTMLValue .= "<a class=\"no-arrow\" href=\"javascript:oACWidget_{$this->iId}.CreateObject();\"><img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;\" src=\"../images/mini_add.gif\" /></a> ";
|
||||
$oPage->add_at_the_end('<div id="ajax_'.$this->iId.'"></div>');
|
||||
$sHTMLValue .= "<img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/> ";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ac_tree_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ac_tree_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
if ($bCreate && $bExtensions)
|
||||
{
|
||||
$sHTMLValue .= "<img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif\" onClick=\"oACWidget_{$this->iId}.CreateObject();\"/> ";
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
if ($('#ajax_{$this->iId}').length == 0)
|
||||
{
|
||||
$('body').append('<div id="ajax_{$this->iId}"></div>');
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
if ($sDisplayStyle == 'select')
|
||||
{
|
||||
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
|
||||
}
|
||||
$sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
|
||||
$sHTMLValue .= "</span>"; // end of no wrap
|
||||
return $sHTMLValue;
|
||||
}
|
||||
|
||||
public function GetSearchDialog(WebPage $oPage)
|
||||
public function GetSearchDialog(WebPage $oPage, $sTitle)
|
||||
{
|
||||
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
|
||||
|
||||
@@ -214,10 +276,11 @@ EOF
|
||||
$sHTML .= "</div>\n";
|
||||
$sHTML .= "<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ac_dlg_{$this->iId}').dialog('close');\"> ";
|
||||
$sHTML .= "<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoOk();\">";
|
||||
$sHTML .= "<input type=\"hidden\" id=\"count_{$this->iId}\" value=\"0\">";
|
||||
$sHTML .= "</form>\n";
|
||||
$sHTML .= '</div></div>';
|
||||
|
||||
$sDialogTitle = addslashes($this->sTitle);
|
||||
$sDialogTitle = addslashes($sTitle);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
|
||||
@@ -234,22 +297,48 @@ EOF
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
|
||||
* @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
|
||||
*/
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sTargetClass = '')
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
|
||||
{
|
||||
if ($sTargetClass != '')
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
|
||||
$oFilter = new DBObjectSearch($sTargetClass);
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
else
|
||||
try
|
||||
{
|
||||
// No remote class specified use the one defined in the linkedset
|
||||
$oFilter = new DBObjectSearch($this->sTargetClass);
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
catch(MissingQueryArgument $e)
|
||||
{
|
||||
// When used in a search form the $this parameter may be missing, in this case return all possible values...
|
||||
// TODO check if we can improve this behavior...
|
||||
$sOQL = 'SELECT '.$sRemoteClass;
|
||||
$oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
|
||||
* @param DBObject $oObj The current object for the OQL context
|
||||
* @param string $sContains The text of the autocomplete to filter the results
|
||||
*/
|
||||
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains)
|
||||
{
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
|
||||
$aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
|
||||
foreach($aValues as $sKey => $sFriendlyName)
|
||||
{
|
||||
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
|
||||
}
|
||||
$oFilter->AddCondition('id', array_keys($this->aAllowedValues), 'IN');
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, $this->iId, array('menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'display_limit' => false)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,10 +355,20 @@ EOF
|
||||
*/
|
||||
public function GetObjectCreationForm(WebPage $oPage)
|
||||
{
|
||||
// Set all the default values in an object and clone this "default" object
|
||||
$oNewObj = MetaModel::NewObject($this->sTargetClass);
|
||||
|
||||
// 1st - set context values
|
||||
$oAppContext = new ApplicationContext();
|
||||
$oAppContext->InitObjectFromContext($oNewObj);
|
||||
|
||||
// 2nd - set values from the page argument 'default'
|
||||
$oNewObj->UpdateObjectFromArg('default');
|
||||
|
||||
$sDialogTitle = addslashes($this->sTitle);
|
||||
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
|
||||
$oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, null, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
|
||||
$oPage->add('</div></div></div>');
|
||||
// $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
@@ -277,13 +376,52 @@ EOF
|
||||
$oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the hierarchy of the 'target' class
|
||||
*/
|
||||
public function DisplayHierarchy(WebPage $oPage, $sFilter, $currValue, $oObj)
|
||||
{
|
||||
$sDialogTitle = addslashes(Dict::Format('UI:HierarchyOf_Class', MetaModel::GetName($this->sTargetClass)));
|
||||
$oPage->add('<div id="dlg_tree_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div style="overflow:auto;background:#fff;margin-bottom:5px;" id="tree_'.$this->iId.'">');
|
||||
$oPage->add('<table style="width:100%"><tr><td>');
|
||||
if (is_null($sFilter))
|
||||
{
|
||||
throw new Exception('Implementation: null value for allowed values definition');
|
||||
}
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
|
||||
}
|
||||
catch(MissingQueryArgument $e)
|
||||
{
|
||||
// When used in a search form the $this parameter may be missing, in this case return all possible values...
|
||||
// TODO check if we can improve this behavior...
|
||||
$sOQL = 'SELECT '.$this->m_sTargetClass;
|
||||
$oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
}
|
||||
|
||||
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
|
||||
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
|
||||
|
||||
$oPage->add('</td></tr></table>');
|
||||
$oPage->add('</div>');
|
||||
$oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\"> ");
|
||||
$oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
|
||||
|
||||
$oPage->add('</div></div>');
|
||||
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview();\n");
|
||||
$oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the form to create a new object of the 'target' class
|
||||
*/
|
||||
public function DoCreateObject($oPage)
|
||||
{
|
||||
$oObj = MetaModel::NewObject($this->sTargetClass);
|
||||
$aErrors = $oObj->UpdateObject($this->sFormPrefix.$this->iId);
|
||||
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
|
||||
if (count($aErrors) == 0)
|
||||
{
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
@@ -299,5 +437,68 @@ EOF
|
||||
return array('name' => implode(' ', $aErrors), 'id' => 0);
|
||||
}
|
||||
}
|
||||
|
||||
function DumpTree($oP, $oSet, $sParentAttCode, $currValue)
|
||||
{
|
||||
$aTree = array();
|
||||
$aNodes = array();
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$iParentId = $oObj->Get($sParentAttCode);
|
||||
if (!isset($aTree[$iParentId]))
|
||||
{
|
||||
$aTree[$iParentId] = array();
|
||||
}
|
||||
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
|
||||
$aNodes[$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
|
||||
$aParents = array_keys($aTree);
|
||||
$aRoots = array();
|
||||
foreach($aParents as $id)
|
||||
{
|
||||
if (!array_key_exists($id, $aNodes))
|
||||
{
|
||||
$aRoots[] = $id;
|
||||
}
|
||||
}
|
||||
foreach($aRoots as $iRootId)
|
||||
{
|
||||
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
|
||||
}
|
||||
}
|
||||
|
||||
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
|
||||
{
|
||||
$bSelect = true;
|
||||
$bMultiple = false;
|
||||
$sSelect = '';
|
||||
if (array_key_exists($iRootId, $aTree))
|
||||
{
|
||||
$aSortedRoots = $aTree[$iRootId];
|
||||
asort($aSortedRoots);
|
||||
$oP->add("<ul>\n");
|
||||
foreach($aSortedRoots as $id => $sName)
|
||||
{
|
||||
if ($bSelect)
|
||||
{
|
||||
$sChecked = ($aNodes[$id]->GetKey() == $currValue) ? 'checked' : '';
|
||||
if ($bMultiple)
|
||||
{
|
||||
$sSelect = '<input type="checkbox" value="'.$aNodes[$id]->GetKey().'" name="selectObject[]" '.$sChecked.'> ';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelect = '<input type="radio" value="'.$aNodes[$id]->GetKey().'" name="selectObject" '.$sChecked.'> ';
|
||||
}
|
||||
}
|
||||
$oP->add('<li>'.$sSelect.$aNodes[$id]->GetHyperlink());
|
||||
$this->DumpNodes($oP, $id, $aTree, $aNodes, $currValue);
|
||||
$oP->add("</li>\n");
|
||||
}
|
||||
$oP->add("</ul>\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -182,17 +182,17 @@ class UILinksWidget
|
||||
|
||||
// Content
|
||||
$sHtml .= "</tbody>\n";
|
||||
if (count($aData) == 0)
|
||||
$sEmptyRowStyle = '';
|
||||
if (count($aData) != 0)
|
||||
{
|
||||
$sHtml .= "<tr id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\"></td></td>";
|
||||
$sEmptyRowStyle = 'style="display:none;"';
|
||||
}
|
||||
else
|
||||
|
||||
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\"></td></td>";
|
||||
foreach($aData as $iRowId => $aRow)
|
||||
{
|
||||
foreach($aData as $iRowId => $aRow)
|
||||
{
|
||||
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
|
||||
}
|
||||
}
|
||||
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
|
||||
}
|
||||
$sHtml .= "</tbody>\n";
|
||||
|
||||
// Footer
|
||||
@@ -219,10 +219,18 @@ class UILinksWidget
|
||||
while($oCurrentLink = $oValue->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$key = $oCurrentLink->GetKey();
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote));
|
||||
if ($oCurrentLink->IsNew())
|
||||
{
|
||||
$key = -$oLinkedObj->GetKey();
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $key, $aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = $oCurrentLink->GetKey();
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs);
|
||||
}
|
||||
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs);
|
||||
}
|
||||
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
|
||||
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
@@ -235,7 +243,7 @@ EOF
|
||||
$sHtmlValue .= " <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"></span>\n";
|
||||
$sHtmlValue .= "<span style=\"clear:both;\"><p> </p></span>\n";
|
||||
$sHtmlValue .= "</div>\n";
|
||||
$oPage->add_at_the_end($this->GetObjectPickerDialog($oPage)); // To prevent adding forms inside the main form
|
||||
$oPage->add_at_the_end($this->GetObjectPickerDialog($oPage), "dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}"); // To prevent adding forms inside the main form
|
||||
return $sHtmlValue;
|
||||
}
|
||||
|
||||
@@ -270,7 +278,8 @@ EOF
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"0\"/>";
|
||||
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\"> <input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
@@ -332,12 +341,13 @@ EOF
|
||||
}
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true, 'display_limit' => false)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter)
|
||||
{
|
||||
$aTable = array();
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
|
||||
foreach($aLinkedObjectIds as $iObjectId)
|
||||
{
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId);
|
||||
|
||||
@@ -52,13 +52,13 @@ class UIPasswordWidget
|
||||
{
|
||||
$sCode = $this->sAttCode.$this->sNameSuffix;
|
||||
$iWidgetIndex = self::$iWidgetIndex;
|
||||
$sPasswordValue = utils::ReadPostedParam("attr_$sCode", '*****');
|
||||
$sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}_confirmed", '*****');
|
||||
$sPasswordValue = utils::ReadPostedParam("attr_{$sCode}[value]", '*****', 'raw_data');
|
||||
$sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}[confirm]", '*****', 'raw_data');
|
||||
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
|
||||
$sHtmlValue = '';
|
||||
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/> <span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
|
||||
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'_confirmed"/> '.Dict::S('UI:PasswordConfirm').' <input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
|
||||
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'_changed" value="'.$sChangedValue.'"/>';
|
||||
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/> <span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
|
||||
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/> '.Dict::S('UI:PasswordConfirm').' <input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
|
||||
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
|
||||
|
||||
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
|
||||
@@ -85,7 +85,7 @@ class UILinksWizard
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId);
|
||||
|
||||
$oP->set_title("iTop - ".MetaModel::GetName($this->m_sLinkedClass)." objects linked with ".MetaModel::GetName(get_class($oTargetObj)).": ".$oTargetObj->GetName());
|
||||
$oP->set_title("iTop - ".MetaModel::GetName($this->m_sLinkedClass)." objects linked with ".MetaModel::GetName(get_class($oTargetObj)).": ".$oTargetObj->GetRawName());
|
||||
$oP->add("<div class=\"wizContainer\">\n");
|
||||
$oP->add("<form method=\"post\">\n");
|
||||
$oP->add("<div class=\"page_header\">\n");
|
||||
@@ -97,8 +97,7 @@ class UILinksWizard
|
||||
$oP->add("<input type=\"hidden\" name=\"linking_attcode\" value=\"{$this->m_sLinkingAttCode}\">\n");
|
||||
$oP->add("<h1>".Dict::Format('UI:ManageObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."</h1>\n");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<script type=\"text/javascript\">\n");
|
||||
$oP->add(
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
function OnSelectChange()
|
||||
{
|
||||
@@ -132,7 +131,7 @@ class UILinksWizard
|
||||
function AddObjects()
|
||||
{
|
||||
// TO DO: compute the list of objects already linked with the current Object
|
||||
$.post( '../pages/ajax.render.php', { 'operation': 'addObjects',
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { 'operation': 'addObjects',
|
||||
'class': '{$this->m_sClass}',
|
||||
'linkageAttr': '{$this->m_sLinkageAttr}',
|
||||
'linkedClass': '{$this->m_sLinkedClass}',
|
||||
@@ -175,7 +174,7 @@ class UILinksWizard
|
||||
theMap['operation'] = 'searchObjectsToAdd';
|
||||
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#SearchResultsToAdd').html(data);
|
||||
@@ -223,7 +222,7 @@ class UILinksWizard
|
||||
theMap['operation'] = 'doAddObjects';
|
||||
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
//console.log('Data: ' + data);
|
||||
@@ -257,7 +256,6 @@ class UILinksWizard
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$oP->Add("</script>\n");
|
||||
$oP->add_ready_script("InitForm();");
|
||||
$oFilter = new DBObjectSearch($this->m_sClass);
|
||||
$oFilter->AddCondition($this->m_sLinkageAttr, $this->m_iObjectId, '=');
|
||||
@@ -395,7 +393,7 @@ EOF
|
||||
$oFilter = new DBObjectSearch($this->m_sLinkedClass);
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true, 'display_limit' => false)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())
|
||||
|
||||
@@ -53,7 +53,7 @@ class UIWizard
|
||||
{
|
||||
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
|
||||
{
|
||||
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"../pages/UI.php\">\n");
|
||||
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
|
||||
}
|
||||
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
|
||||
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
|
||||
@@ -112,8 +112,7 @@ class UIWizard
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" />
|
||||
<input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" />
|
||||
</div>\n");
|
||||
$this->m_oPage->add("
|
||||
<script type=\"text/javascript\">
|
||||
$this->m_oPage->add_script("
|
||||
function OnEnterStep{$iStepIndex}()
|
||||
{
|
||||
oWizardHelper.ResetQuery();
|
||||
@@ -123,7 +122,7 @@ $sJSHandlerCode
|
||||
|
||||
oWizardHelper.AjaxQueryServer();
|
||||
}
|
||||
</script>\n");
|
||||
");
|
||||
$this->m_oPage->add("</div>\n\n");
|
||||
}
|
||||
|
||||
@@ -139,16 +138,15 @@ $sJSHandlerCode
|
||||
$this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n");
|
||||
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
|
||||
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
|
||||
$this->m_oPage->add("<script type=\"text/javascript\">\n");
|
||||
$this->m_oPage->add("function OnEnterStep$iStepIndex() {\n");
|
||||
$sScript = "function OnEnterStep$iStepIndex() {\n";
|
||||
foreach($aFieldsMap as $iInputId => $sAttCode)
|
||||
{
|
||||
$this->m_oPage->add("\toWizardHelper.UpdateCurrentValue('$sAttCode');\n");
|
||||
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
|
||||
}
|
||||
$this->m_oPage->add("\toWizardHelper.Preview('object_preview');\n");
|
||||
$this->m_oPage->add("\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n");
|
||||
$this->m_oPage->add("}\n");
|
||||
$this->m_oPage->add("</script>\n");
|
||||
$sScript .= "\toWizardHelper.Preview('object_preview');\n";
|
||||
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
|
||||
$sScript .= "}\n";
|
||||
$this->m_oPage->add_script($sScript);
|
||||
$this->m_oPage->add("<div id=\"object_preview\">\n");
|
||||
$this->m_oPage->add("</div>\n");
|
||||
$this->m_oPage->add($oAppContext->GetForForm());
|
||||
|
||||
@@ -27,6 +27,7 @@ require_once(APPROOT.'/core/config.class.inc.php');
|
||||
require_once(APPROOT.'/application/transaction.class.inc.php');
|
||||
|
||||
define('ITOP_CONFIG_FILE', APPROOT.'/config-itop.php');
|
||||
define('SERVER_NAME_PLACEHOLDER', '$SERVER_NAME$');
|
||||
|
||||
class FileUploadException extends Exception
|
||||
{
|
||||
@@ -41,6 +42,7 @@ class utils
|
||||
{
|
||||
private static $m_sConfigFile = ITOP_CONFIG_FILE;
|
||||
private static $m_oConfig = null;
|
||||
private static $m_bCASClient = false;
|
||||
|
||||
// Parameters loaded from a file, parameters of the page/command line still have precedence
|
||||
private static $m_aParamsFromFile = null;
|
||||
@@ -86,7 +88,7 @@ class utils
|
||||
|
||||
public static function UseParamFile($sParamFileArgName = 'param_file', $bAllowCLI = true)
|
||||
{
|
||||
$sFileSpec = self::ReadParam($sParamFileArgName, '', $bAllowCLI);
|
||||
$sFileSpec = self::ReadParam($sParamFileArgName, '', $bAllowCLI, 'raw_data');
|
||||
foreach(explode(',', $sFileSpec) as $sFile)
|
||||
{
|
||||
$sFile = trim($sFile);
|
||||
@@ -112,7 +114,7 @@ class utils
|
||||
}
|
||||
|
||||
|
||||
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false)
|
||||
public static function ReadParam($sName, $defaultValue = "", $bAllowCLI = false, $sSanitizationFilter = 'parameter')
|
||||
{
|
||||
global $argv;
|
||||
$retValue = $defaultValue;
|
||||
@@ -139,29 +141,107 @@ class utils
|
||||
}
|
||||
}
|
||||
}
|
||||
return $retValue;
|
||||
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
|
||||
}
|
||||
|
||||
public static function ReadPostedParam($sName, $defaultValue = "")
|
||||
public static function ReadPostedParam($sName, $defaultValue = '', $sSanitizationFilter = 'parameter')
|
||||
{
|
||||
return isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
|
||||
$retValue = isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
|
||||
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
|
||||
}
|
||||
|
||||
public static function Sanitize($value, $defaultValue, $sSanitizationFilter)
|
||||
{
|
||||
$retValue = self::Sanitize_Internal($value, $sSanitizationFilter);
|
||||
if ($retValue === false)
|
||||
{
|
||||
$retValue = $defaultValue;
|
||||
}
|
||||
return $retValue;
|
||||
}
|
||||
|
||||
protected static function Sanitize_Internal($value, $sSanitizationFilter)
|
||||
{
|
||||
switch($sSanitizationFilter)
|
||||
{
|
||||
case 'integer':
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
|
||||
break;
|
||||
|
||||
case 'class':
|
||||
$retValue = $value;
|
||||
if (!MetaModel::IsValidClass($value))
|
||||
{
|
||||
$retValue = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
break;
|
||||
|
||||
case 'parameter':
|
||||
case 'field_name':
|
||||
if (is_array($value))
|
||||
{
|
||||
$retValue = array();
|
||||
foreach($value as $key => $val)
|
||||
{
|
||||
$retValue[$key] = self::Sanitize_Internal($val, $sSanitizationFilter); // recursively check arrays
|
||||
if ($retValue[$key] === false)
|
||||
{
|
||||
$retValue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch($sSanitizationFilter)
|
||||
{
|
||||
case 'parameter':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[ A-Za-z0-9_=-]*$/'))); // the '=' equal character is used in serialized filters
|
||||
break;
|
||||
|
||||
case 'field_name':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'raw_data':
|
||||
$retValue = $value;
|
||||
// Do nothing
|
||||
}
|
||||
return $retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an uploaded file and turns it into an ormDocument object - Triggers an exception in case of error
|
||||
* @param string $sName Name of the input used from uploading the file
|
||||
* @param string $sIndex If Name is an array of posted files, then the index must be used to point out the file
|
||||
* @return ormDocument The uploaded file (can be 'empty' if nothing was uploaded)
|
||||
*/
|
||||
public static function ReadPostedDocument($sName)
|
||||
public static function ReadPostedDocument($sName, $sIndex = null)
|
||||
{
|
||||
$oDocument = new ormDocument(); // an empty document
|
||||
if(isset($_FILES[$sName]))
|
||||
{
|
||||
switch($_FILES[$sName]['error'])
|
||||
$aFileInfo = $_FILES[$sName];
|
||||
|
||||
$sError = is_null($sIndex) ? $aFileInfo['error'] : $aFileInfo['error'][$sIndex];
|
||||
switch($sError)
|
||||
{
|
||||
case UPLOAD_ERR_OK:
|
||||
$doc_content = file_get_contents($_FILES[$sName]['tmp_name']);
|
||||
$sMimeType = $_FILES[$sName]['type'];
|
||||
$sTmpName = is_null($sIndex) ? $aFileInfo['tmp_name'] : $aFileInfo['tmp_name'][$sIndex];
|
||||
$sMimeType = is_null($sIndex) ? $aFileInfo['type'] : $aFileInfo['type'][$sIndex];
|
||||
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
|
||||
|
||||
$doc_content = file_get_contents($sTmpName);
|
||||
if (function_exists('finfo_file'))
|
||||
{
|
||||
// as of PHP 5.3 the fileinfo extension is bundled within PHP
|
||||
@@ -179,7 +259,7 @@ class utils
|
||||
}
|
||||
@finfo_close($rInfo);
|
||||
}
|
||||
$oDocument = new ormDocument($doc_content, $sMimeType, $_FILES[$sName]['name']);
|
||||
$oDocument = new ormDocument($doc_content, $sMimeType, $sName);
|
||||
break;
|
||||
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
@@ -204,11 +284,12 @@ class utils
|
||||
break;
|
||||
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $_FILES[$sName]['name']));
|
||||
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $_FILES[$sName]['error']));
|
||||
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError));
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -216,6 +297,43 @@ class utils
|
||||
return $oDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interprets the results posted by a normal or paginated list (in multiple selection mode)
|
||||
* @param $oFullSetFilter DBObjectSearch The criteria defining the whole sets of objects being selected
|
||||
* @return Array An arry of object IDs corresponding to the objects selected in the set
|
||||
*/
|
||||
public static function ReadMultipleSelection($oFullSetFilter)
|
||||
{
|
||||
$aSelectedObj = utils::ReadParam('selectObject', array());
|
||||
$sSelectionMode = utils::ReadParam('selectionMode', '');
|
||||
if ($sSelectionMode != '')
|
||||
{
|
||||
// Paginated selection
|
||||
$aExceptions = utils::ReadParam('storedSelection', array());
|
||||
if ($sSelectionMode == 'positive')
|
||||
{
|
||||
// Only the explicitely listed items are selected
|
||||
$aSelectedObj = $aExceptions;
|
||||
}
|
||||
else
|
||||
{
|
||||
// All items of the set are selected, except the one explicitely listed
|
||||
$aSelectedObj = array();
|
||||
$oFullSet = new DBObjectSet($oFullSetFilter);
|
||||
$sClassAlias = $oFullSetFilter->GetClassAlias();
|
||||
$oFullSet->OptimizeColumnLoad(array($sClassAlias => array('friendlyname'))); // We really need only the IDs but it does not work since id is not a real field
|
||||
while($oObj = $oFullSet->Fetch())
|
||||
{
|
||||
if (!in_array($oObj->GetKey(), $aExceptions))
|
||||
{
|
||||
$aSelectedObj[] = $oObj->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aSelectedObj;
|
||||
}
|
||||
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
return privUITransaction::GetNewTransactionId();
|
||||
@@ -264,39 +382,91 @@ class utils
|
||||
return $iReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an absolute URL to the current page
|
||||
* @param $bQueryString bool True to also get the query string, false otherwise
|
||||
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
|
||||
* @return string The absolute URL to the current page
|
||||
*/
|
||||
static public function GetAbsoluteUrl($bQueryString = true, $bForceHTTPS = false)
|
||||
/**
|
||||
* Helper function to convert a string to a date, given a format specification. It replaces strtotime which does not allow for specifying a date in a french format (for instance)
|
||||
* Example: StringToTime('01/05/11 12:03:45', '%d/%m/%y %H:%i:%s')
|
||||
* @param string $sDate
|
||||
* @param string $sFormat
|
||||
* @return timestamp or false if the input format is not correct
|
||||
*/
|
||||
public static function StringToTime($sDate, $sFormat)
|
||||
{
|
||||
// Build an absolute URL to this page on this server/port
|
||||
$sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
|
||||
if (MetaModel::GetConfig()->GetSecureConnectionRequired() || MetaModel::GetConfig()->GetHttpsHyperlinks())
|
||||
// Source: http://php.net/manual/fr/function.strftime.php
|
||||
// (alternative: http://www.php.net/manual/fr/datetime.formats.date.php)
|
||||
static $aDateTokens = null;
|
||||
static $aDateRegexps = null;
|
||||
if (is_null($aDateTokens))
|
||||
{
|
||||
// If a secure connection is required, or if the URL is requested to start with HTTPS
|
||||
// then any URL must start with https !
|
||||
$bForceHTTPS = true;
|
||||
$aSpec = array(
|
||||
'%d' =>'(?<day>[0-9]{2})',
|
||||
'%m' => '(?<month>[0-9]{2})',
|
||||
'%y' => '(?<year>[0-9]{2})',
|
||||
'%Y' => '(?<year>[0-9]{4})',
|
||||
'%H' => '(?<hour>[0-2][0-9])',
|
||||
'%i' => '(?<minute>[0-5][0-9])',
|
||||
'%s' => '(?<second>[0-5][0-9])',
|
||||
);
|
||||
$aDateTokens = array_keys($aSpec);
|
||||
$aDateRegexps = array_values($aSpec);
|
||||
}
|
||||
if ($bForceHTTPS)
|
||||
{
|
||||
$sProtocol = 'https';
|
||||
$sPort = '';
|
||||
|
||||
$sDateRegexp = str_replace($aDateTokens, $aDateRegexps, $sFormat);
|
||||
|
||||
if (preg_match('!^(?<head>)'.$sDateRegexp.'(?<tail>)$!', $sDate, $aMatches))
|
||||
{
|
||||
$sYear = isset($aMatches['year']) ? $aMatches['year'] : 0;
|
||||
$sMonth = isset($aMatches['month']) ? $aMatches['month'] : 1;
|
||||
$sDay = isset($aMatches['day']) ? $aMatches['day'] : 1;
|
||||
$sHour = isset($aMatches['hour']) ? $aMatches['hour'] : 0;
|
||||
$sMinute = isset($aMatches['minute']) ? $aMatches['minute'] : 0;
|
||||
$sSecond = isset($aMatches['second']) ? $aMatches['second'] : 0;
|
||||
return strtotime("$sYear-$sMonth-$sDay $sHour:$sMinute:$sSecond");
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// http://www.spaweditor.com/scripts/regex/index.php
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the server's root path
|
||||
* @param $sCurrentRelativePath string NO MORE USED, kept for backward compatibility only !
|
||||
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
|
||||
* @return string The absolute URL to the server's root, without the first slash
|
||||
*/
|
||||
static public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
$sUrl = MetaModel::GetConfig()->Get('app_root_url');
|
||||
if (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
|
||||
{
|
||||
$sProtocol = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!="off")) ? 'https' : 'http';
|
||||
$iPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
|
||||
if ($sProtocol == 'http')
|
||||
if (isset($_SERVER['SERVER_NAME']))
|
||||
{
|
||||
$sPort = ($iPort == 80) ? '' : ':'.$iPort;
|
||||
$sServerName = $_SERVER['SERVER_NAME'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPort = ($iPort == 443) ? '' : ':'.$iPort;
|
||||
// CLI mode ?
|
||||
$sServerName = php_uname('n');
|
||||
}
|
||||
$sUrl = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, $sUrl);
|
||||
}
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
static public function GetDefaultUrlAppRoot()
|
||||
{
|
||||
// Build an absolute URL to this page on this server/port
|
||||
$sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
|
||||
$sProtocol = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!="off")) ? 'https' : 'http';
|
||||
$iPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80;
|
||||
if ($sProtocol == 'http')
|
||||
{
|
||||
$sPort = ($iPort == 80) ? '' : ':'.$iPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPort = ($iPort == 443) ? '' : ':'.$iPort;
|
||||
}
|
||||
// $_SERVER['REQUEST_URI'] is empty when running on IIS
|
||||
// Let's use Ivan Tcholakov's fix (found on www.dokeos.com)
|
||||
@@ -313,51 +483,42 @@ class utils
|
||||
}
|
||||
$_SERVER['REQUEST_URI'] = $sPath;
|
||||
}
|
||||
$sPath = $_SERVER['REQUEST_URI'];
|
||||
if (!$bQueryString)
|
||||
{
|
||||
// remove all the parameters from the query string
|
||||
$iQuestionMarkPos = strpos($sPath, '?');
|
||||
if ($iQuestionMarkPos !== false)
|
||||
{
|
||||
$sPath = substr($sPath, 0, $iQuestionMarkPos);
|
||||
}
|
||||
}
|
||||
$sUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}";
|
||||
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL PATH of the current page
|
||||
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
|
||||
* @return string The absolute URL to the current page
|
||||
*/
|
||||
static public function GetAbsoluteUrlPath($bForceHTTPS = false)
|
||||
{
|
||||
$sAbsoluteUrl = self::GetAbsoluteUrl(false, $bForceHTTPS); // False => Don't get the query string
|
||||
$sAbsoluteUrl = substr($sAbsoluteUrl, 0, 1+strrpos($sAbsoluteUrl, '/')); // remove the current page, keep just the path, up to the last /
|
||||
return $sAbsoluteUrl;
|
||||
}
|
||||
$sPath = $_SERVER['REQUEST_URI'];
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the server's root path
|
||||
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
|
||||
* @return string The absolute URL to the server's root, without the first slash
|
||||
*/
|
||||
static public function GetAbsoluteUrlAppRoot($sCurrentRelativePath = '', $bForceHTTPS = false)
|
||||
{
|
||||
$sAbsoluteUrl = self::GetAbsoluteUrl(false, $bForceHTTPS); // False => Don't get the query string
|
||||
// remove all the parameters from the query string
|
||||
$iQuestionMarkPos = strpos($sPath, '?');
|
||||
if ($iQuestionMarkPos !== false)
|
||||
{
|
||||
$sPath = substr($sPath, 0, $iQuestionMarkPos);
|
||||
}
|
||||
$sAbsoluteUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}";
|
||||
|
||||
$sCurrentScript = realpath($_SERVER['SCRIPT_FILENAME']);
|
||||
$sCurrentScript = str_replace('\\', '/', $sCurrentScript); // canonical path
|
||||
$sAppRoot = str_replace('\\', '/', APPROOT); // canonical path
|
||||
$sCurrentRelativePath = str_replace($sAppRoot, '', $sCurrentScript);
|
||||
|
||||
$sAppRootPos = strpos($sAbsoluteUrl, $sCurrentRelativePath);
|
||||
if ($sAppRootPos !== false)
|
||||
{
|
||||
$sAbsoluteUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
|
||||
$sAppRootUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Failed to determine application root path $sAbsoluteUrl ($sCurrentRelativePath)");
|
||||
// Second attempt without index.php at the end...
|
||||
$sCurrentRelativePath = str_replace('index.php', '', $sCurrentRelativePath);
|
||||
$sAppRootPos = strpos($sAbsoluteUrl, $sCurrentRelativePath);
|
||||
if ($sAppRootPos !== false)
|
||||
{
|
||||
$sAppRootUrl = substr($sAbsoluteUrl, 0, $sAppRootPos); // remove the current page and path
|
||||
}
|
||||
else
|
||||
{
|
||||
// No luck...
|
||||
throw new Exception("Failed to determine application root path $sAbsoluteUrl ($sCurrentRelativePath) APPROOT:'$sAppRoot'");
|
||||
}
|
||||
}
|
||||
return $sAbsoluteUrl;
|
||||
return $sAppRootUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,7 +530,76 @@ class utils
|
||||
*/
|
||||
static function CanLogOff()
|
||||
{
|
||||
return (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form');
|
||||
$bResult = false;
|
||||
if(isset($_SESSION['login_mode']))
|
||||
{
|
||||
$sLoginMode = $_SESSION['login_mode'];
|
||||
switch($sLoginMode)
|
||||
{
|
||||
case 'external':
|
||||
$bResult = false;
|
||||
break;
|
||||
|
||||
case 'form':
|
||||
case 'basic':
|
||||
case 'url':
|
||||
case 'cas':
|
||||
default:
|
||||
$bResult = true;
|
||||
|
||||
}
|
||||
}
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the CAS client
|
||||
*/
|
||||
static function InitCASClient()
|
||||
{
|
||||
$sCASIncludePath = MetaModel::GetConfig()->Get('cas_include_path');
|
||||
include_once($sCASIncludePath.'/CAS.php');
|
||||
|
||||
$bCASDebug = MetaModel::GetConfig()->Get('cas_debug');
|
||||
if ($bCASDebug)
|
||||
{
|
||||
phpCAS::setDebug(APPROOT.'/error.log');
|
||||
}
|
||||
|
||||
if (!self::$m_bCASClient)
|
||||
{
|
||||
// Initialize phpCAS
|
||||
$sCASVersion = MetaModel::GetConfig()->Get('cas_version');
|
||||
$sCASHost = MetaModel::GetConfig()->Get('cas_host');
|
||||
$iCASPort = MetaModel::GetConfig()->Get('cas_port');
|
||||
$sCASContext = MetaModel::GetConfig()->Get('cas_context');
|
||||
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, false /* session already started */);
|
||||
self::$m_bCASClient = true;
|
||||
$sCASCACertPath = MetaModel::GetConfig()->Get('cas_server_ca_cert_path');
|
||||
if (empty($sCASCACertPath))
|
||||
{
|
||||
// If no certificate authority is provided, do not attempt to validate
|
||||
// the server's certificate
|
||||
// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
|
||||
// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
|
||||
phpCAS::setNoCasServerValidation();
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::setCasServerCACert($sCASCACertPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function DebugBacktrace($iLimit = 5)
|
||||
{
|
||||
$aFullTrace = debug_backtrace();
|
||||
$aLightTrace = array();
|
||||
for($i=1; ($i<=$iLimit && $i < count($aFullTrace)); $i++) // Skip the last function call... which is the call to this function !
|
||||
{
|
||||
$aLightTrace[$i] = $aFullTrace[$i]['function'].'(), called from line '.$aFullTrace[$i]['line'].' in '.$aFullTrace[$i]['file'];
|
||||
}
|
||||
echo "<p><pre>".print_r($aLightTrace, true)."</pre></p>\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -47,7 +47,10 @@ class WebPage
|
||||
protected $a_base;
|
||||
protected $iNextId;
|
||||
protected $iTransactionId;
|
||||
|
||||
protected $sContentType;
|
||||
protected $sContentDisposition;
|
||||
protected $sContentFileName;
|
||||
|
||||
public function __construct($s_title)
|
||||
{
|
||||
$this->s_title = $s_title;
|
||||
@@ -61,6 +64,9 @@ class WebPage
|
||||
$this->a_base = array( 'href' => '', 'target' => '');
|
||||
$this->iNextId = 0;
|
||||
$this->iTransactionId = 0;
|
||||
$this->sContentType = '';
|
||||
$this->sContentDisposition = '';
|
||||
$this->sContentFileName = '';
|
||||
ob_start(); // Start capturing the output
|
||||
}
|
||||
|
||||
@@ -90,11 +96,11 @@ class WebPage
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any text or HTML fragment at the end of the body of the page
|
||||
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
|
||||
* This is useful to add hidden content, DIVs or FORMs that should not
|
||||
* be embedded into each other.
|
||||
*/
|
||||
public function add_at_the_end($s_html)
|
||||
public function add_at_the_end($s_html, $sId = '')
|
||||
{
|
||||
$this->s_deferred_content .= $s_html;
|
||||
}
|
||||
@@ -154,27 +160,33 @@ class WebPage
|
||||
$sHtml .= "<tbody>\n";
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
if (isset($aRow['@class'])) // Row specific class, for hilighting certain rows
|
||||
{
|
||||
$sHtml .= "<tr class=\"{$aRow['@class']}\">\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<tr>\n";
|
||||
}
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$aMatches = array();
|
||||
$sClass = isset($aAttribs['class']) ? 'class="'.$aAttribs['class'].'"' : '';
|
||||
$sValue = ($aRow[$sName] === '') ? ' ' : $aRow[$sName];
|
||||
$sHtml .= "<td $sClass>$sValue</td>\n";
|
||||
}
|
||||
$sHtml .= "</tr>\n";
|
||||
$sHtml .= $this->GetTableRow($aRow, $aConfig);
|
||||
}
|
||||
$sHtml .= "</tbody>\n";
|
||||
$sHtml .= "</table>\n";
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function GetTableRow($aRow, $aConfig)
|
||||
{
|
||||
$sHtml = '';
|
||||
if (isset($aRow['@class'])) // Row specific class, for hilighting certain rows
|
||||
{
|
||||
$sHtml .= "<tr class=\"{$aRow['@class']}\">";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<tr>";
|
||||
}
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$sClass = isset($aAttribs['class']) ? 'class="'.$aAttribs['class'].'"' : '';
|
||||
$sValue = ($aRow[$sName] === '') ? ' ' : $aRow[$sName];
|
||||
$sHtml .= "<td $sClass>$sValue</td>";
|
||||
}
|
||||
$sHtml .= "</tr>";
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add some Javascript to the header of the page
|
||||
@@ -240,6 +252,28 @@ class WebPage
|
||||
|
||||
$this->add($this->GetDetails($aFields));
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the current state of the 'html' part of the page output
|
||||
* @return mixed The current state of the 'html' output
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
return strlen($this->s_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the html output that occurred since the call to start_capture
|
||||
* and removes this part from the current html output
|
||||
* @param $offset mixed The value returned by start_capture
|
||||
* @return string The part of the html output that was added since the call to start_capture
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
$sCaptured = substr($this->s_content, $offset);
|
||||
$this->s_content = substr($this->s_content, 0, $offset);
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a special kind of TABLE useful for displaying the details of an object from a hash array of data
|
||||
@@ -269,6 +303,53 @@ class WebPage
|
||||
$sHtml .= "</table>\n";
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a set of radio buttons suitable for editing a field/attribute of an object (including its validation)
|
||||
* @param $aAllowedValues hash Array of value => display_value
|
||||
* @param $value mixed Current value for the field/attribute
|
||||
* @param $iId mixed Unique Id for the input control in the page
|
||||
* @param $sFieldName string The name of the field, attr_<$sFieldName> will hold the value for the field
|
||||
* @param $bMandatory bool Whether or not the field is mandatory
|
||||
* @param $bVertical bool Disposition of the radio buttons vertical or horizontal
|
||||
* @param $sValidationField string HTML fragment holding the validation field (exclamation icon...)
|
||||
* @return string The HTML fragment corresponding to the radio buttons
|
||||
*/
|
||||
public function GetRadioButtons($aAllowedValues, $value, $iId, $sFieldName, $bMandatory, $bVertical, $sValidationField)
|
||||
{
|
||||
$idx = 0;
|
||||
$sHTMLValue = '';
|
||||
foreach($aAllowedValues as $key => $display_value)
|
||||
{
|
||||
if ((count($aAllowedValues) == 1) && ($bMandatory == 'true') )
|
||||
{
|
||||
// When there is only once choice, select it by default
|
||||
$sSelected = ' checked';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($value == $key) ? ' checked' : '';
|
||||
}
|
||||
$sHTMLValue .= "<input type=\"radio\" id=\"{$iId}_{$key}\" name=\"radio_$sFieldName\" onChange=\"$('#{$iId}').val(this.value).trigger('change');\" value=\"$key\"$sSelected><label class=\"radio\" for=\"{$iId}_{$key}\"> $display_value</label> ";
|
||||
if ($bVertical)
|
||||
{
|
||||
if ($idx == 0)
|
||||
{
|
||||
// Validation icon at the end of the first line
|
||||
$sHTMLValue .= " {$sValidationField}\n";
|
||||
}
|
||||
$sHTMLValue .= "<br>\n";
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
$sHTMLValue .= "<input type=\"hidden\" id=\"$iId\" name=\"$sFieldName\" value=\"$value\"/>";
|
||||
if (!$bVertical)
|
||||
{
|
||||
// Validation icon at the end of the line
|
||||
$sHTMLValue .= " {$sValidationField}\n";
|
||||
}
|
||||
return $sHTMLValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs (via some echo) the complete HTML page by assembling all its elements
|
||||
@@ -284,8 +365,8 @@ class WebPage
|
||||
echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
|
||||
echo "<html>\n";
|
||||
echo "<head>\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<title>{$this->s_title}</title>\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
echo $this->get_base_tag();
|
||||
foreach($this->a_linked_scripts as $s_script)
|
||||
{
|
||||
@@ -334,12 +415,12 @@ class WebPage
|
||||
}
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
echo $this->s_content;
|
||||
echo self::FilterXSS($this->s_content);
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo "<div class=\"raw_output\">$s_captured_output</div>\n";
|
||||
echo "<div class=\"raw_output\">".self::FilterXSS($s_captured_output)."</div>\n";
|
||||
}
|
||||
echo '<div id="at_the_end">'.$this->s_deferred_content.'</div>';
|
||||
echo '<div id="at_the_end">'.self::FilterXSS($this->s_deferred_content).'</div>';
|
||||
echo "</body>\n";
|
||||
echo "</html>\n";
|
||||
}
|
||||
@@ -384,7 +465,29 @@ class WebPage
|
||||
{
|
||||
return $this->iNextId++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the content-type (mime type) for the page's content
|
||||
* @param $sContentType string
|
||||
* @return void
|
||||
*/
|
||||
public function SetContentType($sContentType)
|
||||
{
|
||||
$this->sContentType = $sContentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content-disposition (mime type) for the page's content
|
||||
* @param $sDisposition string The disposition: 'inline' or 'attachment'
|
||||
* @param $sFileName string The original name of the file
|
||||
* @return void
|
||||
*/
|
||||
public function SetContentDisposition($sDisposition, $sFileName)
|
||||
{
|
||||
$this->sContentDisposition = $sDisposition;
|
||||
$this->sContentFileName = $sFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transactionId of the current form
|
||||
* @param $iTransactionId integer
|
||||
@@ -403,5 +506,10 @@ class WebPage
|
||||
{
|
||||
return $this->iTransactionId;
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace('<script', '<script', $sHTML);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -98,7 +98,7 @@ class WizardHelper
|
||||
{
|
||||
if ($bReadUploadedFiles)
|
||||
{
|
||||
$oDocument = utils::ReadPostedDocument('file_'.$sAttCode);
|
||||
$oDocument = utils::ReadPostedDocument('attr_'.$sAttCode, 'fcontents');
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
else
|
||||
@@ -125,7 +125,7 @@ class WizardHelper
|
||||
{
|
||||
$oObj->Set(MetaModel::GetStateAttributeCode($this->m_aData['m_sClass']), $this->m_aData['m_sState']);
|
||||
}
|
||||
|
||||
$oObj->DoComputeValues();
|
||||
return $oObj;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,25 +274,33 @@ class ActionEmail extends ActionNotification
|
||||
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
$bRes = false; // until we do succeed in sending the email
|
||||
|
||||
// Determine recicipients
|
||||
//
|
||||
$sTo = $this->FindRecipients('to', $aContextArgs);
|
||||
$sCC = $this->FindRecipients('cc', $aContextArgs);
|
||||
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$sFrom = $this->Get('from');
|
||||
$sReplyTo = $this->Get('reply_to');
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sServerIP = $_SERVER['SERVER_ADDR']; //gethostbyname(gethostname());
|
||||
$sReference = '<iTop/'.get_class($oObj).'/'.$oObj->GetKey().'@'.$sServerIP.'>';
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
$this->m_aMailErrors = array();
|
||||
$bRes = false; // until we do succeed in sending the email
|
||||
|
||||
// Determine recicipients
|
||||
//
|
||||
$sTo = $this->FindRecipients('to', $aContextArgs);
|
||||
$sCC = $this->FindRecipients('cc', $aContextArgs);
|
||||
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
|
||||
|
||||
$sFrom = $this->Get('from');
|
||||
$sReplyTo = $this->Get('reply_to');
|
||||
|
||||
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sReference = '<iTop/'.get_class($oObj).'/'.$oObj->GetKey().'>';
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (!is_null($oLog))
|
||||
{
|
||||
|
||||
@@ -64,7 +64,14 @@ define('DEL_MANUAL', 1);
|
||||
* @package iTopORM
|
||||
*/
|
||||
define('DEL_AUTO', 2);
|
||||
/**
|
||||
* Fully silent delete... not yet implemented
|
||||
*/
|
||||
define('DEL_SILENT', 2);
|
||||
/**
|
||||
* For HierarchicalKeys only: move all the children up one level automatically
|
||||
*/
|
||||
define('DEL_MOVEUP', 3);
|
||||
|
||||
|
||||
/**
|
||||
@@ -167,11 +174,31 @@ abstract class AttributeDefinition
|
||||
public function IsScalar() {return false;}
|
||||
public function IsLinkSet() {return false;}
|
||||
public function IsExternalKey($iType = EXTKEY_RELATIVE) {return false;}
|
||||
public function IsHierarchicalKey() {return false;}
|
||||
public function IsExternalField() {return false;}
|
||||
public function IsWritable() {return false;}
|
||||
public function IsNullAllowed() {return true;}
|
||||
public function GetCode() {return $this->m_sCode;}
|
||||
public function GetLabel() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, $this->m_sCode);}
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
$sLabel = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, '');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$sLabel = $this->m_sCode;
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sLabel = $oAttDef->GetLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetLabel_Obsolete()
|
||||
{
|
||||
// Written for compatibility with a data model written prior to version 0.9.1
|
||||
@@ -184,8 +211,57 @@ abstract class AttributeDefinition
|
||||
return $this->GetLabel();
|
||||
}
|
||||
}
|
||||
public function GetDescription() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'+', '');}
|
||||
public function GetHelpOnEdition() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'?', '');}
|
||||
|
||||
public function GetDescription()
|
||||
{
|
||||
$sDescription = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'+', '');
|
||||
if (strlen($sDescription) == 0)
|
||||
{
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sDescription = $oAttDef->GetDescription();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sDescription;
|
||||
}
|
||||
|
||||
public function GetHelpOnEdition()
|
||||
{
|
||||
$sHelp = Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode.'?', '');
|
||||
if (strlen($sHelp) == 0)
|
||||
{
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sHelp = $oAttDef->GetHelpOnEdition();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sHelp;
|
||||
}
|
||||
|
||||
public function GetHelpOnSmartSearch()
|
||||
{
|
||||
$aParents = array_merge(array(get_class($this) => get_class($this)), class_parents($this));
|
||||
foreach ($aParents as $sClass)
|
||||
{
|
||||
$sHelp = Dict::S("Core:$sClass?SmartSearch", '-missing-');
|
||||
if ($sHelp != '-missing-')
|
||||
{
|
||||
return $sHelp;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public function GetDescription_Obsolete()
|
||||
{
|
||||
// Written for compatibility with a data model written prior to version 0.9.1
|
||||
@@ -586,6 +662,28 @@ class AttributeLinkedSet extends AttributeDefinition
|
||||
}
|
||||
}
|
||||
|
||||
// Check (roughly) if such a link is valid
|
||||
$aErrors = array();
|
||||
foreach(MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
if (($oAttDef->GetTargetClass() == $this->GetHostClass()) || (is_subclass_of($this->GetHostClass(), $oAttDef->GetTargetClass())))
|
||||
{
|
||||
continue; // Don't check the key to self
|
||||
}
|
||||
}
|
||||
|
||||
if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed())
|
||||
{
|
||||
$aErrors[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
if (count($aErrors) > 0)
|
||||
{
|
||||
throw new CoreException("Missing value for mandatory attribute(s): ".implode(', ', $aErrors));
|
||||
}
|
||||
|
||||
$aLinks[] = $oLink;
|
||||
}
|
||||
$oSet = DBObjectSet::FromArray($sTargetClass, $aLinks);
|
||||
@@ -1071,6 +1169,11 @@ class AttributeString extends AttributeDBField
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
return $sTextQualifier.$sEscaped.$sTextQualifier;
|
||||
}
|
||||
|
||||
public function GetDisplayStyle()
|
||||
{
|
||||
return $this->GetOptional('display_style', 'select');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1349,13 +1452,21 @@ class AttributeText extends AttributeString
|
||||
|
||||
static public function RenderWikiHtml($sText)
|
||||
{
|
||||
if (preg_match_all(WIKI_URL, $sText, $aAllMatches, PREG_SET_ORDER))
|
||||
if (preg_match_all(WIKI_URL, $sText, $aAllMatches, PREG_SET_ORDER /* important !*/ |PREG_OFFSET_CAPTURE /* important ! */))
|
||||
{
|
||||
foreach($aAllMatches as $iPos => $aMatches)
|
||||
$aUrls = array();
|
||||
$i = count($aAllMatches);
|
||||
// Replace the URLs by an actual hyperlink <a href="...">...</a>
|
||||
// Let's do it backwards so that the initial positions are not modified by the replacement
|
||||
// This works if the matches are captured: in the order they occur in the string AND
|
||||
// with their offset (i.e. position) inside the string
|
||||
while($i > 0)
|
||||
{
|
||||
$sUrl = $aMatches[0];
|
||||
$sHLink = "<a href=\"$sUrl\">$sUrl</a>";
|
||||
$sText = str_replace($sUrl, $sHLink, $sText);
|
||||
$i--;
|
||||
$sUrl = $aAllMatches[$i][0][0]; // String corresponding to the main pattern
|
||||
$iPos = $aAllMatches[$i][0][1]; // Position of the main pattern
|
||||
$sText = substr_replace($sText, "<a href=\"$sUrl\">$sUrl</a>", $iPos, strlen($sUrl));
|
||||
|
||||
}
|
||||
}
|
||||
if (preg_match_all(WIKI_OBJECT_REGEXP, $sText, $aAllMatches, PREG_SET_ORDER))
|
||||
@@ -1380,7 +1491,7 @@ class AttributeText extends AttributeString
|
||||
$sText = str_replace($aMatches[0], "<span class=\"wiki_broken_link\">$sClassLabel:$sName</span>", $sText);
|
||||
// Later: propose a link to create a new object
|
||||
// Anyhow... there is no easy way to suggest default values based on the given FRIENDLY name
|
||||
//$sText = preg_replace('/\[\[(.+):(.+)\]\]/', '<a href="./UI.php?operation=new&class='.$sClass.'&default[att1]=xxx&default[att2]=yyy">'.$sName.'</a>', $sText);
|
||||
//$sText = preg_replace('/\[\[(.+):(.+)\]\]/', '<a href="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$sClass.'&default[att1]=xxx&default[att2]=yyy">'.$sName.'</a>', $sText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1837,7 +1948,7 @@ class AttributeEnum extends AttributeString
|
||||
return parent::GetBasicFilterSQLExpr($sOpCode, $value);
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null)
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
if (is_null($sValue))
|
||||
{
|
||||
@@ -1846,17 +1957,61 @@ class AttributeEnum extends AttributeString
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue);
|
||||
$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, '');
|
||||
if (strlen($sLabel) == 0)
|
||||
{
|
||||
$sLabel = $sValue;
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sLabel = $oAttDef->GetValueLabel($sValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', $sValue);
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
public function GetValueDescription($sValue)
|
||||
{
|
||||
if (is_null($sValue))
|
||||
{
|
||||
// Unless a specific label is defined for the null value of this enum, use a generic "undefined" label
|
||||
$sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', Dict::S('Enum:Undefined'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', '');
|
||||
if (strlen($sDescription) == 0)
|
||||
{
|
||||
$sParentClass = MetaModel::GetParentClass($this->m_sHostClass);
|
||||
if ($sParentClass)
|
||||
{
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode);
|
||||
$sDescription = $oAttDef->GetValueDescription($sValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sDescription;
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null)
|
||||
{
|
||||
$sLabel = $this->GetValueLabel($sValue);
|
||||
$sDescription = $this->GetValueDescription($sValue);
|
||||
// later, we could imagine a detailed description in the title
|
||||
return "<span title=\"$sDescription\">".parent::GetAsHtml($sLabel)."</span>";
|
||||
}
|
||||
|
||||
public function GetEditValue($sValue)
|
||||
{
|
||||
$sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, $sValue);
|
||||
return $sLabel;
|
||||
return $this->GetValueLabel($sValue);
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
@@ -1866,7 +2021,7 @@ class AttributeEnum extends AttributeString
|
||||
$aLocalizedValues = array();
|
||||
foreach ($aRawValues as $sKey => $sValue)
|
||||
{
|
||||
$aLocalizedValues[$sKey] = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sKey, $sKey);
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
return $aLocalizedValues;
|
||||
}
|
||||
@@ -1927,7 +2082,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
{
|
||||
if (empty($default))
|
||||
{
|
||||
$default = date(self::GetDateFormat());
|
||||
$default = date($this->GetDateFormat());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2185,6 +2340,7 @@ class AttributeDuration extends AttributeInteger
|
||||
|
||||
static function SplitDuration($duration)
|
||||
{
|
||||
$duration = (int) $duration;
|
||||
$days = floor($duration / 86400);
|
||||
$hours = floor(($duration - (86400*$days)) / 3600);
|
||||
$minutes = floor(($duration - (86400*$days + 3600*$hours)) / 60);
|
||||
@@ -2233,17 +2389,20 @@ class AttributeDeadline extends AttributeDateTime
|
||||
$sResult = '';
|
||||
if ($value !== null)
|
||||
{
|
||||
$value = AttributeDateTime::GetAsUnixSeconds($value);
|
||||
$difference = $value - time();
|
||||
$iValue = AttributeDateTime::GetAsUnixSeconds($value);
|
||||
$sDate = parent::GetAsHTML($value, $oHostObject);
|
||||
$difference = $iValue - time();
|
||||
|
||||
if ($difference >= 0)
|
||||
{
|
||||
$sResult = self::FormatDuration($difference);
|
||||
$sDifference = self::FormatDuration($difference);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('UI:DeadlineMissedBy_duration', self::FormatDuration(-$difference));
|
||||
$sDifference = Dict::Format('UI:DeadlineMissedBy_duration', self::FormatDuration(-$difference));
|
||||
}
|
||||
$sFormat = MetaModel::GetConfig()->Get('deadline_format', '$difference$');
|
||||
$sResult = str_replace(array('$date$', '$difference$'), array($sDate, $sDifference), $sFormat);
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
@@ -2305,6 +2464,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
public function GetTargetClass($iType = EXTKEY_RELATIVE) {return $this->Get("targetclass");}
|
||||
public function GetKeyAttDef($iType = EXTKEY_RELATIVE){return $this;}
|
||||
public function GetKeyAttCode() {return $this->GetCode();}
|
||||
public function GetDisplayStyle() { return $this->GetOptional('display_style', 'select'); }
|
||||
|
||||
|
||||
public function GetDefaultValue() {return 0;}
|
||||
@@ -2339,6 +2499,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
//throw new Exception("GetAllowedValues on ext key has been deprecated");
|
||||
try
|
||||
{
|
||||
return parent::GetAllowedValues($aArgs, $sContains);
|
||||
@@ -2351,6 +2512,13 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAllowedValuesAsObjectSet($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
$oSet = $oValSetDef->ToObjectSet($aArgs, $sContains);
|
||||
return $oSet;
|
||||
}
|
||||
|
||||
public function GetDeletionPropagationOption()
|
||||
{
|
||||
return $this->Get("on_target_delete");
|
||||
@@ -2390,6 +2558,130 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special kind of External Key to manage a hierarchy of objects
|
||||
*/
|
||||
class AttributeHierarchicalKey extends AttributeExternalKey
|
||||
{
|
||||
protected $m_sTargetClass;
|
||||
|
||||
static protected function ListExpectedParams()
|
||||
{
|
||||
$aParams = parent::ListExpectedParams();
|
||||
$idx = array_search('targetclass', $aParams);
|
||||
unset($aParams[$idx]);
|
||||
$idx = array_search('jointype', $aParams);
|
||||
unset($aParams[$idx]);
|
||||
return $aParams; // TODO: mettre les bons parametres ici !!
|
||||
}
|
||||
|
||||
public function GetEditClass() {return "ExtKey";}
|
||||
public function RequiresIndex()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The target class is the class for which the attribute has been defined first
|
||||
*/
|
||||
public function SetHostClass($sHostClass)
|
||||
{
|
||||
if (!isset($this->m_sTargetClass))
|
||||
{
|
||||
$this->m_sTargetClass = $sHostClass;
|
||||
}
|
||||
parent::SetHostClass($sHostClass);
|
||||
}
|
||||
|
||||
public function IsHierarchicalKey() {return true;}
|
||||
public function GetTargetClass($iType = EXTKEY_RELATIVE) {return $this->m_sTargetClass;}
|
||||
public function GetKeyAttDef($iType = EXTKEY_RELATIVE){return $this;}
|
||||
public function GetKeyAttCode() {return $this->GetCode();}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return parent::GetBasicFilterOperators();
|
||||
}
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
return parent::GetBasicFilterLooseOperator();
|
||||
}
|
||||
|
||||
public function GetSQLColumns()
|
||||
{
|
||||
$aColumns = array();
|
||||
$aColumns[$this->GetCode()] = 'INT(11)';
|
||||
$aColumns[$this->GetSQLLeft()] = 'INT(11)';
|
||||
$aColumns[$this->GetSQLRight()] = 'INT(11)';
|
||||
return $aColumns;
|
||||
}
|
||||
public function GetSQLRight()
|
||||
{
|
||||
return $this->GetCode().'_right';
|
||||
}
|
||||
public function GetSQLLeft()
|
||||
{
|
||||
return $this->GetCode().'_left';
|
||||
}
|
||||
|
||||
public function GetSQLValues($value)
|
||||
{
|
||||
if (!is_array($value))
|
||||
{
|
||||
$aValues[$this->GetCode()] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues = array();
|
||||
$aValues[$this->GetCode()] = $value[$this->GetCode()];
|
||||
$aValues[$this->GetSQLRight()] = $value[$this->GetSQLRight()];
|
||||
$aValues[$this->GetSQLLeft()] = $value[$this->GetSQLLeft()];
|
||||
}
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
if (array_key_exists('this', $aArgs))
|
||||
{
|
||||
// Hierarchical keys have one more constraint: the "parent value" cannot be
|
||||
// "under" themselves
|
||||
$iRootId = $aArgs['this']->GetKey();
|
||||
if ($iRootId > 0) // ignore objects that do no exist in the database...
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
$sClass = $this->m_sTargetClass;
|
||||
$oFilter = DBObjectSearch::FromOQL("SELECT $sClass AS node JOIN $sClass AS root ON node.".$this->GetCode()." NOT BELOW root.id WHERE root.id = $iRootId");
|
||||
$oValSetDef->AddCondition($oFilter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::GetAllowedValues($aArgs, $sContains);
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAllowedValuesAsObjectSet($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oValSetDef = $this->GetValuesDef();
|
||||
if (array_key_exists('this', $aArgs))
|
||||
{
|
||||
// Hierarchical keys have one more constraint: the "parent value" cannot be
|
||||
// "under" themselves
|
||||
$iRootId = $aArgs['this']->GetKey();
|
||||
if ($iRootId > 0) // ignore objects that do no exist in the database...
|
||||
{
|
||||
$aValuesSetDef = $this->GetValuesDef();
|
||||
$sClass = $this->m_sTargetClass;
|
||||
$oFilter = DBObjectSearch::FromOQL("SELECT $sClass AS node JOIN $sClass AS root ON node.".$this->GetCode()." NOT BELOW root.id WHERE root.id = $iRootId");
|
||||
$oValSetDef->AddCondition($oFilter);
|
||||
}
|
||||
}
|
||||
$oSet = $oValSetDef->ToObjectSet($aArgs, $sContains);
|
||||
return $oSet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An attribute which corresponds to an external key (direct or indirect)
|
||||
*
|
||||
@@ -2495,8 +2787,8 @@ class AttributeExternalField extends AttributeDefinition
|
||||
public function GetExtAttDef()
|
||||
{
|
||||
$oKeyAttDef = $this->GetKeyAttDef();
|
||||
$oExtAttDef = MetaModel::GetAttributeDef($oKeyAttDef->Get("targetclass"), $this->Get("target_attcode"));
|
||||
if (!is_object($oExtAttDef)) throw new CoreException("Invalid external field ".$this->GetCode()." in class ".$this->GetHostClass().". The class ".$oKeyAttDef->Get("targetclass")." has no attribute ".$this->Get("target_attcode"));
|
||||
$oExtAttDef = MetaModel::GetAttributeDef($oKeyAttDef->GetTargetClass(), $this->Get("target_attcode"));
|
||||
if (!is_object($oExtAttDef)) throw new CoreException("Invalid external field ".$this->GetCode()." in class ".$this->GetHostClass().". The class ".$oKeyAttDef->GetTargetClass()." has no attribute ".$this->Get("target_attcode"));
|
||||
return $oExtAttDef;
|
||||
}
|
||||
|
||||
|
||||
@@ -252,8 +252,9 @@ class BulkChange
|
||||
protected $m_aReconcilKeys; // attcode (attcode = 'id' for the pkey)
|
||||
protected $m_sSynchroScope; // OQL - if specified, then the missing items will be reported
|
||||
protected $m_aOnDisappear; // array of attcode => value, values to be set when an object gets out of scope (ignored if no scope has been defined)
|
||||
protected $m_sDateFormat; // Date format specification, see utils::StringToTime()
|
||||
|
||||
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null)
|
||||
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null)
|
||||
{
|
||||
$this->m_sClass = $sClass;
|
||||
$this->m_aData = $aData;
|
||||
@@ -262,6 +263,7 @@ class BulkChange
|
||||
$this->m_aExtKeys = $aExtKeys;
|
||||
$this->m_sSynchroScope = $sSynchroScope;
|
||||
$this->m_aOnDisappear = $aOnDisappear;
|
||||
$this->m_sDateFormat = $sDateFormat;
|
||||
}
|
||||
|
||||
protected $m_bReportHtml = false;
|
||||
@@ -412,7 +414,7 @@ class BulkChange
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
$res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
|
||||
if ($res === true)
|
||||
{
|
||||
@@ -702,6 +704,35 @@ class BulkChange
|
||||
exit;
|
||||
}
|
||||
|
||||
$aResult = array();
|
||||
|
||||
if (!is_null($this->m_sDateFormat) && (strlen($this->m_sDateFormat) > 0))
|
||||
{
|
||||
// Translate dates from the source data
|
||||
//
|
||||
foreach ($this->m_aAttList as $sAttCode => $iCol)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
$sNewDate = utils::StringToTime($this->m_aData[$iRow][$iCol], $this->m_sDateFormat);
|
||||
if ($sNewDate !== false)
|
||||
{
|
||||
// Todo - improve the reporting
|
||||
$this->m_aData[$iRow][$iCol] = $sNewDate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave the cell unchanged
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("wrong date format");
|
||||
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], 'Wrong date format');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the results
|
||||
//
|
||||
@@ -709,9 +740,13 @@ class BulkChange
|
||||
{
|
||||
$aVisited = array();
|
||||
}
|
||||
$aResult = array();
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
if (isset($aResult[$iRow]["__STATUS__"]))
|
||||
{
|
||||
// An issue at the earlier steps - skip the rest
|
||||
continue;
|
||||
}
|
||||
$oReconciliationFilter = new CMDBSearchFilter($this->m_sClass);
|
||||
$bSkipQuery = false;
|
||||
foreach($this->m_aReconcilKeys as $sAttCode)
|
||||
@@ -798,8 +833,28 @@ class BulkChange
|
||||
$aResult[$iRow]["finalclass"]= 'n/a';
|
||||
}
|
||||
}
|
||||
|
||||
// Whatever happened, do report the reconciliation values
|
||||
}
|
||||
|
||||
if (!is_null($this->m_sSynchroScope))
|
||||
{
|
||||
// Compute the delta between the scope and visited objects
|
||||
$oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
|
||||
$oScopeSet = new DBObjectSet($oScopeSearch);
|
||||
while ($oObj = $oScopeSet->Fetch())
|
||||
{
|
||||
$iObj = $oObj->GetKey();
|
||||
if (!in_array($iObj, $aVisited))
|
||||
{
|
||||
$iRow++;
|
||||
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in the blanks - the result matrix is expected to be 100% complete
|
||||
//
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
foreach($this->m_aAttList as $iCol)
|
||||
{
|
||||
if (!array_key_exists($iCol, $aResult[$iRow]))
|
||||
@@ -824,22 +879,6 @@ class BulkChange
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($this->m_sSynchroScope))
|
||||
{
|
||||
// Compute the delta between the scope and visited objects
|
||||
$oScopeSearch = DBObjectSearch::FromOQL($this->m_sSynchroScope);
|
||||
$oScopeSet = new DBObjectSet($oScopeSearch);
|
||||
while ($oObj = $oScopeSet->Fetch())
|
||||
{
|
||||
$iObj = $oObj->GetKey();
|
||||
if (!in_array($iObj, $aVisited))
|
||||
{
|
||||
$iRow++;
|
||||
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
@@ -960,7 +999,7 @@ EOF
|
||||
<<<EOF
|
||||
function OnTruncatedHistoryToggle(bShowAll)
|
||||
{
|
||||
$.get('../pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
|
||||
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
|
||||
{
|
||||
$('#$sAjaxDivId').html(data);
|
||||
var table = $('#$sAjaxDivId .listResults');
|
||||
@@ -1032,10 +1071,19 @@ EOF
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$oOldTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('oldvalue'));
|
||||
$oNewTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('newvalue'));
|
||||
$sOldValue = $oOldTarget->GetHyperlink();
|
||||
$sNewValue = $oNewTarget->GetHyperlink();
|
||||
$sOldValue = Dict::S('UI:UndefinedObject');
|
||||
if ($oOperation->Get('oldvalue') != 0)
|
||||
{
|
||||
$oOldTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('oldvalue'));
|
||||
$sOldValue = $oOldTarget->GetHyperlink();
|
||||
}
|
||||
|
||||
$sNewValue = Dict::S('UI:UndefinedObject');
|
||||
if ($oOperation->Get('newvalue') != 0)
|
||||
{
|
||||
$oNewTarget = MetaModel::GetObject($oAttDef->GetTargetClass(), $oOperation->Get('newvalue'));
|
||||
$sNewValue = $oNewTarget->GetHyperlink();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -212,11 +212,27 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
|
||||
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) return ''; // Protects against renamed attributes...
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
|
||||
$sAttName = $oAttDef->GetLabel();
|
||||
$sNewValue = $this->Get('newvalue');
|
||||
$sOldValue = $this->Get('oldvalue');
|
||||
if ( (($oAttDef->GetType() == 'String') || ($oAttDef->GetType() == 'Text')) &&
|
||||
if ($oAttDef instanceof AttributeEnum)
|
||||
{
|
||||
// translate the enum values
|
||||
$sOldValue = $oAttDef->GetAsHTML($sOldValue);
|
||||
$sNewValue = $oAttDef->GetAsHTML($sNewValue);
|
||||
if (strlen($sOldValue) == 0)
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
|
||||
}
|
||||
}
|
||||
elseif ( (($oAttDef->GetType() == 'String') || ($oAttDef->GetType() == 'Text')) &&
|
||||
(strlen($sNewValue) > strlen($sOldValue)) )
|
||||
{
|
||||
// Check if some text was not appended to the field
|
||||
@@ -554,4 +570,41 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an action made by a plug-in
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class CMDBChangeOpPlugin extends CMDBChangeOp
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "",
|
||||
"name_attcode" => "change",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_changeop_plugin",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
/* May be used later when implementing an extension mechanism that will allow the plug-ins to store some extra information and still degrades gracefully when the plug-in is desinstalled
|
||||
MetaModel::Init_AddAttribute(new AttributeString("extension_class", array("allowed_values"=>null, "sql"=>"extension_class", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("extension_id", array("allowed_values"=>null, "sql"=>"extension_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
*/
|
||||
MetaModel::Init_InheritAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe (as a text string) the modifications corresponding to this change
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
return $this->Get('description');
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -498,24 +498,22 @@ class CMDBObjectSet extends DBObjectSet
|
||||
static public function FromScratch($sClass)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE
|
||||
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private...
|
||||
// BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!!
|
||||
$oFilter->AddConditionExpression(new FalseExpression());
|
||||
$oRetSet = new self($oFilter);
|
||||
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private in the base class (and you will not get any error message)
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
return $oRetSet;
|
||||
}
|
||||
|
||||
// create an object set ex nihilo
|
||||
// input = array of objects
|
||||
static public function FromArray($sClass, $aObjects)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE
|
||||
// NOTE: THIS DOES NOT WORK IF m_bLoaded is private...
|
||||
// BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!!
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
$oRetSet->AddObjectArray($aObjects);
|
||||
$oRetSet = self::FromScratch($sClass);
|
||||
$oRetSet->AddObjectArray($aObjects, $sClass);
|
||||
return $oRetSet;
|
||||
}
|
||||
|
||||
|
||||
static public function FromArrayAssoc($aClasses, $aObjects)
|
||||
{
|
||||
// In a perfect world, we should create a complete tree of DBObjectSearch,
|
||||
|
||||
@@ -58,7 +58,6 @@ define ('DEFAULT_MAX_DISPLAY_LIMIT', 15);
|
||||
define ('DEFAULT_STANDARD_RELOAD_INTERVAL', 5*60);
|
||||
define ('DEFAULT_FAST_RELOAD_INTERVAL', 1*60);
|
||||
define ('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
|
||||
define ('DEFAULT_HTTPS_HYPERLINKS', false);
|
||||
define ('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|basic|external');
|
||||
define ('DEFAULT_EXT_AUTH_VARIABLE', '$_SERVER[\'REMOTE_USER\']');
|
||||
define ('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random value, later...
|
||||
@@ -85,6 +84,14 @@ class Config
|
||||
// New way to store the settings !
|
||||
//
|
||||
protected $m_aSettings = array(
|
||||
'app_root_url' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server\'s name)',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'skip_check_to_write' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Disable data format and integrity checks to boost up data load (insert or update)',
|
||||
@@ -304,12 +311,124 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_include_path' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The path where to find the phpCAS library',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '/usr/share/php',
|
||||
'value' => '/usr/share/php',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_version' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The CAS protocol version to use: "1.0" (CAS v1), "2.0" (CAS v2) or "S1" (SAML V1) )',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '2.0',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_host' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The name of the CAS host',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_port' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'The port used by the CAS server',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 443,
|
||||
'value' => 443,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_context' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The CAS context',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_server_ca_cert_path' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The path where to find the certificate of the CA for validating the certificate of the CAS server',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_logout_redirect_service' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The redirect service (URL) to use when logging-out with CAS',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_memberof' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'A semicolon separated list of group names that the user must be member of (works only with SAML - e.g. cas_version=> "S1")',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_debug' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Activate the CAS debug',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'deadline_format' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$',
|
||||
// examples... $date$ ($deadline$)
|
||||
'default' => '$difference$',
|
||||
'value' => '$difference$',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'buttons_position' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Position of the forms buttons: bottom | top | both',
|
||||
// examples... not used
|
||||
'default' => 'both',
|
||||
'value' => 'both',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'shortcut_actions' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Actions that are available as direct buttons next to the "Actions" menu',
|
||||
// examples... not used
|
||||
'default' => 'UI:Menu:Modify,UI:Menu:New',
|
||||
'value' => 'UI:Menu:Modify',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
{
|
||||
return (array_key_exists($sPropCode, $this->m_aSettings));
|
||||
}
|
||||
public function GetDescription($sPropCode)
|
||||
{
|
||||
return $this->m_aSettings[$sPropCode];
|
||||
}
|
||||
|
||||
public function Set($sPropCode, $value, $sSourceDesc = 'unknown')
|
||||
{
|
||||
@@ -388,13 +507,6 @@ class Config
|
||||
*/
|
||||
protected $m_bSecureConnectionRequired;
|
||||
|
||||
/**
|
||||
* @var boolean Forces iTop to output hyperlinks starting with https:// even
|
||||
* if the current page is not using https. This can be useful when
|
||||
* the application runs behind a SSL gateway
|
||||
*/
|
||||
protected $m_bHttpsHyperlinks;
|
||||
|
||||
/**
|
||||
* @var string Langage code, default if the user language is undefined
|
||||
*/
|
||||
@@ -450,29 +562,8 @@ class Config
|
||||
// Default AddOn, always present can be moved to an official iTop Module later if needed
|
||||
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
|
||||
);
|
||||
$this->m_aDictionaries = array(
|
||||
// Default dictionaries, always present can be moved to an official iTop Module later if needed
|
||||
'dictionaries/dictionary.itop.core.php',
|
||||
'dictionaries/dictionary.itop.ui.php', // Support for English
|
||||
'dictionaries/fr.dictionary.itop.ui.php', // Support for French
|
||||
'dictionaries/fr.dictionary.itop.core.php', // Support for French
|
||||
'dictionaries/es_cr.dictionary.itop.ui.php', // Support for Spanish (from Costa Rica)
|
||||
'dictionaries/es_cr.dictionary.itop.core.php', // Support for Spanish (from Costa Rica)
|
||||
'dictionaries/de.dictionary.itop.ui.php', // Support for German
|
||||
'dictionaries/de.dictionary.itop.core.php', // Support for German
|
||||
'dictionaries/pt_br.dictionary.itop.ui.php', // Support for Brazilian Portuguese
|
||||
'dictionaries/pt_br.dictionary.itop.core.php', // Support for Brazilian Portuguese
|
||||
'dictionaries/ru.dictionary.itop.ui.php', // Support for Russian
|
||||
'dictionaries/ru.dictionary.itop.core.php', // Support for Russian
|
||||
'dictionaries/tr.dictionary.itop.ui.php', // Support for Turkish
|
||||
'dictionaries/tr.dictionary.itop.core.php', // Support for Turkish
|
||||
'dictionaries/zh.dictionary.itop.ui.php', // Support for Chinese
|
||||
'dictionaries/zh.dictionary.itop.core.php', // Support for Chinese
|
||||
'dictionaries/it.dictionary.itop.ui.php', // Support for Italian
|
||||
'dictionaries/it.dictionary.itop.core.php', // Support for Italian
|
||||
'dictionaries/hu.dictionary.itop.ui.php', // Support for Hungarian
|
||||
'dictionaries/hu.dictionary.itop.core.php', // Support for Hungarian
|
||||
);
|
||||
$this->m_aDictionaries = self::ScanDictionariesDir();
|
||||
|
||||
foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
|
||||
{
|
||||
$this->m_aSettings[$sPropCode]['value'] = $aSettingInfo['default'];
|
||||
@@ -496,7 +587,6 @@ class Config
|
||||
$this->m_iStandardReloadInterval = DEFAULT_STANDARD_RELOAD_INTERVAL;
|
||||
$this->m_iFastReloadInterval = DEFAULT_FAST_RELOAD_INTERVAL;
|
||||
$this->m_bSecureConnectionRequired = DEFAULT_SECURE_CONNECTION_REQUIRED;
|
||||
$this->m_bHttpsHyperlinks = DEFAULT_HTTPS_HYPERLINKS;
|
||||
$this->m_sDefaultLanguage = 'EN US';
|
||||
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
|
||||
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
|
||||
@@ -510,6 +600,18 @@ class Config
|
||||
$this->Load($sConfigFile);
|
||||
$this->Verify();
|
||||
}
|
||||
|
||||
// Application root url: set a default value, then normalize it
|
||||
$sAppRootUrl = trim($this->Get('app_root_url'));
|
||||
if (strlen($sAppRootUrl) == 0)
|
||||
{
|
||||
$sAppRootUrl = utils::GetDefaultUrlAppRoot();
|
||||
}
|
||||
if (substr($sAppRootUrl, -1, 1) != '/')
|
||||
{
|
||||
$sAppRootUrl .= '/';
|
||||
}
|
||||
$this->Set('app_root_url', $sAppRootUrl);
|
||||
}
|
||||
|
||||
protected function CheckFile($sPurpose, $sFileName)
|
||||
@@ -518,6 +620,10 @@ class Config
|
||||
{
|
||||
throw new ConfigException("Could not find $sPurpose file", array('file' => $sFileName));
|
||||
}
|
||||
if (!is_readable($sFileName))
|
||||
{
|
||||
throw new ConfigException("Could not read $sPurpose file (the file exists but cannot be read). Do you have the rights to access this file?", array('file' => $sFileName));
|
||||
}
|
||||
}
|
||||
|
||||
protected function Load($sConfigFile)
|
||||
@@ -618,7 +724,6 @@ class Config
|
||||
$this->m_iStandardReloadInterval = isset($MySettings['standard_reload_interval']) ? trim($MySettings['standard_reload_interval']) : DEFAULT_STANDARD_RELOAD_INTERVAL;
|
||||
$this->m_iFastReloadInterval = isset($MySettings['fast_reload_interval']) ? trim($MySettings['fast_reload_interval']) : DEFAULT_FAST_RELOAD_INTERVAL;
|
||||
$this->m_bSecureConnectionRequired = isset($MySettings['secure_connection_required']) ? (bool) trim($MySettings['secure_connection_required']) : DEFAULT_SECURE_CONNECTION_REQUIRED;
|
||||
$this->m_bHttpsHyperlinks = isset($MySettings['https_hyperlinks']) ? (bool) trim($MySettings['https_hyperlinks']) : DEFAULT_HTTPS_HYPERLINKS;
|
||||
|
||||
$this->m_aModuleSettings = isset($MyModuleSettings) ? $MyModuleSettings : array();
|
||||
|
||||
@@ -794,11 +899,6 @@ class Config
|
||||
return $this->m_bSecureConnectionRequired;
|
||||
}
|
||||
|
||||
public function GetHttpsHyperlinks()
|
||||
{
|
||||
return $this->m_bHttpsHyperlinks;
|
||||
}
|
||||
|
||||
public function GetDefaultLanguage()
|
||||
{
|
||||
return $this->m_sDefaultLanguage;
|
||||
@@ -904,11 +1004,6 @@ class Config
|
||||
$this->m_bSecureConnectionRequired = $bSecureConnectionRequired;
|
||||
}
|
||||
|
||||
public function SetHttpsHyperlinks($bHttpsHyperlinks)
|
||||
{
|
||||
$this->m_bHttpsHyperlinks = $bHttpsHyperlinks;
|
||||
}
|
||||
|
||||
public function SetDefaultLanguage($sLanguageCode)
|
||||
{
|
||||
$this->m_sDefaultLanguage = $sLanguageCode;
|
||||
@@ -974,7 +1069,6 @@ class Config
|
||||
$aSettings['standard_reload_interval'] = $this->m_iStandardReloadInterval;
|
||||
$aSettings['fast_reload_interval'] = $this->m_iFastReloadInterval;
|
||||
$aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired;
|
||||
$aSettings['https_hyperlinks'] = $this->m_bHttpsHyperlinks;
|
||||
$aSettings['default_language'] = $this->m_sDefaultLanguage;
|
||||
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
|
||||
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
|
||||
@@ -1069,7 +1163,6 @@ class Config
|
||||
fwrite($hFile, "\t'standard_reload_interval' => {$this->m_iStandardReloadInterval},\n");
|
||||
fwrite($hFile, "\t'fast_reload_interval' => {$this->m_iFastReloadInterval},\n");
|
||||
fwrite($hFile, "\t'secure_connection_required' => ".($this->m_bSecureConnectionRequired ? 'true' : 'false').",\n");
|
||||
fwrite($hFile, "\t'https_hyperlinks' => ".($this->m_bHttpsHyperlinks ? 'true' : 'false').",\n");
|
||||
fwrite($hFile, "\t'default_language' => '{$this->m_sDefaultLanguage}',\n");
|
||||
fwrite($hFile, "\t'allowed_login_types' => '{$this->m_sAllowedLoginTypes}',\n");
|
||||
fwrite($hFile, "\t'encryption_key' => '{$this->m_sEncryptionKey}',\n");
|
||||
@@ -1094,7 +1187,7 @@ class Config
|
||||
|
||||
fwrite($hFile, "\n/**\n");
|
||||
fwrite($hFile, " *\n");
|
||||
fwrite($hFile, " * Data model modules to be loaded. Names should be specified as absolute paths\n");
|
||||
fwrite($hFile, " * Data model modules to be loaded. Names are specified as relative paths\n");
|
||||
fwrite($hFile, " *\n");
|
||||
fwrite($hFile, " */\n");
|
||||
fwrite($hFile, "\$MyModules = array(\n");
|
||||
@@ -1137,5 +1230,25 @@ class Config
|
||||
throw new ConfigException("Could not write to configuration file", array('file' => $sFileName));
|
||||
}
|
||||
}
|
||||
|
||||
protected static function ScanDictionariesDir()
|
||||
{
|
||||
$aResult = array();
|
||||
// Populate automatically the list of dictionary files
|
||||
$sDir = APPROOT.'/dictionaries';
|
||||
if ($hDir = @opendir($sDir))
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (preg_match("/^([^\.]+\.)?dictionary\.itop\.(ui|core)\.php$/i", $sFile, $aMatches)) // Dictionary files named like [<Lang>.]dictionary.[core|ui].php are loaded automatically
|
||||
{
|
||||
$aResult[] = 'dictionaries/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -62,15 +62,15 @@ abstract class DBObject
|
||||
protected $m_oMasterReplicaSet = null; // Set of SynchroReplica related to this object
|
||||
|
||||
// Use the MetaModel::NewObject to build an object (do we have to force it?)
|
||||
public function __construct($aRow = null, $sClassAlias = '', $aExtendedDataSpec = null)
|
||||
public function __construct($aRow = null, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
|
||||
{
|
||||
if (!empty($aRow))
|
||||
{
|
||||
$this->FromRow($aRow, $sClassAlias, $aExtendedDataSpec);
|
||||
$this->FromRow($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
|
||||
$this->m_bFullyLoaded = $this->IsFullyLoaded();
|
||||
return;
|
||||
}
|
||||
// Creation of brand new object
|
||||
// Creation of a brand new object
|
||||
//
|
||||
|
||||
$this->m_iKey = self::GetNextTempId(get_class($this));
|
||||
@@ -82,8 +82,8 @@ abstract class DBObject
|
||||
$this->m_aOrigValues[$sAttCode] = null;
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// This field has to be read from the DB
|
||||
$this->m_aLoadedAtt[$sAttCode] = false;
|
||||
// This field has to be read from the DB
|
||||
// Leave the flag unset (optimization)
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -194,7 +194,7 @@ abstract class DBObject
|
||||
$this->m_bFullyLoaded = true;
|
||||
}
|
||||
|
||||
protected function FromRow($aRow, $sClassAlias = '', $aExtendedDataSpec = null)
|
||||
protected function FromRow($aRow, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
|
||||
{
|
||||
if (strlen($sClassAlias) == 0)
|
||||
{
|
||||
@@ -235,11 +235,17 @@ abstract class DBObject
|
||||
// Build the object from an array of "attCode"=>"value")
|
||||
//
|
||||
$bFullyLoaded = true; // ... set to false if any attribute is not found
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
|
||||
if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad))
|
||||
{
|
||||
$aAttList = MetaModel::ListAttributeDefs(get_class($this));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttList = $aAttToLoad[$sClassAlias];
|
||||
}
|
||||
|
||||
foreach($aAttList as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Say something, whatever the type of attribute
|
||||
$this->m_aLoadedAtt[$sAttCode] = false;
|
||||
|
||||
// Skip links (could not be loaded by the mean of this query)
|
||||
if ($oAttDef->IsLinkSet()) continue;
|
||||
|
||||
@@ -366,7 +372,7 @@ abstract class DBObject
|
||||
{
|
||||
throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this));
|
||||
}
|
||||
if ($this->m_bIsInDB && !$this->m_aLoadedAtt[$sAttCode] && !$this->m_bDirty)
|
||||
if ($this->m_bIsInDB && !isset($this->m_aLoadedAtt[$sAttCode]) && !$this->m_bDirty)
|
||||
{
|
||||
// #@# non-scalar attributes.... handle that differently
|
||||
$this->Reload();
|
||||
@@ -522,44 +528,46 @@ abstract class DBObject
|
||||
return $oAtt->GetAsCSV($this->GetOriginal($sAttCode), $sSeparator, $sTextQualifier, $this);
|
||||
}
|
||||
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '')
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
if ($sObjKey <= 0) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sPage = self::ComputeUIPage($sObjClass);
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlPath();
|
||||
|
||||
// Safety net
|
||||
//
|
||||
if (empty($sLabel))
|
||||
{
|
||||
// If the object if not issued from a query but constructed programmatically
|
||||
// the label may be empty. In this case run a query to get the object's friendly name
|
||||
$oTmpObj = MetaModel::GetObject($sObjClass, $sObjKey);
|
||||
$sLabel = $oTmpObj->GetName();
|
||||
$oTmpObj = MetaModel::GetObject($sObjClass, $sObjKey, false);
|
||||
if (is_object($oTmpObj))
|
||||
{
|
||||
$sLabel = $oTmpObj->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
// May happen in case the target object is not in the list of allowed values for this attribute
|
||||
$sLabel = "<em>$sObjClass::$sObjKey</em>";
|
||||
}
|
||||
//$sLabel = MetaModel::GetName($sObjClass)." #$sObjKey";
|
||||
}
|
||||
$sHint = MetaModel::GetName($sObjClass)."::$sObjKey";
|
||||
return "<a href=\"{$sAbsoluteUrl}{$sPage}?operation=details&class=$sObjClass&id=$sObjKey&".$oAppContext->GetForLink()."\" title=\"$sHint\">$sLabel</a>";
|
||||
$sUrl = ApplicationContext::MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass, $bWithNavigationContext);
|
||||
if (strlen($sUrl) > 0)
|
||||
{
|
||||
return "<a href=\"$sUrl\" title=\"$sHint\">$sLabel</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetHyperlink()
|
||||
public function GetHyperlink($sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
if ($this->IsNew()) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sPage = $this->GetUIPage();
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlPath();
|
||||
$sObjClass = get_class($this);
|
||||
$sObjKey = $this->GetKey();
|
||||
|
||||
$sLabel = $this->GetName();
|
||||
$sHint = MetaModel::GetName($sObjClass)."::$sObjKey";
|
||||
return "<a href=\"{$sAbsoluteUrl}{$sPage}?operation=details&class=$sObjClass&id=$sObjKey&".$oAppContext->GetForLink()."\" title=\"$sHint\">$sLabel</a>";
|
||||
return self::MakeHyperLink(get_class($this), $this->GetKey(), $this->GetName(), $sUrlMakerClass, $bWithNavigationContext);
|
||||
}
|
||||
|
||||
public static function ComputeUIPage($sClass)
|
||||
public static function ComputeStandardUIPage($sClass)
|
||||
{
|
||||
static $aUIPagesCache = array(); // Cache to store the php page used to display each class of object
|
||||
if (!isset($aUIPagesCache[$sClass]))
|
||||
@@ -614,25 +622,25 @@ abstract class DBObject
|
||||
return MetaModel::GetClassIcon(get_class($this), $bImgTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of an object in a safe manner for displaying inside a web page
|
||||
* @return string
|
||||
*/
|
||||
public function GetName()
|
||||
{
|
||||
$aNameSpec = MetaModel::GetNameSpec(get_class($this));
|
||||
$sFormat = $aNameSpec[0];
|
||||
$aAttributes = $aNameSpec[1];
|
||||
return htmlentities($this->GetRawName(), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
$aValues = array();
|
||||
foreach ($aAttributes as $sAttCode)
|
||||
{
|
||||
if (empty($sAttCode))
|
||||
{
|
||||
$aValues[] = $this->m_iKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues[] = $this->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
return vsprintf($sFormat, $aValues);
|
||||
/**
|
||||
* Gets the raw name of an object, this is not safe for displaying inside a web page
|
||||
* since the " < > characters are not escaped and the name may contain some XSS script
|
||||
* instructions.
|
||||
* Use this function only for internal computations or for an output to a non-HTML destination
|
||||
* @return string
|
||||
*/
|
||||
public function GetRawName()
|
||||
{
|
||||
return $this->Get('friendlyname');
|
||||
}
|
||||
|
||||
public function GetState()
|
||||
@@ -678,22 +686,48 @@ abstract class DBObject
|
||||
/**
|
||||
* Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
|
||||
* for the given attribute in the current state of the object
|
||||
* @param string $sAttCode The code of the attribute
|
||||
* @param $sAttCode string $sAttCode The code of the attribute
|
||||
* @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
|
||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array())
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = 0; // By default (if no life cycle) no flag at all
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
if ($sTargetState != '')
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $sTargetState, $sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
}
|
||||
}
|
||||
$aReasons = array();
|
||||
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
return $iFlags | $iSynchroFlags; // Combine both sets of flags
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
|
||||
* for the given attribute for the current state of the object considered as an INITIAL state
|
||||
* @param string $sAttCode The code of the attribute
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = array())
|
||||
{
|
||||
$iFlags = 0;
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
$iFlags = MetaModel::GetInitialStateAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
}
|
||||
return $iFlags; // No need to care about the synchro flags since we'll be creating a new object anyway
|
||||
}
|
||||
|
||||
// check if the given (or current) value is suitable for the attribute
|
||||
// return true if successfull
|
||||
// return the error desciption otherwise
|
||||
@@ -735,6 +769,14 @@ abstract class DBObject
|
||||
return "Target object not found ($sTargetClass::$toCheck)";
|
||||
}
|
||||
}
|
||||
if ($oAtt->IsHierarchicalKey())
|
||||
{
|
||||
// This check cannot be deactivated since otherwise the user may break things by a CSV import of a bulk modify
|
||||
if ($toCheck == $this->GetKey())
|
||||
{
|
||||
return "An object can not be its own parent in a hierarchy (".$oAtt->Getlabel()." = $toCheck)";
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($oAtt->IsScalar())
|
||||
{
|
||||
@@ -1083,6 +1125,8 @@ abstract class DBObject
|
||||
$aValuesToWrite[] = CMDBSource::Quote($this->m_iKey);
|
||||
}
|
||||
|
||||
$aHierarchicalKeys = array();
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
@@ -1093,6 +1137,10 @@ abstract class DBObject
|
||||
$aFieldsToWrite[] = "`$sColumn`";
|
||||
$aValuesToWrite[] = CMDBSource::Quote($sValue);
|
||||
}
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
$aHierarchicalKeys[$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aValuesToWrite) == 0) return false;
|
||||
@@ -1115,6 +1163,17 @@ abstract class DBObject
|
||||
}
|
||||
else
|
||||
{
|
||||
if (count($aHierarchicalKeys) > 0)
|
||||
{
|
||||
foreach($aHierarchicalKeys as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aValues = MetaModel::HKInsertChildUnder($this->m_aCurrValues[$sAttCode], $oAttDef, $sTable);
|
||||
$aFieldsToWrite[] = '`'.$oAttDef->GetSQLRight().'`';
|
||||
$aValuesToWrite[] = $aValues[$oAttDef->GetSQLRight()];
|
||||
$aFieldsToWrite[] = '`'.$oAttDef->GetSQLLeft().'`';
|
||||
$aValuesToWrite[] = $aValues[$oAttDef->GetSQLLeft()];
|
||||
}
|
||||
}
|
||||
$sInsertSQL = "INSERT INTO `$sTable` (".join(",", $aFieldsToWrite).") VALUES (".join(", ", $aValuesToWrite).")";
|
||||
$iNewKey = CMDBSource::InsertInto($sInsertSQL);
|
||||
}
|
||||
@@ -1194,13 +1253,11 @@ abstract class DBObject
|
||||
|
||||
// Activate any existing trigger
|
||||
$sClass = get_class($this);
|
||||
$oSet = new DBObjectSet(new DBObjectSearch('TriggerOnObjectCreate'));
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectCreate AS t WHERE t.target_class IN ('$sClassList')"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
if (MetaModel::IsParentClass($oTrigger->Get('target_class'), $sClass))
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
|
||||
return $this->m_iKey;
|
||||
@@ -1266,22 +1323,68 @@ abstract class DBObject
|
||||
}
|
||||
|
||||
$bHasANewExternalKeyValue = false;
|
||||
$aHierarchicalKeys = array();
|
||||
foreach($aChanges as $sAttCode => $valuecurr)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalKey()) $bHasANewExternalKeyValue = true;
|
||||
if (!$oAttDef->IsDirectField()) unset($aChanges[$sAttCode]);
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
$aHierarchicalKeys[$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
// Update scalar attributes
|
||||
if (count($aChanges) != 0)
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
$oFilter = new DBObjectSearch(get_class($this));
|
||||
$oFilter->AddCondition('id', $this->m_iKey, '=');
|
||||
|
||||
$sSQL = MetaModel::MakeUpdateQuery($oFilter, $aChanges);
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
// Update the left & right indexes for each hierarchical key
|
||||
foreach($aHierarchicalKeys as $sAttCode => $oAttDef)
|
||||
{
|
||||
$sTable = $sTable = MetaModel::DBGetTable(get_class($this), $sAttCode);
|
||||
$sSQL = "SELECT `".$oAttDef->GetSQLRight()."` AS `right`, `".$oAttDef->GetSQLLeft()."` AS `left` FROM `$sTable` WHERE id=".$this->GetKey();
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$iMyLeft = $aRes[0]['left'];
|
||||
$iMyRight = $aRes[0]['right'];
|
||||
$iDelta =$iMyRight - $iMyLeft + 1;
|
||||
MetaModel::HKTemporaryCutBranch($iMyLeft, $iMyRight, $oAttDef, $sTable);
|
||||
|
||||
if ($aChanges[$sAttCode] == 0)
|
||||
{
|
||||
// No new parent, insert completely at the right of the tree
|
||||
$sSQL = "SELECT max(`".$oAttDef->GetSQLRight()."`) AS max FROM `$sTable`";
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
if (count($aRes) == 0)
|
||||
{
|
||||
$iNewLeft = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iNewLeft = $aRes[0]['max']+1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert at the right of the specified parent
|
||||
$sSQL = "SELECT `".$oAttDef->GetSQLRight()."` FROM `$sTable` WHERE id=".((int)$aChanges[$sAttCode]);
|
||||
$iNewLeft = CMDBSource::QueryToScalar($sSQL);
|
||||
}
|
||||
|
||||
MetaModel::HKReplugBranch($iNewLeft, $iNewLeft + $iDelta - 1, $oAttDef, $sTable);
|
||||
|
||||
$aHKChanges = array();
|
||||
$aHKChanges[$sAttCode] = $aChanges[$sAttCode];
|
||||
$aHKChanges[$oAttDef->GetSQLLeft()] = $iNewLeft;
|
||||
$aHKChanges[$oAttDef->GetSQLRight()] = $iNewLeft + $iDelta - 1;
|
||||
$aChanges[$sAttCode] = $aHKChanges; // the 3 values will be stored by MakeUpdateQuery below
|
||||
}
|
||||
|
||||
// Update scalar attributes
|
||||
if (count($aChanges) != 0)
|
||||
{
|
||||
$oFilter = new DBObjectSearch(get_class($this));
|
||||
$oFilter->AddCondition('id', $this->m_iKey, '=');
|
||||
|
||||
$sSQL = MetaModel::MakeUpdateQuery($oFilter, $aChanges);
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
}
|
||||
@@ -1337,6 +1440,34 @@ abstract class DBObject
|
||||
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
// Update the left & right indexes for each hierarchical key
|
||||
$sTable = $sTable = MetaModel::DBGetTable(get_class($this), $sAttCode);
|
||||
$sSQL = "SELECT `".$oAttDef->GetSQLRight()."` AS `right`, `".$oAttDef->GetSQLLeft()."` AS `left` FROM `$sTable` WHERE id=".CMDBSource::Quote($this->m_iKey);
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$iMyLeft = $aRes[0]['left'];
|
||||
$iMyRight = $aRes[0]['right'];
|
||||
$iDelta =$iMyRight - $iMyLeft + 1;
|
||||
MetaModel::HKTemporaryCutBranch($iMyLeft, $iMyRight, $oAttDef, $sTable);
|
||||
|
||||
// No new parent for now, insert completely at the right of the tree
|
||||
$sSQL = "SELECT max(`".$oAttDef->GetSQLRight()."`) AS max FROM `$sTable`";
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
if (count($aRes) == 0)
|
||||
{
|
||||
$iNewLeft = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iNewLeft = $aRes[0]['max']+1;
|
||||
}
|
||||
MetaModel::HKReplugBranch($iNewLeft, $iNewLeft + $iDelta - 1, $oAttDef, $sTable);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL) as $sParentClass)
|
||||
{
|
||||
$this->DBDeleteSingleTable($sParentClass);
|
||||
@@ -1372,7 +1503,14 @@ abstract class DBObject
|
||||
foreach ($aToDelete as $iId => $aData)
|
||||
{
|
||||
$oToDelete = $aData['to_delete'];
|
||||
$oToDelete->DBDeleteSingleObject();
|
||||
// The deletion based on a deletion plan should not be done for each oject if the deletion plan is common (Trac #457)
|
||||
// because for each object we would try to update all the preceding ones... that are already deleted
|
||||
// A better approach would be to change the API to apply the DBDelete on the deletion plan itself... just once
|
||||
// As a temporary fix: delete only the objects that are still to be deleted...
|
||||
if ($oToDelete->m_bIsInDB)
|
||||
{
|
||||
$oToDelete->DBDeleteSingleObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1383,7 +1521,7 @@ abstract class DBObject
|
||||
$oToUpdate = $aData['to_reset'];
|
||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
|
||||
{
|
||||
$oToUpdate->Set($sRemoteExtKey, 0);
|
||||
$oToUpdate->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
|
||||
$oToUpdate->DBUpdate();
|
||||
}
|
||||
}
|
||||
@@ -1474,10 +1612,8 @@ abstract class DBObject
|
||||
$aScalarArgs[$sArgName] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->id'] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->object()'] = $this;
|
||||
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink();
|
||||
// #@# Prototype for a user portal - to be dehardcoded later
|
||||
$sToPortal = utils::GetAbsoluteUrlPath().'../portal/index.php?operation=details&id='.$this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->hyperlink(portal)'] = '<a href="'.$sToPortal.'">'.$this->GetName().'</a>';
|
||||
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink('iTopStandardURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->hyperlink(portal)'] = $this->GetHyperlink('PortalURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->name()'] = $this->GetName();
|
||||
|
||||
$sClass = get_class($this);
|
||||
@@ -1491,6 +1627,13 @@ abstract class DBObject
|
||||
$aScalarArgs[$sArgName.'->html('.$sAttCode.')'] = $sAsHtml;
|
||||
$aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = strip_tags($sAsHtml);
|
||||
}
|
||||
// Do something for case logs... quick N' dirty...
|
||||
if ($aScalarArgs[$sArgName.'->'.$sAttCode] instanceof ormCaseLog)
|
||||
{
|
||||
$oCaseLog = $aScalarArgs[$sArgName.'->'.$sAttCode];
|
||||
$aScalarArgs[$sArgName.'->'.$sAttCode] = $oCaseLog->GetText();
|
||||
$aScalarArgs[$sArgName.'->head('.$sAttCode.')'] = $oCaseLog->GetLatestEntry();
|
||||
}
|
||||
}
|
||||
$this->m_aAsArgs = $aScalarArgs;
|
||||
$oKPI->ComputeStats('ToArgs', get_class($this));
|
||||
@@ -1639,7 +1782,16 @@ abstract class DBObject
|
||||
if ($oAttDef->IsNullAllowed())
|
||||
{
|
||||
// Optional external key, list to reset
|
||||
$oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef);
|
||||
if (($iDeletePropagationOption == DEL_MOVEUP) && ($oAttDef->IsHierarchicalKey()))
|
||||
{
|
||||
// Move the child up one level i.e. set the same parent as the current object
|
||||
$iParentId = $this->Get($oAttDef->GetCode());
|
||||
$oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef, $iParentId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -22,6 +22,16 @@
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
define('TREE_OPERATOR_EQUALS', 0);
|
||||
define('TREE_OPERATOR_BELOW', 1);
|
||||
define('TREE_OPERATOR_BELOW_STRICT', 2);
|
||||
define('TREE_OPERATOR_NOT_BELOW', 3);
|
||||
define('TREE_OPERATOR_NOT_BELOW_STRICT', 4);
|
||||
define('TREE_OPERATOR_ABOVE', 5);
|
||||
define('TREE_OPERATOR_ABOVE_STRICT', 6);
|
||||
define('TREE_OPERATOR_NOT_ABOVE', 7);
|
||||
define('TREE_OPERATOR_NOT_ABOVE_STRICT', 8);
|
||||
|
||||
class DBObjectSearch
|
||||
{
|
||||
@@ -33,6 +43,7 @@ class DBObjectSearch
|
||||
private $m_aPointingTo;
|
||||
private $m_aReferencedBy;
|
||||
private $m_aRelatedTo;
|
||||
private $m_bDataFiltered;
|
||||
|
||||
// By default, some information may be hidden to the current user
|
||||
// But it may happen that we need to disable that feature
|
||||
@@ -53,10 +64,14 @@ class DBObjectSearch
|
||||
$this->m_aPointingTo = array();
|
||||
$this->m_aReferencedBy = array();
|
||||
$this->m_aRelatedTo = array();
|
||||
$this->m_bDataFiltered = false;
|
||||
$this->m_aParentConditions = array();
|
||||
}
|
||||
|
||||
public function AllowAllData() {$this->m_bAllowAllData = true;}
|
||||
public function IsAllDataAllowed() {return $this->m_bAllowAllData;}
|
||||
public function IsDataFiltered() {return $this->m_bDataFiltered; }
|
||||
public function SetDataFiltered() {$this->m_bDataFiltered = true;}
|
||||
|
||||
public function GetClassName($sAlias) {return $this->m_aClasses[$sAlias];}
|
||||
public function GetJoinedClasses() {return $this->m_aClasses;}
|
||||
@@ -107,6 +122,7 @@ class DBObjectSearch
|
||||
if (count($this->m_aPointingTo) > 0) return false;
|
||||
if (count($this->m_aReferencedBy) > 0) return false;
|
||||
if (count($this->m_aRelatedTo) > 0) return false;
|
||||
if (count($this->m_aParentConditions) > 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -115,13 +131,55 @@ class DBObjectSearch
|
||||
// To replace __Describe
|
||||
}
|
||||
|
||||
public function DescribeConditionPointTo($sExtKeyAttCode)
|
||||
public function DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo)
|
||||
{
|
||||
if (!isset($this->m_aPointingTo[$sExtKeyAttCode])) return "";
|
||||
$oFilter = $this->m_aPointingTo[$sExtKeyAttCode];
|
||||
if ($oFilter->IsAny()) return "";
|
||||
$oAtt = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
|
||||
return $oAtt->GetLabel()." having ({$oFilter->DescribeConditions()})";
|
||||
if (empty($aPointingTo)) return "";
|
||||
foreach($aPointingTo as $iOperatorCode => $oFilter)
|
||||
{
|
||||
if ($oFilter->IsAny()) break;
|
||||
$oAtt = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
|
||||
$sOperator = '';
|
||||
switch($iOperatorCode)
|
||||
{
|
||||
case TREE_OPERATOR_EQUALS:
|
||||
$sOperator = 'having';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW:
|
||||
$sOperator = 'below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW_STRICT:
|
||||
$sOperator = 'strictly below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW:
|
||||
$sOperator = 'not below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW_STRICT:
|
||||
$sOperator = 'strictly not below';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE:
|
||||
$sOperator = 'above';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE_STRICT:
|
||||
$sOperator = 'strictly above';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE:
|
||||
$sOperator = 'not above';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE_STRICT:
|
||||
$sOperator = 'strictly not above';
|
||||
break;
|
||||
}
|
||||
$aDescription[] = $oAtt->GetLabel()."$sOperator ({$oFilter->DescribeConditions()})";
|
||||
}
|
||||
return implode(' and ', $aDescription);
|
||||
}
|
||||
|
||||
public function DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode)
|
||||
@@ -141,6 +199,7 @@ class DBObjectSearch
|
||||
return "related ($sRelCode... peut mieux faire !, $iMaxDepth dig depth) to a {$oFilter->GetClass()} ({$oFilter->DescribeConditions()})";
|
||||
}
|
||||
|
||||
|
||||
public function DescribeConditions()
|
||||
{
|
||||
$aConditions = array();
|
||||
@@ -159,10 +218,9 @@ class DBObjectSearch
|
||||
$aConditions[] = $this->RenderCondition();
|
||||
|
||||
$aCondPoint = array();
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter)
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode => $aPointingTo)
|
||||
{
|
||||
if ($oFilter->IsAny()) continue;
|
||||
$aCondPoint[] = $this->DescribeConditionPointTo($sExtKeyAttCode);
|
||||
$aCondPoint[] = $this->DescribeConditionPointTo($sExtKeyAttCode, $aPointingTo);
|
||||
}
|
||||
if (count($aCondPoint) > 0)
|
||||
{
|
||||
@@ -187,6 +245,11 @@ class DBObjectSearch
|
||||
$aConditions[] = implode(" and ", $aCondReferred);
|
||||
}
|
||||
|
||||
foreach ($this->m_aParentConditions as $aRelInfo)
|
||||
{
|
||||
$aCondReferred[] = $this->DescribeConditionParent($aRelInfo);
|
||||
}
|
||||
|
||||
return implode(" and ", $aConditions);
|
||||
}
|
||||
|
||||
@@ -209,18 +272,75 @@ class DBObjectSearch
|
||||
|
||||
protected function TransferConditionExpression($oFilter, $aTranslation)
|
||||
{
|
||||
// Prevent collisions in the parameter names by renaming them if needed
|
||||
foreach($this->m_aParams as $sParam => $value)
|
||||
{
|
||||
if (array_key_exists($sParam, $oFilter->m_aParams) && ($value != $oFilter->m_aParams[$sParam]))
|
||||
{
|
||||
// Generate a new and unique name for the collinding parameter
|
||||
$index = 1;
|
||||
while(array_key_exists($sParam.$index, $oFilter->m_aParams))
|
||||
{
|
||||
$index++;
|
||||
}
|
||||
$secondValue = $oFilter->m_aParams[$sParam];
|
||||
$oFilter->RenameParam($sParam, $sParam.$index);
|
||||
unset($oFilter->m_aParams[$sParam]);
|
||||
$oFilter->m_aParams[$sParam.$index] = $secondValue;
|
||||
}
|
||||
}
|
||||
//echo "<p>TransferConditionExpression:<br/>";
|
||||
//echo "Adding Conditions:<br/><pre>oFilter:\n".print_r($oFilter, true)."\naTranslation:\n".print_r($aTranslation, true)."</pre>\n";
|
||||
//echo "</p>";
|
||||
$oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false, false /* leave unresolved fields */);
|
||||
//echo "Adding Conditions (translated):<br/><pre>".print_r($oTranslated, true)."</pre>\n";
|
||||
$this->AddConditionExpression($oTranslated);
|
||||
// #@# what about collisions in parameter names ???
|
||||
$this->m_aParams = array_merge($this->m_aParams, $oFilter->m_aParams);
|
||||
}
|
||||
|
||||
protected function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oSearchCondition->RenameParam($sOldName, $sNewName);
|
||||
foreach($this->m_aRelatedTo as $aRelatedTo)
|
||||
{
|
||||
$aRelatedTo['flt']->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
{
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oExtFilter)
|
||||
{
|
||||
$oExtFilter->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($this->m_aReferencedBy as $sForeignClass => $aReferences)
|
||||
{
|
||||
foreach($aReferences as $sForeignExtKeyAttCode => $oForeignFilter)
|
||||
{
|
||||
$oForeignFilter->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->m_aParentConditions as $aParent)
|
||||
{
|
||||
$aParent['expression']->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
public function ResetCondition()
|
||||
{
|
||||
$this->m_oSearchCondition = new TrueExpression();
|
||||
$this->m_aParentConditions = array();
|
||||
// ? is that usefull/enough, do I need to rebuild the list after the subqueries ?
|
||||
}
|
||||
|
||||
public function MergeConditionExpression($oExpression)
|
||||
{
|
||||
$this->m_oSearchCondition = $this->m_oSearchCondition->LogOr($oExpression);
|
||||
}
|
||||
|
||||
public function AddConditionExpression($oExpression)
|
||||
{
|
||||
$this->m_oSearchCondition = $this->m_oSearchCondition->LogAnd($oExpression);
|
||||
@@ -320,30 +440,113 @@ class DBObjectSearch
|
||||
$this->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a condition on external keys or link sets
|
||||
* @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
|
||||
* Example: infra_list->ci_id->location_id->country
|
||||
* @param value The value to match
|
||||
* @return void
|
||||
*/
|
||||
public function AddConditionAdvanced($sAttSpec, $value)
|
||||
{
|
||||
$sClass = $this->GetClass();
|
||||
|
||||
$iPos = strpos($sAttSpec, '->');
|
||||
if ($iPos !== false)
|
||||
{
|
||||
$sAttCode = substr($sAttSpec, 0, $iPos);
|
||||
$sSubSpec = substr($sAttSpec, $iPos + 2);
|
||||
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
throw new Exception("Invalid attribute code '$sClass/$sAttCode' in condition specification '$sAttSpec'");
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
|
||||
$oNewFilter = new DBObjectSearch($sTargetClass);
|
||||
$oNewFilter->AddConditionAdvanced($sSubSpec, $value);
|
||||
|
||||
$this->AddCondition_ReferencedBy($oNewFilter, $sExtKeyToMe);
|
||||
}
|
||||
elseif ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
|
||||
|
||||
$oNewFilter = new DBObjectSearch($sTargetClass);
|
||||
$oNewFilter->AddConditionAdvanced($sSubSpec, $value);
|
||||
|
||||
$this->AddCondition_PointingTo($oNewFilter, $sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Attribute specification '$sAttSpec', '$sAttCode' should be either a link set or an external key");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// $sAttSpec is an attribute code
|
||||
//
|
||||
$this->AddCondition($sAttSpec, $value);
|
||||
}
|
||||
}
|
||||
|
||||
public function AddCondition_FullText($sFullText)
|
||||
{
|
||||
$this->m_aFullText[] = $sFullText;
|
||||
}
|
||||
|
||||
protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation)
|
||||
public function AddCondition_Parent($sAttCode, $iOperatorCode, $oExpression)
|
||||
{
|
||||
$sOrigAlias = $this->GetClassAlias();
|
||||
if (array_key_exists($sOrigAlias, $aClassAliases))
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sAttCode);
|
||||
if (!$oAttDef instanceof AttributeHierarchicalKey)
|
||||
{
|
||||
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
|
||||
$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aSelectedClasses[$sOrigAlias]);
|
||||
|
||||
// Translate the condition expression with the new alias
|
||||
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
|
||||
throw new Exception("AddCondition_Parent can only be used on hierarchical keys. '$sAttCode' is not a hierarchical key.");
|
||||
}
|
||||
|
||||
// add the alias into the filter aliases list
|
||||
$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
|
||||
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter)
|
||||
$this->m_aParentConditions[] = array(
|
||||
'attCode' => $sAttCode,
|
||||
'operator' => $iOperatorCode,
|
||||
'expression' => $oExpression,
|
||||
);
|
||||
}
|
||||
|
||||
protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation, $bTranslateMainAlias = true)
|
||||
{
|
||||
if ($bTranslateMainAlias)
|
||||
{
|
||||
$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
|
||||
$sOrigAlias = $this->GetClassAlias();
|
||||
if (array_key_exists($sOrigAlias, $aClassAliases))
|
||||
{
|
||||
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
|
||||
//echo "<p>Generating a new alias for $sOrigAlias (already used). It is now: $sNewAlias</p>\n";
|
||||
$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aSelectedClasses[$sOrigAlias]);
|
||||
|
||||
$this->m_aClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aClasses[$sOrigAlias]);
|
||||
|
||||
// Translate the condition expression with the new alias
|
||||
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
|
||||
}
|
||||
|
||||
//echo "<p>Adding the alias ".$this->GetClass()." as ".$this->GetClassAlias()."</p>\n";
|
||||
// add the alias into the filter aliases list
|
||||
$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
|
||||
}
|
||||
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
{
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oFilter)
|
||||
{
|
||||
$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
|
||||
@@ -355,16 +558,17 @@ class DBObjectSearch
|
||||
}
|
||||
}
|
||||
|
||||
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode)
|
||||
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
|
||||
{
|
||||
$aAliasTranslation = array();
|
||||
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation);
|
||||
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode);
|
||||
$this->TransferConditionExpression($oFilter, $aAliasTranslation);
|
||||
return $res;
|
||||
}
|
||||
|
||||
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation)
|
||||
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode)
|
||||
{
|
||||
//echo "<p style=\"color:green\">Calling: AddCondition_PointingTo_InNameSpace([<pre>".print_r($aClassAliases, true)."</pre></br>], [<pre>".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored");
|
||||
@@ -374,20 +578,41 @@ class DBObjectSearch
|
||||
{
|
||||
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
|
||||
{
|
||||
throw new CoreException("The specified tree operator $isOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
|
||||
}
|
||||
|
||||
$bSamePointingTo = false;
|
||||
if (array_key_exists($sExtKeyAttCode, $this->m_aPointingTo))
|
||||
{
|
||||
$this->m_aPointingTo[$sExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation);
|
||||
if (array_key_exists($iOperatorCode, $this->m_aPointingTo[$sExtKeyAttCode]))
|
||||
{
|
||||
if (array_key_exists($oFilter->GetClassAlias(), $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]))
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetFirstJoinedClassAlias()."]:<pre>\n".print_r($this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode], true)."</pre>;</p>";
|
||||
$bSamePointingTo = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]Calling: AddToNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
|
||||
if ($bSamePointingTo)
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Merging filters for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
|
||||
// Same ext key, alias and same operator, merge the filters together
|
||||
// $sAlias = $oFilter->GetClassAlias();
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]before: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation, true /* Don't translate the main alias */);
|
||||
//echo "<p style=\"color:blue\">[".__LINE__."]after: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
// $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$sAlias]->MergeWith($oFilter, $aClassAliases, $aAliasTranslation);
|
||||
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
|
||||
}
|
||||
else
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Adding a new PointingTo filter for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
|
||||
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
|
||||
|
||||
// #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!!
|
||||
// $oNewFilter = clone $oFilter;
|
||||
// $oNewFilter->ResetCondition();
|
||||
|
||||
$this->m_aPointingTo[$sExtKeyAttCode] = $oFilter;
|
||||
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,6 +656,7 @@ class DBObjectSearch
|
||||
public function AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget)
|
||||
{
|
||||
$oLinkFilterFinal = clone $oLinkFilter;
|
||||
// todo : new function prototype
|
||||
$oLinkFilterFinal->AddCondition_PointingTo($sExtKeyAttCodeToMe);
|
||||
|
||||
$this->AddCondition_ReferencedBy($oLinkFilterFinal, $sExtKeyAttCodeToMe);
|
||||
@@ -463,9 +689,15 @@ class DBObjectSearch
|
||||
$this->m_aFullText = array_merge($this->m_aFullText, $oFilter->m_aFullText);
|
||||
$this->m_aRelatedTo = array_merge($this->m_aRelatedTo, $oFilter->m_aRelatedTo);
|
||||
|
||||
foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$oExtFilter)
|
||||
foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
{
|
||||
$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation);
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oExtFilter)
|
||||
{
|
||||
$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation, $iOperatorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($oFilter->m_aReferencedBy as $sForeignClass => $aReferences)
|
||||
{
|
||||
@@ -484,7 +716,7 @@ class DBObjectSearch
|
||||
{
|
||||
return $this->m_aPointingTo;
|
||||
}
|
||||
if (!array_key_exists($sKeyAttCode, $this->m_aPointingTo)) return null;
|
||||
if (!array_key_exists($sKeyAttCode, $this->m_aPointingTo)) return array();
|
||||
return $this->m_aPointingTo[$sKeyAttCode];
|
||||
}
|
||||
public function GetCriteria_ReferencedBy($sRemoteClass = "", $sForeignExtKeyAttCode = "")
|
||||
@@ -650,10 +882,55 @@ class DBObjectSearch
|
||||
protected function ToOQL_Joins()
|
||||
{
|
||||
$sRes = '';
|
||||
foreach($this->m_aPointingTo as $sExtKey=>$oFilter)
|
||||
foreach($this->m_aPointingTo as $sExtKey => $aPointingTo)
|
||||
{
|
||||
$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.' = '.$oFilter->GetClassAlias().'.id';
|
||||
$sRes .= $oFilter->ToOQL_Joins();
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oFilter)
|
||||
{
|
||||
switch($iOperatorCode)
|
||||
{
|
||||
case TREE_OPERATOR_EQUALS:
|
||||
$sOperator = ' = ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW:
|
||||
$sOperator = ' BELOW ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW_STRICT:
|
||||
$sOperator = ' BELOW STRICT ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW:
|
||||
$sOperator = ' NOT BELOW ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW_STRICT:
|
||||
$sOperator = ' NOT BELOW STRICT ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE:
|
||||
$sOperator = ' ABOVE ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE_STRICT:
|
||||
$sOperator = ' ABOVE STRICT ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE:
|
||||
$sOperator = ' NOT ABOVE ';
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE_STRICT:
|
||||
$sOperator = ' NOT ABOVE STRICT ';
|
||||
break;
|
||||
|
||||
}
|
||||
$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetClassAlias().'.id';
|
||||
$sRes .= $oFilter->ToOQL_Joins();
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
|
||||
{
|
||||
@@ -866,7 +1143,38 @@ class DBObjectSearch
|
||||
}
|
||||
else
|
||||
{
|
||||
$aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode);
|
||||
$sOperator = $oJoinSpec->GetOperator();
|
||||
switch($sOperator)
|
||||
{
|
||||
case '=':
|
||||
$iOperatorCode = TREE_OPERATOR_EQUALS;
|
||||
break;
|
||||
case 'BELOW':
|
||||
$iOperatorCode = TREE_OPERATOR_BELOW;
|
||||
break;
|
||||
case 'BELOW_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
|
||||
break;
|
||||
case 'NOT_BELOW':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
|
||||
break;
|
||||
case 'NOT_BELOW_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
|
||||
break;
|
||||
case 'ABOVE':
|
||||
$iOperatorCode = TREE_OPERATOR_ABOVE;
|
||||
break;
|
||||
case 'ABOVE_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
|
||||
break;
|
||||
case 'NOT_ABOVE':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
|
||||
break;
|
||||
case 'NOT_ABOVE_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
|
||||
break;
|
||||
}
|
||||
$aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode, $iOperatorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
class DBObjectSet
|
||||
{
|
||||
private $m_oFilter;
|
||||
private $m_aAddedIds; // Ids of objects added (discrete lists)
|
||||
private $m_aOrderBy;
|
||||
public $m_bLoaded;
|
||||
private $m_aData;
|
||||
@@ -41,12 +42,15 @@ class DBObjectSet
|
||||
public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0)
|
||||
{
|
||||
$this->m_oFilter = $oFilter;
|
||||
$this->m_aAddedIds = array();
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
$this->m_aArgs = $aArgs;
|
||||
$this->m_aAttToLoad = null;
|
||||
$this->m_aExtendedDataSpec = $aExtendedDataSpec;
|
||||
$this->m_iLimitCount = $iLimitCount;
|
||||
$this->m_iLimitStart = $iLimitStart;
|
||||
|
||||
$this->m_iCount = null; // null if unknown yet
|
||||
$this->m_bLoaded = false; // true when the filter has been used OR the set is built step by step (AddObject...)
|
||||
$this->m_aData = array(); // array of (row => array of (classalias) => object/null)
|
||||
$this->m_aId2Row = array(); // array of (pkey => index in m_aData)
|
||||
@@ -77,6 +81,46 @@ class DBObjectSet
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function OptimizeColumnLoad($aAttToLoad)
|
||||
{
|
||||
if (is_null($aAttToLoad))
|
||||
{
|
||||
$this->m_aAttToLoad = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Complete the attribute list with the attribute codes
|
||||
$aAttToLoadWithAttDef = array();
|
||||
foreach($aAttToLoad as $sClassAlias => $aAttList)
|
||||
{
|
||||
$aSelectedClasses = $this->m_oFilter->GetSelectedClasses();
|
||||
$sClass = $aSelectedClasses[$sClassAlias];
|
||||
foreach($aAttList as $sAttToLoad)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
// Add the external key friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
|
||||
}
|
||||
}
|
||||
// Add the friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
|
||||
|
||||
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
|
||||
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttList))
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_aAttToLoad = $aAttToLoadWithAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
static public function FromObject($oObject)
|
||||
{
|
||||
$oRetSet = self::FromScratch(get_class($oObject));
|
||||
@@ -86,7 +130,8 @@ class DBObjectSet
|
||||
|
||||
static public function FromScratch($sClass)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oFilter->AddConditionExpression(new FalseExpression());
|
||||
$oRetSet = new self($oFilter);
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
return $oRetSet;
|
||||
@@ -96,9 +141,7 @@ class DBObjectSet
|
||||
// input = array of objects
|
||||
static public function FromArray($sClass, $aObjects)
|
||||
{
|
||||
$oFilter = new CMDBSearchFilter($sClass);
|
||||
$oRetSet = new self($oFilter);
|
||||
$oRetSet->m_bLoaded = true; // no DB load
|
||||
$oRetSet = self::FromScratch($sClass);
|
||||
$oRetSet->AddObjectArray($aObjects, $sClass);
|
||||
return $oRetSet;
|
||||
}
|
||||
@@ -226,8 +269,20 @@ class DBObjectSet
|
||||
|
||||
public function GetFilter()
|
||||
{
|
||||
// #@# This is false as soon as the set has been manipulated (AddObject...)
|
||||
return $this->m_oFilter;
|
||||
if (count($this->m_aAddedIds) == 0)
|
||||
{
|
||||
return $this->m_oFilter;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = clone $this->m_oFilter;
|
||||
|
||||
$oIdListExpr = ListExpression::FromScalars(array_keys($this->m_aAddedIds));
|
||||
$oIdExpr = new FieldExpression('id', $oFilter->GetClassAlias());
|
||||
$oIdInList = new BinaryExpression($oIdExpr, 'IN', $oIdListExpr);
|
||||
$oFilter->MergeConditionExpression($oIdInList);
|
||||
return $oFilter;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetClass()
|
||||
@@ -245,6 +300,11 @@ class DBObjectSet
|
||||
return MetaModel::GetRootClass($this->GetClass());
|
||||
}
|
||||
|
||||
public function GetArgs()
|
||||
{
|
||||
return $this->m_aArgs;
|
||||
}
|
||||
|
||||
public function SetLimit($iLimitCount, $iLimitStart = 0)
|
||||
{
|
||||
$this->m_iLimitCount = $iLimitCount;
|
||||
@@ -269,11 +329,11 @@ class DBObjectSet
|
||||
|
||||
if ($this->m_iLimitCount > 0)
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aExtendedDataSpec);
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
}
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return;
|
||||
@@ -290,11 +350,12 @@ class DBObjectSet
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObject = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aExtendedDataSpec);
|
||||
$oObject = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
}
|
||||
|
||||
$aObjects[$sClassAlias] = $oObject;
|
||||
}
|
||||
$this->AddObjectExtended($aObjects);
|
||||
$this->AddObjectExtended($aObjects, true /* internal load */);
|
||||
}
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
}
|
||||
@@ -307,13 +368,17 @@ class DBObjectSet
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
return $aRow['COUNT'];
|
||||
if (is_null($this->m_iCount))
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, null, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
$this->m_iCount = $aRow['COUNT'];
|
||||
}
|
||||
return $this->m_iCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +418,10 @@ class DBObjectSet
|
||||
|
||||
public function Rewind()
|
||||
{
|
||||
$this->Seek(0);
|
||||
if ($this->m_bLoaded)
|
||||
{
|
||||
$this->Seek(0);
|
||||
}
|
||||
}
|
||||
|
||||
public function Seek($iRow)
|
||||
@@ -378,10 +446,11 @@ class DBObjectSet
|
||||
if (!is_null($oObject))
|
||||
{
|
||||
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
|
||||
$this->m_aAddedIds[$oObject->GetKey()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function AddObjectExtended($aObjectArray)
|
||||
protected function AddObjectExtended($aObjectArray, $bInternalLoad = false)
|
||||
{
|
||||
if (!$this->m_bLoaded) $this->Load();
|
||||
|
||||
@@ -393,6 +462,10 @@ class DBObjectSet
|
||||
if (!is_null($oObject))
|
||||
{
|
||||
$this->m_aId2Row[$sClassAlias][$oObject->GetKey()] = $iNextPos;
|
||||
if (!$bInternalLoad)
|
||||
{
|
||||
$this->m_aAddedIds[$oObject->GetKey()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,11 +109,11 @@ class DeletionPlan
|
||||
{
|
||||
$this->m_iToUpdate++;
|
||||
|
||||
$oObject = $aData['to_reset'];
|
||||
$oObject = $aData['to_reset'];
|
||||
$aExtKeyLabels = array();
|
||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
|
||||
{
|
||||
$oObject->Set($sRemoteExtKey, 0);
|
||||
$oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
|
||||
$aExtKeyLabels[] = $aRemoteAttDef->GetLabel();
|
||||
}
|
||||
$this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels);
|
||||
@@ -264,7 +264,7 @@ class DeletionPlan
|
||||
}
|
||||
}
|
||||
|
||||
public function AddToUpdate($oObject, $oAttDef)
|
||||
public function AddToUpdate($oObject, $oAttDef, $value = 0)
|
||||
{
|
||||
$sClass = get_class($oObject);
|
||||
$iId = $oObject->GetKey();
|
||||
@@ -281,6 +281,7 @@ class DeletionPlan
|
||||
);
|
||||
}
|
||||
$this->m_aToUpdate[$sClass][$iId]['attributes'][$oAttDef->GetCode()] = $oAttDef;
|
||||
$this->m_aToUpdate[$sClass][$iId]['values'][$oAttDef->GetCode()] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +86,8 @@ class EMail
|
||||
set_error_handler(array($this, 'mail_error_handler'));
|
||||
$bRes = mail
|
||||
(
|
||||
$this->m_sTo,
|
||||
$this->m_sSubject,
|
||||
str_replace(array("\n", "\r"), ' ', $this->m_sTo), // Prevent header injection
|
||||
str_replace(array("\n", "\r"), ' ', $this->m_sSubject), // Prevent header injection
|
||||
$this->m_sBody,
|
||||
$sHeaders
|
||||
);
|
||||
|
||||
@@ -90,7 +90,7 @@ class Event extends DBObject implements iDisplay
|
||||
|
||||
public static function GetUIPage()
|
||||
{
|
||||
return '../pages/UI.php';
|
||||
return 'UI.php';
|
||||
}
|
||||
|
||||
function DisplayDetails(WebPage $oPage, $bEditMode = false)
|
||||
@@ -103,7 +103,7 @@ class Event extends DBObject implements iDisplay
|
||||
$this->DisplayBareProperties($oPage, $bEditMode);
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false)
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
if ($bEditMode) return; // Not editable
|
||||
|
||||
|
||||
@@ -84,6 +84,8 @@ abstract class Expression
|
||||
{
|
||||
return new BinaryExpression($this, 'OR', $oExpr);
|
||||
}
|
||||
|
||||
abstract public function RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
|
||||
class SQLExpression extends Expression
|
||||
@@ -119,6 +121,11 @@ class SQLExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
// Do nothing, since there is nothing to rename
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -205,6 +212,12 @@ class BinaryExpression extends Expression
|
||||
$aRight = $this->GetRightExpr()->ListRequiredFields();
|
||||
return array_merge($aLeft, $aRight);
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->GetLeftExpr()->RenameParam($sOldName, $sNewName);
|
||||
$this->GetRightExpr()->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -256,6 +269,12 @@ class UnaryExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
// Do nothing
|
||||
// really ? what about :param{$iParamIndex} ??
|
||||
}
|
||||
}
|
||||
|
||||
class ScalarExpression extends UnaryExpression
|
||||
@@ -429,6 +448,14 @@ class VariableExpression extends UnaryExpression
|
||||
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>$aArgs));
|
||||
}
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
if ($this->m_sName == $sOldName)
|
||||
{
|
||||
$this->m_sName = $sNewName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary, until we implement functions and expression casting!
|
||||
@@ -501,6 +528,15 @@ class ListExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$aRes = array();
|
||||
foreach ($this->m_aExpressions as $key => $oExpr)
|
||||
{
|
||||
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -569,6 +605,14 @@ class FunctionExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
foreach ($this->m_aArgs as $key => $oExpr)
|
||||
{
|
||||
$this->m_aArgs[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IntervalExpression extends Expression
|
||||
@@ -618,6 +662,11 @@ class IntervalExpression extends Expression
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oValue->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
class CharConcatExpression extends Expression
|
||||
@@ -680,6 +729,14 @@ class CharConcatExpression extends Expression
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
foreach ($this->m_aExpressions as $key => $oExpr)
|
||||
{
|
||||
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -778,6 +835,19 @@ class QueryBuilderExpressions
|
||||
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
}
|
||||
|
||||
public function RenameParam($sOldName, $sNewName)
|
||||
{
|
||||
$this->m_oConditionExpr->RenameParam($sOldName, $sNewName);
|
||||
foreach($this->m_aSelectExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
foreach($this->m_aJoinFields as $index => $oExpression)
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -310,13 +310,23 @@ abstract class MetaModel
|
||||
return self::GetName($sClass);
|
||||
}
|
||||
}
|
||||
final static public function GetClassFromLabel($sClassLabel)
|
||||
final static public function GetClassFromLabel($sClassLabel, $bCaseSensitive = true)
|
||||
{
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
if (self::GetName($sClass) == $sClassLabel)
|
||||
if ($bCaseSensitive)
|
||||
{
|
||||
return $sClass;
|
||||
if (self::GetName($sClass) == $sClassLabel)
|
||||
{
|
||||
return $sClass;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcasecmp(self::GetName($sClass), $sClassLabel) == 0)
|
||||
{
|
||||
return $sClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -699,7 +709,11 @@ abstract class MetaModel
|
||||
|
||||
final static public function GetAttributeDef($sClass, $sAttCode)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
self::_check_subclass($sClass);
|
||||
if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
{
|
||||
echo "<p>$sAttCode is NOT a valid attribute of class $sClass.</p>";
|
||||
}
|
||||
return self::$m_aAttribDefs[$sClass][$sAttCode];
|
||||
}
|
||||
|
||||
@@ -944,6 +958,36 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumerate all possible initial states, including the default one
|
||||
*/
|
||||
public static function EnumInitialStates($sClass)
|
||||
{
|
||||
if (array_key_exists($sClass, self::$m_aStates))
|
||||
{
|
||||
$aRet = array();
|
||||
// Add the states for which the flag 'is_initial_state' is set to <true>
|
||||
foreach(self::$m_aStates[$sClass] as $aStateCode => $aProps)
|
||||
{
|
||||
if (isset($aProps['initial_state_path']))
|
||||
{
|
||||
$aRet[$aStateCode] = $aProps['initial_state_path'];
|
||||
}
|
||||
}
|
||||
// Add the default initial state
|
||||
$sMainInitialState = self::GetDefaultState($sClass);
|
||||
if (!isset($aRet[$sMainInitialState]))
|
||||
{
|
||||
$aRet[$sMainInitialState] = array();
|
||||
}
|
||||
return $aRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
public static function EnumStimuli($sClass)
|
||||
{
|
||||
if (array_key_exists($sClass, self::$m_aStimuli))
|
||||
@@ -960,21 +1004,13 @@ abstract class MetaModel
|
||||
{
|
||||
$sStateAttrCode = self::GetStateAttributeCode($sClass);
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sStateAttrCode);
|
||||
// Be consistent with what is done for enums, since states are defined as enums...
|
||||
return Dict::S("Class:".$oAttDef->GetHostClass()."/Attribute:$sStateAttrCode/Value:$sStateValue");
|
||||
|
||||
// I've decided the current implementation, because I need
|
||||
// to get the description as well -GetAllowedValues does not render the description,
|
||||
// so far...
|
||||
// Could have been implemented the following way (not tested
|
||||
// $oStateAttrDef = self::GetAttributeDef($sClass, $sStateAttrCode);
|
||||
// $aAllowedValues = $oStateAttrDef->GetAllowedValues();
|
||||
// return $aAllowedValues[$sStateValue];
|
||||
return $oAttDef->GetValueLabel($sStateValue);
|
||||
}
|
||||
public static function GetStateDescription($sClass, $sStateValue)
|
||||
{
|
||||
$sStateAttrCode = self::GetStateAttributeCode($sClass);
|
||||
return Dict::S("Class:$sClass/Attribute:$sStateAttrCode/Value:$sStateValue+", '');
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sStateAttrCode);
|
||||
return $oAttDef->GetValueDescription($sStateValue);
|
||||
}
|
||||
|
||||
public static function EnumTransitions($sClass, $sStateCode)
|
||||
@@ -1008,6 +1044,46 @@ abstract class MetaModel
|
||||
return $iFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the flags from the all states that compose the initial_state_path
|
||||
*/
|
||||
public static function GetInitialStateAttributeFlags($sClass, $sState, $sAttCode)
|
||||
{
|
||||
$iFlags = self::GetAttributeFlags($sClass, $sState, $sAttCode); // Be default set the same flags as the 'target' state
|
||||
$sStateAttCode = self::GetStateAttributeCode($sClass);
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
$aStates = MetaModel::EnumInitialStates($sClass);
|
||||
if (array_key_exists($sState, $aStates))
|
||||
{
|
||||
$bReadOnly = (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY);
|
||||
$bHidden = (($iFlags & OPT_ATT_HIDDEN) == OPT_ATT_HIDDEN);
|
||||
foreach($aStates[$sState] as $sPrevState)
|
||||
{
|
||||
$iPrevFlags = self::GetAttributeFlags($sClass, $sPrevState, $sAttCode);
|
||||
$bReadOnly = $bReadOnly && (($iPrevFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY); // if it is/was not readonly => then it's not
|
||||
$bHidden = $bHidden && (($iPrevFlags & OPT_ATT_HIDDEN) == OPT_ATT_HIDDEN); // if it is/was not hidden => then it's not
|
||||
}
|
||||
if ($bReadOnly)
|
||||
{
|
||||
$iFlags = $iFlags | OPT_ATT_READONLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $iFlags & ~OPT_ATT_READONLY;
|
||||
}
|
||||
if ($bHidden)
|
||||
{
|
||||
$iFlags = $iFlags | OPT_ATT_HIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $iFlags & ~OPT_ATT_HIDDEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $iFlags;
|
||||
}
|
||||
//
|
||||
// Allowed values
|
||||
//
|
||||
@@ -1024,6 +1100,11 @@ abstract class MetaModel
|
||||
return $oFltDef->GetAllowedValues($aArgs, $sContains);
|
||||
}
|
||||
|
||||
public static function GetAllowedValuesAsObjectSet($sClass, $sAttCode, $aArgs = array(), $sContains = '')
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
||||
return $oAttDef->GetAllowedValuesAsObjectSet($aArgs, $sContains);
|
||||
}
|
||||
//
|
||||
// Businezz model declaration verbs (should be static)
|
||||
//
|
||||
@@ -1313,7 +1394,7 @@ abstract class MetaModel
|
||||
{
|
||||
$oExtensionInstance = new $sPHPClass;
|
||||
}
|
||||
self::$m_aExtensionClasses[$sInterface][] = $oExtensionInstance;
|
||||
self::$m_aExtensionClasses[$sInterface][$sPHPClass] = $oExtensionInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1407,19 +1488,10 @@ abstract class MetaModel
|
||||
self::$m_aAttribOrigins[$sTargetClass] = array();
|
||||
}
|
||||
self::$m_aAttribDefs[$sTargetClass] = self::object_array_mergeclone(self::$m_aAttribDefs[$sTargetClass], self::$m_aAttribDefs[$sSourceClass]);
|
||||
// Note: while investigating on some issues related to attribute inheritance,
|
||||
// I found out that the notion of "host class" is unclear
|
||||
// For stability reasons, and also because a workaround has been found
|
||||
// I leave it unchanged, but later it could be a good thing to force
|
||||
// attribute host class to the new class (See code below)
|
||||
// In that case, we will have to review the attribute labels
|
||||
// (currently relying on host class => the original declaration
|
||||
// of the attribute)
|
||||
// See TRAC #148
|
||||
// foreach(self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef)
|
||||
// {
|
||||
// $oAttDef->SetHostClass($sTargetClass);
|
||||
// }
|
||||
foreach(self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef)
|
||||
{
|
||||
$oAttDef->SetHostClass($sTargetClass);
|
||||
}
|
||||
self::$m_aAttribOrigins[$sTargetClass] = array_merge(self::$m_aAttribOrigins[$sTargetClass], self::$m_aAttribOrigins[$sSourceClass]);
|
||||
}
|
||||
// Build root class information
|
||||
@@ -1464,11 +1536,25 @@ abstract class MetaModel
|
||||
|
||||
public static function Init_AddAttribute(AttributeDefinition $oAtt)
|
||||
{
|
||||
$sTargetClass = self::GetCallersPHPClass("Init");
|
||||
|
||||
$sAttCode = $oAtt->GetCode();
|
||||
if ($sAttCode == 'finalclass') throw new Exception('Using a reserved keyword in metamodel declaration: '.$sAttCode);
|
||||
if ($sAttCode == 'friendlyname') throw new Exception('Using a reserved keyword in metamodel declaration: '.$sAttCode);
|
||||
if ($sAttCode == 'finalclass')
|
||||
{
|
||||
throw new Exception("Declaration of $sTargetClass: using the reserved keyword '$sAttCode' in attribute declaration");
|
||||
}
|
||||
if ($sAttCode == 'friendlyname')
|
||||
{
|
||||
throw new Exception("Declaration of $sTargetClass: using the reserved keyword '$sAttCode' in attribute declaration");
|
||||
}
|
||||
if (array_key_exists($sAttCode, self::$m_aAttribDefs[$sTargetClass]))
|
||||
{
|
||||
throw new Exception("Declaration of $sTargetClass: attempting to redeclare the inherited attribute '$sAttCode', originaly declared in ".self::$m_aAttribOrigins[$sTargetClass][$sAttCode]);
|
||||
}
|
||||
|
||||
$sTargetClass = self::GetCallersPHPClass("Init");
|
||||
// Set the "host class" as soon as possible, since HierarchicalKeys use it for their 'target class' as well
|
||||
// and this needs to be know early (for Init_IsKnowClass 19 lines below)
|
||||
$oAtt->SetHostClass($sTargetClass);
|
||||
|
||||
// Some attributes could refer to a class
|
||||
// declared in a module which is currently not installed/active
|
||||
@@ -1508,12 +1594,7 @@ abstract class MetaModel
|
||||
|
||||
self::$m_aAttribDefs[$sTargetClass][$oAtt->GetCode()] = $oAtt;
|
||||
self::$m_aAttribOrigins[$sTargetClass][$oAtt->GetCode()] = $sTargetClass;
|
||||
// Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
|
||||
|
||||
// Specific case of external fields:
|
||||
// I wanted to simplify the syntax of the declaration of objects in the biz model
|
||||
// Therefore, the reference to the host class is set there
|
||||
$oAtt->SetHostClass($sTargetClass);
|
||||
// Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
|
||||
}
|
||||
|
||||
public static function Init_SetZListItems($sListCode, $aItems)
|
||||
@@ -1535,7 +1616,13 @@ abstract class MetaModel
|
||||
{
|
||||
if (is_array($attCode))
|
||||
{
|
||||
self::Init_CheckZListItems($attCode, $sTargetClass);
|
||||
// Note: to make sure that the values will be updated recursively,
|
||||
// do not pass $attCode, but $aItems[$iFoo] instead
|
||||
self::Init_CheckZListItems($aItems[$iFoo], $sTargetClass);
|
||||
if (count($aItems[$iFoo]) == 0)
|
||||
{
|
||||
unset($aItems[$iFoo]);
|
||||
}
|
||||
}
|
||||
else if (isset(self::$m_aIgnoredAttributes[$sTargetClass][$attCode]))
|
||||
{
|
||||
@@ -1655,6 +1742,34 @@ abstract class MetaModel
|
||||
self::_check_subclass($sClass);
|
||||
return (self::GetRootClass($sClass) == $sClass);
|
||||
}
|
||||
public static function GetParentClass($sClass)
|
||||
{
|
||||
if (count(self::$m_aParentClasses[$sClass]) == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return end(self::$m_aParentClasses[$sClass]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Tells if a class contains a hierarchical key, and if so what is its AttCode
|
||||
* @return mixed String = sAttCode or false if the class is not part of a hierarchy
|
||||
*/
|
||||
public static function IsHierarchicalClass($sClass)
|
||||
{
|
||||
$sHierarchicalKeyCode = false;
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt)
|
||||
{
|
||||
if ($oAtt->IsHierarchicalKey())
|
||||
{
|
||||
$sHierarchicalKeyCode = $sAttCode; // Found the hierarchical key, no need to continue
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $sHierarchicalKeyCode;
|
||||
}
|
||||
public static function EnumRootClasses()
|
||||
{
|
||||
return array_unique(self::$m_aRootClasses);
|
||||
@@ -1767,11 +1882,11 @@ abstract class MetaModel
|
||||
return $aScalarArgs;
|
||||
}
|
||||
|
||||
public static function MakeSelectQuery(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false)
|
||||
public static function MakeSelectQuery(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false)
|
||||
{
|
||||
// Hide objects that are not visible to the current user
|
||||
//
|
||||
if (!$oFilter->IsAllDataAllowed())
|
||||
if (!$oFilter->IsAllDataAllowed() && !$oFilter->IsDataFiltered())
|
||||
{
|
||||
$oVisibleObjects = UserRights::GetSelectFilter($oFilter->GetClass());
|
||||
if ($oVisibleObjects === false)
|
||||
@@ -1782,6 +1897,7 @@ abstract class MetaModel
|
||||
if (is_object($oVisibleObjects))
|
||||
{
|
||||
$oFilter->MergeWith($oVisibleObjects);
|
||||
$oFilter->SetDataFiltered();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1794,7 +1910,16 @@ abstract class MetaModel
|
||||
{
|
||||
// Need to identify the query
|
||||
$sOqlQuery = $oFilter->ToOql();
|
||||
$sOqlId = md5($sOqlQuery);
|
||||
|
||||
$sRawId = $sOqlQuery;
|
||||
if (!is_null($aAttToLoad))
|
||||
{
|
||||
foreach($aAttToLoad as $sAlias => $aAttributes)
|
||||
{
|
||||
$sRawId = $sOqlQuery.'|'.implode(',', array_keys($aAttributes));
|
||||
}
|
||||
}
|
||||
$sOqlId = md5($sRawId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1840,6 +1965,43 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Check the order by specification, and prefix with the class alias
|
||||
// and make sure that the ordering columns are going to be selected
|
||||
//
|
||||
$aOrderSpec = array();
|
||||
foreach ($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetFirstJoinedClass()));
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
|
||||
}
|
||||
$sFirstClassAlias = $oFilter->GetFirstJoinedClassAlias();
|
||||
$aOrderSpec[$sFirstClassAlias.$sFieldAlias] = $bAscending;
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sFirstClassAlias][$sFieldAlias]))
|
||||
{
|
||||
$aAttToLoad[$sFirstClassAlias][$sFieldAlias] = MetaModel::GetAttributeDef($oFilter->GetFirstJoinedClass(), $sFieldAlias);
|
||||
}
|
||||
}
|
||||
// By default, force the name attribute to be the ordering key
|
||||
//
|
||||
if (empty($aOrderSpec))
|
||||
{
|
||||
foreach ($oFilter->GetSelectedClasses() as $sSelectedAlias => $sSelectedClass)
|
||||
{
|
||||
// By default, simply order on the "friendlyname" attribute, ascending
|
||||
$aOrderSpec[$sSelectedAlias."friendlyname"] = true;
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sSelectedAlias]["friendlyname"]))
|
||||
{
|
||||
$aAttToLoad[$sSelectedAlias]["friendlyname"] = MetaModel::GetAttributeDef($sSelectedClass, "friendlyname");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($oSelect))
|
||||
{
|
||||
$aClassAliases = array();
|
||||
@@ -1847,7 +2009,7 @@ abstract class MetaModel
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, array(), true /* main query */);
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $aAttToLoad, array(), true /* main query */);
|
||||
$oSelect->SetSourceOQL($sOqlQuery);
|
||||
$oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
|
||||
|
||||
@@ -1864,29 +2026,6 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Check the order by specification, and prefix with the class alias
|
||||
//
|
||||
$aOrderSpec = array();
|
||||
foreach ($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetFirstJoinedClass()));
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
|
||||
}
|
||||
$aOrderSpec[$oFilter->GetFirstJoinedClassAlias().$sFieldAlias] = $bAscending;
|
||||
}
|
||||
// By default, force the name attribute to be the ordering key
|
||||
//
|
||||
if (empty($aOrderSpec))
|
||||
{
|
||||
foreach ($oFilter->GetSelectedClasses() as $sSelectedAlias => $sSelectedClass)
|
||||
{
|
||||
// By default, simply order on the "friendlyname" attribute, ascending
|
||||
$aOrderSpec[$sSelectedAlias."friendlyname"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Join to an additional table, if required...
|
||||
//
|
||||
if ($aExtendedDataSpec != null)
|
||||
@@ -1909,6 +2048,7 @@ abstract class MetaModel
|
||||
try
|
||||
{
|
||||
$sRes = $oSelect->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount);
|
||||
//echo "<p>MakeQuery: $sRes</p>";
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
@@ -1983,7 +2123,7 @@ abstract class MetaModel
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, array(), true /* main query */);
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, null, array(), true /* main query */);
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderDelete($aScalarArgs);
|
||||
}
|
||||
@@ -1994,12 +2134,12 @@ abstract class MetaModel
|
||||
$aClassAliases = array();
|
||||
$aTableAliases = array();
|
||||
$oQBExpr = new QueryBuilderExpressions(array(), $oFilter->GetCriteria());
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $aValues, true /* main query */);
|
||||
$oSelect = self::MakeQuery($oFilter->GetSelectedClasses(), $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, null, $aValues, true /* main query */);
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderUpdate($aScalarArgs);
|
||||
}
|
||||
|
||||
private static function MakeQuery($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, DBObjectSearch $oFilter, $aValues = array(), $bIsMainQuery = false)
|
||||
private static function MakeQuery($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQuery = false)
|
||||
{
|
||||
// Note: query class might be different than the class of the filter
|
||||
// -> this occurs when we are linking our class to an external class (referenced by, or pointing to)
|
||||
@@ -2022,7 +2162,15 @@ abstract class MetaModel
|
||||
// default to the whole list of attributes + the very std id/finalclass
|
||||
$oQBExpr->AddSelect($sClassAlias.'id', new FieldExpression('id', $sClassAlias));
|
||||
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad))
|
||||
{
|
||||
$aAttList = self::ListAttributeDefs($sClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttList = $aAttToLoad[$sClassAlias];
|
||||
}
|
||||
foreach ($aAttList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (!$oAttDef->IsScalar()) continue;
|
||||
|
||||
@@ -2052,8 +2200,9 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
$aExpectedAtts = array(); // array of (attcode => fieldexpression)
|
||||
//echo "<p>".__LINE__.": GetUnresolvedFields($sClassAlias, ...)</p>\n";
|
||||
$oQBExpr->GetUnresolvedFields($sClassAlias, $aExpectedAtts);
|
||||
|
||||
// Compute a clear view of required joins (from the current class)
|
||||
@@ -2078,17 +2227,22 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
// Get all Ext keys used by the filter
|
||||
foreach ($oFilter->GetCriteria_PointingTo() as $sKeyAttCode => $trash)
|
||||
foreach ($oFilter->GetCriteria_PointingTo() as $sKeyAttCode => $aPointingTo)
|
||||
{
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
|
||||
$aExtKeys[$sKeyTableClass][$sKeyAttCode] = array();
|
||||
if (array_key_exists(TREE_OPERATOR_EQUALS, $aPointingTo))
|
||||
{
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
|
||||
$aExtKeys[$sKeyTableClass][$sKeyAttCode] = array();
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('friendlyname', $aExpectedAtts))
|
||||
{
|
||||
$aTranslateNow = array();
|
||||
$aTranslateNow[$sClassAlias]['friendlyname'] = self::GetNameExpression($sClass, $sClassAlias);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
$oQBExpr->Translate($aTranslateNow, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
foreach($aNameSpec[1] as $i => $sAttCode)
|
||||
@@ -2146,6 +2300,7 @@ abstract class MetaModel
|
||||
foreach(self::EnumParentClasses($sClass) as $sParentClass)
|
||||
{
|
||||
if (!self::HasTable($sParentClass)) continue;
|
||||
//echo "<p>Parent class: $sParentClass... let's call MakeQuerySingleTable()</p>";
|
||||
self::DbgTrace("Parent class: $sParentClass... let's call MakeQuerySingleTable()");
|
||||
$oSelectParentTable = self::MakeQuerySingleTable($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oFilter, $sParentClass, $aExtKeys, $aValues);
|
||||
if (is_null($oSelectBase))
|
||||
@@ -2174,7 +2329,7 @@ abstract class MetaModel
|
||||
$sForeignClassAlias = $oForeignFilter->GetFirstJoinedClassAlias();
|
||||
$oQBExpr->PushJoinField(new FieldExpression($sForeignKeyAttCode, $sForeignClassAlias));
|
||||
|
||||
$oSelectForeign = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oForeignFilter);
|
||||
$oSelectForeign = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oForeignFilter, $aAttToLoad);
|
||||
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$sForeignKeyTable = $oJoinExpr->GetParent();
|
||||
@@ -2230,6 +2385,7 @@ abstract class MetaModel
|
||||
protected static function MakeQuerySingleTable($aSelectedClasses, &$oQBExpr, &$aClassAliases, &$aTableAliases, $oFilter, $sTableClass, $aExtKeys, $aValues)
|
||||
{
|
||||
// $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields))
|
||||
//echo "MAKEQUERY($sTableClass)-liste des clefs externes($sTableClass): <pre>".print_r($aExtKeys, true)."</pre><br/>\n";
|
||||
|
||||
// Prepare the query for a single table (compound objects)
|
||||
// Ignores the items (attributes/filters) that are not on the target table
|
||||
@@ -2304,6 +2460,7 @@ abstract class MetaModel
|
||||
}
|
||||
else
|
||||
{
|
||||
//echo "<p>MakeQuerySingleTable: Field $sAttCode is part of the table $sTable (named: $sTableAlias)</p>";
|
||||
// standard field, or external key
|
||||
// add it to the output
|
||||
foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr)
|
||||
@@ -2320,92 +2477,350 @@ abstract class MetaModel
|
||||
//
|
||||
$oSelectBase = new SQLQuery($sTable, $sTableAlias, array(), $bIsOnQueriedClass, $aUpdateValues, $oSelectedIdField);
|
||||
|
||||
//echo "MAKEQUERY- Classe $sTableClass<br/>\n";
|
||||
// 4 - The external keys -> joins...
|
||||
//
|
||||
$aAllPointingTo = $oFilter->GetCriteria_PointingTo();
|
||||
|
||||
if (array_key_exists($sTableClass, $aExtKeys))
|
||||
{
|
||||
foreach ($aExtKeys[$sTableClass] as $sKeyAttCode => $aExtFields)
|
||||
{
|
||||
$oKeyAttDef = self::GetAttributeDef($sTargetClass, $sKeyAttCode);
|
||||
$oKeyAttDef = self::GetAttributeDef($sTableClass, $sKeyAttCode);
|
||||
|
||||
$oExtFilter = $oFilter->GetCriteria_PointingTo($sKeyAttCode);
|
||||
|
||||
// In case the join was not explicitely defined in the filter,
|
||||
// we need to do it now
|
||||
if (empty($oExtFilter))
|
||||
$aPointingTo = $oFilter->GetCriteria_PointingTo($sKeyAttCode);
|
||||
//echo "MAKEQUERY-Cle '$sKeyAttCode'<br/>\n";
|
||||
if (!array_key_exists(TREE_OPERATOR_EQUALS, $aPointingTo))
|
||||
{
|
||||
//echo "MAKEQUERY-Ajoutons l'operateur TREE_OPERATOR_EQUALS pour $sKeyAttCode<br/>\n";
|
||||
// The join was not explicitely defined in the filter,
|
||||
// we need to do it now
|
||||
$sKeyClass = $oKeyAttDef->GetTargetClass();
|
||||
$sKeyClassAlias = self::GenerateUniqueAlias($aClassAliases, $sKeyClass.'_'.$sKeyAttCode, $sKeyClass);
|
||||
$oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias);
|
||||
|
||||
$aAllPointingTo[$sKeyAttCode][TREE_OPERATOR_EQUALS][$sKeyClassAlias] = $oExtFilter;
|
||||
}
|
||||
else
|
||||
}
|
||||
}
|
||||
//echo "MAKEQUERY-liste des clefs de jointure: <pre>".print_r(array_keys($aAllPointingTo), true)."</pre><br/>\n";
|
||||
|
||||
foreach ($aAllPointingTo as $sKeyAttCode => $aPointingTo)
|
||||
{
|
||||
foreach($aPointingTo as $iOperatorCode => $aFilter)
|
||||
{
|
||||
foreach($aFilter as $sAlias => $oExtFilter)
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($sTableClass, $sKeyAttCode)) continue; // Not defined in the class, skip it
|
||||
// The aliases should not conflict because normalization occured while building the filter
|
||||
$oKeyAttDef = self::GetAttributeDef($sTableClass, $sKeyAttCode);
|
||||
$sKeyClass = $oExtFilter->GetFirstJoinedClass();
|
||||
$sKeyClassAlias = $oExtFilter->GetFirstJoinedClassAlias();
|
||||
|
||||
|
||||
//echo "MAKEQUERY-$sTableClass::$sKeyAttCode Foreach PointingTo($iOperatorCode) <span style=\"color:red\">$sKeyClass (alias:$sKeyClassAlias)</span><br/>\n";
|
||||
|
||||
// Note: there is no search condition in $oExtFilter, because normalization did merge the condition onto the top of the filter tree
|
||||
}
|
||||
|
||||
// Specify expected attributes for the target class query
|
||||
// ... and use the current alias !
|
||||
$aTranslateNow = array(); // Translation for external fields - must be performed before the join is done (recursion...)
|
||||
foreach($aExtFields as $sAttCode => $oAtt)
|
||||
{
|
||||
if ($oAtt instanceof AttributeFriendlyName)
|
||||
//echo "MAKEQUERY-array_key_exists($sTableClass, \$aExtKeys)<br/>\n";
|
||||
if ($iOperatorCode == TREE_OPERATOR_EQUALS)
|
||||
{
|
||||
// Note: for a given ext key, there is one single attribute "friendly name"
|
||||
$aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sExtAttCode = $oAtt->GetExtAttCode();
|
||||
// Translate mainclass.extfield => remoteclassalias.remotefieldcode
|
||||
$oRemoteAttDef = self::GetAttributeDef($sKeyClass, $sExtAttCode);
|
||||
foreach ($oRemoteAttDef->GetSQLExpressions() as $sColID => $sRemoteAttExpr)
|
||||
if (array_key_exists($sTableClass, $aExtKeys) && array_key_exists($sKeyAttCode, $aExtKeys[$sTableClass]))
|
||||
{
|
||||
$aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);
|
||||
// Specify expected attributes for the target class query
|
||||
// ... and use the current alias !
|
||||
$aTranslateNow = array(); // Translation for external fields - must be performed before the join is done (recursion...)
|
||||
foreach($aExtKeys[$sTableClass][$sKeyAttCode] as $sAttCode => $oAtt)
|
||||
{
|
||||
//echo "MAKEQUERY aExtKeys[$sTableClass][$sKeyAttCode] => $sAttCode-oAtt: <pre>".print_r($oAtt, true)."</pre><br/>\n";
|
||||
if ($oAtt instanceof AttributeFriendlyName)
|
||||
{
|
||||
// Note: for a given ext key, there is one single attribute "friendly name"
|
||||
$aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);
|
||||
//echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode] = new FieldExpression('friendlyname', $sKeyClassAlias);</b></p>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sExtAttCode = $oAtt->GetExtAttCode();
|
||||
// Translate mainclass.extfield => remoteclassalias.remotefieldcode
|
||||
$oRemoteAttDef = self::GetAttributeDef($sKeyClass, $sExtAttCode);
|
||||
foreach ($oRemoteAttDef->GetSQLExpressions() as $sColID => $sRemoteAttExpr)
|
||||
{
|
||||
$aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);
|
||||
//echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);</b></p>\n";
|
||||
}
|
||||
//echo "<p><b>ExtAttr2: $sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)</b></p>\n";
|
||||
}
|
||||
}
|
||||
// Translate prior to recursing
|
||||
//
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."\n".print_r($aTranslateNow, true)."</pre></p>\n";
|
||||
$oQBExpr->Translate($aTranslateNow, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
|
||||
//echo "<p>External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()/p>\n";
|
||||
self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()");
|
||||
$oQBExpr->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
|
||||
|
||||
//echo "<p>Recursive MakeQuery ".__LINE__.": <pre>\n".print_r($aSelectedClasses, true)."</pre></p>\n";
|
||||
$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
|
||||
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$sExternalKeyTable = $oJoinExpr->GetParent();
|
||||
$sExternalKeyField = $oJoinExpr->GetName();
|
||||
|
||||
$aCols = $oKeyAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
|
||||
$sLocalKeyField = current($aCols); // get the first column for an external key
|
||||
|
||||
self::DbgTrace("External key $sKeyAttCode, Join on $sLocalKeyField = $sExternalKeyField");
|
||||
if ($oKeyAttDef->IsNullAllowed())
|
||||
{
|
||||
$oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
|
||||
}
|
||||
}
|
||||
//#@# debug - echo "<p>$sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)</p>\n";
|
||||
}
|
||||
}
|
||||
// Translate prior to recursing
|
||||
//
|
||||
$oQBExpr->Translate($aTranslateNow, false);
|
||||
|
||||
self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()");
|
||||
|
||||
$oQBExpr->PushJoinField(new FieldExpression('id', $sKeyClassAlias));
|
||||
|
||||
$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
|
||||
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
$sExternalKeyTable = $oJoinExpr->GetParent();
|
||||
$sExternalKeyField = $oJoinExpr->GetName();
|
||||
|
||||
$aCols = $oKeyAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
|
||||
$sLocalKeyField = current($aCols); // get the first column for an external key
|
||||
|
||||
self::DbgTrace("External key $sKeyAttCode, Join on $sLocalKeyField = $sExternalKeyField");
|
||||
if ($oKeyAttDef->IsNullAllowed())
|
||||
{
|
||||
$oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField, $sExternalKeyTable);
|
||||
elseif(self::$m_aAttribOrigins[$sKeyClass][$sKeyAttCode] == $sTableClass)
|
||||
{
|
||||
$oQBExpr->PushJoinField(new FieldExpression($sKeyAttCode, $sKeyClassAlias));
|
||||
$oSelectExtKey = self::MakeQuery($aSelectedClasses, $oQBExpr, $aClassAliases, $aTableAliases, $oExtFilter);
|
||||
$oJoinExpr = $oQBExpr->PopJoinField();
|
||||
//echo "MAKEQUERY-PopJoinField pour $sKeyAttCode, $sKeyClassAlias: <pre>".print_r($oJoinExpr, true)."</pre><br/>\n";
|
||||
$sExternalKeyTable = $oJoinExpr->GetParent();
|
||||
$sExternalKeyField = $oJoinExpr->GetName();
|
||||
$sLeftIndex = $sExternalKeyField.'_left'; // TODO use GetSQLLeft()
|
||||
$sRightIndex = $sExternalKeyField.'_right'; // TODO use GetSQLRight()
|
||||
|
||||
$LocalKeyLeft = $oKeyAttDef->GetSQLLeft();
|
||||
$LocalKeyRight = $oKeyAttDef->GetSQLRight();
|
||||
//echo "MAKEQUERY-LocalKeyLeft pour $sKeyAttCode => $LocalKeyLeft<br/>\n";
|
||||
|
||||
$oSelectBase->AddInnerJoinTree($oSelectExtKey, $LocalKeyLeft, $LocalKeyRight, $sLeftIndex, $sRightIndex, $sExternalKeyTable, $iOperatorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Translate the selected columns
|
||||
//
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
$oQBExpr->Translate($aTranslation, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oQBExpr, true)."</pre></p>\n";
|
||||
|
||||
//MyHelpers::var_dump_html($oSelectBase->RenderSelect());
|
||||
return $oSelectBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Special processing for the hierarchical keys stored as nested sets
|
||||
* @param $iId integer The identifier of the parent
|
||||
* @param $oAttDef AttributeDefinition The attribute corresponding to the hierarchical key
|
||||
* @param $stable string The name of the database table containing the hierarchical key
|
||||
*/
|
||||
public static function HKInsertChildUnder($iId, $oAttDef, $sTable)
|
||||
{
|
||||
// Get the parent id.right value
|
||||
if ($iId == 0)
|
||||
{
|
||||
// No parent, insert completely at the right of the tree
|
||||
$sSQL = "SELECT max(`".$oAttDef->GetSQLRight()."`) AS max FROM `$sTable`";
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
if (count($aRes) == 0)
|
||||
{
|
||||
$iMyRight = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iMyRight = $aRes[0]['max']+1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = "SELECT `".$oAttDef->GetSQLRight()."` FROM `$sTable` WHERE id=".$iId;
|
||||
$iMyRight = CMDBSource::QueryToScalar($sSQL);
|
||||
$sSQLUpdateRight = "UPDATE `$sTable` SET `".$oAttDef->GetSQLRight()."` = `".$oAttDef->GetSQLRight()."` + 2 WHERE `".$oAttDef->GetSQLRight()."` >= $iMyRight";
|
||||
CMDBSource::Query($sSQLUpdateRight);
|
||||
$sSQLUpdateLeft = "UPDATE `$sTable` SET `".$oAttDef->GetSQLLeft()."` = `".$oAttDef->GetSQLLeft()."` + 2 WHERE `".$oAttDef->GetSQLLeft()."` > $iMyRight";
|
||||
CMDBSource::Query($sSQLUpdateLeft);
|
||||
}
|
||||
return array($oAttDef->GetSQLRight() => $iMyRight+1, $oAttDef->GetSQLLeft() => $iMyRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special processing for the hierarchical keys stored as nested sets: temporary remove the branch
|
||||
* @param $iId integer The identifier of the parent
|
||||
* @param $oAttDef AttributeDefinition The attribute corresponding to the hierarchical key
|
||||
* @param $sTable string The name of the database table containing the hierarchical key
|
||||
*/
|
||||
public static function HKTemporaryCutBranch($iMyLeft, $iMyRight, $oAttDef, $sTable)
|
||||
{
|
||||
$iDelta = $iMyRight - $iMyLeft + 1;
|
||||
$sSQL = "UPDATE `$sTable` SET `".$oAttDef->GetSQLRight()."` = $iMyLeft - `".$oAttDef->GetSQLRight()."`, `".$oAttDef->GetSQLLeft()."` = $iMyLeft - `".$oAttDef->GetSQLLeft();
|
||||
$sSQL .= "` WHERE `".$oAttDef->GetSQLLeft()."`> $iMyLeft AND `".$oAttDef->GetSQLRight()."`< $iMyRight";
|
||||
CMDBSource::Query($sSQL);
|
||||
$sSQL = "UPDATE `$sTable` SET `".$oAttDef->GetSQLLeft()."` = `".$oAttDef->GetSQLLeft()."` - $iDelta WHERE `".$oAttDef->GetSQLLeft()."` > $iMyRight";
|
||||
CMDBSource::Query($sSQL);
|
||||
$sSQL = "UPDATE `$sTable` SET `".$oAttDef->GetSQLRight()."` = `".$oAttDef->GetSQLRight()."` - $iDelta WHERE `".$oAttDef->GetSQLRight()."` > $iMyRight";
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special processing for the hierarchical keys stored as nested sets: replug the temporary removed branch
|
||||
* @param $iId integer The identifier of the parent
|
||||
* @param $oAttDef AttributeDefinition The attribute corresponding to the hierarchical key
|
||||
* @param $sTable string The name of the database table containing the hierarchical key
|
||||
*/
|
||||
public static function HKReplugBranch($iNewLeft, $iNewRight, $oAttDef, $sTable)
|
||||
{
|
||||
$iDelta = $iNewRight - $iNewLeft + 1;
|
||||
$sSQL = "UPDATE `$sTable` SET `".$oAttDef->GetSQLLeft()."` = `".$oAttDef->GetSQLLeft()."` + $iDelta WHERE `".$oAttDef->GetSQLLeft()."` > $iNewLeft";
|
||||
CMDBSource::Query($sSQL);
|
||||
$sSQL = "UPDATE `$sTable` SET `".$oAttDef->GetSQLRight()."` = `".$oAttDef->GetSQLRight()."` + $iDelta WHERE `".$oAttDef->GetSQLRight()."` >= $iNewLeft";
|
||||
CMDBSource::Query($sSQL);
|
||||
$sSQL = "UPDATE `$sTable` SET `".$oAttDef->GetSQLRight()."` = $iNewLeft - `".$oAttDef->GetSQLRight()."`, `".$oAttDef->GetSQLLeft()."` = $iNewLeft - `".$oAttDef->GetSQLLeft()."` WHERE `".$oAttDef->GetSQLRight()."`< 0";
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check (and updates if needed) the hierarchical keys
|
||||
* @param $bDiagnosticsOnly boolean If true only a diagnostic pass will be run, returning true or false
|
||||
* @param $bVerbose boolean Displays some information about what is done/what needs to be done
|
||||
* @param $bForceComputation boolean If true, the _left and _right parameters will be recomputed even if some values already exist in the DB
|
||||
*/
|
||||
public static function CheckHKeys($bDiagnosticsOnly = false, $bVerbose = false, $bForceComputation = false)
|
||||
{
|
||||
$bChangeNeeded = false;
|
||||
foreach (self::GetClasses() as $sClass)
|
||||
{
|
||||
if (!self::HasTable($sClass)) continue;
|
||||
|
||||
foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Check (once) all the attributes that are hierarchical keys
|
||||
if((self::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
if ($bVerbose)
|
||||
{
|
||||
echo "The attribute $sAttCode from $sClass is a hierarchical key.\n";
|
||||
}
|
||||
$bResult = self::HKInit($sClass, $sAttCode, $bDiagnosticsOnly, $bVerbose, $bForceComputation);
|
||||
$bChangeNeeded |= $bResult;
|
||||
if ($bVerbose && !$bResult)
|
||||
{
|
||||
echo "Ok, the attribute $sAttCode from class $sClass seems up to date.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $bChangeNeeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes (i.e converts) a hierarchy stored using a 'parent_id' external key
|
||||
* into a hierarchy stored with a HierarchicalKey, by initializing the _left and _right values
|
||||
* to correspond to the existing hierarchy in the database
|
||||
* @param $sClass string Name of the class to process
|
||||
* @param $sAttCode string Code of the attribute to process
|
||||
* @param $bDiagnosticsOnly boolean If true only a diagnostic pass will be run, returning true or false
|
||||
* @param $bVerbose boolean Displays some information about what is done/what needs to be done
|
||||
* @param $bForceComputation boolean If true, the _left and _right parameters will be recomputed even if some values already exist in the DB
|
||||
* @return true if an update is needed (diagnostics only) / was performed
|
||||
*/
|
||||
public static function HKInit($sClass, $sAttCode, $bDiagnosticsOnly = false, $bVerbose = false, $bForceComputation = false)
|
||||
{
|
||||
$idx = 1;
|
||||
$bUpdateNeeded = $bForceComputation;
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
||||
$sTable = self::DBGetTable($sClass, $sAttCode);
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
// Check if some values already exist in the table for the _right value, if so, do nothing
|
||||
$sRight = $oAttDef->GetSQLRight();
|
||||
$sSQL = "SELECT MAX(`$sRight`) AS MaxRight FROM `$sTable`";
|
||||
$iMaxRight = CMDBSource::QueryToScalar($sSQL);
|
||||
$sSQL = "SELECT COUNT(*) AS Count FROM `$sTable`"; // Note: COUNT(field) returns zero if the given field contains only NULLs
|
||||
$iCount = CMDBSource::QueryToScalar($sSQL);
|
||||
if (!$bForceComputation && ($iCount != 0) && ($iMaxRight == 0))
|
||||
{
|
||||
$bUpdateNeeded = true;
|
||||
if ($bVerbose)
|
||||
{
|
||||
echo "The table '$sTable' must be updated to compute the fields $sRight and ".$oAttDef->GetSQLLeft()."\n";
|
||||
}
|
||||
}
|
||||
if ($bForceComputation && !$bDiagnosticsOnly)
|
||||
{
|
||||
echo "Rebuilding the fields $sRight and ".$oAttDef->GetSQLLeft()." from table '$sTable'...\n";
|
||||
}
|
||||
if ($bUpdateNeeded && !$bDiagnosticsOnly)
|
||||
{
|
||||
try
|
||||
{
|
||||
CMDBSource::Query('START TRANSACTION');
|
||||
self::HKInitChildren($sTable, $sAttCode, $oAttDef, 0, $idx);
|
||||
CMDBSource::Query('COMMIT');
|
||||
if ($bVerbose)
|
||||
{
|
||||
echo "Ok, table '$sTable' successfully updated.\n";
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
CMDBSource::Query('ROLLBACK');
|
||||
throw new Exception("An error occured (".$e->getMessage().") while initializing the hierarchy for ($sClass, $sAttCode). The database was not modified.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return $bUpdateNeeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive helper function called by HKInit
|
||||
*/
|
||||
protected static function HKInitChildren($sTable, $sAttCode, $oAttDef, $iId, &$iCurrIndex)
|
||||
{
|
||||
$sSQL = "SELECT id FROM `$sTable` WHERE `$sAttCode` = $iId";
|
||||
$aRes = CMDBSource::QueryToArray($sSQL);
|
||||
$aTree = array();
|
||||
$sLeft = $oAttDef->GetSQLLeft();
|
||||
$sRight = $oAttDef->GetSQLRight();
|
||||
foreach($aRes as $aValues)
|
||||
{
|
||||
$iChildId = $aValues['id'];
|
||||
$iLeft = $iCurrIndex++;
|
||||
$aChildren = self::HKInitChildren($sTable, $sAttCode, $oAttDef, $iChildId, $iCurrIndex);
|
||||
$iRight = $iCurrIndex++;
|
||||
$sSQL = "UPDATE `$sTable` SET `$sLeft` = $iLeft, `$sRight` = $iRight WHERE id= $iChildId";
|
||||
CMDBSource::Query($sSQL);
|
||||
}
|
||||
}
|
||||
|
||||
public static function CheckDataSources($bDiagnostics, $bVerbose)
|
||||
{
|
||||
$sOQL = 'SELECT SynchroDataSource';
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
|
||||
$bFixNeeded = false;
|
||||
if ($bVerbose && $oSet->Count() == 0)
|
||||
{
|
||||
echo "There are no Data Sources in the database.\n";
|
||||
}
|
||||
while($oSource = $oSet->Fetch())
|
||||
{
|
||||
if ($bVerbose)
|
||||
{
|
||||
echo "Checking Data Source '".$oSource->GetName()."'...\n";
|
||||
$bFixNeeded = $bFixNeeded | $oSource->CheckDBConsistency($bDiagnostics, $bVerbose);
|
||||
}
|
||||
}
|
||||
if (!$bFixNeeded && $bVerbose)
|
||||
{
|
||||
echo "Ok.\n";
|
||||
}
|
||||
return $bFixNeeded;
|
||||
}
|
||||
|
||||
public static function GenerateUniqueAlias(&$aAliases, $sNewName, $sRealName)
|
||||
{
|
||||
if (!array_key_exists($sNewName, $aAliases))
|
||||
@@ -2507,7 +2922,7 @@ abstract class MetaModel
|
||||
if (!is_null($aAllowedValues))
|
||||
{
|
||||
$sDefaultValue = $oAttDef->GetDefaultValue();
|
||||
if (!array_key_exists($sDefaultValue, $aAllowedValues))
|
||||
if (is_string($sDefaultValue) && !array_key_exists($sDefaultValue, $aAllowedValues))
|
||||
{
|
||||
$aErrors[$sClass][] = "Default value '".$sDefaultValue."' for attribute $sAttCode is not an allowed value";
|
||||
$aSugFix[$sClass][] = "Please pickup the default value out of {'".implode(", ", array_keys($aAllowedValues))."'}";
|
||||
@@ -3028,7 +3443,7 @@ abstract class MetaModel
|
||||
// Check that any defined field exists
|
||||
//
|
||||
$aTableInfo = CMDBSource::GetTableInfo($sTable);
|
||||
|
||||
$aTableInfo['Fields'][$sKeyField]['used'] = true;
|
||||
foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Skip this attribute if not originaly defined in this class
|
||||
@@ -3036,6 +3451,9 @@ abstract class MetaModel
|
||||
|
||||
foreach($oAttDef->GetSQLColumns() as $sField => $sDBFieldType)
|
||||
{
|
||||
// Keep track of columns used by iTop
|
||||
$aTableInfo['Fields'][$sField]['used'] = true;
|
||||
|
||||
$bIndexNeeded = $oAttDef->RequiresIndex();
|
||||
$sFieldDefinition = "`$sField` ".($oAttDef->IsNullAllowed() ? "$sDBFieldType NULL" : "$sDBFieldType NOT NULL");
|
||||
if (!CMDBSource::IsField($sTable, $sField))
|
||||
@@ -3103,6 +3521,14 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find out unused columns
|
||||
foreach($aTableInfo['Fields'] as $sField => $aFieldData)
|
||||
{
|
||||
if (!isset($aFieldData['used']) || !$aFieldData['used'])
|
||||
{
|
||||
$aErrors[$sClass]['*'][] = "Column '$sField' in table '$sTable' is not used";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aCondensedQueries = array();
|
||||
@@ -3167,6 +3593,7 @@ abstract class MetaModel
|
||||
$oFilter->AllowAllData();
|
||||
$sSQL = self::MakeSelectQuery($oFilter);
|
||||
$aErrors[$sClass]['*'][] = "Missing view for class: $sClass";
|
||||
$aSugFix[$sClass]['*'][] = "DROP VIEW IF EXISTS `$sView`";
|
||||
$aSugFix[$sClass]['*'][] = "CREATE VIEW `$sView` AS $sSQL";
|
||||
}
|
||||
}
|
||||
@@ -3877,7 +4304,7 @@ abstract class MetaModel
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
public static function GetObjectByRow($sClass, $aRow, $sClassAlias = '', $aExtendedDataSpec = null)
|
||||
public static function GetObjectByRow($sClass, $aRow, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
|
||||
@@ -3906,7 +4333,7 @@ abstract class MetaModel
|
||||
// do the job for the real target class
|
||||
$sClass = $aRow[$sClassAlias."finalclass"];
|
||||
}
|
||||
return new $sClass($aRow, $sClassAlias, $aExtendedDataSpec);
|
||||
return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
|
||||
}
|
||||
|
||||
public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false)
|
||||
@@ -4170,6 +4597,22 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the specified plug-ins for the given interface
|
||||
*/
|
||||
public static function GetPlugins($sInterface, $sClassName)
|
||||
{
|
||||
$oInstance = null;
|
||||
if (array_key_exists($sInterface, self::$m_aExtensionClasses))
|
||||
{
|
||||
if (array_key_exists($sClassName, self::$m_aExtensionClasses[$sInterface]))
|
||||
{
|
||||
return self::$m_aExtensionClasses[$sInterface][$sClassName];
|
||||
}
|
||||
}
|
||||
return $oInstance;
|
||||
}
|
||||
|
||||
public static function GetCacheEntries(Config $oConfig = null)
|
||||
{
|
||||
if (!function_exists('apc_cache_info')) return array();
|
||||
|
||||
4
core/oql/build.bash
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
php /usr/share/php/PHP/LexerGenerator/cli.php oql-lexer.plex
|
||||
php /usr/share/php/PHP/ParserGenerator/cli.php oql-parser.y
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
# since they are used solely for constructing other files during the build process
|
||||
#
|
||||
build.cmd
|
||||
build.bash
|
||||
oql-lexer.plex
|
||||
oql-parser.y
|
||||
oql-parser.y
|
||||
|
||||
@@ -104,155 +104,163 @@ class OQLLexerRaw
|
||||
if ($this->count >= strlen($this->data)) {
|
||||
return false; // end of input
|
||||
}
|
||||
do {
|
||||
$rules = array(
|
||||
'/^[ \t\n\r]+/',
|
||||
'/^SELECT/',
|
||||
'/^FROM/',
|
||||
'/^AS/',
|
||||
'/^WHERE/',
|
||||
'/^JOIN/',
|
||||
'/^ON/',
|
||||
'/^\//',
|
||||
'/^\\*/',
|
||||
'/^\\+/',
|
||||
'/^-/',
|
||||
'/^AND/',
|
||||
'/^OR/',
|
||||
'/^,/',
|
||||
'/^\\(/',
|
||||
'/^\\)/',
|
||||
'/^REGEXP/',
|
||||
'/^=/',
|
||||
'/^!=/',
|
||||
'/^>/',
|
||||
'/^</',
|
||||
'/^>=/',
|
||||
'/^<=/',
|
||||
'/^LIKE/',
|
||||
'/^NOT LIKE/',
|
||||
'/^IN/',
|
||||
'/^NOT IN/',
|
||||
'/^INTERVAL/',
|
||||
'/^IF/',
|
||||
'/^ELT/',
|
||||
'/^COALESCE/',
|
||||
'/^ISNULL/',
|
||||
'/^CONCAT/',
|
||||
'/^SUBSTR/',
|
||||
'/^TRIM/',
|
||||
'/^DATE/',
|
||||
'/^DATE_FORMAT/',
|
||||
'/^CURRENT_DATE/',
|
||||
'/^NOW/',
|
||||
'/^TIME/',
|
||||
'/^TO_DAYS/',
|
||||
'/^FROM_DAYS/',
|
||||
'/^YEAR/',
|
||||
'/^MONTH/',
|
||||
'/^DAY/',
|
||||
'/^HOUR/',
|
||||
'/^MINUTE/',
|
||||
'/^SECOND/',
|
||||
'/^DATE_ADD/',
|
||||
'/^DATE_SUB/',
|
||||
'/^ROUND/',
|
||||
'/^FLOOR/',
|
||||
'/^INET_ATON/',
|
||||
'/^INET_NTOA/',
|
||||
'/^[0-9]+|0x[0-9a-fA-F]+/',
|
||||
'/^\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/',
|
||||
'/^([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/',
|
||||
'/^:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/',
|
||||
'/^\\./',
|
||||
);
|
||||
$match = false;
|
||||
foreach ($rules as $index => $rule) {
|
||||
if (preg_match($rule, substr($this->data, $this->count), $yymatches)) {
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
|
||||
if ($r === null) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
// accept this token
|
||||
return true;
|
||||
} elseif ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} elseif ($r === false) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
if ($this->count >= strlen($this->data)) {
|
||||
return false; // end of input
|
||||
}
|
||||
// skip this token
|
||||
continue;
|
||||
} else {
|
||||
$yy_yymore_patterns = array_slice($rules, $this->token, true);
|
||||
// yymore is needed
|
||||
do {
|
||||
if (!isset($yy_yymore_patterns[$this->token])) {
|
||||
throw new Exception('cannot do yymore for the last token');
|
||||
}
|
||||
$match = false;
|
||||
foreach ($yy_yymore_patterns[$this->token] as $index => $rule) {
|
||||
if (preg_match('/' . $rule . '/',
|
||||
substr($this->data, $this->count), $yymatches)) {
|
||||
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$this->line = substr_count($this->value, "\n");
|
||||
$r = $this->{'yy_r1_' . $this->token}();
|
||||
} while ($r !== null || !$r);
|
||||
if ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} else {
|
||||
// accept
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
do {
|
||||
$rules = array(
|
||||
'/\G[ \t\n\r]+/ ',
|
||||
'/\GSELECT/ ',
|
||||
'/\GFROM/ ',
|
||||
'/\GAS/ ',
|
||||
'/\GWHERE/ ',
|
||||
'/\GJOIN/ ',
|
||||
'/\GON/ ',
|
||||
'/\G\// ',
|
||||
'/\G\\*/ ',
|
||||
'/\G\\+/ ',
|
||||
'/\G-/ ',
|
||||
'/\GAND/ ',
|
||||
'/\GOR/ ',
|
||||
'/\G,/ ',
|
||||
'/\G\\(/ ',
|
||||
'/\G\\)/ ',
|
||||
'/\GREGEXP/ ',
|
||||
'/\G=/ ',
|
||||
'/\G!=/ ',
|
||||
'/\G>/ ',
|
||||
'/\G</ ',
|
||||
'/\G>=/ ',
|
||||
'/\G<=/ ',
|
||||
'/\GLIKE/ ',
|
||||
'/\GNOT LIKE/ ',
|
||||
'/\GIN/ ',
|
||||
'/\GNOT IN/ ',
|
||||
'/\GINTERVAL/ ',
|
||||
'/\GIF/ ',
|
||||
'/\GELT/ ',
|
||||
'/\GCOALESCE/ ',
|
||||
'/\GISNULL/ ',
|
||||
'/\GCONCAT/ ',
|
||||
'/\GSUBSTR/ ',
|
||||
'/\GTRIM/ ',
|
||||
'/\GDATE/ ',
|
||||
'/\GDATE_FORMAT/ ',
|
||||
'/\GCURRENT_DATE/ ',
|
||||
'/\GNOW/ ',
|
||||
'/\GTIME/ ',
|
||||
'/\GTO_DAYS/ ',
|
||||
'/\GFROM_DAYS/ ',
|
||||
'/\GYEAR/ ',
|
||||
'/\GMONTH/ ',
|
||||
'/\GDAY/ ',
|
||||
'/\GHOUR/ ',
|
||||
'/\GMINUTE/ ',
|
||||
'/\GSECOND/ ',
|
||||
'/\GDATE_ADD/ ',
|
||||
'/\GDATE_SUB/ ',
|
||||
'/\GROUND/ ',
|
||||
'/\GFLOOR/ ',
|
||||
'/\GINET_ATON/ ',
|
||||
'/\GINET_NTOA/ ',
|
||||
'/\GBELOW/ ',
|
||||
'/\GBELOW STRICT/ ',
|
||||
'/\GNOT BELOW/ ',
|
||||
'/\GNOT BELOW STRICT/ ',
|
||||
'/\GABOVE/ ',
|
||||
'/\GABOVE STRICT/ ',
|
||||
'/\GNOT ABOVE/ ',
|
||||
'/\GNOT ABOVE STRICT/ ',
|
||||
'/\G[0-9]+|0x[0-9a-fA-F]+/ ',
|
||||
'/\G\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/ ',
|
||||
'/\G([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ ',
|
||||
'/\G:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/ ',
|
||||
'/\G\\./ ',
|
||||
);
|
||||
$match = false;
|
||||
foreach ($rules as $index => $rule) {
|
||||
if (preg_match($rule, substr($this->data, $this->count), $yymatches)) {
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line ' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$r = $this->{'yy_r1_' . $this->token}($yysubmatches);
|
||||
if ($r === null) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
// accept this token
|
||||
return true;
|
||||
} elseif ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} elseif ($r === false) {
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
if ($this->count >= strlen($this->data)) {
|
||||
return false; // end of input
|
||||
}
|
||||
// skip this token
|
||||
continue;
|
||||
} else {
|
||||
$yy_yymore_patterns = array_slice($rules, $this->token, true);
|
||||
// yymore is needed
|
||||
do {
|
||||
if (!isset($yy_yymore_patterns[$this->token])) {
|
||||
throw new Exception('cannot do yymore for the last token');
|
||||
}
|
||||
$match = false;
|
||||
foreach ($yy_yymore_patterns[$this->token] as $index => $rule) {
|
||||
if (preg_match('/' . $rule . '/',
|
||||
$this->data, $yymatches, null, $this->count)) {
|
||||
$yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns
|
||||
if ($match) {
|
||||
if (strlen($yymatches[0]) > strlen($match[0][0])) {
|
||||
$match = array($yymatches, $index); // matches, token
|
||||
}
|
||||
} else {
|
||||
$match = array($yymatches, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$match) {
|
||||
throw new Exception('Unexpected input at line ' . $this->line .
|
||||
': ' . $this->data[$this->count]);
|
||||
}
|
||||
$this->token = $match[1];
|
||||
$this->value = $match[0][0];
|
||||
$yysubmatches = $match[0];
|
||||
array_shift($yysubmatches);
|
||||
if (!$yysubmatches) {
|
||||
$yysubmatches = array();
|
||||
}
|
||||
$this->line = substr_count($this->value, "\n");
|
||||
$r = $this->{'yy_r1_' . $this->token}();
|
||||
} while ($r !== null || !$r);
|
||||
if ($r === true) {
|
||||
// we have changed state
|
||||
// process this token in the new state
|
||||
return $this->yylex();
|
||||
} else {
|
||||
// accept
|
||||
$this->count += strlen($this->value);
|
||||
$this->line += substr_count($this->value, "\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
|
||||
} // end function
|
||||
@@ -530,24 +538,64 @@ class OQLLexerRaw
|
||||
function yy_r1_54($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
$this->token = OQLParser::BELOW;
|
||||
}
|
||||
function yy_r1_55($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::STRVAL;
|
||||
$this->token = OQLParser::BELOW_STRICT;
|
||||
}
|
||||
function yy_r1_56($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NAME;
|
||||
$this->token = OQLParser::NOT_BELOW;
|
||||
}
|
||||
function yy_r1_57($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::VARNAME;
|
||||
$this->token = OQLParser::NOT_BELOW_STRICT;
|
||||
}
|
||||
function yy_r1_58($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::ABOVE;
|
||||
}
|
||||
function yy_r1_59($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::ABOVE_STRICT;
|
||||
}
|
||||
function yy_r1_60($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_ABOVE;
|
||||
}
|
||||
function yy_r1_61($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NOT_ABOVE_STRICT;
|
||||
}
|
||||
function yy_r1_62($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
}
|
||||
function yy_r1_63($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::STRVAL;
|
||||
}
|
||||
function yy_r1_64($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::NAME;
|
||||
}
|
||||
function yy_r1_65($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::VARNAME;
|
||||
}
|
||||
function yy_r1_66($yy_subpatterns)
|
||||
{
|
||||
|
||||
$this->token = OQLParser::DOT;
|
||||
|
||||
@@ -132,6 +132,14 @@ f_round = "ROUND"
|
||||
f_floor = "FLOOR"
|
||||
f_inet_aton = "INET_ATON"
|
||||
f_inet_ntoa = "INET_NTOA"
|
||||
below = "BELOW"
|
||||
below_strict = "BELOW STRICT"
|
||||
not_below = "NOT BELOW"
|
||||
not_below_strict = "NOT BELOW STRICT"
|
||||
above = "ABOVE"
|
||||
above_strict = "ABOVE STRICT"
|
||||
not_above = "NOT ABOVE"
|
||||
not_above_strict = "NOT ABOVE STRICT"
|
||||
numval = /[0-9]+|0x[0-9a-fA-F]+/
|
||||
strval = /"([^\\"]|\\"|\\\\)*"|'.chr(94).chr(39).'([^\\'.chr(39).']|\\'.chr(39).'|\\\\)*'.chr(39).'/
|
||||
name = /([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/
|
||||
@@ -302,6 +310,30 @@ f_inet_aton {
|
||||
f_inet_ntoa {
|
||||
$this->token = OQLParser::F_INET_NTOA;
|
||||
}
|
||||
below {
|
||||
$this->token = OQLParser::BELOW;
|
||||
}
|
||||
below_strict {
|
||||
$this->token = OQLParser::BELOW_STRICT;
|
||||
}
|
||||
not_below {
|
||||
$this->token = OQLParser::NOT_BELOW;
|
||||
}
|
||||
not_below_strict {
|
||||
$this->token = OQLParser::NOT_BELOW_STRICT;
|
||||
}
|
||||
above {
|
||||
$this->token = OQLParser::ABOVE;
|
||||
}
|
||||
above_strict {
|
||||
$this->token = OQLParser::ABOVE_STRICT;
|
||||
}
|
||||
not_above {
|
||||
$this->token = OQLParser::NOT_ABOVE;
|
||||
}
|
||||
not_above_strict {
|
||||
$this->token = OQLParser::NOT_ABOVE_STRICT;
|
||||
}
|
||||
numval {
|
||||
$this->token = OQLParser::NUMVAL;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,14 @@ join_item(A) ::= JOIN class_name(X) ON join_condition(C).
|
||||
}
|
||||
|
||||
join_condition(A) ::= field_id(X) EQ field_id(Y). { A = new BinaryOqlExpression(X, '=', Y); }
|
||||
join_condition(A) ::= field_id(X) BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW', Y); }
|
||||
join_condition(A) ::= field_id(X) BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW_STRICT', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW_STRICT', Y); }
|
||||
join_condition(A) ::= field_id(X) ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE', Y); }
|
||||
join_condition(A) ::= field_id(X) ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE_STRICT', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE', Y); }
|
||||
join_condition(A) ::= field_id(X) NOT_ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE_STRICT', Y); }
|
||||
|
||||
condition(A) ::= expression_prio4(X). { A = X; }
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ class OqlJoinSpec
|
||||
protected $m_oClassAlias;
|
||||
protected $m_oLeftField;
|
||||
protected $m_oRightField;
|
||||
protected $m_sOperator;
|
||||
|
||||
protected $m_oNextJoinspec;
|
||||
|
||||
@@ -68,6 +69,8 @@ class OqlJoinSpec
|
||||
$this->m_oClassAlias = $oClassAlias;
|
||||
$this->m_oLeftField = $oExpression->GetLeftExpr();
|
||||
$this->m_oRightField = $oExpression->GetRightExpr();
|
||||
$this->m_oRightField = $oExpression->GetRightExpr();
|
||||
$this->m_sOperator = $oExpression->GetOperator();
|
||||
}
|
||||
|
||||
public function GetClass()
|
||||
@@ -96,6 +99,10 @@ class OqlJoinSpec
|
||||
{
|
||||
return $this->m_oRightField;
|
||||
}
|
||||
public function GetOperator()
|
||||
{
|
||||
return $this->m_sOperator;
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryOqlExpression extends BinaryExpression
|
||||
|
||||
@@ -79,7 +79,29 @@ class ormCaseLog {
|
||||
$iPos += $this->m_aIndex[$index]['text_length'];
|
||||
|
||||
$sEntry = '<div class="caselog_header'.$sOpen.'">';
|
||||
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat')), $this->m_aIndex[$index]['user_name']);
|
||||
// Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
|
||||
// therefore we have changed the format. To preserve the compatibility with existing
|
||||
// installations of iTop, both format are allowed:
|
||||
// the 'date' item is either a DateTime object, or a unix timestamp
|
||||
if (is_int($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
// Unix timestamp
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'), $this->m_aIndex[$index]['date']);
|
||||
}
|
||||
elseif (is_object($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
if (version_compare(phpversion(), '5.3.0', '>='))
|
||||
{
|
||||
// DateTime
|
||||
$sDate = $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Warning... but the date is unknown
|
||||
$sDate = '';
|
||||
}
|
||||
}
|
||||
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $this->m_aIndex[$index]['user_name']);
|
||||
$sEntry .= '</div>';
|
||||
$sEntry .= '<div class="caselog_entry"'.$sDisplay.'>';
|
||||
$sEntry .= $sTextEntry;
|
||||
@@ -141,7 +163,7 @@ class ormCaseLog {
|
||||
$this->m_aIndex[] = array(
|
||||
'user_name' => UserRights::GetUserFriendlyName(),
|
||||
'user_id' => UserRights::GetUserId(),
|
||||
'date' => new DateTime(),
|
||||
'date' => time(),
|
||||
'text_length' => $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
);
|
||||
@@ -153,8 +175,7 @@ class ormCaseLog {
|
||||
*/
|
||||
public function GetLatestEntry()
|
||||
{
|
||||
$iLast = count($this->m_aIndex) - 1;
|
||||
$aLastEntry = $this->m_aIndex[$iLast];
|
||||
$aLastEntry = end($this->m_aIndex);
|
||||
$sRes = substr($this->m_sLog, $aLastEntry['separator_length'], $aLastEntry['text_length']);
|
||||
return $sRes;
|
||||
}
|
||||
@@ -165,7 +186,8 @@ class ormCaseLog {
|
||||
*/
|
||||
public function GetLatestEntryIndex()
|
||||
{
|
||||
$iLast = count($this->m_aIndex) - 1;
|
||||
$aKeys = array_keys($this->m_aIndex);
|
||||
$iLast = end($aKeys); // Strict standards: the parameter passed to 'end' must be a variable since it is passed by reference
|
||||
return $iLast;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class ormDocument
|
||||
*/
|
||||
public function GetDisplayLink($sClass, $Id, $sAttCode)
|
||||
{
|
||||
return "<a href=\"../pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode\" target=\"_blank\" >".$this->GetFileName()."</a>\n";
|
||||
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode\" target=\"_blank\" >".$this->GetFileName()."</a>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +114,7 @@ class ormDocument
|
||||
*/
|
||||
public function GetDownloadLink($sClass, $Id, $sAttCode)
|
||||
{
|
||||
return "<a href=\"../pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".$this->GetFileName()."</a>\n";
|
||||
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".$this->GetFileName()."</a>\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -163,7 +163,6 @@ class SQLQuery
|
||||
// {
|
||||
// throw new CoreException("Unknown field '$sRightField' in table '".$sRightTable."'");
|
||||
// }
|
||||
|
||||
$this->m_aJoinSelects[] = array(
|
||||
"jointype" => $sJoinType,
|
||||
"select" => $oSQLQuery,
|
||||
@@ -172,9 +171,26 @@ class SQLQuery
|
||||
"righttablealias" => $sRightTableAlias
|
||||
);
|
||||
}
|
||||
public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRigthtTable = '')
|
||||
public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField, $sRightTable = '')
|
||||
{
|
||||
$this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField, $sRigthtTable);
|
||||
$this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField, $sRightTable);
|
||||
}
|
||||
public function AddInnerJoinTree($oSQLQuery, $sLeftFieldLeft, $sLeftFieldRight, $sRightFieldLeft, $sRightFieldRight, $sRightTableAlias = '', $iOperatorCode = TREE_OPERATOR_BELOW)
|
||||
{
|
||||
assert((get_class($oSQLQuery) == __CLASS__) || is_subclass_of($oSQLQuery, __CLASS__));
|
||||
if (empty($sRightTableAlias))
|
||||
{
|
||||
$sRightTableAlias = $oSQLQuery->m_sTableAlias;
|
||||
}
|
||||
$this->m_aJoinSelects[] = array(
|
||||
"jointype" => 'inner_tree',
|
||||
"select" => $oSQLQuery,
|
||||
"leftfield" => $sLeftFieldLeft,
|
||||
"rightfield" => $sLeftFieldRight,
|
||||
"rightfield_left" => $sRightFieldLeft,
|
||||
"rightfield_right" => $sRightFieldRight,
|
||||
"righttablealias" => $sRightTableAlias,
|
||||
"tree_operator" => $iOperatorCode);
|
||||
}
|
||||
public function AddLeftJoin($oSQLQuery, $sLeftField, $sRightField)
|
||||
{
|
||||
@@ -227,7 +243,6 @@ class SQLQuery
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sValues = self::ClauseValues($aSetValues);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
@@ -315,6 +330,7 @@ class SQLQuery
|
||||
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
|
||||
break;
|
||||
case "inner":
|
||||
case "inner_tree":
|
||||
$sFrom .= " INNER JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`";
|
||||
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
|
||||
$sFrom .= ") ON ".$aJoinInfo["joincondition"];
|
||||
@@ -368,12 +384,12 @@ class SQLQuery
|
||||
// Purpose: prepare the query data, once for all
|
||||
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
|
||||
{
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
|
||||
$oCondition = $this->m_oConditionExpr;
|
||||
return $sTableAlias;
|
||||
}
|
||||
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sJoinType = 'first', $sCallerAlias = '', $sLeftField = '', $sRightField = '', $sRightTableAlias = '')
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
|
||||
{
|
||||
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
|
||||
|
||||
@@ -381,12 +397,15 @@ class SQLQuery
|
||||
|
||||
// Handle the various kinds of join (or first table in the list)
|
||||
//
|
||||
if (empty($sRightTableAlias))
|
||||
if (empty($aJoinData['righttablealias']))
|
||||
{
|
||||
$sRightTableAlias = $this->m_sTableAlias;
|
||||
}
|
||||
$sJoinCond = "`$sCallerAlias`.`$sLeftField` = `$sRightTableAlias`.`$sRightField`";
|
||||
switch ($sJoinType)
|
||||
else
|
||||
{
|
||||
$sRightTableAlias = $aJoinData['righttablealias'];
|
||||
}
|
||||
switch ($aJoinData['jointype'])
|
||||
{
|
||||
case "first":
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>"first", "tablename"=>$this->m_sTable, "joincondition"=>"");
|
||||
@@ -394,7 +413,50 @@ class SQLQuery
|
||||
case "inner":
|
||||
case "left":
|
||||
// table or tablealias ???
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>$sJoinType, "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
|
||||
$sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`";
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
|
||||
break;
|
||||
case "inner_tree":
|
||||
$sNodeLeft = "`$sCallerAlias`.`{$aJoinData['leftfield']}`";
|
||||
$sNodeRight = "`$sCallerAlias`.`{$aJoinData['rightfield']}`";
|
||||
$sRootLeft = "`$sRightTableAlias`.`{$aJoinData['rightfield_left']}`";
|
||||
$sRootRight = "`$sRightTableAlias`.`{$aJoinData['rightfield_right']}`";
|
||||
switch($aJoinData['tree_operator'])
|
||||
{
|
||||
case TREE_OPERATOR_BELOW:
|
||||
$sJoinCond = "$sNodeLeft >= $sRootLeft AND $sNodeLeft <= $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_BELOW_STRICT:
|
||||
$sJoinCond = "$sNodeLeft > $sRootLeft AND $sNodeLeft < $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW: // Complementary of 'BELOW'
|
||||
$sJoinCond = "$sNodeLeft < $sRootLeft OR $sNodeLeft > $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_BELOW_STRICT: // Complementary of BELOW_STRICT
|
||||
$sJoinCond = "$sNodeLeft <= $sRootLeft OR $sNodeLeft >= $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE:
|
||||
$sJoinCond = "$sNodeLeft <= $sRootLeft AND $sNodeRight >= $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_ABOVE_STRICT:
|
||||
$sJoinCond = "$sNodeLeft < $sRootLeft AND $sNodeRight > $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE: // Complementary of 'ABOVE'
|
||||
$sJoinCond = "$sNodeLeft > $sRootLeft OR $sNodeRight < $sRootRight";
|
||||
break;
|
||||
|
||||
case TREE_OPERATOR_NOT_ABOVE_STRICT: // Complementary of ABOVE_STRICT
|
||||
$sJoinCond = "$sNodeLeft >= $sRootLeft OR $sNodeRight <= $sRootRight";
|
||||
break;
|
||||
|
||||
}
|
||||
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -409,6 +471,7 @@ class SQLQuery
|
||||
{
|
||||
$aDelTables[] = "`{$this->m_sTableAlias}`";
|
||||
}
|
||||
//echo "<p>in privRenderSingleTable this->m_aValues<pre>".print_r($this->m_aValues, true)."</pre></p>\n";
|
||||
foreach($this->m_aValues as $sFieldName=>$value)
|
||||
{
|
||||
$aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further!
|
||||
@@ -424,13 +487,13 @@ class SQLQuery
|
||||
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
|
||||
foreach ($this->m_aJoinSelects as $aJoinData)
|
||||
{
|
||||
$sJoinType = $aJoinData["jointype"];
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
$sLeftField = $aJoinData["leftfield"];
|
||||
$sRightField = $aJoinData["rightfield"];
|
||||
$sRightTableAlias = $aJoinData["righttablealias"];
|
||||
// $sJoinType = $aJoinData["jointype"];
|
||||
// $sLeftField = $aJoinData["leftfield"];
|
||||
// $sRightField = $aJoinData["rightfield"];
|
||||
// $sRightTableAlias = $aJoinData["righttablealias"];
|
||||
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField, $sRightTableAlias);
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
|
||||
}
|
||||
$aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom;
|
||||
|
||||
|
||||
@@ -105,6 +105,34 @@ abstract class TriggerOnObject extends Trigger
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
/**
|
||||
* To trigger notifications when a ticket is updated from the portal
|
||||
*/
|
||||
class TriggerOnPortalUpdate extends TriggerOnObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_trigger_onportalupdate",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TriggerOnStateChange extends TriggerOnObject
|
||||
{
|
||||
|
||||
@@ -405,18 +405,6 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
public static function CanLogOff()
|
||||
{
|
||||
if (!is_null(self::$m_oUser))
|
||||
{
|
||||
return self::$m_oUser->CanLogOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function ChangePassword($sOldPassword, $sNewPassword, $sName = '')
|
||||
{
|
||||
if (empty($sName))
|
||||
@@ -609,8 +597,6 @@ class UserRights
|
||||
if (!self::CheckLogin()) return true;
|
||||
|
||||
if (self::IsAdministrator()) return true;
|
||||
// Portal users actions are limited by the portal page...
|
||||
if (self::IsPortalUser()) return true;
|
||||
|
||||
if (MetaModel::HasCategory($sClass, 'bizmodel'))
|
||||
{
|
||||
@@ -863,7 +849,7 @@ class ActionChecker
|
||||
{
|
||||
$sClass = $this->oFilter->GetClass();
|
||||
$oSet = new DBObjectSet($this->oFilter);
|
||||
$iActionAllowed = UserRights::IsActionAllowed($sClass, $oSet, $this->iActionCode);
|
||||
$iActionAllowed = UserRights::IsActionAllowed($sClass, $this->iActionCode, $oSet);
|
||||
if ($iActionAllowed == UR_ALLOWED_DEPENDS)
|
||||
{
|
||||
// Check for each object if the action is allowed or not
|
||||
@@ -919,6 +905,8 @@ class StimulusChecker extends ActionChecker
|
||||
public function IsAllowed()
|
||||
{
|
||||
$sClass = $this->oFilter->GetClass();
|
||||
if (MetaModel::IsAbstract($sClass)) return UR_ALLOWED_NO; // Safeguard, not implemented if the base class of the set is abstract !
|
||||
|
||||
$oSet = new DBObjectSet($this->oFilter);
|
||||
$iActionAllowed = UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oSet);
|
||||
if ($iActionAllowed == UR_ALLOWED_NO)
|
||||
@@ -945,7 +933,7 @@ class StimulusChecker extends ActionChecker
|
||||
// of IsActionAllowed does not perform a 'per instance' check, we could
|
||||
// skip this second validation phase and assume it would return UR_ALLOWED_YES
|
||||
$oObjSet = DBObjectSet::FromArray($sClass, array($oObj));
|
||||
if (UserRights::IsActionAllowed($sClass, $this->iActionCode, $oObjSet) == UR_ALLOWED_NO)
|
||||
if (!UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oObjSet))
|
||||
{
|
||||
$this->aAllowedIDs[$oObj->GetKey()] = false;
|
||||
}
|
||||
|
||||
@@ -60,10 +60,12 @@ abstract class ValueSetDefinition
|
||||
}
|
||||
if (strlen($sContains) == 0)
|
||||
{
|
||||
// No filtering
|
||||
$aRet = $this->m_aValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Filter on results containing the needle <sContain>
|
||||
$aRet = array();
|
||||
foreach ($this->m_aValues as $sKey=>$sValue)
|
||||
{
|
||||
@@ -73,6 +75,7 @@ abstract class ValueSetDefinition
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort on the display value
|
||||
asort($aRet);
|
||||
return $aRet;
|
||||
}
|
||||
@@ -88,21 +91,62 @@ abstract class ValueSetDefinition
|
||||
*/
|
||||
class ValueSetObjects extends ValueSetDefinition
|
||||
{
|
||||
protected $m_sContains;
|
||||
protected $m_sFilterExpr; // in OQL
|
||||
protected $m_sValueAttCode;
|
||||
protected $m_aOrderBy;
|
||||
protected $m_aExtraConditions;
|
||||
private $m_bAllowAllData;
|
||||
|
||||
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false)
|
||||
{
|
||||
$this->m_sContains = '';
|
||||
$this->m_sFilterExpr = $sFilterExp;
|
||||
$this->m_sValueAttCode = $sValueAttCode;
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
$this->m_bAllowAllData = $bAllowAllData;
|
||||
$this->m_aExtraConditions = array();
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
public function AddCondition(DBObjectSearch $oFilter)
|
||||
{
|
||||
$this->m_aExtraConditions[] = $oFilter;
|
||||
}
|
||||
|
||||
public function ToObjectSet($aArgs = array(), $sContains = '')
|
||||
{
|
||||
if ($this->m_bAllowAllData)
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData($this->m_sFilterExpr);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
}
|
||||
foreach($this->m_aExtraConditions as $oExtraFilter)
|
||||
{
|
||||
$oFilter->MergeWith($oExtraFilter);
|
||||
}
|
||||
|
||||
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
|
||||
}
|
||||
|
||||
public function GetValues($aArgs, $sContains = '')
|
||||
{
|
||||
if (!$this->m_bIsLoaded || ($sContains != $this->m_sContains))
|
||||
{
|
||||
$this->LoadValues($aArgs, $sContains);
|
||||
$this->m_bIsLoaded = true;
|
||||
}
|
||||
// The results are already filtered and sorted (on friendly name)
|
||||
$aRet = $this->m_aValues;
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs, $sContains = '')
|
||||
{
|
||||
$this->m_sContains = $sContains;
|
||||
|
||||
$this->m_aValues = array();
|
||||
|
||||
if ($this->m_bAllowAllData)
|
||||
@@ -114,6 +158,15 @@ class ValueSetObjects extends ValueSetDefinition
|
||||
$oFilter = DBObjectSearch::FromOQL($this->m_sFilterExpr);
|
||||
}
|
||||
if (!$oFilter) return false;
|
||||
foreach($this->m_aExtraConditions as $oExtraFilter)
|
||||
{
|
||||
$oFilter->MergeWith($oExtraFilter);
|
||||
}
|
||||
|
||||
$oValueExpr = new ScalarExpression('%'.$sContains.'%');
|
||||
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
|
||||
$oNewCondition = new BinaryExpression($oNameExpr, 'LIKE', $oValueExpr);
|
||||
$oFilter->AddConditionExpression($oNewCondition);
|
||||
|
||||
$oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
|
||||
while ($oObject = $oObjects->Fetch())
|
||||
@@ -198,7 +251,7 @@ class ValueSetRelatedObjectsFromLinkSet extends ValueSetDefinition
|
||||
}
|
||||
// #@# or AddObjectArray($aObjects) ?
|
||||
$oSetToCreate = DBObjectSet::FromArray($this->m_sTargetLinkClass, $aLinksToCreate);
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetAsHTML($oObject->GetName());
|
||||
$this->m_aValues[$oObject->GetKey()] = $oObject->GetName();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -250,6 +303,34 @@ class ValueSetEnum extends ValueSetDefinition
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed set values, defined as a range: 0..59 (with an optional increment)
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
class ValueSetRange extends ValueSetDefinition
|
||||
{
|
||||
protected $m_iStart;
|
||||
protected $m_iEnd;
|
||||
|
||||
public function __construct($iStart, $iEnd, $iStep = 1)
|
||||
{
|
||||
$this->m_iStart = $iStart;
|
||||
$this->m_iEnd = $iEnd;
|
||||
$this->m_iStep = $iStep;
|
||||
}
|
||||
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
$iValue = $this->m_iStart;
|
||||
for($iValue = $this->m_iStart; $iValue <= $this->m_iEnd; $iValue += $this->m_iStep)
|
||||
{
|
||||
$this->m_aValues[$iValue] = $iValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Data model classes
|
||||
|
||||
@@ -402,8 +402,10 @@ div.itop_popup {
|
||||
|
||||
div.itop_popup > ul {
|
||||
height:19px;
|
||||
line-height: 17px;
|
||||
vertical-align: middle;
|
||||
display:block;
|
||||
width:70px; /* Nasty work-around for IE... en attendant mieux */
|
||||
nowidth:70px; /* Nasty work-around for IE... en attendant mieux */
|
||||
padding-left: 5px;
|
||||
background: url(../images/actions_left.png) no-repeat top left;
|
||||
cursor: pointer;
|
||||
@@ -414,7 +416,7 @@ div.itop_popup > ul > li {
|
||||
list-style: none;
|
||||
font-size: 11px;
|
||||
font-family: Tahoma,sans-serif;
|
||||
height: 19px;
|
||||
height: 17px;
|
||||
padding-right: 16px;
|
||||
padding-left: 4px;
|
||||
background: url(../images/actions_right.png) no-repeat top right transparent;
|
||||
@@ -1048,4 +1050,58 @@ fieldset table.details>tbody>tr>td {
|
||||
}
|
||||
.ac_dlg_loading {
|
||||
background: white url('../images/indicator.gif') right center no-repeat;
|
||||
}
|
||||
table.pagination {
|
||||
display:inline-block;
|
||||
}
|
||||
table.pagination tr td {
|
||||
padding: 3px;
|
||||
}
|
||||
.pager {
|
||||
float:left;
|
||||
}
|
||||
.pager p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.pager td span {
|
||||
min-width: 20px;
|
||||
display:inline-block;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pager td span.curr_page {
|
||||
color: #fff;
|
||||
background: #999;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
img.prev, img.first, img.next, img.last {
|
||||
cursor: pointer;
|
||||
}
|
||||
div.actions_button {
|
||||
float:right;
|
||||
background: url("../images/actions_left.png") no-repeat scroll left top transparent;
|
||||
padding-left: 5px;
|
||||
margin-top: 13px;
|
||||
margin-right: 10px;
|
||||
height:17px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.actions_button a, .actions_button a:hover, .actions_button a:visited {
|
||||
background:url(../images/actions_bkg.png) no-repeat scroll right top transparent;
|
||||
color:#fff;
|
||||
padding-right: 8px;
|
||||
cursor:pointer;
|
||||
font-family: Tahoma,sans-serif;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
padding-left: 4px;
|
||||
text-decoration: none;
|
||||
height:17px;
|
||||
line-height: 17px;
|
||||
display: block;
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
@@ -33,102 +34,102 @@
|
||||
// Class: CMDBChange
|
||||
//
|
||||
|
||||
Dict::Add('DE DE', 'English', 'English', array(
|
||||
'Core:AttributeLinkedSet' => 'Array of objects',
|
||||
'Core:AttributeLinkedSet+' => 'Any kind of objects [subclass] of the same class',
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Core:AttributeLinkedSet' => 'Array von Objekten',
|
||||
'Core:AttributeLinkedSet+' => 'Beliebige Art von Objekten der [subclass] der selben Klasse',
|
||||
|
||||
'Core:AttributeLinkedSetIndirect' => 'Array of objects (N-N)',
|
||||
'Core:AttributeLinkedSetIndirect+' => 'Any kind of objects [subclass] of the same class',
|
||||
'Core:AttributeLinkedSetIndirect' => 'Array von Objekten (N-N)',
|
||||
'Core:AttributeLinkedSetIndirect+' => 'Beliebige Art von Objekten der [subclass] der selben Klasse',
|
||||
|
||||
'Core:AttributeInteger' => 'Integer',
|
||||
'Core:AttributeInteger+' => 'Numeric value (could be negative)',
|
||||
'Core:AttributeInteger+' => 'Numerischer Wert (kann negativ sein)',
|
||||
|
||||
'Core:AttributeDecimal' => 'Decimal',
|
||||
'Core:AttributeDecimal+' => 'Decimal value (could be negative)',
|
||||
'Core:AttributeDecimal+' => 'Dezimaler Wert (kann negativ sein)',
|
||||
|
||||
'Core:AttributeBoolean' => 'Boolean',
|
||||
'Core:AttributeBoolean+' => 'Boolean',
|
||||
'Core:AttributeBoolean+' => 'Boolscher Wert',
|
||||
|
||||
'Core:AttributeString' => 'String',
|
||||
'Core:AttributeString+' => 'Alphanumeric string',
|
||||
'Core:AttributeString+' => 'Alphanumerischer String',
|
||||
|
||||
'Core:AttributeClass' => 'Class',
|
||||
'Core:AttributeClass+' => 'Class',
|
||||
|
||||
'Core:AttributeApplicationLanguage' => 'User language',
|
||||
'Core:AttributeApplicationLanguage+' => 'Language and country (EN US)',
|
||||
'Core:AttributeApplicationLanguage' => 'Benutzersprache',
|
||||
'Core:AttributeApplicationLanguage+' => 'Sprache und LAnd (DE DE)',
|
||||
|
||||
'Core:AttributeFinalClass' => 'Class (auto)',
|
||||
'Core:AttributeFinalClass+' => 'Real class of the object (automatically created by the core)',
|
||||
'Core:AttributeFinalClass+' => 'Echte Klasse des Objekt (automatisch erstellt durch den Core)',
|
||||
|
||||
'Core:AttributePassword' => 'Password',
|
||||
'Core:AttributePassword+' => 'Password of an external device',
|
||||
'Core:AttributePassword' => 'Passwort',
|
||||
'Core:AttributePassword+' => 'Passwort eines externen Geräts',
|
||||
|
||||
'Core:AttributeEncryptedString' => 'Encrypted string',
|
||||
'Core:AttributeEncryptedString+' => 'String encrypted with a local key',
|
||||
'Core:AttributeEncryptedString' => 'verschlüsselter String',
|
||||
'Core:AttributeEncryptedString+' => 'mit einem lokalen Schüssel verschlüsselter String',
|
||||
|
||||
'Core:AttributeText' => 'Text',
|
||||
'Core:AttributeText+' => 'Multiline character string',
|
||||
'Core:AttributeText+' => 'Mehrzeiliger String',
|
||||
|
||||
'Core:AttributeHTML' => 'HTML',
|
||||
'Core:AttributeHTML+' => 'HTML string',
|
||||
'Core:AttributeHTML+' => 'HTML-String',
|
||||
|
||||
'Core:AttributeEmailAddress' => 'Email address',
|
||||
'Core:AttributeEmailAddress+' => 'Email address',
|
||||
'Core:AttributeEmailAddress' => 'Email-Adresse',
|
||||
'Core:AttributeEmailAddress+' => 'Email-Adresse',
|
||||
|
||||
'Core:AttributeIPAddress' => 'IP address',
|
||||
'Core:AttributeIPAddress+' => 'IP address',
|
||||
'Core:AttributeIPAddress' => 'IP-Adresse',
|
||||
'Core:AttributeIPAddress+' => 'IP-Adresse',
|
||||
|
||||
'Core:AttributeOQL' => 'OQL',
|
||||
'Core:AttributeOQL+' => 'Object Query Langage expression',
|
||||
'Core:AttributeOQL+' => 'Object-Query-Langage-Ausdruck',
|
||||
|
||||
'Core:AttributeEnum' => 'Enum',
|
||||
'Core:AttributeEnum+' => 'List of predefined alphanumeric strings',
|
||||
'Core:AttributeEnum+' => 'Liste vordefinierter alphanumerischer Strings',
|
||||
|
||||
'Core:AttributeTemplateString' => 'Template string',
|
||||
'Core:AttributeTemplateString+' => 'String containing placeholders',
|
||||
'Core:AttributeTemplateString' => 'Vorlagen-String',
|
||||
'Core:AttributeTemplateString+' => 'String mit Platzhaltern',
|
||||
|
||||
'Core:AttributeTemplateText' => 'Template text',
|
||||
'Core:AttributeTemplateText+' => 'Text containing placeholders',
|
||||
'Core:AttributeTemplateText' => 'Vorlagen-Text',
|
||||
'Core:AttributeTemplateText+' => 'Text mit Platzhaltern',
|
||||
|
||||
'Core:AttributeTemplateHTML' => 'Template HTML',
|
||||
'Core:AttributeTemplateHTML+' => 'HTML containing placeholders',
|
||||
'Core:AttributeTemplateHTML' => 'Vorlagen-HTML',
|
||||
'Core:AttributeTemplateHTML+' => 'HTML mit Platzhaltern',
|
||||
|
||||
'Core:AttributeDateTime' => 'Date/time',
|
||||
'Core:AttributeDateTime+' => 'Date and time (year-month-day hh:mm:ss)',
|
||||
'Core:AttributeDateTime' => 'Datum/Uhrzeit',
|
||||
'Core:AttributeDateTime+' => 'Datum und Uhrzeit (Jahr-Monat-Tag hh:mm:ss)',
|
||||
|
||||
'Core:AttributeDate' => 'Date',
|
||||
'Core:AttributeDate+' => 'Date (year-month-day)',
|
||||
'Core:AttributeDate' => 'Datum',
|
||||
'Core:AttributeDate+' => 'Datum (Jahr-Monat-Tag)',
|
||||
|
||||
'Core:AttributeDeadline' => 'Deadline',
|
||||
'Core:AttributeDeadline+' => 'Date, displayed relatively to the current time',
|
||||
'Core:AttributeDeadline' => 'Frist',
|
||||
'Core:AttributeDeadline+' => 'relativ zur aktuellen Zeit angezeigtes Datum',
|
||||
|
||||
'Core:AttributeExternalKey' => 'External key',
|
||||
'Core:AttributeExternalKey+' => 'External (or foreign) key',
|
||||
'Core:AttributeExternalKey' => 'Externer Schlüssel',
|
||||
'Core:AttributeExternalKey+' => 'Externer (oder fremder) Schlüssel',
|
||||
|
||||
'Core:AttributeExternalField' => 'External field',
|
||||
'Core:AttributeExternalField+' => 'Field mapped from an external key',
|
||||
'Core:AttributeExternalField' => 'Externes Feld',
|
||||
'Core:AttributeExternalField+' => 'durch einen externen Schlüssel abgebildetes Feld',
|
||||
|
||||
'Core:AttributeURL' => 'URL',
|
||||
'Core:AttributeURL+' => 'Absolute or relative URL as a text string',
|
||||
'Core:AttributeURL+' => 'Absolute oder relative URL als Text-String',
|
||||
|
||||
'Core:AttributeBlob' => 'Blob',
|
||||
'Core:AttributeBlob+' => 'Any binary content (document)',
|
||||
'Core:AttributeBlob+' => 'Beliebiger binärer Inhalt (Dokument)',
|
||||
|
||||
'Core:AttributeOneWayPassword' => 'One way password',
|
||||
'Core:AttributeOneWayPassword+' => 'One way encrypted (hashed) password',
|
||||
'Core:AttributeOneWayPassword' => 'gehashtes Passwort',
|
||||
'Core:AttributeOneWayPassword+' => 'gehashtes Passwort',
|
||||
|
||||
'Core:AttributeTable' => 'Table',
|
||||
'Core:AttributeTable+' => 'Indexed array having two dimensions',
|
||||
'Core:AttributeTable' => 'Tabelle',
|
||||
'Core:AttributeTable+' => 'Indiziertes Array mit zwei Dimensionen',
|
||||
|
||||
'Core:AttributePropertySet' => 'Properties',
|
||||
'Core:AttributePropertySet+' => 'List of untyped properties (name and value)',
|
||||
'Core:AttributePropertySet' => 'Eigenschaften',
|
||||
'Core:AttributePropertySet+' => 'Liste typloser Eigenschaften (Name und Wert)',
|
||||
));
|
||||
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:CMDBChange' => 'Change',
|
||||
'Class:CMDBChange+' => 'Protokllierung der Changes',
|
||||
'Class:CMDBChange+' => 'Protokollierung der Changes',
|
||||
'Class:CMDBChange/Attribute:date' => 'Datum',
|
||||
'Class:CMDBChange/Attribute:date+' => 'Datum und Uhrzeit der Änderungen',
|
||||
'Class:CMDBChange/Attribute:userinfo' => 'Sonstige Informationen',
|
||||
@@ -200,8 +201,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
// Used by CMDBChangeOp... & derived classes
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Change:ObjectCreated' => 'Objekt erstellt',
|
||||
'Change:ObjectDeleted' => 'Object deleted',
|
||||
'Change:ObjectModified' => 'Object modified',
|
||||
'Change:ObjectDeleted' => 'Objekt gelöscht',
|
||||
'Change:ObjectModified' => 'Objekt geändert',
|
||||
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s geändert zu %2$s (vorheriger Wert: %3$s)',
|
||||
'Change:AttName_SetTo' => '%1$s geändert zu %2$s',
|
||||
'Change:Text_AppendedTo_AttName' => '%1$s zugefügt an %2$s',
|
||||
@@ -215,7 +216,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:CMDBChangeOpSetAttributeBlob' => 'Daten ändern',
|
||||
'Class:CMDBChangeOpSetAttributeBlob+' => 'Aufzeichnen der Data Changes',
|
||||
'Class:CMDBChangeOpSetAttributeBlob+' => 'Aufzeichnen der Datenänderung',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Vorherige Daten',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => 'Vorherige Inhalte des Attributes',
|
||||
));
|
||||
@@ -438,7 +439,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:TriggerOnStateEnter' => 'Trigger (beim Eintritt eines Status)',
|
||||
'Class:TriggerOnStateEnter+' => 'Trigger bei Eintritt einer Objektstatusänderungg',
|
||||
'Class:TriggerOnStateEnter+' => 'Trigger bei Eintritt einer Objektstatusänderung',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -447,7 +448,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:TriggerOnStateLeave' => 'Trigger (beim Verlassen eines Status)',
|
||||
'Class:TriggerOnStateLeave+' => 'Trigger beim Verlassen einer Objektstatusänderungg',
|
||||
'Class:TriggerOnStateLeave+' => 'Trigger beim Verlassen einer Objektstatusänderung',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -478,5 +479,218 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:lnkTriggerAction/Attribute:order+' => 'Reihenfolge der Aktionsausführungen',
|
||||
));
|
||||
|
||||
//
|
||||
// Synchro Data Source
|
||||
//
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:SynchroDataSource/Attribute:name' => 'Name',
|
||||
'Class:SynchroDataSource/Attribute:name+' => 'Name',
|
||||
'Class:SynchroDataSource/Attribute:description' => 'Beschreibung',
|
||||
'Class:SynchroDataSource/Attribute:status' => 'Status', //TODO: enum values
|
||||
'Class:SynchroDataSource/Attribute:scope_class' => 'Ziel-Klasse',
|
||||
'Class:SynchroDataSource/Attribute:user_id' => 'Benutzer',
|
||||
'Class:SynchroDataSource/Attribute:notify_contact_id' => 'zu benachrichtigender Kontakt',
|
||||
'Class:SynchroDataSource/Attribute:notify_contact_id+' => 'Kontakt, der im Fehlerfall benachrichtigt werden muß',
|
||||
'Class:SynchroDataSource/Attribute:url_icon' => 'Hyperlink zum Icon',
|
||||
'Class:SynchroDataSource/Attribute:url_icon+' => 'Ein (kleines) Bild verlinken, das die Applikation repräsentiert, mit der iTop synchronisiert wird',
|
||||
'Class:SynchroDataSource/Attribute:url_application' => 'Hyperlink zur Applikation',
|
||||
'Class:SynchroDataSource/Attribute:url_application+' => 'Hyperlink zum iTop Objekt in der externen Applikation mit der iTop synchronisiert wird (falls anwendbar). Mögliche Platzhalter: $this->attribute$ und $replica->primary_key$',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy' => 'Abgleichsvorgehen', //TODO enum values
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity' => 'Intervall zwischen zwei vollständigen Reloads',
|
||||
'Class:SynchroDataSource/Attribute:full_load_periodicity+' => 'Ein vollständiger Reload des gesamten Datenbestands muß mindestens in diesem Intervall erfolgen',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero' => 'Verhalten bei keinen Treffern',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero+' => 'Verhalten, wenn die Suche keine Objekte zurückgibt',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one' => 'Verhalten bei einem Treffer',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one+' => 'Verhalten, wenn die Suche genau ein Objekt zurückgibt',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple' => 'Verhalten bei vielen Treffern',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple+' => 'Verhalten, wenn die Suche mehr als ein Objekt zurückgibt',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'zugelassene Benutzer',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy+' => 'Benutzer, die synchronisierte Objekte löschen dürfen',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy' => 'zugelassene Benutzer',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:never' => 'Niemand',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:depends' => 'nur Administratoren',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:always' => 'Alle zugelassenen Benutzer',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update' => 'Update-Regeln',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_update+' => 'Syntax: Feld_Name:Wert; ...',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention' => 'Zeitraum bis zur endgültigen Löschung',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy_retention+' => 'Zeitraum, nach dem ein obsoletes Objekt endgültig gelöscht wird',
|
||||
'SynchroDataSource:Description' => 'Beschreibung',
|
||||
'SynchroDataSource:Reconciliation' => 'Suche & Abgleich',
|
||||
'SynchroDataSource:Deletion' => 'Löschregeln',
|
||||
'SynchroDataSource:Status' => 'Status',
|
||||
'SynchroDataSource:Information' => 'Information',
|
||||
'SynchroDataSource:Definition' => 'Definition',
|
||||
'Core:SynchroAttributes' => 'Attribute',
|
||||
'Core:SynchroStatus' => 'Status',
|
||||
'Core:Synchro:ErrorsLabel' => 'Fehler',
|
||||
'Core:Synchro:CreatedLabel' => 'erzeugt',
|
||||
'Core:Synchro:ModifiedLabel' => 'modifiziert',
|
||||
'Core:Synchro:UnchangedLabel' => 'unverändert',
|
||||
'Core:Synchro:ReconciledErrorsLabel' => 'Fehler',
|
||||
'Core:Synchro:ReconciledLabel' => 'abgeglichen',
|
||||
'Core:Synchro:ReconciledNewLabel' => 'erzeugt',
|
||||
'Core:SynchroReconcile:Yes' => 'Ja',
|
||||
'Core:SynchroReconcile:No' => 'Nein',
|
||||
'Core:SynchroUpdate:Yes' => 'Ja',
|
||||
'Core:SynchroUpdate:No' => 'Nein',
|
||||
'Core:Synchro:LastestStatus' => 'Neuester Status',
|
||||
'Core:Synchro:History' => 'Verlauf der Synchronisation',
|
||||
'Core:Synchro:NeverRun' => 'Synchronisation noch nicht erfolgt. Kein Protokoll verfügbar.',
|
||||
'Core:Synchro:SynchroEndedOn_Date' => 'Die letzte Synchronisation endete um %1$s.',
|
||||
'Core:Synchro:SynchroRunningStartedOn_Date' => 'Die Synchronisation, die um $1$s gestartet wurde, läuft noch ...',
|
||||
'Menu:DataSources' => 'Datenquellen für die Synchronisation',
|
||||
'Menu:DataSources+' => 'Alle Datenquellen für die Synchronisation',
|
||||
'Core:Synchro:label_repl_ignored' => 'Ignoriert (%1$s)',
|
||||
'Core:Synchro:label_repl_disappeared' => 'Verschwunden (%1$s)',
|
||||
'Core:Synchro:label_repl_existing' => 'Vorhanden (%1$s)',
|
||||
'Core:Synchro:label_repl_new' => 'Neu (%1$s)',
|
||||
'Core:Synchro:label_obj_deleted' => 'gelöscht (%1$s)',
|
||||
'Core:Synchro:label_obj_obsoleted' => 'obsolet (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_errors' => 'Fehler (%1$s)',
|
||||
'Core:Synchro:label_obj_disappeared_no_action' => 'Keine Aktion (%1$s)',
|
||||
'Core:Synchro:label_obj_unchanged' => 'unverändert (%1$s)',
|
||||
'Core:Synchro:label_obj_updated' => 'Updated (%1$s)',
|
||||
'Core:Synchro:label_obj_updated_errors' => 'Fehler (%1$s)',
|
||||
'Core:Synchro:label_obj_new_unchanged' => 'unverändert (%1$s)',
|
||||
'Core:Synchro:label_obj_new_updated' => 'updated (%1$s)',
|
||||
'Core:Synchro:label_obj_created' => 'erzeugt (%1$s)',
|
||||
'Core:Synchro:label_obj_new_errors' => 'Fehler (%1$s)',
|
||||
'Core:Synchro:History' => 'Synchronisations-Verlauf',
|
||||
'Core:SynchroLogTitle' => '%1$s - %2$s',
|
||||
'Core:Synchro:Nb_Replica' => 'Replica verarbeitet: %1$s',
|
||||
'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s',
|
||||
'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Mindestens ein Abgleichsschlüssel muß angegeben werden oder das Abgleichsvorgehen muß den primären Schlüssel verwenden.',
|
||||
'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'Der Zeitraum bis zur endgültigen Löschung muß angegeben werden, da die Objekte nach einer Kennzeichnung als obsolet gelöscht werden.',
|
||||
'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Obsolete Objekte werden aktualisiert, aber es wurde keine Aktualisierung angegeben.',
|
||||
'Core:SynchroReplica:PublicData' => 'Öffentliche Daten',
|
||||
'Core:SynchroReplica:PrivateDetails' => 'Private Hinweise',
|
||||
'Core:SynchroReplica:BackToDataSource' => 'Zurück zur Synchronisations-Datenquelle: %1$s',
|
||||
'Core:SynchroReplica:ListOfReplicas' => 'Liste der Replica',
|
||||
'Core:SynchroAttExtKey:ReconciliationById' => 'id (Primärschlüssel)',
|
||||
'Core:SynchroAtt:attcode' => 'Attribut',
|
||||
'Core:SynchroAtt:attcode+' => 'Feld des Objekts',
|
||||
'Core:SynchroAtt:reconciliation' => 'Abgleich',
|
||||
'Core:SynchroAtt:reconciliation+' => 'Für die Suche genutzt',
|
||||
'Core:SynchroAtt:update' => 'Update',
|
||||
'Core:SynchroAtt:update+' => 'Für die Aktualisierung des Objekts benutzt',
|
||||
'Core:SynchroAtt:update_policy' => 'Update Policy',
|
||||
'Core:SynchroAtt:update_policy+' => 'Verhalten des aktualisierten Feld',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => 'Abgleichsschlüssel',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => 'Attributscode für den Abgleich über einen externen Schlüssel',
|
||||
'Core:SyncDataExchangeComment' => '(DataExchange)',
|
||||
'Core:Synchro:ListOfDataSources' => 'Liste der Datenquellen:',
|
||||
'Core:Synchro:LastSynchro' => 'Letzte Synchronisation:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'Dieses Objekt wird mit einer externen Datenquelle synchronisiert',
|
||||
'Core:Synchro:TheObjectWasCreatedBy_Source' => 'Das Objekt wurde durch die externe Datenquelle %1$s <b>erzeugt</b>',
|
||||
'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'Das Objekt kann durch die externe Datenquelle %1$s <b>gelöscht werden</b>.',
|
||||
'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'Sie <b>können das Objekt nicht löschen</b>, weil es zur externen Datenquelle %1$s gehört',
|
||||
'TitleSynchroExecution' => 'Ausführung der Synchronisation',
|
||||
'Class:SynchroDataSource:DataTable' => 'Datenbanktabelle: %1$s',
|
||||
'Core:SyncDataSourceObsolete' => 'Die Datenquelle ist als obsolet markiert. Operation abgebrochen.',
|
||||
'Core:SyncDataSourceAccessRestriction' => 'Nur Administratoren oder die in der Datenquelle angegebenen Benutzer können diese Operation ausführen. Operation abgebrochen.',
|
||||
'Core:SyncTooManyMissingReplicas' => 'Alle Einträge wurden seit längerem nicht aktualisiert, alle Objekte könnten gelöscht werden. Bitte überprüfen Sie die Funktionalität der Synchronisation. Operation abgebrochen.',
|
||||
|
||||
'Class:AsyncSendEmail' => 'Email (asynchron)',
|
||||
'Class:AsyncSendEmail/Attribute:to' => 'An',
|
||||
'Class:AsyncSendEmail/Attribute:subject' => 'Betreff',
|
||||
'Class:AsyncSendEmail/Attribute:body' => 'Body',
|
||||
'Class:AsyncSendEmail/Attribute:header' => 'Header',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Verschlüsseltes Passwort',
|
||||
'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Vorheriger Wert',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted' => 'Verschlüsseltes Feld',
|
||||
'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Vorheriger Wert',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog' => 'Fall-Protokoll',
|
||||
'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'letzter Eintrag',
|
||||
'Class:SynchroDataSource' => 'Synchronisations-Datenquelle',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:implementation' => 'Implementation',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:obsolete' => 'Obsolet',
|
||||
'Class:SynchroDataSource/Attribute:status/Value:production' => 'Produktion',
|
||||
'Class:SynchroDataSource/Attribute:scope_restriction' => 'Anwendungsbereich',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_attributes' => 'Attribute benutzen',
|
||||
'Class:SynchroDataSource/Attribute:reconciliation_policy/Value:use_primary_key' => 'Feld primary_key benutzen',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:create' => 'Erzeugen',
|
||||
'Class:SynchroDataSource/Attribute:action_on_zero/Value:error' => 'Fehler',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:error' => 'Fehler',
|
||||
'Class:SynchroDataSource/Attribute:action_on_one/Value:update' => 'Update',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:create' => 'Erzeugen',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:error' => 'Fehler',
|
||||
'Class:SynchroDataSource/Attribute:action_on_multiple/Value:take_first' => 'ersten Treffer benutzen',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy' => 'Löschungs-Policy',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:delete' => 'Löschen',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:ignore' => 'Ignorieren',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update' => 'Update',
|
||||
'Class:SynchroDataSource/Attribute:delete_policy/Value:update_then_delete' => 'Update, danach Löschen',
|
||||
'Class:SynchroDataSource/Attribute:attribute_list' => 'Liste der Attribute',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'nur Administratoren',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Jeder darf solche Objekte löschen',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Niemand',
|
||||
'Class:SynchroAttribute' => 'Synchronisations-Attribut',
|
||||
'Class:SynchroAttribute/Attribute:sync_source_id' => 'Synchronisations-Datenquelle',
|
||||
'Class:SynchroAttribute/Attribute:attcode' => 'Attributs-Code',
|
||||
'Class:SynchroAttribute/Attribute:update' => 'Update',
|
||||
'Class:SynchroAttribute/Attribute:reconcile' => 'Abgleich',
|
||||
'Class:SynchroAttribute/Attribute:update_policy' => 'Update Policy',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'gesperrt',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'entsperrt',
|
||||
'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Initialisieren falls leer',
|
||||
'Class:SynchroAttribute/Attribute:finalclass' => 'Klasse',
|
||||
'Class:SynchroAttExtKey' => 'Synchronisations-Attribut (Externer Schlüssel)',
|
||||
'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Abgleichsattribut',
|
||||
'Class:SynchroAttLinkSet' => 'Synchronisations-Attribut (Linkset)',
|
||||
'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Reihen-Trenner',
|
||||
'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Attributs-Trenner',
|
||||
'Class:SynchroLog' => 'Synchronisations-Protokoll',
|
||||
'Class:SynchroLog/Attribute:sync_source_id' => 'Synchronisations-Datenquelle',
|
||||
'Class:SynchroLog/Attribute:start_date' => 'Anfangsdatum',
|
||||
'Class:SynchroLog/Attribute:end_date' => 'Enddatum',
|
||||
'Class:SynchroLog/Attribute:status' => 'Status',
|
||||
'Class:SynchroLog/Attribute:status/Value:completed' => 'vervollständigt',
|
||||
'Class:SynchroLog/Attribute:status/Value:error' => 'Fehler',
|
||||
'Class:SynchroLog/Attribute:status/Value:running' => 'noch in Betrieb',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb replica vorhanden',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb replica insgesamt',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb Objekte gelöscht',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb Fehler während des Löschvorgangs',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb Objekte obsolet',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb Fehler während des Obsolet-Machens',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb Objekte erzeugt',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb oder Fehler während der Erzeugung',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb Objekte aktualisiert',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb Fehler während der Aktualisierung',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb Fehler während des Abgleichs',
|
||||
'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb replica verschwunden',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb Objekte aktualisiert',
|
||||
'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb Objekte nicht verändert',
|
||||
'Class:SynchroLog/Attribute:last_error' => 'Letzter Fehler',
|
||||
'Class:SynchroLog/Attribute:traces' => 'Traces',
|
||||
'Class:SynchroReplica' => 'Synchronisations-Replica',
|
||||
'Class:SynchroReplica/Attribute:sync_source_id' => 'Synchronisations-Datenquelle',
|
||||
'Class:SynchroReplica/Attribute:dest_id' => 'Ziel-Objekt (ID)',
|
||||
'Class:SynchroReplica/Attribute:dest_class' => 'Ziel-Typ',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'Zuletzt gesehen',
|
||||
'Class:SynchroReplica/Attribute:status' => 'Status',
|
||||
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modifiziert',
|
||||
'Class:SynchroReplica/Attribute:status/Value:new' => 'Neu',
|
||||
'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Obsolete',
|
||||
'Class:SynchroReplica/Attribute:status/Value:orphan' => 'Verwaist',
|
||||
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Synchronisiert',
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Objekt erzeugt',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => 'Letzter Fehler',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Erzeugungs-Datum',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Datum der letzten Modifikation',
|
||||
'Class:appUserPreferences' => 'Benutzer-Voreinstellungen',
|
||||
'Class:appUserPreferences/Attribute:userid' => 'Benutzer',
|
||||
'Class:appUserPreferences/Attribute:preferences' => 'Voreinstellungen',
|
||||
));
|
||||
|
||||
//
|
||||
// Attribute Duration
|
||||
//
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Core:Duration_Seconds' => '%1$ds',
|
||||
'Core:Duration_Minutes_Seconds' =>'%1$dmin %2$ds',
|
||||
'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$ds',
|
||||
'Core:Duration_Days_Hours_Minutes_Seconds' => '%1$sd %2$dh %3$dmin %4$ds',
|
||||
));
|
||||
|
||||
?>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
@@ -100,7 +101,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:AuditRule/Attribute:query' => 'Durchzuführende Abfrage',
|
||||
'Class:AuditRule/Attribute:query+' => 'Die auszuführende OQL-Abfrage',
|
||||
'Class:AuditRule/Attribute:valid_flag' => 'Gültiges Objekt?',
|
||||
'Class:AuditRule/Attribute:valid_flag+' => 'True falls die Regel ein gültiges Objekt zurückgibt, andernfalls false',
|
||||
'Class:AuditRule/Attribute:valid_flag+' => 'true falls die Regel ein gültiges Objekt zurückgibt, andernfalls false',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true' => 'true',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true+' => 'true',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false' => 'false',
|
||||
@@ -340,7 +341,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
<p>Alle Module können nacheinander und vollständig unabhängig voneinander eingerichtet werden.</p>',
|
||||
|
||||
'UI:WelcomeMenu:RightBlock' => '<p>iTop ist mandantenfähig, es erlaubt IT-Technikern, auf einfache Art eine Vielzahl an Kunden und Firmen zu verwalten.
|
||||
<ul>iTop bietet ein umfangreiches Set an Business-Prozessen, die..
|
||||
<ul>iTop bietet ein umfangreiches Set an Business-Prozessen, die
|
||||
<li>die Effizienz des IT-Managements steigern,</li>
|
||||
<li>die die Performance des IT-Betriebs steuern,</li>
|
||||
<li>die Kundenzufriedenheit verbessern und Führungskräften Einsicht in die Business Performance ermöglichen.</li>
|
||||
@@ -348,7 +349,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
</p>
|
||||
<p>iTop ist komplett offen, damit es sich bestmöglich in Ihre derzeitige IT-Management-Infrastruktur integriert.</p>
|
||||
<p>
|
||||
<ul>Die neue Generation des IT Operational Portals ermöglicht Ihnen ...
|
||||
<ul>Die neue Generation des IT Operational Portals ermöglicht Ihnen
|
||||
<li>ein besseres Management in einer immer komplexeren IT-Landschaft,</li>
|
||||
<li>die ITIL-Prozesse gemäß dem Rhythmus Ihres Unternehmens einzuführen,</li>
|
||||
<li>und ein besseres Verwalten des wichtigsten Bestandteiles Ihrer IT: der Dokumentation.</li>
|
||||
@@ -404,9 +405,9 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:Error:UploadedFileTooBig' => 'Die hochgeladene Datei ist zu groß. (Maximal erlaubte Dateigröße ist %1$s. Überprüfen Sie upload_max_filesize und post_max_size in der PHP-Konfiguration.',
|
||||
'UI:Error:UploadedFileTruncated.' => 'Hochgeladene Datei wurde beschränkt!',
|
||||
'UI:Error:NoTmpDir' => 'Der temporäre Ordner ist nicht definiert.',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => 'Nicht möglich, die tempöräre Datei auf die Festplatte zu speicher: upload_tmp_dir = "%1$s".',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => 'Nicht möglich, die tempöräre Datei auf die Festplatte zu speichern: upload_tmp_dir = "%1$s".',
|
||||
'UI:Error:UploadStoppedByExtension_FileName' => 'Der Upload wurde von der Erweiterung gestoppt. (urspünglicher Dateiname = "%1$s").',
|
||||
'UI:Error:UploadFailedUnknownCause_Code' => 'Dateiupload fehlgeschStandortn, unbekannte Ursache (Fehlercode = "%1$s").',
|
||||
'UI:Error:UploadFailedUnknownCause_Code' => 'Dateiupload fehlgeschlagen, unbekannte Ursache (Fehlercode = "%1$s").',
|
||||
|
||||
'UI:Error:1ParametersMissing' => 'Fehler: der folgende Parameter muss für diese Operation spezifiziert sein: %1$s.',
|
||||
'UI:Error:2ParametersMissing' => 'Fehler: die folgenden Parameter müssen für diese Operation spezifiziert sein: %1$s und %2$s.',
|
||||
@@ -446,7 +447,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:History:StatsDeletes' => 'Deleted',
|
||||
'UI:History:StatsDeletes+' => 'Count of objects deleted',
|
||||
'UI:Loading' => 'Laden...',
|
||||
'UI:Menu:Actions' => 'Aktionen',
|
||||
'UI:Menu:Actions' => 'Aktionen',
|
||||
'UI:Menu:OtherActions' => 'Andere Aktionen',
|
||||
'UI:Menu:New' => 'Neu...',
|
||||
'UI:Menu:Add' => 'Hinzufügen...',
|
||||
'UI:Menu:Manage' => 'Verwalten...',
|
||||
@@ -487,15 +489,15 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:LogOff:ThankYou' => 'Vielen Dank dafür, dass Sie iTop benutzen!',
|
||||
'UI:LogOff:ClickHereToLoginAgain' => 'Klicken Sie hier, um sich wieder anzumelden...',
|
||||
'UI:ChangePwdMenu' => 'Passwort ändern...',
|
||||
'UI:AccessRO-All' => 'iTop is read-only',
|
||||
'UI:AccessRO-Users' => 'iTop is read-only for end-users',
|
||||
'UI:Login:RetypePwdDoesNotMatch' => 'Neues Passwort und das wiederholte Passwort entsprechen nicht überein!',
|
||||
'UI:Button:Login' => 'iTop betreten',
|
||||
'UI:Login:Error:AccessRestricted' => 'Der iTop-Zugang ist gesperrt. Bitte kontaktieren Sie einen iTop-Administrator.',
|
||||
'UI:AccessRO-All' => 'iTop ist nur lesbar',
|
||||
'UI:AccessRO-Users' => 'iTop ist nur lesbar für Endnutzer',
|
||||
'UI:Login:RetypePwdDoesNotMatch' => 'Neues Passwort und das wiederholte Passwort stimmen nicht überein!',
|
||||
'UI:Button:Login' => 'in iTop anmelden',
|
||||
'UI:Login:Error:AccessRestricted' => 'Der iTop-Zugang ist gesperrt. Bitte kontaktieren Sie Ihren iTop-Administrator.',
|
||||
'UI:Login:Error:AccessAdmin' => 'Zugang nur für Personen mit Administratorrechten. Bitte kontaktieren Sie Ihren iTop-Administrator.',
|
||||
'UI:CSVImport:MappingSelectOne' => 'Bitte wählen',
|
||||
'UI:CSVImport:MappingNotApplicable' => '-- Dieses Feld ignorieren --',
|
||||
'UI:CSVImport:NoData' => 'Keine Daten eingegeben...Bitte geben Sie Daten ein!',
|
||||
'UI:CSVImport:NoData' => 'Keine Daten eingegeben ... bitte geben Sie Daten ein!',
|
||||
'UI:Title:DataPreview' => 'Datenvorschau',
|
||||
'UI:CSVImport:ErrorOnlyOneColumn' => 'Fehler: die Daten behinhalten nur eine Spalte. Haben Sie das dazugehörige Trennzeichen ausgewählt?',
|
||||
'UI:CSVImport:FieldName' => 'Feld %1$d',
|
||||
@@ -505,7 +507,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:Title:BulkImport' => 'iTop - Massenimport',
|
||||
'UI:Title:BulkImport+' => 'CSV-Import-Assistent',
|
||||
'UI:CSVImport:ClassesSelectOne' => 'Bitte wählen',
|
||||
'UI:CSVImport:ErrorExtendedAttCode' => 'Interner Fehler: "%1$s" ist ungültiger Code. Begründung "%2$s" ist NICHT ein externe Schlüssel der Klasse "%3$s"',
|
||||
'UI:CSVImport:ErrorExtendedAttCode' => 'Interner Fehler: "%1$s" ist ungültiger Code. Begründung "%2$s" ist NICHT ein externer Schlüssel der Klasse "%3$s"',
|
||||
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d Objekte bleiben unverändert.',
|
||||
'UI:CSVImport:ObjectsWillBeModified' => '%1$d Objekte werden verändert.',
|
||||
'UI:CSVImport:ObjectsWillBeAdded' => '%1$d Objekte werden hinzugefügt.',
|
||||
@@ -577,7 +579,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:Schema:Title' => 'iTop Objekte-Schema',
|
||||
'UI:Schema:CategoryMenuItem' => 'Kategorie <b>%1$s</b>',
|
||||
'UI:Schema:Relationships' => 'Wechselseite Beziehungen',
|
||||
'UI:Schema:AbstractClass' => 'Abstrakte Klasse: kein Objekt dieser Klasse kann instanziiert werden.',
|
||||
'UI:Schema:AbstractClass' => 'Abstrakte Klasse: ein Objekt dieser Klasse kann nicht instanziiert werden.',
|
||||
'UI:Schema:NonAbstractClass' => 'Keine abstrakte Klasse: Objekte dieser Klasse können instanziiert werden.',
|
||||
'UI:Schema:ClassHierarchyTitle' => 'Klassenhierarchie',
|
||||
'UI:Schema:AllClasses' => 'Alle Klassen',
|
||||
@@ -604,9 +606,9 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:Schema:MoreInfo+' => 'Mehr Informationen zu dem Feld aus der Datenbank',
|
||||
'UI:Schema:SearchCriteria' => 'Suchkriterium',
|
||||
'UI:Schema:FilterCode' => 'Code filtern',
|
||||
'UI:Schema:FilterCode+' => 'Code dieses Suchkriterium',
|
||||
'UI:Schema:FilterCode+' => 'Code für dieses Suchkriterium',
|
||||
'UI:Schema:FilterDescription' => 'Beschreibung',
|
||||
'UI:Schema:FilterDescription+' => 'Beschreibung dieses Suchkriterium',
|
||||
'UI:Schema:FilterDescription+' => 'Beschreibung dieses Suchkriteriums',
|
||||
'UI:Schema:AvailOperators' => 'Verfügbare Operatoren',
|
||||
'UI:Schema:AvailOperators+' => 'Mögliche Operatoren für dieses Suchkriterium',
|
||||
'UI:Schema:ChildClasses' => 'Kind-Klassen',
|
||||
@@ -653,7 +655,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => 'Massenlöschung von %1$d Objekten der %2$s',
|
||||
'UI:Delete:NotAllowedToDelete' => 'Sie sind nicht berechtigt, dieses Objekt zu löschen.',
|
||||
'UI:Delete:NotAllowedToUpdate_Fields' => 'Sie sind nicht berechtigt, die folgenden Felder zu aktualisieren: %1$s',
|
||||
'UI:Error:CannotDeleteBecause' => 'This object could not be deleted because: %1$s',
|
||||
'UI:Error:CannotDeleteBecause' => 'Dieses Objekt konnte aus folgendem Grund nicht gelöscht werden: %1$s',
|
||||
'UI:Error:NotEnoughRightsToDelete' => 'Dieses Objekt konnte nicht gelöscht werden, da der derzeitige Benutzer nicht die notwendigen Rechte dazu besitzt.',
|
||||
'UI:Error:CannotDeleteBecauseOfDepencies' => 'Dieses Objekt konnte nicht gelöscht werden, da zuerst dazu einige manuelle Operationen durchgeführt werden müssen.',
|
||||
'UI:Archive_User_OnBehalfOf_User' => '%1$s im Auftrag von %2$s',
|
||||
@@ -675,19 +677,19 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$d Objekte/Links referenzieren einige der zu löschenden Objekte',
|
||||
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'Um Datenbankintegrität sicherzustellen sollten alle weiteren Referenzen entfernt werden.',
|
||||
'UI:Delete:Consequence+' => 'Was getan wird',
|
||||
'UI:Delete:SorryDeletionNotAllowed' => 'Entschuldigung, Ihnen ist es nicht gestattet, dieses Objekt zu löschen. Eine ausführliche Erklärung dazu finden Sie oben',
|
||||
'UI:Delete:SorryDeletionNotAllowed' => 'Leider ist Ihnen nicht gestattet, dieses Objekt zu löschen. Eine ausführliche Erklärung dazu finden Sie oben',
|
||||
'UI:Delete:PleaseDoTheManualOperations' => 'Bitte führen Sie die oben aufgelisteten manuellen Operationen zuerst durch, bevor Sie dieses Objekt löschen.',
|
||||
'UI:Delect:Confirm_Object' => 'Bitte bestätigen Sie, dass Sie %1$s löschen möchten.',
|
||||
'UI:Delect:Confirm_Count_ObjectsOf_Class' => 'Bitte bestätigen Sie, dasss Sie die folgenden %1$d Objekte der Klasse %2$s löschen möchten.',
|
||||
'UI:WelcomeToITop' => 'Willkommen bei iTop',
|
||||
'UI:DetailsPageTitle' => 'iTop - %1$s - %2$s Details',
|
||||
'UI:ErrorPageTitle' => 'iTop - Fehler',
|
||||
'UI:ObjectDoesNotExist' => 'Entschuldigung, dieses Objekt exisitert nicht oder Sie sind nicht berechtigt es einzusehen.',
|
||||
'UI:ObjectDoesNotExist' => 'Leider existiert dieses Objekt nicht oder Sie sind nicht berechtigt es einzusehen.',
|
||||
'UI:SearchResultsPageTitle' => 'iTop - Suchergebnisse',
|
||||
'UI:Search:NoSearch' => 'Nichts, wonach man suchen kann...',
|
||||
'UI:Search:NoSearch' => 'Kein Suchbegriff eingegeben',
|
||||
'UI:FullTextSearchTitle_Text' => 'Ergebnisse für "%1$s":',
|
||||
'UI:Search:Count_ObjectsOf_Class_Found' => '%1$d Objekt(e) der Klasse %2$s gefunden.',
|
||||
'UI:Search:NoObjectFound' => 'Kein Objekt gefunden.',
|
||||
'UI:Search:NoObjectFound' => 'Kein Objekt gefunden',
|
||||
'UI:ModificationPageTitle_Object_Class' => 'iTop - %1$s - %2$s Änderungen',
|
||||
'UI:ModificationTitle_Class_Object' => 'Änderungen von %1$s: <span class=\"hilite\">%2$s</span>',
|
||||
'UI:ClonePageTitle_Object_Class' => 'iTop - Dupliziere %1$s - %2$s Änderung',
|
||||
@@ -703,7 +705,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:Title:Object_Of_Class_Created' => '%1$s - %2$s erstellt.',
|
||||
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => 'Anwenden von %1$s auf Objekt: %2$s in Status %3$s zu Zielstatus: %4$s.',
|
||||
'UI:PageTitle:FatalError' => 'iTop - Fataler Fehler',
|
||||
'UI:FatalErrorMessage' => 'Fataler Fehler! iTop kann leider nicht forfahren.',
|
||||
'UI:FatalErrorMessage' => 'Fataler Fehler! iTop kann leider nicht fortfahren.',
|
||||
'UI:Error_Details' => 'Fehler: %1$s.',
|
||||
|
||||
'UI:PageTitle:ClassProjections' => 'iTop Benutzerverwaltung - Klassenabbildung',
|
||||
@@ -714,7 +716,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'UI:UserManagement:ProjectedObject+' => 'Geschütztes Objekt',
|
||||
'UI:UserManagement:AnyObject' => '* beliebig *',
|
||||
'UI:UserManagement:User' => 'Benutzer',
|
||||
'UI:UserManagement:User+' => 'Benutzer, der in Abbildung beteilgt ist.',
|
||||
'UI:UserManagement:User+' => 'Benutzer, der in Abbildung beteiligt ist.',
|
||||
'UI:UserManagement:Profile' => 'Profil',
|
||||
'UI:UserManagement:Profile+' => 'Profil, in welchem die Abbildung spezifiziert wird.',
|
||||
'UI:UserManagement:Action:Read' => 'Lesen',
|
||||
|
||||
@@ -86,9 +86,36 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
|
||||
'Core:AttributeDateTime' => 'Date/time',
|
||||
'Core:AttributeDateTime+' => 'Date and time (year-month-day hh:mm:ss)',
|
||||
'Core:AttributeDateTime?SmartSearch' => '
|
||||
<p>
|
||||
Date format:<br/>
|
||||
<b>yyyy-mm-dd hh:mm:ss</b><br/>
|
||||
Example: 2011-07-19 18:40:00
|
||||
</p>
|
||||
<p>
|
||||
Operators:<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>
|
||||
<p>
|
||||
If the time is omitted, it defaults to 00:00:00
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDate' => 'Date',
|
||||
'Core:AttributeDate+' => 'Date (year-month-day)',
|
||||
'Core:AttributeDate?SmartSearch' => '
|
||||
<p>
|
||||
Date format:<br/>
|
||||
<b>yyyy-mm-dd</b><br/>
|
||||
Example: 2011-07-19
|
||||
</p>
|
||||
<p>
|
||||
Operators:<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDeadline' => 'Deadline',
|
||||
'Core:AttributeDeadline+' => 'Date, displayed relatively to the current time',
|
||||
@@ -436,6 +463,15 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:TriggerOnObject/Attribute:target_class+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnPortalUpdate
|
||||
//
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:TriggerOnPortalUpdate' => 'Trigger (when updated from the portal)',
|
||||
'Class:TriggerOnPortalUpdate+' => 'Trigger on a end-user\'s update from the portal',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnStateChange
|
||||
//
|
||||
@@ -591,7 +627,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Core:SynchroAtt:update_policy+' => 'Behavior of the updated field',
|
||||
'Core:SynchroAtt:reconciliation_attcode' => 'Reconciliation Key',
|
||||
'Core:SynchroAtt:reconciliation_attcode+' => 'Attribute Code for the External Key Reconciliation',
|
||||
'Core:SyncDataExchangeComment' => '(DataExchange)',
|
||||
'Core:SyncDataExchangeComment' => '(Data Synchro)',
|
||||
'Core:Synchro:ListOfDataSources' => 'List of data sources:',
|
||||
'Core:Synchro:LastSynchro' => 'Last synchronization:',
|
||||
'Core:Synchro:ThisObjectIsSynchronized' => 'This object is synchronized with an external data source',
|
||||
|
||||
@@ -367,7 +367,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'Incorrect link definition: the class of objects to manage: %1$s was not found as an external key in the class %2$s',
|
||||
'UI:Error:Object_Class_Id_NotFound' => 'Object: %1$s:%2$d not found.',
|
||||
'UI:Error:WizardCircularReferenceInDependencies' => 'Error: Circular reference in the dependencies between the fields, check the data model.',
|
||||
'UI:Error:UploadedFileTooBig' => 'Uploaded file is too big. (Max allowed size is %1$s). Check you PHP configuration for upload_max_filesize and post_max_size.',
|
||||
'UI:Error:UploadedFileTooBig' => 'The uploaded file is too big. (Max allowed size is %1$s). To modify this limit, contact your iTop administrator. (Check the PHP configuration for upload_max_filesize and post_max_size on the server).',
|
||||
'UI:Error:UploadedFileTruncated.' => 'Uploaded file has been truncated !',
|
||||
'UI:Error:NoTmpDir' => 'The temporary directory is not defined.',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => 'Unable to write the temporary file to the disk. upload_tmp_dir = "%1$s".',
|
||||
@@ -416,6 +416,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:History:StatsDeletes+' => 'Count of objects deleted',
|
||||
'UI:Loading' => 'Loading...',
|
||||
'UI:Menu:Actions' => 'Actions',
|
||||
'UI:Menu:OtherActions' => 'Other Actions',
|
||||
'UI:Menu:New' => 'New...',
|
||||
'UI:Menu:Add' => 'Add...',
|
||||
'UI:Menu:Manage' => 'Manage...',
|
||||
@@ -915,5 +916,17 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:ActionNotAllowed' => 'You are not allowed to perform this action on these objects.',
|
||||
'UI:BulkAction:NoObjectSelected' => 'Please select at least one object to perform this operation',
|
||||
'UI:AttemptingToChangeASlaveAttribute_Name' => 'The field %1$s is not writable because it is mastered by the data synchronization. Value remains unchanged.',
|
||||
'UI:Pagination:HeaderSelection' => 'Total: %1$s objects (%2$s objects selected).',
|
||||
'UI:Pagination:HeaderNoSelection' => 'Total: %1$s objects.',
|
||||
'UI:Pagination:PageSize' => '%1$s objects per page',
|
||||
'UI:Pagination:PagesLabel' => 'Pages:',
|
||||
'UI:Pagination:All' => 'All',
|
||||
'UI:HierarchyOf_Class' => 'Hierarchy of %1$s',
|
||||
'UI:Preferences' => 'Preferences...',
|
||||
'UI:FavoriteOrganizations' => 'My Favorite Organizations',
|
||||
'UI:FavoriteOrganizations+' => 'Check in the list below the organizations that you want to see in the drop-down menu for a quick access. '.
|
||||
'Note that this is not a security setting, objects from any organization are still visible and can be accessed by selecting "All Organizations" in the drop-down list.',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Any modification will be discarded.',
|
||||
'UI:Create_Class_InState' => 'Create the %1$s in state: ',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
Dict::Add('ES CR', 'English', 'English', array(
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Core:AttributeLinkedSet' => 'Array of objects',
|
||||
'Core:AttributeLinkedSet+' => 'Any kind of objects [subclass] of the same class',
|
||||
|
||||
|
||||
@@ -414,6 +414,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'UI:History:Changes+' => 'Chambios hechos al objeto',
|
||||
'UI:Loading' => 'Cargando...',
|
||||
'UI:Menu:Actions' => 'Acciones',
|
||||
'UI:Menu:OtherActions' => 'Otras Acciones',
|
||||
'UI:Menu:New' => 'Nuevo...',
|
||||
'UI:History:StatsCreations' => 'Created',
|
||||
'UI:History:StatsCreations+' => 'Count of objects created',
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', array(
|
||||
@@ -48,9 +48,11 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:ActionEmail/Attribute:importance/Value:low+' => '',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal' => 'Normale',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal+' => '',
|
||||
'Class:TriggerOnPortalUpdate' => 'Déclencheur sur mise à jour depuis le portail',
|
||||
'Class:TriggerOnPortalUpdate+' => '',
|
||||
'Class:TriggerOnStateEnter' => 'Déclencheur sur un objet entrant dans un état',
|
||||
'Class:TriggerOnStateEnter+' => '',
|
||||
'Class:TriggerOnStateLeave' => 'Déclencheur sur un objet quitant un état',
|
||||
'Class:TriggerOnStateLeave' => 'Déclencheur sur un objet quittant un état',
|
||||
'Class:TriggerOnStateLeave+' => '',
|
||||
'Class:TriggerOnObjectCreate' => 'Déclencheur sur la création d\'un objet',
|
||||
'Class:TriggerOnObjectCreate+' => '',
|
||||
@@ -436,8 +438,35 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Core:AttributeTemplateHTML+' => 'HTML contenant des espaces réservés pour des données iTop',
|
||||
'Core:AttributeDateTime' => 'Date/heure',
|
||||
'Core:AttributeDateTime+' => 'Date et heure (année-mois-jour hh:mm:ss)',
|
||||
'Core:AttributeDateTime?SmartSearch' => '
|
||||
<p>
|
||||
Format de date :<br/>
|
||||
<b>aaaa-mm-jj hh:mm:ss</b><br/>
|
||||
Exemple : 2011-07-19 18:40:00
|
||||
</p>
|
||||
<p>
|
||||
Opérateurs :<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>
|
||||
<p>
|
||||
Si l\'heure n\'est pas spécifiée, cela revient à 00:00:00 (minuit)
|
||||
</p>',
|
||||
'Core:AttributeDate' => 'Date',
|
||||
'Core:AttributeDate+' => 'Date (année-mois-jour)',
|
||||
'Core:AttributeDate?SmartSearch' => '
|
||||
<p>
|
||||
Format de date :<br/>
|
||||
<b>aaaa-mm-jj</b><br/>
|
||||
Exemple : 2011-07-19
|
||||
</p>
|
||||
<p>
|
||||
Opérateurs :<br/>
|
||||
<b>></b><em>date</em><br/>
|
||||
<b><</b><em>date</em><br/>
|
||||
<b>[</b><em>date</em>,<em>date</em><b>]</b>
|
||||
</p>',
|
||||
'Core:AttributeDeadline' => 'Délai',
|
||||
'Core:AttributeDeadline+' => 'Date/heure exprimée relativement à l\'heure courante',
|
||||
'Core:AttributeExternalKey' => 'Clé externe',
|
||||
@@ -483,7 +512,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:Action/Attribute:finalclass+' => '',
|
||||
'Class:ActionNotification' => 'notification',
|
||||
'Class:ActionNotification+' => '',
|
||||
'Class:Trigger' => 'trigger',
|
||||
'Class:Trigger' => 'Déclencheur',
|
||||
'Class:Trigger+' => '',
|
||||
'Class:Trigger/Attribute:description' => 'Description',
|
||||
'Class:Trigger/Attribute:description+' => '',
|
||||
|
||||
@@ -257,7 +257,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'la définition du lien est incorrecte: la classe d\'objets à gérer: %1$s n\'est référencée par aucune clef externe de la classe %2$s',
|
||||
'UI:Error:Object_Class_Id_NotFound' => 'L\'objet: %1$s:%2$d est introuvable.',
|
||||
'UI:Error:WizardCircularReferenceInDependencies' => 'Erreur: Référence circulaire entre les dépendences entre champs, vérifiez le modèle de données.',
|
||||
'UI:Error:UploadedFileTooBig' => 'Le fichier téléchargé est trop gros. (La taille maximale autorisée est %1$s). Vérifiez la valeur des variables upload_max_filesize et post_max_size dans la configuration PHP.',
|
||||
'UI:Error:UploadedFileTooBig' => 'Le fichier téléchargé est trop gros. (La taille maximale autorisée est %1$s). Pour modifier cette limite contactez votre administrateur iTop. (Réglages upload_max_filesize et post_max_size dans la configuration PHP sur le serveur)',
|
||||
'UI:Error:UploadedFileTruncated.' => 'Le fichier téléchargé a été tronqué !',
|
||||
'UI:Error:NoTmpDir' => 'Il n\'y a aucun répertoire temporaire de défini.',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => 'Impossible d\'écrire le fichier temporaire sur disque. upload_tmp_dir = "%1$s".',
|
||||
@@ -303,6 +303,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:History:StatsDeletes+' => 'Nombre d\'objets effacés',
|
||||
'UI:Loading' => 'Chargement...',
|
||||
'UI:Menu:Actions' => 'Actions',
|
||||
'UI:Menu:OtherActions' => 'Autres Actions',
|
||||
'UI:Menu:New' => 'Créer...',
|
||||
'UI:Menu:Add' => 'Ajouter...',
|
||||
'UI:Menu:Manage' => 'Gérer...',
|
||||
@@ -697,7 +698,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:iTopVersion:Short' => 'iTop version %1$s',
|
||||
'UI:iTopVersion:Long' => 'iTop version %1$s-%2$s du %3$s',
|
||||
'UI:PropertiesTab' => 'Propriétés',
|
||||
'UI:OpenDocumentInNewWindow_' => 'Ouvrir de document dans un autre fenêtre: %1$s',
|
||||
'UI:OpenDocumentInNewWindow_' => 'Ouvrir ce document dans uns autre fenêtre: %1$s',
|
||||
'UI:DownloadDocument_' => 'Télécharger ce document: %1$s',
|
||||
'UI:Document:NoPreview' => 'L\'aperçu n\'est pas disponible pour ce type de documents',
|
||||
'UI:DeadlineMissedBy_duration' => 'Passé de %1$s',
|
||||
@@ -765,5 +766,17 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:ActionNotAllowed' => 'Vous n\'êtes pas autorisé à exécuter cette opération sur ces objets.',
|
||||
'UI:BulkAction:NoObjectSelected' => 'Veuillez s\électionner au moins un objet pour cette opération.',
|
||||
'UI:AttemptingToChangeASlaveAttribute_Name' => 'Le champ %1$s ne peut pas être modifié car il est géré par une synchronisation avec une source de données. Valeur inchangée.',
|
||||
'UI:Pagination:HeaderSelection' => 'Total: %1$s éléments / %2$s éléments sélectionné(s).',
|
||||
'UI:Pagination:HeaderNoSelection' => 'Total: %1$s éléments.',
|
||||
'UI:Pagination:PageSize' => '%1$s éléments par page',
|
||||
'UI:Pagination:PagesLabel' => 'Pages:',
|
||||
'UI:Pagination:All' => 'Tous',
|
||||
'UI:HierarchyOf_Class' => 'Hiérarchie de type %1$s',
|
||||
'UI:Preferences' => 'Preferences...',
|
||||
'UI:FavoriteOrganizations' => 'Mes Organisations Favorites',
|
||||
'UI:FavoriteOrganizations+' => 'Cochez dans la liste ci-dessous les organisations que vous voulez voir listées dans le menu principal. '.
|
||||
'Ceci n\'est pas un réglage de sécurité. Les objets de toutes les organisations sont toujours visibles en choisissant "Toutes les Organisations" dans le menu.',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Toute modification sera perdue.',
|
||||
'UI:Create_Class_InState' => 'Créer l\'objet %1$s dans l\'état: ',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -302,6 +302,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'UI:History:StatsDeletes+' => '',
|
||||
'UI:Loading' => 'Betöltés...',
|
||||
'UI:Menu:Actions' => 'Akciók',
|
||||
'UI:Menu:OtherActions' => 'Egyéb Akciók',
|
||||
'UI:Menu:New' => 'Új...',
|
||||
'UI:Menu:Add' => 'Hozzáad...',
|
||||
'UI:Menu:Manage' => 'Kezel...',
|
||||
|
||||
@@ -305,6 +305,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'UI:History:StatsDeletes+' => '',
|
||||
'UI:Loading' => 'Caricamento...',
|
||||
'UI:Menu:Actions' => 'Azioni',
|
||||
'UI:Menu:OtherActions' => 'Altre Azioni',
|
||||
'UI:Menu:New' => 'Nuovo...',
|
||||
'UI:Menu:Add' => 'Aggiungi...',
|
||||
'UI:Menu:Manage' => 'Gestischi...',
|
||||
|
||||
483
dictionaries/ja.dictionary.itop.core.php
Normal file
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Tadashi Kaneda <kaneda@smartec.co.jp>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Core:AttributeLinkedSet' => 'オブジェクト配列',
|
||||
'Core:AttributeLinkedSet+' => '同一あるいはサブクラスに属するオブジェクト',
|
||||
|
||||
'Core:AttributeLinkedSetIndirect' => 'オブジェクト配列 (N-N)',
|
||||
'Core:AttributeLinkedSetIndirect+' => '同一クラスの任意のオブジェクト(サブクラス)',
|
||||
|
||||
'Core:AttributeInteger' => 'Int型',
|
||||
'Core:AttributeInteger+' => '数値 (負数あり)',
|
||||
|
||||
'Core:AttributeDecimal' => 'Decimal型',
|
||||
'Core:AttributeDecimal+' => 'Decimal値 (負数あり)',
|
||||
|
||||
'Core:AttributeBoolean' => 'ブール型',
|
||||
'Core:AttributeBoolean+' => 'Bool値',
|
||||
|
||||
'Core:AttributeString' => '文字列',
|
||||
'Core:AttributeString+' => '文字列',
|
||||
|
||||
'Core:AttributeClass' => 'クラス',
|
||||
'Core:AttributeClass+' => 'クラス',
|
||||
|
||||
'Core:AttributeApplicationLanguage' => '使用言語',
|
||||
'Core:AttributeApplicationLanguage+' => '言語・国別 (EN US)',
|
||||
|
||||
'Core:AttributeFinalClass' => 'クラス (自動)',
|
||||
'Core:AttributeFinalClass+' => 'オブジェクトの実クラス (コアで自動的に生成される)',
|
||||
|
||||
'Core:AttributePassword' => 'パスワード',
|
||||
'Core:AttributePassword+' => '外部デバイス用パスワード',
|
||||
|
||||
'Core:AttributeEncryptedString' => '暗号化文字列',
|
||||
'Core:AttributeEncryptedString+' => 'ローカルキーで暗号化された文字列',
|
||||
|
||||
'Core:AttributeText' => 'テキスト',
|
||||
'Core:AttributeText+' => '複数行文字列',
|
||||
|
||||
'Core:AttributeHTML' => 'HTML',
|
||||
'Core:AttributeHTML+' => 'HTML文字列',
|
||||
|
||||
'Core:AttributeEmailAddress' => 'メールアドレス',
|
||||
'Core:AttributeEmailAddress+' => 'メールアドレス',
|
||||
|
||||
'Core:AttributeIPAddress' => 'IPアドレス',
|
||||
'Core:AttributeIPAddress+' => 'IPアドレス',
|
||||
|
||||
'Core:AttributeOQL' => 'OQL',
|
||||
'Core:AttributeOQL+' => 'OQL式',
|
||||
|
||||
'Core:AttributeEnum' => '列挙型',
|
||||
'Core:AttributeEnum+' => 'ナンバリング済み文字列のリスト',
|
||||
|
||||
'Core:AttributeTemplateString' => 'テンプレート文字列',
|
||||
'Core:AttributeTemplateString+' => 'プレースホルダを含む文字列',
|
||||
|
||||
'Core:AttributeTemplateText' => 'テンプレートテキスト',
|
||||
'Core:AttributeTemplateText+' => 'プレースホルダを含むテキスト',
|
||||
|
||||
'Core:AttributeTemplateHTML' => 'テンプレートHTML',
|
||||
'Core:AttributeTemplateHTML+' => 'プレースホルダを含むHTML',
|
||||
|
||||
'Core:AttributeWikiText' => 'Wikiアーティクル',
|
||||
'Core:AttributeWikiText+' => 'Wikiフォーマット済みテキスト',
|
||||
|
||||
'Core:AttributeDateTime' => '日付/時刻',
|
||||
'Core:AttributeDateTime+' => '日付と時刻(年-月-日 hh:mm:ss)',
|
||||
|
||||
'Core:AttributeDate' => '日付',
|
||||
'Core:AttributeDate+' => '日付 (年-月-日)',
|
||||
|
||||
'Core:AttributeDeadline' => '締切',
|
||||
'Core:AttributeDeadline+' => '日付, 現在時刻からの相対表示',
|
||||
|
||||
'Core:AttributeExternalKey' => '外部キー',
|
||||
'Core:AttributeExternalKey+' => '外部(あるいはフォーリン)キー',
|
||||
|
||||
'Core:AttributeExternalField' => '外部フィールド',
|
||||
'Core:AttributeExternalField+' => '外部キーにマッピングされたフィールド',
|
||||
|
||||
'Core:AttributeURL' => 'URL',
|
||||
'Core:AttributeURL+' => '絶対URLもしくは相対URLのテキスト文字列',
|
||||
|
||||
'Core:AttributeBlob' => 'Blob',
|
||||
'Core:AttributeBlob+' => '任意のバイナリコンテンツ(ドキュメント)',
|
||||
|
||||
'Core:AttributeOneWayPassword' => '一方向パスワード',
|
||||
'Core:AttributeOneWayPassword+' => '一方向暗号化(ハッシュ)パスワード',
|
||||
|
||||
'Core:AttributeTable' => 'テーブル',
|
||||
'Core:AttributeTable+' => 'インデックス化された二次元配列',
|
||||
|
||||
'Core:AttributePropertySet' => 'プロパティ',
|
||||
'Core:AttributePropertySet+' => '型づけされていないプロパティのリスト(名前とバリュー)',
|
||||
));
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'core/cmdb'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: CMDBChange
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChange' => '変更',
|
||||
'Class:CMDBChange+' => '変更履歴',
|
||||
'Class:CMDBChange/Attribute:date' => '日付',
|
||||
'Class:CMDBChange/Attribute:date+' => '変更が記録された日時',
|
||||
'Class:CMDBChange/Attribute:userinfo' => 'その他情報',
|
||||
'Class:CMDBChange/Attribute:userinfo+' => '呼出側の定義済み情報',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOp
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOp' => '変更操作',
|
||||
'Class:CMDBChangeOp+' => '変更操作履歴',
|
||||
'Class:CMDBChangeOp/Attribute:change' => '変更',
|
||||
'Class:CMDBChangeOp/Attribute:change+' => '変更',
|
||||
'Class:CMDBChangeOp/Attribute:date' => '日付',
|
||||
'Class:CMDBChangeOp/Attribute:date+' => '変更日時',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo' => 'ユーザ',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo+' => '変更者',
|
||||
'Class:CMDBChangeOp/Attribute:objclass' => 'オブジェクトクラス',
|
||||
'Class:CMDBChangeOp/Attribute:objclass+' => 'オブジェクトクラス',
|
||||
'Class:CMDBChangeOp/Attribute:objkey' => 'オブジェクトID',
|
||||
'Class:CMDBChangeOp/Attribute:objkey+' => 'オブジェクトID',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass' => '型',
|
||||
'Class:CMDBChangeOp/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpCreate
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpCreate' => 'オブジェクト生成',
|
||||
'Class:CMDBChangeOpCreate+' => 'オブジェクト生成履歴',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpDelete
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpDelete' => 'オブジェクト削除',
|
||||
'Class:CMDBChangeOpDelete+' => 'オブジェクト削除履歴',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttribute
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttribute' => 'オブジェクト更新',
|
||||
'Class:CMDBChangeOpSetAttribute+' => 'オブジェクトプロパティの更新履歴',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => '属性',
|
||||
'Class:CMDBChangeOpSetAttribute/Attribute:attcode+' => '更新プロパティのコード',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttributeScalar
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttributeScalar' => 'プロパティ更新',
|
||||
'Class:CMDBChangeOpSetAttributeScalar+' => 'オブジェクトのスカラープロパティの更新履歴',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => '変更前の値',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue+' => '属性の変更前の値',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => '新規の値',
|
||||
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => '属性の新規の値',
|
||||
));
|
||||
// Used by CMDBChangeOp... & derived classes
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Change:ObjectCreated' => 'オブジェクトを生成しました',
|
||||
'Change:ObjectDeleted' => 'オブジェクトを削除しました',
|
||||
'Change:ObjectModified' => 'オブジェクトを更新しました',
|
||||
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$sを%2$sに設定しました (変更前の値: %3$s)',
|
||||
'Change:Text_AppendedTo_AttName' => '%1$sを%2$sに追加しました',
|
||||
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$sを更新しました。更新前の値: %2$s',
|
||||
'Change:AttName_Changed' => '%1$sを更新しました',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttributeBlob
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttributeBlob' => 'データ変更',
|
||||
'Class:CMDBChangeOpSetAttributeBlob+' => 'データ変更履歴',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => '変更前のデータ', //'Previous data',
|
||||
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata+' => 'この属性の以前の内容', //'previous contents of the attribute',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: CMDBChangeOpSetAttributeText
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:CMDBChangeOpSetAttributeText' => 'テキストの変更', //'text change',
|
||||
'Class:CMDBChangeOpSetAttributeText+' => 'テキストの変更履歴', //'text change tracking',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => '以前の内容', //'Previous data',
|
||||
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata+' => 'この属性の以前の内容', //'previous contents of the attribute',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: Event
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:Event' => 'ログイベント',// 'Log Event',
|
||||
'Class:Event+' => 'アプリケーション内部イベント', //'An application internal event',
|
||||
'Class:Event/Attribute:message' => 'メッセージ', //'message',
|
||||
'Class:Event/Attribute:message+' => 'イベント概略', //'short description of the event',
|
||||
'Class:Event/Attribute:date' => '日付', //'date',
|
||||
'Class:Event/Attribute:date+' => '変更が記録された日時', //'date and time at which the changes have been recorded',
|
||||
'Class:Event/Attribute:userinfo' => 'ユーザ情報', //'user info',
|
||||
'Class:Event/Attribute:userinfo+' => 'このイベントをトリガーにアクションを起こすユーザの識別', //'identification of the user that was doing the action that triggered this event',
|
||||
'Class:Event/Attribute:finalclass' => '型', //'type',
|
||||
'Class:Event/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventNotification
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:EventNotification' => '通知イベント', // 'Notification event',
|
||||
'Class:EventNotification+' => '創出された通知のトレース', //'Trace of a notification that has been sent',
|
||||
'Class:EventNotification/Attribute:trigger_id' => 'トリガー', //'Trigger',
|
||||
'Class:EventNotification/Attribute:trigger_id+' => 'ユーザアカウント', //'user account',
|
||||
'Class:EventNotification/Attribute:action_id' => 'ユーザ', //'user',
|
||||
'Class:EventNotification/Attribute:action_id+' => 'ユーザアカウント', //'user account',
|
||||
'Class:EventNotification/Attribute:object_id' => 'オブジェクトID', //'Object id',
|
||||
'Class:EventNotification/Attribute:object_id+' => 'オブジェクトID(トリガーでクラスが定義済み?)', //'object id (class defined by the trigger ?)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventNotificationEmail
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array('Class:EventNotificationEmail' => 'メール送出イベント', //'Email emission event',
|
||||
'Class:EventNotificationEmail+' => '送出されたメールのトレース',//Trace of an email that has been sent',
|
||||
'Class:EventNotificationEmail/Attribute:to' => 'TO',
|
||||
'Class:EventNotificationEmail/Attribute:to+' => 'TO',
|
||||
'Class:EventNotificationEmail/Attribute:cc' => 'CC',
|
||||
'Class:EventNotificationEmail/Attribute:cc+' => 'CC',
|
||||
'Class:EventNotificationEmail/Attribute:bcc' => 'BCC',
|
||||
'Class:EventNotificationEmail/Attribute:bcc+' => 'BCC',
|
||||
'Class:EventNotificationEmail/Attribute:from' => 'From',
|
||||
'Class:EventNotificationEmail/Attribute:from+' => 'メール送信者', //'Sender of the message',
|
||||
'Class:EventNotificationEmail/Attribute:subject' => 'Subject',
|
||||
'Class:EventNotificationEmail/Attribute:subject+' => 'Subject',
|
||||
'Class:EventNotificationEmail/Attribute:body' => 'Body',
|
||||
'Class:EventNotificationEmail/Attribute:body+' => 'Body',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventIssue
|
||||
//
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:EventIssue' => 'イシューイベント', //'Issue event',
|
||||
'Class:EventIssue+' => 'イシュー(警告、エラーetc)のトレース', //'Trace of an issue (warning, error, etc.)',
|
||||
'Class:EventIssue/Attribute:issue' => 'イシュー', //'Issue',
|
||||
'Class:EventIssue/Attribute:issue+' => '何が起こったか', //'What happened',
|
||||
'Class:EventIssue/Attribute:impact' => 'インパクト', //'Impact',
|
||||
'Class:EventIssue/Attribute:impact+' => 'その結果', //'What are the consequences',
|
||||
'Class:EventIssue/Attribute:page' => 'ページ', //'Page',
|
||||
'Class:EventIssue/Attribute:page+' => 'HTTPエントリポイント', //'HTTP entry point',
|
||||
'Class:EventIssue/Attribute:arguments_post' => 'POSTされた引数', //'Posted arguments',
|
||||
'Class:EventIssue/Attribute:arguments_post+' => 'HTTP POST引数', //'HTTP POST arguments',
|
||||
'Class:EventIssue/Attribute:arguments_get' => 'URLパラメータ', //'URL arguments',
|
||||
'Class:EventIssue/Attribute:arguments_get+' => 'HTTP GETパラメータ', //'HTTP GET arguments',
|
||||
'Class:EventIssue/Attribute:callstack' => 'コールスタック', //'Callstack',
|
||||
'Class:EventIssue/Attribute:callstack+' => 'スタックをコールする', //'Call stack',
|
||||
'Class:EventIssue/Attribute:data' => 'データ', //'Data',
|
||||
'Class:EventIssue/Attribute:data+' => '詳細情報', //'More information',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: EventWebService
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:EventWebService' => 'ウェブサービスイベント', //'Web service event',
|
||||
'Class:EventWebService+' => 'ウェブサービス呼出のYトレース', //'Trace of an web service call',
|
||||
'Class:EventWebService/Attribute:verb' => '動詞', //'Verb',
|
||||
'Class:EventWebService/Attribute:verb+' => '操作名', //'Name of the operation',
|
||||
'Class:EventWebService/Attribute:result' => '結果', //'Result',
|
||||
'Class:EventWebService/Attribute:result+' => '総体的な成功/失敗', //'Overall success/failure',
|
||||
'Class:EventWebService/Attribute:log_info' => 'インフォログ', //'Info log',
|
||||
'Class:EventWebService/Attribute:log_info+' => 'インフォログの結果', //'Result info log',
|
||||
'Class:EventWebService/Attribute:log_warning' => 'ウォーニングログ', //'Warning log',
|
||||
'Class:EventWebService/Attribute:log_warning+' => 'ウォーニングログ結果', //'Result warning log',
|
||||
'Class:EventWebService/Attribute:log_error' => 'エラーログ', //'Error log',
|
||||
'Class:EventWebService/Attribute:log_error+' => 'エラーログ結果', //'Result error log',
|
||||
'Class:EventWebService/Attribute:data' => 'データ', //'Data',
|
||||
'Class:EventWebService/Attribute:data+' => 'データ結果', //'Result data',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: Action
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:Action' => 'カスタムアクション', //'Custom Action',
|
||||
'Class:Action+' => 'ユーザ定義アクション', //'User defined action',
|
||||
'Class:Action/Attribute:name' => '名前', //'Name',
|
||||
'Class:Action/Attribute:name+' => '',
|
||||
'Class:Action/Attribute:description' => '概要', //'Description',
|
||||
'Class:Action/Attribute:description+' => '',
|
||||
'Class:Action/Attribute:status' => 'ステータス', //'Status',
|
||||
'Class:Action/Attribute:status+' => '製品化済み、あるいは?', //'In production or ?',
|
||||
'Class:Action/Attribute:status/Value:test' => 'テスト済み', //'Being tested',
|
||||
'Class:Action/Attribute:status/Value:test+' => 'テスト済み', //'Being tested',
|
||||
'Class:Action/Attribute:status/Value:enabled' => '製品化済み', //'In production',
|
||||
'Class:Action/Attribute:status/Value:enabled+' => '製品化済み', //'In production',
|
||||
'Class:Action/Attribute:status/Value:disabled' => '非アクティブ', //'Inactive',
|
||||
'Class:Action/Attribute:status/Value:disabled+' => '非アクティブ', //'Inactive',
|
||||
'Class:Action/Attribute:trigger_list' => '関連トリガ', //'Related Triggers',
|
||||
'Class:Action/Attribute:trigger_list+' => 'このアクションにリンクされたトリガ', //'Triggers linked to this action',
|
||||
'Class:Action/Attribute:finalclass' => '型', //'Type',
|
||||
'Class:Action/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: ActionNotification
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:ActionNotification' => 'ノーティフィケーション', //'Notification',
|
||||
'Class:ActionNotification+' => 'ノーティフィケーション(抽象)', //'Notification (abstract)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: ActionEmail
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:ActionEmail' => 'メール通知', //'Email notification',
|
||||
'Class:ActionEmail+' => '',
|
||||
'Class:ActionEmail/Attribute:test_recipient' => 'テストレシピ', //'Test recipient',
|
||||
'Class:ActionEmail/Attribute:test_recipient+' => 'Detination in case status is set to "Test"',
|
||||
'Class:ActionEmail/Attribute:from' => 'From',
|
||||
'Class:ActionEmail/Attribute:from+' => 'Will be sent into the email header',
|
||||
'Class:ActionEmail/Attribute:reply_to' => 'Reply to',
|
||||
'Class:ActionEmail/Attribute:reply_to+' => 'Will be sent into the email header',
|
||||
'Class:ActionEmail/Attribute:to' => 'To',
|
||||
'Class:ActionEmail/Attribute:to+' => 'メールの宛先', //'Destination of the email',
|
||||
'Class:ActionEmail/Attribute:cc' => 'Cc',
|
||||
'Class:ActionEmail/Attribute:cc+' => 'Carbon Copy',
|
||||
'Class:ActionEmail/Attribute:bcc' => 'bcc',
|
||||
'Class:ActionEmail/Attribute:bcc+' => 'Blind Carbon Copy',
|
||||
'Class:ActionEmail/Attribute:subject' => 'subject',
|
||||
'Class:ActionEmail/Attribute:subject+' => 'メールのタイトル', //'Title of the email',
|
||||
'Class:ActionEmail/Attribute:body' => 'body',
|
||||
'Class:ActionEmail/Attribute:body+' => 'メールの本文', //'Contents of the email',
|
||||
'Class:ActionEmail/Attribute:importance' => 'importance',
|
||||
'Class:ActionEmail/Attribute:importance+' => '重要度フラグ', //'Importance flag',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low' => 'low',
|
||||
'Class:ActionEmail/Attribute:importance/Value:low+' => 'low',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal' => 'normal',
|
||||
'Class:ActionEmail/Attribute:importance/Value:normal+' => 'normal',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high' => 'high',
|
||||
'Class:ActionEmail/Attribute:importance/Value:high+' => 'high',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: Trigger
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:Trigger' => 'トリガー', //'Trigger',
|
||||
'Class:Trigger+' => 'カスタムイベントヘッダ', //'Custom event handler',
|
||||
'Class:Trigger/Attribute:description' => '概要', //'Description',
|
||||
'Class:Trigger/Attribute:description+' => '1行概要', //'one line description',
|
||||
'Class:Trigger/Attribute:action_list' => 'トリガされたアクション', //'Triggered actions',
|
||||
'Class:Trigger/Attribute:action_list+' => 'トリガが発火した場合に動作するアクション', //'Actions performed when the trigger is activated',
|
||||
'Class:Trigger/Attribute:finalclass' => '型', //'Type',
|
||||
'Class:Trigger/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnObject
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnObject' => 'トリガ(クラス依存)', //'Trigger (class dependent)',
|
||||
'Class:TriggerOnObject+' => '指定オブジェクトのクラスへのトリガ', //'Trigger on a given class of objects',
|
||||
'Class:TriggerOnObject/Attribute:target_class' => 'ターゲットクラス', //'Target class',
|
||||
'Class:TriggerOnObject/Attribute:target_class+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnStateChange
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnStateChange' => '(状態変更の)トリガ', // Trigger (on state change)',
|
||||
'Class:TriggerOnStateChange+' => 'オブジェクト状態変更のトリガ', //'Trigger on object state change',
|
||||
'Class:TriggerOnStateChange/Attribute:state' => '状態', //'State',
|
||||
'Class:TriggerOnStateChange/Attribute:state+' => '',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnStateEnter
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnStateEnter' => 'トリガ(ある状態に入る)', // 'Trigger (on entering a state)',
|
||||
'Class:TriggerOnStateEnter+' => 'オブジェクト状態変更のトリガ: 入場', //'Trigger on object state change - entering',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnStateLeave
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnStateLeave' => '(ある状態から退場する)トリガ', // 'Trigger (on leaving a state)',
|
||||
'Class:TriggerOnStateLeave+' => 'オブジェクト状態変更のトリガ: 退場', //Trigger on object state change - leaving',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: TriggerOnObjectCreate
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:TriggerOnObjectCreate' => '(オブジェクト生成の)トリガ', //Trigger (on object creation)',
|
||||
'Class:TriggerOnObjectCreate+' => '指定されたクラスの(子クラスの)オブジェクト生成のトリガ', //Trigger on object creation of [a child class of] the given class',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: lnkTriggerAction
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:lnkTriggerAction' => 'アクション/トリガ', //'Action/Trigger',
|
||||
'Class:lnkTriggerAction+' => 'トリガとアクション間のリンク', //'Link between a trigger and an action',
|
||||
'Class:lnkTriggerAction/Attribute:action_id' => 'アクション', //'Action',
|
||||
'Class:lnkTriggerAction/Attribute:action_id+' => '実行されるべきアクション', //'The action to be executed',
|
||||
'Class:lnkTriggerAction/Attribute:action_name' => 'アクション', //'Action',
|
||||
'Class:lnkTriggerAction/Attribute:action_name+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id' => 'トリガ', //'Trigger',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_id+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name' => 'トリガ', //'Trigger',
|
||||
'Class:lnkTriggerAction/Attribute:trigger_name+' => '',
|
||||
'Class:lnkTriggerAction/Attribute:order' => '処理順序', //'Order',
|
||||
'Class:lnkTriggerAction/Attribute:order+' => 'アクション実行順序', //'Actions execution order',
|
||||
));
|
||||
|
||||
|
||||
?>
|
||||
907
dictionaries/ja.dictionary.itop.ui.php
Normal file
@@ -0,0 +1,907 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Tadashi Kaneda <kaneda@rworks.jp>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'gui'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'application'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: AuditCategory
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:AuditCategory' => '監査カテゴリ', //Audit Category',
|
||||
'Class:AuditCategory+' => '監査全体の内部セクション', //'A section inside the overall audit',
|
||||
'Class:AuditCategory/Attribute:name' => 'カテゴリ名', //'Category Name',
|
||||
'Class:AuditCategory/Attribute:name+' => '本カテゴリの短縮名', //'Short name for this category',
|
||||
'Class:AuditCategory/Attribute:description' => '監査カテゴリ概要', //'Audit Category Description',
|
||||
'Class:AuditCategory/Attribute:description+' => '本監査カテゴリの詳細記述', //'Long description for this audit category',
|
||||
'Class:AuditCategory/Attribute:definition_set' => '定義セット', //'Definition Set',
|
||||
'Class:AuditCategory/Attribute:definition_set+' => '監査するべきオブジェクトの集合を定義するOQL式', //'OQL expression defining the set of objects to audit',
|
||||
'Class:AuditCategory/Attribute:rules_list' => '監査ルール', //'Audit Rules',
|
||||
'Class:AuditCategory/Attribute:rules_list+' => '本カテゴリの監査ルール', //'Audit rules for this category',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: AuditRule
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:AuditRule' => '監査ルール', //'Audit Rule',
|
||||
'Class:AuditRule+' => '指定された監査カテゴリをチェックするためのルール', //'A rule to check for a given Audit category',
|
||||
'Class:AuditRule/Attribute:name' => 'ルール名', //'Rule Name',
|
||||
'Class:AuditRule/Attribute:name+' => '本ルールの短縮名', //'Short name for this rule',
|
||||
'Class:AuditRule/Attribute:description' => '監査ルール概要', //'Audit Rule Description',
|
||||
'Class:AuditRule/Attribute:description+' => '本監査ルールの詳細記述', //'Long description for this audit rule',
|
||||
'Class:AuditRule/Attribute:query' => '実行するクエリ', //'Query to Run',
|
||||
'Class:AuditRule/Attribute:query+' => '実行するOQL式', //'The OQL expression to run',
|
||||
'Class:AuditRule/Attribute:valid_flag' => '正しいオブジェクト?', // 'Valid Objects?',
|
||||
'Class:AuditRule/Attribute:valid_flag+' => 'このルールが正しいオブジェクトを返す場合は真、そうでなければ偽', //'True if the rule returns the valid objects, false otherwise',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true' => '真', //'true',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:true+' => '真', //'true',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false' => '偽', //'false',
|
||||
'Class:AuditRule/Attribute:valid_flag/Value:false+' => '偽', //'false',
|
||||
'Class:AuditRule/Attribute:category_id' => 'カテゴリ', //'Category',
|
||||
'Class:AuditRule/Attribute:category_id+' => '本ルールのカテゴリ', //'The category for this rule',
|
||||
'Class:AuditRule/Attribute:category_name' => 'カテゴリ', //'Category',
|
||||
'Class:AuditRule/Attribute:category_name+' => '本ルールのカテゴリ名', //'Name of the category for this rule',
|
||||
));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Classes in 'addon/userrights'
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//
|
||||
// Class: User
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:User' => 'ユーザ', //'User',
|
||||
'Class:User+' => 'ユーザログイン', //'User login',
|
||||
'Class:User/Attribute:finalclass' => 'アカウント種別', //'Type of account',
|
||||
'Class:User/Attribute:finalclass+' => '',
|
||||
'Class:User/Attribute:contactid' => 'コンタクト(人)', //'Contact (person)',
|
||||
'Class:User/Attribute:contactid+' => 'ビジネスデータから抽出した個人情報の詳細', //'Personal details from the business data',
|
||||
'Class:User/Attribute:last_name' => '名字', //'Last name',
|
||||
'Class:User/Attribute:last_name+' => '適切なコンタクト名', //'Name of the corresponding contact',
|
||||
'Class:User/Attribute:first_name' => '名前', //'First name',
|
||||
'Class:User/Attribute:first_name+' => '適切なコンタクトの名前', //'First name of the corresponding contact',
|
||||
'Class:User/Attribute:email' => 'メールアドレス', //'Email',
|
||||
'Class:User/Attribute:email+' => '適切なコンタクトのメールアドレス', //'Email of the corresponding contact',
|
||||
'Class:User/Attribute:login' => 'ログイン', //'Login',
|
||||
'Class:User/Attribute:login+' => 'ユーザ識別文字列', //'user identification string',
|
||||
'Class:User/Attribute:language' => '言語', //'Language',
|
||||
'Class:User/Attribute:language+' => 'ユーザ使用言語', //'user language',
|
||||
'Class:User/Attribute:language/Value:EN US' => '英語', //'English',
|
||||
'Class:User/Attribute:language/Value:EN US+' => '英語(米国)', //'English (U.S.)',
|
||||
'Class:User/Attribute:language/Value:FR FR' => 'フランス語', //'French',
|
||||
'Class:User/Attribute:language/Value:FR FR+' => 'フランス語(フランス)', //'French (France)',
|
||||
'Class:User/Attribute:profile_list' => 'プロフィール', //'Profiles',
|
||||
'Class:User/Attribute:profile_list+' => '役割、この人に委譲された権限', //'Roles, granting rights for that person',
|
||||
'Class:User/Attribute:allowed_org_list' => '許可された組織', //'Allowed Organizations',
|
||||
'Class:User/Attribute:allowed_org_list+' => 'このエンドユーザは以下の組織に属するデータの参照を許可されている。組織が指定されていなければ、制限はありません。', //'The end user is allowed to see data belonging to the following organizations. If no organization is specified, there is no restriction.',
|
||||
|
||||
'Class:User/Error:LoginMustBeUnique' => 'ログイン名は一意でないといけません。- "%1s" はすでに使われています。', //'Login must be unique - "%1s" is already being used.',
|
||||
'Class:User/Error:AtLeastOneProfileIsNeeded' => '少なくとも1件のプロフィールがこのユーザに指定されていないといけません。', //'At least one profile must be assigned to this user.',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_Profiles
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_Profiles' => 'プロフィール', //'Profile',
|
||||
'Class:URP_Profiles+' => 'ユーザプロフィール', //'User profile',
|
||||
'Class:URP_Profiles/Attribute:name' => '名前', //'Name',
|
||||
'Class:URP_Profiles/Attribute:name+' => 'ラベル', //'label',
|
||||
'Class:URP_Profiles/Attribute:description' => '概要', //'Description',
|
||||
'Class:URP_Profiles/Attribute:description+' => '1行で書くと', //'one line description',
|
||||
'Class:URP_Profiles/Attribute:user_list' => 'ユーザ', //'Users',
|
||||
'Class:URP_Profiles/Attribute:user_list+' => 'この役割をもつ人', //'persons having this role',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_Dimensions
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_Dimensions' => '次元', //'dimension',
|
||||
'Class:URP_Dimensions+' => 'application dimension (defining silos)',
|
||||
'Class:URP_Dimensions/Attribute:name' => '名前', //'Name',
|
||||
'Class:URP_Dimensions/Attribute:name+' => 'ラベル', //'label',
|
||||
'Class:URP_Dimensions/Attribute:description' => '概要', //'Description',
|
||||
'Class:URP_Dimensions/Attribute:description+' => '1行で書くと', //'one line description',
|
||||
'Class:URP_Dimensions/Attribute:type' => '種別', //'Type',
|
||||
'Class:URP_Dimensions/Attribute:type+' => 'クラス名、もしくはデータ型(projection unit)', //'class name or data type (projection unit)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_UserProfile
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_UserProfile' => 'User to profile',
|
||||
'Class:URP_UserProfile+' => 'ユーザプロフィール', //'user profiles',
|
||||
'Class:URP_UserProfile/Attribute:userid' => 'ユーザ', //'User',
|
||||
'Class:URP_UserProfile/Attribute:userid+' => 'ユーザアカウント', //'user account',
|
||||
'Class:URP_UserProfile/Attribute:userlogin' => 'ログイン', //'Login',
|
||||
'Class:URP_UserProfile/Attribute:userlogin+' => 'ユーザのログイン', //'User\'s login',
|
||||
'Class:URP_UserProfile/Attribute:profileid' => 'プロフィール', //'Profile',
|
||||
'Class:URP_UserProfile/Attribute:profileid+' => 'プロフィールの用法???', //'usage profile',
|
||||
'Class:URP_UserProfile/Attribute:profile' => 'プロフィール', //'Profile',
|
||||
'Class:URP_UserProfile/Attribute:profile+' => 'プロフィール名', //'Profile name',
|
||||
'Class:URP_UserProfile/Attribute:reason' => '理由', //'Reason',
|
||||
'Class:URP_UserProfile/Attribute:reason+' => 'なぜ、この人物がこの役割を持つかを説明する', //'explain why this person may have this role',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_UserOrg
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_UserOrg' => 'ユーザ組織', //'User organizations',
|
||||
'Class:URP_UserOrg+' => '許可された組織', //'Allowed organizations',
|
||||
'Class:URP_UserOrg/Attribute:userid' => 'ユーザ', //'User',
|
||||
'Class:URP_UserOrg/Attribute:userid+' => 'ユーザアカウント', //'user account',
|
||||
'Class:URP_UserOrg/Attribute:userlogin' => 'ログイン', //'Login',
|
||||
'Class:URP_UserOrg/Attribute:userlogin+' => 'ユーザのログイン', //'User\'s login',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_id' => '組織', //'Organization',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_id+' => '許可された組織', //'Allowed organization',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name' => '組織', //'Organization',
|
||||
'Class:URP_UserOrg/Attribute:allowed_org_name+' => '許可された組織', //'Allowed organization',
|
||||
'Class:URP_UserOrg/Attribute:reason' => '理由', //'Reason',
|
||||
'Class:URP_UserOrg/Attribute:reason+' => 'なぜこの人物がこの組織に属するデータを参照できるのかを説明する', // 'explain why this person is allowed to see the data belonging to this organization',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ProfileProjection
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_ProfileProjection' => 'プロファイルプロジェクション???', // 'profile_projection',
|
||||
'Class:URP_ProfileProjection+' => 'プロファイルプロジェクション???', //'profile projections',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid' => '次元', //'Dimension',
|
||||
'Class:URP_ProfileProjection/Attribute:dimensionid+' => 'アプリケーション次元', // 'application dimension',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension' => '次元', //'Dimension',
|
||||
'Class:URP_ProfileProjection/Attribute:dimension+' => 'アプリケーション次元', //'application dimension',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid' => 'プロフィール', //'Profile',
|
||||
'Class:URP_ProfileProjection/Attribute:profileid+' => 'usage profile???',
|
||||
'Class:URP_ProfileProjection/Attribute:profile' => 'プロフィール', //'Profile',
|
||||
'Class:URP_ProfileProjection/Attribute:profile+' => 'プロフィール名', //'Profile name',
|
||||
'Class:URP_ProfileProjection/Attribute:value' => 'Value式', //'Value expression',
|
||||
'Class:URP_ProfileProjection/Attribute:value+' => '($userを使う)OQL式 | アクセス先 | +attribute code', //'OQL expression (using $user) | constant | | +attribute code',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute' => '属性', //'Attribute',
|
||||
'Class:URP_ProfileProjection/Attribute:attribute+' => 'Target attribute code (optional)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ClassProjection
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_ClassProjection' => 'class_projection',
|
||||
'Class:URP_ClassProjection+' => 'クラスの射影???', // 'clas projection',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid' => '次元', //'Dimension',
|
||||
'Class:URP_ClassProjection/Attribute:dimensionid+' => 'アプリケーション次元', //'application dimension',
|
||||
'Class:URP_ClassProjection/Attribute:dimension' => '次元', //'Dimension',
|
||||
'Class:URP_ClassProjection/Attribute:dimension+' => 'アプリケーション次元', //'application dimension',
|
||||
'Class:URP_ClassProjection/Attribute:class' => 'クラス', //'Class',
|
||||
'Class:URP_ClassProjection/Attribute:class+' => 'ターゲットクラス', //'Target class',
|
||||
'Class:URP_ClassProjection/Attribute:value' => 'Value式???', //'Value expression',
|
||||
'Class:URP_ClassProjection/Attribute:value+' => '($this を使った)OQL式 | 定数 | +attribute code', //'OQL expression (using $this) | constant | | +attribute code',
|
||||
'Class:URP_ClassProjection/Attribute:attribute' => '属性', //'Attribute',
|
||||
'Class:URP_ClassProjection/Attribute:attribute+' => 'ターゲット属性コード(オプション)', //'Target attribute code (optional)',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_ActionGrant
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_ActionGrant' => 'アクション権限', //'action_permission',
|
||||
'Class:URP_ActionGrant+' => 'クラスに対する権限', //'permissions on classes',
|
||||
'Class:URP_ActionGrant/Attribute:profileid' => 'プロファイル', //'Profile',
|
||||
'Class:URP_ActionGrant/Attribute:profileid+' => 'usage profile',
|
||||
'Class:URP_ActionGrant/Attribute:profile' => 'プロファイル', //'Profile',
|
||||
'Class:URP_ActionGrant/Attribute:profile+' => 'usage profile',
|
||||
'Class:URP_ActionGrant/Attribute:class' => 'クラス', //'Class',
|
||||
'Class:URP_ActionGrant/Attribute:class+' => 'ターゲットクラス', //'Target class',
|
||||
'Class:URP_ActionGrant/Attribute:permission' => '権限', //'Permission',
|
||||
'Class:URP_ActionGrant/Attribute:permission+' => '権限の有無は?', //'allowed or not allowed?',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes' => 'はい', //'yes',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:yes+' => 'はい', //'yes',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:no' => 'いいえ', //'no',
|
||||
'Class:URP_ActionGrant/Attribute:permission/Value:no+' => 'いいえ', //'no',
|
||||
'Class:URP_ActionGrant/Attribute:action' => 'アクション', //'Action',
|
||||
'Class:URP_ActionGrant/Attribute:action+' => '指定されたクラスにすべき操作', //'operations to perform on the given class',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_StimulusGrant
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_StimulusGrant' => 'stimulus_permission',
|
||||
'Class:URP_StimulusGrant+' => 'permissions on stimilus in the life cycle of the object',
|
||||
'Class:URP_StimulusGrant/Attribute:profileid' => 'プロファイル', //'Profile',
|
||||
'Class:URP_StimulusGrant/Attribute:profileid+' => 'usage profile',
|
||||
'Class:URP_StimulusGrant/Attribute:profile' => 'プロファイル', //'Profile',
|
||||
'Class:URP_StimulusGrant/Attribute:profile+' => 'usage profile',
|
||||
'Class:URP_StimulusGrant/Attribute:class' => 'クラス', //'Class',
|
||||
'Class:URP_StimulusGrant/Attribute:class+' => 'ターゲットクラス', //'Target class',
|
||||
'Class:URP_StimulusGrant/Attribute:permission' => '権限', // 'Permission',
|
||||
'Class:URP_StimulusGrant/Attribute:permission+' => '権限の有無?', //'allowed or not allowed?',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes' => 'はい', //'yes',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:yes+' => 'はい', //'yes',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:no' => 'いいえ', //'no',
|
||||
'Class:URP_StimulusGrant/Attribute:permission/Value:no+' => 'いいえ', //'no',
|
||||
'Class:URP_StimulusGrant/Attribute:stimulus' => 'Stimulus',
|
||||
'Class:URP_StimulusGrant/Attribute:stimulus+' => 'stimulus code',
|
||||
));
|
||||
|
||||
//
|
||||
// Class: URP_AttributeGrant
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:URP_AttributeGrant' => '権限属性', //'attribute_permission',
|
||||
'Class:URP_AttributeGrant+' => '属性レベルでの権限', //'permissions at the attributes level',
|
||||
'Class:URP_AttributeGrant/Attribute:actiongrantid' => '実行権限', //'Action grant',
|
||||
'Class:URP_AttributeGrant/Attribute:actiongrantid+' => '実行権限', //'action grant',
|
||||
'Class:URP_AttributeGrant/Attribute:attcode' => '属性', //'Attribute',
|
||||
'Class:URP_AttributeGrant/Attribute:attcode+' => '属性コード', //'attribute code',
|
||||
));
|
||||
|
||||
//
|
||||
// String from the User Interface: menu, messages, buttons, etc...
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Menu:WelcomeMenu' => 'ようこそ', //'Welcome',
|
||||
'Menu:WelcomeMenu+' => 'ようこそ、iTopへ', //'Welcome to iTop',
|
||||
'Menu:WelcomeMenuPage' => 'ようこそ', //'Welcome',
|
||||
'Menu:WelcomeMenuPage+' => 'ようこそ、iTopへ', //'Welcome to iTop',
|
||||
'UI:WelcomeMenu:Title' => 'ようこそ、iTopへ', //'Welcome to iTop',
|
||||
// '<p>iTop is a complete, OpenSource, IT Operational Portal.</p>
|
||||
'UI:WelcomeMenu:LeftBlock' => '<p>iTopは、オープンソースの、これだけで完結したIT業務用ポータルです。</p>
|
||||
<ul>下記に挙げるものが同梱されています。
|
||||
<li>IT資産インベントリをドキュメント化、管理を行うための完全なCMDB(コンフィグレーション管理データベース)</li>
|
||||
<li>IT資産関連で発生した問題のトラッキングとそれに関する議論のためのインシデント管理モジュール</li>
|
||||
<li>IT資産環境への変更を加える場合のプランニングと変更をトラッキングするための変更管理モジュール</li>
|
||||
<li>インシデント解決のスピードアップするための既知エラーデータベース</li>
|
||||
<li>計画停電をすべてドキュメント化し、適切な連絡先に通知するための停電モジュール</li>
|
||||
<li>IT資産の概観を素早く得るためのダッシュボード</li>
|
||||
</ul>
|
||||
<p>すべてのモジュールはそれぞれ独立して別個にセットアップが可能である。</p>',
|
||||
|
||||
//'<p>iTop is service provider oriented, it allows IT engineers to manage easily multiple customers or organizations.
|
||||
'UI:WelcomeMenu:RightBlock' => '<p>iTopはサービスプロバイダ指向であり、ITエンジニアが複数の顧客や組織を簡単に管理できるようになる。
|
||||
<ul>iTopでは 下記のように、機能豊富なビジネスプロセスを取り揃えた。
|
||||
<li>効果的なIT資産管理</li>
|
||||
<li>IT業務の効率化推進</li>
|
||||
<li>顧客満足度の改善と、経営幹部へ、ビジネスパフォーマンス見える化を提供</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>iTopは完全にオープンなので、あなたが今使っているIT資産管理インフラとの統合が可能である。</p>
|
||||
<p>
|
||||
<ul>この次世代IT資産管理業務ポータルを採用すれば、こんなことが可能になる。
|
||||
<li>より複雑になりつつある、IT資産環境の管理を確実にする。</li>
|
||||
<li>自分のペースでITILプロセス実装することができる。</li>
|
||||
<li>IT資産の中でもっとも重要なアセットである、「ドキュメンテーション」を管理することができる。</li>
|
||||
</ul>
|
||||
</p>',
|
||||
'UI:WelcomeMenu:AllOpenRequests' => 'リクエストを開く: %1$d', //'Open requests: %1$d',
|
||||
'UI:WelcomeMenu:MyCalls' => 'マイリクエスト', //'My requests',
|
||||
'UI:WelcomeMenu:OpenIncidents' => 'インシデントを開く: %1$d', //'Open incidents: %1$d',
|
||||
'UI:WelcomeMenu:AllConfigItems' => '設定項目', //'Configuration Items: %1$d',
|
||||
'UI:WelcomeMenu:MyIncidents' => '自分にアサインされたインシデント', //'Incidents assigned to me',
|
||||
'UI:AllOrganizations' => '全組織', //' All Organizations ',
|
||||
'UI:YourSearch' => 'あなたのサーチ', //'Your Search',
|
||||
'UI:LoggedAsMessage' => '%1$s としてログインする', //'Logged in as %1$s',
|
||||
'UI:LoggedAsMessage+Admin' => '%1$s (管理者)としてログインする', //'Logged in as %1$s (Administrator)',
|
||||
'UI:Button:Logoff' => 'ログオフ', //'Log off',
|
||||
'UI:Button:GlobalSearch' => 'サーチ', //'Search',
|
||||
'UI:Button:Search' => ' サーチ', //' Search ',
|
||||
'UI:Button:Query' => ' クエリ', //' Query ',
|
||||
'UI:Button:Ok' => 'OK', //'Ok',
|
||||
'UI:Button:Cancel' => 'キャンセル', //'Cancel',
|
||||
'UI:Button:Apply' => '適用する', //'Apply',
|
||||
'UI:Button:Back' => ' << 戻る', //' << Back ',
|
||||
'UI:Button:Restart' => ' |<< リスタート', //' |<< Restart ',
|
||||
'UI:Button:Next' => ' 次へ >> ', //' Next >> ',
|
||||
'UI:Button:Finish' => ' 終了 ', //' Finish ',
|
||||
'UI:Button:DoImport' => ' インポート実行! ', //' Run the Import ! ',
|
||||
'UI:Button:Done' => ' 完了 ', //' Done ',
|
||||
'UI:Button:SimulateImport' => ' インポートをシュミレート ', //' Simulate the Import ',
|
||||
'UI:Button:Test' => 'テスト実行!', //'Test!',
|
||||
'UI:Button:Evaluate' => ' 評価 ', //' Evaluate ',
|
||||
'UI:Button:AddObject' => ' 追加...', //' Add... ',
|
||||
'UI:Button:BrowseObjects' => 'ブラウズ...', //' Browse... ',
|
||||
'UI:Button:Add' => ' 追加 ', //' Add ',
|
||||
'UI:Button:AddToList' => ' << 追加 ', //' << Add ',
|
||||
'UI:Button:RemoveFromList' => '削除 >> ', //' Remove >> ',
|
||||
'UI:Button:FilterList' => ' フィルタ... ', //' Filter... ',
|
||||
'UI:Button:Create' => ' 生成 ', //' Create ',
|
||||
'UI:Button:Delete' => ' 削除! ', //' Delete ! ',
|
||||
'UI:Button:ChangePassword' => ' パスワード変更 ', //' Change Password ',
|
||||
'UI:Button:ResetPassword' => 'パスワードリセット ', //' Reset Password ',
|
||||
|
||||
'UI:SearchToggle' => 'サーチ', //'Search',
|
||||
'UI:ClickToCreateNew' => '新規 %1$s を生成', //'Create a new %1$s',
|
||||
'UI:SearchFor_Class' => '%1$s オブジェクトをサーチ', //'Search for %1$s objects',
|
||||
'UI:NoObjectToDisplay' => '表示すべきオブジェクトがありません。', //'No object to display.',
|
||||
'UI:Error:MandatoryTemplateParameter_object_id' => 'link_attrが指定されている時は、object_idパラメータは必須です。表示テンプレートの定義を確認してください。', //'Parameter object_id is mandatory when link_attr is specified. Check the definition of the display template.',
|
||||
'UI:Error:MandatoryTemplateParameter_target_attr' => 'link_attrを指定する場合は、target_attrパラメータは必須です。表示テンプレートの定義を確認してください。', //'Parameter target_attr is mandatory when link_attr is specified. Check the definition of the display template.',
|
||||
'UI:Error:MandatoryTemplateParameter_group_by' => 'group_byパラメータは必須です。表示テンプレートの定義を確認してください。', //'Parameter group_by is mandatory. Check the definition of the display template.',
|
||||
'UI:Error:InvalidGroupByFields' => 'Invalid list of fields to group by: "%1$s".',
|
||||
'UI:Error:UnsupportedStyleOfBlock' => 'エラー:"%1$s"はサポートされていないブロックスタイルです。', //'Error: unsupported style of block: "%1$s".',
|
||||
'UI:Error:IncorrectLinkDefinition_LinkedClass_Class' => 'リンク定義が正しくありません。管理オブジェクトのクラス:%1Ss は、クラス %2$s クラスの外部キーとして見つかりません。', //'Incorrect link definition: the class of objects to manage: %1$s was not found as an external key in the class %2$s',
|
||||
'UI:Error:Object_Class_Id_NotFound' => 'オブジェクト:%1$s:%2$d が見つかりません。', //'Object: %1$s:%2$d not found.',
|
||||
'UI:Error:WizardCircularReferenceInDependencies' => 'エラー: フィールド間の依存関係に循環参照があります。データモデルを確認してください。', //'Error: Circular reference in the dependencies between the fields, check the data model.',
|
||||
'UI:Error:UploadedFileTooBig' => 'アップロードファイルが大きすぎます(上限は %1$s )。PHPの設定にある、upload_max_filesizeと、post_max_sizeを確認してください。', //'Uploaded file is too big. (Max allowed size is %1$s). Check you PHP configuration for upload_max_filesize and post_max_size.',
|
||||
'UI:Error:UploadedFileTruncated.' => 'アップロードファイルが切り捨てられました!', //'Uploaded file has been truncated !',
|
||||
'UI:Error:NoTmpDir' => 'この一時ディレクトリは定義されていません。', //'The temporary directory is not defined.',
|
||||
'UI:Error:CannotWriteToTmp_Dir' => '一時ファイルをディスクに書き込めません。upload_tmp_dir = "%1$s" です。', //'Unable to write the temporary file to the disk. upload_tmp_dir = "%1$s".',
|
||||
'UI:Error:UploadStoppedByExtension_FileName' => 'extensionにより、アップロードを停止しました。(オリジナルのファイル名は"%1$s"です)。', //'Upload stopped by extension. (Original file name = "%1$s").',
|
||||
'UI:Error:UploadFailedUnknownCause_Code' => 'ファイルのアップロードに失敗しました。原因は不明(エラーコード: "%1$s")です。', //'File upload failed, unknown cause. (Error code = "%1$s").',
|
||||
|
||||
'UI:Error:1ParametersMissing' => 'エラー: この操作には下記のパラメータを指定する必要があります:%1$s', //'Error: the following parameter must be specified for this operation: %1$s.',
|
||||
'UI:Error:2ParametersMissing' => 'エラー:この操作には、下記のパラメータを指定する必要があります:%1$s , %2$s', //'Error: the following parameters must be specified for this operation: %1$s and %2$s.',
|
||||
'UI:Error:3ParametersMissing' => 'エラー:この操作には、下記のパラメータを指定する必要があります:%1$s, %2$s, %3$s', //Error: the following parameters must be specified for this operation: %1$s, %2$s and %3$s.',
|
||||
'UI:Error:4ParametersMissing' => 'エラー:この操作には、下記のパラメータを指定する必要があります:%1$s, %2$s, %3$s,%4$s', //'Error: the following parameters must be specified for this operation: %1$s, %2$s, %3$s and %4$s.',
|
||||
'UI:Error:IncorrectOQLQuery_Message' => 'エラー:OQLクエリが正しくありません:%1$s', //'Error: incorrect OQL query: %1$s',
|
||||
'UI:Error:AnErrorOccuredWhileRunningTheQuery_Message' => 'クエリ;%1$s 実行中にエラーが発生しました。', //'An error occured while running the query: %1$s',
|
||||
'UI:Error:ObjectAlreadyUpdated' => 'エラー:このオブジェクトはすでに更新済みです。', //'Error: the object has already been updated.',
|
||||
'UI:Error:ObjectCannotBeUpdated' => 'エラー:オブジェクトを更新できません。', //'Error: object cannot be updated.',
|
||||
'UI:Error:ObjectsAlreadyDeleted' => 'エラー:オブジェクトは既に削除されています。', //'Error: objects have already been deleted!',
|
||||
'UI:Error:BulkDeleteNotAllowedOn_Class' => '%1$s クラスのオブジェクトに対するバルク削除は許可されていません。', //'You are not allowed to perform a bulk delete of objects of class %1$s',
|
||||
'UI:Error:DeleteNotAllowedOn_Class' => '%1$s クラスのオブジェクトの削除は許可されていません。', //'You are not allowed to delete objects of class %1$s',
|
||||
'UI:Error:BulkModifyNotAllowedOn_Class' => '%1$s クラスのオブジェクトに対するバルクアップデート処理の実行は許可されていません。', //'You are not allowed to perform a bulk update of objects of class %1$s',
|
||||
'UI:Error:ObjectAlreadyCloned' => 'エラー:このオブジェクトはすでに、クローニングされています。', // 'Error: the object has already been cloned!',
|
||||
'UI:Error:ObjectAlreadyCreated' => 'エラー:このオブジェクトは既に生成済みです。', //'Error: the object has already been created!',
|
||||
'UI:Error:Invalid_Stimulus_On_Object_In_State' => 'エラー:Error: invalid stimulus "%1$s" on object %2$s in state "%3$s".',
|
||||
|
||||
|
||||
'UI:GroupBy:Count' => 'カウント', //'Count',
|
||||
'UI:GroupBy:Count+' => '要素数', //'Number of elements',
|
||||
'UI:CountOfObjects' => '%1$d 個のオブジェクトが条件にマッチしました。', //'%1$d objects matching the criteria.',
|
||||
'UI_CountOfObjectsShort' => '%1$d オブジェクトです。', //'%1$d objects.',
|
||||
'UI:NoObject_Class_ToDisplay' => '表示できる %1$s はありません。', //'No %1$s to display',
|
||||
'UI:History:LastModified_On_By' => '最終更新日: %1$s ( %2$s )', //'Last modified on %1$s by %2$s.',
|
||||
'UI:HistoryTab' => '履歴', //'History',
|
||||
'UI:NotificationsTab' => '通知', //'Notifications',
|
||||
'UI:History:BulkImports' => '履歴', //'History',
|
||||
'UI:History:BulkImports+' => 'CSVインポートのリスト(last first)', //'List of CSV imports (last first)',
|
||||
'UI:History:BulkImportDetails' => '%2$s により実行された %1$s へのCSVインポート結果の変更???', // 'Changes resulting from the CSV import performed on %1$s (by %2$s)',
|
||||
'UI:History:Date' => '日付',//'Date',
|
||||
'UI:History:Date+' => '更新日時', //'Date of the change',
|
||||
'UI:History:User' => 'ユーザ', //'User',
|
||||
'UI:History:User+' => 'この変更を行ったユーザ', //'User who made the change',
|
||||
'UI:History:Changes' => '変更', //'Changes',
|
||||
'UI:History:Changes+' => 'このオブジェクトを変更する', //'Changes made to the object',
|
||||
'UI:History:StatsCreations' => '生成された', //'Created',
|
||||
'UI:History:StatsCreations+' => '生成されたオブジェクト数', //'Count of objects created',
|
||||
'UI:History:StatsModifs' => '修正された', //'Modified',
|
||||
'UI:History:StatsModifs+' => '修正されたオブジェクト数', //'Count of objects modified',
|
||||
'UI:History:StatsDeletes' => '削除された', //'Deleted',
|
||||
'UI:History:StatsDeletes+' => '削除されたオブジェクト数', //'Count of objects deleted',
|
||||
'UI:Loading' => '読み込み...', //'Loading...',
|
||||
'UI:Menu:Actions' => '実行...', //'Actions',
|
||||
'UI:Menu:OtherActions' => '実行...', //'Actions',
|
||||
'UI:Menu:New' => '新規...', //'New...',
|
||||
'UI:Menu:Add' => '追加...', //'Add...',
|
||||
'UI:Menu:Manage' => '管理する...', //'Manage...',
|
||||
'UI:Menu:EMail' => 'Eメール', //'eMail',
|
||||
'UI:Menu:CSVExport' => 'CSVエクスポート', //'CSV Export',
|
||||
'UI:Menu:Modify' => '修正する...', //'Modify...',
|
||||
'UI:Menu:Delete' => '削除する...', //'Delete...',
|
||||
'UI:Menu:Manage' => '管理する...', //'Manage...',
|
||||
'UI:Menu:BulkDelete' => '削除する', //'Delete...',
|
||||
'UI:UndefinedObject' => '未定義', //'undefined',
|
||||
'UI:Document:OpenInNewWindow:Download' => '新規ウィンドウで開く: %1$s, ダウンロード: %2$s', //'Open in new window: %1$s, Download: %2$s',
|
||||
'UI:SelectAllToggle+' => 'すべて選択 / すべて非選択', //'Select / Deselect All',
|
||||
'UI:TruncatedResults' => '%1$d objects displayed out of %2$d',
|
||||
'UI:DisplayAll' => 'すべて表示', //'Display All',
|
||||
'UI:CollapseList' => '折り畳む', //'Collapse',
|
||||
'UI:CountOfResults' => '%1$d オブジェクト', //'%1$d object(s)',
|
||||
'UI:ChangesLogTitle' => '変更履歴(%1$d)', //'Changes log (%1$d):',
|
||||
'UI:EmptyChangesLogTitle' => '変更履歴は空です。', //'Changes log is empty',
|
||||
'UI:SearchFor_Class_Objects' => '%1$s オブジェクトを検索', //'Search for %1$s Objects',
|
||||
'UI:OQLQueryBuilderTitle' => 'OQLクエリビルダ', //'OQL Query Builder',
|
||||
'UI:OQLQueryTab' => 'OQLクエリ', //'OQL Query',
|
||||
'UI:SimpleSearchTab' => '単純検索', //'Simple Search',
|
||||
'UI:Details+' => '詳細情報', //'Details',
|
||||
'UI:SearchValue:Any' => '* 任意 *', //'* Any *',
|
||||
'UI:SearchValue:Mixed' => '* 混成 *', //'* mixed *',
|
||||
'UI:SelectOne' => '-- 選んでください --', //'-- select one --',
|
||||
'UI:Login:Welcome' => 'iTopへようこそ', //'Welcome to iTop!',
|
||||
'UI:Login:IncorrectLoginPassword' => 'ログイン/パスワードが正しくありません。再度ログインしてください。', //'Incorrect login/password, please try again.',
|
||||
'UI:Login:IdentifyYourself' => '続けて作業を行う前に認証を受けてください。', //'Identify yourself before continuing',
|
||||
'UI:Login:UserNamePrompt' => 'ユーザ名', //'User Name',
|
||||
'UI:Login:PasswordPrompt' => 'パスワード', //'Password',
|
||||
'UI:Login:ChangeYourPassword' => 'パスワードを変更してください', //'Change Your Password',
|
||||
'UI:Login:OldPasswordPrompt' => '既存パスワード',//'Old password',
|
||||
'UI:Login:NewPasswordPrompt' => '新規パスワード', //'New password',
|
||||
'UI:Login:RetypeNewPasswordPrompt' => '新規パスワードを再度入力してください。', //'Retype new password',
|
||||
'UI:Login:IncorrectOldPassword' => 'エラー:既存パスワードが正しくありません。', //'Error: the old password is incorrect',
|
||||
'UI:LogOffMenu' => 'ログオフ', //'Log off',
|
||||
'UI:LogOff:ThankYou' => 'iTopをご利用いただき、ありがとうございます。', //'Thank you for using iTop',
|
||||
'UI:LogOff:ClickHereToLoginAgain' => '再度ログインするにはここをクリックしてください...', //'Click here to login again...',
|
||||
'UI:ChangePwdMenu' => 'パスワードを変更する...', //'Change Password...',
|
||||
'UI:AccessRO-All' => 'iTopは参照のみ有効です。', //'iTop is read-only',
|
||||
'UI:AccessRO-Users' => 'エンドユーザの方はiTopは参照のみ有効です。', //'iTop is read-only for end-users',
|
||||
'UI:Login:RetypePwdDoesNotMatch' => '2度入力された新規パスワードが一致しません!', //'New password and retyped new password do not match !',
|
||||
'UI:Button:Login' => 'iTopへ入る', //'Enter iTop',
|
||||
'UI:Login:Error:AccessRestricted' => 'iTopへのアクセスは制限されています。iTop管理者に問い合わせしてください。', //'iTop access is restricted. Please, contact an iTop administrator.',
|
||||
'UI:Login:Error:AccessAdmin' => '管理者権限をもつユーザにアクセスが制限されています。iTop管理者に問い合わせしてください。', //'Access restricted to people having administrator privileges. Please, contact an iTop administrator.',
|
||||
'UI:CSVImport:MappingSelectOne' => '-- 選択してください --', //'-- select one --',
|
||||
'UI:CSVImport:MappingNotApplicable' => '--このフィールドを無視する --', //'-- ignore this field --',
|
||||
'UI:CSVImport:NoData' => 'データが空です..., データを指定してください。', // 'Empty data set..., please provide some data!',
|
||||
'UI:Title:DataPreview' => 'データプレビュー', //'Data Preview',
|
||||
'UI:CSVImport:ErrorOnlyOneColumn' => 'エラー:このデータにはカラムが1つしか含まれていません。適切なセパレータ文字を選択しましたか?', //'Error: The data contains only one column. Did you select the appropriate separator character?',
|
||||
'UI:CSVImport:FieldName' => 'フィールド: %1$d', //'Field %1$d',
|
||||
'UI:CSVImport:DataLine1' => 'データ行 1', //'Data Line 1',
|
||||
'UI:CSVImport:DataLine2' => 'データ行 2', //'Data Line 2',
|
||||
'UI:CSVImport:idField' => 'ID (プライマリキー)', //'id (Primary Key)',
|
||||
'UI:Title:BulkImport' => 'iTop - バルクインポート', //'iTop - Bulk import',
|
||||
'UI:Title:BulkImport+' => 'CSV インポートウィザード', //'CSV Import Wizard',
|
||||
'UI:Title:BulkSynchro_nbItem_ofClass_class' => '%2$s クラスの %1$d オブジェクトを同期', //'Synchronization of %1$d objects of class %2$s',
|
||||
'UI:CSVImport:ClassesSelectOne' => '--選択してください --', //'-- select one --',
|
||||
'UI:CSVImport:ErrorExtendedAttCode' => '内部エラー: "%2$s" は"%3$s"クラスの外部キーではないので、"%1$s" は正しくないコードです。', // 'Internal error: "%1$s" is an incorrect code because "%2$s" is NOT an external key of the class "%3$s"',
|
||||
'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d オブジェクトが変更されないままです。', //'%1$d objects(s) will stay unchanged.',
|
||||
'UI:CSVImport:ObjectsWillBeModified' => '%1$d オブジェクトが修正されます。', //'%1$d objects(s) will be modified.',
|
||||
'UI:CSVImport:ObjectsWillBeAdded' => '%1$d オブジェクトが追加されます。', //'%1$d objects(s) will be added.',
|
||||
'UI:CSVImport:ObjectsWillHaveErrors' => '%1$d オブジェクトにエラーがあります。', //'%1$d objects(s) will have errors.',
|
||||
'UI:CSVImport:ObjectsRemainedUnchanged' => '%1$d オブジェクトは変更されていません。', //'%1$d objects(s) remained unchanged.',
|
||||
'UI:CSVImport:ObjectsWereModified' => '%1$d オブジェクトが変更されました。', //'%1$d objects(s) were modified.',
|
||||
'UI:CSVImport:ObjectsWereAdded' => '%1$d オブジェクトが追加されました。', //'%1$d objects(s) were added.',
|
||||
'UI:CSVImport:ObjectsHadErrors' => '%1$s オブジェクトにエラーがあります。', //'%1$d objects(s) had errors.',
|
||||
'UI:Title:CSVImportStep2' => 'ステップ2/5: CSVデータオプション', //'Step 2 of 5: CSV data options',
|
||||
'UI:Title:CSVImportStep3' => 'ステップ3/5: データマッピング', //'Step 3 of 5: Data mapping',
|
||||
'UI:Title:CSVImportStep4' => 'ステップ4/5: インポートシミュレーション', //'Step 4 of 5: Import simulation',
|
||||
'UI:Title:CSVImportStep5' => 'ステップ5/5: インポート完了', //'Step 5 of 5: Import completed',
|
||||
'UI:CSVImport:LinesNotImported' => 'ロードできなかった行:', //'Lines that could not be loaded:',
|
||||
'UI:CSVImport:LinesNotImported+' => '下記の行はエラーが含まれていたのでインポートされませんでした。', //'The following lines have not been imported because they contain errors',
|
||||
'UI:CSVImport:SeparatorComma+' => ', (コンマ)', //', (comma)',
|
||||
'UI:CSVImport:SeparatorSemicolon+' => '; (セミコロン)', //'; (semicolon)',
|
||||
'UI:CSVImport:SeparatorTab+' => 'タブ', //'tab',
|
||||
'UI:CSVImport:SeparatorOther' => 'その他:', //'other:',
|
||||
'UI:CSVImport:QualifierDoubleQuote+' => '" (ダブルクォート)', //'" (double quote)',
|
||||
'UI:CSVImport:QualifierSimpleQuote+' => '\' (シングルクォート)', //'\' (simple quote)',
|
||||
'UI:CSVImport:QualifierOther' => 'その他:', //'other:',
|
||||
'UI:CSVImport:TreatFirstLineAsHeader' => '1行めをヘッダ(カラム名)として扱う', // 'Treat the first line as a header (column names)',
|
||||
'UI:CSVImport:Skip_N_LinesAtTheBeginning' => 'ファイル冒頭の%1$s 行をスキップする', //'Skip %1$s line(s) at the beginning of the file',
|
||||
'UI:CSVImport:CSVDataPreview' => 'CSVデータプレビュー', //'CSV Data Preview',
|
||||
'UI:CSVImport:SelectFile' => 'インポートするファイルを選択してください:', //'Select the file to import:',
|
||||
'UI:CSVImport:Tab:LoadFromFile' => 'ファイルからロードしてください', //'Load from a file',
|
||||
'UI:CSVImport:Tab:CopyPaste' => 'データをコピーペーストしてください', //'Copy and paste data',
|
||||
'UI:CSVImport:Tab:Templates' => 'テンプレート', //'Templates',
|
||||
'UI:CSVImport:PasteData' => 'インポートするデータをペーストしてください', //'Paste the data to import:',
|
||||
'UI:CSVImport:PickClassForTemplate' => 'ダウンロードするテンプレートを選んでください', //'Pick the template to download: ',
|
||||
'UI:CSVImport:SeparatorCharacter' => 'セパレータ文字', //'Separator character:',
|
||||
'UI:CSVImport:TextQualifierCharacter' => 'テキスト識別文字', //'Text qualifier character',
|
||||
'UI:CSVImport:CommentsAndHeader' => 'コメントとヘッダ', //'Comments and header',
|
||||
'UI:CSVImport:SelectClass' => 'インポートするクラスを選択してください', //'Select the class to import:',
|
||||
'UI:CSVImport:AdvancedMode' => '拡張モード', //'Advanced mode',
|
||||
'UI:CSVImport:AdvancedMode+' => '拡張モードでは、オブジェクトに付与されている"id"(プライマリキー)がオブジェクトの更新、リネームに指定可能です。' . //In advanced mode the "id" (primary key) of the objects can be used to update and rename objects.' .
|
||||
'しかしながら、"id"カラムは(たとえ存在しても)検索条件として指定できるのみであり、他の検索条件と組み合わせて利用することはできません。', //'However the column "id" (if present) can only be used as a search criteria and can not be combined with any other search criteria.',
|
||||
'UI:CSVImport:SelectAClassFirst' => 'マッピングを設定するには、まず最初にクラスを選択してください。', //'To configure the mapping, select a class first.',
|
||||
'UI:CSVImport:HeaderFields' => 'フィールド', //'Fields',
|
||||
'UI:CSVImport:HeaderMappings' => 'マッピング', //'Mappings',
|
||||
'UI:CSVImport:HeaderSearch' => '検索しますか?', //'Search?',
|
||||
'UI:CSVImport:AlertIncompleteMapping' => 'すべてのフィールドのマッピングを選択してください。', //'Please select a mapping for every field.',
|
||||
'UI:CSVImport:AlertNoSearchCriteria' => '少なくとも1つ以上の検索条件を選択してください。', //'Please select at least one search criteria',
|
||||
'UI:CSVImport:Encoding' => '文字エンコーディング', //'Character encoding',
|
||||
'UI:UniversalSearchTitle' => 'iTop - ユニバーサルサーチ', //'iTop - Universal Search',
|
||||
'UI:UniversalSearch:Error' => 'エラー:%1$s', //'Error: %1$s',
|
||||
'UI:UniversalSearch:LabelSelectTheClass' => '検索するクラスを選択してください。', //'Select the class to search: ',
|
||||
|
||||
'UI:Audit:Title' => 'iTop - CMDB 監査', //'iTop - CMDB Audit',
|
||||
'UI:Audit:InteractiveAudit' => '対話型監査', //'Interactive Audit',
|
||||
'UI:Audit:HeaderAuditRule' => '監査ルール', //'Audit Rule',
|
||||
'UI:Audit:HeaderNbObjects' => 'オブジェクト数', //'# Objects',
|
||||
'UI:Audit:HeaderNbErrors' => 'エラー数', //'# Errors',
|
||||
'UI:Audit:PercentageOk' => '% OK', //'% Ok',
|
||||
|
||||
'UI:RunQuery:Title' => 'iTop - OQLクエリ評価', //'iTop - OQL Query Evaluation',
|
||||
'UI:RunQuery:QueryExamples' => 'クエリの例', //'Query Examples',
|
||||
'UI:RunQuery:HeaderPurpose' => '目的', //'Purpose',
|
||||
'UI:RunQuery:HeaderPurpose+' => 'クエリについての説明', //'Explanation about the query',
|
||||
'UI:RunQuery:HeaderOQLExpression' => 'OQL式', //'OQL Expression',
|
||||
'UI:RunQuery:HeaderOQLExpression+' => 'OQL文法によるクエリ', //'The query in OQL syntax',
|
||||
'UI:RunQuery:ExpressionToEvaluate' => '評価式', //'Expression to evaluate: ',
|
||||
'UI:RunQuery:MoreInfo' => '本クエリに関する詳細情報', //'More information about the query: ',
|
||||
'UI:RunQuery:DevelopedQuery' => 'クエリ式の再開発', //'Redevelopped query expression: ',
|
||||
'UI:RunQuery:SerializedFilter' => '序列化フィルタ:', //'Serialized filter: ',
|
||||
'UI:RunQuery:Error' => '本クエリ実行時にエラーが発生しました:%1$s', //'An error occured while running the query: %1$s',
|
||||
|
||||
'UI:Schema:Title' => 'iTop オブジェクトスキーマ', //'iTop objects schema',
|
||||
'UI:Schema:CategoryMenuItem' => 'カテゴリ <b>%1$s</b>', //'Category <b>%1$s</b>',
|
||||
'UI:Schema:Relationships' => '関連', //'Relationships',
|
||||
'UI:Schema:AbstractClass' => '抽象クラス:このクラスのインスタンスを生成することはできません。', //'Abstract class: no object from this class can be instantiated.',
|
||||
'UI:Schema:NonAbstractClass' => '非抽象クラス:このクラスのインスタンスを生成できます。', //'Non abstract class: objects from this class can be instantiated.',
|
||||
'UI:Schema:ClassHierarchyTitle' => 'クラス階層', //'Class hierarchy',
|
||||
'UI:Schema:AllClasses' => '全クラス', //'All classes',
|
||||
'UI:Schema:ExternalKey_To' => '%1$s の外部キー', //'External key to %1$s',
|
||||
'UI:Schema:Columns_Description' => 'カラム: <em>%1$s</em>', //'Columns: <em>%1$s</em>',
|
||||
'UI:Schema:Default_Description' => 'デフォルト: "%1$s"', //'Default: "%1$s"',
|
||||
'UI:Schema:NullAllowed' => 'Null許容', //'Null Allowed',
|
||||
'UI:Schema:NullNotAllowed' => 'Null 非許容', //'Null NOT Allowed',
|
||||
'UI:Schema:Attributes' => '属性', //'Attributes',
|
||||
'UI:Schema:AttributeCode' => '属性コード', //'Attribute Code',
|
||||
'UI:Schema:AttributeCode+' => '属性の内部コード', //'Internal code of the attribute',
|
||||
'UI:Schema:Label' => 'ラベル', //'Label',
|
||||
'UI:Schema:Label+' => '属性のラベル', //'Label of the attribute',
|
||||
'UI:Schema:Type' => '型', //'Type',
|
||||
|
||||
'UI:Schema:Type+' => '属性のデータ型', //'Data type of the attribute',
|
||||
'UI:Schema:Origin' => 'オリジン', //'Origin',
|
||||
'UI:Schema:Origin+' => 'この属性が定義されているベースクラス', //'The base class in which this attribute is defined',
|
||||
'UI:Schema:Description' => '概要', //'Description',
|
||||
'UI:Schema:Description+' => '本属性の概要', //'Description of the attribute',
|
||||
'UI:Schema:AllowedValues' => '取りうる値', //'Allowed values',
|
||||
'UI:Schema:AllowedValues+' => '本属性で取りうる値の制限', //'Restrictions on the possible values for this attribute',
|
||||
'UI:Schema:MoreInfo' => '詳細情報', //'More info',
|
||||
'UI:Schema:MoreInfo+' => 'データベースに定義された本フィールドの詳細情報', //'More information about the field defined in the database',
|
||||
'UI:Schema:SearchCriteria' => '検索条件', //'Search criteria',
|
||||
'UI:Schema:FilterCode' => 'フィルタコード', //'Filter code',
|
||||
'UI:Schema:FilterCode+' => '本検索条件のコード', //'Code of this search criteria',
|
||||
'UI:Schema:FilterDescription' => '概要', //'Description',
|
||||
'UI:Schema:FilterDescription+' => '本検索条件の概要', //'Description of this search criteria',
|
||||
'UI:Schema:AvailOperators' => '利用可能な演算子', //'Available operators',
|
||||
'UI:Schema:AvailOperators+' => '本検索条件で利用可能な演算子', //'Possible operators for this search criteria',
|
||||
'UI:Schema:ChildClasses' => '子クラス', //'Child classes',
|
||||
'UI:Schema:ReferencingClasses' => '参照クラス', //'Referencing classes',
|
||||
'UI:Schema:RelatedClasses' => '関係するクラス', //'Related classes',
|
||||
'UI:Schema:LifeCycle' => 'ライフサイクル', //'Life cycle',
|
||||
'UI:Schema:Triggers' => 'トリガ', //'Triggers',
|
||||
'UI:Schema:Relation_Code_Description' => 'リレーション <em>%1$s</em> (%2$s)', //'Relation <em>%1$s</em> (%2$s)',
|
||||
'UI:Schema:RelationDown_Description' => '下へ: %1$s', //'Down: %1$s',
|
||||
'UI:Schema:RelationUp_Description' => '上へ: $1$s', //'Up: %1$s',
|
||||
'UI:Schema:RelationPropagates' => '%1$s: %2$d レベルへ伝播、クエリ:%3$s', //'%1$s: propagate to %2$d levels, query: %3$s',
|
||||
'UI:Schema:RelationDoesNotPropagate' => '%1$s: 伝播しない (%2$d レベル), クエリ: %3$s', //'%1$s: does not propagates (%2$d levels), query: %3$s',
|
||||
'UI:Schema:Class_ReferencingClasses_From_By' => '%1$s は%2$s クラスから %3$s フィールドにより参照されている', //'%1$s is referenced by the class %2$s via the field %3$s',
|
||||
'UI:Schema:Class_IsLinkedTo_Class_Via_ClassAndAttribute' => '%1$s は %3$s::<em>%4$s</em>により%2$s へリンクされています。', //'%1$s is linked to %2$s via %3$s::<em>%4$s</em>',
|
||||
'UI:Schema:Links:1-n' => 'クラスは%1$sへポイントしています。(1:n リンク)', //'Classes pointing to %1$s (1:n links):',
|
||||
'UI:Schema:Links:n-n' => 'クラスは%1$sへリンクしています。(n:n リンク)', //'Classes linked to %1$s (n:n links):',
|
||||
'UI:Schema:Links:All' => '関連する全クラスのグラフ表示', //'Graph of all related classes',
|
||||
'UI:Schema:NoLifeCyle' => 'このクラスにはライフサイクルが定義されていません。', //'There is no life cycle defined for this class.',
|
||||
'UI:Schema:LifeCycleTransitions' => 'トランジション', //'Transitions',
|
||||
'UI:Schema:LifeCyleAttributeOptions' => '属性オプション', //'Attribute options',
|
||||
'UI:Schema:LifeCycleHiddenAttribute' => '隠し', //'Hidden',
|
||||
'UI:Schema:LifeCycleReadOnlyAttribute' => '参照限定',// 'Read-only',
|
||||
'UI:Schema:LifeCycleMandatoryAttribute' => '必須', //'Mandatory',
|
||||
'UI:Schema:LifeCycleAttributeMustChange' => '変更必須', //'Must change',
|
||||
'UI:Schema:LifeCycleAttributeMustPrompt' => 'ユーザはこの値を変更するよう、促されます。', //'User will be prompted to change the value',
|
||||
'UI:Schema:LifeCycleEmptyList' => '空リスト', //'empty list',
|
||||
|
||||
'UI:LinksWidget:Autocomplete+' => '最初の3文字をタイプしてください...', //'Type the first 3 characters...',
|
||||
'UI:Combo:SelectValue' => '--- 値を選んでください ---', //'--- select a value ---',
|
||||
'UI:Label:SelectedObjects' => '選択されたオブジェクト: ', //'Selected objects: ',
|
||||
'UI:Label:AvailableObjects' => '選択可能なオブジェクト: ', //'Available objects: ',
|
||||
'UI:Link_Class_Attributes' => '%1$s 属性', //'%1$s attributes',
|
||||
'UI:SelectAllToggle+' => '全部を選択 / 全部を非選択', //'Select All / Deselect All',
|
||||
'UI:AddObjectsOf_Class_LinkedWith_Class_Instance' => '%2$s にリンクされた%1$sオブジェクトを追加:%3$s', //'Add %1$s objects linked with %2$s: %3$s',
|
||||
'UI:AddObjectsOf_Class_LinkedWith_Class' => '$1$s オブジェクトを%2$sとのリンクに追加', //'Add %1$s objects to link with the %2$s',
|
||||
'UI:ManageObjectsOf_Class_LinkedWith_Class_Instance' => '%2$s とりんくされた%1$sオブジェクトを管理する: %3$s', //'Manage %1$s objects linked with %2$s: %3$s',
|
||||
'UI:AddLinkedObjectsOf_Class' => '%1$s を追加...', //'Add %1$ss...',
|
||||
'UI:RemoveLinkedObjectsOf_Class' => '選択したオブジェクトを除外', //'Remove selected objects',
|
||||
'UI:Message:EmptyList:UseAdd' => 'リストは空です。"追加..."ボタンを利用して要素を追加してください。', //'The list is empty, use the "Add..." button to add elements.',
|
||||
'UI:Message:EmptyList:UseSearchForm' => '上の検索フォームを使って追加するオブジェクトを検索してください。', //'Use the search form above to search for objects to be added.',
|
||||
|
||||
'UI:Wizard:FinalStepTitle' => '最終ステップ:コンファーム', //'Final step: confirmation',
|
||||
'UI:Title:DeletionOf_Object' => '%1$sの削除', //'Deletion of %1$s',
|
||||
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => '%2$s クラスの%1$d個のオブジェクトをバルク削除', //'Bulk deletion of %1$d objects of class %2$s',
|
||||
'UI:Delete:NotAllowedToDelete' => 'このオブジェクトを削除する権限がありません。', //'You are not allowed to delete this object',
|
||||
'UI:Delete:NotAllowedToUpdate_Fields' => '以下のフィールドを更新する権限が与えられていません: %1$s', //'You are not allowed to update the following field(s): %1$s',
|
||||
'UI:Error:NotEnoughRightsToDelete' => 'カレントユーザは十分な権限を持っていないので、このオブジェクトは削除することができません。', //'This object could not be deleted because the current user do not have sufficient rights',
|
||||
'UI:Error:CannotDeleteBecauseOfDepencies' => 'いくつかのマニュアル操作を先に実装する必要があるので、このオブジェクトは削除できません。', //'This object could not be deleted because some manual operations must be performed prior to that',
|
||||
'UI:Archive_User_OnBehalfOf_User' => '%2$s を代表して %1$s', // '%1$s on behalf of %2$s',
|
||||
'UI:Delete:AutomaticallyDeleted' => '自動的に削除されました。', //'automatically deleted',
|
||||
'UI:Delete:AutomaticResetOf_Fields' => 'フィールドの自動リセット: %1$s', //'automatic reset of field(s): %1$s',
|
||||
'UI:Delete:CleaningUpRefencesTo_Object' => '%1$s への参照すべてをクリア', //'Cleaning up all references to %1$s...',
|
||||
'UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class' => '%2$s クラスの %1$d個のオブジェクトへの参照をすべてクリア', //'Cleaning up all references to %1$d objects of class %2$s...',
|
||||
'UI:Delete:Done+' => '実行しました...???', //'What was done...',
|
||||
'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s 削除しました。', //'%1$s - %2$s deleted.',
|
||||
'UI:Delete:ConfirmDeletionOf_Name' => '%1$s の削除', //'Deletion of %1$s',
|
||||
'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => '%2$sクラスの%1$dオブジェクトの削除', //'Deletion of %1$d objects of class %2$s',
|
||||
'UI:Delete:ShouldBeDeletedAtomaticallyButNotAllowed' => '自動的に削除されるべきだが、そのための権限がありません。', //'Should be automaticaly deleted, but you are not allowed to do so',
|
||||
'UI:Delete:MustBeDeletedManuallyButNotAllowed' => '手動で削除されるべきだが、このオブジェクトを削除するための権限がありません。アプリケーション管理者に問い合わせてください。', //'Must be deleted manually - but you are not allowed to delete this object, please contact your application admin',
|
||||
'UI:Delete:WillBeDeletedAutomatically' => '自動的に削除されます。', //'Will be automaticaly deleted',
|
||||
'UI:Delete:MustBeDeletedManually' => '手動で削除されるべきです。', //'Must be deleted manually',
|
||||
'UI:Delete:CannotUpdateBecause_Issue' => '自動的に更新されるべきだが: %1$s', //'Should be automatically updated, but: %1$s',
|
||||
'UI:Delete:WillAutomaticallyUpdate_Fields' => 'は自動的に更新されます。(reset: %1$s)', //'will be automaticaly updated (reset: %1$s)',
|
||||
'UI:Delete:Count_Objects/LinksReferencing_Object' => '%1$dオブジェクト/リンクは%2$sを参照しています。', //'%1$d objects/links are referencing %2$s',
|
||||
'UI:Delete:Count_Objects/LinksReferencingTheObjects' => '%1$dオブジェクト/リンクは削除されるべきオブジェクトを参照しています。', //'%1$d objects/links are referencing some of the objects to be deleted',
|
||||
'UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity' => 'データベース一貫性を確実にするために、いくつかの参照を除去する必要があります。', //'To ensure Database integrity, any reference should be further eliminated',
|
||||
'UI:Delete:Consequence+' => 'What will be done',
|
||||
'UI:Delete:SorryDeletionNotAllowed' => '申し訳ございません。このオブジェクトを削除する権限がありません。上述の詳細説明を参照してください。', //'Sorry, you are not allowed to delete this object, see the detailed explanations above',
|
||||
'UI:Delete:PleaseDoTheManualOperations' => '本オブジェクトの削除を要求する前に、上記にリストされている操作を手動で行ってください。', //'Please perform the manual operations listed above prior to requesting the deletion of this object',
|
||||
'UI:Delect:Confirm_Object' => '%1$sを削除しようとしています。確認してください。', //'Please confirm that you want to delete %1$s.',
|
||||
'UI:Delect:Confirm_Count_ObjectsOf_Class' => '以下の%2$sクラスの%1$dオブジェクトを削除しようとしています。確認してください。', //'Please confirm that you want to delete the following %1$d objects of class %2$s.',
|
||||
'UI:WelcomeToITop' => 'iTopへようこそ', //'Welcome to iTop',
|
||||
'UI:DetailsPageTitle' => 'iTop - %1$s - %2$sの詳細', //'iTop - %1$s - %2$s details',
|
||||
'UI:ErrorPageTitle' => 'iTop - エラー', //'iTop - Error',
|
||||
'UI:ObjectDoesNotExist' => '申し訳ございません。このオブジェクトは既に存在しません。(あるいは参照する権限がありません。)', //'Sorry, this object does not exist (or you are not allowed to view it).',
|
||||
'UI:SearchResultsPageTitle' => 'iTop - 検索結果', //'iTop - Search Results',
|
||||
'UI:Search:NoSearch' => '検索するものがありません。', //'Nothing to search for',
|
||||
'UI:FullTextSearchTitle_Text' => '"%1$s"の結果:', //'Results for "%1$s":',
|
||||
'UI:Search:Count_ObjectsOf_Class_Found' => '%2$sクラスの%1$dオブジェクトが見つかりました。', //'%1$d object(s) of class %2$s found.',
|
||||
'UI:Search:NoObjectFound' => 'オブジェクトが見つかりませんでした。', //'No object found.',
|
||||
'UI:ModificationPageTitle_Object_Class' => 'iTop - %1$s - %2$s 修正???', //'iTop - %1$s - %2$s modification',
|
||||
'UI:ModificationTitle_Class_Object' => '%1$sの修正: <span class=\"hilite\">%2$s</span>', //'Modification of %1$s: <span class=\"hilite\">%2$s</span>',
|
||||
'UI:ClonePageTitle_Object_Class' => 'iTop - クローン%1$s - %2$s 修正???', //'iTop - Clone %1$s - %2$s modification',
|
||||
'UI:CloneTitle_Class_Object' => '%1$sのクローン:<span class=\"hilite">%2$s</span>', //'Clone of %1$s: <span class=\"hilite\">%2$s</span>',
|
||||
'UI:CreationPageTitle_Class' => 'iTop - 新規%1$sを生成', //'iTop - Creation of a new %1$s ',
|
||||
'UI:CreationTitle_Class' => '新規%1$sの生成', //'Creation of a new %1$s',
|
||||
'UI:SelectTheTypeOf_Class_ToCreate' => '生成する%1$sの型を選択', //'Select the type of %1$s to create:',
|
||||
'UI:Class_Object_NotUpdated' => '変更は検出されませんでした。%1$sは修正されて<strong>いません</strong>', //'No change detected, %1$s (%2$s) has <strong>not</strong> been modified.',
|
||||
'UI:Class_Object_Updated' => '%1$s (%2$s) は更新されました。', //'%1$s (%2$s) updated.',
|
||||
'UI:BulkDeletePageTitle' => 'iTop - バルク削除', //'iTop - Bulk Delete',
|
||||
'UI:BulkDeleteTitle' => '削除するオブジェクトを選択してください。', //'Select the objects you want to delete:',
|
||||
'UI:PageTitle:ObjectCreated' => 'iTopオブジェクトが生成されました。', //'iTop Object Created.',
|
||||
'UI:Title:Object_Of_Class_Created' => '%1$s - %2$s が生成されました。', //'%1$s - %2$s created.',
|
||||
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => '状態%3$sにある%1$sを状態%4$s状態をターゲットに、オブジェクト:%2$sに適用します。', //'Applying %1$s on object: %2$s in state %3$s to target state: %4$s.',
|
||||
'UI:ObjectCouldNotBeWritten' => 'そのオブジェクトは書き込みできません: %1$s', //'The object could not be written: %1$s',
|
||||
'UI:PageTitle:FatalError' => 'iTop - 致命的エラー', // 'iTop - Fatal Error',
|
||||
'UI:SystemIntrusion' => 'アクセスできません。権限のない操作を行おうとしています。', //'Access denied. You have trying to perform an operation that is not allowed for you.',
|
||||
'UI:FatalErrorMessage' => '致命的エラー、iTopは処理を継続できません。', //'Fatal error, iTop cannot continue.',
|
||||
'UI:Error_Details' => 'エラー:%1$s', //'Error: %1$s.',
|
||||
|
||||
'UI:PageTitle:ClassProjections' => 'iTop ユーザ管理', //'iTop user management - class projections',
|
||||
'UI:PageTitle:ProfileProjections' => 'iTop ユーザ管理 - プロファイル立案', //'iTop user management - profile projections',
|
||||
'UI:UserManagement:Class' => 'クラス', //'Class',
|
||||
'UI:UserManagement:Class+' => 'オブジェクトのクラス', //'Class of objects',
|
||||
'UI:UserManagement:ProjectedObject' => 'オブジェクト', //'Object',
|
||||
'UI:UserManagement:ProjectedObject+' => 'Projected object',
|
||||
'UI:UserManagement:AnyObject' => '* 任意 *', //'* any *',
|
||||
'UI:UserManagement:User' => 'ユーザ', //'User',
|
||||
'UI:UserManagement:User+' => 'User involved in the projection',
|
||||
'UI:UserManagement:Profile' => 'プロファイル', //'Profile',
|
||||
'UI:UserManagement:Profile+' => 'Profile in which the projection is specified',
|
||||
'UI:UserManagement:Action:Read' => '読み込み', //'Read',
|
||||
'UI:UserManagement:Action:Read+' => 'オブジェクトの読み込み/表示', //'Read/display objects',
|
||||
'UI:UserManagement:Action:Modify' => '修正', //'Modify',
|
||||
'UI:UserManagement:Action:Modify+' => 'オブジェクトの生成、編集(修正)', //'Create and edit (modify) objects',
|
||||
'UI:UserManagement:Action:Delete' => '削除', //'Delete',
|
||||
'UI:UserManagement:Action:Delete+' => 'オブジェクトの削除', //'Delete objects',
|
||||
'UI:UserManagement:Action:BulkRead' => '一括読み出し(エクスポート)', //'Bulk Read (Export)',
|
||||
'UI:UserManagement:Action:BulkRead+' => 'オブジェクトのリスト表示、もしくは一括エクスポート', // 'List objects or export massively',
|
||||
'UI:UserManagement:Action:BulkModify' => '一括修正', // 'Bulk Modify',
|
||||
'UI:UserManagement:Action:BulkModify+' => '一括生成/編集(CVSインポート)', //'Massively create/edit (CSV import)',
|
||||
'UI:UserManagement:Action:BulkDelete' => '一括削除', //'Bulk Delete',
|
||||
'UI:UserManagement:Action:BulkDelete+' => '複数オブジェクトをまとめて削除', //'Massively delete objects',
|
||||
'UI:UserManagement:Action:Stimuli' => 'Stimuli',
|
||||
'UI:UserManagement:Action:Stimuli+' => '許可されている(複合)アクション', //'Allowed (compound) actions',
|
||||
'UI:UserManagement:Action' => 'アクション', // 'Action',
|
||||
'UI:UserManagement:Action+' => 'ユーザが実行したアクション', // 'Action performed by the user',
|
||||
'UI:UserManagement:TitleActions' => 'アクション', //'Actions',
|
||||
'UI:UserManagement:Permission' => 'パーミッション', //'Permission',
|
||||
'UI:UserManagement:Permission+' => 'ユーザのパーミッション', // 'User\'s permissions',
|
||||
'UI:UserManagement:Attributes' => '属性', // 'Attributes',
|
||||
'UI:UserManagement:ActionAllowed:Yes' => 'はい', //'Yes',
|
||||
'UI:UserManagement:ActionAllowed:No' => 'いいえ', //'No',
|
||||
'UI:UserManagement:AdminProfile+' => '管理者にはデータベース中の全てのオブジェクトに対する読み/書きの全権限が与えられます。', //'Administrators have full read/write access to all objects in the database.',
|
||||
'UI:UserManagement:NoLifeCycleApplicable' => 'N/A',
|
||||
'UI:UserManagement:NoLifeCycleApplicable+' => 'この暮らすにはライフサイクルは定義されていません。', //'No lifecycle has been defined for this class',
|
||||
'UI:UserManagement:GrantMatrix' => '権限マトリクス', //'Grant Matrix',
|
||||
'UI:UserManagement:LinkBetween_User_And_Profile' => '%1$s と %2$s間のリンク', //'Link between %1$s and %2$s',
|
||||
'UI:UserManagement:LinkBetween_User_And_Org' => '%1$s と %2$s 間のリンク', // 'Link between %1$s and %2$s',
|
||||
|
||||
'Menu:AdminTools' => '管理ツール', //'Admin tools',
|
||||
'Menu:AdminTools+' => '管理ツール', //'Administration tools',
|
||||
'Menu:AdminTools?' => 'このツールは管理者プロファイルが設定されているユーザにのみアクセスが可能です。', //'Tools accessible only to users having the administrator profile',
|
||||
|
||||
'UI:ChangeManagementMenu' => '変更管理', //'Change Management',
|
||||
'UI:ChangeManagementMenu+' => '変更管理', //'Change Management',
|
||||
'UI:ChangeManagementMenu:Title' => '変更状況概観', //'Changes Overview',
|
||||
'UI-ChangeManagementMenu-ChangesByType' => '型別変更内容', //'Changes by type',
|
||||
'UI-ChangeManagementMenu-ChangesByStatus' => '状態別変更内容', //'Changes by status',
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'ワークグループ別変更内容', //'Changes by workgroup',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'まだアサインされていない変更', //'Changes not yet assigned',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> '設定項目', //'Configuration Items',
|
||||
'UI:ConfigurationItemsMenu+'=> 'すべてのデバイス', //'All Devices',
|
||||
'UI:ConfigurationItemsMenu:Title' => '設定項目概観', //'Configuration Items Overview',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'サーバ(by criticity)', // 'Servers by criticity',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PC (by criticity)', // 'PCs by criticity',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'ネットワークデバイス (by criticity)', // 'Network devices by criticity',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'アプリケーション (by criticity)', // 'Applications by criticity',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => 'コンフィグレーション管理', //'Configuration Management',
|
||||
'UI:ConfigurationManagementMenu+' => 'コンフィグレーション管理', // 'Configuration Management',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'インフラストラクチャ概観', // 'Infrastructure Overview',
|
||||
'UI-ConfigurationManagementMenu-InfraByType' => '型別インフラオブジェクト', // 'Infrastructure objects by type',
|
||||
'UI-ConfigurationManagementMenu-InfraByStatus' => '状態別インフラオブジェクト', // 'Infrastructure objects by status',
|
||||
|
||||
'UI:ConfigMgmtMenuOverview:Title' => 'コンフィグレーション管理用ダッシュボード', // 'Dashboard for Configuration Management',
|
||||
'UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus' => '状態別コンフィグレーション項目', //'Configuration Items by status',
|
||||
'UI-ConfigMgmtMenuOverview-FunctionalCIByType' => '型別コンフィグレーション項目', // 'Configuration Items by type',
|
||||
|
||||
'UI:RequestMgmtMenuOverview:Title' => 'リクエスト管理用ダッシュボード', // 'Dashboard for Request Management',
|
||||
'UI-RequestManagementOverview-RequestByService' => 'サービス別ユーザリクエスト', //'User Requests by service',
|
||||
'UI-RequestManagementOverview-RequestByPriority' => '優先度別ユーザリクエスト', // 'User Requests by priority',
|
||||
'UI-RequestManagementOverview-RequestUnassigned' => 'エージェントへ未アサインのユーザリクエスト', // 'User Requests not yet assigned to an agent',
|
||||
|
||||
'UI:IncidentMgmtMenuOverview:Title' => 'インシデント管理用ダッシュボード', // 'Dashboard for Incident Management',
|
||||
'UI-IncidentManagementOverview-IncidentByService' => 'サービス別インシデント', // 'Incidents by service',
|
||||
'UI-IncidentManagementOverview-IncidentByPriority' => '優先度別インシデント', // 'Incidents by priority',
|
||||
'UI-IncidentManagementOverview-IncidentUnassigned' => 'エージェントへ未アサインのインシデント', // 'Incidents not yet assigned to an agent',
|
||||
|
||||
'UI:ChangeMgmtMenuOverview:Title' => '変更管理用ダッシュボード', // 'Dashboard for Change Management',
|
||||
'UI-ChangeManagementOverview-ChangeByType' => '型別変更内容', // 'Changes by type',
|
||||
'UI-ChangeManagementOverview-ChangeUnassigned' => 'エージェントへ未アサインの変更内容', // 'Changes not yet assigned to an agent',
|
||||
'UI-ChangeManagementOverview-ChangeWithOutage' => '変更すべき一時停止???', // 'Outages due to changes',
|
||||
|
||||
'UI:ServiceMgmtMenuOverview:Title' => 'サービス管理用ダッシュボード', // 'Dashboard for Service Management',
|
||||
'UI-ServiceManagementOverview-CustomerContractToRenew' => '30日以内に契約更新が必要な顧客', // 'Customer contracts to be renewed in 30 days',
|
||||
'UI-ServiceManagementOverview-ProviderContractToRenew' => '30日以内に契約更新が必要なプロバイダ', // 'Provider contracts to be renewed in 30 days',
|
||||
|
||||
'UI:ContactsMenu' => 'コンタクト', // 'Contacts',
|
||||
'UI:ContactsMenu+' => 'コンタクト', // 'Contacts',
|
||||
'UI:ContactsMenu:Title' => 'コンタクト概観', // 'Contacts Overview',
|
||||
'UI-ContactsMenu-ContactsByLocation' => 'ロケーション別コンタクト', // 'Contacts by location',
|
||||
'UI-ContactsMenu-ContactsByType' => 'タイプ別コンタクト', // 'Contacts by type',
|
||||
'UI-ContactsMenu-ContactsByStatus' => '状態別コンタクト', //'Contacts by status',
|
||||
|
||||
'Menu:CSVImportMenu' => 'CSV インポート', // 'CSV import',
|
||||
'Menu:CSVImportMenu+' => '一括生成/一括更新', //'Bulk creation or update',
|
||||
|
||||
'Menu:DataModelMenu' => 'データモデル', // 'Data Model',
|
||||
'Menu:DataModelMenu+' => 'データモデル概観', // 'Overview of the Data Model',
|
||||
|
||||
'Menu:ExportMenu' => 'エクスポート', // 'Export',
|
||||
'Menu:ExportMenu+' => '任意のクエリ結果をHTML、CSV、XMLでエクスポートする', // 'Export the results of any query in HTML, CSV or XML',
|
||||
|
||||
'Menu:NotificationsMenu' => 'ノーティフィケーション', // 'Notifications',
|
||||
'Menu:NotificationsMenu+' => 'ノーティフィケーションの設定', // 'Configuration of the Notifications',
|
||||
'UI:NotificationsMenu:Title' => '<span class="hilite">ノーティフィケーション</span>の設定', // 'Configuration of the <span class="hilite">Notifications</span>',
|
||||
'UI:NotificationsMenu:Help' => 'ヘルプ', // 'Help'
|
||||
// 'UI:NotificationsMenu:HelpContent' => '<p>In iTop the notifications are fully customizable. They are based on two sets of objects: <i>triggers and actions</i>.</p>
|
||||
//<p><i><b>Triggers</b></i> define when a notification will be executed. There are 3 types of triggers for covering 3 differents phases of an object life cycle:
|
||||
//<ol>
|
||||
// <li>the "OnCreate" triggers get executed when an object of the specified class is created</li>
|
||||
// <li>the "OnStateEnter" triggers get executed before an object of the given class enters a specified state (coming from another state)</li>
|
||||
// <li>the "OnStateLeave" triggers get executed when an object of the given class is leaving a specified state</li>
|
||||
//</ol>
|
||||
//</p>
|
||||
//<p>
|
||||
//<i><b>Actions</b></i> define the actions to be performed when the triggers execute. For now there is only one kind of action consisting in sending an email message.
|
||||
//Such actions also define the template to be used for sending the email as well as the other parameters of the message like the recipients, importance, etc.
|
||||
//</p>
|
||||
//<p>A special page: <a href="../setup/email.test.php" target="_blank">email.test.php</a> is available for testing and troubleshooting your PHP mail configuration.</p>
|
||||
//<p>To be executed, actions must be associated to triggers.
|
||||
//When associated with a trigger, each action is given an "order" number, specifying in which order the actions are to be executed.</p>',
|
||||
|
||||
'UI:NotificationsMenu:HelpContent' => '<p>iTopでは、ノーティフィケーションはすべてカスタマイズが可能です。ノーティフィケーションは<i>トリガーとアクション</i>という二つのオブジェクトがベースになっています。
|
||||
<p><i><b>トリガー</b></i>は、あるノーティフィケーションがいつ実行されるのか、を定義する。トリガーは3つのタイプに分類され、オブジェクトライフサイクルにおける3つの異なるフェーズに対応する:
|
||||
<ol>
|
||||
<li>"onCreate"トリガーは、指定されたクラスのオブジェクトが生成されたときに実行される。</li>
|
||||
<li>"onStateEnter"トリガーは、指定されたクラスのオブジェクトが(他の状態から)指定された状態に入る前に実行される。</li>
|
||||
<li>"onStateLeave"トリガーは、指定されたクラスのオブジェクトが指定された状態から出る際に実行される。</li>
|
||||
</ol>
|
||||
</p>
|
||||
<p>
|
||||
<i><b>アクション</b></i>はトリガーが実行される際の動作を定義する。例えば今、「メールを送信する」という動作で構成されるたった1種類だけのアクションがあるとしよう。
|
||||
このようなアクションは、受信者、重要度といったメッセージに付随する他のパラメータと同様、メール送信に利用されるテンプレートも定義する。
|
||||
</p>
|
||||
<p>特別なページ: <a href="../setup/email.test.php" target="_blank">email.test.php</p>は、PHPのメール設定をテストしたりトラブルシュートするのに利用可能である。</p>
|
||||
<p>実行するには、アクションがトリガーに関連づけられている必要がある。
|
||||
トリガーに関連づけられると、各々のアクションは順番が与えられ、どの順序でそのアクションが実行されるかが指定される。</p>',
|
||||
|
||||
'UI:NotificationsMenu:Triggers' => 'トリガー', // 'Triggers',
|
||||
'UI:NotificationsMenu:AvailableTriggers' => '実行可能トリガー', // 'Available triggers',
|
||||
'UI:NotificationsMenu:OnCreate' => 'オブジェクトが生成された時', // 'When an object is created',
|
||||
'UI:NotificationsMenu:OnStateEnter' => 'オブジェクトが指定状態に入った時', // 'When an object enters a given state',
|
||||
'UI:NotificationsMenu:OnStateLeave' => 'オブジェクトが指定状態から出た時', // 'When an object leaves a given state',
|
||||
'UI:NotificationsMenu:Actions' => 'アクション', // 'Actions',
|
||||
'UI:NotificationsMenu:AvailableActions' => '実行可能アクション', // 'Available actions',
|
||||
|
||||
'Menu:AuditCategories' => '監査カテゴリ', // 'Audit Categories',
|
||||
'Menu:AuditCategories+' => '監査カテゴリ', // 'Audit Categories',
|
||||
'Menu:Notifications:Title' => '監査カテゴリ', // 'Audit Categories',
|
||||
|
||||
'Menu:RunQueriesMenu' => 'クエリ実行', // 'Run Queries',
|
||||
'Menu:RunQueriesMenu+' => '任意のクエリを実行', // 'Run any query',
|
||||
|
||||
'Menu:DataAdministration' => 'データ管理', // 'Data administration',
|
||||
'Menu:DataAdministration+' => 'データ管理', // 'Data administration',
|
||||
|
||||
'Menu:UniversalSearchMenu' => '全検索', // 'Universal Search',
|
||||
'Menu:UniversalSearchMenu+' => '何か...を検索', // 'Search for anything...',
|
||||
|
||||
'Menu:ApplicationLogMenu' => 'Log de l\'application',
|
||||
'Menu:ApplicationLogMenu+' => 'Log de l\'application',
|
||||
'Menu:ApplicationLogMenu:Title' => 'Log de l\'application',
|
||||
|
||||
'Menu:UserManagementMenu' => 'ユーザ管理', // 'User Management',
|
||||
'Menu:UserManagementMenu+' => 'ユーザ管理', // 'User management',
|
||||
|
||||
'Menu:ProfilesMenu' => 'プロファイル', // 'Profiles',
|
||||
'Menu:ProfilesMenu+' => 'プロファイル', // 'Profiles',
|
||||
'Menu:ProfilesMenu:Title' => 'プロファイル', // 'Profiles',
|
||||
|
||||
'Menu:UserAccountsMenu' => 'ユーザアカウント', // 'User Accounts',
|
||||
'Menu:UserAccountsMenu+' => 'ユーザアカウント', // 'User Accounts',
|
||||
'Menu:UserAccountsMenu:Title' => 'ユーザアカウント', // 'User Accounts',
|
||||
|
||||
'UI:iTopVersion:Short' => 'iTopバージョン%1$s', // 'iTop version %1$s',
|
||||
'UI:iTopVersion:Long' => 'iTopバージョン%1$s-%2$s, %3$sビルド', // 'iTop version %1$s-%2$s built on %3$s',
|
||||
'UI:PropertiesTab' => 'プロパティ', // 'Properties',
|
||||
|
||||
'UI:OpenDocumentInNewWindow_' => '新規ウィンドウで本ドキュメント: $1$sを開く', // 'Open this document in a new window: %1$s',
|
||||
'UI:DownloadDocument_' => '本ドキュメント: $1$sをダウンロードする', // 'Download this document: %1$s',
|
||||
'UI:Document:NoPreview' => 'このタイプのドキュメントはプレビューできません。', // 'No preview is available for this type of document',
|
||||
|
||||
'UI:DeadlineMissedBy_duration' => '%1$s によって消去されました。', // 'Missed by %1$s',
|
||||
'UI:Deadline_LessThan1Min' => '1分以内', // '< 1 min',
|
||||
'UI:Deadline_Minutes' => '%1$d 分', // '%1$d min',
|
||||
'UI:Deadline_Hours_Minutes' => '%1$d時間%2$d分', // '%1$dh %2$dmin',
|
||||
'UI:Deadline_Days_Hours_Minutes' => '%1$d日%2$d時間%3$d分', // '%1$dd %2$dh %3$dmin',
|
||||
'UI:Help' => 'ヘルプ', // 'Help',
|
||||
'UI:PasswordConfirm' => '(確認)', // '(Confirm)',
|
||||
'UI:BeforeAdding_Class_ObjectsSaveThisObject' => '%1$sオブジェクトをさらに追加する前に、このオブジェクトを保存してください。', // 'Before adding more %1$s objects, save this object.',
|
||||
'UI:DisplayThisMessageAtStartup' => '起動時にこのメッセージを表示する', // 'Display this message at startup',
|
||||
'UI:RelationshipGraph' => 'グラフィカル表示', // 'Graphical view',
|
||||
'UI:RelationshipList' => 'リスト', // 'List',
|
||||
'UI:OperationCancelled' => '操作はキャンセルされました', // 'Operation Cancelled',
|
||||
|
||||
'Portal:Title' => 'iTopユーザポータル', // 'iTop user portal',
|
||||
'Portal:Refresh' => '更新', // 'Refresh',
|
||||
'Portal:Back' => '戻る', // 'Back',
|
||||
'Portal:CreateNewRequest' => '新規リクエストを生成する', // 'Create a new request',
|
||||
'Portal:ChangeMyPassword' => 'パスワードを変更する', // 'Change my password',
|
||||
'Portal:Disconnect' => '切断する', // 'Disconnect',
|
||||
'Portal:OpenRequests' => '発行済みリクエスト', // 'My open requests',
|
||||
'Portal:ResolvedRequests' => '解決済みリクエスト', // 'My resolved requests',
|
||||
'Portal:SelectService' => 'カタログからサービスを選択してください:', // 'Select a service from the catalog:',
|
||||
'Portal:PleaseSelectOneService' => 'サービスを1つ選んでください', // 'Please select one service',
|
||||
'Portal:SelectSubcategoryFrom_Service' => '本サービス:%1$sのサブカテゴリを選んでください', // 'Select a sub-category for the service %1$s:',
|
||||
'Portal:PleaseSelectAServiceSubCategory' => 'サブカテゴリを1つ選んでください', // 'Please select one sub-category',
|
||||
'Portal:DescriptionOfTheRequest' => 'あなたのリクエストの詳細を記入してください:', // 'Enter the description of your request:',
|
||||
'Portal:TitleRequestDetailsFor_Request' => 'リクエスト%1$sの詳細:', // Details for request %1$s:',
|
||||
'Portal:NoOpenRequest' => '本カテゴリにリクエストはありません', // 'No request in this category.',
|
||||
'Portal:Button:CloseTicket' => '本チケットを閉じます。', // 'Close this ticket',
|
||||
'Portal:EnterYourCommentsOnTicket' => '本チケットの解決について、コメントを入力してください。', // 'Enter your comments about the resolution of this ticket:',
|
||||
'Portal:ErrorNoContactForThisUser' => 'エラー:現在のユーザはコンタクト/人物に関連づけられていません。管理者に問い合わせてください。', // 'Error: the current user is not associated with a Contact/Person. Please contact your administrator.',
|
||||
'Portal:Attachments' => '添付', // 'Attachments',
|
||||
'Portal:AddAttachment' => ' 添付を付加する ', // ' Add Attachment ',
|
||||
'Portal:RemoveAttachment' => ' 添付を除去する ', // ' Remove Attachment ',
|
||||
'Portal:Attachment_No_To_Ticket_Name' => '#%1$d を$2$s ($3$s)に添付する', // 'Attachment #%1$d to %2$s (%3$s)',
|
||||
'Enum:Undefined' => '定義されていません', // 'Undefined',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -304,6 +304,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'UI:History:StatsDeletes+' => 'Count of objects deleted',
|
||||
'UI:Loading' => 'Carregando...',
|
||||
'UI:Menu:Actions' => 'Ações',
|
||||
'UI:Menu:OtherActions' => 'Outras Ações',
|
||||
'UI:Menu:New' => 'Novo...',
|
||||
'UI:Menu:Add' => 'Adicionar...',
|
||||
'UI:Menu:Manage' => 'Gerencia...',
|
||||
|
||||
@@ -406,6 +406,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'UI:History:Changes+' => 'Изменения, внесенные в объект',
|
||||
'UI:Loading' => 'Загрузка...',
|
||||
'UI:Menu:Actions' => 'Действия',
|
||||
'UI:Menu:OtherActions' => 'Другие Действия',
|
||||
'UI:Menu:New' => 'Новый...',
|
||||
'UI:Menu:Add' => 'Добавить...',
|
||||
'UI:Menu:Manage' => 'Управление...',
|
||||
|
||||
@@ -405,6 +405,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'UI:History:Changes+' => 'Nesneye yapılan değişiklikler',
|
||||
'UI:Loading' => 'Yükleniyor...',
|
||||
'UI:Menu:Actions' => 'İşlemler',
|
||||
'UI:Menu:OtherActions' => 'Diğer İşlemler',
|
||||
'UI:Menu:New' => 'Yeni...',
|
||||
'UI:Menu:Add' => 'Ekle...',
|
||||
'UI:Menu:Manage' => 'Yönet...',
|
||||
|
||||
@@ -404,6 +404,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'UI:History:Changes+' => '对该对象所做的变更',
|
||||
'UI:Loading' => '载入...',
|
||||
'UI:Menu:Actions' => '动作',
|
||||
'UI:Menu:OtherActions' => '其他操作',
|
||||
'UI:Menu:New' => '新建...',
|
||||
'UI:Menu:Add' => '添加...',
|
||||
'UI:Menu:Manage' => '管理...',
|
||||
|
||||
BIN
images/actions_bkg.png
Normal file
|
After Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 314 B |
BIN
images/first.png
Normal file
|
After Width: | Height: | Size: 720 B |
BIN
images/last.png
Normal file
|
After Width: | Height: | Size: 737 B |
BIN
images/mini_tree.gif
Normal file
|
After Width: | Height: | Size: 140 B |
BIN
images/next.png
Normal file
|
After Width: | Height: | Size: 736 B |
BIN
images/play.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
images/preferences.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
images/prev.png
Normal file
|
After Width: | Height: | Size: 745 B |
@@ -13,12 +13,12 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper)
|
||||
{
|
||||
this.id = id;
|
||||
this.sClass = sClass;
|
||||
this.sAttCode = sAttCode;
|
||||
this.sSuffix = sSuffix;
|
||||
this.sTargetClass = sTargetClass;
|
||||
this.sFilter = sFilter;
|
||||
this.sTitle = sTitle;
|
||||
this.emptyHtml = ''; // content to be displayed when the search results are empty (when opening the dialog)
|
||||
this.emptyOnClose = true; // Workaround for the JQuery dialog being very slow when opening and closing if the content contains many INPUT tags
|
||||
this.oWizardHelper = oWizHelper;
|
||||
@@ -38,7 +38,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
{
|
||||
if (me.ajax_request)
|
||||
{
|
||||
me.ajax_request.Abort();
|
||||
me.ajax_request.abort();
|
||||
me.ajax_request = null;
|
||||
}
|
||||
}
|
||||
@@ -60,9 +60,8 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
}
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
sValue: value,
|
||||
sTitle: me.sTitle,
|
||||
sTargetClass: me.sTargetClass,
|
||||
operation: 'objectSearchForm'
|
||||
}
|
||||
|
||||
@@ -71,7 +70,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in HTML
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#ac_dlg_'+me.id).html(data);
|
||||
@@ -79,6 +78,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.UpdateSizes();
|
||||
me.UpdateButtons();
|
||||
me.ajax_request = null;
|
||||
me.DoSearchObjects();
|
||||
},
|
||||
'html'
|
||||
);
|
||||
@@ -111,7 +111,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
this.UpdateButtons = function()
|
||||
{
|
||||
var okBtn = $('#btn_ok_'+me.id);
|
||||
if ($('#fr_'+me.id+' input[name=selectObject]:checked').length > 0)
|
||||
if ($('#count_'+me.id).val() > 0)
|
||||
{
|
||||
okBtn.attr('disabled', '');
|
||||
}
|
||||
@@ -123,9 +123,9 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
|
||||
this.DoSearchObjects = function(id)
|
||||
{
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix
|
||||
sFilter: me.sFilter
|
||||
}
|
||||
|
||||
// Gather the parameters from the search form
|
||||
@@ -151,7 +151,6 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
}
|
||||
|
||||
theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass'
|
||||
theMap['class'] = me.sClass;
|
||||
theMap.operation = 'searchObjectsToSelect'; // Override what is defined in the form itself
|
||||
|
||||
sSearchAreaId = '#dr_'+me.id;
|
||||
@@ -164,15 +163,17 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and display the results
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$(sSearchAreaId).html(data);
|
||||
$(sSearchAreaId+' .listResults').tableHover();
|
||||
$(sSearchAreaId+' .listResults').tablesorter( { headers: {0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$('#fr_'+me.id+' input:radio').click(function() { me.UpdateButtons(); });
|
||||
me.UpdateButtons();
|
||||
me.ajax_request = null;
|
||||
$('#count_'+me.id).change(function(){
|
||||
me.UpdateButtons();
|
||||
});
|
||||
},
|
||||
'html'
|
||||
);
|
||||
@@ -182,16 +183,23 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
|
||||
this.DoOk = function()
|
||||
{
|
||||
var iObjectId = $('#fr_'+me.id+' input[name=selectObject]:checked').val();
|
||||
var s = $('#'+me.id+'_results').find(':input[name^=storedSelection]');
|
||||
var iObjectId = 0;
|
||||
if (s.length > 0)
|
||||
{
|
||||
iObjectId = s.val();
|
||||
}
|
||||
else
|
||||
{
|
||||
iObjectId = $('#fr_'+me.id+' input[name=selectObject]:checked').val();
|
||||
}
|
||||
$('#ac_dlg_'+this.id).dialog('close');
|
||||
$('#label_'+this.id).addClass('ac_dlg_loading');
|
||||
|
||||
// Query the server again to get the display name of the selected object
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
iObjectId: iObjectId,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
operation: 'getObjectName'
|
||||
}
|
||||
|
||||
@@ -200,13 +208,19 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in JSON
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#label_'+me.id).val(data.name);
|
||||
$('#label_'+me.id).removeClass('ac_dlg_loading');
|
||||
var prevValue = $('#'+me.id).val();
|
||||
$('#'+me.id).val(iObjectId);
|
||||
$('#'+me.id).trigger('validate');
|
||||
if (prevValue != iObjectId)
|
||||
{
|
||||
$('#'+me.id).trigger('validate');
|
||||
$('#'+me.id).trigger('extkeychange');
|
||||
$('#'+me.id).trigger('change');
|
||||
}
|
||||
$('#label_'+me.id).focus();
|
||||
me.ajax_request = null;
|
||||
},
|
||||
@@ -246,10 +260,8 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).addClass('ac_dlg_loading');
|
||||
}
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
'json': me.oWizardHelper.ToJSON(),
|
||||
operation: 'objectCreationForm'
|
||||
}
|
||||
@@ -259,7 +271,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in HTML
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#ajax_'+me.id).html(data);
|
||||
@@ -309,10 +321,8 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
if (CheckFields(sFormId, true))
|
||||
{
|
||||
$('#'+sFormId).block();
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
sSuffix: me.sSuffix,
|
||||
'class': me.sClass,
|
||||
'json': me.oWizardHelper.ToJSON()
|
||||
}
|
||||
|
||||
@@ -338,13 +348,13 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in JSON
|
||||
me.ajax_request = $.post( '../pages/ajax.render.php', theMap,
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
if (me.bSelectMode)
|
||||
{
|
||||
// Add the newly created object to the drop-down list and select it
|
||||
$('<option/>', { value : data.id }).text(data.name).appendTo('#'+me.id);
|
||||
$('<option/>', { value : data.id }).html(data.name).appendTo('#'+me.id);
|
||||
$('#'+me.id+' option[value="'+data.id+'"]').attr('selected', 'selected');
|
||||
$('#'+me.id).focus();
|
||||
}
|
||||
@@ -357,6 +367,8 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).focus();
|
||||
}
|
||||
$('#'+me.id).trigger('validate');
|
||||
$('#'+me.id).trigger('extkeychange');
|
||||
$('#'+me.id).trigger('change');
|
||||
me.ajax_request = null;
|
||||
},
|
||||
'json'
|
||||
@@ -373,6 +385,7 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).attr('disabled', 'disabled');
|
||||
$('#label_'+me.id).css({'background': 'transparent'});
|
||||
$('#mini_add_'+me.id).hide();
|
||||
$('#mini_tree_'+me.id).hide();
|
||||
$('#mini_search_'+me.id).hide();
|
||||
}
|
||||
else
|
||||
@@ -380,7 +393,125 @@ function ExtKeyWidget(id, sClass, sAttCode, sSuffix, bSelectMode, oWizHelper)
|
||||
$('#label_'+me.id).attr('disabled', '');
|
||||
$('#label_'+me.id).css({'background': '#fff url(../images/ac-background.gif) no-repeat right'});
|
||||
$('#mini_add_'+me.id).show();
|
||||
$('#mini_tree_'+me.id).show();
|
||||
$('#mini_search_'+me.id).show();
|
||||
}
|
||||
}
|
||||
|
||||
this.HKDisplay = function()
|
||||
{
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
sInputId: me.id,
|
||||
sFilter: me.sFilter,
|
||||
value: $('#'+me.id).val()
|
||||
};
|
||||
|
||||
if (me.bSelectMode)
|
||||
{
|
||||
me.v_html = $('#v_'+me.id).html();
|
||||
$('#v_'+me.id).html('<img src="../images/indicator.gif" />');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#label_'+me.id).addClass('ac_dlg_loading');
|
||||
}
|
||||
if (me.oWizardHelper == null)
|
||||
{
|
||||
theMap['json'] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not inside a "search form", updating a real object
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
theMap['json'] = me.oWizardHelper.ToJSON();
|
||||
}
|
||||
|
||||
theMap['sRemoteClass'] = me.sTargetClass;
|
||||
theMap.operation = 'displayHierarchy';
|
||||
|
||||
// Make sure that we cancel any pending request before issuing another
|
||||
// since responses may arrive in arbitrary order
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and display the results
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#ac_tree_'+me.id).html(data);
|
||||
var maxHeight = $(window).height()-110;
|
||||
$('#tree_'+me.id).css({maxHeight: maxHeight});
|
||||
},
|
||||
'html'
|
||||
);
|
||||
}
|
||||
|
||||
this.OnHKResize = function(event, ui)
|
||||
{
|
||||
var dh = ui.size.height - ui.originalSize.height;
|
||||
if (dh != 0)
|
||||
{
|
||||
var dlg_content = $('#dlg_tree_'+me.id+' .wizContainer');
|
||||
var h = dlg_content.height();
|
||||
dlg_content.height(h + dh);
|
||||
var tree = $('#tree_'+me.id);
|
||||
var h = tree.height();
|
||||
tree.height(h + dh - 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.OnHKClose = function()
|
||||
{
|
||||
if (me.bSelectMode)
|
||||
{
|
||||
$('#v_'+me.id).html(me.v_html);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#label_'+me.id).removeClass('ac_dlg_loading');
|
||||
}
|
||||
$('#label_'+me.id).focus();
|
||||
$('#dlg_tree_'+me.id).dialog("destroy");
|
||||
$('#dlg_tree_'+me.id).remove();
|
||||
}
|
||||
|
||||
this.DoHKOk = function()
|
||||
{
|
||||
iObjectId = $('#tree_'+me.id+' input[name=selectObject]:checked').val();
|
||||
|
||||
$('#dlg_tree_'+me.id).dialog('close');
|
||||
|
||||
// Query the server again to get the display name of the selected object
|
||||
var theMap = { sTargetClass: me.sTargetClass,
|
||||
iInputId: me.id,
|
||||
iObjectId: iObjectId,
|
||||
operation: 'getObjectName'
|
||||
}
|
||||
|
||||
// Make sure that we cancel any pending request before issuing another
|
||||
// since responses may arrive in arbitrary order
|
||||
me.StopPendingRequest();
|
||||
|
||||
// Run the query and get the result back directly in JSON
|
||||
me.ajax_request = $.post( AddAppContext(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'), theMap,
|
||||
function(data)
|
||||
{
|
||||
$('#label_'+me.id).val(data.name);
|
||||
$('#label_'+me.id).removeClass('ac_dlg_loading');
|
||||
var prevValue = $('#'+me.id).val();
|
||||
$('#'+me.id).val(iObjectId);
|
||||
if (prevValue != iObjectId)
|
||||
{
|
||||
$('#'+me.id).trigger('validate');
|
||||
$('#'+me.id).trigger('extkeychange');
|
||||
$('#'+me.id).trigger('change');
|
||||
}
|
||||
$('#label_'+me.id).focus();
|
||||
me.ajax_request = null;
|
||||
},
|
||||
'json'
|
||||
);
|
||||
|
||||
return false; // Do NOT submit the form in case we are called by OnSubmit...
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,8 @@ var oObj = {};
|
||||
// of Id 'att_2' in the form
|
||||
var aFieldsMap = new Array;
|
||||
|
||||
window.bInSubmit = false; // For handling form cancellation via OnBeforeUnload events
|
||||
|
||||
// Update the whole object from the form and also update its
|
||||
// JSON (serialized) representation in the (hidden) field
|
||||
function UpdateObjectFromForm(aFieldsMap, oObj)
|
||||
@@ -88,34 +90,28 @@ function ActivateStep(iTargetStep)
|
||||
//$('#wizStep'+(iTargetStep)).block({ message: null });
|
||||
}
|
||||
|
||||
function OnUnload(sTransactionId)
|
||||
{
|
||||
if (!window.bInSubmit)
|
||||
{
|
||||
// If it's not a submit, then it's a "cancel" (Pressing the Cancel button, closing the window, using the back button...)
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'on_form_cancel', transaction_id: sTransactionId }, function()
|
||||
{
|
||||
// Do nothing for now...
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//function AjaxGetValuesDef(oObj, sClass, sAttCode, iFieldId)
|
||||
//{
|
||||
// var oJSON = document.getElementById(sJsonFieldId);
|
||||
// $.get('ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
|
||||
// { operation: "allowed_values" },
|
||||
// function(data){
|
||||
// //$('#field_'+iFieldId).html(data);
|
||||
// }
|
||||
// );
|
||||
//}
|
||||
//
|
||||
//function AjaxGetDefaultValue(oObj, sClass, sAttCode, iFieldId)
|
||||
//{
|
||||
// // Asynchronously call the server to provide a default value if the field is
|
||||
// // empty
|
||||
// if (oObj['m_aCurrValues'][sAttCode] == '')
|
||||
// {
|
||||
// var oJSON = document.getElementById(sJsonFieldId);
|
||||
// $.get('../pages/ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
|
||||
// { operation: "default_value" },
|
||||
// function(json_data){
|
||||
// var oObj = ReloadObjectFromServer(json_data);
|
||||
// UpdateFieldFromObject(iFieldId, aFieldsMap, oObj)
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
//}
|
||||
function OnSubmit(sFormId)
|
||||
{
|
||||
window.bInSubmit=true; // This is a submit, make sure that when the page gets unloaded we don't cancel the action
|
||||
var bResult = CheckFields(sFormId, true);
|
||||
if (!bResult)
|
||||
{
|
||||
window.bInSubmit = false; // Submit is/will be canceled
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
|
||||
// Store the result of the form validation... there may be several forms per page, beware
|
||||
var oFormErrors = { err_form0: 0 };
|
||||
@@ -299,6 +295,35 @@ function ValidatePasswordField(id, sFormId)
|
||||
return true;
|
||||
}
|
||||
|
||||
//Special validation function for case log fields, taking into account the history
|
||||
// to determine if the field is empty or not
|
||||
function ValidateCaseLogField(sFieldId, bMandatory, sFormId)
|
||||
{
|
||||
bValid = true;
|
||||
|
||||
if ($('#'+sFieldId).attr('disabled'))
|
||||
{
|
||||
bValid = true; // disabled fields are not checked
|
||||
}
|
||||
else if (!bMandatory)
|
||||
{
|
||||
bValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bMandatory)
|
||||
{
|
||||
var count = $('#'+sFieldId+'_count').val();
|
||||
if ( (count == 0) && ($('#'+sFieldId).val() == '') )
|
||||
{
|
||||
// No previous entry and no content typed
|
||||
bValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ReportFieldValidationStatus(sFieldId, sFormId, bValid);
|
||||
return bValid;
|
||||
}
|
||||
// Manage a 'duration' field
|
||||
function UpdateDuration(iId)
|
||||
{
|
||||
@@ -319,8 +344,12 @@ function OnAutoComplete(id, event, data, formatted)
|
||||
if (data)
|
||||
{
|
||||
// A valid match was found: data[0] => label, data[1] => value
|
||||
$('#'+id).val(data[1]);
|
||||
$('#'+id).trigger('change');
|
||||
if (data[1] != $('#'+id).val())
|
||||
{
|
||||
$('#'+id).val(data[1]);
|
||||
$('#'+id).trigger('change');
|
||||
$('#'+id).trigger('extkeychange');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -388,7 +388,7 @@ $.Autocompleter = function(input, options) {
|
||||
for (var i=0; i < rows.length; i++) {
|
||||
var row = $.trim(rows[i]);
|
||||
if (row) {
|
||||
row = row.split("|");
|
||||
row = row.split("\t");
|
||||
parsed[parsed.length] = {
|
||||
data: row,
|
||||
value: row[0],
|
||||
@@ -668,6 +668,8 @@ $.Autocompleter.Select = function (options, input, select, config) {
|
||||
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
|
||||
if ( formatted === false )
|
||||
continue;
|
||||
// Escape dangerous characters to prevent XSS vulnerabilities
|
||||
formatted = formatted.replace('&', '&').replace('"', '"').replace('>', '>').replace('<', '<');
|
||||
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
|
||||
$.data(li, "ac_data", data[i]);
|
||||
}
|
||||
|
||||
468
js/jquery.tablesorter.pager.js
Normal file
@@ -0,0 +1,468 @@
|
||||
function sprintf(format, etc) {
|
||||
var arg = arguments;
|
||||
var i = 1;
|
||||
return format.replace(/%((%)|s)/g, function (m) { return m[2] || arg[i++] })
|
||||
}
|
||||
|
||||
|
||||
(function($) {
|
||||
$.extend({
|
||||
tablesorterPager: new function() {
|
||||
|
||||
function updatePageDisplay(c) {
|
||||
var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);
|
||||
}
|
||||
|
||||
function setPageSize(table,size, bReload) {
|
||||
var c = table.config;
|
||||
c.selectedSize = size;
|
||||
if (size == -1)
|
||||
{
|
||||
size = c.totalRows;
|
||||
}
|
||||
c.size = size;
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
c.pagerPositionSet = false;
|
||||
if (bReload)
|
||||
{
|
||||
moveToPage(table);
|
||||
}
|
||||
fixPosition(table);
|
||||
}
|
||||
|
||||
function fixPosition(table) {
|
||||
var c = table.config;
|
||||
if(!c.pagerPositionSet && c.positionFixed) {
|
||||
var c = table.config, o = $(table);
|
||||
if(o.offset) {
|
||||
c.container.css({
|
||||
top: o.offset().top + o.height() + 'px',
|
||||
position: 'absolute'
|
||||
});
|
||||
}
|
||||
c.pagerPositionSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
function moveToFirstPage(table) {
|
||||
var c = table.config;
|
||||
c.page = 0;
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToLastPage(table) {
|
||||
var c = table.config;
|
||||
c.page = (c.totalPages-1);
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToNextPage(table) {
|
||||
var c = table.config;
|
||||
c.page++;
|
||||
if(c.page >= (c.totalPages-1)) {
|
||||
c.page = (c.totalPages-1);
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToPrevPage(table) {
|
||||
var c = table.config;
|
||||
c.page--;
|
||||
if(c.page <= 0) {
|
||||
c.page = 0;
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
|
||||
function moveToPage(table) {
|
||||
var c = table.config;
|
||||
if(c.page < 0 || c.page > (c.totalPages-1)) {
|
||||
c.page = 0;
|
||||
}
|
||||
|
||||
renderTable(table,c.rowsCopy);
|
||||
}
|
||||
|
||||
function checkAll(table, pager, value)
|
||||
{
|
||||
// Mark all the displayed items as check or unchecked depending on the value
|
||||
$(table).find(':checkbox[name^=selectObj]').attr('checked', value);
|
||||
// Set the 'selectionMode' for the future objects to load
|
||||
if (value)
|
||||
{
|
||||
table.config.selectionMode = 'negative';
|
||||
}
|
||||
else
|
||||
{
|
||||
table.config.selectionMode = 'positive';
|
||||
}
|
||||
$(pager).find(':input[name=selectionMode]').val(table.config.selectionMode);
|
||||
// Reset the list of saved selection...
|
||||
resetStoredSelection(pager);
|
||||
updateCounter(table, pager);
|
||||
return true;
|
||||
}
|
||||
|
||||
function resetStoredSelection(pager)
|
||||
{
|
||||
$(':input[name^=storedSelection]', pager).remove();
|
||||
}
|
||||
|
||||
function storeSelection(table, pager, id, value)
|
||||
{
|
||||
var valueToStore = value;
|
||||
if (table.config.selectionMode == 'negative')
|
||||
{
|
||||
valueToStore = !(valueToStore);
|
||||
}
|
||||
if (valueToStore)
|
||||
{
|
||||
if (table.config.select_mode == 'single')
|
||||
{
|
||||
$(':input[name^=storedSelection]', pager).remove(); // Remove any previous selection
|
||||
}
|
||||
if ($('#'+id, pager).length ==0)
|
||||
{
|
||||
$(pager).append($('<input type="hidden" id="'+id+'" name="storedSelection[]" value="'+id+'"></input>'));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($('#'+id, pager).length !=0)
|
||||
{
|
||||
$('#'+id, pager).remove();
|
||||
}
|
||||
}
|
||||
updateCounter(table, pager);
|
||||
}
|
||||
|
||||
function loadSelection(table, pager)
|
||||
{
|
||||
table.config.selectionMode = $(pager).find(':input[name=selectionMode]').val();
|
||||
updateCounter(table, pager);
|
||||
}
|
||||
|
||||
function updateCounter(table, pager)
|
||||
{
|
||||
var ex = $(':input[name^=storedSelection]', pager).length;
|
||||
var s = ex;
|
||||
if (table.config.selectionMode == 'negative')
|
||||
{
|
||||
s = table.config.totalRows - ex;
|
||||
}
|
||||
$('.selectedCount',pager).text(s);
|
||||
if (table.config.cssCount != '')
|
||||
{
|
||||
$(table.config.cssCount).val(s);
|
||||
$(table.config.cssCount).trigger('change');
|
||||
}
|
||||
}
|
||||
|
||||
function getData(table, start, end)
|
||||
{
|
||||
if (table.ajax_request)
|
||||
{
|
||||
table.ajax_request.abort();
|
||||
table.ajax_request = null;
|
||||
}
|
||||
|
||||
var c = table.config;
|
||||
var s = c.sortList[0];
|
||||
var s_col = null;
|
||||
var s_order = null;
|
||||
if (s != undefined)
|
||||
{
|
||||
s_col = s[0];
|
||||
s_order = (s[1] == 0) ? 'asc' : 'desc';
|
||||
}
|
||||
$('#loading', table.config.container).html('<img src="../images/indicator.gif" />');
|
||||
table.ajax_request = $.post(AddAppContext(GetAbsoluteUrlAppRoot()+"pages/ajax.render.php"),
|
||||
{ operation: 'pagination',
|
||||
filter: c.filter,
|
||||
extra_param: c.extra_params,
|
||||
start: start,
|
||||
end: end,
|
||||
sort_col: s_col,
|
||||
sort_order: s_order,
|
||||
select_mode: c.select_mode,
|
||||
display_key: c.displayKey,
|
||||
display_list: c.displayList
|
||||
},
|
||||
function(data)
|
||||
{
|
||||
table.ajax_request = null; // Ajax request completed
|
||||
oData = $(data);
|
||||
var tableBody = $(table.tBodies[0]);
|
||||
|
||||
// clear the table body
|
||||
|
||||
$.tablesorter.clearTableBody(table);
|
||||
|
||||
for(var i = 0; i < end-start; i++) {
|
||||
|
||||
//tableBody.append(rows[i]);
|
||||
|
||||
//var o = rows[i];
|
||||
var r = $(oData[i]);
|
||||
var l = r.length;
|
||||
for(var j=0; j < l; j++) {
|
||||
|
||||
//tableBody[0].appendChild(r);
|
||||
tableBody[0].appendChild(r[j]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fixPosition(table,tableBody);
|
||||
applySelection(table);
|
||||
|
||||
$(table).trigger("applyWidgets");
|
||||
|
||||
if( c.page >= c.totalPages ) {
|
||||
moveToLastPage(table);
|
||||
}
|
||||
|
||||
updatePageDisplay(c);
|
||||
updateCounter(table, table.config.container);
|
||||
renderPager(table, table.config.container);
|
||||
$(table).tableHover();
|
||||
$('#loading', table.config.container).empty();
|
||||
|
||||
saveParams(table.config);
|
||||
});
|
||||
}
|
||||
|
||||
function applySelection(table)
|
||||
{
|
||||
var c = table.config;
|
||||
if (c.selectionMode == 'negative')
|
||||
{
|
||||
$(table).find(':checkbox[name^=selectObj]').attr('checked', true);
|
||||
}
|
||||
|
||||
if (table.config.select_mode == 'multiple')
|
||||
{
|
||||
$(table).find(':checkbox[name^=selectObj]').each(function() {
|
||||
var id = parseInt(this.value, 10);
|
||||
if ($('#'+id, table.config.container).length > 0)
|
||||
{
|
||||
if (c.selectionMode == 'positive')
|
||||
{
|
||||
$(this).attr('checked', true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).attr('checked', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(table).find(':checkbox[name^=selectObj]').change(function() {
|
||||
storeSelection(table, table.config.container, this.value, this.checked);
|
||||
});
|
||||
}
|
||||
else if (table.config.select_mode == 'single')
|
||||
{
|
||||
$(table).find('input[name^=selectObject]:radio').each(function() {
|
||||
var id = parseInt(this.value, 10);
|
||||
if ($('#'+id, table.config.container).length > 0)
|
||||
{
|
||||
if (c.selectionMode == 'positive')
|
||||
{
|
||||
$(this).attr('checked', true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).attr('checked', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(table).find('input[name^=selectObject]:radio').change(function() {
|
||||
storeSelection(table, table.config.container, this.value, this.checked);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderPager(table, pager)
|
||||
{
|
||||
var c = table.config;
|
||||
var s = c.page - 2;
|
||||
var nb = Math.ceil(c.totalRows / c.size);
|
||||
if (s < 0)
|
||||
{
|
||||
s = 0;
|
||||
}
|
||||
var e = s +5;
|
||||
if (e > nb)
|
||||
{
|
||||
e = nb;
|
||||
s = e - 5;
|
||||
if (s < 0) s = 0;
|
||||
}
|
||||
txt = '';
|
||||
for(var i=s; i<e; i++)
|
||||
{
|
||||
var page = 1+i;
|
||||
var link = ' '+page+' ';
|
||||
if (i != c.page)
|
||||
{
|
||||
link = ' <span page="'+i+'" id="gotopage_'+i+'">'+page+'</span> ';
|
||||
}
|
||||
else
|
||||
{
|
||||
link = ' <span class="curr_page" page="'+i+'">'+page+'</span> ';
|
||||
}
|
||||
txt += link;
|
||||
}
|
||||
txt += '';
|
||||
$('#total', pager).text(c.totalRows);
|
||||
$('#index', pager).html(txt);
|
||||
for(var j=s; j<e; j++)
|
||||
{
|
||||
$('#gotopage_'+j, pager).click(function(){
|
||||
var idx = $(this).attr('page');
|
||||
table.config.page = idx;
|
||||
moveToPage(table);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function renderTable(table) {
|
||||
|
||||
var c = table.config;
|
||||
//var l = rows.length;
|
||||
var s = (c.page * c.size);
|
||||
var e = (s + c.size);
|
||||
if(e > c.totalRows ) {
|
||||
e = c.totalRows;
|
||||
}
|
||||
|
||||
getData(table, s, e);
|
||||
}
|
||||
|
||||
this.appender = function(table,rows) {
|
||||
|
||||
var c = table.config;
|
||||
|
||||
if (c.totalRows == 0)
|
||||
{
|
||||
c.totalRows = rows.length;
|
||||
}
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
|
||||
renderTable(table,rows);
|
||||
};
|
||||
|
||||
function saveParams(config) {
|
||||
|
||||
var sPagerId = config.container.attr('id');
|
||||
|
||||
var params = { size: config.selectedSize, page: config.page, sortList: config.sortList };
|
||||
if (window.pager_params == undefined)
|
||||
{
|
||||
window.pager_params = {};
|
||||
}
|
||||
window.pager_params[sPagerId] = params;
|
||||
};
|
||||
|
||||
function restoreParams(table) {
|
||||
|
||||
var sPagerId = config.container.attr('id');
|
||||
if (window.pager_params != undefined)
|
||||
{
|
||||
params = window.pager_params[sPagerId];
|
||||
|
||||
if (params != undefined)
|
||||
{
|
||||
$(table.config.cssPageSize, table.config.container).val(params.size);
|
||||
setPageSize(table, params.size, false); // false => don't trigger a reload
|
||||
if (table.config.sortList != params.sortList)
|
||||
{
|
||||
$(table).trigger("sorton", [params.sortList]); // triggers a reload anyway
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.defaults = {
|
||||
size: 10,
|
||||
offset: 0,
|
||||
page: 0,
|
||||
totalRows: 0,
|
||||
totalPages: 0,
|
||||
container: null,
|
||||
cssNext: '.next',
|
||||
cssPrev: '.prev',
|
||||
cssFirst: '.first',
|
||||
cssLast: '.last',
|
||||
cssPageDisplay: '.pagedisplay',
|
||||
cssPageSize: '.pagesize',
|
||||
cssCount: '',
|
||||
seperator: "/",
|
||||
positionFixed: false,
|
||||
appender: this.appender,
|
||||
filter: '',
|
||||
extra_params: '',
|
||||
select_mode: '',
|
||||
totalSelected: 0,
|
||||
selectionMode: 'positive',
|
||||
displayKey: true,
|
||||
displayList: []
|
||||
};
|
||||
|
||||
this.construct = function(settings) {
|
||||
|
||||
return this.each(function() {
|
||||
|
||||
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
|
||||
|
||||
var table = this, pager = config.container;
|
||||
|
||||
this.ajax_request = null;
|
||||
|
||||
config.selectedSize = parseInt($(".pagesize",pager).val());
|
||||
setPageSize(table,config.selectedSize, false);
|
||||
restoreParams(table, config);
|
||||
|
||||
$(this).trigger("appendCache"); // Load the data
|
||||
|
||||
$(config.cssFirst,pager).click(function() {
|
||||
moveToFirstPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssNext,pager).click(function() {
|
||||
moveToNextPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPrev,pager).click(function() {
|
||||
moveToPrevPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssLast,pager).click(function() {
|
||||
moveToLastPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPageSize,pager).change(function() {
|
||||
setPageSize(table,parseInt($(this).val()), true);
|
||||
return false;
|
||||
});
|
||||
$(table).find(':checkbox.checkAll').removeAttr('onclick').click(function() {
|
||||
return checkAll(table, pager, this.checked);
|
||||
});
|
||||
|
||||
$(table).bind('load_selection', function() {
|
||||
loadSelection(table, pager);
|
||||
applySelection(table);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
// extend plugin scope
|
||||
$.fn.extend({
|
||||
tablesorterPager: $.tablesorterPager.construct
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -40,6 +40,12 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
// Re-run the zebra plugin to properly highlight the remaining lines & and take into account the removed ones
|
||||
$('#linkedset_'+this.id+' .listResults').trigger('update').trigger("applyWidgets");
|
||||
|
||||
if ($('$linkedset_'+this.id+' .selection').length == 0)
|
||||
{
|
||||
// All items were removed: add a dummy hidden input to make sure that the linkset will be updated (emptied) when posted
|
||||
$('#'+me.id+'_empty_row').show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.OnSelectChange = function()
|
||||
@@ -59,6 +65,7 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
{
|
||||
$('#dlg_'+me.id).dialog('open');
|
||||
this.UpdateSizes(null, null);
|
||||
this.SearchObjectsToAdd();
|
||||
}
|
||||
|
||||
this.SearchObjectsToAdd = function()
|
||||
@@ -69,6 +76,7 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
bDuplicates: me.bDuplicates
|
||||
}
|
||||
|
||||
me.UpdateButtons(0);
|
||||
// Gather the parameters from the search form
|
||||
$('#SearchFormToAdd_'+me.id+' :input').each(
|
||||
function(i)
|
||||
@@ -96,12 +104,15 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
$(sSearchAreaId).block();
|
||||
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
$(sSearchAreaId).html(data);
|
||||
$(sSearchAreaId+' .listResults').tableHover();
|
||||
$(sSearchAreaId+' .listResults').tablesorter( { headers: {0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$('#count_'+me.id).change(function(){
|
||||
var c = this.value;
|
||||
me.UpdateButtons(c);
|
||||
});
|
||||
$(sSearchAreaId).unblock();
|
||||
},
|
||||
'html'
|
||||
@@ -110,6 +121,19 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
return false; // Don't submit the form, stay in the current page !
|
||||
}
|
||||
|
||||
this.UpdateButtons = function(iCount)
|
||||
{
|
||||
var okBtn = $('#btn_ok_'+me.id);
|
||||
if (iCount > 0)
|
||||
{
|
||||
okBtn.attr('disabled', '');
|
||||
}
|
||||
else
|
||||
{
|
||||
okBtn.attr('disabled', 'disabled');
|
||||
}
|
||||
}
|
||||
|
||||
this.DoAddObjects = function()
|
||||
{
|
||||
var theMap = { sAttCode: me.sAttCode,
|
||||
@@ -120,40 +144,73 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
}
|
||||
|
||||
// Gather the parameters from the search form
|
||||
$('#SearchResultsToAdd_'+me.id+' :checked').each(
|
||||
function(i)
|
||||
{
|
||||
if ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) )
|
||||
{
|
||||
//console.log(this.type);
|
||||
arrayExpr = /\[\]$/;
|
||||
if (arrayExpr.test(this.name))
|
||||
{
|
||||
// Array
|
||||
if (theMap[this.name] == undefined)
|
||||
{
|
||||
theMap[this.name] = new Array();
|
||||
}
|
||||
theMap[this.name].push(this.value);
|
||||
}
|
||||
else
|
||||
var context = $('#SearchResultsToAdd_'+me.id);
|
||||
var selectionMode = $(':input[name=selectionMode]', context);
|
||||
if (selectionMode.length > 0)
|
||||
{
|
||||
// Paginated table retrieve the mode and the exceptions
|
||||
var sMode = selectionMode.val();
|
||||
theMap['selectionMode'] = sMode;
|
||||
$('#fs_SearchFormToAdd_'+me.id+' :input').each(
|
||||
function(i)
|
||||
{
|
||||
theMap[this.name] = this.value;
|
||||
}
|
||||
);
|
||||
theMap['sRemoteClass'] = theMap['class']; // swap 'class' (defined in the form) and 'remoteClass'
|
||||
theMap['class'] = me.sClass;
|
||||
$(' :input[name^=storedSelection]', context).each(function() {
|
||||
if (theMap[this.name] == undefined)
|
||||
{
|
||||
theMap[this.name] = new Array();
|
||||
}
|
||||
theMap[this.name].push(this.value);
|
||||
$(this).remove(); // Remove the selection for the next time the dialog re-opens
|
||||
});
|
||||
// Retrieve the 'filter' definition
|
||||
var table = $('#ResultsToAdd_'+me.id).find('table.listResults')[0];
|
||||
theMap['filter'] = table.config.filter;
|
||||
theMap['extra_params'] = table.config.extra_params;
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// Normal table, retrieve all the checked check-boxes
|
||||
$(':checked[name^=selectObject]', context).each(
|
||||
function(i)
|
||||
{
|
||||
if ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) )
|
||||
{
|
||||
//console.log(this.type);
|
||||
arrayExpr = /\[\]$/;
|
||||
if (arrayExpr.test(this.name))
|
||||
{
|
||||
// Array
|
||||
if (theMap[this.name] == undefined)
|
||||
{
|
||||
theMap[this.name] = new Array();
|
||||
}
|
||||
theMap[this.name].push(this.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
theMap[this.name] = this.value;
|
||||
}
|
||||
}
|
||||
$(this).parents('tr:first').remove(); // Remove the whole line, so that, next time the dialog gets displayed it's no longer there
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
// }
|
||||
|
||||
theMap['operation'] = 'doAddObjects';
|
||||
$('#busy_'+me.iInputId).html(' <img src="../images/indicator.gif"/>');
|
||||
// Run the query and display the results
|
||||
$.post( '../pages/ajax.render.php', theMap,
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
function(data)
|
||||
{
|
||||
//console.log('Data: ' + data);
|
||||
if (data != '')
|
||||
{
|
||||
$('#'+me.id+'_empty_row').remove();
|
||||
$('#'+me.id+'_empty_row').hide();
|
||||
$('#linkedset_'+me.id+' .listResults tbody').append(data);
|
||||
$('#linkedset_'+me.id+' .listResults').trigger('update');
|
||||
$('#linkedset_'+me.id+' .listResults').tableHover();
|
||||
|
||||
56
js/utils.js
@@ -21,7 +21,7 @@ function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
||||
console.log('Uh,uh, exception !');
|
||||
}
|
||||
}
|
||||
aTruncatedLists[divId] = $.post('../pages/ajax.render.php?style=list',
|
||||
aTruncatedLists[divId] = $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?style=list',
|
||||
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
||||
function(data)
|
||||
{
|
||||
@@ -39,12 +39,12 @@ function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $("#pager")}); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $("#pager"), totalRows:97, filter: sSerializedFilter, extra_params: sExtraParams }); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
$('#'+divId).unblock();
|
||||
@@ -76,30 +76,12 @@ function ReloadBlock(divId, sStyle, sSerializedFilter, sExtraParams)
|
||||
{
|
||||
$('#'+divId).block();
|
||||
//$('#'+divId).blockUI();
|
||||
$.post('../pages/ajax.render.php?style='+sStyle,
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?style='+sStyle,
|
||||
{ operation: 'ajax', filter: sSerializedFilter, extra_params: sExtraParams },
|
||||
function(data){
|
||||
$('#'+divId).empty();
|
||||
$('#'+divId).append(data);
|
||||
$('#'+divId).removeClass('loading');
|
||||
$('#'+divId+' .listResults').tableHover(); // hover tables
|
||||
$('#'+divId+' .listResults').each( function()
|
||||
{
|
||||
var table = $(this);
|
||||
var id = $(this).parent();
|
||||
var checkbox = (table.find('th:first :checkbox').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sortable
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sortable
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
}
|
||||
});
|
||||
//$('#'+divId).unblockUI();
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -137,7 +119,7 @@ function ReloadSearchForm(divId, sClassName, sBaseClass, sContext)
|
||||
}
|
||||
sAction = $('#ds_'+divId+' form').attr('action');
|
||||
|
||||
$.post('../pages/ajax.render.php?'+sContext,
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?'+sContext,
|
||||
{ operation: 'search_form', className: sClassName, baseClass: sBaseClass, currentId: divId, action: sAction },
|
||||
function(data) {
|
||||
oDiv.empty();
|
||||
@@ -183,7 +165,7 @@ function SetUserPreference(sPreferenceCode, sPrefValue, bPersistent)
|
||||
oUserPreferences[sPreferenceCode] = sPrefValue;
|
||||
if (bPersistent && (sPrefValue != sPreviousValue))
|
||||
{
|
||||
ajax_request = $.post('../pages/ajax.render.php',
|
||||
ajax_request = $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'set_pref', code: sPreferenceCode, value: sPrefValue} ); // Make it persistent
|
||||
}
|
||||
}
|
||||
@@ -210,10 +192,15 @@ function CheckAll(sSelector, bValue)
|
||||
{
|
||||
var value = bValue;
|
||||
$(sSelector).each( function() {
|
||||
this.checked = value;
|
||||
if (this.checked != value)
|
||||
{
|
||||
this.checked = value;
|
||||
$(this).trigger('change');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Toggle (enabled/disabled) the specified field of a form
|
||||
*/
|
||||
@@ -284,4 +271,23 @@ function PropagateCheckBox(bCurrValue, aFieldsList, bCheck)
|
||||
ToogleField(bCheck, aFieldsList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function FixTableSorter(table)
|
||||
{
|
||||
if ($('th.header', table).length == 0)
|
||||
{
|
||||
// Table is not sort-able, let's fix it
|
||||
var checkbox = (table.find('th:first :checkbox').length > 0);
|
||||
if (checkbox)
|
||||
{
|
||||
// There is a checkbox in the first column, don't make it sort-able
|
||||
table.tablesorter( { headers: { 0: {sorter: false}}, widgets: ['myZebra', 'truncatedList']} ); // sort-able and zebra tables
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is NO checkbox in the first column, all columns are considered sort-able
|
||||
table.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sort-able and zebra tables
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ function UpdateObjectList(sClass, sId, sExtKeyToRemote)
|
||||
aRelatedObjectIds[0] = 0;
|
||||
}
|
||||
var oql = "SELECT "+sClass+" AS c WHERE c.id IN (" + aRelatedObjectIds.join(", ") + ")";
|
||||
$.post("ajax.render.php?style=list&encoding=oql",
|
||||
$.post(GetAbsoluteUrlAppRoot()+"ajax.render.php?style=list&encoding=oql",
|
||||
{ operation: "ajax", filter: oql },
|
||||
function(data){
|
||||
$("#related_objects_"+sId).empty();
|
||||
@@ -42,7 +42,7 @@ function ManageObjects(sTitle, sClass, sId, sExtKeyToRemote)
|
||||
function Manage_LoadSelect(sSelectedId, sFilter)
|
||||
{
|
||||
$('#'+sSelectedId).addClass('loading');
|
||||
$.post('../pages/ajax.render.php',
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'combo_options', filter: sFilter },
|
||||
function(data){
|
||||
$('#'+sSelectedId).empty();
|
||||
|
||||
@@ -140,7 +140,7 @@ function WizardHelper(sClass, sFormPrefix, sState)
|
||||
{
|
||||
//console.log('data sent:', this.ToJSON());
|
||||
//console.log('oWizard:', this);
|
||||
$.post('../pages/ajax.render.php',
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'wizard_helper', json_obj: this.ToJSON() },
|
||||
function(html){
|
||||
$('#ajax_content').html(html);
|
||||
@@ -156,7 +156,7 @@ function WizardHelper(sClass, sFormPrefix, sState)
|
||||
{
|
||||
//console.log('data sent:', this.ToJSON());
|
||||
//console.log('oWizard:', this);
|
||||
$('#'+divId).load('../pages/ajax.render.php?operation=wizard_helper_preview',
|
||||
$('#'+divId).load(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=wizard_helper_preview',
|
||||
{'json_obj': this.ToJSON()},
|
||||
function(responseText, textStatus, XMLHttpRequest){
|
||||
$('#wizStep'+ G_iCurrentStep).unblock( {fadeOut: 0} );
|
||||
@@ -189,4 +189,21 @@ function WizardHelper(sClass, sFormPrefix, sState)
|
||||
}
|
||||
this.AjaxQueryServer();
|
||||
}
|
||||
|
||||
this.ReloadObjectCreationForm = function(sFormId, sTargetState)
|
||||
{
|
||||
$('#'+sFormId).block();
|
||||
this.UpdateWizard();
|
||||
this.ResetQuery();
|
||||
var sTransactionId = $('input[name=transaction_id]').val();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ json_obj: this.ToJSON(), operation: 'obj_creation_form', target_state: sTargetState, transaction_id: sTransactionId },
|
||||
function(data)
|
||||
{
|
||||
$('#'+sFormId).html(data);
|
||||
onDelayedReady();
|
||||
$('#'+sFormId).unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
48
modules/authent-external/ja.dict.authent-external.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Hirofumi Kosaka <kosaka@rworks.jp>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserExternal
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array (
|
||||
'Class:UserExternal' => '外部ユーザー', # 'External user',
|
||||
'Class:UserExternal+' => '外部認証ユーザー', # 'User authentified outside of iTop',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -79,12 +79,6 @@ class UserExternal extends User
|
||||
return false;
|
||||
}
|
||||
|
||||
public function CanLogOff()
|
||||
{
|
||||
// External authentication: iTop has no way to force a log off
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ChangePassword($sOldPassword, $sNewPassword)
|
||||
{
|
||||
return false;
|
||||
|
||||
25
modules/authent-external/pt_br.dict.authent-external.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserExternal' => 'Usuário externo',
|
||||
'Class:UserExternal+' => '',
|
||||
));
|
||||
?>
|
||||
@@ -20,6 +20,7 @@
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserLDAP' => 'LDAP-Benutzer',
|
||||
'Class:UserLDAP+' => 'Benutzer,der über LDAP authenifiziert wird',
|
||||
'Class:UserLDAP+' => 'Benutzer, der über LDAP authentifiziert wird',
|
||||
'Class:UserLDAP/Attribute:password' => 'Passwort',
|
||||
'Class:UserLDAP/Attribute:password+' => 'Benutzerpasswort',
|
||||
));
|
||||
|
||||
50
modules/authent-ldap/ja.dict.authent-ldap.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Hirofumi Kosaka <kosaka@rworks.jp>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLDAP
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array (
|
||||
'Class:UserLDAP' => 'LDAP ユーザー', # 'LDAP user',
|
||||
'Class:UserLDAP+' => 'LDAP認証ユーザー', # 'User authentified by LDAP',
|
||||
'Class:UserLDAP/Attribute:password' => 'パスワード', # 'Password',
|
||||
'Class:UserLDAP/Attribute:password+' => '認証文字列', # 'user authentication string',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -158,12 +158,6 @@ class UserLDAP extends UserInternal
|
||||
return false;
|
||||
}
|
||||
|
||||
public function CanLogOff()
|
||||
{
|
||||
// Internal authentication allows everybody to log off
|
||||
return true;
|
||||
}
|
||||
|
||||
public function ChangePassword($sOldPassword, $sNewPassword)
|
||||
{
|
||||
return false;
|
||||
|
||||
27
modules/authent-ldap/pt_br.dict.authent-ldap.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserLDAP' => 'Usuário externo',
|
||||
'Class:UserLDAP+' => '',
|
||||
'Class:UserLDAP/Attribute:password' => 'Senha',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
));
|
||||
?>
|
||||
@@ -20,6 +20,7 @@
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
@@ -39,7 +40,7 @@
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserLocal' => 'iTop-Benutzer',
|
||||
'Class:UserLocal+' => 'Benutzer von iTop authenifiziert',
|
||||
'Class:UserLocal+' => 'Benutzer von iTop authentifiziert',
|
||||
'Class:UserLocal/Attribute:password' => 'Passwort',
|
||||
'Class:UserLocal/Attribute:password+' => 'Benutzerpasswort',
|
||||
));
|
||||
|
||||
50
modules/authent-local/ja.dict.authent-local.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Hirofumi Kosaka <kosaka@rworks.jp>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLocal
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:UserLocal' => 'iTopユーザー', // 'iTop user',
|
||||
'Class:UserLocal+' => 'iTopローカル認証ユーザー', // 'User authentified by iTop',
|
||||
'Class:UserLocal/Attribute:password' => 'パスワード', // 'Password',
|
||||
'Class:UserLocal/Attribute:password+' => '認証文字列', // 'user authentication string',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -77,12 +77,6 @@ class UserLocal extends UserInternal
|
||||
return true;
|
||||
}
|
||||
|
||||
public function CanLogOff()
|
||||
{
|
||||
// Internal authentication allows everybody to log off
|
||||
return true;
|
||||
}
|
||||
|
||||
public function ChangePassword($sOldPassword, $sNewPassword)
|
||||
{
|
||||
$oPassword = $this->Get('password'); // ormPassword object
|
||||
|
||||
27
modules/authent-local/pt_br.dict.authent-local.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* @licence http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserLocal' => 'Usuário local',
|
||||
'Class:UserLocal+' => '',
|
||||
'Class:UserLocal/Attribute:password' => 'Senha',
|
||||
'Class:UserLocal/Attribute:password+' => '',
|
||||
));
|
||||
?>
|
||||
108
modules/itop-attachments/ajax.attachment.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Handles various ajax requests
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
require_once('../../approot.inc.php');
|
||||
require_once(APPROOT.'/application/application.inc.php');
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
|
||||
|
||||
try
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
// require_once(APPROOT.'/application/user.preferences.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(false /* bMustBeAdmin */, true /* IsAllowedToPortalUsers */); // Check user rights and prompt if needed
|
||||
|
||||
$oPage = new ajax_page("");
|
||||
$oPage->no_cache();
|
||||
|
||||
$sOperation = utils::ReadParam('operation', '');
|
||||
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'add':
|
||||
$aResult = array(
|
||||
'error' => '',
|
||||
'att_id' => 0,
|
||||
'msg' => ''
|
||||
);
|
||||
$sObjClass = stripslashes(utils::ReadParam('obj_class', '', false, 'class'));
|
||||
$sTempId = utils::ReadParam('temp_id', '');
|
||||
if (empty($sObjClass))
|
||||
{
|
||||
$aResult['error'] = "Missing argument 'obj_class'";
|
||||
}
|
||||
elseif (empty($sTempId))
|
||||
{
|
||||
$aResult['error'] = "Missing argument 'temp_id'";
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$oDoc = utils::ReadPostedDocument('file');
|
||||
$oAttachment = MetaModel::NewObject('Attachment');
|
||||
$oAttachment->Set('expire', time() + 3600); // one hour...
|
||||
$oAttachment->Set('temp_id', $sTempId);
|
||||
$oAttachment->Set('item_class', $sObjClass);
|
||||
$oAttachment->Set('item_id', 0);
|
||||
$oAttachment->Set('contents', $oDoc);
|
||||
$iAttId = $oAttachment->DBInsert();
|
||||
|
||||
$aResult['msg'] = $oDoc->GetFileName();
|
||||
$aResult['icon'] = utils::GetAbsoluteUrlAppRoot().AttachmentPlugIn::GetFileIcon($oDoc->GetFileName());
|
||||
$aResult['att_id'] = $iAttId;
|
||||
}
|
||||
catch (FileUploadException $e)
|
||||
{
|
||||
$aResult['error'] = $e->GetMessage();
|
||||
}
|
||||
}
|
||||
$oPage->add(json_encode($aResult));
|
||||
break;
|
||||
|
||||
case 'remove':
|
||||
$iAttachmentId = utils::ReadParam('att_id', '');
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id = :id");
|
||||
$oSet = new DBObjectSet($oSearch, array(), array('id' => $iAttachmentId));
|
||||
while ($oAttachment = $oSet->Fetch())
|
||||
{
|
||||
$oAttachment->DBDelete();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$oPage->p("Missing argument 'operation'");
|
||||
}
|
||||
|
||||
$oPage->output();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
echo $e->GetMessage();
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
?>
|
||||
191
modules/itop-attachments/ajaxfileupload.js
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
jQuery.extend(
|
||||
{
|
||||
createUploadIframe: function(id, uri)
|
||||
{
|
||||
//create frame
|
||||
var frameId = 'jUploadFrame' + id;
|
||||
var iframeHtml = '<iframe id="' + frameId + '" name="' + frameId + '" style="position:absolute; top:-9999px; left:-9999px"';
|
||||
if(window.ActiveXObject)
|
||||
{
|
||||
if(typeof uri== 'boolean')
|
||||
{
|
||||
iframeHtml += ' src="' + 'javascript:false' + '"';
|
||||
}
|
||||
else if(typeof uri== 'string')
|
||||
{
|
||||
iframeHtml += ' src="' + uri + '"';
|
||||
}
|
||||
}
|
||||
iframeHtml += ' />';
|
||||
jQuery(iframeHtml).appendTo(document.body);
|
||||
|
||||
return jQuery('#' + frameId).get(0);
|
||||
},
|
||||
createUploadForm: function(id, fileElementId)
|
||||
{
|
||||
//create form
|
||||
var formId = 'jUploadForm' + id;
|
||||
var fileId = 'jUploadFile' + id;
|
||||
var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
|
||||
var oldElement = jQuery('#' + fileElementId);
|
||||
var newElement = jQuery(oldElement).clone();
|
||||
jQuery(oldElement).attr('id', fileId);
|
||||
jQuery(oldElement).before(newElement);
|
||||
jQuery(oldElement).appendTo(form);
|
||||
//set attributes
|
||||
jQuery(form).css('position', 'absolute');
|
||||
jQuery(form).css('top', '-1200px');
|
||||
jQuery(form).css('left', '-1200px');
|
||||
jQuery(form).appendTo('body');
|
||||
return form;
|
||||
},
|
||||
|
||||
ajaxFileUpload: function(s) {
|
||||
// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
|
||||
s = jQuery.extend({}, jQuery.ajaxSettings, s);
|
||||
var id = new Date().getTime();
|
||||
var form = jQuery.createUploadForm(id, s.fileElementId);
|
||||
var io = jQuery.createUploadIframe(id, s.secureuri);
|
||||
var frameId = 'jUploadFrame' + id;
|
||||
var formId = 'jUploadForm' + id;
|
||||
// Watch for a new set of requests
|
||||
if ( s.global && ! jQuery.active++ )
|
||||
{
|
||||
jQuery.event.trigger( "ajaxStart" );
|
||||
}
|
||||
var requestDone = false;
|
||||
// Create the request object
|
||||
var xml = {};
|
||||
if ( s.global )
|
||||
jQuery.event.trigger("ajaxSend", [xml, s]);
|
||||
// Wait for a response to come back
|
||||
var uploadCallback = function(isTimeout)
|
||||
{
|
||||
var io = document.getElementById(frameId);
|
||||
try
|
||||
{
|
||||
if(io.contentWindow)
|
||||
{
|
||||
xml.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;
|
||||
xml.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
|
||||
|
||||
}else if(io.contentDocument)
|
||||
{
|
||||
xml.responseText = io.contentDocument.document.body?io.contentDocument.document.body.innerHTML:null;
|
||||
xml.responseXML = io.contentDocument.document.XMLDocument?io.contentDocument.document.XMLDocument:io.contentDocument.document;
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
jQuery.handleError(s, xml, null, e);
|
||||
}
|
||||
if ( xml || isTimeout == "timeout")
|
||||
{
|
||||
requestDone = true;
|
||||
var status;
|
||||
try {
|
||||
status = isTimeout != "timeout" ? "success" : "error";
|
||||
// Make sure that the request was successful or notmodified
|
||||
if ( status != "error" )
|
||||
{
|
||||
// process the data (runs the xml through httpData regardless of callback)
|
||||
var data = jQuery.uploadHttpData( xml, s.dataType );
|
||||
// If a local callback was specified, fire it and pass it the data
|
||||
if ( s.success )
|
||||
s.success( data, status );
|
||||
|
||||
// Fire the global callback
|
||||
if( s.global )
|
||||
jQuery.event.trigger( "ajaxSuccess", [xml, s] );
|
||||
} else
|
||||
jQuery.handleError(s, xml, status);
|
||||
} catch(e)
|
||||
{
|
||||
status = "error";
|
||||
jQuery.handleError(s, xml, status, e);
|
||||
}
|
||||
|
||||
// The request was completed
|
||||
if( s.global )
|
||||
jQuery.event.trigger( "ajaxComplete", [xml, s] );
|
||||
|
||||
// Handle the global AJAX counter
|
||||
if ( s.global && ! --jQuery.active )
|
||||
jQuery.event.trigger( "ajaxStop" );
|
||||
|
||||
// Process result
|
||||
if ( s.complete )
|
||||
s.complete(xml, status);
|
||||
|
||||
jQuery(io).unbind();
|
||||
|
||||
setTimeout(function()
|
||||
{ try
|
||||
{
|
||||
jQuery(io).remove();
|
||||
jQuery(form).remove();
|
||||
|
||||
} catch(e)
|
||||
{
|
||||
jQuery.handleError(s, xml, null, e);
|
||||
}
|
||||
|
||||
}, 100)
|
||||
|
||||
xml = null
|
||||
|
||||
}
|
||||
}
|
||||
// Timeout checker
|
||||
if ( s.timeout > 0 )
|
||||
{
|
||||
setTimeout(function(){
|
||||
// Check to see if the request is still happening
|
||||
if( !requestDone ) uploadCallback( "timeout" );
|
||||
}, s.timeout);
|
||||
}
|
||||
try
|
||||
{
|
||||
|
||||
var form = jQuery('#' + formId);
|
||||
jQuery(form).attr('action', s.url);
|
||||
jQuery(form).attr('method', 'POST');
|
||||
jQuery(form).attr('target', frameId);
|
||||
if(form.encoding)
|
||||
{
|
||||
jQuery(form).attr('encoding', 'multipart/form-data');
|
||||
}
|
||||
else
|
||||
{
|
||||
jQuery(form).attr('enctype', 'multipart/form-data');
|
||||
}
|
||||
jQuery(form).submit();
|
||||
|
||||
} catch(e)
|
||||
{
|
||||
jQuery.handleError(s, xml, null, e);
|
||||
}
|
||||
|
||||
jQuery('#' + frameId).load(uploadCallback );
|
||||
return {abort: function () {}};
|
||||
|
||||
},
|
||||
|
||||
uploadHttpData: function( r, type ) {
|
||||
var data = !type;
|
||||
data = type == "xml" || data ? r.responseXML : r.responseText;
|
||||
// If the type is "script", eval it in global context
|
||||
if ( type == "script" )
|
||||
jQuery.globalEval( data );
|
||||
// Get the JavaScript object, if JSON is used.
|
||||
if ( type == "json" )
|
||||
eval( "data = " + data );
|
||||
// evaluate scripts within html
|
||||
if ( type == "html" )
|
||||
jQuery("<div>").html(data).evalScripts();
|
||||
|
||||
return data;
|
||||
}
|
||||
})
|
||||
|
||||
40
modules/itop-attachments/de.dict.attachments.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Attachments:TabTitle_Count' => 'Attachments (%1$d)',
|
||||
'Attachments:EmptyTabTitle' => 'Attachments',
|
||||
'Attachments:FieldsetTitle' => 'Attachments',
|
||||
'Attachments:DeleteBtn' => 'Löschen',
|
||||
'Attachments:History_File_Added' => 'Attachment %1$s hinzugefügt.',
|
||||
'Attachments:History_File_Removed' => 'Attachment %1$s entfernt.',
|
||||
'Attachments:AddAttachment' => 'Attachment hinzufügen: ',
|
||||
'Attachments:UploadNotAllowedOnThisSystem' => 'Datei-Upload auf diesem System NICHT erlaubt.',
|
||||
'Attachment:Max_Go' => '(Maximale Datei-Größe: %1$s Go)',
|
||||
'Attachment:Max_Mo' => '(Maximale Datei-Größe: %1$s Mo)',
|
||||
'Attachment:Max_Ko' => '(Maximale Datei-Größe: %1$s Ko)',
|
||||
));
|
||||
?>
|
||||
39
modules/itop-attachments/en.dict.attachments.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', array(
|
||||
'Attachments:TabTitle_Count' => 'Attachments (%1$d)',
|
||||
'Attachments:EmptyTabTitle' => 'Attachments',
|
||||
'Attachments:FieldsetTitle' => 'Attachments',
|
||||
'Attachments:DeleteBtn' => 'Delete',
|
||||
'Attachments:History_File_Added' => 'Attachment %1$s added.',
|
||||
'Attachments:History_File_Removed' => 'Attachment %1$s removed.',
|
||||
'Attachments:AddAttachment' => 'Add attachment: ',
|
||||
'Attachments:UploadNotAllowedOnThisSystem' => 'File upload in NOT allowed on this system.',
|
||||
'Attachment:Max_Go' => '(Maximum file size: %1$s Go)',
|
||||
'Attachment:Max_Mo' => '(Maximum file size: %1$s Mo)',
|
||||
'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)',
|
||||
));
|
||||
?>
|
||||