mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-14 07:54:10 +01:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da217a1cb3 | ||
|
|
d90b1a3d82 | ||
|
|
3694108f42 | ||
|
|
8cf75f826f | ||
|
|
ad9726b64c | ||
|
|
e32e275f40 | ||
|
|
195056492e | ||
|
|
af338de17f | ||
|
|
a6aa183e26 | ||
|
|
b5074c4cee | ||
|
|
8b9589744b | ||
|
|
8259a79cd2 | ||
|
|
a23ea9a01f | ||
|
|
949b213f9d | ||
|
|
a940adc4ba | ||
|
|
5d994edd62 | ||
|
|
b1ca1f2630 | ||
|
|
58e315d7f6 | ||
|
|
1059befa39 | ||
|
|
0f5130611d | ||
|
|
a1271da74a | ||
|
|
0d40235791 | ||
|
|
dd63f2b817 | ||
|
|
8f84c3b84b | ||
|
|
00c58bb245 | ||
|
|
3a876d5c75 | ||
|
|
147916062b | ||
|
|
0de6f98add | ||
|
|
a076792e77 | ||
|
|
2d2a6857de | ||
|
|
373641e01d | ||
|
|
d11eceac62 | ||
|
|
3965806fa0 | ||
|
|
2625d2da80 | ||
|
|
02d32a556d | ||
|
|
71fcc6f026 | ||
|
|
7168860a0b | ||
|
|
684c88e0b8 | ||
|
|
84741c19f0 | ||
|
|
86f649affc | ||
|
|
4f5c987d8b | ||
|
|
e7b5953feb | ||
|
|
e441e5e78a | ||
|
|
6be9a87c15 | ||
|
|
43daa2ef08 | ||
|
|
caa2a05bf4 | ||
|
|
fc39d8aca9 | ||
|
|
cf12578289 | ||
|
|
44952d1ea0 | ||
|
|
7f15eed9a8 | ||
|
|
c2f5cafaf3 | ||
|
|
81822efa0f | ||
|
|
923a025f1c | ||
|
|
a4b6f4e37c | ||
|
|
f0c73451a2 | ||
|
|
db6e813cba | ||
|
|
d74e3e6b42 | ||
|
|
b740cb2afd | ||
|
|
6ad3c40c42 | ||
|
|
f49c8ce188 | ||
|
|
acf828b72e | ||
|
|
bac92716f3 | ||
|
|
07257cc2d2 | ||
|
|
87ba67225a | ||
|
|
2ad3b3c27e | ||
|
|
92a640e41a | ||
|
|
842df7646b | ||
|
|
01b38d2ed6 |
@@ -90,7 +90,7 @@ ij_xml_attribute_wrap = normal
|
||||
ij_xml_block_comment_at_first_column = true
|
||||
ij_xml_keep_blank_lines = 2
|
||||
ij_xml_keep_indents_on_empty_lines = false
|
||||
ij_xml_keep_line_breaks = false
|
||||
ij_xml_keep_line_breaks = true
|
||||
ij_xml_keep_line_breaks_in_text = true
|
||||
ij_xml_keep_whitespaces = false
|
||||
ij_xml_keep_whitespaces_around_cdata = preserve
|
||||
@@ -110,6 +110,7 @@ ij_shell_keep_column_alignment_padding = false
|
||||
ij_shell_minify_program = false
|
||||
ij_shell_redirect_followed_by_space = false
|
||||
ij_shell_switch_cases_indented = false
|
||||
ij_shell_use_unix_line_separator = true
|
||||
|
||||
[{*.cjs,*.js}]
|
||||
indent_style = tab
|
||||
@@ -279,17 +280,17 @@ ij_javascript_while_brace_force = always
|
||||
ij_javascript_while_on_new_line = false
|
||||
ij_javascript_wrap_comments = false
|
||||
|
||||
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
|
||||
[{*.ctp, *.hphp, *.inc, *.module, *.php, *.php4, *.php5, *.phtml}]
|
||||
indent_style = tab
|
||||
ij_continuation_indent_size = 4
|
||||
ij_smart_tabs = true
|
||||
ij_wrap_on_typing = false
|
||||
ij_php_align_assignments = false
|
||||
ij_php_align_assignments = true
|
||||
ij_php_align_class_constants = false
|
||||
ij_php_align_group_field_declarations = false
|
||||
ij_php_align_inline_comments = false
|
||||
ij_php_align_key_value_pairs = false
|
||||
ij_php_align_multiline_array_initializer_expression = false
|
||||
ij_php_align_key_value_pairs = true
|
||||
ij_php_align_multiline_array_initializer_expression = true
|
||||
ij_php_align_multiline_binary_operation = false
|
||||
ij_php_align_multiline_chained_methods = false
|
||||
ij_php_align_multiline_extends_list = false
|
||||
@@ -514,7 +515,7 @@ ij_json_wrap_long_lines = false
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_visual_guides = none
|
||||
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
|
||||
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
|
||||
ij_html_align_attributes = true
|
||||
ij_html_align_text = false
|
||||
ij_html_attribute_wrap = normal
|
||||
@@ -541,7 +542,21 @@ ij_html_space_inside_empty_tag = false
|
||||
ij_html_text_wrap = normal
|
||||
ij_html_uniform_ident = false
|
||||
|
||||
[{*.yaml, *.yml}]
|
||||
[{*.markdown,*.md}]
|
||||
ij_visual_guides = none
|
||||
ij_markdown_force_one_space_after_blockquote_symbol = true
|
||||
ij_markdown_force_one_space_after_header_symbol = true
|
||||
ij_markdown_force_one_space_after_list_bullet = true
|
||||
ij_markdown_force_one_space_between_words = true
|
||||
ij_markdown_keep_indents_on_empty_lines = false
|
||||
ij_markdown_max_lines_around_block_elements = 1
|
||||
ij_markdown_max_lines_around_header = 1
|
||||
ij_markdown_max_lines_between_paragraphs = 1
|
||||
ij_markdown_min_lines_around_block_elements = 1
|
||||
ij_markdown_min_lines_around_header = 1
|
||||
ij_markdown_min_lines_between_paragraphs = 1
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 2
|
||||
ij_visual_guides = none
|
||||
ij_yaml_align_values_properties = do_not_align
|
||||
|
||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -1,15 +1,4 @@
|
||||
|
||||
################################### Temporary ignore rules during 2.8 UI/UX dev - START
|
||||
/css/backoffice/main.css
|
||||
|
||||
# Sass converter
|
||||
/**/.sass-cache/
|
||||
################################### Temporary ignore rules during 2.8 UI/UX dev - END
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# no slash at the end to handle also symlinks
|
||||
/toolkit
|
||||
/env-*
|
||||
@@ -17,6 +6,12 @@
|
||||
# maintenance mode (N°2240)
|
||||
/.maintenance
|
||||
|
||||
# listing prevention in conf directory
|
||||
/conf/**
|
||||
!/conf/.htaccess
|
||||
!/conf/index.php
|
||||
!/conf/web.config
|
||||
|
||||
# composer reserver directory, from sources, populate/update using "composer install"
|
||||
vendor/*
|
||||
test/vendor/*
|
||||
@@ -24,7 +19,6 @@ test/vendor/*
|
||||
# all conf but listing prevention
|
||||
/conf/**
|
||||
!/conf/.htaccess
|
||||
!/conf/index.php
|
||||
!/conf/web.config
|
||||
|
||||
# all datas but listing prevention
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2010-2021 Combodo SARL
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2021 Combodo SARL
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2021 Combodo SARL
|
||||
* Copyright (C) 2010-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
* `curl -L -o /usr/bin/jq.exe https://github.com/stedolan/jq/releases/latest/download/jq-win64.exe`
|
||||
* this is a Windows port : https://stedolan.github.io/jq/
|
||||
*
|
||||
* Known bug on Windows :
|
||||
* Licenses added from Composer contains a path in the product node (N°3870)
|
||||
* `<product scope="lib">C:\Dev\wamp64\www\itop-dev\.make\license/../..//lib/symfony/console</product>`
|
||||
*
|
||||
* Licenses sources :
|
||||
* * `composer licenses --format json` (see https://getcomposer.org/doc/03-cli.md#licenses)
|
||||
* * keep every existing nodes with `/licenses/license[11]/product/@scope` not in ['lib', 'datamodels']
|
||||
@@ -70,39 +66,83 @@ function get_license_nodes($file_path)
|
||||
$xp = new DOMXPath($dom);
|
||||
|
||||
$licenseList = $xp->query('/licenses/license');
|
||||
$licenses = iterator_to_array($licenseList);
|
||||
$licenses = iterator_to_array($licenseList);
|
||||
|
||||
usort($licenses, 'sort_by_product');
|
||||
|
||||
return $licenses;
|
||||
}
|
||||
|
||||
/** @noinspection SuspiciousAssignmentsInspection */
|
||||
function fix_product_name(DOMNode &$oProductNode)
|
||||
{
|
||||
$sProductNameOrig = $oProductNode->nodeValue;
|
||||
|
||||
// sample : `C:\Dev\wamp64\www\itop-27\.make\license/../..//lib/symfony/polyfill-ctype`
|
||||
$sProductNameFixed = remove_dir_from_string($sProductNameOrig, 'lib/');
|
||||
|
||||
// sample : `C:\Dev\wamp64\www\itop-27\.make\license/../..//datamodels/2.x/authent-cas/vendor/apereo/phpcas`
|
||||
$sProductNameFixed = remove_dir_from_string($sProductNameFixed, 'vendor/');
|
||||
|
||||
$oProductNode->nodeValue = $sProductNameFixed;
|
||||
}
|
||||
|
||||
function remove_dir_from_string($sString, $sNeedle)
|
||||
{
|
||||
if (strpos($sString, $sNeedle) === false) {
|
||||
return $sString;
|
||||
}
|
||||
|
||||
$sStringTmp = strstr($sString, $sNeedle);
|
||||
$sStringFixed = str_replace($sNeedle, '', $sStringTmp);
|
||||
|
||||
// DEBUG trace O:)
|
||||
// echo "$sNeedle = $sString => $sStringFixed\n";
|
||||
|
||||
return $sStringFixed;
|
||||
}
|
||||
|
||||
$old_licenses = get_license_nodes($xmlFilePath);
|
||||
|
||||
//generate file with updated licenses
|
||||
$generated_license_file_path = __DIR__."/provfile.xml";
|
||||
exec("bash " . __DIR__ . "/gen-community-license.sh $iTopFolder > ". $generated_license_file_path);
|
||||
echo "- Generating licences...";
|
||||
exec("bash ".__DIR__."/gen-community-license.sh $iTopFolder > ".$generated_license_file_path);
|
||||
echo "OK!\n";
|
||||
|
||||
echo "- Get licenses nodes...";
|
||||
$new_licenses = get_license_nodes($generated_license_file_path);
|
||||
exec("rm -f ". $generated_license_file_path);
|
||||
unlink($generated_license_file_path);
|
||||
|
||||
foreach ($old_licenses as $b) {
|
||||
$aProductNode = get_product_node($b);
|
||||
|
||||
if (get_scope($aProductNode) !== "lib" && get_scope($aProductNode) !== "datamodels" )
|
||||
{
|
||||
if (get_scope($aProductNode) !== "lib" && get_scope($aProductNode) !== "datamodels") {
|
||||
$new_licenses[] = $b;
|
||||
}
|
||||
}
|
||||
|
||||
usort($new_licenses, 'sort_by_product');
|
||||
echo "OK!\n";
|
||||
|
||||
echo "- Overwritting Combodo license file...";
|
||||
$new_dom = new DOMDocument("1.0");
|
||||
$new_dom->formatOutput = true;
|
||||
$root = $new_dom->createElement("licenses");
|
||||
$new_dom->appendChild($root);
|
||||
|
||||
foreach ($new_licenses as $b) {
|
||||
$node = $new_dom->importNode($b,true);
|
||||
$root->appendChild($new_dom->importNode($b,true));
|
||||
$node = $new_dom->importNode($b, true);
|
||||
|
||||
// N°3870 fix when running script in Windows
|
||||
// fix should be in gen-community-license.sh but it is easier to do it here !
|
||||
if (strncasecmp(PHP_OS, 'WIN', 3) === 0) {
|
||||
$oProductNodeOrig = get_product_node($node);
|
||||
fix_product_name($oProductNodeOrig);
|
||||
}
|
||||
|
||||
$root->appendChild($node);
|
||||
}
|
||||
|
||||
$new_dom->save($xmlFilePath);
|
||||
$new_dom->save($xmlFilePath);
|
||||
echo "OK!\n";
|
||||
77
.make/release/changelog.php
Normal file
77
.make/release/changelog.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* Usage :
|
||||
* `php changelog.php 2.7.4`
|
||||
*
|
||||
* As argument is passed the git ref (tag name or sha1) we want to use as reference
|
||||
*
|
||||
* Outputs :
|
||||
*
|
||||
* 1. List of bugs as CSV :
|
||||
* bug ref;link
|
||||
* Example :
|
||||
* <code>
|
||||
* Bug_ref;Bug_URL;sha1
|
||||
* 1234;https://support.combodo.com/pages/UI.php?operation=details&class=Bug&id=1234;949b213f9|b1ca1f263|a1271da74
|
||||
* </code>
|
||||
*
|
||||
* 2. List of commits sha1/message without bug ref
|
||||
* Example :
|
||||
* <code>
|
||||
* sha1;subject
|
||||
* a6aa183e2;:bookmark: Prepare 2.7.5
|
||||
* </code>
|
||||
*/
|
||||
|
||||
|
||||
if (count($argv) === 1) {
|
||||
echo '⚠ You must pass the base tag/sha1 as parameter';
|
||||
exit(1);
|
||||
}
|
||||
$sBaseReference = $argv[1];
|
||||
|
||||
|
||||
//--- Get log
|
||||
$sGitLogCommand = 'git log --decorate --pretty="%h;%s" --date-order --no-merges '.$sBaseReference.'..HEAD';
|
||||
$sGitLogRaw = shell_exec($sGitLogCommand);
|
||||
|
||||
|
||||
//--- Analyze log
|
||||
$aGitLogLines = preg_split('/\n/', trim($sGitLogRaw));;
|
||||
$aLogLinesWithBugRef = [];
|
||||
$aLogLineNoBug = [];
|
||||
foreach ($aGitLogLines as $sLogLine) {
|
||||
$sBugRef = preg_match('/[nN]°(\d{3,4})/', $sLogLine, $aLineBugRef);
|
||||
if (($sBugRef === false) || empty($aLineBugRef)) {
|
||||
$aLogLineNoBug[] = $sLogLine;
|
||||
continue;
|
||||
}
|
||||
|
||||
$iBugId = $aLineBugRef[1];
|
||||
$sSha = substr($sLogLine, 0, 9);
|
||||
|
||||
if (array_key_exists($iBugId, $aLogLinesWithBugRef)) {
|
||||
$aBugShaRefs = $aLogLinesWithBugRef[$iBugId];
|
||||
$aBugShaRefs[] = $sSha;
|
||||
$aLogLinesWithBugRef[$iBugId] = $aBugShaRefs;
|
||||
} else {
|
||||
$aLogLinesWithBugRef[$iBugId] = [$sSha];
|
||||
}
|
||||
}
|
||||
$aBugsList = array_keys($aLogLinesWithBugRef);
|
||||
sort($aBugsList, SORT_NUMERIC);
|
||||
|
||||
|
||||
//-- Output results
|
||||
echo "# Bugs included\n";
|
||||
echo "Bug_ref;Bug_URL;sha1\n";
|
||||
foreach ($aBugsList as $sBugRef) {
|
||||
$sShaRefs = implode('|', $aLogLinesWithBugRef[$sBugRef]);
|
||||
echo "{$sBugRef};https://support.combodo.com/pages/UI.php?operation=details&class=Bug&id={$sBugRef};$sShaRefs\n";
|
||||
}
|
||||
echo "\n";
|
||||
echo "# Logs line without bug referenced\n";
|
||||
echo "sha1;subject\n";
|
||||
foreach ($aLogLineNoBug as $sLogLine) {
|
||||
echo "$sLogLine\n";
|
||||
}
|
||||
@@ -42,7 +42,7 @@ If you want to use another license, you may [create an extension][wiki new ext].
|
||||
When we first start with Git, we were using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. As
|
||||
there was some confusions about branches to use for current developed release and previous maintained release, and also because we were
|
||||
using just a very few of the GitFlow commands, we decided to add just a little modification to this branch model : since april 2020
|
||||
we don't have a `master` branch anymore.
|
||||
we don't have anymore a `master` branch.
|
||||
|
||||
Here are the branches we use and their meaning :
|
||||
|
||||
@@ -52,23 +52,23 @@ Here are the branches we use and their meaning :
|
||||
|
||||
For example, if no version is currently prepared for shipping we could have:
|
||||
|
||||
- `develop` containing future 3.0.0 version
|
||||
- `develop` containing future 2.8.0 version
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
In this example, when 3.0.0-beta is shipped that will become:
|
||||
In this example, when 2.8.0-beta is shipped that will become:
|
||||
|
||||
- `develop`: future 3.1.0 version
|
||||
- `release/3.0.0`: 3.0.0-beta
|
||||
- `develop`: future 2.9.0 version
|
||||
- `release/2.8`: 2.8.0-beta
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
And when 3.0.0 final will be out:
|
||||
And when 2.8.0 final will be out:
|
||||
|
||||
- `develop`: future 3.1.0 version
|
||||
- `support/3.0`: 3.0.x maintenance version (will host developments for 3.0.1)
|
||||
- `develop`: future 2.9.0 version
|
||||
- `support/2.8`: 2.8.x maintenance version (will host developments for 2.8.1)
|
||||
- `support/2.7`: 2.7.x maintenance version
|
||||
- `support/2.6`: 2.6.x maintenance version
|
||||
- `support/2.5`: 2.5.x maintenance version
|
||||
|
||||
145
README.md
145
README.md
@@ -21,35 +21,21 @@ iTop also offers mass import tools and web services to integrate with your IT
|
||||
- [Data synchronization][18] (for data federation)
|
||||
|
||||
|
||||
## Latest release
|
||||
|
||||
- [Changes since the previous version][62]
|
||||
- [New features][63]
|
||||
- [Installation notes][64]
|
||||
- [Download][65]
|
||||
|
||||
[62]: https://www.itophub.io/wiki/page?id=latest:release:change_log
|
||||
[63]: https://www.itophub.io/wiki/page?id=latest:release:start
|
||||
[64]: https://www.itophub.io/wiki/page?id=latest:install:start
|
||||
[65]: https://sourceforge.net/projects/itop/files/latest/download
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
- [iTop Forums][1]: community support
|
||||
- [iTop Tickets][2]: for feature requests and bug reports
|
||||
- [Releases download][3]
|
||||
- [Software requirements][4]
|
||||
- [Documentation][5] covering both iTop and its official extensions
|
||||
- [iTop Hub][6] : discover and install extensions !
|
||||
- [Documentation][4] covering both iTop and its official extensions
|
||||
- [iTop Hub][5] : discover and install extensions !
|
||||
|
||||
|
||||
|
||||
[1]: https://sourceforge.net/p/itop/discussion/
|
||||
[2]: https://sourceforge.net/p/itop/tickets/
|
||||
[3]: https://sourceforge.net/projects/itop/files/itop/
|
||||
[4]: https://www.itophub.io/wiki/page?id=latest:install:upgrading_itop
|
||||
[5]: https://www.itophub.io/wiki
|
||||
[6]: https://store.itophub.io/en_US/
|
||||
[4]: https://www.itophub.io/wiki
|
||||
[5]: https://store.itophub.io/en_US/
|
||||
|
||||
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
|
||||
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing
|
||||
@@ -63,6 +49,47 @@ iTop also offers mass import tools and web services to integrate with your IT
|
||||
|
||||
|
||||
|
||||
## Last releases
|
||||
|
||||
### Versions 2.7.*
|
||||
- 2.7.1 published on April 8, 2020
|
||||
- [Changes since the previous version][62]
|
||||
- [New features][63]
|
||||
- [Migration notes][64]
|
||||
- [Download iTop 2.7.0-2][65]
|
||||
|
||||
[62]: https://www.itophub.io/wiki/page?id=2_7_0:release:change_log
|
||||
[63]: https://www.itophub.io/wiki/page?id=2_7_0:release:2_7_whats_new
|
||||
[64]: https://www.itophub.io/wiki/page?id=2_7_0:install:260_to_270_migration_notes
|
||||
[65]: https://sourceforge.net/projects/itop/files/itop/2.7.0-2
|
||||
|
||||
|
||||
### Versions 2.6.*
|
||||
- 2.6.0 published on January 9, 2019
|
||||
- [Changes since the previous version][58]
|
||||
- [New features][59]
|
||||
- [Migration notes][60]
|
||||
- [Download iTop 2.6.3][61]
|
||||
|
||||
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
|
||||
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
|
||||
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
|
||||
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.3
|
||||
|
||||
|
||||
### Versions 2.5.*
|
||||
- 2.5.0 published on July 11, 2018
|
||||
- [Changes since the previous version][54]
|
||||
- [New features][55]
|
||||
- [Migration notes][56]
|
||||
- [Download iTop 2.5.1][57]
|
||||
|
||||
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
|
||||
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
|
||||
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
|
||||
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
|
||||
|
||||
|
||||
## About Us
|
||||
|
||||
iTop development is sponsored, led and supported by [Combodo][0].
|
||||
@@ -72,55 +99,51 @@ iTop development is sponsored, led and supported by [Combodo][0].
|
||||
|
||||
## Contributors
|
||||
|
||||
We would like to give a special thank you 🤗 to the people from the community who contributed to this project, including:
|
||||
We would like to give a special thank you to the people from the community who contributed to this project, including:
|
||||
|
||||
### Names
|
||||
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Bilger, Jean-François
|
||||
- Bostoen, Jeffrey (a.k.a @jbostoen)
|
||||
- Cardoso, Anderson
|
||||
- Cassaro, Bruno
|
||||
- Casteleyn, Thomas (a.k.a @Hipska)
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Couronné, Guy
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
- Kaltefleiter, Lars (a.k.a @larhip)
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
- Konečný, Kamil
|
||||
- Kunin, Vladimir
|
||||
- Lassiter, Dennis
|
||||
- Lazcano, Federico
|
||||
- Lucas, Jonathan
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Bilger, Jean-François
|
||||
- Bostoen, Jeffrey
|
||||
- Cardoso, Anderson
|
||||
- Cassaro, Bruno
|
||||
- Casteleyn, Thomas
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Couronné, Guy
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
- Hippler, Lars
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
- Konečný, Kamil
|
||||
- Kunin, Vladimir
|
||||
- Lassiter, Dennis
|
||||
- Lazcano, Federico
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Mindêllo de Andrade, Lucas (a.k.a @rokam)
|
||||
- Rosenke, Stephan
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
|
||||
### Aliases
|
||||
|
||||
- chifu1234
|
||||
- cprobst
|
||||
- DudekArtur
|
||||
- Karkoff1212
|
||||
- Laura
|
||||
- Purple Grape
|
||||
- Schlobinux
|
||||
- theBigOne
|
||||
- ulmerspatz
|
||||
- chifu1234
|
||||
- cprobst
|
||||
- Karkoff1212
|
||||
- larhip
|
||||
- Laura
|
||||
- Purple Grape
|
||||
- Schlobinux
|
||||
- theBigOne
|
||||
- ulmerspatz
|
||||
|
||||
### Companies
|
||||
|
||||
- [Hardis](https://www.hardis-group.com/)
|
||||
- [ITOMIG](https://www.itomig.de/)
|
||||
- [Pimkie](https://www.pimkie.com/)
|
||||
- [Super-Visions](https://www.super-visions.com/)
|
||||
- Hardis
|
||||
- ITOMIG
|
||||
- Pimkie
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ responsible disclosure and will make every effort to acknowledge your contributi
|
||||
### iTop vulnerabilities
|
||||
Please send a procedure to reproduce iTop vulnerabilities to [itop-security@combodo.com](mailto:itop-security@combodo.com).
|
||||
|
||||
You can send us a standard "given / when / then" report, including iTop version, impacts, and maybe installed modules or data if they are
|
||||
You can send us a standard "given / then / when" report, including iTop version, impacts, and maybe installed modules or data if they are
|
||||
needed to reproduce.
|
||||
|
||||
### Dependencies vulnerabilities
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* UserRightsMatrix (User management Module)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
* UserRightsNull
|
||||
* User management Module - say Yeah! to everything
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
define('ADMIN_PROFILE_NAME', 'Administrator');
|
||||
@@ -42,6 +55,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_profiles",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -156,9 +170,11 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetReadOnlyAttributes()
|
||||
@@ -227,6 +243,7 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -253,54 +270,17 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
|
||||
public function CheckToDelete(&$oDeletionPlan)
|
||||
{
|
||||
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
||||
{
|
||||
// Users deletion is NOT allowed in demo mode
|
||||
$oDeletionPlan->AddToDelete($this, null);
|
||||
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
|
||||
$oDeletionPlan->ComputeResults();
|
||||
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
||||
}
|
||||
catch (SecurityException $e) {
|
||||
// Users deletion is NOT allowed
|
||||
$oDeletionPlan->AddToDelete($this, null);
|
||||
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
||||
$oDeletionPlan->ComputeResults();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::CheckToDelete($oDeletionPlan);
|
||||
}
|
||||
|
||||
public function DoCheckToDelete(&$oDeletionPlan)
|
||||
{
|
||||
if (MetaModel::GetConfig()->Get('demo_mode')) {
|
||||
// Users deletion is NOT allowed in demo mode
|
||||
$oDeletionPlan->AddToDelete($this, null);
|
||||
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
|
||||
$oDeletionPlan->ComputeResults();
|
||||
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
||||
}
|
||||
catch (SecurityException $e) {
|
||||
// Users deletion is NOT allowed
|
||||
$oDeletionPlan->AddToDelete($this, null);
|
||||
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
|
||||
$oDeletionPlan->ComputeResults();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return parent::DoCheckToDelete($oDeletionPlan);
|
||||
}
|
||||
|
||||
protected function OnInsert()
|
||||
{
|
||||
$this->CheckIfProfileIsAllowed(UR_ACTION_CREATE);
|
||||
@@ -313,6 +293,7 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
|
||||
protected function OnDelete()
|
||||
{
|
||||
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,6 +349,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userorg",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -77,6 +77,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_profiles",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -311,9 +312,11 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +336,7 @@ class URP_UserProfile extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -372,6 +376,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
"db_table" => "priv_urp_userorg",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -412,6 +417,7 @@ class URP_ActionGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_actions",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -448,6 +454,7 @@ class URP_StimulusGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_stimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -484,6 +491,7 @@ class URP_AttributeGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_attributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -58,6 +58,7 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_profiles",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -143,9 +144,11 @@ class URP_Profiles extends UserRightsBaseClass
|
||||
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +167,7 @@ class URP_Dimensions extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_dimensions",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -276,6 +280,7 @@ class URP_UserProfile extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_userprofile",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -316,6 +321,7 @@ class URP_ProfileProjection extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_profileprojection",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -396,6 +402,7 @@ class URP_ClassProjection extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_classprojection",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -467,6 +474,7 @@ class URP_ActionGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_actions",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -503,6 +511,7 @@ class URP_StimulusGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_stimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -539,6 +548,7 @@ class URP_AttributeGrant extends UserRightsBaseClass
|
||||
"db_table" => "priv_urp_grant_attributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -30,11 +30,8 @@ function mb_str_replace($search, $replace, $subject, &$count = 0) {
|
||||
$replacements = array_pad($replacements, count($searches), '');
|
||||
foreach ($searches as $key => $search) {
|
||||
$parts = mb_split(preg_quote($search), $subject);
|
||||
if (is_array($parts))
|
||||
{
|
||||
$count += count($parts) - 1;
|
||||
$subject = implode($replacements[$key], $parts);
|
||||
}
|
||||
$count += count($parts) - 1;
|
||||
$subject = implode($replacements[$key], $parts);
|
||||
}
|
||||
} else {
|
||||
// Call mb_str_replace for each subject in array, recursively
|
||||
|
||||
@@ -1,16 +1,415 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/AjaxPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class ajax_page
|
||||
* @deprecated will be removed in 3.1.0 - moved to AjaxPage
|
||||
*/
|
||||
class ajax_page extends AjaxPage
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class ajax_page extends WebPage implements iTabbedPage
|
||||
{
|
||||
/**
|
||||
* Jquery style ready script
|
||||
* @var array
|
||||
*/
|
||||
protected $m_sReadyScript;
|
||||
protected $m_oTabs;
|
||||
private $m_sMenu; // If set, then the menu will be updated
|
||||
|
||||
/**
|
||||
* constructor for the web page
|
||||
*
|
||||
* @param string $s_title Not used
|
||||
*/
|
||||
function __construct($s_title) {
|
||||
$sPrintable = utils::ReadParam('printable', '0');
|
||||
$bPrintable = ($sPrintable == '1');
|
||||
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
$this->m_sReadyScript = "";
|
||||
//$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->no_cache();
|
||||
$this->add_xframe_options();
|
||||
$this->m_oTabs = new TabManager();
|
||||
$this->sContentType = 'text/html';
|
||||
$this->sContentDisposition = 'inline';
|
||||
$this->m_sMenu = "";
|
||||
|
||||
utils::InitArchiveMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function SetCurrentTabContainer($sTabContainer = '')
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
|
||||
{
|
||||
return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
|
||||
{
|
||||
$this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetCurrentTab()
|
||||
{
|
||||
return $this->m_oTabs->GetCurrentTab();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function RemoveTab($sTabCode, $sTabContainer = null)
|
||||
{
|
||||
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function FindTab($sPattern, $sTabContainer = null)
|
||||
{
|
||||
return $this->m_oTabs->FindTab($sPattern, $sTabContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the given tab the active one, as if it were clicked
|
||||
* DOES NOT WORK: apparently in the *old* version of jquery
|
||||
* that we are using this is not supported... TO DO upgrade
|
||||
* the whole jquery bundle...
|
||||
*/
|
||||
public function SelectTab($sTabContainer, $sTabCode)
|
||||
{
|
||||
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sHtml
|
||||
*/
|
||||
public function AddToMenu($sHtml)
|
||||
{
|
||||
$this->m_sMenu .= $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
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 ($this->m_oTabs->TabsContainerCount() > 0)
|
||||
{
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
// Ugly patch for a change in the behavior of jQuery UI:
|
||||
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
|
||||
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
|
||||
// is taken into account and causes "local" tabs to be considered as Ajax
|
||||
// unless their URL is equal to the URL of the page...
|
||||
if ($('base').length > 0)
|
||||
{
|
||||
$('div[id^=tabbedContent] > ul > li > a').each(function() {
|
||||
var sHash = location.hash;
|
||||
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
|
||||
$(this).attr("href", sCleanLocation+$(this).attr("href"));
|
||||
});
|
||||
}
|
||||
if ($.bbq)
|
||||
{
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// Enable tabs on all tab widgets. The `event` property must be overridden so
|
||||
// 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' });
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
tabs.find( tab_a_selector ).click(function()
|
||||
{
|
||||
var state = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
|
||||
|
||||
// Get the index of this tab.
|
||||
var idx = $(this).parent().prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
state[ id ] = idx;
|
||||
$.bbq.pushState( state );
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
tabs.tabs();
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
// Render the tabs in the page (if any)
|
||||
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
|
||||
|
||||
// Additional UI widgets to be activated inside the ajax fragment
|
||||
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script)
|
||||
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
|
||||
{
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
PrepareWidgets();
|
||||
EOF
|
||||
);
|
||||
}
|
||||
$this->outputCollapsibleSectionInit();
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
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;
|
||||
}
|
||||
if (!empty($this->m_sMenu))
|
||||
{
|
||||
$uid = time();
|
||||
echo "<div id=\"accordion_temp_$uid\">\n";
|
||||
echo "<div id=\"accordion\">\n";
|
||||
echo "<!-- Beginning of the accordion menu -->\n";
|
||||
echo self::FilterXSS($this->m_sMenu);
|
||||
echo "<!-- End of the accordion menu-->\n";
|
||||
echo "</div>\n";
|
||||
echo "</div>\n";
|
||||
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
|
||||
echo "$('#accordion_temp_$uid').remove();\n";
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
|
||||
//echo $this->s_deferred_content;
|
||||
if (count($this->a_scripts) > 0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo implode("\n", $this->a_scripts);
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (count($this->a_linked_scripts) > 0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
foreach($this->a_linked_scripts as $sScriptUrl)
|
||||
{
|
||||
echo '$.getScript('.json_encode($sScriptUrl).");\n";
|
||||
}
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (!empty($this->s_deferred_content))
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if (!empty($this->m_sReadyScript))
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
if(count($this->a_linked_stylesheets) > 0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">";
|
||||
foreach($this->a_linked_stylesheets as $aStylesheet)
|
||||
{
|
||||
$sStylesheetUrl = $aStylesheet['link'];
|
||||
echo "if (!$('link[href=\"{$sStylesheetUrl}\"]').length) $('<link href=\"{$sStylesheetUrl}\" rel=\"stylesheet\">').appendTo('head');\n";
|
||||
}
|
||||
echo "\n</script>\n";
|
||||
}
|
||||
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo self::FilterXSS($s_captured_output);
|
||||
}
|
||||
|
||||
$oKPI->ComputeAndReport('Echoing');
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a paragraph with a smaller font into the page
|
||||
* NOT implemented (i.e does nothing)
|
||||
* @param string $sText Content of the (small) paragraph
|
||||
* @return void
|
||||
*/
|
||||
public function small_p($sText)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add($sHtml)
|
||||
{
|
||||
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
|
||||
{
|
||||
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::add($sHtml);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function start_capture()
|
||||
{
|
||||
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
|
||||
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
|
||||
|
||||
if (!empty($sCurrentTabContainer) && !empty($sCurrentTab))
|
||||
{
|
||||
$iOffset = $this->m_oTabs->GetCurrentTabLength();
|
||||
return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::start_capture();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function end_capture($offset)
|
||||
{
|
||||
if (is_array($offset))
|
||||
{
|
||||
if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab']))
|
||||
{
|
||||
$sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = '';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCaptured = parent::end_capture($offset);
|
||||
}
|
||||
return $sCaptured;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_sReadyScript .= $sScript."\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetUniqueId()
|
||||
{
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Includes all the classes to have the application up and running
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
|
||||
@@ -15,4 +31,10 @@ require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.rule.class.inc.php');
|
||||
require_once(APPROOT.'/application/query.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
|
||||
//require_once(APPROOT.'/application/menunode.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
class ApplicationException extends CoreException
|
||||
{
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,27 +20,23 @@
|
||||
/**
|
||||
* Class ApplicationContext
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
|
||||
require_once(APPROOT."/application/utils.inc.php");
|
||||
|
||||
/**
|
||||
* Interface for directing end-users to the relevant application
|
||||
*/
|
||||
*/
|
||||
interface iDBObjectURLMaker
|
||||
{
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
/**
|
||||
* @param string $sClass
|
||||
* @param string $iId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function MakeObjectURL($sClass, $iId);
|
||||
}
|
||||
|
||||
@@ -204,46 +200,23 @@ class ApplicationContext
|
||||
}
|
||||
return implode("&", $aParams);
|
||||
}
|
||||
/**
|
||||
* @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation
|
||||
* Returns the params as c[menu]:..., c[org_id]:....
|
||||
* @return string The params
|
||||
*/
|
||||
public function GetForPostParams()
|
||||
{
|
||||
return json_encode($this->aValues);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the context as sequence of input tags to be inserted inside a <form> tag
|
||||
*
|
||||
* @return string The context as a sequence of <input type="hidden" /> tags
|
||||
*/
|
||||
public function GetForForm()
|
||||
{
|
||||
$sContext = "";
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
foreach($this->aValues as $sName => $sValue)
|
||||
{
|
||||
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
|
||||
}
|
||||
return $sContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as sequence of input tags to be inserted inside a <form> tag
|
||||
*
|
||||
*/
|
||||
public function GetForFormBlock(): UIBlock
|
||||
{
|
||||
$oContext = new UIContentBlock();
|
||||
foreach ($this->aValues as $sName => $sValue) {
|
||||
$oContext->AddSubBlock(InputUIBlockFactory::MakeForHidden('c[$sName]', utils::HtmlEntities($sValue)));
|
||||
}
|
||||
return $oContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the context as a hash array 'parameter_name' => value
|
||||
*
|
||||
* @return array The context information
|
||||
*/
|
||||
public function GetAsHash()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -18,7 +18,6 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
|
||||
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
|
||||
@@ -30,7 +29,7 @@ require_once(APPROOT.'application/newsroomprovider.class.inc.php');
|
||||
* You may implement such interfaces in a module file (e.g. main.mymodule.php)
|
||||
*
|
||||
* @api
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @package Extensibility
|
||||
* @since 2.7.0
|
||||
@@ -73,15 +72,14 @@ abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public abstract function ListSupportedLoginModes();
|
||||
abstract public function ListSupportedLoginModes();
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function LoginAction($sLoginState, &$iErrorCode)
|
||||
{
|
||||
switch ($sLoginState)
|
||||
{
|
||||
switch ($sLoginState) {
|
||||
case LoginWebPage::LOGIN_STATE_START:
|
||||
return $this->OnStart($iErrorCode);
|
||||
|
||||
@@ -431,7 +429,7 @@ interface iApplicationUIExtension
|
||||
*
|
||||
* @param DBObjectSet $oSet A set of persistent objects (DBObject)
|
||||
*
|
||||
* @return array
|
||||
* @return string[string]
|
||||
*/
|
||||
public function EnumAllowedActions(DBObjectSet $oSet);
|
||||
}
|
||||
@@ -870,7 +868,7 @@ abstract class ApplicationPopupMenuItem
|
||||
class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
/** @ignore */
|
||||
protected $sUrl;
|
||||
protected $sURL;
|
||||
/** @ignore */
|
||||
protected $sTarget;
|
||||
|
||||
@@ -879,32 +877,20 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
*
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param string $sUrl If the menu is an hyperlink, provide the absolute hyperlink here
|
||||
* @param string $sURL If the menu is an hyperlink, provide the absolute hyperlink here
|
||||
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
|
||||
*/
|
||||
public function __construct($sUID, $sLabel, $sUrl, $sTarget = '_top')
|
||||
public function __construct($sUID, $sLabel, $sURL, $sTarget = '_top')
|
||||
{
|
||||
parent::__construct($sUID, $sLabel);
|
||||
$this->sUrl = $sUrl;
|
||||
$this->sURL = $sURL;
|
||||
$this->sTarget = $sTarget;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetMenuItem()
|
||||
{
|
||||
return array('label' => $this->GetLabel(), 'url' => $this->GetUrl(), 'target' => $this-> GetTarget(), 'css_classes' => $this->aCssClasses);
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetUrl()
|
||||
{
|
||||
return $this->sUrl;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetTarget()
|
||||
{
|
||||
return $this->sTarget;
|
||||
return array('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget, 'css_classes' => $this->aCssClasses);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,9 +904,7 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
/** @ignore */
|
||||
protected $sJsCode;
|
||||
/** @ignore */
|
||||
protected $sUrl;
|
||||
protected $sJSCode;
|
||||
/** @ignore */
|
||||
protected $aIncludeJSFiles;
|
||||
|
||||
@@ -938,8 +922,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
|
||||
{
|
||||
parent::__construct($sUID, $sLabel);
|
||||
$this->sJsCode = $sJSCode;
|
||||
$this->sUrl = '#';
|
||||
$this->sJSCode = $sJSCode;
|
||||
$this->aIncludeJSFiles = $aIncludeJSFiles;
|
||||
}
|
||||
|
||||
@@ -949,9 +932,9 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
// Note: the semicolumn is a must here!
|
||||
return array(
|
||||
'label' => $this->GetLabel(),
|
||||
'onclick' => $this->GetJsCode().'; return false;',
|
||||
'url' => $this->GetUrl(),
|
||||
'css_classes' => $this->GetCssClasses(),
|
||||
'onclick' => $this->sJSCode.'; return false;',
|
||||
'url' => '#',
|
||||
'css_classes' => $this->aCssClasses,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -960,18 +943,6 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
return $this->aIncludeJSFiles;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetJsCode()
|
||||
{
|
||||
return $this->sJsCode;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
public function GetUrl()
|
||||
{
|
||||
return $this->sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1043,12 +1014,11 @@ class JSButtonItem extends JSPopupMenuItem
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 2.0
|
||||
* @deprecated since 3.0.0 use iPageUIBlockExtension instead
|
||||
*/
|
||||
interface iPageUIExtension
|
||||
{
|
||||
/**
|
||||
* Add content to the header of the page
|
||||
* Add content to the North pane
|
||||
*
|
||||
* @param iTopWebPage $oPage The page to insert stuff into.
|
||||
*
|
||||
@@ -1057,7 +1027,7 @@ interface iPageUIExtension
|
||||
public function GetNorthPaneHtml(iTopWebPage $oPage);
|
||||
|
||||
/**
|
||||
* Add content to the footer of the page
|
||||
* Add content to the South pane
|
||||
*
|
||||
* @param iTopWebPage $oPage The page to insert stuff into.
|
||||
*
|
||||
@@ -1075,56 +1045,12 @@ interface iPageUIExtension
|
||||
public function GetBannerHtml(iTopWebPage $oPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this interface to add content to any iTopWebPage
|
||||
*
|
||||
* There are 3 places where content can be added:
|
||||
*
|
||||
* * The north pane: (normaly empty/hidden) at the top of the page, spanning the whole
|
||||
* width of the page
|
||||
* * The south pane: (normaly empty/hidden) at the bottom of the page, spanning the whole
|
||||
* width of the page
|
||||
* * The admin banner (two tones gray background) at the left of the global search.
|
||||
* Limited space, use it for short messages
|
||||
*
|
||||
* Each of the methods of this interface is supposed to return the HTML to be inserted at
|
||||
* the specified place and can use the passed iTopWebPage object to add javascript or CSS definitions
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iPageUIBlockExtension
|
||||
{
|
||||
/**
|
||||
* Add content to the "admin banner"
|
||||
*
|
||||
* @return iUIBlock|null The Block to add into the page
|
||||
*/
|
||||
public function GetBannerBlock();
|
||||
|
||||
/**
|
||||
* Add content to the header of the page
|
||||
*
|
||||
* @return iUIBlock|null The Block to add into the page
|
||||
*/
|
||||
public function GetHeaderBlock();
|
||||
|
||||
/**
|
||||
* Add content to the footer of the page
|
||||
*
|
||||
* @return iUIBlock|null The Block to add into the page
|
||||
*/
|
||||
public function GetFooterBlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 2.7.0
|
||||
* @deprecated since 3.0.0 use AbstractPageUIBlockExtension instead
|
||||
*/
|
||||
abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
{
|
||||
@@ -1154,40 +1080,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
|
||||
*
|
||||
* @api
|
||||
* @package Extensibility
|
||||
* @since 3.0.0
|
||||
*/
|
||||
abstract class AbstractPageUIBlockExtension implements iPageUIBlockExtension
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetBannerBlock()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetHeaderBlock()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetFooterBlock()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this interface to add content to any enhanced portal page
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -22,7 +22,7 @@
|
||||
* to check and is linked to a set of rules that determine the valid or invalid objects
|
||||
* inside the set
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -23,7 +23,7 @@
|
||||
* or the "bad" ones. The core audit engines computes the complement to the definition
|
||||
* set when needed to obtain either the valid objects, or the ones with an error
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -43,6 +43,7 @@ class AuditRule extends cmdbAbstractObject
|
||||
"db_table" => "priv_auditrule",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
@@ -1,7 +1,84 @@
|
||||
<?php
|
||||
// Copyright (C) 2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CaptureWebPage.php
|
||||
* Adapter class: when an API requires WebPage and you want to produce something else
|
||||
*
|
||||
* @copyright Copyright (C) 2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class CaptureWebPage extends WebPage
|
||||
{
|
||||
protected $aReadyScripts;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct('capture web page');
|
||||
$this->aReadyScripts = array();
|
||||
}
|
||||
|
||||
public function GetHtml()
|
||||
{
|
||||
$trash = $this->ob_get_clean_safe();
|
||||
return $this->s_content;
|
||||
}
|
||||
|
||||
public function GetJS()
|
||||
{
|
||||
$sRet = implode("\n", $this->a_scripts);
|
||||
if (!empty($this->s_deferred_content))
|
||||
{
|
||||
$sRet .= "\n\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');";
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetReadyJS()
|
||||
{
|
||||
return "\$(document).ready(function() {\n".implode("\n", $this->aReadyScripts)."\n});";
|
||||
}
|
||||
|
||||
public function GetCSS()
|
||||
{
|
||||
return $this->a_styles;
|
||||
}
|
||||
|
||||
public function GetJSFiles()
|
||||
{
|
||||
return $this->a_linked_scripts;
|
||||
}
|
||||
|
||||
public function GetCSSFiles()
|
||||
{
|
||||
return $this->a_linked_stylesheets;
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
throw new Exception(__method__.' should not be called');
|
||||
}
|
||||
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->aReadyScripts[] = $sScript;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,97 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CLIPage.php
|
||||
* CLI page
|
||||
* The page adds the content-type text/XML and the encoding into the headers
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class CLIPage implements Page
|
||||
{
|
||||
function __construct($s_title)
|
||||
{
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
{
|
||||
echo $sText;
|
||||
}
|
||||
|
||||
public function p($sText)
|
||||
{
|
||||
echo $sText."\n";
|
||||
}
|
||||
|
||||
public function pre($sText)
|
||||
{
|
||||
echo $sText."\n";
|
||||
}
|
||||
|
||||
public function add_comment($sText)
|
||||
{
|
||||
echo "#".$sText."\n";
|
||||
}
|
||||
|
||||
public function table($aConfig, $aData, $aParams = array())
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aDef)
|
||||
{
|
||||
if (strlen($aDef['description']) > 0)
|
||||
{
|
||||
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCells[] = $aDef['label'];
|
||||
}
|
||||
}
|
||||
echo implode(';', $aCells)."\n";
|
||||
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$sValue = $aRow["$sName"];
|
||||
$aCells[] = $sValue;
|
||||
}
|
||||
echo implode(';', $aCells)."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class CompileCSSService : used to ease testing ThemeHander class via mocks
|
||||
*
|
||||
* @author Olivier DAIN <olivier.dain@combodo.com>
|
||||
* @since 3.0.0 N°2982
|
||||
*/
|
||||
class CompileCSSService
|
||||
{
|
||||
/**
|
||||
* CompileCSSService constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
|
||||
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,111 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CSVPage.php
|
||||
* Simple web page with no includes or fancy formatting, useful to generateXML documents
|
||||
* The page adds the content-type text/XML and the encoding into the headers
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class CSVPage extends WebPage
|
||||
{
|
||||
function __construct($s_title) {
|
||||
parent::__construct($s_title);
|
||||
$this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET);
|
||||
$this->no_cache();
|
||||
$this->add_xframe_options();
|
||||
//$this->add_header("Content-Transfer-Encoding: binary");
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
|
||||
|
||||
// Get the unexpected output but do nothing with it
|
||||
$sTrash = $this->ob_get_clean_safe();
|
||||
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
echo trim($this->s_content);
|
||||
echo "\n";
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
|
||||
public function small_p($sText)
|
||||
{
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
{
|
||||
$this->s_content .= $sText;
|
||||
}
|
||||
|
||||
public function p($sText)
|
||||
{
|
||||
$this->s_content .= $sText."\n";
|
||||
}
|
||||
|
||||
public function add_comment($sText)
|
||||
{
|
||||
$this->s_content .= "#".$sText."\n";
|
||||
}
|
||||
|
||||
public function table($aConfig, $aData, $aParams = array())
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aDef)
|
||||
{
|
||||
if (strlen($aDef['description']) > 0)
|
||||
{
|
||||
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCells[] = $aDef['label'];
|
||||
}
|
||||
}
|
||||
$this->s_content .= implode(';', $aCells)."\n";
|
||||
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
$aCells = array();
|
||||
foreach($aConfig as $sName=>$aAttribs)
|
||||
{
|
||||
$sValue = $aRow["$sName"];
|
||||
$aCells[] = $sValue;
|
||||
}
|
||||
$this->s_content .= implode(';', $aCells)."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
/**
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
|
||||
|
||||
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
|
||||
require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
@@ -430,19 +438,22 @@ abstract class Dashboard
|
||||
public function RenderProperties($oPage, $aExtraParams = array())
|
||||
{
|
||||
// menu to pick a layout and edit other properties of the dashboard
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
$oPage->add('<div class="ibo-dashboard-editor--properties-subtitle" data-role="ibo-dashboard-editor--properties-subtitle">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
|
||||
$oPage->add('<div id="select_layout" class="ibo-dashboard-editor--layout-list" data-role="ibo-dashboard-editor--layout-list">');
|
||||
foreach (get_declared_classes() as $sLayoutClass) {
|
||||
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
|
||||
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
|
||||
$oPage->add('<div id="select_layout" style="text-align:center">');
|
||||
foreach( get_declared_classes() as $sLayoutClass)
|
||||
{
|
||||
if (is_subclass_of($sLayoutClass, 'DashboardLayout'))
|
||||
{
|
||||
$oReflection = new ReflectionClass($sLayoutClass);
|
||||
if (!$oReflection->isAbstract()) {
|
||||
if (!$oReflection->isAbstract())
|
||||
{
|
||||
$aCallSpec = array($sLayoutClass, 'GetInfo');
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
|
||||
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing !
|
||||
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" /></label>'); // title="" on either the img or the label does nothing !
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -473,15 +484,14 @@ abstract class Dashboard
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
|
||||
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
$('#select_layout').controlgroup();
|
||||
$('#select_layout').buttonset();
|
||||
$('#select_dashlet').droppable({
|
||||
accept: '.dashlet',
|
||||
drop: function(event, ui) {
|
||||
@@ -491,7 +501,7 @@ abstract class Dashboard
|
||||
},
|
||||
});
|
||||
|
||||
$('#event_bus').on('dashlet-selected', function(event, data){
|
||||
$('#event_bus').bind('dashlet-selected', function(event, data){
|
||||
var sDashletId = data.dashlet_id;
|
||||
var sPropId = 'dashlet_properties_'+sDashletId;
|
||||
$('.dashlet_properties').each(function() {
|
||||
@@ -516,55 +526,34 @@ EOF
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
* @param bool $bCanEdit
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
if (!array_key_exists('dashboard_div_id', $aExtraParams)) {
|
||||
if (!array_key_exists('dashboard_div_id', $aExtraParams))
|
||||
{
|
||||
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
|
||||
}
|
||||
|
||||
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
|
||||
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
foreach ($this->aCells as $iCellIdx => $aDashlets) {
|
||||
foreach ($aDashlets as $oDashlet) {
|
||||
foreach($this->aCells as $iCellIdx => $aDashlets)
|
||||
{
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
$aDashletCoordinates = $oLayout->GetDashletCoordinates($iCellIdx);
|
||||
$this->PrepareDashletForRendering($oDashlet, $aDashletCoordinates, $aExtraParams);
|
||||
}
|
||||
}
|
||||
|
||||
$oDashboard = $oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
$oPage->AddUiBlock($oDashboard);
|
||||
|
||||
$bFromDasboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
|
||||
|
||||
if ($bFromDasboardPage) {
|
||||
$sTitleForHTML = utils::HtmlEntities(Dict::S($this->sTitle));
|
||||
$sHtml = "<div class=\"ibo-top-bar--toolbar-dashboard-title\">{$sTitleForHTML}</div>";
|
||||
if ($oPage instanceof iTopWebPage) {
|
||||
$oTopBar = $oPage->GetTopBarLayout();
|
||||
$oToolbar = ToolbarUIBlockFactory::MakeStandard();
|
||||
$oTopBar->SetToolbar($oToolbar);
|
||||
|
||||
$oToolbar->AddHtml($sHtml);
|
||||
} else {
|
||||
$oPage->add_script(<<<JS
|
||||
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML");
|
||||
JS
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$oDashboard->SetTitle(Dict::S($this->sTitle));
|
||||
}
|
||||
|
||||
if (!$bEditMode) {
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
}
|
||||
|
||||
return $oDashboard;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -576,18 +565,19 @@ JS
|
||||
public function RenderDashletsSelection(WebPage $oPage)
|
||||
{
|
||||
// Toolbox/palette to drag and drop dashlets
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard--available-dashlets"><div class="ui-widget-header ui-corner-all ibo-dashboard--available-dashlet--title">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
$oPage->add('<div id="select_dashlet" class="ibo-dashboard--available-dashlets--list" data-role="ibo-dashboard--available-dashlets--list">');
|
||||
$oPage->add('<div id="select_dashlet" style="text-align:center; max-height:120px; overflow-y:auto;">');
|
||||
$aAvailableDashlets = $this->GetAvailableDashlets();
|
||||
foreach ($aAvailableDashlets as $sDashletClass => $aInfo) {
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
foreach($aAvailableDashlets as $sDashletClass => $aInfo)
|
||||
{
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({cursor: 'move', helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -597,12 +587,12 @@ JS
|
||||
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
// Toolbox/palette to edit the properties of each dashlet
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
$oPage->add('<div id="dashlet_properties">');
|
||||
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
|
||||
foreach($this->aCells as $iCellIdx => $aCell)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
@@ -635,13 +625,16 @@ JS
|
||||
|
||||
foreach( get_declared_classes() as $sDashletClass)
|
||||
{
|
||||
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy'))) {
|
||||
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instanciated.
|
||||
if ( is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy')) )
|
||||
{
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract()) {
|
||||
if (!$oReflection->isAbstract())
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'IsVisible');
|
||||
$bVisible = call_user_func($aCallSpec);
|
||||
if ($bVisible) {
|
||||
if ($bVisible)
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$aDashlets[$sDashletClass] = $aInfo;
|
||||
@@ -889,53 +882,11 @@ class RuntimeDashboard extends Dashboard
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFile);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDashboard = null;
|
||||
}
|
||||
|
||||
return $oDashboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDashboardFile file name relative to the current module folder
|
||||
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
|
||||
*
|
||||
* @return null|RuntimeDashboard
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetDashboardToEdit($sDashboardFile, $sDashBoardId)
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0) {
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
}
|
||||
|
||||
|
||||
if ($sDashboardDefinition !== false) {
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFile);
|
||||
} else {
|
||||
$oDashboard = null;
|
||||
}
|
||||
|
||||
return $oDashboard;
|
||||
}
|
||||
|
||||
@@ -945,33 +896,40 @@ class RuntimeDashboard extends Dashboard
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
|
||||
{
|
||||
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) {
|
||||
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
|
||||
$oDashboard = parent::Render($oPage, $bEditMode, $aRenderParams);
|
||||
parent::Render($oPage, $bEditMode, $aRenderParams);
|
||||
|
||||
if (isset($aExtraParams['query_params']['this->object()'])) {
|
||||
if (isset($aExtraParams['query_params']['this->object()']))
|
||||
{
|
||||
/** @var \DBObject $oObj */
|
||||
$oObj = $aExtraParams['query_params']['this->object()'];
|
||||
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
|
||||
if (isset($aExtraParams['from_dashboard_page'])) {
|
||||
$aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page'];
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAjaxParams = $aExtraParams;
|
||||
}
|
||||
if (!$bEditMode && !$oPage->IsPrintableVersion()) {
|
||||
if (!$bEditMode && !$oPage->IsPrintableVersion())
|
||||
{
|
||||
$sId = $this->GetId();
|
||||
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
|
||||
if ($this->GetAutoReload()) {
|
||||
if ($this->GetAutoReload())
|
||||
{
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
|
||||
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
{
|
||||
clearInterval(AutoReloadDashboardId$sDivId);
|
||||
@@ -983,18 +941,25 @@ class RuntimeDashboard extends Dashboard
|
||||
function ReloadDashboard$sDivId()
|
||||
{
|
||||
// Do not reload when a dialog box is active
|
||||
if (!($('.ui-dialog:visible').length > 0) && $('.ibo-dashboard#$sDivId').is(':visible'))
|
||||
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
|
||||
{
|
||||
updateDashboard$sDivId();
|
||||
$('.dashboard_contents#$sDivId').block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
|
||||
function(data){
|
||||
$('.dashboard_contents#$sDivId').html(data);
|
||||
$('.dashboard_contents#$sDivId').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
JS
|
||||
EOF
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
|
||||
{
|
||||
clearInterval(AutoReloadDashboardId$sDivId);
|
||||
@@ -1004,75 +969,60 @@ EOF
|
||||
);
|
||||
}
|
||||
|
||||
if ($bCanEdit) {
|
||||
$this->RenderSelector($oPage, $oDashboard, $aAjaxParams);
|
||||
$this->RenderEditionTools($oPage, $oDashboard, $aAjaxParams);
|
||||
if ($bCanEdit)
|
||||
{
|
||||
$this->RenderSelector($oPage, $aAjaxParams);
|
||||
$this->RenderEditionTools($oPage, $aAjaxParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout $oDashboard
|
||||
* @param bool $bFromDashboardPage
|
||||
* @param \iTopWebPage $oPage
|
||||
* @param array $aAjaxParams
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = array())
|
||||
protected function RenderSelector($oPage, $aAjaxParams = array())
|
||||
{
|
||||
if (!$this->HasCustomDashboard()) {
|
||||
return;
|
||||
}
|
||||
$sId = $this->GetId();
|
||||
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
|
||||
$sExtraParams = json_encode($aAjaxParams);
|
||||
|
||||
$sSwitchToStandard = Dict::S('UI:Toggle:SwitchToStandardDashboard');
|
||||
$sSwitchToCustom = Dict::S('UI:Toggle:SwitchToCustomDashboard');
|
||||
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
|
||||
$sSelectorHtml = '<div class="dashboard-selector">';
|
||||
if ($this->HasCustomDashboard())
|
||||
{
|
||||
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
|
||||
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
|
||||
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
|
||||
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
|
||||
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
|
||||
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
|
||||
|
||||
$sSelectorHtml = '<div id="ibo-dashboard-selector'.$sDivId.'" class="ibo-dashboard--selector" data-tooltip-content="'.($bStandardSelected ? $sSwitchToCustom : $sSwitchToStandard).'">';
|
||||
$sSelectorHtml .= '<label class="ibo-dashboard--switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="ibo-dashboard--slider"></span></label></input></label>';
|
||||
}
|
||||
$sSelectorHtml .= '</div>';
|
||||
|
||||
$sSelectorHtml = addslashes($sSelectorHtml);
|
||||
$sFile = addslashes($this->GetDefinitionFile());
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
$bFromDashboardPage = isset($aAjaxParams['from_dashboard_page']) ? isset($aAjaxParams['from_dashboard_page']) : false;
|
||||
if ($bFromDashboardPage) {
|
||||
if ($oPage instanceof iTopWebPage) {
|
||||
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
|
||||
$oToolbar->AddHtml($sSelectorHtml);
|
||||
}
|
||||
} else {
|
||||
$oToolbar = $oDashboard->GetToolbar();
|
||||
$oToolbar->AddHtml($sSelectorHtml);
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('.dashboard-title').after('$sSelectorHtml');
|
||||
EOF
|
||||
);
|
||||
|
||||
$oPage->add_script(
|
||||
<<<JS
|
||||
<<<EOF
|
||||
function ToggleDashboardSelector$sDivId()
|
||||
{
|
||||
var dashboard = $('.ibo-dashboard#$sDivId')
|
||||
dashboard.block();
|
||||
$('.dashboard_contents#$sDivId').block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
|
||||
function(data) {
|
||||
dashboard.html(data);
|
||||
dashboard.unblock();
|
||||
if ($('#ibo-dashboard-selector$sDivId input').prop("checked")) {
|
||||
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToStandard');
|
||||
} else {
|
||||
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToCustom');
|
||||
}
|
||||
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent());
|
||||
$('.dashboard_contents#$sDivId').html(data);
|
||||
$('.dashboard_contents#$sDivId').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
JS
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1103,58 +1053,45 @@ JS
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function RenderEditionTools(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aExtraParams)
|
||||
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
|
||||
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
|
||||
|
||||
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
|
||||
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
|
||||
$sName = 'UI:Dashboard:Actions';
|
||||
|
||||
$bFromDashboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
|
||||
if ($bFromDashboardPage) {
|
||||
if (!($oPage instanceof iTopWebPage)) {
|
||||
// TODO 3.0 change the menu
|
||||
return;
|
||||
}
|
||||
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
|
||||
} else {
|
||||
$oToolbar = $oDashboard->GetToolbar();
|
||||
}
|
||||
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sMenuTogglerId)
|
||||
->AddCSSClass('ibo-top-bar--toolbar-dashboard-menu-toggler')
|
||||
->AddCSSClass('ibo-action-button');
|
||||
|
||||
$oToolbar->AddSubBlock($oActionButton);
|
||||
|
||||
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
|
||||
|
||||
$aActions = array();
|
||||
$sFile = addslashes($this->sDefinitionFile);
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
if ($this->HasCustomDashboard()) {
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:DeleteCustom'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
} else {
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
$bCanEdit = true;
|
||||
if ($this->HasCustomDashboard())
|
||||
{
|
||||
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
|
||||
}
|
||||
if ($bCanEdit)
|
||||
{
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
}
|
||||
|
||||
|
||||
if ($this->bCustomized)
|
||||
{
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
}
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
|
||||
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
|
||||
->SetTogglerJSSelector("#$sMenuTogglerId");
|
||||
|
||||
$oToolbar->AddSubBlock($oActionButton)
|
||||
->AddSubBlock($oActionsMenu);
|
||||
|
||||
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
|
||||
$sEditMenu = addslashes($sEditMenu);
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('.dashboard-title').after('$sEditMenu');
|
||||
$('#DashboardMenu>ul').popupmenu();
|
||||
|
||||
EOF
|
||||
);
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
function EditDashboard(sId, sDashboardFile, aExtraParams)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
|
||||
@@ -1188,7 +1125,7 @@ EOF
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#select_layout input').on('click', function() {
|
||||
$('#select_layout input').click( function() {
|
||||
var sLayoutClass = $(this).val();
|
||||
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
|
||||
} );
|
||||
@@ -1227,27 +1164,30 @@ EOF
|
||||
*/
|
||||
public function RenderEditor($oPage, $aExtraParams = array())
|
||||
{
|
||||
if (isset($aExtraParams['this->class'])) {
|
||||
if (isset($aExtraParams['this->class']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRenderParams = $aExtraParams;
|
||||
}
|
||||
$aRenderParams['dashboard_div_id'] = $aExtraParams['dashboard_div_id'];
|
||||
$sJSExtraParams = json_encode($aExtraParams);
|
||||
$oPage->add('<div id="dashboard_editor" class="ibo-dashboard-editor" data-role="ibo-dashboard-editor">');
|
||||
$oPage->add('<div id="dashboard_editor">');
|
||||
$oPage->add('<div class="ui-layout-center">');
|
||||
$this->SetCustomFlag(true);
|
||||
$this->Render($oPage, true, $aRenderParams);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div class="ui-layout-east ibo-dashboard-editor--pane" data-role="ibo-dashboard-editor--pane">');
|
||||
$oPage->add('<div class="ui-layout-east">');
|
||||
$this->RenderProperties($oPage, $aExtraParams);
|
||||
$this->RenderDashletsSelection($oPage);
|
||||
$this->RenderDashletsProperties($oPage, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
|
||||
$oPage->add('</div>');
|
||||
|
||||
|
||||
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
@@ -1275,24 +1215,7 @@ $('#dashboard_editor').dialog({
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sCancelButtonLabel",
|
||||
class: "ibo-is-alternative",
|
||||
click: function() {
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
if (oDashboard.is_modified())
|
||||
{
|
||||
if (!confirm('$sCancelConfirmationMessage'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
window.bLeavingOnUserAction = true;
|
||||
$(this).dialog( "close" );
|
||||
$(this).remove();
|
||||
} },
|
||||
{ text: "$sOkButtonLabel",
|
||||
class: "ibo-is-primary",
|
||||
click: function() {
|
||||
{ text: "$sOkButtonLabel", click: function() {
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
if (oDashboard.is_dirty())
|
||||
{
|
||||
@@ -1308,6 +1231,19 @@ $('#dashboard_editor').dialog({
|
||||
window.bLeavingOnUserAction = true;
|
||||
oDashboard.save($(this));
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
if (oDashboard.is_modified())
|
||||
{
|
||||
if (!confirm('$sCancelConfirmationMessage'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
window.bLeavingOnUserAction = true;
|
||||
$(this).dialog( "close" );
|
||||
$(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
@@ -1325,16 +1261,20 @@ $('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
var dashboard_prop_size = GetUserPreference('dashboard_prop_size', 400);
|
||||
$('#dashboard_editor > .itop-dashboard').width($('#dashboard_editor').width() - dashboard_prop_size);
|
||||
|
||||
// We check when we finish click on the pane with the resize slider
|
||||
// if the pane size changed (% 5px), if it's the case we save the value in userpref
|
||||
$('#dashboard_editor > .itop-dashboard').on('mouseup',function (){
|
||||
var iWidthDiff = $(this).width() - ($('#dashboard_editor').width() - dashboard_prop_size);
|
||||
if( Math.abs(iWidthDiff) > 5){
|
||||
dashboard_prop_size = iWidthDiff;
|
||||
SetUserPreference('dashboard_prop_size', $('#dashboard_editor').width() - $(this).width(), true);
|
||||
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
|
||||
$('#dashboard_editor').layout({
|
||||
east: {
|
||||
minSize: 200,
|
||||
size: dashboard_prop_size,
|
||||
togglerLength_open: 0,
|
||||
togglerLength_closed: 0,
|
||||
onresize_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('dashboard_prop_size', state.size, true);
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1496,37 +1436,32 @@ JS
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
<<<JS
|
||||
$('#dashlet_creation_dlg').dialog({
|
||||
width: 600,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sCancelButtonLabel",
|
||||
click: function() {
|
||||
{ text: "$sOkButtonLabel", click: function() {
|
||||
var oForm = $(this).find('form');
|
||||
var sFormId = oForm.attr('id');
|
||||
var oParams = null;
|
||||
var aErrors = ValidateForm(sFormId, false);
|
||||
if (aErrors.length == 0)
|
||||
{
|
||||
oParams = ReadFormParams(sFormId);
|
||||
}
|
||||
oParams.operation = 'add_dashlet';
|
||||
var me = $(this);
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
|
||||
me.dialog( "close" );
|
||||
me.remove();
|
||||
$('body').append(data);
|
||||
});
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} ,
|
||||
'class': 'ibo-button ibo-is-alternative ibo-is-neutral action cancel'
|
||||
},
|
||||
{ text: "$sOkButtonLabel",
|
||||
click: function() {
|
||||
var oForm = $(this).find('form');
|
||||
var sFormId = oForm.attr('id');
|
||||
var oParams = null;
|
||||
var aErrors = ValidateForm(sFormId, false);
|
||||
if (aErrors.length == 0)
|
||||
{
|
||||
oParams = ReadFormParams(sFormId);
|
||||
}
|
||||
oParams.operation = 'add_dashlet';
|
||||
var me = $(this);
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
|
||||
me.dialog( "close" );
|
||||
me.remove();
|
||||
$('body').append(data);
|
||||
});
|
||||
},
|
||||
'class': 'ibo-button ibo-is-regular ibo-is-primary action' }
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
@@ -1640,10 +1575,12 @@ JS
|
||||
{
|
||||
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
|
||||
$aClassAliases = array();
|
||||
try {
|
||||
try{
|
||||
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
|
||||
$aClassAliases = $oFilter->GetSelectedClasses();
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
//on error, return default value
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -15,17 +15,15 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardColumn;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardRow;
|
||||
|
||||
/**
|
||||
* Dashboard presentation
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
abstract class DashboardLayout
|
||||
{
|
||||
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
|
||||
@@ -116,59 +114,61 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||
$aCells = $this->TrimCellsArray($aCells);
|
||||
|
||||
$oDashboardLayout = new DashboardLayoutUIBlock();
|
||||
//$oPage->AddUiBlock($oDashboardLayout);
|
||||
|
||||
$oPage->add('<table style="width:100%;table-layout:fixed;"><tbody>');
|
||||
$iCellIdx = 0;
|
||||
$fColSize = 100 / $this->iNbCols;
|
||||
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
|
||||
$sClass = $bEditMode ? 'layout_cell edit_mode' : 'dashboard';
|
||||
$iNbRows = ceil(count($aCells) / $this->iNbCols);
|
||||
|
||||
//Js given by each dashlet to reload
|
||||
$sJSReload = "";
|
||||
|
||||
for ($iRows = 0; $iRows < $iNbRows; $iRows++) {
|
||||
$oDashboardRow = new DashboardRow();
|
||||
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||
|
||||
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
|
||||
$oDashboardColumn = new DashboardColumn($bEditMode);
|
||||
$oDashboardColumn->SetCellIndex($iCellIdx);
|
||||
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
|
||||
|
||||
if (array_key_exists($iCellIdx, $aCells)) {
|
||||
for($iRows = 0; $iRows < $iNbRows; $iRows++)
|
||||
{
|
||||
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$sCellClass = ($iRows == $iNbRows-1) ? $sClass.' layout_last_used_rank' : $sClass;
|
||||
$oPage->add("<td style=\"$sStyle\" class=\"$sCellClass\" data-dashboard-column-index=\"$iCols\" data-dashboard-cell-index=\"$iCellIdx\">");
|
||||
if (array_key_exists($iCellIdx, $aCells))
|
||||
{
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
if (count($aDashlets) > 0) {
|
||||
if (count($aDashlets) > 0)
|
||||
{
|
||||
/** @var \Dashlet $oDashlet */
|
||||
foreach ($aDashlets as $oDashlet) {
|
||||
if ($oDashlet::IsVisible()) {
|
||||
$oDashboardColumn->AddUIBlock($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams));
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
if ($oDashlet::IsVisible())
|
||||
{
|
||||
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$oDashboardColumn->AddUIBlock(new Html(' '));
|
||||
}
|
||||
} else {
|
||||
$oDashboardColumn->AddUIBlock(new Html(' '));
|
||||
else
|
||||
{
|
||||
$oPage->add(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add(' ');
|
||||
}
|
||||
$oPage->add('</td>');
|
||||
$iCellIdx++;
|
||||
}
|
||||
$sJSReload .= $oDashboardRow->GetJSRefreshCallback()." ";
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
|
||||
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
|
||||
|
||||
if ($bEditMode) // Add one row for extensibility
|
||||
{
|
||||
$oDashboardRow = new DashboardRow();
|
||||
$oDashboardLayout->AddDashboardRow($oDashboardRow);
|
||||
|
||||
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
|
||||
$oDashboardColumn = new DashboardColumn($bEditMode, true);
|
||||
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
|
||||
$oDashboardColumn->AddUIBlock(new Html(' '));
|
||||
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"';
|
||||
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$oPage->add("<td $sStyle data-dashboard-column-index=\"$iCols\">");
|
||||
$oPage->add(' ');
|
||||
$oPage->add('</td>');
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
|
||||
return $oDashboardLayout;
|
||||
$oPage->add('</tbody></table>');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2012-2021 Combodo SARL
|
||||
// Copyright (C) 2012-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -16,19 +16,12 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Dashlet\DashletContainer;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Dashlet\DashletFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
|
||||
require_once(APPROOT.'application/forms.class.inc.php');
|
||||
|
||||
/**
|
||||
* Base class for all 'dashlets' (i.e. widgets to be inserted into a dashboard)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
abstract class Dashlet
|
||||
@@ -57,7 +50,7 @@ abstract class Dashlet
|
||||
$this->bRedrawNeeded = true; // By default: redraw each time a property changes
|
||||
$this->bFormRedrawNeeded = false; // By default: no need to redraw the form (independent fields)
|
||||
$this->aProperties = array(); // By default: there is no property
|
||||
$this->aCSSClasses = array('ibo-dashlet');
|
||||
$this->aCSSClasses = array('dashlet');
|
||||
$this->sDashletType = get_class($this);
|
||||
}
|
||||
|
||||
@@ -73,17 +66,21 @@ abstract class Dashlet
|
||||
{
|
||||
$refValue = $this->aProperties[$sProperty];
|
||||
$sRefType = gettype($refValue);
|
||||
|
||||
if (gettype($sValue) == $sRefType) {
|
||||
if (gettype($sValue) == $sRefType)
|
||||
{
|
||||
// Do not change anything in that case!
|
||||
$ret = $sValue;
|
||||
} elseif ($sRefType == 'boolean') {
|
||||
}
|
||||
elseif ($sRefType == 'boolean')
|
||||
{
|
||||
$ret = ($sValue == 'true');
|
||||
} elseif ($sRefType == 'array') {
|
||||
}
|
||||
elseif ($sRefType == 'array')
|
||||
{
|
||||
$ret = explode(',', $sValue);
|
||||
} elseif (is_array($sValue)) {
|
||||
$ret = $sValue;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = $sValue;
|
||||
settype($ret, $sRefType);
|
||||
}
|
||||
@@ -194,8 +191,10 @@ abstract class Dashlet
|
||||
*/
|
||||
public function FromParams($aParams)
|
||||
{
|
||||
foreach ($this->aProperties as $sProperty => $value) {
|
||||
if (array_key_exists($sProperty, $aParams)) {
|
||||
foreach ($this->aProperties as $sProperty => $value)
|
||||
{
|
||||
if (array_key_exists($sProperty, $aParams))
|
||||
{
|
||||
$this->aProperties[$sProperty] = $aParams[$sProperty];
|
||||
}
|
||||
}
|
||||
@@ -208,55 +207,79 @@ abstract class Dashlet
|
||||
* @param bool $bEnclosingDiv
|
||||
* @param array $aExtraParams
|
||||
*/
|
||||
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array()): UIBlock
|
||||
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array())
|
||||
{
|
||||
$sCSSClasses = implode(' ', $this->aCSSClasses);
|
||||
$sId = $this->GetID();
|
||||
|
||||
if ($bEnclosingDiv) {
|
||||
if ($bEditMode) {
|
||||
$oDashletContainer = new DashletContainer("dashlet_{$sId}");
|
||||
} else {
|
||||
$oDashletContainer = new DashletContainer();
|
||||
if ($bEnclosingDiv)
|
||||
{
|
||||
if ($bEditMode)
|
||||
{
|
||||
$oPage->add('<div class="'.$sCSSClasses.'" id="dashlet_'.$sId.'">');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add('<div class="'.$sCSSClasses.'">');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($this->aCSSClasses as $sCSSClass)
|
||||
{
|
||||
$oPage->add_ready_script("$('#dashlet_".$sId."').addClass('$sCSSClass');");
|
||||
}
|
||||
$oDashletContainer->AddCSSClasses($this->aCSSClasses);
|
||||
} else {
|
||||
$oDashletContainer = new DashletContainer();
|
||||
$oDashletContainer->AddCSSClasses($this->aCSSClasses);
|
||||
}
|
||||
|
||||
try {
|
||||
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime') {
|
||||
$oBlock = $this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
} else {
|
||||
$oBlock = $this->RenderNoData($oPage, $bEditMode, $aExtraParams);
|
||||
try
|
||||
{
|
||||
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime')
|
||||
{
|
||||
$this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
$oDashletContainer->AddSubBlock($oBlock);
|
||||
} catch (UnknownClassOqlException $e) {
|
||||
else
|
||||
{
|
||||
$this->RenderNoData($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
}
|
||||
catch(UnknownClassOqlException $e)
|
||||
{
|
||||
// Maybe the class is part of a non-installed module, fail silently
|
||||
// Except in Edit mode
|
||||
if ($bEditMode) {
|
||||
$oDashletContainer->AddCSSClass("dashlet-content");
|
||||
$oDashletContainer->AddHtml('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
|
||||
if ($bEditMode)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
} catch (OqlException $e) {
|
||||
$oDashletContainer->AddCSSClass("dashlet-content");
|
||||
$oDashletContainer->AddHtml('<p>'.$e->GetUserFriendlyDescription().'</p>');
|
||||
} catch (Exception $e) {
|
||||
$oDashletContainer->AddCSSClass("dashlet-content");
|
||||
$oDashletContainer->AddHtml('<p>'.$e->getMessage().'</p>');
|
||||
}
|
||||
catch(OqlException $e)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->p($e->GetUserFriendlyDescription());
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->p($e->getMessage());
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
if ($bEditMode) {
|
||||
if ($bEnclosingDiv)
|
||||
{
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
if ($bEditMode)
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
$sType = $this->sDashletType;
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
$('#dashlet_$sId').dashlet({dashlet_id: '$sId', dashlet_class: '$sClass', 'dashlet_type': '$sType'});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
return $oDashletContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,7 +303,7 @@ EOF
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return iUIBlock
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function Render($oPage, $bEditMode = false, $aExtraParams = array());
|
||||
|
||||
@@ -290,12 +313,10 @@ EOF
|
||||
* @param \WebPage $oPage
|
||||
* @param bool $bEditMode
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return iUIBlock
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
return $this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
$this->Render($oPage, $bEditMode, $aExtraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,12 +623,12 @@ class DashletUnknown extends Dashlet
|
||||
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
|
||||
$sExplainText = ($bEditMode) ? Dict::Format('UI:DashletUnknown:RenderText:Edit', $this->GetDashletType()) : Dict::S('UI:DashletUnknown:RenderText:View');
|
||||
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
|
||||
return $oDashletContainer;
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -622,12 +643,12 @@ class DashletUnknown extends Dashlet
|
||||
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
|
||||
$sExplainText = Dict::Format('UI:DashletUnknown:RenderNoDataText:Edit', $this->GetDashletType());
|
||||
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
|
||||
|
||||
return $oDashletContainer;
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -746,9 +767,9 @@ class DashletProxy extends DashletUnknown
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
// This should never be called.
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
$oDashletContainer->AddHtml('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
|
||||
return $oDashletContainer;
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -763,14 +784,12 @@ class DashletProxy extends DashletUnknown
|
||||
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
|
||||
$sExplainText = Dict::Format('UI:DashletProxy:RenderNoDataText:Edit', $this->GetDashletType());
|
||||
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$sHtml = '';
|
||||
$sHtml .= '<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>';
|
||||
$sHtml .= '<div class="dashlet-pxy-text">'.$sExplainText.'</div>';
|
||||
$oPage->add('<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>');
|
||||
$oPage->add('<div class="dashlet-pxy-text">'.$sExplainText.'</div>');
|
||||
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
return $oDashletContainer;
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -801,7 +820,7 @@ class DashletEmptyCell extends Dashlet
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
return new Html(' ');
|
||||
$oPage->add(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -848,13 +867,11 @@ class DashletPlainText extends Dashlet
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sText = $this->aProperties['text'];
|
||||
$sText = utils::EscapeHtml($sText);
|
||||
$sText = utils::HtmlEntities($this->aProperties['text']);
|
||||
$sText = str_replace(array("\r\n", "\n", "\r"), "<br/>", $sText);
|
||||
|
||||
$sId = 'plaintext_'.($bEditMode ? 'edit_' : '').$this->sId;
|
||||
|
||||
return DashletFactory::MakeForDashletPlainText($sText, $sId);
|
||||
$sId = 'plaintext_'.($bEditMode? 'edit_' : '').$this->sId;
|
||||
$oPage->add('<div id="'.$sId.'" class="dashlet-content">'.$sText.'</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -874,7 +891,7 @@ class DashletPlainText extends Dashlet
|
||||
{
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletPlainText:Label'),
|
||||
'icon' => 'images/dashlets/icons8-text-box-48.png',
|
||||
'icon' => 'images/dashlet-text.png',
|
||||
'description' => Dict::S('UI:DashletPlainText:Description'),
|
||||
);
|
||||
}
|
||||
@@ -904,21 +921,42 @@ class DashletObjectList extends Dashlet
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sShowMenu = $this->aProperties['menu'] ? '1' : '0';
|
||||
$oFilter = $this->GetDBSearch($aExtraParams);
|
||||
$sClass = $oFilter->GetClass();
|
||||
$oPanel = PanelUIBlockFactory::MakeForClass($sClass, Dict::S($sTitle))
|
||||
->AddCSSClass('ibo-datatable-panel');
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
$oPage->add('<div class="main_header"><h1> '.$sHtmlTitle.'</h1></div>');
|
||||
}
|
||||
$oFilter = $this->GetDBSearch($aExtraParams);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list');
|
||||
$aParams = array(
|
||||
'menu' => $sShowMenu,
|
||||
'table_id' => self::APPUSERPREFERENCES_PREFIX.$this->sId,
|
||||
'surround_with_panel' => false,
|
||||
);
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
|
||||
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
return $oPanel;
|
||||
public function GetDBSearch($aExtraParams = array())
|
||||
{
|
||||
$sQuery = $this->aProperties['query'];
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
}
|
||||
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
|
||||
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,35 +970,22 @@ class DashletObjectList extends Dashlet
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$sHtmlTitle = utils::HtmlEntities($this->oModelReflection->DictString($sTitle)); // done in the itop block
|
||||
if ($sHtmlTitle != '') {
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
|
||||
}
|
||||
$oQuery = $this->oModelReflection->GetQuery($sQuery);
|
||||
$sClass = $oQuery->GetClass();
|
||||
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
|
||||
$oPage->p(Dict::S('UI:NoObjectToDisplay'));
|
||||
if ($bShowMenu) {
|
||||
if ($bShowMenu)
|
||||
{
|
||||
$oPage->p('<a>'.Dict::Format('UI:ClickToCreateNew', $this->oModelReflection->GetName($sClass)).'</a>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
public function GetDBSearch($aExtraParams = array())
|
||||
{
|
||||
$sQuery = $this->aProperties['query'];
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
} else {
|
||||
$aQueryParams = array();
|
||||
}
|
||||
|
||||
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@@ -984,7 +1009,7 @@ class DashletObjectList extends Dashlet
|
||||
{
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletObjectList:Label'),
|
||||
'icon' => 'images/dashlets/icons8-list-48.png',
|
||||
'icon' => 'images/dashlet-list.png',
|
||||
'description' => Dict::S('UI:DashletObjectList:Description'),
|
||||
);
|
||||
}
|
||||
@@ -1178,81 +1203,93 @@ abstract class DashletGroupBy extends Dashlet
|
||||
$sStyle = $this->aProperties['style'];
|
||||
|
||||
// First perform the query - if the OQL is not ok, it will generate an exception : no need to go further
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
|
||||
}
|
||||
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
|
||||
$sClass = $oFilter->GetClass();
|
||||
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode)) {
|
||||
return new Html('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
|
||||
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode))
|
||||
{
|
||||
$oPage->add('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
|
||||
}
|
||||
else
|
||||
{
|
||||
switch($sStyle)
|
||||
{
|
||||
case 'bars':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'bars',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
|
||||
switch ($sStyle) {
|
||||
case 'bars':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'bars',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
case 'pie':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'pie',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
|
||||
case 'pie':
|
||||
$sType = 'chart';
|
||||
$aParams = array(
|
||||
'chart_type' => 'pie',
|
||||
'chart_title' => $sTitle,
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
$sHtmlTitle = ''; // done in the itop block
|
||||
break;
|
||||
case 'table':
|
||||
default:
|
||||
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
|
||||
$sType = 'count';
|
||||
$aParams = array(
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'table':
|
||||
default:
|
||||
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
|
||||
$sType = 'count';
|
||||
$aParams = array(
|
||||
'group_by' => $this->sGroupByExpr,
|
||||
'group_by_label' => $this->sGroupByLabel,
|
||||
'aggregation_function' => $this->sAggregationFunction,
|
||||
'aggregation_attribute' => $this->sAggregationAttribute,
|
||||
'limit' => $this->sLimit,
|
||||
'order_direction' => $this->sOrderDirection,
|
||||
'order_by' => $this->sOrderBy,
|
||||
);
|
||||
break;
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
if ($sHtmlTitle != '')
|
||||
{
|
||||
$oPage->add('<div class="main_header"><h1> '.$sHtmlTitle.'</h1></div>');
|
||||
}
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock = new DisplayBlock($oFilter, $sType);
|
||||
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
if($bEditMode)
|
||||
{
|
||||
$oPage->add('<div class="dashlet-blocker"></div>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
$oPanel = PanelUIBlockFactory::MakeForClass($sClass, Dict::S($sTitle));
|
||||
|
||||
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
|
||||
$oBlock = new DisplayBlock($oFilter, $sType);
|
||||
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
if ($bEditMode) {
|
||||
$oPanel->AddHtml('<div class="dashlet-blocker"></div>');
|
||||
}
|
||||
return $oPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1335,9 +1372,9 @@ abstract class DashletGroupBy extends Dashlet
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
$oDashletContainer->AddHtml('error!');
|
||||
return $oDashletContainer;
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('error!');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1584,7 +1621,7 @@ abstract class DashletGroupBy extends Dashlet
|
||||
// Note: no need to translate, should never be visible to the end-user!
|
||||
return array(
|
||||
'label' => 'Objects grouped by...',
|
||||
'icon' => 'images/dashlets/icons8-transaction-list-48.png',
|
||||
'icon' => 'images/dashlet-object-grouped.png',
|
||||
'description' => 'Grouped objects dashlet (abstract)',
|
||||
);
|
||||
}
|
||||
@@ -1648,7 +1685,7 @@ class DashletGroupByPie extends DashletGroupBy
|
||||
{
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletGroupByPie:Label'),
|
||||
'icon' => 'images/dashlets/icons8-pie-chart-48.png',
|
||||
'icon' => 'images/dashlet-pie-chart.png',
|
||||
'description' => Dict::S('UI:DashletGroupByPie:Description'),
|
||||
);
|
||||
}
|
||||
@@ -1658,27 +1695,26 @@ class DashletGroupByPie extends DashletGroupBy
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
|
||||
$sTitle = $this->aProperties['title'];
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
|
||||
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
|
||||
$aDisplayValues = $this->MakeSimulatedData();
|
||||
|
||||
$aColumns = array();
|
||||
$aNames = array();
|
||||
foreach ($aDisplayValues as $idx => $aValue) {
|
||||
foreach($aDisplayValues as $idx => $aValue)
|
||||
{
|
||||
$aColumns[] = array('series_'.$idx, (int)$aValue['value']);
|
||||
$aNames['series_'.$idx] = $aValue['label'];
|
||||
}
|
||||
$sJSColumns = json_encode($aColumns);
|
||||
$sJSNames = json_encode($aNames);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
window.setTimeout(function() {
|
||||
var chart = c3.generate({
|
||||
bindto: '#{$sBlockId}',
|
||||
@@ -1699,8 +1735,6 @@ var chart = c3.generate({
|
||||
});}, 100);
|
||||
EOF
|
||||
);
|
||||
|
||||
return $oDashletContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1723,7 +1757,7 @@ class DashletGroupByBars extends DashletGroupBy
|
||||
{
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletGroupByBars:Label'),
|
||||
'icon' => 'images/dashlets/icons8-bar-chart-48.png',
|
||||
'icon' => 'images/dashlet-bar-chart.png',
|
||||
'description' => Dict::S('UI:DashletGroupByBars:Description'),
|
||||
);
|
||||
}
|
||||
@@ -1733,26 +1767,25 @@ class DashletGroupByBars extends DashletGroupBy
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
|
||||
$sTitle = $this->aProperties['title'];
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
|
||||
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
|
||||
|
||||
$aDisplayValues = $this->MakeSimulatedData();
|
||||
|
||||
$aNames = array();
|
||||
foreach ($aDisplayValues as $idx => $aValue) {
|
||||
foreach($aDisplayValues as $idx => $aValue)
|
||||
{
|
||||
$aNames[$idx] = $aValue['label'];
|
||||
}
|
||||
$sJSNames = json_encode($aNames);
|
||||
|
||||
$sJson = json_encode($aDisplayValues);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
window.setTimeout(function() {
|
||||
var chart = c3.generate({
|
||||
bindto: '#{$sBlockId}',
|
||||
@@ -1800,8 +1833,6 @@ window.setTimeout(function() {
|
||||
}, 100);
|
||||
EOF
|
||||
);
|
||||
|
||||
return $oDashletContainer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1824,7 +1855,7 @@ class DashletGroupByTable extends DashletGroupBy
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletGroupByTable:Label'),
|
||||
'description' => Dict::S('UI:DashletGroupByTable:Description'),
|
||||
'icon' => 'images/dashlets/icons8-transaction-list-48.png',
|
||||
'icon' => 'images/dashlet-groupby-table.png',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1833,44 +1864,40 @@ class DashletGroupByTable extends DashletGroupBy
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer();
|
||||
|
||||
$aDisplayValues = $this->MakeSimulatedData();
|
||||
$iTotal = 0;
|
||||
foreach ($aDisplayValues as $iRow => $aDisplayData) {
|
||||
foreach($aDisplayValues as $iRow => $aDisplayData)
|
||||
{
|
||||
$iTotal += $aDisplayData['value'];
|
||||
}
|
||||
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$sHtml = '';
|
||||
$sHtml .= '<div id="'.$sBlockId.'" class="display_block">';
|
||||
$sHtml .= '<div class="dashlet-content">';
|
||||
$sHtml .= '<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>';
|
||||
$sHtml .= '<table class="listResults">';
|
||||
$sHtml .= '<thead>';
|
||||
$sHtml .= '<tr>';
|
||||
$sHtml .= '<th class="header" title="">'.$this->sGroupByLabel.'</th>';
|
||||
$sHtml .= '<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>';
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= '</thead>';
|
||||
$sHtml .= '<tbody>';
|
||||
foreach ($aDisplayValues as $aDisplayData) {
|
||||
$sHtml .= '<tr class="even">';
|
||||
$sHtml .= '<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>';
|
||||
$sHtml .= '<td class=""><a>'.$aDisplayData['value'].'</a></td>';
|
||||
$sHtml .= '</tr>';
|
||||
$oPage->add('<div id="'.$sBlockId.'" class="display_block">');
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>');
|
||||
$oPage->add('<table class="listResults">');
|
||||
$oPage->add('<thead>');
|
||||
$oPage->add('<tr>');
|
||||
$oPage->add('<th class="header" title="">'.$this->sGroupByLabel.'</th>');
|
||||
$oPage->add('<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>');
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('</thead>');
|
||||
$oPage->add('<tbody>');
|
||||
foreach($aDisplayValues as $aDisplayData)
|
||||
{
|
||||
$oPage->add('<tr class="even">');
|
||||
$oPage->add('<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>');
|
||||
$oPage->add('<td class=""><a>'.$aDisplayData['value'].'</a></td>');
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
$sHtml .= '</tbody>';
|
||||
$sHtml .= '</table>';
|
||||
$sHtml .= '</div>';
|
||||
$oPage->add('</tbody>');
|
||||
$oPage->add('</table>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
|
||||
return $oDashletContainer;
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1893,13 +1920,20 @@ class DashletHeaderStatic extends Dashlet
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sTitle = $this->aProperties['title'];
|
||||
$sTitle = utils::HtmlEntities($this->aProperties['title']);
|
||||
$sIcon = $this->aProperties['icon'];
|
||||
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
|
||||
|
||||
return DashletFactory::MakeForDashletHeaderStatic($this->oModelReflection->DictString($sTitle), $sIconPath);
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
$oPage->add('<div class="main_header"><h1> '.$this->oModelReflection->DictString($sTitle).'</h1></div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1953,7 +1987,7 @@ class DashletHeaderStatic extends Dashlet
|
||||
{
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletHeaderStatic:Label'),
|
||||
'icon' => 'images/dashlets/icons8-header-48.png',
|
||||
'icon' => 'images/dashlet-header.png',
|
||||
'description' => Dict::S('UI:DashletHeaderStatic:Description'),
|
||||
);
|
||||
}
|
||||
@@ -2023,10 +2057,11 @@ class DashletHeaderDynamic extends Dashlet
|
||||
$sGroupBy = $this->aProperties['group_by'];
|
||||
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
|
||||
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
|
||||
|
||||
$aValues = $this->GetValues();
|
||||
if (count($aValues) > 0) {
|
||||
if (count($aValues) > 0)
|
||||
{
|
||||
// Stats grouped by <group_by>
|
||||
$sCSV = implode(',', $aValues);
|
||||
$aParams = array(
|
||||
@@ -2036,7 +2071,9 @@ class DashletHeaderDynamic extends Dashlet
|
||||
'status_codes[block]' => $sCSV,
|
||||
'context_filter' => 1,
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple stats
|
||||
$aParams = array(
|
||||
'title[block]' => $sTitle,
|
||||
@@ -2045,33 +2082,31 @@ class DashletHeaderDynamic extends Dashlet
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($aExtraParams['query_params'])) {
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
|
||||
if (isset($aExtraParams['query_params']))
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
} elseif (isset($aExtraParams['this->class'])) {
|
||||
}
|
||||
elseif (isset($aExtraParams['this->class']))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
|
||||
$aQueryParams = $oObj->ToArgsForQuery();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$aQueryParams = array();
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
|
||||
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
|
||||
$sClass = $oFilter->GetClass();
|
||||
|
||||
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S(str_replace('_', ':', $sTitle)))
|
||||
->SetIcon($sIconPath)
|
||||
->SetColorFromClass($sClass);
|
||||
$oBlock = new DisplayBlock($oFilter, 'summary');
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
|
||||
|
||||
$oSubTitle = $oPanel->GetSubTitleBlock();
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$iCount = $oSet->Count();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($oFilter->serialize());
|
||||
$oSubTitle->AddHtml('<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sSubtitle), $iCount).'</a>');
|
||||
|
||||
return $oPanel;
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2091,48 +2126,46 @@ class DashletHeaderDynamic extends Dashlet
|
||||
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
|
||||
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
|
||||
|
||||
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
$oPage->add('<div class="main_header">');
|
||||
|
||||
$sHtml = '';
|
||||
$sHtml .= '<img src="'.$sIconPath.'">';
|
||||
$oPage->add('<img src="'.$sIconPath.'">');
|
||||
|
||||
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
|
||||
|
||||
$iTotal = 0;
|
||||
$aValues = $this->GetValues();
|
||||
|
||||
$sHtml .= '<div class="display_block" id="'.$sBlockId.'">';
|
||||
$sHtml .= '<div class="summary-details">';
|
||||
$sHtml .= '<table><tbody>';
|
||||
$sHtml .= '<tr>';
|
||||
foreach ($aValues as $sValue) {
|
||||
$oPage->add('<div class="display_block" id="'.$sBlockId.'">');
|
||||
$oPage->add('<div class="summary-details">');
|
||||
$oPage->add('<table><tbody>');
|
||||
$oPage->add('<tr>');
|
||||
foreach ($aValues as $sValue)
|
||||
{
|
||||
$sValueLabel = $this->oModelReflection->GetValueLabel($sClass, $sGroupBy, $sValue);
|
||||
$sHtml .= ' <th>'.$sValueLabel.'</th>';
|
||||
$oPage->add(' <th>'.$sValueLabel.'</th>');
|
||||
}
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= '<tr>';
|
||||
foreach ($aValues as $sValue) {
|
||||
$iCount = (int)rand(2, 100);
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('<tr>');
|
||||
foreach ($aValues as $sValue)
|
||||
{
|
||||
$iCount = (int) rand(2, 100);
|
||||
$iTotal += $iCount;
|
||||
$sHtml .= ' <td>'.$iCount.'</td>';
|
||||
$oPage->add(' <td>'.$iCount.'</td>');
|
||||
}
|
||||
$sHtml .= '</tr>';
|
||||
$sHtml .= '</tbody></table>';
|
||||
$sHtml .= '</div>';
|
||||
$oPage->add('</tr>');
|
||||
$oPage->add('</tbody></table>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sTitle = $this->oModelReflection->DictString($sTitle);
|
||||
$sSubtitle = $this->oModelReflection->DictFormat($sSubtitle, $iTotal);
|
||||
|
||||
$sHtml .= '<h1>'.utils::HtmlEntities($sTitle).'</h1>';
|
||||
$sHtml .= '<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
|
||||
return $oDashletContainer;
|
||||
$oPage->add('<h1>'.utils::HtmlEntities($sTitle).'</h1>');
|
||||
$oPage->add('<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2261,7 +2294,7 @@ class DashletHeaderDynamic extends Dashlet
|
||||
{
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletHeaderDynamic:Label'),
|
||||
'icon' => 'images/dashlets/icons8-header-altered-48.png',
|
||||
'icon' => 'images/dashlet-header-stats.png',
|
||||
'description' => Dict::S('UI:DashletHeaderDynamic:Description'),
|
||||
);
|
||||
}
|
||||
@@ -2277,8 +2310,8 @@ class DashletBadge extends Dashlet
|
||||
{
|
||||
parent::__construct($oModelReflection, $sId);
|
||||
$this->aProperties['class'] = 'Contact';
|
||||
$this->aCSSClasses[] = 'ibo-dashlet--is-inline';
|
||||
$this->aCSSClasses[] = 'ibo-dashlet-badge';
|
||||
$this->aCSSClasses[] = 'dashlet-inline';
|
||||
$this->aCSSClasses[] = 'dashlet-badge';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2288,17 +2321,17 @@ class DashletBadge extends Dashlet
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer($this->sId, ['dashlet-content']);
|
||||
|
||||
$sClass = $this->aProperties['class'];
|
||||
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oBlock = new DisplayBlock($oFilter, 'actions');
|
||||
$aExtraParams['context_filter'] = 1;
|
||||
$aExtraParams['withJSRefreshCallBack'] = true;
|
||||
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
|
||||
$oBlock->DisplayIntoContentBlock($oDashletContainer, $oPage, $sBlockId, $aExtraParams);
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
|
||||
return $oDashletContainer;
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2306,25 +2339,25 @@ class DashletBadge extends Dashlet
|
||||
*/
|
||||
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oDashletContainer = new DashletContainer($this->sId, ['dashlet-content']);
|
||||
|
||||
$sClass = $this->aProperties['class'];
|
||||
|
||||
$sIconUrl = $this->oModelReflection->GetClassIcon($sClass, false);
|
||||
$sClassLabel = $this->oModelReflection->GetName($sClass);
|
||||
|
||||
$sHtml = '';
|
||||
$sHtml .= '<div id="block_fake_'.$this->sId.'" class="display_block">';
|
||||
$sHtml .= '<p>';
|
||||
$sHtml .= ' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>';
|
||||
$sHtml .= '</p>';
|
||||
$sHtml .= '<p>';
|
||||
$sHtml .= ' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>';
|
||||
$sHtml .= '</p>';
|
||||
$sHtml .= '</div>';
|
||||
$oPage->add('<div class="dashlet-content">');
|
||||
|
||||
$oDashletContainer->AddHtml($sHtml);
|
||||
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
|
||||
$oPage->add('<p>');
|
||||
$oPage->add(' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>');
|
||||
$oPage->add('</p>');
|
||||
$oPage->add('<p>');
|
||||
$oPage->add(' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>');
|
||||
$oPage->add(' <br/>');
|
||||
$oPage->add(' <a>'.Dict::Format('UI:SearchFor_Class', $sClassLabel).'</a>');
|
||||
$oPage->add('</p>');
|
||||
$oPage->add('</div>');
|
||||
|
||||
return $oDashletContainer;
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
static protected $aClassList = null;
|
||||
@@ -2374,7 +2407,7 @@ class DashletBadge extends Dashlet
|
||||
{
|
||||
return array(
|
||||
'label' => Dict::S('UI:DashletBadge:Label'),
|
||||
'icon' => 'images/dashlets/icons8-badge-48.png',
|
||||
'icon' => 'images/dashlet-badge.png',
|
||||
'description' => Dict::S('UI:DashletBadge:Description'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,46 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<classes>
|
||||
<class id="AbstractResource" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */</comment>
|
||||
<abstract>true</abstract>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ResourceAdminMenu" _delta="define">
|
||||
<parent>AbstractResource</parent>
|
||||
<properties>
|
||||
<comment>/* AdminTools menu access control. */</comment>
|
||||
<abstract>true</abstract>
|
||||
<category>grant_by_profile</category>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ResourceRunQueriesMenu" _delta="define">
|
||||
<parent>AbstractResource</parent>
|
||||
<properties>
|
||||
<comment>/* RunQueriesMenu menu access control. */</comment>
|
||||
<abstract>true</abstract>
|
||||
<category>grant_by_profile</category>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ResourceSystemMenu" _delta="define">
|
||||
<parent>AbstractResource</parent>
|
||||
<properties>
|
||||
<comment>/* System menu access control. */</comment>
|
||||
<abstract>true</abstract>
|
||||
<category>grant_by_profile</category>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
</class>
|
||||
</classes>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<portals>
|
||||
<portal id="backoffice" _delta="define">
|
||||
<url>pages/UI.php</url>
|
||||
@@ -53,388 +12,13 @@
|
||||
</portal>
|
||||
</portals>
|
||||
<menus>
|
||||
<menu id="WelcomeMenu" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>10</rank>
|
||||
<style>
|
||||
<decoration_classes>fas fa-home</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
<menu id="WelcomeMenuPage" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>10</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
<definition>
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title>Menu:WelcomeMenuPage</title>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
<menu id="MyShortcuts" xsi:type="ShortcutContainerMenuNode" _delta="define">
|
||||
<rank>20</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
</menu>
|
||||
<menu id="UserManagement" xsi:type="TemplateMenuNode" _delta="define">
|
||||
<rank>10</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<template_file/>
|
||||
</menu>
|
||||
<menu id="UserAccountsMenu" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>11</rank>
|
||||
<parent>UserManagement</parent>
|
||||
<oql><![CDATA[SELECT User]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<search_form_open>1</search_form_open>
|
||||
<enable_class>User</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="ProfilesMenu" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>12</rank>
|
||||
<parent>UserManagement</parent>
|
||||
<oql><![CDATA[SELECT URP_Profiles]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>URP_Profiles</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="AuditCategories" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>20</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<oql><![CDATA[SELECT AuditCategory]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>AuditCategory</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="Queries" xsi:type="TemplateMenuNode" _delta="define">
|
||||
<rank>30</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<template_file/>
|
||||
</menu>
|
||||
<menu id="RunQueriesMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>31</rank>
|
||||
<parent>Queries</parent>
|
||||
<url>$pages/run_query.php</url>
|
||||
<enable_class>ResourceRunQueriesMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="QueryMenu" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>32</rank>
|
||||
<parent>Queries</parent>
|
||||
<oql><![CDATA[SELECT Query]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>Query</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="ExportMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>33</rank>
|
||||
<parent>Queries</parent>
|
||||
<url>$webservices/export-v2.php?interactive=1</url>
|
||||
<enable_class>ResourceAdminMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="DataModelMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>40</rank>
|
||||
<parent>AdminTools</parent>
|
||||
<url>$pages/schema.php</url>
|
||||
<enable_class>ResourceRunQueriesMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="UniversalSearchMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>35</rank>
|
||||
<parent>Queries</parent>
|
||||
<url>$pages/UniversalSearch.php</url>
|
||||
<enable_class>ResourceAdminMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="ConfigurationTools" xsi:type="MenuGroup" _delta="define_if_not_exists">
|
||||
<rank>90</rank>
|
||||
<style>
|
||||
<decoration_classes>fas fa-cog</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
<menu id="DataSources" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>20</rank>
|
||||
<parent>ConfigurationTools</parent>
|
||||
<oql><![CDATA[SELECT SynchroDataSource]]></oql>
|
||||
<do_search>1</do_search>
|
||||
<enable_class>SynchroDataSource</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="NotificationsMenu" xsi:type="WebPageMenuNode" _delta="define">
|
||||
<rank>40</rank>
|
||||
<parent>ConfigurationTools</parent>
|
||||
<url>$pages/notifications.php</url>
|
||||
<enable_class>Trigger</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
</menu>
|
||||
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>80</rank>
|
||||
<style>
|
||||
<decoration_classes>fas fa-tools</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
<menu id="SystemTools" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>100</rank>
|
||||
<enable_class>ResourceSystemMenu</enable_class>
|
||||
<enable_action>UR_ACTION_MODIFY</enable_action>
|
||||
<style>
|
||||
<decoration_classes>fas fa-terminal</decoration_classes>
|
||||
</style>
|
||||
</menu>
|
||||
</menus>
|
||||
<meta>
|
||||
<classes>
|
||||
<class id="cmdbAbstractObject" _delta="define">
|
||||
<methods>
|
||||
<method id="Set">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
<type id="AttributeLinkedSetIndirect"/>
|
||||
<type id="AttributeLinkedSet"/>
|
||||
<type id="AttributeImage"/>
|
||||
<type id="AttributeBlob"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>string</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetIfNull">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
<type id="AttributeLinkedSetIndirect"/>
|
||||
<type id="AttributeLinkedSet"/>
|
||||
<type id="AttributeImage"/>
|
||||
<type id="AttributeBlob"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>string</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="AddValue">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeInteger"/>
|
||||
<type id="AttributeDecimal"/>
|
||||
<type id="AttributePercentage"/>
|
||||
<type id="AttributeDuration"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>string</type>
|
||||
<mandatory>false</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetCurrentDate">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeDate"/>
|
||||
<type id="AttributeDateTime"/>
|
||||
<type id="AttributeString"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetCurrentDateIfNull">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeDate"/>
|
||||
<type id="AttributeDateTime"/>
|
||||
<type id="AttributeString"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetCurrentUser">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeExternalKey"/>
|
||||
<type id="AttributeInteger"/>
|
||||
<type id="AttributeString"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetCurrentPerson">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeExternalKey"/>
|
||||
<type id="AttributeInteger"/>
|
||||
<type id="AttributeString"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="SetElapsedTime">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeDuration"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeDate"/>
|
||||
<type id="AttributeDateTime"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="3">
|
||||
<type>string</type>
|
||||
<mandatory>false</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="Reset">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="ResetStopWatch">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>allow</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="Copy">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
<type_restrictions>
|
||||
<operation>deny</operation>
|
||||
<types>
|
||||
<type id="AttributeStopWatch"/>
|
||||
<type id="AttributeSubItem"/>
|
||||
<type id="AttributeExternalField"/>
|
||||
</types>
|
||||
</type_restrictions>
|
||||
</argument>
|
||||
<argument id="2">
|
||||
<type>attcode</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="ApplyStimulus">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>string</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="PrefillCreationForm">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>reference</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="PrefillTransitionForm">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>reference</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
<method id="PrefillSearchForm">
|
||||
<arguments>
|
||||
<argument id="1">
|
||||
<type>reference</type>
|
||||
<mandatory>true</mandatory>
|
||||
</argument>
|
||||
</arguments>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
</classes>
|
||||
</meta>
|
||||
</itop_design>
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -18,8 +15,6 @@ use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*
|
||||
* @deprecated since 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
|
||||
*/
|
||||
|
||||
class DataTable
|
||||
@@ -30,7 +25,7 @@ class DataTable
|
||||
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
|
||||
protected $oSet; // The set of objects to display
|
||||
protected $aClassAliases; // The aliases (alias => class) inside the set
|
||||
protected $iNbObjects; // Total number of objects in the set
|
||||
protected $iNbObjects; // Total number of objects inthe set
|
||||
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
|
||||
protected $oDefaultSettings; // the default settings for displaying such a list
|
||||
protected $bShowObsoleteData;
|
||||
@@ -162,17 +157,17 @@ class DataTable
|
||||
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$sActionsMenu = '';
|
||||
$sToolkitMenu = '';
|
||||
if ($bActionsMenu) {
|
||||
if ($bActionsMenu)
|
||||
{
|
||||
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
|
||||
}
|
||||
// if ($bToolkitMenu)
|
||||
// {
|
||||
// $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
|
||||
// }
|
||||
|
||||
if ($bToolkitMenu)
|
||||
{
|
||||
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
|
||||
}
|
||||
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
|
||||
|
||||
|
||||
$sHtml = "<table id=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
|
||||
$sHtml .= "<tr><td>";
|
||||
$sHtml .= "<table style=\"width:100%;\">";
|
||||
@@ -213,7 +208,7 @@ class DataTable
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
|
||||
* return string The HTML rows to insert inside the <tbody> node
|
||||
@@ -352,26 +347,17 @@ EOF;
|
||||
* @param $aExtraParams
|
||||
*
|
||||
* @return string
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*/
|
||||
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
|
||||
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
||||
|
||||
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
|
||||
|
||||
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -527,7 +513,6 @@ EOF;
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $aColumns
|
||||
* @param $sSelectMode
|
||||
@@ -875,3 +860,396 @@ class PrintableDataTable extends DataTable
|
||||
return $sHtml;
|
||||
}
|
||||
}
|
||||
|
||||
class DataTableSettings implements Serializable
|
||||
{
|
||||
public $aClassAliases;
|
||||
public $sTableId;
|
||||
public $iDefaultPageSize;
|
||||
public $aColumns;
|
||||
|
||||
|
||||
/**
|
||||
* DataTableSettings constructor.
|
||||
*
|
||||
* @param $aClassAliases
|
||||
* @param null $sTableId
|
||||
*/
|
||||
public function __construct($aClassAliases, $sTableId = null)
|
||||
{
|
||||
$this->aClassAliases = $aClassAliases;
|
||||
$this->sTableId = $sTableId;
|
||||
$this->iDefaultPageSize = 10;
|
||||
$this->aColumns = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iDefaultPageSize
|
||||
* @param $aSortOrder
|
||||
* @param $aColumns
|
||||
*/
|
||||
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
|
||||
{
|
||||
$this->iDefaultPageSize = $iDefaultPageSize;
|
||||
$this->aColumns = $aColumns;
|
||||
$this->FixVisibleColumns();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
// Save only the 'visible' columns
|
||||
$aColumns = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
$aColumns[$sAlias] = array();
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
unset($aData['label']); // Don't save the display name
|
||||
unset($aData['alias']); // Don't save the alias (redundant)
|
||||
unset($aData['code']); // Don't save the code (redundant)
|
||||
if ($aData['checked'])
|
||||
{
|
||||
$aColumns[$sAlias][$sAttCode] = $aData;
|
||||
}
|
||||
}
|
||||
}
|
||||
return serialize(
|
||||
array(
|
||||
'iDefaultPageSize' => $this->iDefaultPageSize,
|
||||
'aColumns' => $aColumns,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sData
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function unserialize($sData)
|
||||
{
|
||||
$aData = unserialize($sData);
|
||||
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
|
||||
$this->aColumns = $aData['aColumns'];
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
$aFieldData = false;
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
|
||||
}
|
||||
else if (MetaModel::isValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
|
||||
}
|
||||
|
||||
if ($aFieldData)
|
||||
{
|
||||
$this->aColumns[$sAlias][$sAttCode] = $aFieldData;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($this->aColumns[$sAlias][$sAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->FixVisibleColumns();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aClassAliases
|
||||
* @param $bViewLink
|
||||
* @param $aDefaultLists
|
||||
*
|
||||
* @return \DataTableSettings
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
|
||||
{
|
||||
$oSettings = new DataTableSettings($aClassAliases);
|
||||
// Retrieve the class specific settings for each class/alias based on the 'list' ZList
|
||||
//TODO let the caller pass some other default settings (another Zlist, extre fields...)
|
||||
$aColumns = array();
|
||||
foreach($aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
if ($aDefaultLists == null)
|
||||
{
|
||||
$aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aList = $aDefaultLists[$sAlias];
|
||||
}
|
||||
|
||||
$aSortOrder = MetaModel::GetOrderByDefault($sClass);
|
||||
if ($bViewLink)
|
||||
{
|
||||
$sSort = 'none';
|
||||
if(array_key_exists('friendlyname', $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
|
||||
}
|
||||
$sNormalizedFName = MetaModel::NormalizeFieldSpec($sClass, 'friendlyname');
|
||||
if(array_key_exists($sNormalizedFName, $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder[$sNormalizedFName] ? 'asc' : 'desc';
|
||||
}
|
||||
|
||||
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
$sSort = 'none';
|
||||
if(array_key_exists($sAttCode, $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
|
||||
}
|
||||
$oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
|
||||
if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
|
||||
}
|
||||
}
|
||||
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
|
||||
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
protected function FixVisibleColumns()
|
||||
{
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
if (!isset($this->aColumns[$sAlias]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
// Remove non-existent columns
|
||||
// TODO: check if the existing ones are still valid (in case their type changed)
|
||||
if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
|
||||
{
|
||||
unset($this->aColumns[$sAlias][$sAttCode]);
|
||||
}
|
||||
}
|
||||
$aList = MetaModel::ListAttributeDefs($sClass);
|
||||
|
||||
// Add the other (non visible ones), sorted in alphabetical order
|
||||
$aTempData = array();
|
||||
foreach($aList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
|
||||
{
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
|
||||
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
|
||||
}
|
||||
}
|
||||
ksort($aTempData);
|
||||
foreach($aTempData as $sLabel => $aFieldData)
|
||||
{
|
||||
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aClassAliases
|
||||
* @param null $sTableId
|
||||
* @param bool $bOnlyOnTable
|
||||
*
|
||||
* @return \DataTableSettings|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
|
||||
{
|
||||
$pref = null;
|
||||
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
|
||||
|
||||
if ($sTableId != null)
|
||||
{
|
||||
// An identified table, let's fetch its own settings (if any)
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
|
||||
}
|
||||
|
||||
if ($pref == null)
|
||||
{
|
||||
if (!$bOnlyOnTable)
|
||||
{
|
||||
// Try the global preferred values for this class / set of classes
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
|
||||
}
|
||||
if ($pref == null)
|
||||
{
|
||||
// no such settings, use the default values provided by the data model
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$oSettings->unserialize($pref);
|
||||
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function GetSortOrder()
|
||||
{
|
||||
$aSortOrder = array();
|
||||
foreach($this->aColumns as $sAlias => $aColumns)
|
||||
{
|
||||
foreach($aColumns as $aColumn)
|
||||
{
|
||||
if ($aColumn['sort'] != 'none')
|
||||
{
|
||||
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
|
||||
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
|
||||
}
|
||||
}
|
||||
break; // TODO: For now the Set object supports only sorting on the first class of the set
|
||||
}
|
||||
return $aSortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $sTargetTableId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function Save($sTargetTableId = null)
|
||||
{
|
||||
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
|
||||
if ($sSaveId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
|
||||
|
||||
$sSettings = $this->serialize();
|
||||
appUserPreferences::SetPref($this->GetPrefsKey($sSaveId), $sSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function SaveAsDefault()
|
||||
{
|
||||
$sSettings = $this->serialize();
|
||||
appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear the preferences for this particular table
|
||||
* @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
|
||||
*/
|
||||
public function ResetToDefault($bResetAll)
|
||||
{
|
||||
if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
|
||||
if ($bResetAll)
|
||||
{
|
||||
// Turn the key into a suitable PCRE pattern
|
||||
$sKey = $this->GetPrefsKey(null);
|
||||
$sPattern = str_replace(array('|'), array('\\|'), $sKey); // escape the | character
|
||||
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
|
||||
appUserPreferences::UnsetPref($sPattern, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $sTableId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function GetPrefsKey($sTableId = null)
|
||||
{
|
||||
return static::GetAppUserPreferenceKey($this->aClassAliases, $sTableId);
|
||||
}
|
||||
|
||||
public static function GetAppUserPreferenceKey($aClassAliases, $sTableId)
|
||||
{
|
||||
if ($sTableId === null)
|
||||
{
|
||||
$sTableId = '*';
|
||||
}
|
||||
|
||||
$aKeys = array();
|
||||
foreach($aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
$aKeys[] = $sAlias.'-'.$sClass;
|
||||
}
|
||||
return implode('/', $aKeys).'|'.$sTableId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sAlias
|
||||
* @param $sAttCode
|
||||
* @param $oAttDef
|
||||
* @param $bChecked
|
||||
* @param $sSort
|
||||
*
|
||||
* @return array|bool
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
|
||||
{
|
||||
$ret = false;
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
|
||||
$ret = array(
|
||||
'label' => $sLabel,
|
||||
'checked' => true,
|
||||
'disabled' => true,
|
||||
'alias' => $sAlias,
|
||||
'code' => $sAttCode,
|
||||
'sort' => $sSort,
|
||||
);
|
||||
}
|
||||
else if (!$oAttDef->IsLinkSet())
|
||||
{
|
||||
$sLabel = $oAttDef->GetLabel();
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
|
||||
}
|
||||
else if ($oAttDef->IsExternalField())
|
||||
{
|
||||
if ($oAttDef->IsFriendlyName())
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
|
||||
}
|
||||
else
|
||||
{
|
||||
$oExtAttDef = $oAttDef->GetExtAttDef();
|
||||
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
|
||||
}
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
|
||||
}
|
||||
$ret = array(
|
||||
'label' => $sLabel,
|
||||
'checked' => $bChecked,
|
||||
'disabled' => false,
|
||||
'alias' => $sAlias,
|
||||
'code' => $sAttCode,
|
||||
'sort' => $sSort,
|
||||
);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/ErrorPage.php
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
|
||||
|
||||
class ErrorPage extends NiceWebPage
|
||||
{
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../setup/setup.js");
|
||||
$this->add_saas("css/setup.scss");
|
||||
}
|
||||
|
||||
public function info($sText)
|
||||
{
|
||||
$this->add("<p class=\"info\">$sText</p>\n");
|
||||
$this->log_info($sText);
|
||||
}
|
||||
|
||||
public function ok($sText)
|
||||
{
|
||||
$this->add("<div class=\"message message-valid\"><span class=\"message-title\">Success:</span>$sText</div>");
|
||||
$this->log_ok($sText);
|
||||
}
|
||||
|
||||
public function warning($sText)
|
||||
{
|
||||
$this->add("<div class=\"message message-warning\"><span class=\"message-title\">Warning:</span>$sText</div>");
|
||||
$this->log_warning($sText);
|
||||
}
|
||||
|
||||
public function error($sText)
|
||||
{
|
||||
$this->add("<div class=\"message message-error\">$sText</div>");
|
||||
$this->log_error($sText);
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$sLogo = utils::GetAbsoluteUrlAppRoot().'/images/itop-logo.png';
|
||||
$sTimeStamp = utils::GetCacheBusterTimestamp();
|
||||
$sTitle = utils::HtmlEntities($this->s_title);
|
||||
$this->s_content = <<<HTML
|
||||
<div id="header" class="error_page">
|
||||
<h1><a href="http://www.combodo.com/itop" target="_blank"><img title="iTop by Combodo" alt=" " src="{$sLogo}?t={$sTimeStamp}"></a> {$sTitle}</h1>
|
||||
</div>
|
||||
<div id="setup" class="error_page">
|
||||
{$this->s_content}
|
||||
</div>
|
||||
HTML;
|
||||
return parent::output();
|
||||
}
|
||||
|
||||
public static function log_error($sText)
|
||||
{
|
||||
IssueLog::Error($sText);
|
||||
}
|
||||
|
||||
public static function log_warning($sText)
|
||||
{
|
||||
IssueLog::Warning($sText);
|
||||
}
|
||||
|
||||
public static function log_info($sText)
|
||||
{
|
||||
IssueLog::Info($sText);
|
||||
}
|
||||
|
||||
public static function log_ok($sText)
|
||||
{
|
||||
IssueLog::Ok($sText);
|
||||
}
|
||||
|
||||
public static function log($sText)
|
||||
{
|
||||
IssueLog::Ok($sText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ApplicationException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when querying on an object that exists in the database but is archived
|
||||
*
|
||||
* @since 2.5.1 N°1108
|
||||
*/
|
||||
class ArchivedObjectException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class BulkChangeException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class CSVParserException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ConfigException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class CoreCannotSaveObjectException
|
||||
*
|
||||
* Specialized exception to raise if {@link DBObject::CheckToWrite()} fails, which allow easy data retrieval
|
||||
*
|
||||
* @see \DBObject::DBInsertNoReload()
|
||||
* @see \DBObject::DBUpdate()
|
||||
*
|
||||
* @since 2.6.0 N°659 uniqueness constraint
|
||||
*/
|
||||
class CoreCannotSaveObjectException extends CoreException
|
||||
{
|
||||
/** @var string[] */
|
||||
private $aIssues;
|
||||
/** @var int */
|
||||
private $iObjectId;
|
||||
/** @var string */
|
||||
private $sObjectClass;
|
||||
|
||||
/**
|
||||
* CoreCannotSaveObjectException constructor.
|
||||
*
|
||||
* @param array $aContextData containing at least those keys : issues, id, class
|
||||
*/
|
||||
public function __construct($aContextData)
|
||||
{
|
||||
$this->aIssues = $aContextData['issues'];
|
||||
$this->iObjectId = $aContextData['id'];
|
||||
$this->sObjectClass = $aContextData['class'];
|
||||
|
||||
$sIssues = implode(', ', $this->aIssues);
|
||||
parent::__construct($sIssues, $aContextData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHtmlMessage()
|
||||
{
|
||||
$sTitle = Dict::S('UI:Error:SaveFailed');
|
||||
$sContent = "<span><strong>{$sTitle}</strong></span>";
|
||||
|
||||
if (count($this->aIssues) == 1) {
|
||||
$sIssue = reset($this->aIssues);
|
||||
$sContent .= " <span>{$sIssue}</span>";
|
||||
} else {
|
||||
$sContent .= '<ul>';
|
||||
foreach ($this->aIssues as $sError) {
|
||||
$sContent .= "<li>$sError</li>";
|
||||
}
|
||||
$sContent .= '</ul>';
|
||||
}
|
||||
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
public function getIssues()
|
||||
{
|
||||
return $this->aIssues;
|
||||
}
|
||||
|
||||
public function getObjectId()
|
||||
{
|
||||
return $this->iObjectId;
|
||||
}
|
||||
|
||||
public function getObjectClass()
|
||||
{
|
||||
return $this->sObjectClass;
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class CoreException extends Exception
|
||||
{
|
||||
/**
|
||||
* CoreException constructor.
|
||||
*
|
||||
* @param string $sIssue error message
|
||||
* @param array|null $aContextData key/value array, value MUST implements _toString
|
||||
* @param string $sImpact
|
||||
* @param Exception|null $oPrevious
|
||||
*/
|
||||
public function __construct($sIssue, $aContextData = null, $sImpact = '', $oPrevious = null)
|
||||
{
|
||||
$this->m_sIssue = $sIssue;
|
||||
$this->m_sImpact = $sImpact;
|
||||
|
||||
if (is_array($aContextData)) {
|
||||
$this->m_aContextData = $aContextData;
|
||||
} else {
|
||||
$this->m_aContextData = [];
|
||||
}
|
||||
|
||||
$sMessage = $sIssue;
|
||||
if (!empty($sImpact)) {
|
||||
$sMessage .= "($sImpact)";
|
||||
}
|
||||
if (count($this->m_aContextData) > 0) {
|
||||
$sMessage .= ": ";
|
||||
$aContextItems = array();
|
||||
foreach ($this->m_aContextData as $sKey => $value) {
|
||||
if (is_array($value)) {
|
||||
$aPairs = array();
|
||||
foreach ($value as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$aPairs[] = $key.'=>('.implode(', ', $val).')';
|
||||
} else {
|
||||
$aPairs[] = $key.'=>'.$val;
|
||||
}
|
||||
}
|
||||
$sValue = '{'.implode('; ', $aPairs).'}';
|
||||
} else {
|
||||
$sValue = $value;
|
||||
}
|
||||
$aContextItems[] = "$sKey = $sValue";
|
||||
}
|
||||
$sMessage .= implode(', ', $aContextItems);
|
||||
}
|
||||
parent::__construct($sMessage, 0, $oPrevious);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string code and message for log purposes
|
||||
*/
|
||||
public function getInfoLog()
|
||||
{
|
||||
return 'error_code='.$this->getCode().', message="'.$this->getMessage().'"';
|
||||
}
|
||||
|
||||
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
|
||||
{
|
||||
return $this->getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* getTraceAsString() cannot be overrided and it is limited as only current exception stack is returned.
|
||||
* we need stack of all previous exceptions
|
||||
*
|
||||
* @uses __tostring() already does the work.
|
||||
* @since 2.7.2/ 3.0.0
|
||||
*/
|
||||
public function getFullStackTraceAsString()
|
||||
{
|
||||
return "".$this;
|
||||
}
|
||||
|
||||
public function getTraceAsHtml()
|
||||
{
|
||||
$aBackTrace = $this->getTrace();
|
||||
|
||||
return MyHelpers::get_callstack_html(0, $this->getTrace());
|
||||
// return "<pre>\n".$this->getTraceAsString()."</pre>\n";
|
||||
}
|
||||
|
||||
public function addInfo($sKey, $value)
|
||||
{
|
||||
$this->m_aContextData[$sKey] = $value;
|
||||
}
|
||||
|
||||
public function getIssue()
|
||||
{
|
||||
return $this->m_sIssue;
|
||||
}
|
||||
|
||||
public function getImpact()
|
||||
{
|
||||
return $this->m_sImpact;
|
||||
}
|
||||
|
||||
public function getContextData()
|
||||
{
|
||||
return $this->m_aContextData;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°2555
|
||||
*/
|
||||
class CorePortalInvalidActionRuleException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°3522
|
||||
*/
|
||||
class CoreTemplateException extends CoreException
|
||||
{
|
||||
public function __construct(Exception $oTwigException, string $sTemplatePath)
|
||||
{
|
||||
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
|
||||
parent::__construct($sMessage, null, '', $oTwigException);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class CoreUnexpectedValue extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class CoreWarning extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class DeleteException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* A parameter stored in the {@link Config} is invalid
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class InvalidConfigParamException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Thrown when the password is not valid
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
class InvalidPasswordAttributeOneWayPassword extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\TwigBase\Controller;
|
||||
|
||||
use Exception;
|
||||
|
||||
class PageNotFoundException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class SecurityException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class SynchroExceptionNotStarted extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class UserRightException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class DictException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class DictExceptionMissingString extends DictException
|
||||
{
|
||||
public function __construct($sLanguageCode, $sStringCode)
|
||||
{
|
||||
$aContext = array();
|
||||
$aContext['language_code'] = $sLanguageCode;
|
||||
$aContext['string_code'] = $sStringCode;
|
||||
parent::__construct('Missing localized string', $aContext);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class DictExceptionUnknownLanguage extends DictException
|
||||
{
|
||||
public function __construct($sLanguageCode)
|
||||
{
|
||||
$aContext = array();
|
||||
$aContext['language_code'] = $sLanguageCode;
|
||||
parent::__construct('Unknown localization language', $aContext);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class MySQLException extends CoreException
|
||||
{
|
||||
/**
|
||||
* MySQLException constructor.
|
||||
*
|
||||
* @param string $sIssue
|
||||
* @param array $aContext
|
||||
* @param \Exception $oException
|
||||
* @param \mysqli $oMysqli to use when working with a custom mysqli instance
|
||||
*/
|
||||
public function __construct($sIssue, $aContext, $oException = null, $oMysqli = null)
|
||||
{
|
||||
if ($oException != null) {
|
||||
$aContext['mysql_errno'] = $oException->getCode();
|
||||
$this->code = $oException->getCode();
|
||||
$aContext['mysql_error'] = $oException->getMessage();
|
||||
} else if ($oMysqli != null) {
|
||||
$aContext['mysql_errno'] = $oMysqli->errno;
|
||||
$this->code = $oMysqli->errno;
|
||||
$aContext['mysql_error'] = $oMysqli->error;
|
||||
} else {
|
||||
$aContext['mysql_errno'] = CMDBSource::GetErrNo();
|
||||
$this->code = CMDBSource::GetErrNo();
|
||||
$aContext['mysql_error'] = CMDBSource::GetError();
|
||||
}
|
||||
parent::__construct($sIssue, $aContext);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class MySQLHasGoneAwayException
|
||||
*
|
||||
* @see https://dev.mysql.com/doc/refman/5.7/en/gone-away.html
|
||||
* @since 2.5.0 N°1195
|
||||
*/
|
||||
class MySQLHasGoneAwayException extends MySQLException
|
||||
{
|
||||
/**
|
||||
* can not be a constant before PHP 5.6 (http://php.net/manual/fr/language.oop5.constants.php)
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public static function getErrorCodes()
|
||||
{
|
||||
return array(
|
||||
2006,
|
||||
2013,
|
||||
);
|
||||
}
|
||||
|
||||
public function __construct($sIssue, $aContext)
|
||||
{
|
||||
parent::__construct($sIssue, $aContext, null);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°679
|
||||
*/
|
||||
class MySQLNoTransactionException extends MySQLException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class MySQLQueryHasNoResultException
|
||||
*
|
||||
* @since 2.5.0
|
||||
*/
|
||||
class MySQLQueryHasNoResultException extends MySQLException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°2555
|
||||
*/
|
||||
class CoreOqlException extends CoreException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @since 2.7.0 N°2555
|
||||
*/
|
||||
class CoreOqlMultipleResultsForbiddenException extends CoreOqlException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Exception for {@link iProcess} implementations.<br>
|
||||
* An error happened during the processing but we can go on with the next implementations.
|
||||
*
|
||||
* @since 2.5.0 N°1195
|
||||
*/
|
||||
class ProcessException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class ProcessFatalException
|
||||
* Exception for iProcess implementations.<br>
|
||||
* A big error occurred, we have to stop the iProcess processing.
|
||||
*
|
||||
* @since 2.5.0 N°1195
|
||||
*/
|
||||
class ProcessFatalException extends CoreException
|
||||
{
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @since 2.7.0 PR #89
|
||||
*/
|
||||
class ProcessInvalidConfigException extends ProcessException
|
||||
{
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class FindStylesheetObject: dedicated class to store computations made in method ThemeHandler::FindStylesheetFile.
|
||||
* @author Olivier DAIN <olivier.dain@combodo.com>
|
||||
* @since 3.0.0 N°3588
|
||||
*/
|
||||
class FindStylesheetObject{
|
||||
|
||||
//file URIs
|
||||
private $aStylesheetFileURIs;
|
||||
|
||||
//fill paths
|
||||
private $aStylesheetImportPaths;
|
||||
private $aAllStylesheetFilePaths;
|
||||
private $sLastStyleSheetPath;
|
||||
|
||||
private $iLastModified;
|
||||
|
||||
/**
|
||||
* FindStylesheetObject constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->aStylesheetFileURIs = [];
|
||||
$this->aStylesheetImportPaths = [];
|
||||
$this->aAllStylesheetFilePaths = [];
|
||||
$this->sLastStyleSheetPath = "";
|
||||
$this->iLastModified = 0;
|
||||
}
|
||||
|
||||
public function GetLastStylesheetFile(): string
|
||||
{
|
||||
return $this->sLastStyleSheetPath;
|
||||
}
|
||||
|
||||
public function GetImportPaths(): array
|
||||
{
|
||||
return $this->aStylesheetImportPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array : main stylesheets URIs
|
||||
*/
|
||||
public function GetStylesheetFileURIs(): array
|
||||
{
|
||||
return $this->aStylesheetFileURIs;
|
||||
}
|
||||
|
||||
public function GetLastModified() : int
|
||||
{
|
||||
return $this->iLastModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array : main stylesheets paths + included files paths
|
||||
*/
|
||||
public function GetAllStylesheetPaths(): array
|
||||
{
|
||||
return $this->aAllStylesheetFilePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string : last found stylesheet URI
|
||||
*/
|
||||
public function GetLastStyleSheetPath(): string
|
||||
{
|
||||
return $this->sLastStyleSheetPath;
|
||||
}
|
||||
|
||||
public function AddStylesheet(string $sStylesheetFileURI, string $sStylesheetFilePath): void
|
||||
{
|
||||
$this->aStylesheetFileURIs[] = $sStylesheetFileURI;
|
||||
$this->aAllStylesheetFilePaths[] = $sStylesheetFilePath;
|
||||
$this->sLastStyleSheetPath = $sStylesheetFilePath;
|
||||
}
|
||||
|
||||
public function AlreadyFetched(string $sStylesheetFilePath) : bool {
|
||||
return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths);
|
||||
}
|
||||
|
||||
public function AddImport(string $sStylesheetFileURI, string $sStylesheetFilePath): void
|
||||
{
|
||||
$this->aStylesheetImportPaths[$sStylesheetFileURI] = $sStylesheetFilePath;
|
||||
$this->aAllStylesheetFilePaths[] = $sStylesheetFilePath;
|
||||
}
|
||||
|
||||
public function UpdateLastModified(string $sStylesheetFile): void
|
||||
{
|
||||
$this->iLastModified = max($this->iLastModified, @filemtime($sStylesheetFile));
|
||||
}
|
||||
|
||||
public function ResetLastStyleSheet(): void
|
||||
{
|
||||
$this->sLastStyleSheetPath = "";
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
* Helper class to build interactive forms to be used either in stand-alone
|
||||
* modal dialog or in "property-sheet" panes.
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
class DesignerForm
|
||||
@@ -102,19 +102,23 @@ class DesignerForm
|
||||
$sReturn .= '<fieldset>';
|
||||
$sReturn .= '<legend>'.$sLabel.'</legend>';
|
||||
}
|
||||
foreach($aFields as $oField) {
|
||||
foreach($aFields as $oField)
|
||||
{
|
||||
$aRow = $oField->Render($oP, $sFormId);
|
||||
if ($oField->IsVisible()) {
|
||||
$sValidation = '<span class="prop_apply ibo-prop--apply">'.$this->GetValidationArea($oField->GetFieldId()).'</span>';
|
||||
if ($oField->IsVisible())
|
||||
{
|
||||
$sValidation = ' <span class="prop_apply">'.$this->GetValidationArea($oField->GetFieldId()).'</span>';
|
||||
$sField = $aRow['value'].$sValidation;
|
||||
$aDetails[] = array('label' => $aRow['label'], 'value' => $sField);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHiddenFields .= $aRow['value'];
|
||||
}
|
||||
}
|
||||
$sReturn .= $oP->GetDetails($aDetails);
|
||||
|
||||
if ($sLabel != '') {
|
||||
if ($sLabel != '')
|
||||
{
|
||||
$sReturn .= '</fieldset>';
|
||||
}
|
||||
}
|
||||
@@ -226,18 +230,18 @@ class DesignerForm
|
||||
if ($oField->IsVisible())
|
||||
{
|
||||
$sFieldId = $this->GetFieldId($oField->GetCode());
|
||||
$sValidation = $this->GetValidationArea($sFieldId, '<span data-tooltip-content="Apply"><i class="fas fa-check"></i></span>');
|
||||
$sValidationFields = '</td><td class="prop_icon prop_apply ibo-prop--apply">'.$sValidation.'</td><td class="prop_icon prop_cancel ibo-prop--cancel"><span data-tooltip-content="Revert"><i class="fas fa-times"></i></span></td>'.$this->EndRow();
|
||||
$sValidation = $this->GetValidationArea($sFieldId, '<span title="Apply" class="ui-icon ui-icon-circle-check"/>');
|
||||
$sValidationFields = '</td><td class="prop_icon prop_apply">'.$sValidation.'</td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td>'.$this->EndRow();
|
||||
|
||||
$sPath = $this->GetHierarchyPath().'/'.$oField->GetCode();
|
||||
|
||||
if (is_null($aRow['label']))
|
||||
{
|
||||
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_value ibo-field--value" colspan="2">'.$aRow['value'];
|
||||
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_value" colspan="2">'.$aRow['value'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_label ibo-field--label">'.$aRow['label'].'</td><td class="prop_value ibo-field--value">'.$aRow['value'];
|
||||
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_label">'.$aRow['label'].'</td><td class="prop_value">'.$aRow['value'];
|
||||
}
|
||||
if (!($oField instanceof DesignerFormSelectorField) && !($oField instanceof DesignerMultipleSubFormField))
|
||||
{
|
||||
@@ -262,7 +266,6 @@ class DesignerForm
|
||||
$this->AddReadyScript(
|
||||
<<<EOF
|
||||
$('#row_$sFieldId').$sWidgetClass({parent_selector: $sNotifyParentSelectorJS, field_id: '$sFieldId', equals: $sHandlerEquals, get_field_value: $sHandlerGetValue, auto_apply: $sAutoApply, value: '', submit_to: '$sActionUrl', submit_parameters: $sJSSubmitParams $sJSExtraParams });
|
||||
CombodoTooltip.InitTooltipFromMarkup($('#$sFormId [data-tooltip-content]'));
|
||||
EOF
|
||||
);
|
||||
}
|
||||
@@ -288,6 +291,7 @@ EOF
|
||||
}
|
||||
$this->AddReadyScript(
|
||||
<<<EOF
|
||||
$('.prop_table').tableHover();
|
||||
var idx = 0;
|
||||
$('.prop_table tbody tr').each(function() {
|
||||
if ((idx % 2) == 0)
|
||||
@@ -544,7 +548,7 @@ EOF
|
||||
|
||||
public function GetValidationArea($sId, $sContent = '')
|
||||
{
|
||||
return "<span id=\"v_{$sId}\">$sContent</span>";
|
||||
return "<span style=\"display:inline-block;width:20px;\" id=\"v_{$sId}\"><span class=\"ui-icon ui-icon-alert\"></span>$sContent</span>";
|
||||
}
|
||||
public function GetAsyncActionClass()
|
||||
{
|
||||
@@ -712,7 +716,7 @@ class DesignerFormField
|
||||
$this->bMandatory = false;
|
||||
$this->bReadOnly = false;
|
||||
$this->bAutoApply = false;
|
||||
$this->aCSSClasses = array('ibo-input');
|
||||
$this->aCSSClasses = array();
|
||||
$this->bDisplayed = true;
|
||||
$this->aWidgetExtraParams = array();
|
||||
}
|
||||
@@ -1016,10 +1020,10 @@ class DesignerTextField extends DesignerFormField
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
|
||||
{
|
||||
var myTimer = null;
|
||||
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
}
|
||||
EOF
|
||||
);
|
||||
@@ -1051,12 +1055,6 @@ EOF
|
||||
|
||||
class DesignerLongTextField extends DesignerTextField
|
||||
{
|
||||
public function __construct($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
$this->aCSSClasses[] = 'ibo-input-text';
|
||||
}
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
@@ -1080,10 +1078,10 @@ class DesignerLongTextField extends DesignerTextField
|
||||
{
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
|
||||
{
|
||||
var myTimer = null;
|
||||
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
}
|
||||
EOF
|
||||
);
|
||||
@@ -1131,10 +1129,10 @@ class DesignerIntegerField extends DesignerFormField
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').on('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, $(this).closest('form').attr('id'), $sMin, $sMax); } );
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, $(this).closest('form').attr('id'), $sMin, $sMax); } );
|
||||
{
|
||||
var myTimer = null;
|
||||
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
}
|
||||
EOF
|
||||
);
|
||||
@@ -1180,7 +1178,6 @@ class DesignerComboField extends DesignerFormField
|
||||
$this->bMultipleSelection = false;
|
||||
$this->bOtherChoices = false;
|
||||
$this->sNullLabel = Dict::S('UI:SelectOne');
|
||||
$this->aCSSClasses[] = 'ibo-input-select';
|
||||
|
||||
$this->bAutoApply = true;
|
||||
$this->bSorted = true; // Sorted by default
|
||||
@@ -1295,12 +1292,11 @@ class DesignerComboField extends DesignerFormField
|
||||
}
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').on('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', $(this).closest('form').attr('id'), null, null); } );
|
||||
$('#$sId').bind('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', $(this).closest('form').attr('id'), null, null); } );
|
||||
EOF
|
||||
);
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sHtml);
|
||||
|
||||
}
|
||||
|
||||
public function ReadParam(&$aValues)
|
||||
@@ -1319,7 +1315,6 @@ class DesignerBooleanField extends DesignerFormField
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
$this->bAutoApply = true;
|
||||
$this->aCSSClasses[] = 'ibo-input-checkbox';
|
||||
}
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
@@ -1602,7 +1597,6 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
$this->defaultRealValue = $defaultValue;
|
||||
$this->aSubForms = array();
|
||||
$this->bSorted = true;
|
||||
$this->aCSSClasses[] = 'ibo-input-select';
|
||||
}
|
||||
|
||||
public function IsSorted()
|
||||
@@ -1736,7 +1730,7 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
{
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').on('change reverted', function() { $('.subform_{$sId}').hide(); $('.{$sId}_'+this.value).show(); } );
|
||||
$('#$sId').bind('change reverted', function() { $('.subform_{$sId}').hide(); $('.{$sId}_'+this.value).show(); } );
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Persistent class InputOutputTask
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,7 @@ class InputOutputTask extends cmdbAbstractObject
|
||||
"db_table" => "priv_iotask",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,57 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/iTopWizardWebPage.php
|
||||
* Class iTopWizardWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
|
||||
require_once('itopwebpage.class.inc.php');
|
||||
/**
|
||||
* Web page to display a wizard in the iTop framework
|
||||
*/
|
||||
class iTopWizardWebPage extends iTopWebPage
|
||||
{
|
||||
var $m_iCurrentStep;
|
||||
var $m_aSteps;
|
||||
public function __construct($sTitle, $currentOrganization, $iCurrentStep, $aSteps)
|
||||
{
|
||||
parent::__construct($sTitle." - step $iCurrentStep of ".count($aSteps)." - ".$aSteps[$iCurrentStep - 1], $currentOrganization);
|
||||
$this->m_iCurrentStep = $iCurrentStep;
|
||||
$this->m_aSteps = $aSteps;
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$aSteps = array();
|
||||
$iIndex = 0;
|
||||
foreach($this->m_aSteps as $sStepTitle)
|
||||
{
|
||||
$iIndex++;
|
||||
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
|
||||
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
|
||||
}
|
||||
$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();
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Class LoginBasic
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* Class LoginExternal
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -224,7 +224,7 @@ class LoginTwigRenderer
|
||||
}
|
||||
|
||||
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
|
||||
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password');
|
||||
$aCoreTemplatesPaths = array('login', 'login/password');
|
||||
// Having this path declared after the plugins let the plugins replace the core templates
|
||||
$oCoreLoader->setPaths($aCoreTemplatesPaths);
|
||||
// Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/**
|
||||
* Class LoginURL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Class LoginWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -92,6 +92,7 @@ class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/login.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css');
|
||||
}
|
||||
|
||||
public static function SetLoginFailedMessage($sMessage)
|
||||
@@ -99,44 +100,6 @@ class LoginWebPage extends NiceWebPage
|
||||
self::$m_sLoginFailedMessage = $sMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $oUser
|
||||
* @param array $aProfiles
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public static function SynchronizeProfiles(&$oUser, array $aProfiles, $sOrigin)
|
||||
{
|
||||
$oProfilesSet = $oUser->Get(‘profile_list’);
|
||||
//delete old profiles
|
||||
$aExistingProfiles = [];
|
||||
while ($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
array_push($aExistingProfiles, $oProfile->Get('profileid'));
|
||||
$iArrayKey = array_search($oProfile->Get('profileid'), $aProfiles);
|
||||
if (!$iArrayKey)
|
||||
{
|
||||
$oProfilesSet->RemoveItem($oProfile->Get('profileid'));
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($aProfiles[$iArrayKey]);
|
||||
}
|
||||
}
|
||||
//add profiles not already linked with user
|
||||
foreach ($aProfiles as $iProfileId)
|
||||
{
|
||||
$oLink = new URP_UserProfile();
|
||||
$oLink->Set('profileid', $iProfileId);
|
||||
$oLink->Set('reason', $sOrigin);
|
||||
|
||||
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', array('profileid' => $iProfileId, 'reason' => $sOrigin)));
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
}
|
||||
|
||||
public function DisplayLoginHeader($bMainAppLogo = false)
|
||||
{
|
||||
$sLogo = 'itop-logo-external.png';
|
||||
@@ -923,12 +886,20 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
|
||||
// Now synchronize the profiles
|
||||
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
|
||||
$sOrigin = 'External User provisioning';
|
||||
if (isset($_SESSION['login_mode']))
|
||||
{
|
||||
$sOrigin .= " ({$_SESSION['login_mode']})";
|
||||
}
|
||||
$aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin);
|
||||
foreach ($aProfiles as $iProfileId)
|
||||
{
|
||||
$oLink = new URP_UserProfile();
|
||||
$oLink->Set('profileid', $iProfileId);
|
||||
$oLink->Set('reason', $sOrigin);
|
||||
$oProfilesSet->AddObject($oLink);
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
if ($oUser->IsModified())
|
||||
{
|
||||
$oUser->DBWrite();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/application/template.class.inc.php');
|
||||
require_once(APPROOT."/application/user.dashboard.class.inc.php");
|
||||
@@ -53,10 +51,7 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
|
||||
* new OQLMenuNode('PersonsMenu', 'SELECT bizPerson', $oContactsMenu->GetIndex(), 0);
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class ApplicationMenu
|
||||
*/
|
||||
|
||||
class ApplicationMenu
|
||||
{
|
||||
/**
|
||||
@@ -76,10 +71,7 @@ class ApplicationMenu
|
||||
*/
|
||||
static $sFavoriteSiloQuery = 'SELECT Organization';
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public static function LoadAdditionalMenus()
|
||||
static public function LoadAdditionalMenus()
|
||||
{
|
||||
if (!self::$bAdditionalMenusLoaded)
|
||||
{
|
||||
@@ -105,10 +97,10 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Set the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @param string $sOQL The OQL query returning a list of Organization objects
|
||||
* @param $sOQL string The OQL query returning a list of Organization objects
|
||||
* @return void
|
||||
*/
|
||||
public static function SetFavoriteSiloQuery($sOQL)
|
||||
static public function SetFavoriteSiloQuery($sOQL)
|
||||
{
|
||||
self::$sFavoriteSiloQuery = $sOQL;
|
||||
}
|
||||
@@ -117,7 +109,7 @@ class ApplicationMenu
|
||||
* 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
|
||||
*/
|
||||
public static function GetFavoriteSiloQuery()
|
||||
static public function GetFavoriteSiloQuery()
|
||||
{
|
||||
return self::$sFavoriteSiloQuery;
|
||||
}
|
||||
@@ -125,11 +117,11 @@ class ApplicationMenu
|
||||
/**
|
||||
* Check whether a menu Id is enabled or not
|
||||
*
|
||||
* @param string $sMenuId
|
||||
* @param $sMenuId
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function CheckMenuIdEnabled($sMenuId)
|
||||
static public function CheckMenuIdEnabled($sMenuId)
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
|
||||
@@ -148,11 +140,11 @@ class ApplicationMenu
|
||||
* Main function to add a menu entry into the application, can be called during the definition
|
||||
* of the data model objects
|
||||
* @param MenuNode $oMenuNode
|
||||
* @param int $iParentIndex
|
||||
* @param float $fRank
|
||||
* @param $iParentIndex
|
||||
* @param $fRank
|
||||
* @return int
|
||||
*/
|
||||
public static function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
|
||||
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
|
||||
{
|
||||
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
|
||||
if ($index == -1)
|
||||
@@ -193,154 +185,20 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Reflection API - Get menu entries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function ReflectionMenuNodes()
|
||||
static public function ReflectionMenuNodes()
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
return self::$aMenusIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entries count for all the menus
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return array
|
||||
* @throws \DictExceptionMissingString
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetMenusCount($aExtraParams = array())
|
||||
{
|
||||
$aMenuGroups = static::GetMenuGroups($aExtraParams);
|
||||
|
||||
$aMenusCount = [];
|
||||
foreach ($aMenuGroups as $aMenuGroup) {
|
||||
$aSubMenuNodes = $aMenuGroup['aSubMenuNodes'];
|
||||
$aMenusCount = array_merge($aMenusCount, static::GetSubMenusCount($aSubMenuNodes));
|
||||
}
|
||||
|
||||
return $aMenusCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recurse sub menus for counts
|
||||
*
|
||||
* @param array $aSubMenuNodes
|
||||
*
|
||||
* @return array
|
||||
* @since 3.0.0
|
||||
*/
|
||||
private static function GetSubMenusCount(array $aSubMenuNodes)
|
||||
{
|
||||
$aSubMenusCount = [];
|
||||
foreach ($aSubMenuNodes as $aSubMenuNode) {
|
||||
if ($aSubMenuNode['bHasCount']) {
|
||||
$oMenuNode = static::GetMenuNode(static::GetMenuIndexById($aSubMenuNode['sId']));
|
||||
$aSubMenusCount[$aSubMenuNode['sId']] = $oMenuNode->GetEntriesCount();
|
||||
}
|
||||
$aSubMenusCount = array_merge($aSubMenusCount, static::GetSubMenusCount($aSubMenuNode['aSubMenuNodes']));
|
||||
}
|
||||
return $aSubMenusCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of menu groups
|
||||
*
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return array
|
||||
* @throws \DictExceptionMissingString
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetMenuGroups($aExtraParams = array())
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
|
||||
// Sort the root menu based on the rank
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
|
||||
$aMenuGroups = [];
|
||||
foreach(static::$aRootMenus as $aMenuGroup)
|
||||
{
|
||||
if(!static::CanDisplayMenu($aMenuGroup))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$sMenuGroupIdx = $aMenuGroup['index'];
|
||||
/** @var \MenuGroup $oMenuNode */
|
||||
$oMenuNode = static::GetMenuNode($sMenuGroupIdx);
|
||||
|
||||
$aMenuGroups[] = [
|
||||
'sId' => $oMenuNode->GetMenuID(),
|
||||
'sIconCssClasses' => $oMenuNode->GetDecorationClasses(),
|
||||
'sInitials' => $oMenuNode->GetInitials(),
|
||||
'sTitle' => $oMenuNode->GetTitle(),
|
||||
'aSubMenuNodes' => static::GetSubMenuNodes($sMenuGroupIdx, $aExtraParams),
|
||||
];
|
||||
}
|
||||
|
||||
return $aMenuGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of sub-menu nodes for $sMenuGroupIdx
|
||||
*
|
||||
* @param string $sMenuGroupIdx
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return array
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetSubMenuNodes($sMenuGroupIdx, $aExtraParams = array())
|
||||
{
|
||||
$aSubMenuItems = self::GetChildren($sMenuGroupIdx);
|
||||
|
||||
// Sort the children based on the rank
|
||||
usort($aSubMenuItems, array('ApplicationMenu', 'CompareOnRank'));
|
||||
|
||||
$aSubMenuNodes = [];
|
||||
foreach($aSubMenuItems as $aSubMenuItem)
|
||||
{
|
||||
if(!static::CanDisplayMenu($aSubMenuItem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$sSubMenuItemIdx = $aSubMenuItem['index'];
|
||||
$oSubMenuNode = static::GetMenuNode($sSubMenuItemIdx);
|
||||
|
||||
if(!$oSubMenuNode->IsEnabled())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$aSubMenuNodes[] = [
|
||||
'sId' => $oSubMenuNode->GetMenuId(),
|
||||
'sTitle' => $oSubMenuNode->GetTitle(),
|
||||
'bHasCount' => $oSubMenuNode->HasCount(),
|
||||
'sUrl' => $oSubMenuNode->GetHyperlink($aExtraParams),
|
||||
'bOpenInNewWindow' => $oSubMenuNode->IsHyperLinkInNewWindow(),
|
||||
'aSubMenuNodes' => static::GetSubMenuNodes($sSubMenuItemIdx, $aExtraParams),
|
||||
];
|
||||
}
|
||||
|
||||
return $aSubMenuNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point to display the whole menu into the web page, used by iTopWebPage
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param $aExtraParams
|
||||
* @throws DictExceptionMissingString
|
||||
*
|
||||
* @deprecated Will be removed in 3.0.0, use static::GetMenuGroups() instead
|
||||
*/
|
||||
public static function DisplayMenu($oPage, $aExtraParams)
|
||||
static public function DisplayMenu($oPage, $aExtraParams)
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
// Sort the root menu based on the rank
|
||||
@@ -379,7 +237,7 @@ EOF
|
||||
* @param array $aMenu menu entry
|
||||
* @return bool true if at least one menu is enabled
|
||||
*/
|
||||
private static function CanDisplayMenu($aMenu)
|
||||
static private function CanDisplayMenu($aMenu)
|
||||
{
|
||||
$oMenuNode = self::GetMenuNode($aMenu['index']);
|
||||
if ($oMenuNode->IsEnabled())
|
||||
@@ -411,12 +269,11 @@ EOF
|
||||
* @param array $aExtraParams
|
||||
* @param int $iActiveMenu
|
||||
*
|
||||
* @return bool True if the currently selected menu is one of the submenus
|
||||
* @return true if the currently selected menu is one of the submenus
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws \Exception
|
||||
* @deprecated Will be removed in 3.0.0, use static::GetSubMenuNodes() instead
|
||||
*/
|
||||
protected static function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
|
||||
static protected function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
|
||||
{
|
||||
// Sort the menu based on the rank
|
||||
$bActive = false;
|
||||
@@ -473,11 +330,11 @@ EOF
|
||||
|
||||
/**
|
||||
* Helper function to sort the menus based on their rank
|
||||
* @param array $a
|
||||
* @param array $b
|
||||
* @param $a
|
||||
* @param $b
|
||||
* @return int
|
||||
*/
|
||||
public static function CompareOnRank($a, $b)
|
||||
static public function CompareOnRank($a, $b)
|
||||
{
|
||||
$result = 1;
|
||||
if ($a['rank'] == $b['rank'])
|
||||
@@ -496,7 +353,7 @@ EOF
|
||||
* @param int $index
|
||||
* @return MenuNode|null
|
||||
*/
|
||||
public static function GetMenuNode($index)
|
||||
static public function GetMenuNode($index)
|
||||
{
|
||||
return isset(self::$aMenusIndex[$index]) ? self::$aMenusIndex[$index]['node'] : null;
|
||||
}
|
||||
@@ -506,7 +363,7 @@ EOF
|
||||
* @param int $index
|
||||
* @return array
|
||||
*/
|
||||
public static function GetChildren($index)
|
||||
static public function GetChildren($index)
|
||||
{
|
||||
return self::$aMenusIndex[$index]['children'];
|
||||
}
|
||||
@@ -516,7 +373,7 @@ EOF
|
||||
* @param string $sTitle Title of the menu (as passed when creating the menu)
|
||||
* @return integer ID of the menu, or -1 if not found
|
||||
*/
|
||||
public static function GetMenuIndexById($sTitle)
|
||||
static public function GetMenuIndexById($sTitle)
|
||||
{
|
||||
$index = -1;
|
||||
/** @var MenuNode[] $aMenu */
|
||||
@@ -535,7 +392,7 @@ EOF
|
||||
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
|
||||
* @return string The Id of the currently active menu
|
||||
*/
|
||||
public static function GetActiveNodeId()
|
||||
static public function GetActiveNodeId()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
@@ -549,7 +406,7 @@ EOF
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public static function GetDefaultMenuId()
|
||||
static public function GetDefaultMenuId()
|
||||
{
|
||||
static $sDefaultMenuId = null;
|
||||
if (is_null($sDefaultMenuId))
|
||||
@@ -569,7 +426,7 @@ EOF
|
||||
* @param $sMenuId
|
||||
* @return string
|
||||
*/
|
||||
public static function GetRootMenuId($sMenuId)
|
||||
static public function GetRootMenuId($sMenuId)
|
||||
{
|
||||
$iMenuIndex = self::GetMenuIndexById($sMenuId);
|
||||
if ($iMenuIndex == -1)
|
||||
@@ -706,95 +563,29 @@ abstract class MenuNode
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws DictExceptionMissingString
|
||||
*/
|
||||
public function GetTitle()
|
||||
{
|
||||
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the page corresponding to this menu node is countable
|
||||
*
|
||||
* @return bool true if corresponding page is countable
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function HasCount()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function GetEntriesCountFromOQL(string $sOQL)
|
||||
{
|
||||
// Count the entries up to 99
|
||||
$oSearch = DBSearch::FromOQL($sOQL);
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClass = $oSearch->GetClass();
|
||||
foreach ($oAppContext->GetNames() as $key) {
|
||||
// Find the value of the object corresponding to each 'context' parameter
|
||||
$aCallSpec = [$sClass, 'MapContextParam'];
|
||||
$sAttCode = '';
|
||||
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)) {
|
||||
// Add Hierarchical condition if hierarchical key
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if (isset($oAttDef) && ($oAttDef->IsExternalKey())) {
|
||||
$iDefaultValue = intval($oAppContext->GetCurrentValue($key));
|
||||
if ($iDefaultValue != 0) {
|
||||
try {
|
||||
/** @var AttributeExternalKey $oAttDef */
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass);
|
||||
if ($sHierarchicalKeyCode !== false) {
|
||||
$oFilter = new DBObjectSearch($sTargetClass);
|
||||
$oFilter->AddCondition('id', $iDefaultValue);
|
||||
$oHKFilter = new DBObjectSearch($sTargetClass);
|
||||
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
|
||||
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// If filtering fails just ignore it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$iCount = $oSet->CountWithLimit(99);
|
||||
if ($iCount > 99) {
|
||||
$iCount = "99+";
|
||||
}
|
||||
|
||||
return $iCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of entries of the page corresponding to this menu item.
|
||||
*
|
||||
* @return int the number of entries
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetEntriesCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws DictExceptionMissingString
|
||||
*/
|
||||
public function GetLabel()
|
||||
{
|
||||
$sRet = Dict::S("Menu:$this->sMenuId+", "");
|
||||
if ($sRet === '') {
|
||||
if ($this->iParentIndex != -1) {
|
||||
if ($sRet === '')
|
||||
{
|
||||
if ($this->iParentIndex != -1)
|
||||
{
|
||||
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
|
||||
$sRet = $oParentMenu->GetTitle().' / '.$this->GetTitle();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRet = $this->GetTitle();
|
||||
}
|
||||
//$sRet = $this->GetTitle();
|
||||
@@ -809,10 +600,7 @@ abstract class MenuNode
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
||||
public function PopulateChildMenus()
|
||||
{
|
||||
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu)
|
||||
@@ -937,64 +725,18 @@ abstract class MenuNode
|
||||
*/
|
||||
class MenuGroup extends MenuNode
|
||||
{
|
||||
/** @var string DEFAULT_DECORATION_CLASSES Set to null by default so it is replaced by initials when none is specified */
|
||||
const DEFAULT_DECORATION_CLASSES = null;
|
||||
|
||||
/** @var string The CSS classes used to display the menu group's icon */
|
||||
protected $sDecorationClasses = self::DEFAULT_DECORATION_CLASSES;
|
||||
|
||||
/**
|
||||
* Create a top-level menu group and inserts it into the application's main menu
|
||||
*
|
||||
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
|
||||
* @param float $fRank Number used to order the list, the groups are sorted based on this value
|
||||
* @param string|null $sDecorationClasses CSS classes used to display the menu group's icon
|
||||
* @param string $sEnableClass Name of class of object
|
||||
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
|
||||
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
|
||||
* @param string $sEnableStimulus
|
||||
*/
|
||||
public function __construct($sMenuId, $fRank, $sDecorationClasses = null, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
public function __construct($sMenuId, $fRank, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
{
|
||||
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
|
||||
if(!empty($sDecorationClasses))
|
||||
{
|
||||
$this->sDecorationClasses = $sDecorationClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the menu group has some decoration classes
|
||||
*
|
||||
* @return bool
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function HasDecorationClasses()
|
||||
{
|
||||
return (empty($this->GetDecorationClasses()) === false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSS classes used for decorating the menu group (typically the icon in the navigation menu)
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetDecorationClasses()
|
||||
{
|
||||
return $this->sDecorationClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initials of the menu group, used by the rendering in case there is no decoration classes
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function GetInitials()
|
||||
{
|
||||
return mb_substr($this->GetTitle(), 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1171,43 +913,30 @@ class OQLMenuNode extends MenuNode
|
||||
{
|
||||
$sUsageId = utils::GetSafeId($sUsageId);
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
//$sIcon = MetaModel::GetClassIcon($oSearch->GetClass(), false);
|
||||
$sIcon = MetaModel::GetClassIcon($oSearch->GetClass());
|
||||
|
||||
if ($bSearchPane) {
|
||||
if ($bSearchPane)
|
||||
{
|
||||
$aParams = array_merge(array('open' => $bSearchOpen, 'table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 0);
|
||||
}
|
||||
|
||||
//$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
|
||||
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
|
||||
$oTitle = TitleUIBlockFactory::MakeForPage($sTitle);
|
||||
$oPage->AddUiBlock($oTitle);
|
||||
|
||||
|
||||
$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
|
||||
|
||||
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, $sUsageId);
|
||||
|
||||
$oPage->add("</div>");
|
||||
|
||||
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage)) {
|
||||
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage))
|
||||
{
|
||||
// Breadcrumb
|
||||
//$iCount = $oBlock->GetDisplayedCount();
|
||||
$sPageId = "ui-search-".$oSearch->GetClass();
|
||||
$sLabel = MetaModel::GetName($oSearch->GetClass());
|
||||
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', 'fas fa-list', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', '../images/breadcrumb-search.png');
|
||||
}
|
||||
}
|
||||
|
||||
public function HasCount()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function GetEntriesCount()
|
||||
{
|
||||
return $this->GetEntriesCountFromOQL($this->sOQL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1252,7 +981,7 @@ class SearchMenuNode extends MenuNode
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
|
||||
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
|
||||
|
||||
$oSearch = new DBObjectSearch($this->sClass);
|
||||
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
|
||||
@@ -1462,32 +1191,40 @@ class DashboardMenuNode extends MenuNode
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
|
||||
$oPage->add('<div id="'.$sDivId.'" class="ibo-dashboard" data-role="ibo-dashboard">');
|
||||
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
|
||||
$aExtraParams['dashboard_div_id'] = $sDivId;
|
||||
$aExtraParams['from_dashboard_page'] = true;
|
||||
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
|
||||
$oDashboard->Render($oPage, false, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
|
||||
$bEdit = utils::ReadParam('edit', false);
|
||||
if ($bEdit) {
|
||||
if ($bEdit)
|
||||
{
|
||||
$sId = addslashes($this->sMenuId);
|
||||
$oPage->add_ready_script("EditDashboard('$sId');");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
|
||||
$sParentTitle = $oParentMenu->GetTitle();
|
||||
$sThisTitle = $this->GetTitle();
|
||||
if ($sParentTitle != $sThisTitle) {
|
||||
if ($sParentTitle != $sThisTitle)
|
||||
{
|
||||
$sDescription = $sParentTitle.' / '.$sThisTitle;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDescription = $sThisTitle;
|
||||
}
|
||||
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId()) {
|
||||
$sIcon = 'fas fa-home';
|
||||
} else {
|
||||
$sIcon = 'fas fa-chart-pie';
|
||||
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId())
|
||||
{
|
||||
$sIcon = '../images/breadcrumb_home.png';
|
||||
}
|
||||
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon, iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
else
|
||||
{
|
||||
$sIcon = '../images/breadcrumb-dashboard.png';
|
||||
}
|
||||
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1656,23 +1393,5 @@ class ShortcutMenuNode extends MenuNode
|
||||
{
|
||||
return $this->oShortcut->Get('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the page corresponding to this menu node is countable
|
||||
*
|
||||
* @return bool true if corresponding page is countable
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function HasCount()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function GetEntriesCount()
|
||||
{
|
||||
return $this->GetEntriesCountFromOQL($this->oShortcut->Get('oql'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
|
||||
@@ -1,7 +1,262 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/NiceWebPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
/**
|
||||
* Web page with some associated CSS and scripts (jquery) for a fancier display
|
||||
*/
|
||||
class NiceWebPage extends WebPage
|
||||
{
|
||||
var $m_aReadyScripts;
|
||||
var $m_sRootUrl;
|
||||
|
||||
public function __construct($s_title, $bPrintable = false)
|
||||
{
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
$this->m_aReadyScripts = array();
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.min.js');
|
||||
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.dev.js');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.prod.min.js');
|
||||
}
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/hovertip.js');
|
||||
// table sorting
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.popupmenu.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/searchformforeignkeys.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/latinise/latinise.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler_history.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_raw.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_string.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_time.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboard.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboardwidget.js');
|
||||
|
||||
$this->add_dict_entries('UI:Combo');
|
||||
|
||||
$this->add_ready_script(
|
||||
<<< EOF
|
||||
//add new widget called TruncatedList to properly display truncated lists when they are sorted
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "truncatedList",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Check if there is a "truncated" line
|
||||
this.truncatedList = false;
|
||||
if ($("tr td.truncated",table).length > 0)
|
||||
{
|
||||
this.truncatedList = true;
|
||||
}
|
||||
if (this.truncatedList)
|
||||
{
|
||||
$("tr td",table).removeClass('truncated');
|
||||
$("tr:last td",table).addClass('truncated');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "myZebra",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
|
||||
$("tbody tr:even",table).addClass('even');
|
||||
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
|
||||
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
|
||||
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
|
||||
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
|
||||
$("tbody tr:odd",table).removeClass('even');
|
||||
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
|
||||
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
|
||||
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
|
||||
}
|
||||
});
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
EOF
|
||||
);
|
||||
$this->LoadTheme();
|
||||
|
||||
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
|
||||
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
|
||||
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
|
||||
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
|
||||
|
||||
$sAppContext = addslashes($this->GetApplicationContext());
|
||||
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return '$sAbsURLModulesRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulePage(sModule, sPage, aArguments)
|
||||
{
|
||||
// aArguments is optional, it default to an empty hash
|
||||
aArguments = typeof aArguments !== 'undefined' ? aArguments : {};
|
||||
|
||||
var sUrl = '$sAbsURLAppRoot'+'pages/exec.php?exec_module='+sModule+'&exec_page='+sPage+'&exec_env='+'$sEnvironment';
|
||||
for (var sArgName in aArguments)
|
||||
{
|
||||
if (aArguments.hasOwnProperty(sArgName))
|
||||
{
|
||||
sUrl = sUrl + '&'+sArgName+'='+aArguments[sArgname];
|
||||
}
|
||||
}
|
||||
return sUrl;
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function SetRootUrl($sRootUrl)
|
||||
{
|
||||
$this->m_sRootUrl = $sRootUrl;
|
||||
}
|
||||
|
||||
public function small_p($sText)
|
||||
{
|
||||
$this->add("<p style=\"font-size:smaller\">$sText</p>\n");
|
||||
}
|
||||
|
||||
public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return utils::GetAbsoluteUrlAppRoot();
|
||||
}
|
||||
|
||||
public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot();
|
||||
}
|
||||
|
||||
function GetApplicationContext()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
return $oAppContext->GetForLink();
|
||||
}
|
||||
|
||||
// By Rom, used by CSVImport and Advanced search
|
||||
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
|
||||
{
|
||||
// $aTopLevelClasses = array('bizService', 'bizContact', 'logInfra', 'bizDocument');
|
||||
// These are classes wich root class is cmdbAbstractObject !
|
||||
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
|
||||
$aValidClasses = array();
|
||||
foreach(MetaModel::GetClasses('bizmodel') as $sClassName)
|
||||
{
|
||||
if (is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode))
|
||||
{
|
||||
$sSelected = ($sClassName == $sDefaultValue) ? " SELECTED" : "";
|
||||
$sDescription = MetaModel::GetClassDescription($sClassName);
|
||||
$sDisplayName = MetaModel::GetName($sClassName);
|
||||
$aValidClasses[$sDisplayName] = "<option style=\"width: ".$iWidthPx." px;\" title=\"$sDescription\" value=\"$sClassName\"$sSelected>$sDisplayName</option>";
|
||||
}
|
||||
}
|
||||
ksort($aValidClasses);
|
||||
$this->add(implode("\n", $aValidClasses));
|
||||
|
||||
$this->add("</select>");
|
||||
}
|
||||
|
||||
// By Rom, used by Advanced search
|
||||
public function add_select($aChoices, $sName, $sDefaultValue, $iWidthPx)
|
||||
{
|
||||
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
|
||||
foreach($aChoices as $sKey => $sValue)
|
||||
{
|
||||
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
|
||||
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue,
|
||||
ENT_QUOTES, self::PAGES_CHARSET)."</option>");
|
||||
}
|
||||
$this->add("</select>");
|
||||
}
|
||||
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_aReadyScripts[] = $sScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs (via some echo) the complete HTML page by assembling all its elements
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
//$this->set_base($this->m_sRootUrl.'pages/');
|
||||
if (count($this->m_aReadyScripts)>0)
|
||||
{
|
||||
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");
|
||||
}
|
||||
parent::output();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @since 2.7.0
|
||||
*/
|
||||
protected function LoadTheme()
|
||||
{
|
||||
$sCssThemeUrl = ThemeHandler::GetCurrentThemeUrl();
|
||||
$this->add_linked_stylesheet($sCssThemeUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,248 @@
|
||||
<?php
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/PDFPage.php
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2019 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'application/utils.inc.php');
|
||||
|
||||
/**
|
||||
* Custom class derived from TCPDF for providing custom headers and footers
|
||||
*
|
||||
* @author denis
|
||||
*
|
||||
*/
|
||||
class iTopPDF extends TCPDF
|
||||
{
|
||||
protected $sDocumentTitle;
|
||||
|
||||
/**
|
||||
* Shortcut for {@link TCPDF::SetFont}, to use the font configured
|
||||
*
|
||||
* @param string $style
|
||||
* @param int $size
|
||||
* @param string $fontfile
|
||||
* @param string $subset
|
||||
* @param bool $out
|
||||
*
|
||||
* @uses \TCPDF::SetFont()
|
||||
* @uses \iTopPDF::GetPdfFont()
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public function SetFontParams($style, $size, $fontfile='', $subset='default', $out=true)
|
||||
{
|
||||
$siTopFont = self::GetPdfFont();
|
||||
$this->SetFont($siTopFont, $style, $size, $fontfile, $subset, $out);
|
||||
}
|
||||
|
||||
public function SetDocumentTitle($sDocumentTitle)
|
||||
{
|
||||
$this->sDocumentTitle = $sDocumentTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the custom header. Called for each new page.
|
||||
*
|
||||
* @see TCPDF::Header()
|
||||
*/
|
||||
public function Header()
|
||||
{
|
||||
// Title
|
||||
// Set font
|
||||
$this->SetFontParams('B', 10);
|
||||
|
||||
$iPageNumberWidth = 25;
|
||||
$aMargins = $this->getMargins();
|
||||
|
||||
// Display the title (centered)
|
||||
$this->SetXY($aMargins['left'] + $iPageNumberWidth, 0);
|
||||
$this->MultiCell($this->getPageWidth() - $aMargins['left'] - $aMargins['right'] - 2 * $iPageNumberWidth, 15, $this->sDocumentTitle,
|
||||
0, 'C', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
$this->SetFontParams('', 10);
|
||||
|
||||
// Display the page number (right aligned)
|
||||
// Warning: the 'R'ight alignment does not work when using placeholders like $this->getAliasNumPage() or $this->getAliasNbPages()
|
||||
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber', $this->page), 0, 'R', false, 0 /* $ln */, '',
|
||||
'', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
|
||||
// Branding logo
|
||||
$sBrandingIcon = APPROOT.'images/itop-logo.png';
|
||||
if (file_exists(MODULESROOT.'branding/main-logo.png'))
|
||||
{
|
||||
$sBrandingIcon = MODULESROOT.'branding/main-logo.png';
|
||||
}
|
||||
$this->Image($sBrandingIcon, $aMargins['left'], 5, 0, 10);
|
||||
}
|
||||
|
||||
// Page footer
|
||||
public function Footer()
|
||||
{
|
||||
// No footer
|
||||
}
|
||||
|
||||
/**
|
||||
* dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
|
||||
* @return string font in the config file (export_pdf_font)
|
||||
*/
|
||||
public static function GetPdfFont()
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sPdfFont = $oConfig->Get('export_pdf_font');
|
||||
|
||||
return $sPdfFont;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special class of WebPage for printing into a PDF document
|
||||
*/
|
||||
class PDFPage extends WebPage
|
||||
{
|
||||
/** @var \iTopPDF Instance of the TCPDF object for creating the PDF */
|
||||
protected $oPdf;
|
||||
|
||||
public function __construct($s_title, $sPageFormat = 'A4', $sPageOrientation = 'L')
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
define(K_PATH_FONTS, APPROOT.'lib/combodo/tcpdf/fonts');
|
||||
$this->oPdf = new iTopPDF($sPageOrientation, 'mm', $sPageFormat, true, self::PAGES_CHARSET, false);
|
||||
|
||||
// set document information
|
||||
$this->oPdf->SetCreator(PDF_CREATOR);
|
||||
$this->oPdf->SetAuthor('iTop');
|
||||
$this->oPdf->SetTitle($s_title);
|
||||
$this->oPdf->SetDocumentTitle($s_title);
|
||||
|
||||
$this->oPdf->setFontSubsetting(true);
|
||||
|
||||
// dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
|
||||
$this->oPdf->SetFontParams('', 10, '', true);
|
||||
|
||||
// set auto page breaks
|
||||
$this->oPdf->SetAutoPageBreak(true, 15); // 15 mm break margin at the bottom
|
||||
$this->oPdf->SetTopMargin(15);
|
||||
|
||||
// Add a page, we're ready to start
|
||||
$this->oPdf->AddPage();
|
||||
|
||||
$this->SetContentDisposition('inline', $s_title.'.pdf');
|
||||
$this->SetDefaultStyle();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default style (suitable for printing) to be included each time $this->oPdf->writeHTML() is called
|
||||
*/
|
||||
protected function SetDefaultStyle()
|
||||
{
|
||||
$this->add_style(
|
||||
<<<EOF
|
||||
table {
|
||||
padding: 2pt;
|
||||
}
|
||||
table.listResults td {
|
||||
border: 0.5pt solid #000 ;
|
||||
}
|
||||
table.listResults th {
|
||||
background-color: #eee;
|
||||
border: 0.5pt solid #000 ;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
table.section td {
|
||||
vertical-align: middle;
|
||||
font-size: 10pt;
|
||||
background-color:#eee;
|
||||
}
|
||||
td.icon {
|
||||
width: 30px;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access to the underlying TCPDF object
|
||||
*
|
||||
* @return \iTopPDF
|
||||
*/
|
||||
public function get_tcpdf()
|
||||
{
|
||||
$this->flush();
|
||||
|
||||
return $this->oPdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the currently buffered HTML content into the PDF. This can be useful:
|
||||
* - to sync the flow in case you want to access the underlying TCPDF object for some specific/graphic output
|
||||
* - to process the HTML by smaller chunks instead of processing the whole page at once for performance reasons
|
||||
*/
|
||||
public function flush()
|
||||
{
|
||||
if (strlen($this->s_content) > 0)
|
||||
{
|
||||
$sHtml = '';
|
||||
if (count($this->a_styles) > 0)
|
||||
{
|
||||
$sHtml .= "<style>\n".implode("\n", $this->a_styles)."\n</style>\n";
|
||||
}
|
||||
$sHtml .= $this->s_content;
|
||||
$this->oPdf->writeHTML($sHtml); // The style(s) must be supplied each time we call writeHtml
|
||||
$this->s_content = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the page is a PDF page
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_pdf()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the PDF document and returns the PDF content as a string
|
||||
*
|
||||
* @return string
|
||||
* @see WebPage::output()
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$this->add_header('Content-type: application/x-pdf');
|
||||
if (!empty($this->sContentDisposition))
|
||||
{
|
||||
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
|
||||
}
|
||||
foreach ($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
$this->flush();
|
||||
echo $this->oPdf->Output($this->s_title.'.pdf', 'S');
|
||||
}
|
||||
|
||||
public function get_pdf()
|
||||
{
|
||||
$this->flush();
|
||||
|
||||
return $this->oPdf->Output($this->s_title.'.pdf', 'S');
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,33 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Event and derived
|
||||
* Application internal events
|
||||
* There is also a file log
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class Query extends cmdbAbstractObject
|
||||
{
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @since 3.0.0 N°3227 add is_template field for predefined queries
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -35,41 +40,20 @@ abstract class Query extends cmdbAbstractObject
|
||||
"db_table" => "priv_query",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array(
|
||||
"allowed_values" => null,
|
||||
"sql" => "name",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("description", array(
|
||||
"allowed_values" => null,
|
||||
"sql" => "description",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("is_template", array(
|
||||
'allowed_values' => new ValueSetEnum('yes,no'),
|
||||
'sql' => 'is_template',
|
||||
'default_value' => 'no',
|
||||
'is_null_allowed' => false,
|
||||
'depends_on' => [],
|
||||
'display_style' => 'radio_horizontal',
|
||||
)));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details',
|
||||
array('name', 'is_template', 'description')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'is_template')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search',
|
||||
array('name', 'description', 'is_template')); // Criteria of the default search form
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
@@ -84,37 +68,24 @@ class QueryOQL extends Query
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('oql', 'is_template'),
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_query_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array(
|
||||
"allowed_values" => null,
|
||||
"sql" => "oql",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => false,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", array(
|
||||
"allowed_values" => null,
|
||||
"sql" => "fields",
|
||||
"default_value" => null,
|
||||
"is_null_allowed" => true,
|
||||
"depends_on" => array(),
|
||||
)));
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly
|
||||
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details',
|
||||
array('name', 'is_template', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search',
|
||||
array('name', 'description', 'is_template', 'fields', 'oql')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
|
||||
}
|
||||
|
||||
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -15,14 +15,13 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class Shortcut and derived
|
||||
* Shortcuts of any kind
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -40,6 +39,7 @@ abstract class Shortcut extends DBObject implements iDisplay
|
||||
"db_table" => "priv_shortcut",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "realclass",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
@@ -101,7 +101,7 @@ function ShortcutRenameOK()
|
||||
});
|
||||
}
|
||||
|
||||
$('#shortcut_rename_dlg form').on('submit', function() { return false; });
|
||||
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
|
||||
|
||||
$('#shortcut_rename_dlg').dialog({
|
||||
width: 400,
|
||||
@@ -161,6 +161,7 @@ class ShortcutOQL extends Shortcut
|
||||
"db_table" => "priv_shortcut_oql",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -286,7 +287,8 @@ class ShortcutOQL extends Shortcut
|
||||
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
<<<EOF
|
||||
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
@@ -314,30 +316,23 @@ function ShortcutCreationOK()
|
||||
});
|
||||
}
|
||||
|
||||
$('#shortcut_creation_dlg form').on('submit', function() { ShortcutCreationOK(); return false; });
|
||||
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
|
||||
|
||||
$('#shortcut_creation_dlg').dialog({
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{
|
||||
text: "$sCancelButtonLabel",
|
||||
class: "ibo-is-alternative",
|
||||
click: function() {
|
||||
$(this).dialog( "close" );
|
||||
$(this).remove();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "$sOkButtonLabel",
|
||||
class: "ibo-is-primary",
|
||||
click: ShortcutCreationOK
|
||||
},
|
||||
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
JS
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -23,7 +23,7 @@ require_once(APPROOT.'/core/contexttag.class.inc.php');
|
||||
/**
|
||||
* File to include to initialize the datamodel in memory
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2019 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -45,7 +45,7 @@ register_shutdown_function(function()
|
||||
$sMessage = substr($sMessage, 0, $iStackTracePos);
|
||||
}
|
||||
}
|
||||
IssueLog::error($sMessage);
|
||||
IssueLog::error($sMessage, null, $err);
|
||||
if (strpos($err['message'], 'Allowed memory size of') !== false)
|
||||
{
|
||||
$sLimit = ini_get('memory_limit');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -20,8 +20,6 @@
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
/**
|
||||
* This class manages the special template format used internally to build the iTop web pages
|
||||
*
|
||||
* @deprecated 3.0.0
|
||||
*/
|
||||
class DisplayTemplate
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -25,15 +25,6 @@
|
||||
*/
|
||||
class ThemeHandler
|
||||
{
|
||||
const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg'];
|
||||
|
||||
private static $oCompileCSSService;
|
||||
|
||||
public static function GetAppRootWithSlashes()
|
||||
{
|
||||
return str_replace('\\', '/', APPROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return default theme name and parameters
|
||||
*
|
||||
@@ -42,17 +33,19 @@ class ThemeHandler
|
||||
*/
|
||||
public static function GetDefaultThemeInformation()
|
||||
{
|
||||
return [
|
||||
'name' => 'fullmoon',
|
||||
'parameters' => [
|
||||
'variables' => [],
|
||||
'imports' => [
|
||||
],
|
||||
'stylesheets' => [
|
||||
'main' => '../css/backoffice/main.scss',
|
||||
],
|
||||
],
|
||||
];
|
||||
return array(
|
||||
'name' => 'light-grey',
|
||||
'parameters' => array(
|
||||
'variables' => array(),
|
||||
'imports' => array(
|
||||
'css-variables' => '../css/css-variables.scss',
|
||||
),
|
||||
'stylesheets' => array(
|
||||
'jqueryui' => '../css/ui-lightness/jqueryui.scss',
|
||||
'main' => '../css/light-grey.scss',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,46 +112,37 @@ class ThemeHandler
|
||||
SetupUtils::builddir($sDefaultThemeDirPath);
|
||||
}
|
||||
|
||||
static::CompileTheme($sThemeId, false, "", $aDefaultTheme['parameters']);
|
||||
static::CompileTheme($sThemeId, $aDefaultTheme['parameters']);
|
||||
}
|
||||
|
||||
// Return absolute url to theme compiled css
|
||||
return utils::GetAbsoluteUrlModulesRoot().'branding/themes/'.$sThemeId.'/main.css';
|
||||
return utils::GetAbsoluteUrlModulesRoot().'/branding/themes/'.$sThemeId.'/main.css';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the $sThemeId theme, the actual compilation is skipped when either
|
||||
* 1) The produced CSS file exists and is more recent than any of its components (imports, stylesheets)
|
||||
* 2) The produced CSS file exists and its signature is equal to the expected signature (imports, stylesheets, variables)
|
||||
* Compile the $sThemeId theme
|
||||
*
|
||||
* @param string $sThemeId
|
||||
* @param boolean $bSetup
|
||||
* @param string $sSetupCompilationTimestamp : setup compilation timestamp in micro secunds
|
||||
* @param array|null $aThemeParameters Parameters (variables, imports, stylesheets) for the theme, if not passed, will be retrieved from compiled DM
|
||||
* @param array|null $aImportsPaths Paths where imports can be found. Must end with '/'
|
||||
* @param string|null $sWorkingPath Path of the folder used during compilation. Must end with a '/'
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @return boolean: indicate whether theme compilation occured
|
||||
*/
|
||||
public static function CompileTheme($sThemeId, $bSetup=false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null) {
|
||||
if ($sSetupCompilationTimestamp === "") {
|
||||
$sSetupCompilationTimestamp = microtime(true);
|
||||
}
|
||||
|
||||
$sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !== false) ? explode('.',
|
||||
$sSetupCompilationTimestamp)[0] : $sSetupCompilationTimestamp;
|
||||
|
||||
$sEnv = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
|
||||
|
||||
public static function CompileTheme($sThemeId, $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
|
||||
{
|
||||
// Default working path
|
||||
if ($sWorkingPath === null) {
|
||||
$sWorkingPath = $sEnv;
|
||||
if($sWorkingPath === null)
|
||||
{
|
||||
$sWorkingPath = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
|
||||
}
|
||||
|
||||
// Default import paths (env-*)
|
||||
if ($aImportsPaths === null) {
|
||||
$aImportsPaths = [$sEnv];
|
||||
if($aImportsPaths === null)
|
||||
{
|
||||
$aImportsPaths = array(
|
||||
APPROOT.'env-'.utils::GetCurrentEnvironment().'/',
|
||||
);
|
||||
}
|
||||
|
||||
// Note: We do NOT check that the folder exists!
|
||||
@@ -166,732 +150,45 @@ class ThemeHandler
|
||||
$sThemeCssPath = $sThemeFolderPath.'main.css';
|
||||
|
||||
// Save parameters if passed... (typically during DM compilation)
|
||||
if (is_array($aThemeParameters)) {
|
||||
if (!is_dir($sThemeFolderPath)) {
|
||||
mkdir($sWorkingPath.'/branding/');
|
||||
mkdir($sWorkingPath.'/branding/themes/');
|
||||
}
|
||||
if(is_array($aThemeParameters))
|
||||
{
|
||||
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
|
||||
} // ... Otherwise, retrieve them from compiled DM (typically when switching current theme in the config. file)
|
||||
else {
|
||||
}
|
||||
// ... Otherwise, retrieve them from compiled DM (typically when switching current theme in the config. file)
|
||||
else
|
||||
{
|
||||
$aThemeParameters = json_decode(@file_get_contents($sThemeFolderPath.'theme-parameters.json'), true);
|
||||
if ($aThemeParameters === null) {
|
||||
if ($aThemeParameters === null)
|
||||
{
|
||||
throw new CoreException('Could not load "'.$sThemeId.'" theme parameters from file, check that it has been compiled correctly');
|
||||
}
|
||||
}
|
||||
|
||||
$aThemeParametersWithVersion = self::CloneThemeParameterAndIncludeVersion($aThemeParameters, $sSetupCompilationTimestampInSecunds);
|
||||
|
||||
clearstatcache();
|
||||
|
||||
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
|
||||
$sTmpThemeScssContent = '';
|
||||
$oFindStylesheetObject = new FindStylesheetObject();
|
||||
if (isset($aThemeParameters['imports_utility'])) {
|
||||
foreach ($aThemeParameters['imports_utility'] as $sImport) {
|
||||
static::FindStylesheetFile($sImport, $aImportsPaths, $oFindStylesheetObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aThemeParameters['stylesheets'])) {
|
||||
foreach ($aThemeParameters['stylesheets'] as $sStylesheet) {
|
||||
static::FindStylesheetFile($sStylesheet, $aImportsPaths, $oFindStylesheetObject);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($oFindStylesheetObject->GetStylesheetFileURIs() as $sStylesheet){
|
||||
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
|
||||
}
|
||||
|
||||
$iStyleLastModified = $oFindStylesheetObject->GetLastModified();
|
||||
|
||||
$aIncludedImages=static::GetIncludedImages($aThemeParametersWithVersion, $oFindStylesheetObject->GetAllStylesheetPaths(), $sThemeId);
|
||||
foreach ($aIncludedImages as $sImage)
|
||||
$iStyleLastModified = 0;
|
||||
clearstatcache();
|
||||
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
|
||||
foreach ($aThemeParameters['imports'] as $sImport)
|
||||
{
|
||||
if (is_file($sImage))
|
||||
{
|
||||
$iStylesheetLastModified = @filemtime($sImage);
|
||||
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
|
||||
}
|
||||
$sTmpThemeScssContent .= '@import "'.$sImport.'";'."\n";
|
||||
|
||||
$iImportLastModified = @filemtime($sWorkingPath.$sImport);
|
||||
$iStyleLastModified = $iStyleLastModified < $iImportLastModified ? $iImportLastModified : $iStyleLastModified;
|
||||
}
|
||||
foreach ($aThemeParameters['stylesheets'] as $sStylesheet)
|
||||
{
|
||||
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
|
||||
|
||||
$iStylesheetLastModified = @filemtime($sWorkingPath.$sStylesheet);
|
||||
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
|
||||
}
|
||||
|
||||
// Checking if our compiled css is outdated
|
||||
$iFilemetime = @filemtime($sThemeCssPath);
|
||||
$bFileExists = file_exists($sThemeCssPath);
|
||||
$bVarSignatureChanged=false;
|
||||
if ($bFileExists && $bSetup)
|
||||
if (!file_exists($sThemeCssPath) || (is_writable($sThemeFolderPath) && (@filemtime($sThemeCssPath) < $iStyleLastModified)))
|
||||
{
|
||||
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
|
||||
//check variable signature has changed which is independant from any file modification
|
||||
if (!empty($sPrecompiledSignature)){
|
||||
$sPreviousVariableSignature = static::GetVarSignature($sPrecompiledSignature);
|
||||
$sCurrentVariableSignature = md5(json_encode($aThemeParameters['variables']));
|
||||
$bVarSignatureChanged= ($sPreviousVariableSignature!==$sCurrentVariableSignature);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified)))
|
||||
{
|
||||
// Dates don't match. Second chance: check if the already compiled stylesheet exists and is consistent based on its signature
|
||||
$sActualSignature = static::ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages);
|
||||
|
||||
if ($bFileExists && !$bSetup)
|
||||
{
|
||||
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
|
||||
}
|
||||
|
||||
if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature)
|
||||
{
|
||||
touch($sThemeCssPath); // Stylesheet is up to date, mark it as more recent to speedup next time
|
||||
}
|
||||
else
|
||||
{
|
||||
// Alas, we really need to recompile
|
||||
// Add the signature to the generated CSS file so that the file can be used as a precompiled stylesheet if needed
|
||||
$sSignatureComment =
|
||||
<<<CSS
|
||||
/*
|
||||
=== SIGNATURE BEGIN ===
|
||||
$sActualSignature
|
||||
=== SIGNATURE END ===
|
||||
*/
|
||||
|
||||
CSS;
|
||||
if (!static::$oCompileCSSService)
|
||||
{
|
||||
static::$oCompileCSSService = new CompileCSSService();
|
||||
}
|
||||
//store it again to change $version with latest compiled time
|
||||
$sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths,
|
||||
$aThemeParametersWithVersion);
|
||||
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
|
||||
file_put_contents($sThemeCssPath, $sSignatureComment.$sTmpThemeCssContent);
|
||||
SetupLog::Info("Theme $sThemeId file compiled.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Compute the signature of a theme defined by its theme parameters. The signature is a JSON structure of
|
||||
* 1) one MD5 of all the variables/values (JSON encoded)
|
||||
* 2) the MD5 of each stylesheet file
|
||||
* 3) the MD5 of each import file
|
||||
* 3) the MD5 of each images referenced in style sheets
|
||||
*
|
||||
* @param string[] $aThemeParameters
|
||||
* @param string[] $aImportsPaths
|
||||
* @param string[] $aIncludedImages
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages) {
|
||||
$aSignature = [
|
||||
'variables' => md5(json_encode($aThemeParameters['variables'])),
|
||||
'stylesheets' => [],
|
||||
'imports' => [],
|
||||
'images' => []
|
||||
];
|
||||
|
||||
$oFindStylesheetObject = new FindStylesheetObject();
|
||||
|
||||
if (isset($aThemeParameters['imports_variable'])) {
|
||||
foreach ($aThemeParameters['imports_variable'] as $key => $sImport) {
|
||||
static::FindStylesheetFile($sImport, $aImportsPaths, $oFindStylesheetObject);
|
||||
$sFile = $oFindStylesheetObject->GetLastStylesheetFile();
|
||||
if (!empty($sFile)) {
|
||||
$aSignature['stylesheets'][$key] = md5_file($sFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($aThemeParameters['imports_utility'])) {
|
||||
foreach ($aThemeParameters['imports_utility'] as $key => $sImport) {
|
||||
static::FindStylesheetFile($sImport, $aImportsPaths, $oFindStylesheetObject);
|
||||
$sFile = $oFindStylesheetObject->GetLastStylesheetFile();
|
||||
if (!empty($sFile)) {
|
||||
$aSignature['stylesheets'][$key] = md5_file($sFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($aThemeParameters['stylesheets'])) {
|
||||
foreach ($aThemeParameters['stylesheets'] as $key => $sStylesheet) {
|
||||
static::FindStylesheetFile($sStylesheet, $aImportsPaths, $oFindStylesheetObject);
|
||||
$sFile = $oFindStylesheetObject->GetLastStylesheetFile();
|
||||
|
||||
if (!empty($sFile)) {
|
||||
$aSignature['stylesheets'][$key] = md5_file($sFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aFiles = $oFindStylesheetObject->GetImportPaths();
|
||||
if (count($aFiles) !== 0) {
|
||||
foreach ($aFiles as $sFileURI => $sFilePath) {
|
||||
$aSignature['imports_utility'][$sFileURI] = md5_file($sFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aIncludedImages as $sImage)
|
||||
{
|
||||
if (is_file($sImage)) {
|
||||
$sUri = str_replace(self::GetAppRootWithSlashes(), '', $sImage);
|
||||
$aSignature['images'][$sUri] = md5_file($sImage);
|
||||
}
|
||||
}
|
||||
|
||||
return json_encode($aSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for images referenced in stylesheet files
|
||||
*
|
||||
* @param array $aThemeParametersVariables
|
||||
* @param array $aStylesheetFiles
|
||||
* @param string $sThemeId : used only for logging purpose
|
||||
*
|
||||
* @return array complete path of the images, but with slashes as dir separator instead of DIRECTORY_SEPARATOR
|
||||
* @since 3.0.0 N°2982
|
||||
*/
|
||||
public static function GetIncludedImages($aThemeParametersVariables, $aStylesheetFiles, $sThemeId)
|
||||
{
|
||||
$sTargetThemeFolderPath = static::GetCompiledThemeFolderAbsolutePath($sThemeId);
|
||||
|
||||
$aCompleteUrls = [];
|
||||
$aToCompleteUrls = [];
|
||||
$aMissingVariables = [];
|
||||
$aFoundVariables = ['version'=>''];
|
||||
$aMap = [
|
||||
'aCompleteUrls' => $aCompleteUrls,
|
||||
'aToCompleteUrls' => $aToCompleteUrls,
|
||||
'aMissingVariables' => $aMissingVariables,
|
||||
'aFoundVariables' => $aFoundVariables,
|
||||
];
|
||||
|
||||
foreach ($aStylesheetFiles as $sStylesheetFile)
|
||||
{
|
||||
$aRes = static::GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile);
|
||||
/** @var array $aVal */
|
||||
foreach($aMap as $key => $aVal)
|
||||
{
|
||||
if (array_key_exists($key, $aMap))
|
||||
{
|
||||
$aMap[$key] = array_merge($aVal, $aRes[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$aMap = static::ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFiles);
|
||||
$aImages = [];
|
||||
|
||||
foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl)
|
||||
{
|
||||
$sImg = $sUrl;
|
||||
if (preg_match("/(.*)\?/", $sUrl, $aMatches))
|
||||
{
|
||||
$sImg=$aMatches[1];
|
||||
}
|
||||
|
||||
if (static::HasImageExtension($sImg)
|
||||
&& ! array_key_exists($sImg, $aImages))
|
||||
{
|
||||
$sFilePath = realpath($sImg);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
continue;
|
||||
}
|
||||
|
||||
$sCanonicalPath = static::CanonicalizePath($sTargetThemeFolderPath.'/'.$sImg);
|
||||
$sFilePath = realpath($sCanonicalPath);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
continue;
|
||||
}
|
||||
|
||||
SetupLog::Warning("Cannot find $sCanonicalPath ($sImg) during SCSS $sThemeId precompilation");
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($aImages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce path without using realpath (works only when file exists)
|
||||
* @param $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function CanonicalizePath($path)
|
||||
{
|
||||
$path = explode('/', str_replace('//','/', $path));
|
||||
$stack = array();
|
||||
foreach ($path as $seg) {
|
||||
if ($seg == '..') {
|
||||
// Ignore this segment, remove last segment from stack
|
||||
array_pop($stack);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($seg == '.') {
|
||||
// Ignore this segment
|
||||
continue;
|
||||
}
|
||||
|
||||
$stack[] = $seg;
|
||||
}
|
||||
|
||||
return implode('/', $stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Complete url using provided variables. Example with $var=1: XX + $var => XX1
|
||||
* @param $aMap
|
||||
* @param $aThemeParametersVariables
|
||||
* @param $aStylesheetFile
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFile)
|
||||
{
|
||||
$sContent="";
|
||||
foreach ($aStylesheetFile as $sStylesheetFile)
|
||||
{
|
||||
if (is_file($sStylesheetFile))
|
||||
{
|
||||
$sContent .= '\n' . file_get_contents($sStylesheetFile);
|
||||
}
|
||||
}
|
||||
|
||||
$aMissingVariables=$aMap['aMissingVariables'];
|
||||
$aFoundVariables=$aMap['aFoundVariables'];
|
||||
$aToCompleteUrls=$aMap['aToCompleteUrls'];
|
||||
$aCompleteUrls=$aMap['aCompleteUrls'];
|
||||
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, true);
|
||||
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
|
||||
$aMap['aMissingVariables']=$aMissingVariables;
|
||||
$aMap['aFoundVariables']=$aFoundVariables;
|
||||
$aMap['aToCompleteUrls']=$aToCompleteUrls;
|
||||
$aMap['aCompleteUrls']=$aCompleteUrls;
|
||||
return $aMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Find missing variable values from SCSS content based on their name.
|
||||
*
|
||||
* @param $aThemeParametersVariables
|
||||
* @param $aMissingVariables
|
||||
* @param $aFoundVariables
|
||||
* @param $sContent : scss content
|
||||
* @param bool $bForceEmptyValueWhenNotFound
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound=false)
|
||||
{
|
||||
$aNewMissingVars = [];
|
||||
if (!empty($aMissingVariables))
|
||||
{
|
||||
foreach ($aMissingVariables as $var)
|
||||
{
|
||||
if (array_key_exists($var, $aThemeParametersVariables))
|
||||
{
|
||||
$aFoundVariables[$var] = $aThemeParametersVariables[$var];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues))
|
||||
{
|
||||
$sValue = $aValues[1][0];
|
||||
if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues))
|
||||
{
|
||||
$sValue = trim($aSubValues[1][0], ' "\'');
|
||||
}
|
||||
|
||||
if (strpos($sValue, '$') === false)
|
||||
{
|
||||
$aFoundVariables[$var] = $sValue;
|
||||
}
|
||||
else{
|
||||
$aNewMissingVars[] = $var;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($bForceEmptyValueWhenNotFound)
|
||||
{
|
||||
$aFoundVariables[$var] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aNewMissingVars[] = $var;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [ $aNewMissingVars, $aFoundVariables ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* @param $aFoundVariables
|
||||
* @param array $aToCompleteUrls
|
||||
* @param array $aCompleteUrls
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function ResolveUrls($aFoundVariables, array $aToCompleteUrls, array $aCompleteUrls)
|
||||
{
|
||||
if (!empty($aFoundVariables))
|
||||
{
|
||||
$aFoundVariablesWithEmptyValue = [];
|
||||
foreach ($aFoundVariables as $aFoundVariable => $sValue)
|
||||
{
|
||||
$aFoundVariablesWithEmptyValue[$aFoundVariable] = '';
|
||||
}
|
||||
|
||||
foreach ($aToCompleteUrls as $sUrlTemplate)
|
||||
{
|
||||
unset($aToCompleteUrls[$sUrlTemplate]);
|
||||
$sResolvedUrl = static::ResolveUrl($sUrlTemplate, $aFoundVariables);
|
||||
if ($sResolvedUrl == false)
|
||||
{
|
||||
$aToCompleteUrls[$sUrlTemplate] = $sUrlTemplate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUri = static::ResolveUrl($sUrlTemplate, $aFoundVariablesWithEmptyValue);
|
||||
$aExplodedUri = explode('?', $sUri);
|
||||
if (empty($aExplodedUri))
|
||||
{
|
||||
$aCompleteUrls[$sUri] = $sResolvedUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCompleteUrls[$aExplodedUri[0]] = $sResolvedUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [ $aToCompleteUrls, $aCompleteUrls];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Find all referenced URLs from a SCSS file.
|
||||
* @param $aThemeParametersVariables
|
||||
* @param $sStylesheetFile
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile)
|
||||
{
|
||||
$aCompleteUrls = [];
|
||||
$aToCompleteUrls = [];
|
||||
$aMissingVariables = [];
|
||||
$aFoundVariables = [];
|
||||
|
||||
if (is_file($sStylesheetFile))
|
||||
{
|
||||
$sContent = file_get_contents($sStylesheetFile);
|
||||
if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches))
|
||||
{
|
||||
foreach ($aMatches[1] as $path)
|
||||
{
|
||||
$iRemainingClosingParenthesisPos = strpos($path, ')');
|
||||
if ($iRemainingClosingParenthesisPos !== false){
|
||||
$path = substr($path, 0, $iRemainingClosingParenthesisPos);
|
||||
}
|
||||
if (!array_key_exists($path, $aCompleteUrls)
|
||||
&& !array_key_exists($path, $aToCompleteUrls))
|
||||
{
|
||||
if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars))
|
||||
{
|
||||
/** @var string $aCurrentVars */
|
||||
foreach ($aCurrentVars[1] as $var)
|
||||
{
|
||||
if (!array_key_exists($var, $aMissingVariables))
|
||||
{
|
||||
$aMissingVariables[$var] = $var;
|
||||
}
|
||||
}
|
||||
$aToCompleteUrls[$path] = $path;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCompleteUrls[$path] = trim($path, "\"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($aMissingVariables))
|
||||
{
|
||||
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent);
|
||||
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'aCompleteUrls' => $aCompleteUrls,
|
||||
'aToCompleteUrls' => $aToCompleteUrls,
|
||||
'aMissingVariables' => $aMissingVariables,
|
||||
'aFoundVariables' => $aFoundVariables
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Calculate url based on its template + variables.
|
||||
* @param $sUrlTemplate
|
||||
* @param $aFoundVariables
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function ResolveUrl($sUrlTemplate, $aFoundVariables)
|
||||
{
|
||||
$aPattern= [];
|
||||
$aReplacement= [];
|
||||
foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue)
|
||||
{
|
||||
//XX + $key + YY
|
||||
$aPattern[]="/['\"]\s*\+\s*\\\$" . $aFoundVariable . "[\s\+]+\s*['\"]/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
//$key + YY
|
||||
$aPattern[]="/\\\$" . $aFoundVariable. "[\s\+]+\s*['\"]/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
//XX + $key
|
||||
$aPattern[]="/['\"]\s*[\+\s]+\\\$" . $aFoundVariable . "$/";
|
||||
$aReplacement[]=$aFoundVariableValue;
|
||||
}
|
||||
$sResolvedUrl=preg_replace($aPattern, $aReplacement, $sUrlTemplate);
|
||||
if (strpos($sResolvedUrl, "+")!==false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return trim($sResolvedUrl, "\"'");
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate whether a string ends with image suffix.
|
||||
* @param $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function HasImageExtension($path)
|
||||
{
|
||||
foreach (static::IMAGE_EXTENSIONS as $sExt)
|
||||
{
|
||||
if (endsWith($path, $sExt))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Extract the signature for a generated CSS file.
|
||||
* The signature MUST be alone one line immediately followed (on the next line) by the === SIGNATURE END === pattern
|
||||
* The signature MUST be in the first 100th lines of the file.
|
||||
*
|
||||
* Note the signature can be place anywhere in the CSS file (obviously inside a CSS comment !) but the
|
||||
* function will be faster if the signature is at the beginning of the file (since the file is scanned from the start)
|
||||
*
|
||||
* @param $sFilepath
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetSignature($sFilepath)
|
||||
{
|
||||
$iCount = 0;
|
||||
$sPreviousLine = '';
|
||||
$hFile = @fopen($sFilepath, "r");
|
||||
if ($hFile !== false)
|
||||
{
|
||||
$sLine = '';
|
||||
do
|
||||
{
|
||||
$iCount++;
|
||||
$sPreviousLine = $sLine;
|
||||
$sLine = rtrim(fgets($hFile)); // Remove the trailing \n
|
||||
}
|
||||
while (($sLine !== false) && ($sLine != '=== SIGNATURE END ===') && ($iCount <= 100));
|
||||
fclose($hFile);
|
||||
}
|
||||
return $sPreviousLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* @param $JsonSignature
|
||||
*
|
||||
* @return false|mixed
|
||||
*/
|
||||
public static function GetVarSignature($JsonSignature)
|
||||
{
|
||||
$aJsonArray = json_decode($JsonSignature, true);
|
||||
if (array_key_exists('variables', $aJsonArray))
|
||||
{
|
||||
return $aJsonArray['variables'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sFileURI
|
||||
* @param string[] $aImportsPaths
|
||||
* @param FindStylesheetObject $oFindStylesheetObject
|
||||
* @param bool $bImports
|
||||
*
|
||||
* @throws \Exception
|
||||
*@since 3.0.0 N°2982
|
||||
* Find the given file in the list '$aImportsPaths' of directory and all included stylesheets as well
|
||||
* Compute latest timestamp found among all found stylesheets
|
||||
*
|
||||
*/
|
||||
public static function FindStylesheetFile(string $sFileURI, array $aImportsPaths, $oFindStylesheetObject, $bImports = false)
|
||||
{
|
||||
if (! $bImports) {
|
||||
$oFindStylesheetObject->ResetLastStyleSheet();
|
||||
}
|
||||
|
||||
foreach($aImportsPaths as $sPath)
|
||||
{
|
||||
$sFilePath = $sPath.'/'.$sFileURI;
|
||||
$sImportedFile = realpath($sFilePath);
|
||||
if ($sImportedFile === false){
|
||||
// Handle shortcut syntax : @import "typo" ;
|
||||
// file matched: typo.scss
|
||||
$sFilePath2 = "$sFilePath.scss";
|
||||
$sImportedFile = realpath($sFilePath2);
|
||||
if ($sImportedFile){
|
||||
self::FindStylesheetFile("$sFileURI.scss", [ $sPath ], $oFindStylesheetObject, $bImports);
|
||||
$sImportedFile = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($sImportedFile === false){
|
||||
// Handle shortcut syntax : @import "typo" ;
|
||||
// file matched: _typo.scss
|
||||
$sShortCut = substr($sFilePath, strrpos($sFilePath, '/') + 1);
|
||||
$sFilePath = static::ReplaceLastOccurrence($sShortCut, "_$sShortCut.scss", $sFilePath);
|
||||
$sFileURI = static::ReplaceLastOccurrence($sShortCut, "_$sShortCut.scss", $sFileURI);
|
||||
$sImportedFile = realpath($sFilePath);
|
||||
}
|
||||
|
||||
if ((file_exists($sImportedFile))
|
||||
&& (!$oFindStylesheetObject->AlreadyFetched($sImportedFile)))
|
||||
{
|
||||
if ($bImports){
|
||||
$oFindStylesheetObject->AddImport($sFileURI, $sImportedFile);
|
||||
}else{
|
||||
$oFindStylesheetObject->AddStylesheet($sFileURI, $sImportedFile);
|
||||
}
|
||||
$oFindStylesheetObject->UpdateLastModified($sImportedFile);
|
||||
|
||||
//Regexp matching on all included scss files : @import 'XXX.scss';
|
||||
$sDirUri = dirname($sFileURI);
|
||||
preg_match_all('/@import \s*[\"\']([^\"\']*)\s*[\"\']\s*;/', file_get_contents($sImportedFile), $aMatches);
|
||||
if ( (is_array($aMatches)) && (count($aMatches)!==0) ){
|
||||
foreach ($aMatches[1] as $sImportedFile){
|
||||
self::FindStylesheetFile("$sDirUri/$sImportedFile", [ $sPath ], $oFindStylesheetObject, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sTmpThemeCssContent = utils::CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths, $aThemeParameters['variables']);
|
||||
file_put_contents($sThemeCssPath, $sTmpThemeCssContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $search
|
||||
* @param $replace
|
||||
* @param $subject
|
||||
*
|
||||
* @since 3.0.0 N°2982
|
||||
* Replaces last occurrence of the string
|
||||
* @return string|string[]
|
||||
*/
|
||||
public static function ReplaceLastOccurrence($sSearch, $sReplace, $sSubject)
|
||||
{
|
||||
$iPos = strrpos($sSubject, $sSearch);
|
||||
|
||||
if($iPos !== false)
|
||||
{
|
||||
$sSubject = substr_replace($sSubject, $sReplace, $iPos, strlen($sSearch));
|
||||
}
|
||||
|
||||
return $sSubject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Used for testing purpose
|
||||
* @param $oCompileCSSServiceMock
|
||||
*/
|
||||
public static function MockCompileCSSService($oCompileCSSServiceMock)
|
||||
{
|
||||
static::$oCompileCSSService = $oCompileCSSServiceMock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0 N°2982
|
||||
* Clone variable array and include $version with bSetupCompilationTimestamp value
|
||||
* @param $aThemeParameters
|
||||
* @param $bSetupCompilationTimestamp
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp)
|
||||
{
|
||||
$aThemeParametersVariable = [];
|
||||
if (array_key_exists('variables', $aThemeParameters))
|
||||
{
|
||||
if (is_array($aThemeParameters['variables']))
|
||||
{
|
||||
$aThemeParametersVariable = array_merge([], $aThemeParameters['variables']);
|
||||
}
|
||||
}
|
||||
if (array_key_exists('imports_variable', $aThemeParameters))
|
||||
{
|
||||
if (is_array($aThemeParameters['imports_variable']))
|
||||
{
|
||||
$aThemeParametersVariable = array_merge($aThemeParametersVariable, static::GetVariablesFromFile($aThemeParameters['imports_variable']));
|
||||
}
|
||||
}
|
||||
|
||||
$aThemeParametersVariable['$version'] = $bSetupCompilationTimestamp;
|
||||
return $aThemeParametersVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $aVariableFiles
|
||||
*
|
||||
* @return array
|
||||
* @since 3.0.0 N°3593
|
||||
*/
|
||||
public static function GetVariablesFromFile($aVariableFiles){
|
||||
$aVariablesResults = [];
|
||||
foreach ($aVariableFiles as $sVariableFile)
|
||||
{
|
||||
$sFileContent = file_get_contents(APPROOT.'env-'.utils::GetCurrentEnvironment().'/'.$sVariableFile);
|
||||
$aVariableMatches = [];
|
||||
|
||||
preg_match_all( '/\$(.*?):(.*?);/', $sFileContent,$aVariableMatches);
|
||||
$aVariableMatches = array_combine( $aVariableMatches[1], array_map( function($sVariableValue) { return ltrim($sVariableValue); }, $aVariableMatches[2] ) );
|
||||
$aVariablesResults = array_merge($aVariablesResults, $aVariableMatches);
|
||||
}
|
||||
array_map( function($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults );
|
||||
return $aVariablesResults;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -23,7 +23,7 @@
|
||||
* which choice is configured via the parameter 'transaction_storage'
|
||||
*
|
||||
* @package iTop
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -21,7 +21,7 @@
|
||||
* UI wdiget for displaying and editing one-way encrypted passwords
|
||||
*
|
||||
* @author Romain Quetiez
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -70,7 +70,11 @@ class UIHTMLEditorWidget
|
||||
// To change the default settings of the editor,
|
||||
// a) edit the file /js/ckeditor/config.js
|
||||
// b) or override some of the configuration settings, using the second parameter of ckeditor()
|
||||
$aConfig = utils::GetCkeditorPref();
|
||||
$aConfig = array();
|
||||
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
|
||||
$aConfig['language'] = $sLanguage;
|
||||
$aConfig['contentsLanguage'] = $sLanguage;
|
||||
$aConfig['extraPlugins'] = 'disabler,codesnippet';
|
||||
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
|
||||
if ($sWidthSpec != '')
|
||||
{
|
||||
@@ -93,10 +97,10 @@ class UIHTMLEditorWidget
|
||||
// The most relevant solution would be to implement a plugin to CKEdit, and handle the internal events like: setData, insertHtml, insertElement, loadSnapshot, key, afterUndo, afterRedo
|
||||
|
||||
// Could also be bound to 'instanceReady.ckeditor'
|
||||
$oPage->add_ready_script("$('#$iId').on('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
|
||||
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$iId').on('update', function(evt){
|
||||
$('#$iId').bind('update', function(evt){
|
||||
BlockField('cke_$iId', $('#$iId').prop('disabled'));
|
||||
//Delayed execution - ckeditor must be properly initialized before setting readonly
|
||||
var retryCount = 0;
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* Class UILinksWidgetDirect
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
*/
|
||||
|
||||
class UILinksWidgetDirect
|
||||
{
|
||||
protected $sClass;
|
||||
@@ -174,7 +184,7 @@ class UILinksWidgetDirect
|
||||
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
|
||||
// and that the current user is allowed to create objects of this class
|
||||
$sRealClass = '';
|
||||
//$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
|
||||
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
|
||||
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
|
||||
$aPossibleClasses = array();
|
||||
foreach($aSubClasses as $sCandidateClass)
|
||||
@@ -233,21 +243,23 @@ class UILinksWidgetDirect
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
|
||||
$oValue->Rewind();
|
||||
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
|
||||
|
||||
$aData = array();
|
||||
while ($oLinkObj = $oValue->Fetch()) {
|
||||
while($oLinkObj = $oValue->Fetch())
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
|
||||
foreach ($this->aZlist as $sLinkedAttCode) {
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
$oDiv = UIContentBlockUIBlockFactory::MakeStandard($this->sInputid, ['listContainer']);
|
||||
$oPage->AddSubBlock($oDiv);
|
||||
$oDatatable = DataTableUIBlockFactory::MakeForForm($this->sInputid, $aAttribs, $aData);
|
||||
$oDatatable->SetOptions(['select_mode' => 'custom']);
|
||||
$oDiv->AddSubBlock($oDatatable);
|
||||
$oPage->table($aAttribs, $aData);
|
||||
$oPage->add('</td></tr></table>'); //listcontainer
|
||||
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
|
||||
$aLabels = array(
|
||||
'delete' => Dict::S('UI:Button:Delete'),
|
||||
@@ -282,17 +294,20 @@ class UILinksWidgetDirect
|
||||
*/
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
|
||||
{
|
||||
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass)) {
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass))
|
||||
{
|
||||
// Prevent linking to self if the linked object is of the same family
|
||||
// and already present in the database
|
||||
if (!$oCurrentObj->IsNew()) {
|
||||
if (!$oCurrentObj->IsNew())
|
||||
{
|
||||
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0) {
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
|
||||
@@ -304,14 +319,18 @@ class UILinksWidgetDirect
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
} else {
|
||||
if (!$valuesDef instanceof ValueSetObjects) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$valuesDef instanceof ValueSetObjects)
|
||||
{
|
||||
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
|
||||
}
|
||||
|
||||
if ($oCurrentObj != null) {
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
@@ -320,7 +339,7 @@ class UILinksWidgetDirect
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
|
||||
array(
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
|
||||
'table_id' => "add_{$this->sInputid}",
|
||||
@@ -330,21 +349,16 @@ class UILinksWidgetDirect
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sHiddenCriteria,
|
||||
)
|
||||
));
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->sInputid}">
|
||||
<div id="SearchResultsToAdd_{$this->sInputid}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->sInputid}" value="0"/>
|
||||
<button type="button" class="cancel">{$sCancel}</button> <button type="button" class="ok" disabled="disabled">{$sAdd}</button>
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
);
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" 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=\"hidden\" id=\"count_{$this->sInputid}\" value=\"0\"/>";
|
||||
$sHtml .= "<button type=\"button\" class=\"cancel\">".Dict::S('UI:Button:Cancel')."</button> <button type=\"button\" class=\"ok\" disabled=\"disabled\">".Dict::S('UI:Button:Add')."</button>";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Class UILinksWidget
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\StaticTable\FormTableRow\FormTableRow;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinksEdit\BlockIndirectLinksEdit;
|
||||
use Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog\BlockObjectPickerDialog;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
|
||||
require_once(APPROOT.'application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'application/displayblock.class.inc.php');
|
||||
|
||||
class UILinksWidget
|
||||
@@ -24,7 +39,6 @@ class UILinksWidget
|
||||
protected $m_sLinkedClass;
|
||||
protected $m_sRemoteClass;
|
||||
protected $m_bDuplicatesAllowed;
|
||||
/** @var string[] list of editables attcodes */
|
||||
protected $m_aEditableFields;
|
||||
protected $m_aTableConfig;
|
||||
|
||||
@@ -32,7 +46,7 @@ class UILinksWidget
|
||||
* UILinksWidget constructor.
|
||||
*
|
||||
* @param string $sClass
|
||||
* @param string $sAttCode AttributeLinkedSetIndirect attcode
|
||||
* @param string $sAttCode
|
||||
* @param int $iInputId
|
||||
* @param string $sNameSuffix
|
||||
* @param bool $bDuplicatesAllowed
|
||||
@@ -59,35 +73,41 @@ class UILinksWidget
|
||||
/** @var AttributeExternalKey $oLinkingAttDef */
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
|
||||
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
|
||||
$sDefaultState = MetaModel::GetDefaultState($this->m_sClass);
|
||||
|
||||
$this->m_aEditableFields = array();
|
||||
$this->m_aTableConfig = array();
|
||||
$this->m_aTableConfig['form::checkbox'] = array(
|
||||
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">",
|
||||
'description' => Dict::S('UI:SelectAllToggle+'),
|
||||
);
|
||||
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
|
||||
|
||||
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode);
|
||||
foreach ($aLnkAttDefsToDisplay as $oLnkAttDef)
|
||||
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode)
|
||||
{
|
||||
$sLnkAttCode = $oLnkAttDef->GetCode();
|
||||
$this->m_aEditableFields[] = $sLnkAttCode;
|
||||
$this->m_aTableConfig[$sLnkAttCode] = array('label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription());
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
|
||||
if ($sStateAttCode == $sAttCode)
|
||||
{
|
||||
// State attribute is always hidden from the UI
|
||||
}
|
||||
else if ($oAttDef->IsWritable() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags($this->m_sLinkedClass, $sDefaultState, $sAttCode);
|
||||
if ( !($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY) )
|
||||
{
|
||||
$this->m_aEditableFields[] = $sAttCode;
|
||||
$this->m_aTableConfig[$sAttCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_aTableConfig['static::key'] = array(
|
||||
'label' => MetaModel::GetName($this->m_sRemoteClass),
|
||||
'description' => MetaModel::GetClassDescription($this->m_sRemoteClass),
|
||||
);
|
||||
$this->m_aEditableFields[] = $this->m_sExtKeyToRemote;
|
||||
|
||||
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
|
||||
foreach ($aRemoteAttDefsToDisplay as $oRemoteAttDef) {
|
||||
$sRemoteAttCode = $oRemoteAttDef->GetCode();
|
||||
$this->m_aTableConfig['static::'.$sRemoteAttCode] = array(
|
||||
'label' => $oRemoteAttDef->GetLabel(),
|
||||
'description' => $oRemoteAttDef->GetDescription(),
|
||||
);
|
||||
|
||||
$this->m_aTableConfig['static::key'] = array( 'label' => MetaModel::GetName($this->m_sRemoteClass), 'description' => MetaModel::GetClassDescription($this->m_sRemoteClass));
|
||||
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
{
|
||||
// TO DO: check the state of the attribute: hidden or visible ?
|
||||
if ($sFieldCode != 'finalclass')
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sRemoteClass, $sFieldCode);
|
||||
$this->m_aTableConfig['static::'.$sFieldCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +116,7 @@ class UILinksWidget
|
||||
*
|
||||
* @param WebPage $oP Web page used for the ouput
|
||||
* @param DBObject $oLinkedObj Remote object
|
||||
* @param DBObject|int $linkObjOrId Either the lnk object or a unique number for new link records to add
|
||||
* @param mixed $linkObjOrId Either the object linked or a unique number for new link records to add
|
||||
* @param array $aArgs Extra context arguments
|
||||
* @param DBObject $oCurrentObj The object to which all the elements of the linked set refer to
|
||||
* @param int $iUniqueId A unique identifier of new links
|
||||
@@ -114,39 +134,43 @@ class UILinksWidget
|
||||
$aRow = array();
|
||||
$aFieldsMap = array();
|
||||
$iKey = 0;
|
||||
|
||||
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
|
||||
if(is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
|
||||
{
|
||||
$iKey = $linkObjOrId->GetKey();
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
|
||||
$sPrefix .= "[$iKey][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
|
||||
if ($bReadOnly)
|
||||
{
|
||||
$aRow['form::checkbox'] = "";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$aRow[$sFieldCode] = $sDisplayValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach ($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
}
|
||||
if($bReadOnly)
|
||||
{
|
||||
$aRow['form::checkbox'] = "";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$aRow[$sFieldCode] = $sDisplayValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
|
||||
$sSafeId = utils::GetSafeId($sFieldId);
|
||||
$sValue = $linkObjOrId->Get($sFieldCode);
|
||||
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
|
||||
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId, $sNameSuffix, 0, $aArgs).
|
||||
'</div></div></div>';
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
}
|
||||
}
|
||||
|
||||
$sState = $linkObjOrId->GetState();
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->m_sExtKeyToRemote);;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -156,18 +180,15 @@ class UILinksWidget
|
||||
// New link existing only in memory
|
||||
$oNewLinkObj = $linkObjOrId;
|
||||
$iRemoteObjKey = $oNewLinkObj->Get($this->m_sExtKeyToRemote);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRemoteObjKey = $linkObjOrId;
|
||||
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
|
||||
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, $iRemoteObjKey);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote,
|
||||
$oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe,
|
||||
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
|
||||
}
|
||||
$sPrefix .= "[-$iUniqueId][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
@@ -201,136 +222,113 @@ EOF
|
||||
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($iUniqueId, $sFieldCode);
|
||||
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $oNewLinkObj, $oP, $sNameSuffix, $sSafeFieldId);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']';
|
||||
$sSafeId = utils::GetSafeId($sFieldId);
|
||||
$sValue = $oNewLinkObj->Get($sFieldCode);
|
||||
$oP->add_ready_script(
|
||||
<<<JS
|
||||
$sDisplayValue = $oNewLinkObj->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
|
||||
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs).
|
||||
'</div></div></div>';
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
$oP->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
|
||||
JS
|
||||
);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
$sState = '';
|
||||
$sRemoteKeySafeFieldId = $this->GetFieldId($iUniqueId, $this->m_sExtKeyToRemote);
|
||||
}
|
||||
|
||||
if (!$bReadOnly)
|
||||
{
|
||||
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
|
||||
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
|
||||
if(!$bReadOnly)
|
||||
{
|
||||
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
|
||||
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
|
||||
|
||||
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
|
||||
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
|
||||
}
|
||||
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
|
||||
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
|
||||
}
|
||||
|
||||
// Adding fields from remote class
|
||||
// all fields are embedded in a span + added to $aFieldsMap array so that we can refresh them after extkey change
|
||||
$aRemoteFieldsMap = [];
|
||||
foreach (MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
{
|
||||
$sSafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $sFieldCode);
|
||||
$aRow['static::'.$sFieldCode] = "<span id='field_$sSafeFieldId'>".$oLinkedObj->GetAsHTML($sFieldCode).'</span>';
|
||||
$aRemoteFieldsMap[$sFieldCode] = $sSafeFieldId;
|
||||
}
|
||||
// id field is needed so that remote object could be load server side
|
||||
$aRemoteFieldsMap['id'] = $sRemoteKeySafeFieldId;
|
||||
|
||||
// Generate WizardHelper to update dependant fields
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelper'], $this->m_sLinkedClass, $sState, $aFieldsMap);
|
||||
//instantiate specific WizarHelper instance for remote class fields refresh
|
||||
$bHasExtKeyUpdatingRemoteClassFields = (
|
||||
array_key_exists('replaceDependenciesByRemoteClassFields', $aArgs)
|
||||
&& ($aArgs['replaceDependenciesByRemoteClassFields'])
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
|
||||
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
|
||||
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
|
||||
EOF
|
||||
);
|
||||
if ($bHasExtKeyUpdatingRemoteClassFields)
|
||||
$aRow['static::key'] = $oLinkedObj->GetHyperLink();
|
||||
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
|
||||
{
|
||||
$this->AddWizardHelperInit($oP, $aArgs['wizHelperRemote'], $this->m_sRemoteClass, $sState, $aRemoteFieldsMap);
|
||||
$aRow['static::'.$sFieldCode] = $oLinkedObj->GetAsHTML($sFieldCode);
|
||||
}
|
||||
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
private function AddRowForFieldCode(&$aRow, $sFieldCode, &$aArgs, $oLnk, $oP, $sNameSuffix, $sSafeFieldId): void
|
||||
/**
|
||||
* Display one row of the whole form
|
||||
* @param WebPage $oP
|
||||
* @param array $aConfig
|
||||
* @param array $aRow
|
||||
* @param int $iRowId
|
||||
* @return string
|
||||
*/
|
||||
protected function DisplayFormRow(WebPage $oP, $aConfig, $aRow, $iRowId)
|
||||
{
|
||||
if (($sFieldCode === $this->m_sExtKeyToRemote))
|
||||
$sHtml = '';
|
||||
$sHtml .= "<tr id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_row_$iRowId\">\n";
|
||||
foreach($aConfig as $sName=>$void)
|
||||
{
|
||||
// current field is the lnk extkey to the remote class
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = true;
|
||||
$sRowFieldCode = 'static::key';
|
||||
$aArgs['wizHelperRemote'] = $aArgs['wizHelper'].'_remote';
|
||||
$aRemoteAttDefs = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
|
||||
$aRemoteCodes = array_map(
|
||||
function ($value) {
|
||||
return $value->GetCode();
|
||||
},
|
||||
$aRemoteAttDefs
|
||||
);
|
||||
$aArgs['remoteCodes'] = $aRemoteCodes;
|
||||
$sHtml .= "<td>".$aRow[$sName]."</td>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aArgs['replaceDependenciesByRemoteClassFields'] = false;
|
||||
$sRowFieldCode = $sFieldCode;
|
||||
}
|
||||
$sValue = $oLnk->Get($sFieldCode);
|
||||
$sDisplayValue = $oLnk->GetEditValue($sFieldCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
|
||||
$aRow[$sRowFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'
|
||||
.cmdbAbstractObject::GetFormElementForField(
|
||||
$oP,
|
||||
$this->m_sLinkedClass,
|
||||
$sFieldCode,
|
||||
$oAttDef,
|
||||
$sValue,
|
||||
$sDisplayValue,
|
||||
$sSafeFieldId,
|
||||
$sNameSuffix,
|
||||
0,
|
||||
$aArgs
|
||||
)
|
||||
.'</div></div></div>';
|
||||
$sHtml .= "</tr>\n";
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
private function GetFieldId($iLnkId, $sFieldCode, $bSafe = true)
|
||||
{
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$iLnkId.']';
|
||||
|
||||
return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId;
|
||||
}
|
||||
|
||||
private function AddWizardHelperInit($oP, $sWizardHelperVarName, $sWizardHelperClass, $sState, $aFieldsMap): void
|
||||
{
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oP->add_script(
|
||||
<<<JS
|
||||
var $sWizardHelperVarName = new WizardHelper('$sWizardHelperClass', '', '$sState');
|
||||
$sWizardHelperVarName.SetFieldsMap($sJsonFieldsMap);
|
||||
$sWizardHelperVarName.SetFieldsCount($iFieldsCount);
|
||||
$sWizardHelperVarName.SetReturnNotEditableFields(true);
|
||||
$sWizardHelperVarName.SetWizHelperJsVarName('$sWizardHelperVarName');
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the table with the form for editing all the links at once
|
||||
*
|
||||
* @param WebPage $oP The web page used for the output
|
||||
* @param array $aConfig The table's header configuration
|
||||
* @param array $aData The tabular data to be displayed
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Component\DataTable\StaticTable\FormTable\FormTable
|
||||
* @return string Html fragment representing the form table
|
||||
*/
|
||||
protected function GetFormTableBlock($aConfig, $aData)
|
||||
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
|
||||
{
|
||||
return DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig, $aData);
|
||||
$sHtml = "<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\">";
|
||||
$sHtml .= "<table class=\"listResults\">\n";
|
||||
// Header
|
||||
$sHtml .= "<thead>\n";
|
||||
$sHtml .= "<tr>\n";
|
||||
foreach($aConfig as $sName=>$aDef)
|
||||
{
|
||||
$sHtml .= "<th title=\"".$aDef['description']."\">".$aDef['label']."</th>\n";
|
||||
}
|
||||
$sHtml .= "</tr>\n";
|
||||
$sHtml .= "</thead>\n";
|
||||
|
||||
// Content
|
||||
$sHtml .= "</tbody>\n";
|
||||
$sEmptyRowStyle = '';
|
||||
if (count($aData) != 0)
|
||||
{
|
||||
$sEmptyRowStyle = 'style="display:none;"';
|
||||
}
|
||||
|
||||
foreach($aData as $iRowId => $aRow)
|
||||
{
|
||||
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
|
||||
}
|
||||
$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')."</td></tr>";
|
||||
$sHtml .= "</tbody>\n";
|
||||
|
||||
// Footer
|
||||
$sHtml .= "</table>\n";
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
@@ -345,65 +343,63 @@ JS
|
||||
*
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj): string
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$sLinkedSetId = "{$this->m_sAttCode}{$this->m_sNameSuffix}";
|
||||
|
||||
$oBlock = new BlockIndirectLinksEdit("linkedset_{$sLinkedSetId}", ["ibo-block-indirect-links--edit"]);
|
||||
|
||||
$oBlock->sLinkedSetId = $sLinkedSetId;
|
||||
$oBlock->sClass = $this->m_sClass;
|
||||
$oBlock->sAttCode = $this->m_sAttCode;
|
||||
$oBlock->iInputId = $this->m_iInputId;
|
||||
$oBlock->sNameSuffix = $this->m_sNameSuffix;
|
||||
$oBlock->bDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
$oBlock->oWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oBlock->sExtKeyToRemote = $this->m_sExtKeyToRemote;
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$oBlock->bJSDoSearch = utils::IsHighCardinality($this->m_sRemoteClass) ? 'false' : 'true';
|
||||
$oBlock->sFormPrefix = $sFormPrefix;
|
||||
$oBlock->sRemoteClass = $this->m_sRemoteClass;
|
||||
|
||||
$sHtmlValue = '';
|
||||
$sHtmlValue .= "<div id=\"linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
|
||||
$sHtmlValue .= "<input type=\"hidden\" id=\"{$sFormPrefix}{$this->m_iInputId}\">\n";
|
||||
$oValue->Rewind();
|
||||
$aForm = array();
|
||||
$iAddedId = -1; // Unique id for new links
|
||||
while ($oCurrentLink = $oValue->Fetch())
|
||||
|
||||
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
// Don't automatically launch the search if the table is huge
|
||||
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
|
||||
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
EOF
|
||||
);
|
||||
|
||||
while($oCurrentLink = $oValue->Fetch())
|
||||
{
|
||||
// We try to retrieve the remote object as usual
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote),
|
||||
false /* Must not be found */);
|
||||
// We try to retrieve the remote object as usual
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */);
|
||||
// If successful, it means that we can edit its link
|
||||
if ($oLinkedObj !== null) {
|
||||
$bReadOnly = false;
|
||||
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else {
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */, true);
|
||||
}
|
||||
if($oLinkedObj !== null)
|
||||
{
|
||||
$bReadOnly = false;
|
||||
}
|
||||
// Else we retrieve it without restrictions (silos) and will display its link as readonly
|
||||
else
|
||||
{
|
||||
$bReadOnly = true;
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */, true);
|
||||
}
|
||||
|
||||
if ($oCurrentLink->IsNew()) {
|
||||
$key = $iAddedId--;
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
if ($oCurrentLink->IsNew())
|
||||
{
|
||||
$key = $iAddedId--;
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
}
|
||||
$oDataTable = DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aForm);
|
||||
$oDataTable->SetOptions(['select_mode' => 'custom']);
|
||||
$oBlock->AddSubBlock($oDataTable);
|
||||
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
|
||||
|
||||
$oBlock->AddControls();
|
||||
|
||||
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
|
||||
$sHtmlValue .= "<span style=\"float:left;\"> <img src=\"../images/tv-item-last.gif\"> <input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
|
||||
$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 id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
|
||||
$sHtmlValue .= "<span style=\"clear:both;\"><p> </p></span>\n";
|
||||
$sHtmlValue .= "</div>\n";
|
||||
$oPage->add_at_the_end("<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\"></div>"); // To prevent adding forms inside the main form
|
||||
return $sHtmlValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,49 +443,55 @@ JS
|
||||
*/
|
||||
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array())
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
|
||||
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0)
|
||||
{
|
||||
$oAlreadyLinkedFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN');
|
||||
$oAlreadyLinkedExpression = $oAlreadyLinkedFilter->GetCriteria();
|
||||
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->RenderExpression();
|
||||
} else {
|
||||
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->Render();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sAlreadyLinkedExpression = '';
|
||||
}
|
||||
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
|
||||
if (!empty($oCurrentObj)) {
|
||||
if(!empty($oCurrentObj))
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
$aPrefillFormParam['filter'] = $oFilter;
|
||||
$aPrefillFormParam['dest_class'] = $this->m_sRemoteClass;
|
||||
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
|
||||
}
|
||||
|
||||
$sLinkedSetId = "{$this->m_sAttCode}{$this->m_sNameSuffix}";
|
||||
|
||||
$oBlock = new BlockObjectPickerDialog();
|
||||
$oPage->AddUiBlock($oBlock);
|
||||
|
||||
$oBlock->sLinkedSetId = $sLinkedSetId;
|
||||
$oBlock->iInputId = $this->m_iInputId;
|
||||
$oBlock->sLinkedClassName = MetaModel::GetName($this->m_sLinkedClass);
|
||||
$oBlock->sClassName = MetaModel::GetName($this->m_sClass);
|
||||
|
||||
$oDisplayBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}",
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
array(
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}",
|
||||
'table_id' => "add_{$sLinkedSetId}",
|
||||
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
'table_id' => 'add_'.$this->m_sAttCode,
|
||||
'table_inner_id' => "ResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
|
||||
'selection_mode' => true,
|
||||
'json' => $sJson,
|
||||
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
'hidden_criteria' => $sAlreadyLinkedExpression,
|
||||
)));
|
||||
|
||||
$oBlock->AddForm();
|
||||
));
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
|
||||
$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=\"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=\"button\" onclick=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -539,44 +541,17 @@ JS
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
|
||||
$iAdditionId = $iMaxAddedId + 1;
|
||||
foreach ($aLinkedObjectIds as $iObjectId) {
|
||||
foreach($aLinkedObjectIds as $iObjectId)
|
||||
{
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
|
||||
if (is_object($oLinkedObj)) {
|
||||
if (is_object($oLinkedObj))
|
||||
{
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId);
|
||||
$oP->AddUiBlock($oRow);
|
||||
$oP->add($this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iAdditionId));
|
||||
$iAdditionId++;
|
||||
} else {
|
||||
$oP->p(Dict::Format('UI:Error:Object_Class_Id_NotFound', $this->m_sLinkedClass, $iObjectId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oP
|
||||
* @param int $iMaxAddedId
|
||||
* @param $oFullSetFilter
|
||||
* @param DBObject $oCurrentObj
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function DoAddIndirectLinks(JsonPage $oP, $iMaxAddedId, $oFullSetFilter, $oCurrentObj)
|
||||
{
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
|
||||
$iAdditionId = $iMaxAddedId + 1;
|
||||
foreach ($aLinkedObjectIds as $iObjectId) {
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
|
||||
if (is_object($oLinkedObj)) {
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
|
||||
$aData = [];
|
||||
foreach ($aRow as $item) {
|
||||
$aData[] = $item;
|
||||
}
|
||||
$oP->AddData($aData);
|
||||
$iAdditionId++;
|
||||
} else {
|
||||
else
|
||||
{
|
||||
$oP->p(Dict::Format('UI:Error:Object_Class_Id_NotFound', $this->m_sLinkedClass, $iObjectId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,10 +20,11 @@
|
||||
* Class UIPasswordWidget
|
||||
* UI wdiget for displaying and editing one-way encrypted passwords
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UIPasswordWidget
|
||||
@@ -65,12 +66,12 @@ class UIPasswordWidget
|
||||
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
|
||||
$sHtmlValue .= '</div>';
|
||||
|
||||
$sHtmlValue .= '<span class="form_validation ibo-field-validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
|
||||
$sHtmlValue .= '<span class="form_validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
|
||||
|
||||
$oPage->add_ready_script("$('#$this->iId').on('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#$this->iId').on('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#{$this->iId}_confirm').on('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#{$this->iId}').on('update', function(evt, sFormId)
|
||||
$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
|
||||
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
|
||||
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
|
||||
{
|
||||
if ($(this).prop('disabled'))
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2010-2021 Combodo SARL
|
||||
* Copyright (C) 2010-2018 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/displayblock.class.inc.php');
|
||||
|
||||
class UISearchFormForeignKeys
|
||||
@@ -40,11 +41,12 @@ class UISearchFormForeignKeys
|
||||
*/
|
||||
public function ShowModalSearchForeignKeys($oPage, $sTitle)
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
|
||||
array(
|
||||
'menu' => false,
|
||||
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
|
||||
@@ -53,26 +55,19 @@ class UISearchFormForeignKeys
|
||||
'selection_mode' => true,
|
||||
'cssCount' => "#count_{$this->m_iInputId}",
|
||||
'query_params' => $oFilter->GetInternalParams(),
|
||||
)));
|
||||
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
|
||||
$sCancel = Dict::S('UI:Button:Cancel');
|
||||
$sAdd = Dict::S('UI:Button:Add');
|
||||
|
||||
$oPage->add(<<<HTML
|
||||
<form id="ObjectsAddForm_{$this->m_iInputId}">
|
||||
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
|
||||
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
|
||||
</div>
|
||||
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
|
||||
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_iInputId}').dialog('close');">
|
||||
<input id="btn_ok_add_{$this->m_iInputId}" disabled="disabled" type="button" onclick="return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
|
||||
));
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_iInputId}\">\n";
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_iInputId}\" 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=\"hidden\" id=\"count_{$this->m_iInputId}\" value=\"0\"/>";
|
||||
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_iInputId}').dialog('close');\"> <input id=\"btn_ok_{$this->m_iInputId}\" disabled=\"disabled\" type=\"button\" onclick=\"return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes });");
|
||||
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').on('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').bind('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
|
||||
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId}').resize(oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);");
|
||||
}
|
||||
|
||||
@@ -117,4 +112,4 @@ HTML
|
||||
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Class UIWizard
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* Store and retrieve user custom dashboards
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
require_once(APPROOT.'/core/dbobject.class.php');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* Store and retrieve user's preferences (i.e persistent per user settings)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
require_once(APPROOT.'/core/dbobject.class.php');
|
||||
@@ -34,215 +34,165 @@ require_once(APPROOT.'/core/userrights.class.inc.php');
|
||||
*/
|
||||
class appUserPreferences extends DBObject
|
||||
{
|
||||
/** @var array Associative array of the prefs. of users: <USER_ID> => <PREFS> */
|
||||
private static $aUsersPrefs = []; // Local cache
|
||||
|
||||
private static $oUserPrefs = null; // Local cache
|
||||
|
||||
/**
|
||||
* Get the value of the given property/preference
|
||||
* If not set, the default value will be returned
|
||||
*
|
||||
* @param string $sCode Code/Name of the property to set
|
||||
* @param mixed $defaultValue The default value
|
||||
* @param string|null $sUserId Added in 3.0.0. ID of the user we want the pref. from, default is the current user
|
||||
*
|
||||
* @return mixed The value of the property for the current user
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
* @since 3.0.0 Added the $sUserId parameter
|
||||
* @param string $sDefaultValue The default value
|
||||
* @return string The value of the property for the current user
|
||||
*/
|
||||
public static function GetPref($sCode, $defaultValue, ?string $sUserId = null)
|
||||
public static function GetPref($sCode, $sDefaultValue)
|
||||
{
|
||||
if (null === $sUserId) {
|
||||
$sUserId = UserRights::GetUserId();
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
self::Load();
|
||||
}
|
||||
|
||||
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
|
||||
self::Load($sUserId);
|
||||
}
|
||||
|
||||
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
|
||||
if (array_key_exists($sCode, $aPrefs)) {
|
||||
$aPrefs = self::$oUserPrefs->Get('preferences');
|
||||
if (array_key_exists($sCode, $aPrefs))
|
||||
{
|
||||
return $aPrefs[$sCode];
|
||||
} else {
|
||||
return $defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sDefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value for a given preference for the current user, and stores it into the database
|
||||
*
|
||||
* Set the value for a given preference, and stores it into the database
|
||||
* @param string $sCode Code/Name of the property/preference to set
|
||||
* @param mixed $value Value to set
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @param string $sValue Value to set
|
||||
*/
|
||||
public static function SetPref($sCode, $value)
|
||||
public static function SetPref($sCode, $sValue)
|
||||
{
|
||||
$sUserId = UserRights::GetUserId();
|
||||
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
|
||||
self::Load($sUserId);
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
self::Load();
|
||||
}
|
||||
|
||||
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
|
||||
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $value)) {
|
||||
$aPrefs = self::$oUserPrefs->Get('preferences');
|
||||
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $sValue))
|
||||
{
|
||||
// Do not write it again
|
||||
} else {
|
||||
$aPrefs[$sCode] = $value;
|
||||
self::$aUsersPrefs[$sUserId]->Set('preferences', $aPrefs);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aPrefs[$sCode] = $sValue;
|
||||
self::$oUserPrefs->Set('preferences', $aPrefs);
|
||||
self::Save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the value for a given preference (or list of preferences that matches a pattern) for the current user, and updates the database
|
||||
*
|
||||
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
|
||||
* @param string $sCodeOrPattern Code/Pattern of the properties/preferences to reset
|
||||
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
|
||||
*
|
||||
* @return void
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function UnsetPref($sCodeOrPattern, $bPattern = false)
|
||||
{
|
||||
$sUserId = UserRights::GetUserId();
|
||||
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
|
||||
self::Load($sUserId);
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
self::Load();
|
||||
}
|
||||
|
||||
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
|
||||
if ($bPattern) {
|
||||
$aPrefs = self::$oUserPrefs->Get('preferences');
|
||||
if ($bPattern)
|
||||
{
|
||||
// the supplied code is a pattern, clear all preferences that match
|
||||
foreach ($aPrefs as $sKey => $void) {
|
||||
if (preg_match($sCodeOrPattern, $sKey)) {
|
||||
foreach($aPrefs as $sKey => $void)
|
||||
{
|
||||
if (preg_match($sCodeOrPattern, $sKey))
|
||||
{
|
||||
unset($aPrefs[$sKey]);
|
||||
}
|
||||
}
|
||||
self::$aUsersPrefs[$sUserId]->Set('preferences', $aPrefs);
|
||||
} else {
|
||||
unset($aPrefs[$sCodeOrPattern]);
|
||||
self::$aUsersPrefs[$sUserId]->Set('preferences', $aPrefs);
|
||||
self::$oUserPrefs->Set('preferences', $aPrefs);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($aPrefs[$sCodeOrPattern]);
|
||||
self::$oUserPrefs->Set('preferences', $aPrefs);
|
||||
}
|
||||
|
||||
// Save only if needed
|
||||
if (self::$aUsersPrefs[$sUserId]->IsModified()) {
|
||||
if (self::$oUserPrefs->IsModified())
|
||||
{
|
||||
self::Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call this function to get all the preferences for the current user, packed as a JSON object
|
||||
*
|
||||
* Call this function to get all the preferences for the user, packed as a JSON object
|
||||
* @return string JSON representation of the preferences
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public static function GetAsJSON()
|
||||
{
|
||||
$sUserId = UserRights::GetUserId();
|
||||
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
|
||||
self::Load($sUserId);
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
self::Load();
|
||||
}
|
||||
|
||||
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
|
||||
|
||||
$aPrefs = self::$oUserPrefs->Get('preferences');
|
||||
return json_encode($aPrefs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function if the user has changed (like when doing a logoff...)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function ResetPreferences()
|
||||
{
|
||||
self::$aUsersPrefs = [];
|
||||
self::$oUserPrefs = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to ERASE all the preferences from the current user (only in memory, not in DB)
|
||||
*
|
||||
* @return void
|
||||
* Call this function to ERASE all the preferences from the current user
|
||||
*/
|
||||
public static function ClearPreferences()
|
||||
{
|
||||
$sUserId = UserRights::GetUserId();
|
||||
unset(self::$aUsersPrefs[$sUserId]);
|
||||
self::$oUserPrefs = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save preferences of the current user in the DB, for now we don't allow interfering with an other users preferences
|
||||
*
|
||||
* @return void;
|
||||
*/
|
||||
|
||||
protected static function Save()
|
||||
{
|
||||
$sUserId = UserRights::GetUserId();
|
||||
|
||||
if (array_key_exists($sUserId, self::$aUsersPrefs)) {
|
||||
if (self::$aUsersPrefs[$sUserId]->IsModified()) {
|
||||
if (self::$oUserPrefs != null)
|
||||
{
|
||||
if (self::$oUserPrefs->IsModified())
|
||||
{
|
||||
utils::PushArchiveMode(false);
|
||||
self::$aUsersPrefs[$sUserId]->DBUpdate();
|
||||
self::$oUserPrefs->DBUpdate();
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the preferences for the current user, creating the record in the database
|
||||
* if needed
|
||||
*
|
||||
* @param string|null $sUserId Added in 3.0.0. ID of the user to load the prefs for, if null then current user will be used.
|
||||
*
|
||||
* @return void;
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
* @since 3.0.0 Added $sUserId parameter
|
||||
*/
|
||||
protected static function Load(?string $sUserId = null)
|
||||
protected static function Load()
|
||||
{
|
||||
// Already in cache
|
||||
if (array_key_exists($sUserId, self::$aUsersPrefs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $sUserId) {
|
||||
$sUserId = UserRights::GetUserId();
|
||||
}
|
||||
|
||||
if (self::$oUserPrefs != null) return;
|
||||
$oSearch = new DBObjectSearch('appUserPreferences');
|
||||
$oSearch->AddCondition('userid', $sUserId, '=');
|
||||
$oSearch->AddCondition('userid', UserRights::GetUserId(), '=');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oObj = $oSet->Fetch();
|
||||
if ($oObj == null) {
|
||||
if ($oObj == null)
|
||||
{
|
||||
// No prefs (yet) for this user, create the object
|
||||
$oObj = new appUserPreferences();
|
||||
$oObj->Set('userid', $sUserId);
|
||||
$oObj->Set('userid', UserRights::GetUserId());
|
||||
$oObj->Set('preferences', array()); // Default preferences: an empty array
|
||||
try {
|
||||
try
|
||||
{
|
||||
utils::PushArchiveMode(false);
|
||||
$oObj->DBInsert();
|
||||
utils::PopArchiveMode();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Ignore errors
|
||||
}
|
||||
}
|
||||
self::$aUsersPrefs[$sUserId] = $oObj;
|
||||
self::$oUserPrefs = $oObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
@@ -263,22 +213,9 @@ class appUserPreferences extends DBObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloading this function here to secure a fix done right before the release
|
||||
* The real fix should be to implement this verb in DBObject
|
||||
*
|
||||
* @param \CMDBChange $oChange
|
||||
* @param bool|null $bSkipStrongSecurity
|
||||
* @param \DeletionPlan|null $oDeletionPlan
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DeleteException
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
* Overloading this function here to secure a fix done right before the release
|
||||
* The real fix should be to implement this verb in DBObject
|
||||
*/
|
||||
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
|
||||
{
|
||||
utils::PushArchiveMode(false);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2021 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Class WizardHelper
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -335,41 +335,20 @@ class WizardHelper
|
||||
{
|
||||
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
|
||||
}
|
||||
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
public function GetReturnNotEditableFields()
|
||||
{
|
||||
return $this->m_aData['m_bReturnNotEditableFields'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string JS code to be executed for fields update
|
||||
* @since 3.0.0 N°3198
|
||||
*/
|
||||
public function GetJsForUpdateFields()
|
||||
{
|
||||
$sWizardHelperJsVar = ($this->m_aData['m_sWizHelperJsVarName']) ?? 'oWizardHelper'.$this->GetFormPrefix();
|
||||
$sWizardHelperJson = $this->ToJSON();
|
||||
|
||||
return <<<JS
|
||||
{$sWizardHelperJsVar}.m_oData = {$sWizardHelperJson};
|
||||
{$sWizardHelperJsVar}.UpdateFields();
|
||||
JS;
|
||||
}
|
||||
|
||||
|
||||
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
|
||||
{
|
||||
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
|
||||
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
|
||||
foreach ($aSet as $aLinkObj)
|
||||
foreach($aSet as $aLinkObj)
|
||||
{
|
||||
$oLink = MetaModel::NewObject($sLinkClass);
|
||||
foreach ($aLinkObj as $sAttCode => $value)
|
||||
foreach($aLinkObj as $sAttCode => $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
|
||||
@@ -1,7 +1,109 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/XMLPage.php
|
||||
* Class XMLPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
*/
|
||||
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
/**
|
||||
* Simple web page with no includes or fancy formatting, useful to generateXML documents
|
||||
* The page adds the content-type text/XML and the encoding into the headers
|
||||
*/
|
||||
class XMLPage extends WebPage
|
||||
{
|
||||
/**
|
||||
* For big XML files, it's better NOT to store everything in memory and output the XML piece by piece
|
||||
*/
|
||||
var $m_bPassThrough;
|
||||
var $m_bHeaderSent;
|
||||
|
||||
function __construct($s_title, $bPassThrough = false)
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
$this->m_bPassThrough = $bPassThrough;
|
||||
$this->m_bHeaderSent = false;
|
||||
$this->add_header("Content-type: text/xml; charset=".self::PAGES_CHARSET);
|
||||
$this->no_cache();
|
||||
$this->add_xframe_options();
|
||||
$this->add_header("Content-location: export.xml");
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
if (!$this->m_bPassThrough)
|
||||
{
|
||||
// Get the unexpected output but do nothing with it
|
||||
$sTrash = $this->ob_get_clean_safe();
|
||||
|
||||
$sCharset = self::PAGES_CHARSET;
|
||||
$this->s_content = "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n".trim($this->s_content);
|
||||
$this->add_header("Content-Length: ".strlen($this->s_content));
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
echo $this->s_content;
|
||||
}
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
{
|
||||
if (!$this->m_bPassThrough)
|
||||
{
|
||||
parent::add($sText);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->m_bHeaderSent)
|
||||
{
|
||||
echo $sText;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
foreach($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
$sCharset = self::PAGES_CHARSET;
|
||||
echo "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n";
|
||||
echo trim($s_captured_output);
|
||||
echo trim($this->s_content);
|
||||
echo $sText;
|
||||
$this->m_bHeaderSent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function small_p($sText)
|
||||
{
|
||||
}
|
||||
|
||||
public function table($aConfig, $aData, $aParams = array())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user