Änderungen von Dokument Live-Table Ergebnismakros
Zuletzt geändert von Daniel Herrmann am 2026/02/07 23:25
Von Version 1.1
bearbeitet von admin
am 2025/02/23 10:22
am 2025/02/23 10:22
Änderungskommentar:
Install extension [org.xwiki.platform:xwiki-platform-livetable-ui/17.0.0]
Auf Version
4.1
bearbeitet von Daniel Herrmann
am 2026/02/07 23:25
am 2026/02/07 23:25
Änderungskommentar:
Install extension [org.xwiki.platform:xwiki-platform-livetable-ui/18.0.1]
Zusammenfassung
Details
- Seiteneigenschaften
-
- Dokument-Autor
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki. admin1 +XWiki.dherrman - Inhalt
-
... ... @@ -37,9 +37,10 @@ 37 37 #foreach($colname in $collist) 38 38 ## If a classname is defined and the class field corresponding to the column name, 39 39 ## we check the type of the field and skip it if it's Password. 40 - #if ($className != '' && $class.get($colname)) 41 - #set ($isPasswordType = $class.get($colname).classType == 'Password') 42 - #set ($isEmailType = $class.get($colname).classType == 'Email') 40 + #livetable_getPropertyClassAndType($colname) 41 + #if ($propType != '') 42 + #set ($isPasswordType = $propClass.get($colname).classType == 'Password') 43 + #set ($isEmailType = $propClass.get($colname).classType == 'Email') 43 43 #set ($emailObfuscated = $services.mail.general.shouldObfuscate()) 44 44 #if (!($isPasswordType || ($isEmailType && $emailObfuscated))) 45 45 #livetable_addColumnToQuery($colname) ... ... @@ -114,7 +114,8 @@ 114 114 ## The column is a document field. 115 115 ## 116 116 ## These document fields need to be ordered as raw values and not as strings. 117 - #set($rawDocumentFields = ['translation', 'date', 'contentUpdateDate', 'creationDate', 'elements', 'minorEdit1', 'hidden']) 118 + #set($rawDocumentFields = ['translation', 'date', 'contentUpdateDate', 'creationDate', 'elements', 119 + 'minorEdit1', 'hidden', 'enforceRequiredRights']) 118 118 #set($documentField = $stringtool.removeStart($order, 'doc.')) 119 119 #setOrderClause(${safe_tableAlias.replace('_','.')}, ${orderDirection}, $rawDocumentFields.contains($documentField)) 120 120 #else ... ... @@ -305,10 +305,7 @@ 305 305 #if(!$offset || $offset < 0) 306 306 #set($offset = 0) 307 307 #end 308 - #set($limit = $numbertool.toNumber($request.get('limit')).intValue()) 309 - #if(!$limit) 310 - #set ($limit = 15) 311 - #end 310 + #getAndValidateQueryLimitFromRequest('limit', 15, $limit) 312 312 #set($query = $services.query.hql($sql)) 313 313 ## Apply query filters if defined. Otherwise use default. 314 314 #foreach ($queryFilter in $stringtool.split($!request.queryFilters, ', ')) ... ... @@ -419,6 +419,7 @@ 419 419 #set($discard = $row.put('doc_creationDate', $xwiki.formatDate($translatedDoc.creationDate))) 420 420 #set($discard = $row.put('doc_creator', $xwiki.getPlainUserName($translatedDoc.creatorReference))) 421 421 #set($discard = $row.put('doc_hidden', $translatedDoc.isHidden())) 421 + #set($discard = $row.put('doc_enforceRequiredRights', $itemDoc.isEnforceRequiredRights())) 422 422 #foreach($colname in $collist) 423 423 #gridresult_buildColumnJSON($colname $row) 424 424 #end ... ... @@ -560,8 +560,10 @@ 560 560 #elseif($propType == 'TextAreaClass' || $propType == 'UsersClass' || $propType == 'GroupsClass') 561 561 #set($tableName = 'LargeStringProperty') 562 562 #elseif($propType == 'StaticListClass' || $propType == 'DBListClass' || $propType == 'DBTreeListClass' || $propType == 'PageClass') 563 + ## The following logic is mirrored from ListClass and might need to be updated when the logic in ListClass changes. 563 563 #set($multiSelect = $propClass.get($colname).getProperty('multiSelect').getValue()) 564 564 #set($relationalStorage = $propClass.get($colname).getProperty('relationalStorage').getValue()) 566 + #set($largeStorage = $propClass.get($colname).getProperty('largeStorage').getValue()) 565 565 #if($multiSelect == 1) 566 566 #if($relationalStorage == 1) 567 567 #set($tableName = 'DBStringListProperty') ... ... @@ -568,6 +568,8 @@ 568 568 #else 569 569 #set($tableName = 'StringListProperty') 570 570 #end 573 + #elseif($largeStorage == 1) 574 + #set($tableName = 'LargeStringProperty') 571 571 #else 572 572 #set($tableName = 'StringProperty') 573 573 #end ... ... @@ -689,6 +689,19 @@ 689 689 #elseif ($colName == 'doc.date' || $colName == 'doc.creationDate' || $colName == 'doc.contentUpdateDate') 690 690 #livetable_getTableAlias($colName) 691 691 #livetable_filterDateProperty() 696 + #elseif ($colName == 'doc.hidden' || $colName == 'doc.minorEdit1' || $colName == 'doc.enforceRequiredRights') 697 + ## Boolean document fields need special handling to work across all databases 698 + ## (HSQLDB/PostgreSQL use true/false, MySQL/MariaDB/Oracle use 1/0). 699 + ## Support both true/false and 1/0 as Live Data uses the former while LiveTable uses the latter. 700 + #set ($booleanValue = ($filterValue.toLowerCase() == 'true' || $filterValue == '1')) 701 + ## No need to clean the column name since it's only one of the given values. 702 + #if ($whereParams.entrySet()) 703 + #set ($whereSql = "${whereSql} and $colName = :${colName.replace('.', '_')}_filter") 704 + #set ($discard = $whereParams.put("${colName.replace('.', '_')}_filter", $booleanValue)) 705 + #else 706 + #set ($whereSql = "${whereSql} and $colName = ?") 707 + #set ($discard = $whereParams.add($booleanValue)) 708 + #end 692 692 #else 693 693 #set ($safeColName = $colName.replaceAll('[^a-zA-Z0-9_.]', '').replace('_', '.')) 694 694 #if ($whereParams.entrySet()) ... ... @@ -881,34 +881,79 @@ 881 881 *# 882 882 #macro (livetable_filterDBStringListProperty) 883 883 ## Perform exact matching by default if no match type is specified. 884 - ## Note that for DBStringList properties we takeintoaccount onlythefirstmatch type,evenifmultiplefilter885 - ## valuesare specified. Basicallythefirst match type isused for allfilter values.901 + ## For DBStringList properties we still apply a single match type to all non-empty values, but we also allow 902 + ## combining the special "empty" match type with other match types. 886 886 #livetable_getMatchTypes($colname $filterValues.size() 'exact') 887 - #if ($matchType == 'partial' || $matchType == 'prefix') 888 - ## We need to join with the list of values in order to be able to use the LIKE operator. 889 - #set ($matchTarget = "${safe_tableAlias}_item") 890 - #if ($whereParams.entrySet()) 891 - #set ($paramPrefix = "${safe_tableAlias}_item_") 904 + #livetable_getJoinOperator($colname) 905 + 906 + ## Collect non-empty filter values (those whose match type is not 'empty'). 907 + #set ($nonEmptyValues = []) 908 + #set ($hasEmpty = false) 909 + #set ($matchType = 'invalid') 910 + #foreach ($filterValue in $filterValues) 911 + #if ($matchTypes.get($foreach.index) == 'empty') 912 + #set ($hasEmpty = true) 913 + ## When we want to match empty values, we can't have other match types than exact for non-empty values as for 914 + ## other match types, we need to join with the list of values, which is not compatible with checking for 915 + ## emptiness. 916 + #set ($matchType = 'exact') 917 + #elseif ("$!filterValue" != '') 918 + #set ($discard = $nonEmptyValues.add($filterValue)) 919 + ## Store the first non-empty match type. 920 + #if ($matchType == 'invalid') 921 + #set ($matchType = $matchTypes.get($foreach.index)) 922 + #end 923 + #end 924 + #end 925 + 926 + ## 1) Apply the non-empty constraints. 927 + #if (!$nonEmptyValues.isEmpty()) 928 + #if ($matchType == 'partial' || $matchType == 'prefix') 929 + ## We need to join with the list of values in order to be able to use the LIKE operator. 930 + #set ($matchTarget = "${safe_tableAlias}_item") 931 + #if ($whereParams.entrySet()) 932 + #set ($paramPrefix = "${safe_tableAlias}_item_") 933 + #else 934 + #set ($paramPrefix = $NULL) 935 + #end 936 + #set ($joinPos = $mathtool.add($fromSql.lastIndexOf(" $safe_tableAlias"), $mathtool.add($safe_tableAlias.length(), 1))) 937 + #set ($fromSql = "$fromSql.substring(0, $joinPos) join ${safe_tableAlias}.list as $matchTarget $fromSql.substring($joinPos)") 892 892 #else 893 - #set ($paramPrefix = $NULL) 939 + ## Fall-back on exact matching even if the match type is specified, when its value is not supported. 940 + #set ($matchType = 'exact') 941 + #set ($matchTarget = "${safe_tableAlias}.list") 942 + #if ($whereParams.entrySet()) 943 + #set ($paramPrefix = "${safe_tableAlias}_list_") 944 + #else 945 + #set ($paramPrefix = $NULL) 946 + #end 894 894 #end 895 - #set ($joinPos = $mathtool.add($fromSql.lastIndexOf(" $safe_tableAlias"), $mathtool.add($safe_tableAlias.length(), 1))) 896 - #set ($fromSql = "$fromSql.substring(0, $joinPos) join ${safe_tableAlias}.list as $matchTarget $fromSql.substring($joinPos)") 897 - #else 898 - ## Fall-back on exact matching even if the match type is specified, when its value is not supported. 899 - #set ($matchType = 'exact') 900 - #set ($matchTarget = "${safe_tableAlias}.list") 901 - #if ($whereParams.entrySet()) 902 - #set ($paramPrefix = "${safe_tableAlias}_list_") 948 + 949 + #set ($filterQuery = "#livetable_getFilterQuery($matchTarget $matchType true $nonEmptyValues.size() $paramPrefix $NULL)") 950 + #if (!$hasEmpty) 951 + ## Only non-empty values are used, combine directly with the existing constraints, otherwise, they will be 952 + ## combined later together with the empty constraint. 953 + #set ($whereSql = "$whereSql and ($filterQuery.trim())") 954 + #end 955 + #foreach ($filterValue in $nonEmptyValues) 956 + #livetable_addFilterParam($filterValue $matchType $whereParams "${paramPrefix}${foreach.count}") 957 + #end 958 + #end 959 + 960 + ## 2) Optionally add a single constraint if any match type is 'empty'. 961 + #if ($hasEmpty) 962 + ## "empty" means that there is no list item stored for this property on the filtered object. 963 + ## The proper way to check for that would be "${safe_tableAlias}.list IS EMPTY", but JSQL cannot parse "IS EMPTY" 964 + ## which means that we cannot use it without programming right. 965 + #set ($emptyConstraint = "size(${safe_tableAlias}.list) = 0") 966 + #if ($nonEmptyValues.isEmpty()) 967 + ## Only 'empty' is used, combine with the existing constraints. 968 + #set ($whereSql = "${whereSql} and ${emptyConstraint}") 903 903 #else 904 - #set ($paramPrefix = $NULL) 970 + ## Combine non-empty group and empty condition using the join operator. 971 + #set ($whereSql = "${whereSql} and ($filterQuery.trim() ${joinOperator} ${emptyConstraint})") 905 905 #end 906 906 #end 907 - #set ($filterQuery = "#livetable_getFilterQuery($matchTarget $matchType true $filterValues.size() $paramPrefix $NULL)") 908 - #set ($whereSql = "$whereSql and ($filterQuery.trim())") 909 - #foreach ($filterValue in $filterValues) 910 - #livetable_addFilterParam($filterValue $matchType $whereParams "${paramPrefix}${foreach.count}") 911 - #end 912 912 #end 913 913 914 914 ... ... @@ -1003,9 +1003,9 @@ 1003 1003 #if ($matchType == 'partial' || $matchType == 'prefix') 1004 1004 #livetable_repeatParams("upper($column) like upper(?)", " $joinOperator ", $valueCount, $paramPrefix, $paramOffset) 1005 1005 #elseif($matchType == 'empty') 1006 - ## Check if the value of the column is like the empty parameter (which is often the empty string), or if the value 1068 + ## Check if the value of the column is like the empty parameter (which is often the empty string), or if the value 1007 1007 ## of the column is null (to be compliant with Oracle which stores the empty string as a NULL value). 1008 - #livetable_repeatParams("($column like ? or $column is null)", " $joinOperator ", $valueCount, $paramPrefix, 1070 + #livetable_repeatParams("($column like ? or $column is null)", " $joinOperator ", $valueCount, $paramPrefix, 1009 1009 $paramOffset) 1010 1010 #elseif ($isList) 1011 1011 #livetable_repeatParams("? in elements($column)", " $joinOperator ", $valueCount, $paramPrefix, $paramOffset)