diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a4038b82e..a0d6bd3d49 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,7 @@ on: [push, pull_request, workflow_dispatch] env: MAVEN_OPTS: >- -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 + SCREENSHOT_DIRECTORY: '/tmp/pf_it/' jobs: build: @@ -54,6 +55,13 @@ jobs: run: mvn clean install -pl -primefaces-integration-tests-jakarta -T1C -DskipTests -Dcheckstyle.skip -Djsdoc.skip.typedoc=true -Dmaven.javadoc.skip=true --batch-mode --show-version - name: Integration Tests run: mvn -B -V clean install -fprimefaces-integration-tests/pom.xml -Pintegration-tests,parallel-execution,headless,chrome,theme-saga,csp,${{ matrix.facesimpl }} + - name: Upload failure-screenshots + uses: actions/upload-artifact@v4 + if: always() + with: + name: failed_tests_screenshots_java${{ matrix.java }}_${{ matrix.facesimpl }} + if-no-files-found: ignore + path: /tmp/pf_it/ integration-tests-40: @@ -77,3 +85,10 @@ jobs: run: mvn clean install -T1C -DskipTests -Dcheckstyle.skip -Djsdoc.skip.typedoc=true -Dmaven.javadoc.skip=true --batch-mode --show-version - name: Integration Tests run: mvn -B -V clean install -fprimefaces-integration-tests-jakarta/pom.xml -Pintegration-tests,parallel-execution,headless,chrome,theme-saga,csp,${{ matrix.facesimpl }} + - name: Upload failure-screenshots + uses: actions/upload-artifact@v4 + if: always() + with: + name: failed_tests_screenshots_java${{ matrix.java }}_${{ matrix.facesimpl }}_jakarta + if-no-files-found: ignore + path: /tmp/pf_it/ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9a9f084396..2ddf16a803 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -5,6 +5,9 @@ on: schedule: - cron: '0 6 * * *' +env: + SCREENSHOT_DIRECTORY: '/tmp/pf_it/' + permissions: contents: read @@ -33,3 +36,10 @@ jobs: run: mvn clean install -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 --batch-mode --show-version - name: Integration Tests run: mvn -B -V clean install -fprimefaces-integration-tests/pom.xml -Pintegration-tests,headless,${{ matrix.profile }} + - name: Upload failure-screenshots + uses: actions/upload-artifact@v4 + if: always() + with: + name: failed_tests_screenshots_java${{ matrix.java }}_${{ matrix.facesimpl }} + if-no-files-found: ignore + path: /tmp/pf_it/ diff --git a/docs/10_0_0/components/confirm.md b/docs/10_0_0/components/confirm.md index 03d170a0b5..8aa6231826 100644 --- a/docs/10_0_0/components/confirm.md +++ b/docs/10_0_0/components/confirm.md @@ -19,6 +19,7 @@ Confirm is a behavior element used to integrate with global confirm dialog/popup | icon | null | String | Icon to display next to message. | disabled | false | Boolean | Disables confirm behavior when true. | escape | true | Boolean | Whether to escape the message. +| beforeShow | null | String | Callback to execute before displaying confirmation dialog. Return false to prevent dialog from appearing. ## Getting started with Confirm See global confirm dialog/popup topic in next section for details. diff --git a/docs/10_0_0/components/selectcheckboxmenu.md b/docs/10_0_0/components/selectcheckboxmenu.md index 39c17edced..b487058e1c 100644 --- a/docs/10_0_0/components/selectcheckboxmenu.md +++ b/docs/10_0_0/components/selectcheckboxmenu.md @@ -57,6 +57,7 @@ labelSeparator | , | String | Separator for joining item lables if updateLabel i emptyLabel | null | String | Label to be shown in updateLabel mode when no item is selected. If not set the label is shown. filterPlaceholder | null | String | Placeholder text to show when filter input is empty. hideNoSelectionOption | false | boolean | Flag indicating that, if this component is activated by the user, The "no selection option", if any, must be hidden. +collectionType | null | String | Optional attribute that is a literal string that is the fully qualified class name of a concrete class that implements `java.util.Collection` or an EL expression that evaluates to either 1. such a String, or 2. the `Class` object itself. ## Getting started with SelectCheckboxMenu diff --git a/docs/11_0_0/components/confirm.md b/docs/11_0_0/components/confirm.md index 03d170a0b5..8aa6231826 100644 --- a/docs/11_0_0/components/confirm.md +++ b/docs/11_0_0/components/confirm.md @@ -19,6 +19,7 @@ Confirm is a behavior element used to integrate with global confirm dialog/popup | icon | null | String | Icon to display next to message. | disabled | false | Boolean | Disables confirm behavior when true. | escape | true | Boolean | Whether to escape the message. +| beforeShow | null | String | Callback to execute before displaying confirmation dialog. Return false to prevent dialog from appearing. ## Getting started with Confirm See global confirm dialog/popup topic in next section for details. diff --git a/docs/11_0_0/components/selectcheckboxmenu.md b/docs/11_0_0/components/selectcheckboxmenu.md index 8f4ef79a48..e485a553e1 100644 --- a/docs/11_0_0/components/selectcheckboxmenu.md +++ b/docs/11_0_0/components/selectcheckboxmenu.md @@ -57,6 +57,7 @@ labelSeparator | , | String | Separator for joining item lables if updateLabel i emptyLabel | null | String | Label to be shown in updateLabel mode when no item is selected. If not set the label is shown. filterPlaceholder | null | String | Placeholder text to show when filter input is empty. hideNoSelectionOption | false | boolean | Flag indicating that, if this component is activated by the user, The "no selection option", if any, must be hidden. +collectionType | null | String | Optional attribute that is a literal string that is the fully qualified class name of a concrete class that implements `java.util.Collection` or an EL expression that evaluates to either 1. such a String, or 2. the `Class` object itself. ## Getting started with SelectCheckboxMenu diff --git a/docs/12_0_0/components/confirm.md b/docs/12_0_0/components/confirm.md index ccabf9a9cf..1df0bb50c9 100644 --- a/docs/12_0_0/components/confirm.md +++ b/docs/12_0_0/components/confirm.md @@ -20,6 +20,7 @@ Confirm is a behavior element used to integrate with global confirm dialog/popup | icon | null | String | Icon to display next to message. | disabled | false | Boolean | Disables confirm behavior when true. | escape | true | Boolean | Whether to escape the message. +| beforeShow | null | String | Callback to execute before displaying confirmation dialog. Return false to prevent dialog from appearing. ## Getting started with Confirm See global confirm dialog/popup topic in next section for details. \ No newline at end of file diff --git a/docs/12_0_0/components/selectcheckboxmenu.md b/docs/12_0_0/components/selectcheckboxmenu.md index 4014838195..6fd9a3ff97 100644 --- a/docs/12_0_0/components/selectcheckboxmenu.md +++ b/docs/12_0_0/components/selectcheckboxmenu.md @@ -57,6 +57,7 @@ labelSeparator | , | String | Separator for joining item lables if updateLabel i emptyLabel | null | String | Label to be shown in updateLabel mode when no item is selected. If not set the label is shown. filterPlaceholder | null | String | Placeholder text to show when filter input is empty. hideNoSelectionOption | false | boolean | Flag indicating that, if this component is activated by the user, The "no selection option", if any, must be hidden. +collectionType | null | String | Optional attribute that is a literal string that is the fully qualified class name of a concrete class that implements `java.util.Collection` or an EL expression that evaluates to either 1. such a String, or 2. the `Class` object itself. ## Getting started with SelectCheckboxMenu diff --git a/docs/13_0_0/components/confirm.md b/docs/13_0_0/components/confirm.md index ccabf9a9cf..1df0bb50c9 100644 --- a/docs/13_0_0/components/confirm.md +++ b/docs/13_0_0/components/confirm.md @@ -20,6 +20,7 @@ Confirm is a behavior element used to integrate with global confirm dialog/popup | icon | null | String | Icon to display next to message. | disabled | false | Boolean | Disables confirm behavior when true. | escape | true | Boolean | Whether to escape the message. +| beforeShow | null | String | Callback to execute before displaying confirmation dialog. Return false to prevent dialog from appearing. ## Getting started with Confirm See global confirm dialog/popup topic in next section for details. \ No newline at end of file diff --git a/docs/13_0_0/components/selectcheckboxmenu.md b/docs/13_0_0/components/selectcheckboxmenu.md index 9f9cef4938..9f769e21e8 100644 --- a/docs/13_0_0/components/selectcheckboxmenu.md +++ b/docs/13_0_0/components/selectcheckboxmenu.md @@ -59,6 +59,7 @@ emptyLabel | null | String | Label to be shown in updateLabel mode when no item filterPlaceholder | null | String | Placeholder text to show when filter input is empty. hideNoSelectionOption | false | boolean | Flag indicating that, if this component is activated by the user, The "no selection option", if any, must be hidden. var | null | String | Name of iterator to be used in custom content display. +collectionType | null | String | Optional attribute that is a literal string that is the fully qualified class name of a concrete class that implements `java.util.Collection` or an EL expression that evaluates to either 1. such a String, or 2. the `Class` object itself. ## Getting started with SelectCheckboxMenu SelectCheckboxMenu usage is same as the standard selectManyCheckbox or PrimeFaces diff --git a/docs/14_0_0/components/columntoggler.md b/docs/14_0_0/components/columntoggler.md index b18c0339c1..f6d8ddadab 100644 --- a/docs/14_0_0/components/columntoggler.md +++ b/docs/14_0_0/components/columntoggler.md @@ -40,7 +40,7 @@ For this to contain meaningful ids your columns should define an id attribute ot | Event | Listener Parameter | Fired | | --- | --- | --- | -| toggle | org.primefaces.event.ToggleEvent | On item selection/unselection. | +| toggle | org.primefaces.event.ColumnToggleEvent | On item selection/unselection. | | close | org.primefaces.event.ToggleCloseEvent | On closing of toggler popup. | ## Client Side API diff --git a/docs/14_0_0/components/confirm.md b/docs/14_0_0/components/confirm.md index ccabf9a9cf..1df0bb50c9 100644 --- a/docs/14_0_0/components/confirm.md +++ b/docs/14_0_0/components/confirm.md @@ -20,6 +20,7 @@ Confirm is a behavior element used to integrate with global confirm dialog/popup | icon | null | String | Icon to display next to message. | disabled | false | Boolean | Disables confirm behavior when true. | escape | true | Boolean | Whether to escape the message. +| beforeShow | null | String | Callback to execute before displaying confirmation dialog. Return false to prevent dialog from appearing. ## Getting started with Confirm See global confirm dialog/popup topic in next section for details. \ No newline at end of file diff --git a/docs/14_0_0/components/selectcheckboxmenu.md b/docs/14_0_0/components/selectcheckboxmenu.md index 7488dc42e9..b6db4184bc 100644 --- a/docs/14_0_0/components/selectcheckboxmenu.md +++ b/docs/14_0_0/components/selectcheckboxmenu.md @@ -60,6 +60,7 @@ selectedLabel | null | String | Label to be shown in updateLabel mode when one o filterPlaceholder | null | String | Placeholder text to show when filter input is empty. hideNoSelectionOption | false | boolean | Flag indicating that, if this component is activated by the user, The "no selection option", if any, must be hidden. var | null | String | Name of iterator to be used in custom content display. +collectionType | null | String | Optional attribute that is a literal string that is the fully qualified class name of a concrete class that implements `java.util.Collection` or an EL expression that evaluates to either 1. such a String, or 2. the `Class` object itself. ## Getting started with SelectCheckboxMenu SelectCheckboxMenu usage is same as the standard selectManyCheckbox or PrimeFaces diff --git a/docs/14_0_0/core/localization.md b/docs/14_0_0/core/localization.md index 7ff7ea919b..745f3db1ef 100644 --- a/docs/14_0_0/core/localization.md +++ b/docs/14_0_0/core/localization.md @@ -69,122 +69,251 @@ related properties are utilized by components such as calendar and schedule. If Side Validation, messages property is used as the bundle for the locale. ```js -{ - weekNumberTitle: 'W', - isRTL: false, - yearSuffix: '', - timeOnlyTitle: 'Only Time', - timeText: 'Time', - hourText: 'Hour', - minuteText: 'Minute', - secondText: 'Second', - millisecondText: 'Millisecond', - year: 'Year', - month: 'Month', - week: 'Week', - day: 'Day', - list: 'Agenda', - allDayText: 'All Day', - moreLinkText: 'More...', - noEventsText: 'No Events', - unexpectedError: 'Unexpected error', - aria: { - 'datatable.sort.ASC': 'activate to sort column ascending', - 'datatable.sort.DESC': 'activate to sort column descending', - 'datatable.sort.NONE': 'activate to remove sorting on column', - 'colorpicker.OPEN': 'Open color picker', - 'colorpicker.CLOSE': 'Close color picker', - 'colorpicker.CLEAR': 'Clear the selected color', - 'colorpicker.MARKER': 'Saturation: {s}. Brightness: {v}.', - 'colorpicker.HUESLIDER': 'Hue slider', - 'colorpicker.ALPHASLIDER': 'Opacity slider', - 'colorpicker.INPUT': 'Color value field', - 'colorpicker.FORMAT': 'Color format', - 'colorpicker.SWATCH': 'Color swatch', - 'colorpicker.INSTRUCTION': 'Saturation and brightness selector. Use up, down, left and right arrow keys to select.', - 'spinner.INCREASE': 'Increase Value', - 'spinner.DECREASE': 'Decrease Value', - 'switch.ON': 'On', - 'switch.OFF': 'Off', - 'messages.ERROR': 'Error', - 'messages.FATAL': 'Fatal', - 'messages.INFO': 'Information', - 'messages.WARN': 'Warning' - }, - messages: { //optional for Client Side Validation - 'javax.faces.component.UIInput.REQUIRED': '{0}: Validation Error: Value is required.', - 'javax.faces.converter.IntegerConverter.INTEGER': '{2}: \'{0}\' must be a number consisting of one or more digits.', - 'javax.faces.converter.IntegerConverter.INTEGER_detail': '{2}: \'{0}\' must be a number between -2147483648 and 2147483647. Example: {1}.', - 'javax.faces.converter.DoubleConverter.DOUBLE': '{2}: \'{0}\' must be a number consisting of one or more digits.', - 'javax.faces.converter.DoubleConverter.DOUBLE_detail': '{2}: \'{0}\' must be a number between 4.9E-324 and 1.7976931348623157E308. Example: {1}.', - 'javax.faces.converter.BigDecimalConverter.DECIMAL': '{2}: \'{0}\' must be a signed decimal number.', - 'javax.faces.converter.BigDecimalConverter.DECIMAL_detail': '{2}: \'{0}\' must be a signed decimal number consisting of zero or more digits, that may be followed by a decimal point and fraction. Example: {1}.', - 'javax.faces.converter.BigIntegerConverter.BIGINTEGER': '{2}: \'{0}\' must be a number consisting of one or more digits.', - 'javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail': '{2}: \'{0}\' must be a number consisting of one or more digits. Example: {1}.', - 'javax.faces.converter.ByteConverter.BYTE': '{2}: \'{0}\' must be a number between 0 and 255.', - 'javax.faces.converter.ByteConverter.BYTE_detail': '{2}: \'{0}\' must be a number between 0 and 255. Example: {1}.', - 'javax.faces.converter.CharacterConverter.CHARACTER': '{1}: \'{0}\' must be a valid character.', - 'javax.faces.converter.CharacterConverter.CHARACTER_detail': '{1}: \'{0}\' must be a valid ASCII character.', - 'javax.faces.converter.ShortConverter.SHORT': '{2}: \'{0}\' must be a number consisting of one or more digits.', - 'javax.faces.converter.ShortConverter.SHORT_detail': '{2}: \'{0}\' must be a number between -32768 and 32767. Example: {1}.', - 'javax.faces.converter.BooleanConverter.BOOLEAN': '{1}: \'{0}\' must be \'true\' or \'false\'.', - 'javax.faces.converter.BooleanConverter.BOOLEAN_detail': '{1}: \'{0}\' must be \'true\' or \'false\'. Any value other than \'true\' will evaluate to \'false\'.', - 'javax.faces.validator.LongRangeValidator.MAXIMUM': '{1}: Validation Error: Value is greater than allowable maximum of \'{0}\'.', - 'javax.faces.validator.LongRangeValidator.MINIMUM': '{1}: Validation Error: Value is less than allowable minimum of \'{0}\'.', - 'javax.faces.validator.LongRangeValidator.NOT_IN_RANGE': '{2}: Validation Error: Specified attribute is not between the expected values of {0} and {1}.', - 'javax.faces.validator.LongRangeValidator.TYPE': '{0}: Validation Error: Value is not of the correct type.', - 'javax.faces.validator.DoubleRangeValidator.MAXIMUM': '{1}: Validation Error: Value is greater than allowable maximum of \'{0}\'.', - 'javax.faces.validator.DoubleRangeValidator.MINIMUM': '{1}: Validation Error: Value is less than allowable minimum of \'{0}\'.', - 'javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE': '{2}: Validation Error: Specified attribute is not between the expected values of {0} and {1}.', - 'javax.faces.validator.DoubleRangeValidator.TYPE': '{0}: Validation Error: Value is not of the correct type.', - 'javax.faces.converter.FloatConverter.FLOAT': '{2}: \'{0}\' must be a number consisting of one or more digits.', - 'javax.faces.converter.FloatConverter.FLOAT_detail': '{2}: \'{0}\' must be a number between 1.4E-45 and 3.4028235E38 Example: {1}.', - 'javax.faces.converter.DateTimeConverter.DATE': '{2}: \'{0}\' could not be understood as a date.', - 'javax.faces.converter.DateTimeConverter.DATE_detail': '{2}: \'{0}\' could not be understood as a date. Example: {1}.', - 'javax.faces.converter.DateTimeConverter.TIME': '{2}: \'{0}\' could not be understood as a time.', - 'javax.faces.converter.DateTimeConverter.TIME_detail': '{2}: \'{0}\' could not be understood as a time. Example: {1}.', - 'javax.faces.converter.DateTimeConverter.DATETIME': '{2}: \'{0}\' could not be understood as a date and time.', - 'javax.faces.converter.DateTimeConverter.DATETIME_detail': '{2}: \'{0}\' could not be understood as a date and time. Example: {1}.', - 'javax.faces.converter.DateTimeConverter.PATTERN_TYPE': '{1}: A \'pattern\' or \'type\' attribute must be specified to convert the value \'{0}\'.', - 'javax.faces.converter.NumberConverter.CURRENCY': '{2}: \'{0}\' could not be understood as a currency value.', - 'javax.faces.converter.NumberConverter.CURRENCY_detail': '{2}: \'{0}\' could not be understood as a currency value. Example: {1}.', - 'javax.faces.converter.NumberConverter.PERCENT': '{2}: \'{0}\' could not be understood as a percentage.', - 'javax.faces.converter.NumberConverter.PERCENT_detail': '{2}: \'{0}\' could not be understood as a percentage. Example: {1}.', - 'javax.faces.converter.NumberConverter.NUMBER': '{2}: \'{0}\' could not be understood as a number.', - 'javax.faces.converter.NumberConverter.NUMBER_detail': '{2}: \'{0}\' could not be understood as a number. Example: {1}.', - 'javax.faces.converter.NumberConverter.PATTERN': '{2}: \'{0}\' could not be understood as a number pattern.', - 'javax.faces.converter.NumberConverter.PATTERN_detail': '{2}: \'{0}\' could not be understood as a number pattern. Example: {1}.', - 'javax.faces.validator.LengthValidator.MINIMUM': '{1}: Validation Error: Length is less than allowable minimum of \'{0}\'.', - 'javax.faces.validator.LengthValidator.MAXIMUM': '{1}: Validation Error: Length is greater than allowable maximum of \'{0}\'.', - 'javax.faces.validator.RegexValidator.PATTERN_NOT_SET': 'Regex pattern must be set.', - 'javax.faces.validator.RegexValidator.PATTERN_NOT_SET_detail': 'Regex pattern must be set to non-empty value.', - 'javax.faces.validator.RegexValidator.NOT_MATCHED': 'Regex Pattern not matched.', - 'javax.faces.validator.RegexValidator.NOT_MATCHED_detail': 'Regex pattern of \'{0}\' not matched.', - 'javax.faces.validator.RegexValidator.MATCH_EXCEPTION': 'Error in regular expression.', - 'javax.faces.validator.RegexValidator.MATCH_EXCEPTION_detail': 'Error in regular expression, \'{0}\'.', - 'primefaces.FileValidator.FILE_LIMIT': 'Maximum number of files exceeded.', - 'primefaces.FileValidator.FILE_LIMIT_detail': 'Maximum number: {0}.', - 'primefaces.FileValidator.ALLOW_TYPES': 'Invalid file type.', - 'primefaces.FileValidator.ALLOW_TYPES_detail': 'Invalid file type: \'{0}\'.', - 'primefaces.FileValidator.SIZE_LIMIT': 'Invalid file size.', - 'primefaces.FileValidator.SIZE_LIMIT_detail': 'File \'{0}\' must not be larger than {1}.', - //optional for bean validation integration in client side validation - 'javax.faces.validator.BeanValidator.MESSAGE': '{0}', - 'javax.validation.constraints.AssertFalse.message': 'must be false.', - 'javax.validation.constraints.AssertTrue.message': 'must be true.', - 'javax.validation.constraints.DecimalMax.message': 'must be less than or equal to {0}.', - 'javax.validation.constraints.DecimalMin.message': 'must be greater than or equal to {0}.', - 'javax.validation.constraints.Digits.message': 'numeric value out of bounds (<{0} digits>.<{1} digits> expected).', - 'javax.validation.constraints.Future.message': 'must be in the future.', - 'javax.validation.constraints.Max.message': 'must be less than or equal to {0}.', - 'javax.validation.constraints.Min.message': 'must be greater than or equal to {0}.', - 'javax.validation.constraints.NotNull.message': 'may not be null.', - 'javax.validation.constraints.Null.message': 'must be null.', - 'javax.validation.constraints.Past.message': 'must be in the past.', - 'javax.validation.constraints.Pattern.message': 'must match "{0}".', - 'javax.validation.constraints.Size.message': 'size must be between {0} and {1}.' - } - }); +if (window.PrimeFaces) { + /** English (from PrimeLocale)*/ + PrimeFaces.locales["en"] = { + startsWith: "Starts with", + contains: "Contains", + notContains: "Not contains", + endsWith: "Ends with", + equals: "Equals", + notEquals: "Not equals", + noFilter: "No Filter", + filter: "Filter", + lt: "Less than", + lte: "Less than or equal to", + gt: "Greater than", + gte: "Greater than or equal to", + dateIs: "Date is", + dateIsNot: "Date is not", + dateBefore: "Date is before", + dateAfter: "Date is after", + custom: "Custom", + clear: "Clear", + apply: "Apply", + matchAll: "Match All", + matchAny: "Match Any", + addRule: "Add Rule", + removeRule: "Remove Rule", + accept: "Yes", + reject: "No", + choose: "Choose", + upload: "Upload", + cancel: "Cancel", + completed: "Completed", + pending: "Pending", + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + dayNamesMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + chooseYear: "Choose Year", + chooseMonth: "Choose Month", + chooseDate: "Choose Date", + prevDecade: "Previous Decade", + nextDecade: "Next Decade", + prevYear: "Previous Year", + nextYear: "Next Year", + prevMonth: "Previous Month", + nextMonth: "Next Month", + prevHour: "Previous Hour", + nextHour: "Next Hour", + prevMinute: "Previous Minute", + nextMinute: "Next Minute", + prevSecond: "Previous Second", + nextSecond: "Next Second", + am: "AM", + pm: "PM", + today: "Today", + now: "Now", + weekHeader: "Wk", + firstDayOfWeek: 0, + showMonthAfterYear: false, + dateFormat: "mm/dd/yy", + weak: "Weak", + medium: "Medium", + strong: "Strong", + passwordPrompt: "Enter a password", + emptyFilterMessage: "No results found", + searchMessage: "{0} results are available", + selectionMessage: "{0} items selected", + emptySelectionMessage: "No selected item", + emptySearchMessage: "No results found", + emptyMessage: "No available options", + aria: { + trueLabel: "True", + falseLabel: "False", + nullLabel: "Not Selected", + star: "1 star", + stars: "{star} stars", + selectAll: "All items selected", + unselectAll: "All items unselected", + close: "Close", + previous: "Previous", + next: "Next", + navigation: "Navigation", + scrollTop: "Scroll Top", + moveTop: "Move Top", + moveUp: "Move Up", + moveDown: "Move Down", + moveBottom: "Move Bottom", + moveToTarget: "Move to Target", + moveToSource: "Move to Source", + moveAllToTarget: "Move All to Target", + moveAllToSource: "Move All to Source", + pageLabel: "Page {page}", + firstPageLabel: "First Page", + lastPageLabel: "Last Page", + nextPageLabel: "Next Page", + previousPageLabel: "Previous Page", + rowsPerPageLabel: "Rows per page", + jumpToPageDropdownLabel: "Jump to Page Dropdown", + jumpToPageInputLabel: "Jump to Page Input", + selectRow: "Row Selected", + unselectRow: "Row Unselected", + expandRow: "Row Expanded", + collapseRow: "Row Collapsed", + showFilterMenu: "Show Filter Menu", + hideFilterMenu: "Hide Filter Menu", + filterOperator: "Filter Operator", + filterConstraint: "Filter Constraint", + editRow: "Edit Row", + saveEdit: "Save Edit", + cancelEdit: "Cancel Edit", + listView: "List View", + gridView: "Grid View", + slide: "Slide", + slideNumber: "{slideNumber}", + zoomImage: "Zoom Image", + zoomIn: "Zoom In", + zoomOut: "Zoom Out", + rotateRight: "Rotate Right", + rotateLeft: "Rotate Left", + }, + }; + + // custom PF labels + PrimeFaces.locales["en"] = $.extend(true, {}, PrimeFaces.locales["en"], { + weekNumberTitle: "W", + isRTL: false, + yearSuffix: "", + timeOnlyTitle: "Only Time", + timeText: "Time", + hourText: "Hour", + minuteText: "Minute", + secondText: "Second", + millisecondText: "Millisecond", + year: "Year", + month: "Month", + week: "Week", + day: "Day", + list: "Agenda", + allDayText: "All Day", + moreLinkText: "More...", + noEventsText: "No Events", + unexpectedError: "Unexpected error", + aria: { + "datatable.sort.ASC": "activate to sort column ascending", + "datatable.sort.DESC": "activate to sort column descending", + "datatable.sort.NONE": "activate to remove sorting on column", + "colorpicker.OPEN": "Open color picker", + "colorpicker.CLOSE": "Close color picker", + "colorpicker.CLEAR": "Clear the selected color", + "colorpicker.MARKER": "Saturation: {s}. Brightness: {v}.", + "colorpicker.HUESLIDER": "Hue slider", + "colorpicker.ALPHASLIDER": "Opacity slider", + "colorpicker.INPUT": "Color value field", + "colorpicker.FORMAT": "Color format", + "colorpicker.SWATCH": "Color swatch", + "colorpicker.INSTRUCTION": "Saturation and brightness selector. Use up, down, left and right arrow keys to select.", + "spinner.INCREASE": "Increase Value", + "spinner.DECREASE": "Decrease Value", + "switch.ON": "On", + "switch.OFF": "Off", + "messages.ERROR": "Error", + "messages.FATAL": "Fatal", + "messages.INFO": "Information", + "messages.WARN": "Warning", + }, + messages: { + //optional for Client Side Validation + "javax.faces.component.UIInput.REQUIRED": "{0}: Validation Error: Value is required.", + "javax.faces.converter.IntegerConverter.INTEGER": "{2}: '{0}' must be a number consisting of one or more digits.", + "javax.faces.converter.IntegerConverter.INTEGER_detail": "{2}: '{0}' must be a number between -2147483648 and 2147483647. Example: {1}.", + "javax.faces.converter.DoubleConverter.DOUBLE": "{2}: '{0}' must be a number consisting of one or more digits.", + "javax.faces.converter.DoubleConverter.DOUBLE_detail": "{2}: '{0}' must be a number between 4.9E-324 and 1.7976931348623157E308. Example: {1}.", + "javax.faces.converter.BigDecimalConverter.DECIMAL": "{2}: '{0}' must be a signed decimal number.", + "javax.faces.converter.BigDecimalConverter.DECIMAL_detail": "{2}: '{0}' must be a signed decimal number consisting of zero or more digits, that may be followed by a decimal point and fraction. Example: {1}.", + "javax.faces.converter.BigIntegerConverter.BIGINTEGER": "{2}: '{0}' must be a number consisting of one or more digits.", + "javax.faces.converter.BigIntegerConverter.BIGINTEGER_detail": "{2}: '{0}' must be a number consisting of one or more digits. Example: {1}.", + "javax.faces.converter.ByteConverter.BYTE": "{2}: '{0}' must be a number between 0 and 255.", + "javax.faces.converter.ByteConverter.BYTE_detail": "{2}: '{0}' must be a number between 0 and 255. Example: {1}.", + "javax.faces.converter.CharacterConverter.CHARACTER": "{1}: '{0}' must be a valid character.", + "javax.faces.converter.CharacterConverter.CHARACTER_detail": "{1}: '{0}' must be a valid ASCII character.", + "javax.faces.converter.ShortConverter.SHORT": "{2}: '{0}' must be a number consisting of one or more digits.", + "javax.faces.converter.ShortConverter.SHORT_detail": "{2}: '{0}' must be a number between -32768 and 32767. Example: {1}.", + "javax.faces.converter.BooleanConverter.BOOLEAN": "{1}: '{0}' must be 'true' or 'false'.", + "javax.faces.converter.BooleanConverter.BOOLEAN_detail": "{1}: '{0}' must be 'true' or 'false'. Any value other than 'true' will evaluate to 'false'.", + "javax.faces.validator.LongRangeValidator.MAXIMUM": "{1}: Validation Error: Value is greater than allowable maximum of '{0}'.", + "javax.faces.validator.LongRangeValidator.MINIMUM": "{1}: Validation Error: Value is less than allowable minimum of '{0}'.", + "javax.faces.validator.LongRangeValidator.NOT_IN_RANGE": "{2}: Validation Error: Specified attribute is not between the expected values of {0} and {1}.", + "javax.faces.validator.LongRangeValidator.TYPE": "{0}: Validation Error: Value is not of the correct type.", + "javax.faces.validator.DoubleRangeValidator.MAXIMUM": "{1}: Validation Error: Value is greater than allowable maximum of '{0}'.", + "javax.faces.validator.DoubleRangeValidator.MINIMUM": "{1}: Validation Error: Value is less than allowable minimum of '{0}'.", + "javax.faces.validator.DoubleRangeValidator.NOT_IN_RANGE": "{2}: Validation Error: Specified attribute is not between the expected values of {0} and {1}.", + "javax.faces.validator.DoubleRangeValidator.TYPE": "{0}: Validation Error: Value is not of the correct type.", + "javax.faces.converter.FloatConverter.FLOAT": "{2}: '{0}' must be a number consisting of one or more digits.", + "javax.faces.converter.FloatConverter.FLOAT_detail": "{2}: '{0}' must be a number between 1.4E-45 and 3.4028235E38 Example: {1}.", + "javax.faces.converter.DateTimeConverter.DATE": "{2}: '{0}' could not be understood as a date.", + "javax.faces.converter.DateTimeConverter.DATE_detail": "{2}: '{0}' could not be understood as a date. Example: {1}.", + "javax.faces.converter.DateTimeConverter.TIME": "{2}: '{0}' could not be understood as a time.", + "javax.faces.converter.DateTimeConverter.TIME_detail": "{2}: '{0}' could not be understood as a time. Example: {1}.", + "javax.faces.converter.DateTimeConverter.DATETIME": "{2}: '{0}' could not be understood as a date and time.", + "javax.faces.converter.DateTimeConverter.DATETIME_detail": "{2}: '{0}' could not be understood as a date and time. Example: {1}.", + "javax.faces.converter.DateTimeConverter.PATTERN_TYPE": "{1}: A 'pattern' or 'type' attribute must be specified to convert the value '{0}'.", + "javax.faces.converter.NumberConverter.CURRENCY": "{2}: '{0}' could not be understood as a currency value.", + "javax.faces.converter.NumberConverter.CURRENCY_detail": "{2}: '{0}' could not be understood as a currency value. Example: {1}.", + "javax.faces.converter.NumberConverter.PERCENT": "{2}: '{0}' could not be understood as a percentage.", + "javax.faces.converter.NumberConverter.PERCENT_detail": "{2}: '{0}' could not be understood as a percentage. Example: {1}.", + "javax.faces.converter.NumberConverter.NUMBER": "{2}: '{0}' could not be understood as a number.", + "javax.faces.converter.NumberConverter.NUMBER_detail": "{2}: '{0}' could not be understood as a number. Example: {1}.", + "javax.faces.converter.NumberConverter.PATTERN": "{2}: '{0}' could not be understood as a number pattern.", + "javax.faces.converter.NumberConverter.PATTERN_detail": "{2}: '{0}' could not be understood as a number pattern. Example: {1}.", + "javax.faces.validator.LengthValidator.MINIMUM": "{1}: Validation Error: Length is less than allowable minimum of '{0}'.", + "javax.faces.validator.LengthValidator.MAXIMUM": "{1}: Validation Error: Length is greater than allowable maximum of '{0}'.", + "javax.faces.validator.RegexValidator.PATTERN_NOT_SET": "Regex pattern must be set.", + "javax.faces.validator.RegexValidator.PATTERN_NOT_SET_detail": "Regex pattern must be set to non-empty value.", + "javax.faces.validator.RegexValidator.NOT_MATCHED": "Regex Pattern not matched.", + "javax.faces.validator.RegexValidator.NOT_MATCHED_detail": "Regex pattern of '{0}' not matched.", + "javax.faces.validator.RegexValidator.MATCH_EXCEPTION": "Error in regular expression.", + "javax.faces.validator.RegexValidator.MATCH_EXCEPTION_detail": "Error in regular expression, '{0}'.", + "primefaces.FileValidator.FILE_LIMIT": "Maximum number of files exceeded.", + "primefaces.FileValidator.FILE_LIMIT_detail": "Maximum number: {0}.", + "primefaces.FileValidator.ALLOW_TYPES": "Invalid file type.", + "primefaces.FileValidator.ALLOW_TYPES_detail": "Invalid file type: '{0}'.", + "primefaces.FileValidator.SIZE_LIMIT": "Invalid file size.", + "primefaces.FileValidator.SIZE_LIMIT_detail": "File '{0}' must not be larger than {1}.", + //optional for bean validation integration in client side validation + "javax.faces.validator.BeanValidator.MESSAGE": "{0}", + "javax.validation.constraints.AssertFalse.message": "must be false.", + "javax.validation.constraints.AssertTrue.message": "must be true.", + "javax.validation.constraints.DecimalMax.message": "must be less than or equal to {0}.", + "javax.validation.constraints.DecimalMin.message": "must be greater than or equal to {0}.", + "javax.validation.constraints.Digits.message": "numeric value out of bounds (<{0} digits>.<{1} digits> expected).", + "javax.validation.constraints.Future.message": "must be in the future.", + "javax.validation.constraints.Max.message": "must be less than or equal to {0}.", + "javax.validation.constraints.Min.message": "must be greater than or equal to {0}.", + "javax.validation.constraints.NotNull.message": "may not be null.", + "javax.validation.constraints.Null.message": "must be null.", + "javax.validation.constraints.Past.message": "must be in the past.", + "javax.validation.constraints.Pattern.message": 'must match "{0}".', + "javax.validation.constraints.Size.message": "size must be between {0} and {1}.", + }, + }); + // United States + PrimeFaces.locales["en_US"] = PrimeFaces.locales["en"]; +} + ``` ### Usage diff --git a/docs/7_0/components/confirm.md b/docs/7_0/components/confirm.md index 16718eb702..9fcab3939f 100644 --- a/docs/7_0/components/confirm.md +++ b/docs/7_0/components/confirm.md @@ -18,6 +18,7 @@ Confirm is a behavior element used to integrate with global confirm dialog. | icon | null | String | Icon to display next to message. | disabled | false | Boolean | Disables confirm behavior when true. | escape | false | Boolean | Whether to escape the message. +| beforeShow | null | String | Callback to execute before displaying confirmation dialog. Return false to prevent dialog from appearing. ## Getting started with Confirm See global confirm dialog topic in next section for details. \ No newline at end of file diff --git a/docs/7_0/components/selectcheckboxmenu.md b/docs/7_0/components/selectcheckboxmenu.md index e710686561..ab20da25de 100644 --- a/docs/7_0/components/selectcheckboxmenu.md +++ b/docs/7_0/components/selectcheckboxmenu.md @@ -54,6 +54,7 @@ dynamic | false | Boolean | Defines if dynamic loading is enabled for the elemen labelSeparator | , | String | Separator for joining item lables if updateLabel is set to true. Default is ",". emptyLabel | null | String | Label to be shown in updateLabel mode when no item is selected. If not set the label is shown. filterPlaceholder | null | String | Placeholder text to show when filter input is empty. +collectionType | null | String | Optional attribute that is a literal string that is the fully qualified class name of a concrete class that implements `java.util.Collection` or an EL expression that evaluates to either 1. such a String, or 2. the `Class` object itself. ## Getting started with SelectCheckboxMenu SelectCheckboxMenu usage is same as the standard selectManyCheckbox or PrimeFaces diff --git a/docs/8_0/components/confirm.md b/docs/8_0/components/confirm.md index 16718eb702..9fcab3939f 100644 --- a/docs/8_0/components/confirm.md +++ b/docs/8_0/components/confirm.md @@ -18,6 +18,7 @@ Confirm is a behavior element used to integrate with global confirm dialog. | icon | null | String | Icon to display next to message. | disabled | false | Boolean | Disables confirm behavior when true. | escape | false | Boolean | Whether to escape the message. +| beforeShow | null | String | Callback to execute before displaying confirmation dialog. Return false to prevent dialog from appearing. ## Getting started with Confirm See global confirm dialog topic in next section for details. \ No newline at end of file diff --git a/docs/8_0/components/selectcheckboxmenu.md b/docs/8_0/components/selectcheckboxmenu.md index b21dc1edf4..2d17062fdb 100644 --- a/docs/8_0/components/selectcheckboxmenu.md +++ b/docs/8_0/components/selectcheckboxmenu.md @@ -54,6 +54,7 @@ dynamic | false | Boolean | Defines if dynamic loading is enabled for the elemen labelSeparator | , | String | Separator for joining item lables if updateLabel is set to true. Default is ",". emptyLabel | null | String | Label to be shown in updateLabel mode when no item is selected. If not set the label is shown. filterPlaceholder | null | String | Placeholder text to show when filter input is empty. +collectionType | null | String | Optional attribute that is a literal string that is the fully qualified class name of a concrete class that implements `java.util.Collection` or an EL expression that evaluates to either 1. such a String, or 2. the `Class` object itself. ## Getting started with SelectCheckboxMenu SelectCheckboxMenu usage is same as the standard selectManyCheckbox or PrimeFaces diff --git a/docs/migrationguide/14_0_0.md b/docs/migrationguide/14_0_0.md index e77b103cb0..310a280b0a 100644 --- a/docs/migrationguide/14_0_0.md +++ b/docs/migrationguide/14_0_0.md @@ -24,18 +24,15 @@ ## AutoComplete * `dropdownAriaLabel`, `emptyMessage`, `resultsMessage` properties have been moved to client side locale + +## ColumnToggler + + * AJAX `toggle` event is now `org.primefaces.event.ColumnToggleEvent` giving access to `UIColumn` that was toggled ## DatePicker/Calendar * Locale `firstDay` renamed `firstDayOfWeek` to match other Prime libraries -## FileUpload - - * `invalidSizeMessage`, `invalidFileMessage`, `fileLimitMessage` are deprecated and will be removed in 15.0.0. PF i18n will be used for it. - * `maxFileSize`, `fileLimit`, `allowedTypes` are deprecated and will be removed in 15.0.0. Please attach `p:validateFile` to the `p:fileUpload` component. - * Simple FileUpload: Client side validation has been reimplemented with PrimeFaces CSV and support for `p:message(s)`/`p:growl`. Please make sure to enable CSV to use it. - * Simple FileUpload: filename is not displayed by default when `auto=true`, set `displayFilename=true` instead if you need it. - ## DataTable * Using Column custom `sortFunction` signature change now requires a third parameter `SortMeta` like `public int sortByModel(Object car1, Object car2, SortMeta sortMeta)` @@ -51,7 +48,14 @@ Few selection attributes have been renamed for consistency purposes: * `UIColumn#selectionMode` renamed to `selectionBox` and reworked. Since [13.0.0](https://github.com/primefaces/primefaces/issues/10129), `DataTable#selectionMode` is automatically deduced from `selection` value binding. !> Starting from 14.0.0, `DataTable#selectionMode` will be the single source of truth to configure whether selection should be `single` or `multiple`. To configure selection column, e.g display radiobutton or checkbox, `UIColumn#selectionBox` should be set to true. Whether it's a radiobutton or checkbox will depend on `DataTable#selectionMode` - + +## FileUpload + + * `invalidSizeMessage`, `invalidFileMessage`, `fileLimitMessage` are deprecated and will be removed in 15.0.0. PF i18n will be used for it. + * `maxFileSize`, `fileLimit`, `allowedTypes` are deprecated and will be removed in 15.0.0. Please attach `p:validateFile` to the `p:fileUpload` component. + * Simple FileUpload: Client side validation has been reimplemented with PrimeFaces CSV and support for `p:message(s)`/`p:growl`. Please make sure to enable CSV to use it. + * Simple FileUpload: filename is not displayed by default when `auto=true`, set `displayFilename=true` instead if you need it. + ## MenuBar * `delay` has been renamed `showDelay` and new `hideDelay` property added diff --git a/primefaces-integration-tests-jakarta/src/test/resources-filtered/primefaces-selenium/config.properties b/primefaces-integration-tests-jakarta/src/test/resources-filtered/primefaces-selenium/config.properties index 7560f10e61..7136bfd33d 100644 --- a/primefaces-integration-tests-jakarta/src/test/resources-filtered/primefaces-selenium/config.properties +++ b/primefaces-integration-tests-jakarta/src/test/resources-filtered/primefaces-selenium/config.properties @@ -7,3 +7,5 @@ timeout.documentLoad = 30 webdriver.browser = ${webdriver.browser} webdriver.headless = ${webdriver.headless} + +screenshotDirectory = ${SCREENSHOT_DIRECTORY} diff --git a/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog001.xhtml b/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog001.xhtml index 126038e57b..4cabc28207 100644 --- a/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog001.xhtml +++ b/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog001.xhtml @@ -14,11 +14,11 @@ - + - + diff --git a/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog002.xhtml b/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog002.xhtml index 9b5ec7f411..9d05346e25 100644 --- a/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog002.xhtml +++ b/primefaces-integration-tests/src/main/webapp/confirmdialog/confirmDialog002.xhtml @@ -14,11 +14,11 @@ - + - + diff --git a/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog001Test.java b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog001Test.java index c4758ea7b6..cd38350add 100644 --- a/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog001Test.java +++ b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog001Test.java @@ -183,11 +183,10 @@ void nonAjaxYes(Page page) { page.nonAjax.click(); // Act - PrimeSelenium.guardHttp(dialog.getYesButton().getRoot()).click(); + dialog.getYesButton().click(); // Assert - //PrimeSelenium.waitGui().until(PrimeExpectedConditions.visibleInViewport(page.message)); - //assertEquals("Full page submitted", page.message.getMessage(0).getDetail()); + assertEquals("Full page submitted", page.message.getMessage(0).getDetail()); assertDialog(page, false); } diff --git a/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog002Test.java b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog002Test.java index 34fda2f22d..91a435a5c1 100644 --- a/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog002Test.java +++ b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/confirmdialog/ConfirmDialog002Test.java @@ -186,8 +186,7 @@ void nonAjaxYes(Page page) { dialog.getYesButton().click(); // Assert - //PrimeSelenium.waitGui().until(PrimeExpectedConditions.visibleInViewport(page.message)); - //assertEquals("Full page submitted", page.message.getMessage(0).getDetail()); + assertEquals("Full page submitted", page.message.getMessage(0).getDetail()); assertDialog(page, false); } diff --git a/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/datepicker/DatePicker011Test.java b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/datepicker/DatePicker011Test.java index 4c6d374d86..43faa0e273 100644 --- a/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/datepicker/DatePicker011Test.java +++ b/primefaces-integration-tests/src/test/java/org/primefaces/integrationtests/datepicker/DatePicker011Test.java @@ -294,7 +294,7 @@ private void testDatePickerPart1(DatePicker datePicker, Page page, DatePickerBeh } // Act - 7th next year via year drop down - datePicker.selectYearDropdown(LocalDate.now().getYear() + 1); + datePicker.selectYear(LocalDate.now().getYear() + 1); // Assert PrimeSelenium.wait(SAFETY_WAIT_AFTER_DOUBLE_AJAX_CALL_MILLISECONDS); diff --git a/primefaces-integration-tests/src/test/resources-filtered/primefaces-selenium/config.properties b/primefaces-integration-tests/src/test/resources-filtered/primefaces-selenium/config.properties index 7560f10e61..7136bfd33d 100644 --- a/primefaces-integration-tests/src/test/resources-filtered/primefaces-selenium/config.properties +++ b/primefaces-integration-tests/src/test/resources-filtered/primefaces-selenium/config.properties @@ -7,3 +7,5 @@ timeout.documentLoad = 30 webdriver.browser = ${webdriver.browser} webdriver.headless = ${webdriver.headless} + +screenshotDirectory = ${SCREENSHOT_DIRECTORY} diff --git a/primefaces-selenium/README.md b/primefaces-selenium/README.md index 026f9609f4..bb3c58bdaf 100644 --- a/primefaces-selenium/README.md +++ b/primefaces-selenium/README.md @@ -76,6 +76,7 @@ Properties: | onloadScripts.adapter | org.primefaces.extensions.selenium.spi.OnloadScriptsAdapter | | Adapter implementation to provide custom onload scripts | | disableAnimations | boolean | true | If animations should be disabled for tests | | scrollElementIntoView | String | | Scroll the element to be clicked into view via the configured #scrollIntoView option. Valid options are a boolean or object | +| screenshotDirectory | String | | Path where browser-screenshots should be saved if a test fails | ## Status diff --git a/primefaces-selenium/primefaces-selenium-components/src/main/java/org/primefaces/selenium/component/DatePicker.java b/primefaces-selenium/primefaces-selenium-components/src/main/java/org/primefaces/selenium/component/DatePicker.java index 7e15bc02ce..e4cae610c3 100644 --- a/primefaces-selenium/primefaces-selenium-components/src/main/java/org/primefaces/selenium/component/DatePicker.java +++ b/primefaces-selenium/primefaces-selenium-components/src/main/java/org/primefaces/selenium/component/DatePicker.java @@ -306,21 +306,13 @@ public void selectMonthDropdown(int month) { } /** - * Open the year select dropdown. - */ - public void toggleYearDropdown() { - WebElement yearDropDown = showPanel().findElement(By.cssSelector("select.ui-datepicker-year")); - yearDropDown.click(); - } - - /** - * Select a year from the drodown. + * Select a year. * * @param year the year to select */ - public void selectYearDropdown(int year) { - Select yearDropDown = new Select(showPanel().findElement(By.cssSelector("select.ui-datepicker-year"))); - yearDropDown.selectByValue(Integer.toString(year)); + public void selectYear(int year) { + WebElement yearInput = showPanel().findElement(By.cssSelector("input.ui-datepicker-year")); + yearInput.sendKeys(Integer.toString(year)); } } diff --git a/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/AbstractPrimePageTest.java b/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/AbstractPrimePageTest.java index 7f6f53880b..d72045a8c5 100644 --- a/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/AbstractPrimePageTest.java +++ b/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/AbstractPrimePageTest.java @@ -34,6 +34,7 @@ import org.openqa.selenium.logging.Logs; import org.primefaces.selenium.internal.junit.BootstrapExtension; import org.primefaces.selenium.internal.junit.PageInjectionExtension; +import org.primefaces.selenium.internal.junit.ScreenshotOnFailureExtension; import org.primefaces.selenium.internal.junit.WebDriverExtension; import org.primefaces.selenium.spi.WebDriverProvider; @@ -54,6 +55,7 @@ @ExtendWith(BootstrapExtension.class) @ExtendWith(WebDriverExtension.class) @ExtendWith(PageInjectionExtension.class) +@ExtendWith(ScreenshotOnFailureExtension.class) public abstract class AbstractPrimePageTest { @BeforeEach diff --git a/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/internal/ConfigProvider.java b/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/internal/ConfigProvider.java index 4dd4a89448..75fb319ea4 100644 --- a/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/internal/ConfigProvider.java +++ b/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/internal/ConfigProvider.java @@ -31,6 +31,8 @@ import java.util.List; import java.util.Properties; import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.primefaces.selenium.spi.WebDriverAdapter; @@ -41,6 +43,8 @@ public class ConfigProvider { private static ConfigProvider configProvider = null; + private static final Pattern PROPERTY_ENV_PLACEHOLDER = Pattern.compile("\\$\\{(.*?)}"); + private int timeoutGui = 2; private int timeoutAjax = 10; private int timeoutHttp = 10; @@ -64,6 +68,8 @@ public class ConfigProvider { private List onloadScripts; + private String screenshotDirectory; + public ConfigProvider() { try { InputStream config = getClass().getResourceAsStream("/primefaces-selenium/config.properties"); @@ -71,80 +77,85 @@ public ConfigProvider() { Properties properties = new Properties(); properties.load(config); - String timeoutGui = properties.getProperty("timeout.gui"); + String timeoutGui = getAndResolveProperty(properties, "timeout.gui"); if (timeoutGui != null && !timeoutGui.trim().isEmpty()) { this.timeoutGui = Integer.parseInt(timeoutGui); } - String timeoutAjax = properties.getProperty("timeout.ajax"); + String timeoutAjax = getAndResolveProperty(properties, "timeout.ajax"); if (timeoutAjax != null && !timeoutAjax.trim().isEmpty()) { this.timeoutAjax = Integer.parseInt(timeoutAjax); } - String timeoutHttp = properties.getProperty("timeout.http"); + String timeoutHttp = getAndResolveProperty(properties, "timeout.http"); if (timeoutHttp != null && !timeoutHttp.trim().isEmpty()) { this.timeoutHttp = Integer.parseInt(timeoutHttp); } - String timeoutDocumentLoad = properties.getProperty("timeout.documentLoad"); + String timeoutDocumentLoad = getAndResolveProperty(properties, "timeout.documentLoad"); if (timeoutDocumentLoad != null && !timeoutDocumentLoad.trim().isEmpty()) { this.timeoutDocumentLoad = Integer.parseInt(timeoutDocumentLoad); } - String timeoutFileUpload = properties.getProperty("timeout.fileUpload"); + String timeoutFileUpload = getAndResolveProperty(properties, "timeout.fileUpload"); if (timeoutFileUpload != null && !timeoutFileUpload.trim().isEmpty()) { this.timeoutFileUpload = Integer.parseInt(timeoutFileUpload); } - String disableAnimations = properties.getProperty("disableAnimations"); + String disableAnimations = getAndResolveProperty(properties, "disableAnimations"); if (disableAnimations != null && !disableAnimations.trim().isEmpty()) { this.disableAnimations = Boolean.parseBoolean(disableAnimations); } - String scrollElementIntoView = properties.getProperty("scrollElementIntoView"); + String scrollElementIntoView = getAndResolveProperty(properties, "scrollElementIntoView"); if (scrollElementIntoView != null && !scrollElementIntoView.trim().isEmpty()) { this.scrollElementIntoView = scrollElementIntoView; } - String deploymentBaseUrl = properties.getProperty("deployment.baseUrl"); + String deploymentBaseUrl = getAndResolveProperty(properties, "deployment.baseUrl"); if (deploymentBaseUrl != null && !deploymentBaseUrl.trim().isEmpty()) { this.deploymentBaseUrl = deploymentBaseUrl; } - String deploymentAdapter = properties.getProperty("deployment.adapter"); + String deploymentAdapter = getAndResolveProperty(properties, "deployment.adapter"); if (deploymentAdapter != null && !deploymentAdapter.trim().isEmpty()) { this.deploymentAdapter = (DeploymentAdapter) Class.forName(deploymentAdapter).getDeclaredConstructor().newInstance(); } - String webdriverAdapter = properties.getProperty("webdriver.adapter"); + String webdriverAdapter = getAndResolveProperty(properties, "webdriver.adapter"); if (webdriverAdapter != null && !webdriverAdapter.trim().isEmpty()) { this.webdriverAdapter = (WebDriverAdapter) Class.forName(webdriverAdapter).getDeclaredConstructor().newInstance(); } - String webdriverBrowser = properties.getProperty("webdriver.browser"); + String webdriverBrowser = getAndResolveProperty(properties, "webdriver.browser"); if (webdriverBrowser != null && !webdriverBrowser.trim().isEmpty()) { this.webdriverBrowser = webdriverBrowser; } - String webdriverHeadless = properties.getProperty("webdriver.headless"); + String webdriverHeadless = getAndResolveProperty(properties, "webdriver.headless"); if (webdriverHeadless != null && !webdriverHeadless.trim().isEmpty()) { this.webdriverHeadless = Boolean.parseBoolean(webdriverHeadless); } - String webdriverVersion = properties.getProperty("webdriver.version"); + String webdriverVersion = getAndResolveProperty(properties, "webdriver.version"); if (webdriverVersion != null && !webdriverVersion.trim().isEmpty()) { this.webdriverVersion = webdriverVersion; } - String webdriverLogLevel = properties.getProperty("webdriver.logLevel"); + String webdriverLogLevel = getAndResolveProperty(properties, "webdriver.logLevel"); if (webdriverLogLevel != null && !webdriverLogLevel.trim().isEmpty()) { this.webdriverLogLevel = Level.parse(webdriverLogLevel); } - String onloadScriptsAdapter = properties.getProperty("onloadScripts.adapter"); + String onloadScriptsAdapter = getAndResolveProperty(properties, "onloadScripts.adapter"); if (onloadScriptsAdapter != null && !onloadScriptsAdapter.trim().isEmpty()) { this.onloadScriptsAdapter = (OnloadScriptsAdapter) Class.forName(onloadScriptsAdapter).getDeclaredConstructor().newInstance(); } + + String screenshotDirectory = getAndResolveProperty(properties, "screenshotDirectory"); + if (screenshotDirectory != null && !screenshotDirectory.trim().isEmpty()) { + this.screenshotDirectory = screenshotDirectory; + } } if (webdriverAdapter == null) { @@ -165,6 +176,20 @@ public ConfigProvider() { } } + private String getAndResolveProperty(Properties properties, String propertyKey) { + String val = properties.getProperty(propertyKey); + if (val != null) { + Matcher matcher = PROPERTY_ENV_PLACEHOLDER.matcher(val); + if (matcher.matches()) { + String env = System.getenv(matcher.group(1)); + if (env != null && !env.trim().isEmpty()) { + return env; + } + } + } + return val; + } + protected void buildOnloadScripts() throws Exception { onloadScripts = new ArrayList<>(); try (BufferedReader buffer = new BufferedReader(new InputStreamReader( @@ -257,6 +282,10 @@ public Level getWebdriverLogLevel() { return webdriverLogLevel; } + public String getScreenshotDirectory() { + return screenshotDirectory; + } + public static synchronized ConfigProvider getInstance() { if (configProvider == null) { configProvider = new ConfigProvider(); @@ -264,4 +293,5 @@ public static synchronized ConfigProvider getInstance() { return configProvider; } + } diff --git a/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/internal/junit/ScreenshotOnFailureExtension.java b/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/internal/junit/ScreenshotOnFailureExtension.java new file mode 100644 index 0000000000..3bec6f1eb7 --- /dev/null +++ b/primefaces-selenium/primefaces-selenium-core/src/main/java/org/primefaces/selenium/internal/junit/ScreenshotOnFailureExtension.java @@ -0,0 +1,76 @@ +/* + * The MIT License + * + * Copyright (c) 2009-2024 PrimeTek Informatics + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.primefaces.selenium.internal.junit; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestWatcher; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; +import org.primefaces.selenium.internal.ConfigProvider; +import org.primefaces.selenium.spi.WebDriverProvider; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +public class ScreenshotOnFailureExtension implements TestWatcher { + + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"); + + @Override + public void testFailed(ExtensionContext context, Throwable cause) { + String screenshotDirectory = ConfigProvider.getInstance().getScreenshotDirectory(); + + if (StringUtils.isNotBlank(screenshotDirectory)) { + File scrFile = ((TakesScreenshot) WebDriverProvider.get()).getScreenshotAs(OutputType.FILE); + String filename = screenshotDirectory + LocalDateTime.now().format(DATE_TIME_FORMATTER) + "_" + UUID.randomUUID().toString(); + + try { + FileUtils.moveFile(scrFile, new File(filename + ".png")); + + // write additional textfile with context-information + PrintWriter printWriter = new PrintWriter(new FileWriter(filename + ".txt")); + if (context.getTestMethod().isPresent()) { + printWriter.println("Test-method: " + context.getTestMethod().get()); + } + printWriter.println("Test-description: " + context.getDisplayName()); + printWriter.println(""); + printWriter.println("Stacktrace: " + ExceptionUtils.getStackTrace(cause)); + printWriter.close(); + } + catch (IOException ex) { + System.err.println("Failed to save screenshot auf failed test: " + ex.getMessage()); + } + } + + TestWatcher.super.testFailed(context, cause); + } +} diff --git a/primefaces-showcase/pom.xml b/primefaces-showcase/pom.xml index 0aa66a390e..1e3a911a98 100644 --- a/primefaces-showcase/pom.xml +++ b/primefaces-showcase/pom.xml @@ -468,6 +468,105 @@ + + release + + + org.apache.myfaces.core + myfaces-api + ${myfaces-next.version} + compile + + + org.apache.myfaces.core + myfaces-impl + ${myfaces-next.version} + compile + + + + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} + + + + org.jboss.resteasy + resteasy-core + ${resteasy.version} + + + org.jboss.spec.javax.xml.bind + jboss-jaxb-api_2.3_spec + + + jakarta.activation + jakarta.activation-api + + + + + org.jboss.resteasy + resteasy-servlet-initializer + ${resteasy.version} + + + org.jboss.resteasy + resteasy-cdi + ${resteasy.version} + + + org.jboss.weld + weld-api + + + + + org.jboss.resteasy + resteasy-jackson2-provider + ${resteasy.version} + + + jakarta.activation + jakarta.activation-api + + + + + + org.apache.geronimo.specs + geronimo-atinject_1.0_spec + 1.2 + + + org.apache.geronimo.specs + geronimo-jcdi_2.0_spec + 1.3 + + + + org.apache.openwebbeans + openwebbeans-impl + ${owb.version} + + + org.apache.openwebbeans + openwebbeans-web + ${owb.version} + + + org.apache.openwebbeans + openwebbeans-jsf + ${owb.version} + + + + + ${basedir}/src/main/resources/filters/myfaces.properties + ${basedir}/src/main/resources/filters/non-ee.properties + + + diff --git a/primefaces-showcase/src/main/java/org/primefaces/showcase/view/data/datatable/BasicView.java b/primefaces-showcase/src/main/java/org/primefaces/showcase/view/data/datatable/BasicView.java index e46109cccb..c79b2f60a6 100644 --- a/primefaces-showcase/src/main/java/org/primefaces/showcase/view/data/datatable/BasicView.java +++ b/primefaces-showcase/src/main/java/org/primefaces/showcase/view/data/datatable/BasicView.java @@ -26,10 +26,15 @@ import java.io.Serializable; import java.util.List; import javax.annotation.PostConstruct; +import javax.faces.application.FacesMessage; +import javax.faces.context.FacesContext; import javax.faces.view.ViewScoped; import javax.inject.Inject; import javax.inject.Named; +import org.primefaces.component.api.UIColumn; +import org.primefaces.event.ColumnToggleEvent; +import org.primefaces.model.Visibility; import org.primefaces.showcase.domain.Product; import org.primefaces.showcase.service.ProductService; @@ -55,4 +60,13 @@ public void setService(ProductService service) { this.service = service; } + public void onToggle(ColumnToggleEvent e) { + Integer index = (Integer) e.getData(); + UIColumn column = e.getColumn(); + Visibility visibility = e.getVisibility(); + String header = column.getAriaHeaderText() != null ? column.getAriaHeaderText() : column.getHeaderText(); + FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Column " + index + " toggled: " + header + " " + visibility, null); + FacesContext.getCurrentInstance().addMessage(null, msg); + } + } diff --git a/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/_core.scss b/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/_core.scss index 1d92a9d59a..9da481f513 100644 --- a/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/_core.scss +++ b/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/_core.scss @@ -65,16 +65,6 @@ p { margin: 0 0 1rem 0; } -input[type="number"] { - -moz-appearance: textfield; - - &::-webkit-outer-spin-button, - &::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; - } -} - @keyframes pulse { 0% { diff --git a/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/layout.css b/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/layout.css index c32f254558..bd7f3c2ba4 100644 --- a/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/layout.css +++ b/primefaces-showcase/src/main/webapp/resources/showcase/css/layout/layout.css @@ -1 +1 @@ -html{font-size:14px}body{margin:0px;height:100%;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-a);font-family:var(--font-family);font-weight:normal;color:var(--text-color);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{text-decoration:none}h1,h2,h3,h4,h5,h6{margin:1.5rem 0 1rem 0;font-family:inherit;font-weight:600;line-height:1.2;color:inherit}h1:first-child,h2:first-child,h3:first-child,h4:first-child,h5:first-child,h6:first-child{margin-top:0}h1{font-size:2.5rem}h2{font-size:2rem}h3{font-size:1.75rem}h4{font-size:1.5rem}h5{font-size:1.25rem}h6{font-size:1rem}p{line-height:1.5;margin:0 0 1rem 0}input[type=number]{-moz-appearance:textfield}input[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}@keyframes pulse{0%{background-color:rgba(165,165,165,.1)}50%{background-color:rgba(165,165,165,.3)}100%{background-color:rgba(165,165,165,.1)}}.p-toast.p-toast-topright,.p-toast.p-toast-topleft{top:100px}.action-button{font-weight:bold;text-align:center;color:#2b3034 !important;background-color:#feab4d;padding:10px 24px 9px 24px;border-radius:3px;transition:background-color .2s}.action-button:hover{background-color:#feb767;color:#fff;text-decoration:none !important}.status-indicator{position:fixed;width:42px;height:42px;right:7px;bottom:7px;font-size:28px;color:var(--primary-color);pointer-events:none}.text-secondary{color:var(--text-color-secondary)}.floatlabel-demo .field{margin-top:2rem}.p-connected-overlay{opacity:0;transform:scaleY(0.8);transition:transform .12s cubic-bezier(0, 0, 0.2, 1),opacity .12s cubic-bezier(0, 0, 0.2, 1)}.p-connected-overlay-visible{opacity:1;transform:scaleY(1)}.p-connected-overlay-hidden{opacity:0;transform:scaleY(1);transition:opacity .1s linear}@-webkit-keyframes connected-overlay-in{from{opacity:0;-webkit-transform:scaleY(0.8);transform:scaleY(0.8)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes connected-overlay-in{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}@-webkit-keyframes connected-overlay-out{from{opacity:1}to{opacity:0}}@keyframes fade-out-down{from{opacity:1}to{opacity:0}}.connected-overlay-in{-webkit-animation-name:connected-overlay-in;animation-name:connected-overlay-in}.connected-overlay-out{-webkit-animation-name:connected-overlay-out;animation-name:connected-overlay-out}.layout-topbar{background-color:var(--surface-a);padding:0;height:70px;position:fixed;top:0;left:0;width:100%;z-index:997;box-shadow:0 0 4px rgba(0,0,0,.25);border-bottom:1px solid var(--surface-d);display:flex;align-items:center;padding:0 35px}.layout-topbar .menu-button{display:none;color:var(--text-color);width:70px;height:70px;line-height:70px;text-align:center;transition:background-color .2s;overflow:hidden;cursor:pointer}.layout-topbar .menu-button:hover{background-color:var(--surface-c)}.layout-topbar .menu-button i{font-size:24px;line-height:inherit}.layout-topbar .logo img{width:180px}.layout-topbar .logo:focus{outline:0 none;transition:box-shadow .2s;box-shadow:0 0 0 .2rem #bbdefb}.layout-topbar .app-theme{background-color:var(--primary-color);color:var(--primary-color-text);padding:.5rem;border-radius:4px;box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12);width:39px;height:39px;margin-left:70px}.layout-topbar .app-theme img{width:25px}.layout-topbar .topbar-form{margin-left:auto}.layout-topbar .topbar-menu{list-style-type:none;margin:0;padding:0;height:100%;display:flex}.layout-topbar .topbar-menu>li{height:70px;line-height:70px}.layout-topbar .topbar-menu>li>a{text-decoration:none;color:var(--text-color);min-width:120px;font-size:16px;display:block;text-align:center;user-select:none;line-height:68px;border-bottom:2px solid rgba(0,0,0,0);transition:border-bottom-color .2s;cursor:pointer}.layout-topbar .topbar-menu>li>a:hover,.layout-topbar .topbar-menu>li>a:focus{border-bottom-color:var(--primary-color)}.layout-topbar .topbar-menu>li>a:focus{z-index:1;outline:0 none;transition:box-shadow .2s;box-shadow:inset 0 0 0 .2em #bbdefb}.layout-topbar .topbar-menu>li.topbar-submenu{position:relative}.layout-topbar .topbar-menu>li.topbar-submenu .ui-overlay-badge{display:inline}.layout-topbar .topbar-menu>li.topbar-submenu.topbar-submenu-active>ul{display:block}.layout-topbar .topbar-menu>li.topbar-submenu>ul{display:none;position:absolute;transform-origin:top;top:70px;right:0;width:275px;max-height:400px;background-color:var(--surface-f);box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12);overflow:auto;list-style-type:none;padding:1rem;margin:0;border-radius:3px;animation-duration:.12s}.layout-topbar .topbar-menu>li.topbar-submenu>ul>li{line-height:1}.layout-topbar .topbar-menu>li.topbar-submenu>ul>li.topbar-submenu-header{display:block;color:var(--text-color-secondary);font-weight:600;user-select:none;padding:1.5rem 0 1rem 0;font-size:.857rem;text-transform:uppercase}.layout-topbar .topbar-menu>li.topbar-submenu>ul>li.topbar-submenu-header:first-child{padding-top:1rem}.layout-topbar .topbar-menu>li.topbar-submenu>ul a{text-decoration:none;color:var(--text-color);padding:.5rem;display:flex;align-items:center;user-select:none;border-radius:3px;cursor:pointer}.layout-topbar .topbar-menu>li.topbar-submenu>ul a:hover{background-color:var(--surface-c)}.layout-topbar .topbar-menu>li.topbar-submenu>ul a span{margin-left:.5rem}.layout-topbar .topbar-menu>li.topbar-submenu>ul a i{font-size:18px;color:var(--text-color-secondary)}.layout-topbar .topbar-menu>li.topbar-submenu>ul a img{width:32px;margin-right:.5rem}.layout-topbar .topbar-menu .theme-badge{padding:2px 4px;vertical-align:middle;border-radius:3px;color:#fff;font-weight:bold;font-size:11px;position:relative;top:-1px}.layout-topbar .topbar-menu .theme-badge.material{background:linear-gradient(to bottom, #2196F3, #2196F3)}.layout-topbar .topbar-menu .theme-badge.bootstrap{background:linear-gradient(to bottom, #563D7C, #966BD8)}.layout-topbar .topbar-menu .theme-badge.darkmode{background:linear-gradient(to bottom, #141d26, #5a6067)}.layout-sidebar{position:fixed;left:0;top:70px;height:calc(100% - 70px);background-color:var(--surface-a);width:250px;border-right:1px solid var(--surface-d);user-select:none;transition:transform .4s cubic-bezier(0.05, 0.74, 0.2, 0.99);display:flex;flex-direction:column}.layout-sidebar .layout-sidebar-filter{padding:1.25rem 1rem;border-bottom:1px solid var(--surface-d);background-color:var(--surface-a)}.layout-sidebar .layout-menu{padding:0 1rem;overflow-y:auto;flex-grow:1}.layout-sidebar .layout-menu .menu-category{display:block;color:var(--text-color);font-weight:700;user-select:none;padding:1.5rem 0 1rem 0;font-size:.857rem;text-transform:uppercase;border-top:1px solid var(--surface-d)}.layout-sidebar .layout-menu .menu-category:first-child{border-top:0 none;padding-top:1rem}.layout-sidebar .layout-menu .menu-items{padding:0 0 1rem 0;display:flex;flex-direction:column}.layout-sidebar .layout-menu .menu-items a{color:var(--text-color);display:flex;align-items:center;padding:.5rem;border-radius:3px;cursor:pointer}.layout-sidebar .layout-menu .menu-items a:hover{background-color:var(--surface-c)}.layout-sidebar .layout-menu .menu-items a:focus{z-index:1;outline:0 none;transition:box-shadow .2s;box-shadow:0 0 0 .2em #bbdefb}.layout-sidebar .layout-menu .menu-items a.router-link-active{font-weight:700;color:var(--primary-color)}.layout-sidebar .layout-menu .menu-items a .ui-tag{padding-top:.125rem;padding-bottom:.125rem;margin-left:.5rem}.layout-sidebar .layout-menu .menu-items a.hidden{pointer-events:none}.layout-sidebar .layout-menu .menu-items .submenu{display:none}.layout-sidebar .layout-menu .menu-items .submenu ul{padding:.5rem 0;margin:0;list-style-type:none}.layout-sidebar .layout-menu .menu-items .submenu ul a{font-size:.875rem;padding:.475rem .5rem .475rem 2rem}.layout-sidebar .layout-menu .menu-image{padding:0 0 1rem 0}.layout-sidebar .layout-menu .menu-image.menu-banner a{padding:0}.layout-sidebar .layout-menu .menu-image.menu-banner a:hover{background-color:rgba(0,0,0,0)}.layout-sidebar .layout-menu .menu-image.menu-banner a:hover img{background-color:var(--surface-c)}.layout-sidebar .layout-menu .menu-image.menu-banner a:focus{box-shadow:none}.layout-sidebar .layout-menu .menu-image img{width:100%}.layout-sidebar-filter-panel.ui-autocomplete-panel{padding:.5rem 0}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-widget-header td{border:1px solid rgba(0,0,0,0);padding:3px 5px}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row>td{border:1px solid rgba(0,0,0,0);padding:0}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row>td a{display:flex;align-items:center;padding:.5rem 1rem;color:var(--text-color)}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row>td a .ui-tag{padding-top:.125rem;padding-bottom:.125rem;margin-left:.5rem}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row.ui-state-highlight>td a{background:var(--primary-color);color:var(--primary-color-text)}.layout-content{margin-left:250px;padding-top:70px}.layout-content .content-section{padding:2rem}.layout-content .content-section.introduction{background-color:var(--surface-b);color:var(--text-color);padding-bottom:0;display:flex;align-items:top;justify-content:space-between}.layout-content .content-section.introduction .feature-intro h1 span{font-weight:400;color:var(--text-color-secondary)}.layout-content .content-section.introduction .feature-intro p{margin:0}.layout-content .content-section.introduction .feature-intro a{text-decoration:none;color:#2196f3;font-weight:600}.layout-content .content-section.introduction .feature-intro a:hover{text-decoration:underline}.layout-content .content-section.introduction .documentation-link{text-decoration:none;color:#2196f3;font-weight:600;display:flex;align-items:center;margin:1rem 0;white-space:nowrap}.layout-content .content-section.introduction .documentation-link:hover{text-decoration:underline}.layout-content .content-section.introduction .documentation-link i{margin-right:.5rem}.layout-content .content-section.implementation{background-color:var(--surface-b);color:var(--text-color)}.layout-content .content-section.implementation+.documentation{padding-top:0}.layout-content .content-section.implementation input[type=hidden]+h5{margin-top:0}.layout-content .content-section.documentation{background-color:var(--surface-b);color:var(--text-color)}.layout-content .content-section.documentation li{line-height:1.5}.layout-content .content-section.documentation a{text-decoration:none;color:#2196f3;font-weight:600}.layout-content .content-section.documentation a:hover{text-decoration:underline}.layout-content .content-section.documentation .doc-tablewrapper{margin:1rem 0;overflow:auto}.layout-content .content-section.documentation i:not([class~=pi]){background-color:var(--surface-a);color:#2196f3;font-family:Monaco,courier,monospace;font-style:normal;font-size:12px;padding:2px 4px;letter-spacing:.5px;border-radius:3px;font-weight:600;margin:0 2px}.layout-content .content-section.documentation .ui-tabs{background:rgba(0,0,0,0);border:0 none}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav{background-color:rgba(0,0,0,0)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav:before{border-bottom:1px solid var(--surface-d) !important}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header{background-color:rgba(0,0,0,0);border-bottom-width:1px}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header a{text-decoration:none}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-hover{border-color:rgba(0,0,0,0);border-bottom-color:var(--primary-color);border-radius:0}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-hover a{color:var(--text-color)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-active{border-color:rgba(0,0,0,0);border-bottom-color:var(--primary-color);border-radius:0}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-active a{color:var(--primary-color)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-panels{background:rgba(0,0,0,0)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-panels .ui-tabs-panel{padding:2rem 1rem}.layout-content .content-section .doc-table{border-collapse:collapse;width:100%;background-color:var(--surface-a)}.layout-content .content-section .doc-table th{border-bottom:1px solid var(--surface-d);padding:1rem;text-align:left}.layout-content .content-section .doc-table tbody td{padding:1rem;border-bottom:1px solid var(--surface-d)}.layout-content .card{background:var(--surface-e);padding:2rem;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);border-radius:4px;margin-bottom:2rem}.layout-content .card .card-header{display:flex;align-items:center;justify-content:space-between}code[class*=language-],pre[class*=language-]{color:#000;background:none;font-family:Consolas,Monaco,"Andale Mono","Ubuntu Mono",monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{position:relative;margin:.5em 0;overflow:visible;padding:0}pre[class*=language-]>code{position:relative;border-left:10px solid var(--surface-d) !important;background-color:var(--surface-e) !important;background-image:linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);background-size:3em 3em;background-origin:content-box;background-attachment:local;color:var(--text-color)}code[class*=language-]{max-height:inherit;height:inherit;padding:0 1em;display:block;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background-color:#fdfdfd;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin-bottom:1em}:not(pre)>code[class*=language-]{position:relative;padding:.2em;border-radius:.3em;color:#c92c2c;border:1px solid rgba(0,0,0,.1);display:inline;white-space:normal}pre[class*=language-]:before,pre[class*=language-]:after{content:"";z-index:-2;display:block;position:absolute;bottom:.75em;left:.18em;width:40%;height:20%;max-height:13em;box-shadow:0px 13px 8px #979797;-webkit-transform:rotate(-2deg);-moz-transform:rotate(-2deg);-ms-transform:rotate(-2deg);-o-transform:rotate(-2deg);transform:rotate(-2deg)}pre[class*=language-]:after{right:.75em;left:auto;-webkit-transform:rotate(2deg);-moz-transform:rotate(2deg);-ms-transform:rotate(2deg);-o-transform:rotate(2deg);transform:rotate(2deg)}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#7d8b99}.token.punctuation{color:var(--text-color)}.token.property,.token.tag,.token.boolean,.token.number,.token.function-name,.token.constant,.token.symbol,.token.deleted{color:#c92c2c}.token.selector,.token.attr-name,.token.string,.token.char,.token.function,.token.builtin,.token.inserted{color:#2f9c0a}.token.operator,.token.entity,.token.url,.token.variable{color:#a67f59;background:rgba(255,255,255,.5)}.token.atrule,.token.attr-value,.token.keyword,.token.class-name{color:#1990b8}.token.regex,.token.important{color:#e90}.language-css .token.string,.style .token.string{color:#a67f59;background:rgba(255,255,255,.5)}.token.important{font-weight:normal}.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help}.token.namespace{opacity:.7}@media screen and (max-width: 767px){pre[class*=language-]:before,pre[class*=language-]:after{bottom:14px;box-shadow:none}}pre[class*=language-].line-numbers.line-numbers{padding-left:0}pre[class*=language-].line-numbers.line-numbers code{padding-left:3.8em}pre[class*=language-].line-numbers.line-numbers .line-numbers-rows{left:0}pre[class*=language-][data-line]{padding-top:0;padding-bottom:0;padding-left:0}pre[data-line] code{position:relative;padding-left:4em}pre .line-highlight{margin-top:0}pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid var(--surface-d) !important;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:var(--text-color-secondary);display:block;padding-right:.8em;text-align:right}.layout-news{position:fixed;top:0;left:0;z-index:997;height:70px;width:100%;display:flex;justify-content:center;align-items:center;background-image:url("#{resource['showcase:images/news/topbar-newyear-bg.png']}"),linear-gradient(180deg, #D2000B 0%, #9B0008 100%);background-size:cover;background-blend-mode:multiply}.layout-news .layout-news-container{width:100%;height:100%;display:flex;justify-content:center;align-items:center;color:#fff;font-weight:bold;font-size:20px}.layout-news .layout-news-container .layout-news-details{display:flex;align-items:center;z-index:1}.layout-news .layout-news-container .layout-news-details .rate{color:#f2b837;font-size:25px;font-weight:bold;margin:0 .25rem}.layout-news .layout-news-container .layout-news-details .helper-text{background-color:#f2b837;color:#212121;padding:0 .2rem;margin-right:.3rem}.layout-news .layout-news-container .layout-news-header{margin:0;background:linear-gradient(180deg, #D8000A 0%, rgba(255, 0, 0, 0) 100%);border-radius:4px 4px 0px 0px;text-shadow:0px 4px 4.4px rgba(0,0,0,.3);font-weight:900}.layout-news .layout-news-container img.layouts-news-mockup-image{height:70px}.layout-news .layout-news-container .layout-news-logo{position:absolute;left:0}.layout-news .layout-news-container .layout-news-button{color:#fff;font-size:14px;padding:.4em .8em .4em 1em;font-weight:bold;border-radius:3px;display:flex;justify-content:center;align-items:center;flex-shrink:0;transition:background-color .15s;margin-left:1rem;position:relative;z-index:1;background:linear-gradient(180deg, #D8000A 0%, rgba(251, 0, 1, 0.4) 89.06%, rgba(255, 0, 0, 0) 100%);border-radius:5px}.layout-news .layout-news-container .layout-news-button>i{margin-left:.5em;font-weight:bold;position:relative;top:1px}.layout-news .layout-news-container .layout-news-button:hover{background:linear-gradient(180deg, #EE000B 0%, rgba(255, 0, 0, 0.55) 100%)}.layout-news .layout-news-close{cursor:pointer;color:#fff;position:absolute;z-index:2;right:28px;background:linear-gradient(180deg, #D8000A 0%, rgba(255, 0, 0, 0) 100%);filter:drop-shadow(0px 12px 12px rgba(0, 0, 0, 0.17));border-radius:50%;display:flex;justify-content:center;align-items:center;width:34px;height:34px}.layout-wrapper.layout-news-active .layout-topbar{top:70px}.layout-wrapper.layout-news-active .layout-sidebar{top:140px;height:calc(100% - 140px)}.layout-wrapper.layout-news-active .layout-content{padding-top:140px}.layout-wrapper.layout-news-active .layout-config{top:140px;height:calc(100% - 140px)}.layout-footer{font-size:1rem;padding:2rem;background-color:var(--surface-a);display:flex;align-items:center;justify-content:space-between}.layout-footer a{color:var(--text-color);font-weight:600}.layout-footer .layout-footer-right a i{color:var(--text-secondary-color);font-size:1.5rem}.layout-config{position:fixed;padding:0;top:0;right:0;display:block;width:550px;z-index:998;height:100%;transition:transform .4s cubic-bezier(0.05, 0.74, 0.2, 0.99);transform:translateX(100%);backface-visibility:hidden}.layout-config.layout-config-active{transform:translateX(0)}.layout-config.layout-config-active .layout-config-content-wrapper .layout-config-button i{transform:rotate(0deg)}.layout-config .layout-config-content-wrapper{position:relative;height:100%;box-shadow:0 2px 10px 0 rgba(0,0,0,.24);color:var(--text-color);background-color:var(--surface-f)}.layout-config .layout-config-content-wrapper .layout-config-button{display:block;position:absolute;width:52px;height:52px;line-height:52px;background-color:var(--primary-color);text-align:center;color:var(--primary-color-text);top:270px;left:-51px;z-index:-1;overflow:hidden;cursor:pointer;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-left-radius:3px;border-bottom-right-radius:3px;animation-name:rubberBand;animation-duration:1s;animation-iteration-count:3;animation-delay:5s;box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.layout-config .layout-config-content-wrapper .layout-config-button i{font-size:26px;line-height:inherit;cursor:pointer;transform:rotate(360deg);transition:transform 1s}.layout-config a{color:#2196f3;font-weight:600;cursor:pointer}.layout-config a:hover{text-decoration:underline}.layout-config .layout-config-content{overflow:auto;height:100%;padding:2rem}.layout-config .config-scale{display:flex;align-items:center;margin:1rem 0 2rem 0}.layout-config .config-scale .p-button{margin-right:.5rem}.layout-config .config-scale i{margin-right:.5rem;font-size:.75rem;color:var(--text-color-secondary)}.layout-config .config-scale i.scale-active{font-size:1.25rem;color:#2196f3}.layout-config .layout-config-close{position:absolute;width:25px;height:25px;line-height:25px;text-align:center;right:20px;top:20px;z-index:999;background-color:var(--primary-color);border-radius:50%;transition:background-color .2s,box-shadow .2s,transform .2s}.layout-config .layout-config-close i{color:var(--primary-color-text);line-height:inherit;font-size:14px}.layout-config .layout-config-close:hover{transform:scale(1.1)}.layout-config .layout-config-close:focus{outline:0 none;box-shadow:0 0 0 .2rem #bbdefb}.layout-config .grid>div{padding:1rem;text-align:center}.layout-config .grid>div span{display:block}.layout-config .grid>div button{position:relative;display:inline-flex;justify-content:center}.layout-config .free-themes img{width:50px;border-radius:4px;transition:transform .2s}.layout-config .free-themes img:hover{transform:scale(1.1)}.layout-config .free-themes span{font-size:.875rem;margin-top:.25rem}.layout-config .premium-themes img{width:100%;transition:transform .2s}.layout-config .premium-themes img:hover{transform:scale(1.1)}@keyframes rubberBand{from{transform:scale3d(1, 1, 1)}30%{transform:scale3d(1.25, 0.75, 1)}40%{transform:scale3d(0.75, 1.25, 1)}50%{transform:scale3d(1.15, 0.85, 1)}65%{transform:scale3d(0.95, 1.05, 1)}75%{transform:scale3d(1.05, 0.95, 1)}to{transform:scale3d(1, 1, 1)}}.layout-error+.layout-footer{display:none}.home a{text-decoration:none;color:#2196f3;font-weight:600}.home a:hover{text-decoration:underline}.home p{margin-bottom:2rem}.home .introduction{background-color:var(--surface-a);background-image:url("#{resource['showcase:images/home/intro-bg.jpg']}");background-repeat:no-repeat;background-size:cover;padding:115px 30px 135px 50px;color:var(--text-color);position:relative}.home .introduction.introduction-dark{background-image:url("#{resource['showcase:images/home/intro-bg-dark.jpg']}");color:var(--text-color)}.home .introduction.introduction-dark .introduction-promo{background:linear-gradient(90deg, rgba(76, 87, 111, 0.4) 0%, transparent 100%)}.home .introduction .introduction-promo{display:inline-block;margin-left:-50px;margin-bottom:20px;padding:10px 175px 10px 50px;font-size:1.5rem;background:linear-gradient(90deg, rgba(12, 75, 152, 0.6) 0%, transparent 100%);position:relative;color:#fff;font-weight:700}.home .introduction .introduction-title{font-weight:400;margin-bottom:5px;font-size:24px}.home .introduction .introduction-subtitle{font-weight:700;margin-bottom:40px;margin-top:0;font-size:24px}.home .introduction .introduction-devices{position:absolute;bottom:0;right:0;width:55%}.home .features{background-color:var(--surface-b);text-align:center;padding:2rem}.home .features .col-12{padding:1rem}.home .features .feature-card{background-color:var(--surface-e);box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);height:100%;border-radius:3px}.home .features .feature-card .feature-card-detail{padding:0 2rem 2rem 2rem}.home .features .feature-card p{margin-bottom:0}.home .features img{width:100%}.home .features .feature-name{font-weight:700;font-size:16px;margin:1rem 0}.home .video{background-color:var(--surface-a);text-align:center;padding:2rem}.home .whouses{background-color:#34495e;color:#eaecee;text-align:center;padding:2rem}.home .whouses img{height:30px}.home .whouses img.circular{height:50px}.home .whouses .grid>div{padding:2rem .5rem;display:flex;align-items:center;justify-content:center}.home .templates{background-color:var(--surface-b);text-align:center;padding:2rem;border-bottom:1px solid var(--surface-d)}.home .templates img{width:100%;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12)}.home .prime-designer{background-color:var(--surface-a);color:var(--text-color);padding:2rem}.home .prime-designer img{width:100%;margin-bottom:30px}.home .prime-designer h4{text-align:center}.home .primeblocks{color:var(--text-color);padding:2rem}.home .primeflex{background-color:var(--surface-d);color:var(--text-color);padding:2rem}.home .prosupport{border-bottom:1px solid var(--surface-d);background-color:var(--surface-b);padding:2rem;color:var(--text-color)}.home .prosupport img{margin-top:10px}.home .prosupport .md-6:last-child{text-align:center}.home .prosupport .action-button{display:inline-block;margin-top:1rem}@media screen and (max-width: 960px){.layout-wrapper.layout-news-active .layout-content{padding-top:180px}.layout-wrapper.layout-news-active .layout-sidebar{top:0;height:100%}.layout-wrapper.layout-news-active .layout-news-button{opacity:0;position:absolute;z-index:1;width:100%;height:100%;margin:0;top:0;left:0}.layout-wrapper.layout-news-active .layout-news-logo{display:none}.layout-topbar{height:110px;flex-wrap:wrap;justify-content:space-between;padding:0}.layout-topbar .menu-button{display:block}.layout-topbar .logo img{width:150px}.layout-topbar .app-theme{margin-left:0;margin-right:23px}.layout-topbar .topbar-form{width:100%}.layout-topbar .topbar-menu{background-color:var(--surface-a);width:100%;height:40px;margin:0;border-top:1px solid var(--surface-d)}.layout-topbar .topbar-menu>li{height:40px;line-height:40px;width:25%}.layout-topbar .topbar-menu>li>a{padding-bottom:0;height:40px;line-height:38px;width:100%;font-size:14px;min-width:auto}.layout-topbar .topbar-menu>li.topbar-submenu>ul{top:40px}.layout-sidebar{top:0;z-index:999;height:100%;transform:translateX(-100%)}.layout-sidebar.active{transform:translateX(0)}.layout-content{margin-left:0;padding-top:110px}.layout-content .content-section.introduction{flex-direction:column}.layout-content .video-container{position:relative;width:100%;height:0;padding-bottom:56.25%}.layout-content .video-container iframe{position:absolute;top:0;left:0;width:100%;height:100%}.layout-mask{background-color:rgba(0,0,0,.1)}.layout-mask.layout-mask-active{z-index:998;width:100%;height:100%;position:fixed;top:0;left:0;background-color:rgba(0,0,0,.4);transition:background-color .2s}.home .introduction>div{width:100%}.home .features>div{width:100%}.home .whouses>div{width:100%}.home .prosupport>div{width:100%}.home .video iframe{width:100% !important}.layout-config .layout-config-button{left:auto;right:-52px}.layout-config.layout-config-active{width:100%}.blocked-scroll{overflow:hidden}}@media screen and (max-width: 640px){.layout-wrapper.layout-news-active .topbar-menu>li.topbar-submenu>ul{top:180px}.layout-topbar .topbar-menu>li.topbar-submenu{position:static}.layout-topbar .topbar-menu>li.topbar-submenu>ul{top:110px;position:fixed;right:auto;left:0;width:100vw}.layout-error img{width:80%}}.customer-badge{border-radius:2px;padding:.25em .5rem;text-transform:uppercase;font-weight:700;font-size:12px;letter-spacing:.3px}.customer-badge.status-qualified{background-color:#c8e6c9;color:#256029}.customer-badge.status-unqualified{background-color:#ffcdd2;color:#c63737}.customer-badge.status-negotiation{background-color:#feedaf;color:#8a5340}.customer-badge.status-new{background-color:#b3e5fc;color:#23547b}.customer-badge.status-renewal{background-color:#eccfff;color:#694382}.customer-badge.status-proposal{background-color:#ffd8b2;color:#805b36}.product-badge{border-radius:2px;padding:.25em .5rem;text-transform:uppercase;font-weight:700;font-size:12px;letter-spacing:.3px}.product-badge.status-instock{background:#c8e6c9;color:#256029}.product-badge.status-outofstock{background:#ffcdd2;color:#c63737}.product-badge.status-lowstock{background:#feedaf;color:#8a5340}.order-badge{border-radius:2px;padding:.25em .5rem;text-transform:uppercase;font-weight:700;font-size:12px;letter-spacing:.3px}.order-badge.order-delivered{background:#c8e6c9;color:#256029}.order-badge.order-cancelled{background:#ffcdd2;color:#c63737}.order-badge.order-pending{background:#feedaf;color:#8a5340}.order-badge.order-returned{background:#eccfff;color:#694382}.image-text{vertical-align:middle;margin-left:.5rem}.p-multiselect-representative-option{display:inline-block;vertical-align:middle}.p-multiselect-representative-option img{vertical-align:middle;width:24px}.p-multiselect-representative-option span{margin-top:.125rem}.p-column-filter{width:100%}.country-item{display:flex;align-items:center}.country-item img.flag{width:18px;margin-right:.5rem}.image-text{vertical-align:middle;margin-left:.5rem}.p-multiselect-representative-option{display:inline-block;vertical-align:middle}.p-multiselect-representative-option img{vertical-align:middle;width:24px}.p-multiselect-representative-option span{margin-top:.125rem}.p-column-filter{width:100%}.country-item{display:flex;align-items:center}.country-item img.flag{width:18px;margin-right:.5rem}.product .product-name{font-size:1rem;font-weight:700}.product .product-description{margin:0 0 1rem 0}.product .product-category-icon{vertical-align:middle;margin-right:.5rem}.product .product-category{font-weight:600;vertical-align:middle}.product .product-list-item{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:1rem}.product .product-list-item.border-1{border-bottom:1px solid var(--surface-d)}.product .product-list-item img{width:150px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);margin-right:2rem}.product .product-list-item .product-list-detail{flex:1 1 0;-ms-flex:1 1 0}.product .product-list-item .ui-rating{margin:0 0 .5rem 0}.product .product-list-item .product-price{font-size:1.5rem;font-weight:600;margin-bottom:.5rem;align-self:flex-end}.product .product-list-item .product-list-action{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.product .product-list-item .ui-button{margin-bottom:.5rem}.product .product-grid-item.border-1{border:1px solid var(--surface-d)}.product .product-grid-item .product-grid-item-top,.product .product-grid-item .product-grid-item-bottom{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.product .product-grid-item img{width:75%;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);margin:2rem 0}.product .product-grid-item .ui-rating{margin:0 0 1rem 0}.product .product-grid-item .product-grid-item-content{text-align:center}.product .product-grid-item .product-price{font-size:1.5rem;font-weight:600}@media screen and (max-width: 576px){.product .product-list-item{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center}.product .product-list-item img{width:75%;margin:2rem 0}.product .product-list-item .product-list-detail{text-align:center}.product .product-list-item .product-price{align-self:center}.product .product-list-item .product-list-action{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.product .product-list-item .product-list-action{margin-top:2rem;-ms-flex-direction:row;flex-direction:row;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:center;align-items:center;width:100%}}.crud-demo .ui-datatable{margin-top:1rem}.crud-demo .product-image{width:100px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}.crud-demo .ui-dialog .product-image{width:250px;margin:0 auto 2rem auto;display:block}.crud-demo .ui-dialog-footer .ui-button{min-width:6rem}.crud-demo .ui-datatable .ui-column-filter{display:none}.crud-demo .products-table-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-wrap:wrap;flex-wrap:wrap}.crud-demo .edit-button.ui-button{margin-right:.5rem}.crud-demo .orders-subtable{padding:1rem}.crud-demo .products-table>.ui-datatable-tablewrapper>table>thead>tr>th:nth-child(1){width:1rem}.crud-demo .products-table .ui-rating{display:inline-block}@media(max-width: 640px){.products-table>.ui-datatable-tablewrapper>table>thead>tr>th:nth-child(2) .ui-column-title,.products-table>.ui-datatable-tablewrapper>table>tbody>tr>td:nth-child(2) .ui-column-title{display:none !important}.products-buttonbar{-ms-flex-direction:column;flex-direction:column}.products-buttonbar>div:last-child{margin-top:.5rem}}.cascadeselect-item.country-item .flag{width:18px;height:12px;margin-right:.5rem}.manymenu-advanced.ui-selectmanymenu .ui-selectlistbox-listcontainer .ui-selectlistbox-list .ui-selectlistbox-item>td:nth-child(2){width:1rem;padding:0} +html{font-size:14px}body{margin:0px;height:100%;overflow-x:hidden;overflow-y:auto;background-color:var(--surface-a);font-family:var(--font-family);font-weight:normal;color:var(--text-color);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{text-decoration:none}h1,h2,h3,h4,h5,h6{margin:1.5rem 0 1rem 0;font-family:inherit;font-weight:600;line-height:1.2;color:inherit}h1:first-child,h2:first-child,h3:first-child,h4:first-child,h5:first-child,h6:first-child{margin-top:0}h1{font-size:2.5rem}h2{font-size:2rem}h3{font-size:1.75rem}h4{font-size:1.5rem}h5{font-size:1.25rem}h6{font-size:1rem}p{line-height:1.5;margin:0 0 1rem 0}@keyframes pulse{0%{background-color:rgba(165,165,165,.1)}50%{background-color:rgba(165,165,165,.3)}100%{background-color:rgba(165,165,165,.1)}}.p-toast.p-toast-topright,.p-toast.p-toast-topleft{top:100px}.action-button{font-weight:bold;text-align:center;color:#2b3034 !important;background-color:#feab4d;padding:10px 24px 9px 24px;border-radius:3px;transition:background-color .2s}.action-button:hover{background-color:#feb767;color:#fff;text-decoration:none !important}.status-indicator{position:fixed;width:42px;height:42px;right:7px;bottom:7px;font-size:28px;color:var(--primary-color);pointer-events:none}.text-secondary{color:var(--text-color-secondary)}.floatlabel-demo .field{margin-top:2rem}.p-connected-overlay{opacity:0;transform:scaleY(0.8);transition:transform .12s cubic-bezier(0, 0, 0.2, 1),opacity .12s cubic-bezier(0, 0, 0.2, 1)}.p-connected-overlay-visible{opacity:1;transform:scaleY(1)}.p-connected-overlay-hidden{opacity:0;transform:scaleY(1);transition:opacity .1s linear}@-webkit-keyframes connected-overlay-in{from{opacity:0;-webkit-transform:scaleY(0.8);transform:scaleY(0.8)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes connected-overlay-in{from{opacity:0;transform:scaleY(0.8)}to{opacity:1;transform:none}}@-webkit-keyframes connected-overlay-out{from{opacity:1}to{opacity:0}}@keyframes fade-out-down{from{opacity:1}to{opacity:0}}.connected-overlay-in{-webkit-animation-name:connected-overlay-in;animation-name:connected-overlay-in}.connected-overlay-out{-webkit-animation-name:connected-overlay-out;animation-name:connected-overlay-out}.layout-topbar{background-color:var(--surface-a);padding:0;height:70px;position:fixed;top:0;left:0;width:100%;z-index:997;box-shadow:0 0 4px rgba(0,0,0,.25);border-bottom:1px solid var(--surface-d);display:flex;align-items:center;padding:0 35px}.layout-topbar .menu-button{display:none;color:var(--text-color);width:70px;height:70px;line-height:70px;text-align:center;transition:background-color .2s;overflow:hidden;cursor:pointer}.layout-topbar .menu-button:hover{background-color:var(--surface-c)}.layout-topbar .menu-button i{font-size:24px;line-height:inherit}.layout-topbar .logo img{width:180px}.layout-topbar .logo:focus{outline:0 none;transition:box-shadow .2s;box-shadow:0 0 0 .2rem #bbdefb}.layout-topbar .app-theme{background-color:var(--primary-color);color:var(--primary-color-text);padding:.5rem;border-radius:4px;box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12);width:39px;height:39px;margin-left:70px}.layout-topbar .app-theme img{width:25px}.layout-topbar .topbar-form{margin-left:auto}.layout-topbar .topbar-menu{list-style-type:none;margin:0;padding:0;height:100%;display:flex}.layout-topbar .topbar-menu>li{height:70px;line-height:70px}.layout-topbar .topbar-menu>li>a{text-decoration:none;color:var(--text-color);min-width:120px;font-size:16px;display:block;text-align:center;user-select:none;line-height:68px;border-bottom:2px solid rgba(0,0,0,0);transition:border-bottom-color .2s;cursor:pointer}.layout-topbar .topbar-menu>li>a:hover,.layout-topbar .topbar-menu>li>a:focus{border-bottom-color:var(--primary-color)}.layout-topbar .topbar-menu>li>a:focus{z-index:1;outline:0 none;transition:box-shadow .2s;box-shadow:inset 0 0 0 .2em #bbdefb}.layout-topbar .topbar-menu>li.topbar-submenu{position:relative}.layout-topbar .topbar-menu>li.topbar-submenu .ui-overlay-badge{display:inline}.layout-topbar .topbar-menu>li.topbar-submenu.topbar-submenu-active>ul{display:block}.layout-topbar .topbar-menu>li.topbar-submenu>ul{display:none;position:absolute;transform-origin:top;top:70px;right:0;width:275px;max-height:400px;background-color:var(--surface-f);box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12);overflow:auto;list-style-type:none;padding:1rem;margin:0;border-radius:3px;animation-duration:.12s}.layout-topbar .topbar-menu>li.topbar-submenu>ul>li{line-height:1}.layout-topbar .topbar-menu>li.topbar-submenu>ul>li.topbar-submenu-header{display:block;color:var(--text-color-secondary);font-weight:600;user-select:none;padding:1.5rem 0 1rem 0;font-size:.857rem;text-transform:uppercase}.layout-topbar .topbar-menu>li.topbar-submenu>ul>li.topbar-submenu-header:first-child{padding-top:1rem}.layout-topbar .topbar-menu>li.topbar-submenu>ul a{text-decoration:none;color:var(--text-color);padding:.5rem;display:flex;align-items:center;user-select:none;border-radius:3px;cursor:pointer}.layout-topbar .topbar-menu>li.topbar-submenu>ul a:hover{background-color:var(--surface-c)}.layout-topbar .topbar-menu>li.topbar-submenu>ul a span{margin-left:.5rem}.layout-topbar .topbar-menu>li.topbar-submenu>ul a i{font-size:18px;color:var(--text-color-secondary)}.layout-topbar .topbar-menu>li.topbar-submenu>ul a img{width:32px;margin-right:.5rem}.layout-topbar .topbar-menu .theme-badge{padding:2px 4px;vertical-align:middle;border-radius:3px;color:#fff;font-weight:bold;font-size:11px;position:relative;top:-1px}.layout-topbar .topbar-menu .theme-badge.material{background:linear-gradient(to bottom, #2196F3, #2196F3)}.layout-topbar .topbar-menu .theme-badge.bootstrap{background:linear-gradient(to bottom, #563D7C, #966BD8)}.layout-topbar .topbar-menu .theme-badge.darkmode{background:linear-gradient(to bottom, #141d26, #5a6067)}.layout-sidebar{position:fixed;left:0;top:70px;height:calc(100% - 70px);background-color:var(--surface-a);width:250px;border-right:1px solid var(--surface-d);user-select:none;transition:transform .4s cubic-bezier(0.05, 0.74, 0.2, 0.99);display:flex;flex-direction:column}.layout-sidebar .layout-sidebar-filter{padding:1.25rem 1rem;border-bottom:1px solid var(--surface-d);background-color:var(--surface-a)}.layout-sidebar .layout-menu{padding:0 1rem;overflow-y:auto;flex-grow:1}.layout-sidebar .layout-menu .menu-category{display:block;color:var(--text-color);font-weight:700;user-select:none;padding:1.5rem 0 1rem 0;font-size:.857rem;text-transform:uppercase;border-top:1px solid var(--surface-d)}.layout-sidebar .layout-menu .menu-category:first-child{border-top:0 none;padding-top:1rem}.layout-sidebar .layout-menu .menu-items{padding:0 0 1rem 0;display:flex;flex-direction:column}.layout-sidebar .layout-menu .menu-items a{color:var(--text-color);display:flex;align-items:center;padding:.5rem;border-radius:3px;cursor:pointer}.layout-sidebar .layout-menu .menu-items a:hover{background-color:var(--surface-c)}.layout-sidebar .layout-menu .menu-items a:focus{z-index:1;outline:0 none;transition:box-shadow .2s;box-shadow:0 0 0 .2em #bbdefb}.layout-sidebar .layout-menu .menu-items a.router-link-active{font-weight:700;color:var(--primary-color)}.layout-sidebar .layout-menu .menu-items a .ui-tag{padding-top:.125rem;padding-bottom:.125rem;margin-left:.5rem}.layout-sidebar .layout-menu .menu-items a.hidden{pointer-events:none}.layout-sidebar .layout-menu .menu-items .submenu{display:none}.layout-sidebar .layout-menu .menu-items .submenu ul{padding:.5rem 0;margin:0;list-style-type:none}.layout-sidebar .layout-menu .menu-items .submenu ul a{font-size:.875rem;padding:.475rem .5rem .475rem 2rem}.layout-sidebar .layout-menu .menu-image{padding:0 0 1rem 0}.layout-sidebar .layout-menu .menu-image.menu-banner a{padding:0}.layout-sidebar .layout-menu .menu-image.menu-banner a:hover{background-color:rgba(0,0,0,0)}.layout-sidebar .layout-menu .menu-image.menu-banner a:hover img{background-color:var(--surface-c)}.layout-sidebar .layout-menu .menu-image.menu-banner a:focus{box-shadow:none}.layout-sidebar .layout-menu .menu-image img{width:100%}.layout-sidebar-filter-panel.ui-autocomplete-panel{padding:.5rem 0}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-widget-header td{border:1px solid rgba(0,0,0,0);padding:3px 5px}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row>td{border:1px solid rgba(0,0,0,0);padding:0}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row>td a{display:flex;align-items:center;padding:.5rem 1rem;color:var(--text-color)}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row>td a .ui-tag{padding-top:.125rem;padding-bottom:.125rem;margin-left:.5rem}.layout-sidebar-filter-panel.ui-autocomplete-panel .ui-autocomplete-table .ui-autocomplete-item.ui-autocomplete-row.ui-state-highlight>td a{background:var(--primary-color);color:var(--primary-color-text)}.layout-content{margin-left:250px;padding-top:70px}.layout-content .content-section{padding:2rem}.layout-content .content-section.introduction{background-color:var(--surface-b);color:var(--text-color);padding-bottom:0;display:flex;align-items:top;justify-content:space-between}.layout-content .content-section.introduction .feature-intro h1 span{font-weight:400;color:var(--text-color-secondary)}.layout-content .content-section.introduction .feature-intro p{margin:0}.layout-content .content-section.introduction .feature-intro a{text-decoration:none;color:#2196f3;font-weight:600}.layout-content .content-section.introduction .feature-intro a:hover{text-decoration:underline}.layout-content .content-section.introduction .documentation-link{text-decoration:none;color:#2196f3;font-weight:600;display:flex;align-items:center;margin:1rem 0;white-space:nowrap}.layout-content .content-section.introduction .documentation-link:hover{text-decoration:underline}.layout-content .content-section.introduction .documentation-link i{margin-right:.5rem}.layout-content .content-section.implementation{background-color:var(--surface-b);color:var(--text-color)}.layout-content .content-section.implementation+.documentation{padding-top:0}.layout-content .content-section.implementation input[type=hidden]+h5{margin-top:0}.layout-content .content-section.documentation{background-color:var(--surface-b);color:var(--text-color)}.layout-content .content-section.documentation li{line-height:1.5}.layout-content .content-section.documentation a{text-decoration:none;color:#2196f3;font-weight:600}.layout-content .content-section.documentation a:hover{text-decoration:underline}.layout-content .content-section.documentation .doc-tablewrapper{margin:1rem 0;overflow:auto}.layout-content .content-section.documentation i:not([class~=pi]){background-color:var(--surface-a);color:#2196f3;font-family:Monaco,courier,monospace;font-style:normal;font-size:12px;padding:2px 4px;letter-spacing:.5px;border-radius:3px;font-weight:600;margin:0 2px}.layout-content .content-section.documentation .ui-tabs{background:rgba(0,0,0,0);border:0 none}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav{background-color:rgba(0,0,0,0)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav:before{border-bottom:1px solid var(--surface-d) !important}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header{background-color:rgba(0,0,0,0);border-bottom-width:1px}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header a{text-decoration:none}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-hover{border-color:rgba(0,0,0,0);border-bottom-color:var(--primary-color);border-radius:0}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-hover a{color:var(--text-color)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-active{border-color:rgba(0,0,0,0);border-bottom-color:var(--primary-color);border-radius:0}.layout-content .content-section.documentation .ui-tabs .ui-tabs-nav li.ui-tabs-header.ui-state-active a{color:var(--primary-color)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-panels{background:rgba(0,0,0,0)}.layout-content .content-section.documentation .ui-tabs .ui-tabs-panels .ui-tabs-panel{padding:2rem 1rem}.layout-content .content-section .doc-table{border-collapse:collapse;width:100%;background-color:var(--surface-a)}.layout-content .content-section .doc-table th{border-bottom:1px solid var(--surface-d);padding:1rem;text-align:left}.layout-content .content-section .doc-table tbody td{padding:1rem;border-bottom:1px solid var(--surface-d)}.layout-content .card{background:var(--surface-e);padding:2rem;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);border-radius:4px;margin-bottom:2rem}.layout-content .card .card-header{display:flex;align-items:center;justify-content:space-between}code[class*=language-],pre[class*=language-]{color:#000;background:none;font-family:Consolas,Monaco,"Andale Mono","Ubuntu Mono",monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{position:relative;margin:.5em 0;overflow:visible;padding:0}pre[class*=language-]>code{position:relative;border-left:10px solid var(--surface-d) !important;background-color:var(--surface-e) !important;background-image:linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);background-size:3em 3em;background-origin:content-box;background-attachment:local;color:var(--text-color)}code[class*=language-]{max-height:inherit;height:inherit;padding:0 1em;display:block;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background-color:#fdfdfd;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin-bottom:1em}:not(pre)>code[class*=language-]{position:relative;padding:.2em;border-radius:.3em;color:#c92c2c;border:1px solid rgba(0,0,0,.1);display:inline;white-space:normal}pre[class*=language-]:before,pre[class*=language-]:after{content:"";z-index:-2;display:block;position:absolute;bottom:.75em;left:.18em;width:40%;height:20%;max-height:13em;box-shadow:0px 13px 8px #979797;-webkit-transform:rotate(-2deg);-moz-transform:rotate(-2deg);-ms-transform:rotate(-2deg);-o-transform:rotate(-2deg);transform:rotate(-2deg)}pre[class*=language-]:after{right:.75em;left:auto;-webkit-transform:rotate(2deg);-moz-transform:rotate(2deg);-ms-transform:rotate(2deg);-o-transform:rotate(2deg);transform:rotate(2deg)}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#7d8b99}.token.punctuation{color:var(--text-color)}.token.property,.token.tag,.token.boolean,.token.number,.token.function-name,.token.constant,.token.symbol,.token.deleted{color:#c92c2c}.token.selector,.token.attr-name,.token.string,.token.char,.token.function,.token.builtin,.token.inserted{color:#2f9c0a}.token.operator,.token.entity,.token.url,.token.variable{color:#a67f59;background:rgba(255,255,255,.5)}.token.atrule,.token.attr-value,.token.keyword,.token.class-name{color:#1990b8}.token.regex,.token.important{color:#e90}.language-css .token.string,.style .token.string{color:#a67f59;background:rgba(255,255,255,.5)}.token.important{font-weight:normal}.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help}.token.namespace{opacity:.7}@media screen and (max-width: 767px){pre[class*=language-]:before,pre[class*=language-]:after{bottom:14px;box-shadow:none}}pre[class*=language-].line-numbers.line-numbers{padding-left:0}pre[class*=language-].line-numbers.line-numbers code{padding-left:3.8em}pre[class*=language-].line-numbers.line-numbers .line-numbers-rows{left:0}pre[class*=language-][data-line]{padding-top:0;padding-bottom:0;padding-left:0}pre[data-line] code{position:relative;padding-left:4em}pre .line-highlight{margin-top:0}pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid var(--surface-d) !important;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:var(--text-color-secondary);display:block;padding-right:.8em;text-align:right}.layout-news{position:fixed;top:0;left:0;z-index:997;height:70px;width:100%;display:flex;justify-content:center;align-items:center;background-image:url("#{resource['showcase:images/news/topbar-newyear-bg.png']}"),linear-gradient(180deg, #D2000B 0%, #9B0008 100%);background-size:cover;background-blend-mode:multiply}.layout-news .layout-news-container{width:100%;height:100%;display:flex;justify-content:center;align-items:center;color:#fff;font-weight:bold;font-size:20px}.layout-news .layout-news-container .layout-news-details{display:flex;align-items:center;z-index:1}.layout-news .layout-news-container .layout-news-details .rate{color:#f2b837;font-size:25px;font-weight:bold;margin:0 .25rem}.layout-news .layout-news-container .layout-news-details .helper-text{background-color:#f2b837;color:#212121;padding:0 .2rem;margin-right:.3rem}.layout-news .layout-news-container .layout-news-header{margin:0;background:linear-gradient(180deg, #D8000A 0%, rgba(255, 0, 0, 0) 100%);border-radius:4px 4px 0px 0px;text-shadow:0px 4px 4.4px rgba(0,0,0,.3);font-weight:900}.layout-news .layout-news-container img.layouts-news-mockup-image{height:70px}.layout-news .layout-news-container .layout-news-logo{position:absolute;left:0}.layout-news .layout-news-container .layout-news-button{color:#fff;font-size:14px;padding:.4em .8em .4em 1em;font-weight:bold;border-radius:3px;display:flex;justify-content:center;align-items:center;flex-shrink:0;transition:background-color .15s;margin-left:1rem;position:relative;z-index:1;background:linear-gradient(180deg, #D8000A 0%, rgba(251, 0, 1, 0.4) 89.06%, rgba(255, 0, 0, 0) 100%);border-radius:5px}.layout-news .layout-news-container .layout-news-button>i{margin-left:.5em;font-weight:bold;position:relative;top:1px}.layout-news .layout-news-container .layout-news-button:hover{background:linear-gradient(180deg, #EE000B 0%, rgba(255, 0, 0, 0.55) 100%)}.layout-news .layout-news-close{cursor:pointer;color:#fff;position:absolute;z-index:2;right:28px;background:linear-gradient(180deg, #D8000A 0%, rgba(255, 0, 0, 0) 100%);filter:drop-shadow(0px 12px 12px rgba(0, 0, 0, 0.17));border-radius:50%;display:flex;justify-content:center;align-items:center;width:34px;height:34px}.layout-wrapper.layout-news-active .layout-topbar{top:70px}.layout-wrapper.layout-news-active .layout-sidebar{top:140px;height:calc(100% - 140px)}.layout-wrapper.layout-news-active .layout-content{padding-top:140px}.layout-wrapper.layout-news-active .layout-config{top:140px;height:calc(100% - 140px)}.layout-footer{font-size:1rem;padding:2rem;background-color:var(--surface-a);display:flex;align-items:center;justify-content:space-between}.layout-footer a{color:var(--text-color);font-weight:600}.layout-footer .layout-footer-right a i{color:var(--text-secondary-color);font-size:1.5rem}.layout-config{position:fixed;padding:0;top:0;right:0;display:block;width:550px;z-index:998;height:100%;transition:transform .4s cubic-bezier(0.05, 0.74, 0.2, 0.99);transform:translateX(100%);backface-visibility:hidden}.layout-config.layout-config-active{transform:translateX(0)}.layout-config.layout-config-active .layout-config-content-wrapper .layout-config-button i{transform:rotate(0deg)}.layout-config .layout-config-content-wrapper{position:relative;height:100%;box-shadow:0 2px 10px 0 rgba(0,0,0,.24);color:var(--text-color);background-color:var(--surface-f)}.layout-config .layout-config-content-wrapper .layout-config-button{display:block;position:absolute;width:52px;height:52px;line-height:52px;background-color:var(--primary-color);text-align:center;color:var(--primary-color-text);top:270px;left:-51px;z-index:-1;overflow:hidden;cursor:pointer;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-left-radius:3px;border-bottom-right-radius:3px;animation-name:rubberBand;animation-duration:1s;animation-iteration-count:3;animation-delay:5s;box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.layout-config .layout-config-content-wrapper .layout-config-button i{font-size:26px;line-height:inherit;cursor:pointer;transform:rotate(360deg);transition:transform 1s}.layout-config a{color:#2196f3;font-weight:600;cursor:pointer}.layout-config a:hover{text-decoration:underline}.layout-config .layout-config-content{overflow:auto;height:100%;padding:2rem}.layout-config .config-scale{display:flex;align-items:center;margin:1rem 0 2rem 0}.layout-config .config-scale .p-button{margin-right:.5rem}.layout-config .config-scale i{margin-right:.5rem;font-size:.75rem;color:var(--text-color-secondary)}.layout-config .config-scale i.scale-active{font-size:1.25rem;color:#2196f3}.layout-config .layout-config-close{position:absolute;width:25px;height:25px;line-height:25px;text-align:center;right:20px;top:20px;z-index:999;background-color:var(--primary-color);border-radius:50%;transition:background-color .2s,box-shadow .2s,transform .2s}.layout-config .layout-config-close i{color:var(--primary-color-text);line-height:inherit;font-size:14px}.layout-config .layout-config-close:hover{transform:scale(1.1)}.layout-config .layout-config-close:focus{outline:0 none;box-shadow:0 0 0 .2rem #bbdefb}.layout-config .grid>div{padding:1rem;text-align:center}.layout-config .grid>div span{display:block}.layout-config .grid>div button{position:relative;display:inline-flex;justify-content:center}.layout-config .free-themes img{width:50px;border-radius:4px;transition:transform .2s}.layout-config .free-themes img:hover{transform:scale(1.1)}.layout-config .free-themes span{font-size:.875rem;margin-top:.25rem}.layout-config .premium-themes img{width:100%;transition:transform .2s}.layout-config .premium-themes img:hover{transform:scale(1.1)}@keyframes rubberBand{from{transform:scale3d(1, 1, 1)}30%{transform:scale3d(1.25, 0.75, 1)}40%{transform:scale3d(0.75, 1.25, 1)}50%{transform:scale3d(1.15, 0.85, 1)}65%{transform:scale3d(0.95, 1.05, 1)}75%{transform:scale3d(1.05, 0.95, 1)}to{transform:scale3d(1, 1, 1)}}.layout-error+.layout-footer{display:none}.home a{text-decoration:none;color:#2196f3;font-weight:600}.home a:hover{text-decoration:underline}.home p{margin-bottom:2rem}.home .introduction{background-color:var(--surface-a);background-image:url("#{resource['showcase:images/home/intro-bg.jpg']}");background-repeat:no-repeat;background-size:cover;padding:115px 30px 135px 50px;color:var(--text-color);position:relative}.home .introduction.introduction-dark{background-image:url("#{resource['showcase:images/home/intro-bg-dark.jpg']}");color:var(--text-color)}.home .introduction.introduction-dark .introduction-promo{background:linear-gradient(90deg, rgba(76, 87, 111, 0.4) 0%, transparent 100%)}.home .introduction .introduction-promo{display:inline-block;margin-left:-50px;margin-bottom:20px;padding:10px 175px 10px 50px;font-size:1.5rem;background:linear-gradient(90deg, rgba(12, 75, 152, 0.6) 0%, transparent 100%);position:relative;color:#fff;font-weight:700}.home .introduction .introduction-title{font-weight:400;margin-bottom:5px;font-size:24px}.home .introduction .introduction-subtitle{font-weight:700;margin-bottom:40px;margin-top:0;font-size:24px}.home .introduction .introduction-devices{position:absolute;bottom:0;right:0;width:55%}.home .features{background-color:var(--surface-b);text-align:center;padding:2rem}.home .features .col-12{padding:1rem}.home .features .feature-card{background-color:var(--surface-e);box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12);height:100%;border-radius:3px}.home .features .feature-card .feature-card-detail{padding:0 2rem 2rem 2rem}.home .features .feature-card p{margin-bottom:0}.home .features img{width:100%}.home .features .feature-name{font-weight:700;font-size:16px;margin:1rem 0}.home .video{background-color:var(--surface-a);text-align:center;padding:2rem}.home .whouses{background-color:#34495e;color:#eaecee;text-align:center;padding:2rem}.home .whouses img{height:30px}.home .whouses img.circular{height:50px}.home .whouses .grid>div{padding:2rem .5rem;display:flex;align-items:center;justify-content:center}.home .templates{background-color:var(--surface-b);text-align:center;padding:2rem;border-bottom:1px solid var(--surface-d)}.home .templates img{width:100%;box-shadow:0 2px 1px -1px rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 1px 3px 0 rgba(0,0,0,.12)}.home .prime-designer{background-color:var(--surface-a);color:var(--text-color);padding:2rem}.home .prime-designer img{width:100%;margin-bottom:30px}.home .prime-designer h4{text-align:center}.home .primeblocks{color:var(--text-color);padding:2rem}.home .primeflex{background-color:var(--surface-d);color:var(--text-color);padding:2rem}.home .prosupport{border-bottom:1px solid var(--surface-d);background-color:var(--surface-b);padding:2rem;color:var(--text-color)}.home .prosupport img{margin-top:10px}.home .prosupport .md-6:last-child{text-align:center}.home .prosupport .action-button{display:inline-block;margin-top:1rem}@media screen and (max-width: 960px){.layout-wrapper.layout-news-active .layout-content{padding-top:180px}.layout-wrapper.layout-news-active .layout-sidebar{top:0;height:100%}.layout-wrapper.layout-news-active .layout-news-button{opacity:0;position:absolute;z-index:1;width:100%;height:100%;margin:0;top:0;left:0}.layout-wrapper.layout-news-active .layout-news-logo{display:none}.layout-topbar{height:110px;flex-wrap:wrap;justify-content:space-between;padding:0}.layout-topbar .menu-button{display:block}.layout-topbar .logo img{width:150px}.layout-topbar .app-theme{margin-left:0;margin-right:23px}.layout-topbar .topbar-form{width:100%}.layout-topbar .topbar-menu{background-color:var(--surface-a);width:100%;height:40px;margin:0;border-top:1px solid var(--surface-d)}.layout-topbar .topbar-menu>li{height:40px;line-height:40px;width:25%}.layout-topbar .topbar-menu>li>a{padding-bottom:0;height:40px;line-height:38px;width:100%;font-size:14px;min-width:auto}.layout-topbar .topbar-menu>li.topbar-submenu>ul{top:40px}.layout-sidebar{top:0;z-index:999;height:100%;transform:translateX(-100%)}.layout-sidebar.active{transform:translateX(0)}.layout-content{margin-left:0;padding-top:110px}.layout-content .content-section.introduction{flex-direction:column}.layout-content .video-container{position:relative;width:100%;height:0;padding-bottom:56.25%}.layout-content .video-container iframe{position:absolute;top:0;left:0;width:100%;height:100%}.layout-mask{background-color:rgba(0,0,0,.1)}.layout-mask.layout-mask-active{z-index:998;width:100%;height:100%;position:fixed;top:0;left:0;background-color:rgba(0,0,0,.4);transition:background-color .2s}.home .introduction>div{width:100%}.home .features>div{width:100%}.home .whouses>div{width:100%}.home .prosupport>div{width:100%}.home .video iframe{width:100% !important}.layout-config .layout-config-button{left:auto;right:-52px}.layout-config.layout-config-active{width:100%}.blocked-scroll{overflow:hidden}}@media screen and (max-width: 640px){.layout-wrapper.layout-news-active .topbar-menu>li.topbar-submenu>ul{top:180px}.layout-topbar .topbar-menu>li.topbar-submenu{position:static}.layout-topbar .topbar-menu>li.topbar-submenu>ul{top:110px;position:fixed;right:auto;left:0;width:100vw}.layout-error img{width:80%}}.customer-badge{border-radius:2px;padding:.25em .5rem;text-transform:uppercase;font-weight:700;font-size:12px;letter-spacing:.3px}.customer-badge.status-qualified{background-color:#c8e6c9;color:#256029}.customer-badge.status-unqualified{background-color:#ffcdd2;color:#c63737}.customer-badge.status-negotiation{background-color:#feedaf;color:#8a5340}.customer-badge.status-new{background-color:#b3e5fc;color:#23547b}.customer-badge.status-renewal{background-color:#eccfff;color:#694382}.customer-badge.status-proposal{background-color:#ffd8b2;color:#805b36}.product-badge{border-radius:2px;padding:.25em .5rem;text-transform:uppercase;font-weight:700;font-size:12px;letter-spacing:.3px}.product-badge.status-instock{background:#c8e6c9;color:#256029}.product-badge.status-outofstock{background:#ffcdd2;color:#c63737}.product-badge.status-lowstock{background:#feedaf;color:#8a5340}.order-badge{border-radius:2px;padding:.25em .5rem;text-transform:uppercase;font-weight:700;font-size:12px;letter-spacing:.3px}.order-badge.order-delivered{background:#c8e6c9;color:#256029}.order-badge.order-cancelled{background:#ffcdd2;color:#c63737}.order-badge.order-pending{background:#feedaf;color:#8a5340}.order-badge.order-returned{background:#eccfff;color:#694382}.image-text{vertical-align:middle;margin-left:.5rem}.p-multiselect-representative-option{display:inline-block;vertical-align:middle}.p-multiselect-representative-option img{vertical-align:middle;width:24px}.p-multiselect-representative-option span{margin-top:.125rem}.p-column-filter{width:100%}.country-item{display:flex;align-items:center}.country-item img.flag{width:18px;margin-right:.5rem}.image-text{vertical-align:middle;margin-left:.5rem}.p-multiselect-representative-option{display:inline-block;vertical-align:middle}.p-multiselect-representative-option img{vertical-align:middle;width:24px}.p-multiselect-representative-option span{margin-top:.125rem}.p-column-filter{width:100%}.country-item{display:flex;align-items:center}.country-item img.flag{width:18px;margin-right:.5rem}.product .product-name{font-size:1rem;font-weight:700}.product .product-description{margin:0 0 1rem 0}.product .product-category-icon{vertical-align:middle;margin-right:.5rem}.product .product-category{font-weight:600;vertical-align:middle}.product .product-list-item{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:1rem}.product .product-list-item.border-1{border-bottom:1px solid var(--surface-d)}.product .product-list-item img{width:150px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);margin-right:2rem}.product .product-list-item .product-list-detail{flex:1 1 0;-ms-flex:1 1 0}.product .product-list-item .ui-rating{margin:0 0 .5rem 0}.product .product-list-item .product-price{font-size:1.5rem;font-weight:600;margin-bottom:.5rem;align-self:flex-end}.product .product-list-item .product-list-action{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.product .product-list-item .ui-button{margin-bottom:.5rem}.product .product-grid-item.border-1{border:1px solid var(--surface-d)}.product .product-grid-item .product-grid-item-top,.product .product-grid-item .product-grid-item-bottom{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.product .product-grid-item img{width:75%;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);margin:2rem 0}.product .product-grid-item .ui-rating{margin:0 0 1rem 0}.product .product-grid-item .product-grid-item-content{text-align:center}.product .product-grid-item .product-price{font-size:1.5rem;font-weight:600}@media screen and (max-width: 576px){.product .product-list-item{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center}.product .product-list-item img{width:75%;margin:2rem 0}.product .product-list-item .product-list-detail{text-align:center}.product .product-list-item .product-price{align-self:center}.product .product-list-item .product-list-action{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.product .product-list-item .product-list-action{margin-top:2rem;-ms-flex-direction:row;flex-direction:row;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-align:center;align-items:center;width:100%}}.crud-demo .ui-datatable{margin-top:1rem}.crud-demo .product-image{width:100px;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}.crud-demo .ui-dialog .product-image{width:250px;margin:0 auto 2rem auto;display:block}.crud-demo .ui-dialog-footer .ui-button{min-width:6rem}.crud-demo .ui-datatable .ui-column-filter{display:none}.crud-demo .products-table-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;-ms-flex-wrap:wrap;flex-wrap:wrap}.crud-demo .edit-button.ui-button{margin-right:.5rem}.crud-demo .orders-subtable{padding:1rem}.crud-demo .products-table>.ui-datatable-tablewrapper>table>thead>tr>th:nth-child(1){width:1rem}.crud-demo .products-table .ui-rating{display:inline-block}@media(max-width: 640px){.products-table>.ui-datatable-tablewrapper>table>thead>tr>th:nth-child(2) .ui-column-title,.products-table>.ui-datatable-tablewrapper>table>tbody>tr>td:nth-child(2) .ui-column-title{display:none !important}.products-buttonbar{-ms-flex-direction:column;flex-direction:column}.products-buttonbar>div:last-child{margin-top:.5rem}}.cascadeselect-item.country-item .flag{width:18px;height:12px;margin-right:.5rem}.manymenu-advanced.ui-selectmanymenu .ui-selectlistbox-listcontainer .ui-selectlistbox-list .ui-selectlistbox-item>td:nth-child(2){width:1rem;padding:0} diff --git a/primefaces-showcase/src/main/webapp/ui/data/datatable/columnToggler.xhtml b/primefaces-showcase/src/main/webapp/ui/data/datatable/columnToggler.xhtml index 3cb7ccaa02..d75205d88b 100644 --- a/primefaces-showcase/src/main/webapp/ui/data/datatable/columnToggler.xhtml +++ b/primefaces-showcase/src/main/webapp/ui/data/datatable/columnToggler.xhtml @@ -18,6 +18,9 @@ + + +
@@ -40,13 +43,13 @@
- +
- + diff --git a/primefaces-showcase/src/main/webapp/ui/overlay/confirmDialog.xhtml b/primefaces-showcase/src/main/webapp/ui/overlay/confirmDialog.xhtml index aaf8e43421..c2ac0e2e2c 100644 --- a/primefaces-showcase/src/main/webapp/ui/overlay/confirmDialog.xhtml +++ b/primefaces-showcase/src/main/webapp/ui/overlay/confirmDialog.xhtml @@ -29,7 +29,7 @@ - + diff --git a/primefaces-showcase/src/main/webapp/ui/overlay/confirmPopup.xhtml b/primefaces-showcase/src/main/webapp/ui/overlay/confirmPopup.xhtml index 10f8a95c09..37ff0fef76 100644 --- a/primefaces-showcase/src/main/webapp/ui/overlay/confirmPopup.xhtml +++ b/primefaces-showcase/src/main/webapp/ui/overlay/confirmPopup.xhtml @@ -25,9 +25,13 @@ - + + + + + diff --git a/primefaces/src/main/java/org/primefaces/component/columntoggler/ColumnToggler.java b/primefaces/src/main/java/org/primefaces/component/columntoggler/ColumnToggler.java index 123ff76e53..0ade1431f8 100644 --- a/primefaces/src/main/java/org/primefaces/component/columntoggler/ColumnToggler.java +++ b/primefaces/src/main/java/org/primefaces/component/columntoggler/ColumnToggler.java @@ -34,6 +34,9 @@ import javax.faces.event.BehaviorEvent; import javax.faces.event.FacesEvent; +import org.primefaces.component.api.UIColumn; +import org.primefaces.component.datatable.DataTable; +import org.primefaces.event.ColumnToggleEvent; import org.primefaces.event.ToggleCloseEvent; import org.primefaces.event.ToggleEvent; import org.primefaces.expression.SearchExpressionUtils; @@ -87,7 +90,8 @@ public void queueEvent(FacesEvent event) { Visibility visibility = Visibility.valueOf(params.get(clientId + "_visibility")); int index = Integer.parseInt(params.get(clientId + "_index")); - super.queueEvent(new ToggleEvent(this, ((AjaxBehaviorEvent) event).getBehavior(), visibility, index)); + UIColumn column = ((DataTable) getDataSourceComponent()).getColumns().get(index); + super.queueEvent(new ColumnToggleEvent(this, ((AjaxBehaviorEvent) event).getBehavior(), column, visibility, index)); } else if (event instanceof AjaxBehaviorEvent && "close".equals(eventName)) { String clientId = this.getClientId(context); diff --git a/primefaces/src/main/java/org/primefaces/component/inputswitch/InputSwitchRenderer.java b/primefaces/src/main/java/org/primefaces/component/inputswitch/InputSwitchRenderer.java index 4dc2ca4193..2d76d3977b 100644 --- a/primefaces/src/main/java/org/primefaces/component/inputswitch/InputSwitchRenderer.java +++ b/primefaces/src/main/java/org/primefaces/component/inputswitch/InputSwitchRenderer.java @@ -102,7 +102,9 @@ protected void encodeOption(FacesContext context, String label, String styleClas writer.startElement("span", null); if (showLabels) { - writer.writeText(label, null); + if (label != null) { + writer.writeText(label, null); + } } else { writer.write(" "); diff --git a/primefaces/src/main/java/org/primefaces/event/ColumnToggleEvent.java b/primefaces/src/main/java/org/primefaces/event/ColumnToggleEvent.java new file mode 100644 index 0000000000..d024d33f5e --- /dev/null +++ b/primefaces/src/main/java/org/primefaces/event/ColumnToggleEvent.java @@ -0,0 +1,45 @@ +/* + * The MIT License + * + * Copyright (c) 2009-2024 PrimeTek Informatics + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.primefaces.event; + +import javax.faces.component.UIComponent; +import javax.faces.component.behavior.Behavior; +import org.primefaces.component.api.UIColumn; +import org.primefaces.model.Visibility; + +public class ColumnToggleEvent extends ToggleEvent { + + private static final long serialVersionUID = 1L; + + private transient UIColumn column; + + public ColumnToggleEvent(UIComponent component, Behavior behavior, UIColumn column, Visibility visibility, Object data) { + super(component, behavior, visibility, data); + this.column = column; + } + + public UIColumn getColumn() { + return column; + } +} diff --git a/primefaces/src/main/resources/META-INF/primefaces-p.taglib.xml b/primefaces/src/main/resources/META-INF/primefaces-p.taglib.xml index 0b517ab831..ec165b2be3 100644 --- a/primefaces/src/main/resources/META-INF/primefaces-p.taglib.xml +++ b/primefaces/src/main/resources/META-INF/primefaces-p.taglib.xml @@ -533,6 +533,14 @@ false java.lang.Boolean + + + + + beforeShow + false + java.lang.String + @@ -23608,6 +23616,19 @@ false java.lang.Boolean + + + java.util.Collection, or an EL expression that + evaluates to either 1. such a String, or 2. the + Class object itself.]]> + + collectionType + false + java.lang.String + diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/confirmpopup/confirmpopup.js b/primefaces/src/main/resources/META-INF/resources/primefaces/confirmpopup/confirmpopup.js index 28b18d22bf..acf313b9b9 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/confirmpopup/confirmpopup.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/confirmpopup/confirmpopup.js @@ -76,8 +76,23 @@ PrimeFaces.widget.ConfirmPopup = PrimeFaces.widget.DynamicOverlayWidget.extend({ if (el.hasClass('ui-confirm-popup-yes') && PrimeFaces.confirmPopupSource) { var id = PrimeFaces.confirmPopupSource.get(0); var js = PrimeFaces.confirmPopupSource.data('pfconfirmcommand'); - - PrimeFaces.csp.executeEvent(id, js, e); + var command = $(id); + + // Test if the function matches the pattern + if (PrimeFaces.ajax.Utils.isAjaxRequest(js) || command.is('a')) { + // command is ajax=true + PrimeFaces.csp.executeEvent(id, js, e); + } + else { + // command is ajax=false + if (command.prop('onclick')) { + command.removeAttr("onclick"); + } + else { + command.off("click"); + } + command.removeAttr("data-pfconfirmcommand").click(); + } PrimeFaces.confirmPopup.hide(); PrimeFaces.confirmPopupSource = null; diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.csp.js b/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.csp.js index 3232032263..416802d625 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.csp.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/core/core.csp.js @@ -101,10 +101,7 @@ if (!PrimeFaces.csp) { PrimeFaces.csp.EVENT_REGISTRY.set(id, new Map()); } var script = js.toString(); - var isAjaxified = (script.indexOf("PrimeFaces.ab(") >= 0) || - (script.indexOf("pf.ab(") >= 0) || - (script.indexOf("mojarra.ab(") >= 0) || - (script.indexOf("jsf.ajax.request") >= 0); + var isAjaxified = PrimeFaces.ajax.Utils.isAjaxRequest(script); PrimeFaces.csp.EVENT_REGISTRY.get(id).set(jqEvent, isAjaxified); } } diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/0-datepicker.js b/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/0-datepicker.js index 4ca957e695..c179a88e8a 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/0-datepicker.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/0-datepicker.js @@ -1427,16 +1427,21 @@ renderTitleYearElement: function(year, index) { if (this.options.yearNavigator && index === 0) { this.updateYearNavigator(); - var yearOptions = [], - years = this.options.yearRange.split(':'), + var years = this.options.yearRange.split(':'), yearStart = parseInt(years[0], 10), - yearEnd = parseInt(years[1], 10); - - for (var i = yearStart; i <= yearEnd; i++) { - yearOptions.push(i); + yearEnd = parseInt(years[1], 10), + minDate = this.options.minDate, + maxDate = this.options.maxDate, + minYear = yearStart, + maxYear = yearEnd; + if (minDate) { + minYear = Math.max(minDate.getFullYear(), yearStart); + } + if (maxDate) { + maxYear = Math.min(maxDate.getFullYear(), yearEnd); } - return ''; + return ''; } else { return '' + year + ''; @@ -1833,7 +1838,9 @@ var monthNavigatorSelector = '.ui-datepicker-header > .ui-datepicker-title > .ui-datepicker-month', yearNavigatorSelector = '.ui-datepicker-header > .ui-datepicker-title > .ui-datepicker-year'; this.panel.off('change.datePicker-monthNav', monthNavigatorSelector).on('change.datePicker-monthNav', monthNavigatorSelector, null, this.onMonthDropdownChange.bind($this)); - this.panel.off('change.datePicker-yearNav', yearNavigatorSelector).on('change.datePicker-yearNav', yearNavigatorSelector, null, this.onYearDropdownChange.bind($this)); + this.panel.off('change.datePicker-yearnav keydown.datePicker-yearnav', yearNavigatorSelector) + .on('change.datePicker-yearnav', yearNavigatorSelector, null, this.onYearInputChange.bind($this)) + .on('keydown.datePicker-yearnav', yearNavigatorSelector, null, function(event) {$this.onTimeInputKeyDown(event);}); var monthViewMonthSelector = '.ui-monthpicker > .ui-monthpicker-month'; this.panel.off('click.datePicker-monthViewMonth', monthViewMonthSelector).on('click.datePicker-monthViewMonth', monthViewMonthSelector, null, function(e) { @@ -2108,11 +2115,21 @@ if (input.value.length >= input.maxLength) { event.preventDefault(); event.stopPropagation(); + return; } + var val = input.value + event.key; + + // for year we only want to evaluate the full number + if (input.maxLength === 4 && val.length != 4) { + return; + } + + // evaluate if its within min and max range + val = parseInt(val, 10); + var inputMin = parseInt(input.min, 10); + var inputMax = parseInt(input.max, 10); - const val = input.value + event.key; - - if (val < parseInt(input.min, 10) || val > parseInt(input.max, 10)) { + if (val < inputMin || val > inputMax) { event.preventDefault(); event.stopPropagation(); } @@ -2180,7 +2197,6 @@ }, onInputChange: function(event) { - // TODO: The following code block will be rearranged according to PrimeNG/React/Vue library in future versions. if ((this.options.autoMonthFormat || !this.inputfield.val() || this.options.showMinMaxRange) && this.options.monthNavigator && this.options.view !== 'month') { var viewMonth = this.viewDate.getMonth(); viewMonth = (this.isInMaxYear() && Math.min(this.options.maxDate.getMonth(), viewMonth)) || (this.isInMinYear() && Math.max(this.options.minDate.getMonth(), viewMonth)) || viewMonth; @@ -2265,7 +2281,7 @@ this.updateViewDate(event, newViewDate); }, - onYearDropdownChange: function(event) { + onYearInputChange: function(event) { var newViewDate = new Date(this.viewDate.getTime()); newViewDate.setFullYear(parseInt(event.target.value, 10)); @@ -3221,7 +3237,7 @@ }, updateYearNavigator: function() { - if (this.hasCustomYearRange) { + if (this.hasCustomYearRange || this.options.yearRange) { return; } if (this.options.yearNavigator) { diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/datepicker.css b/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/datepicker.css index 79f949391b..00566ee593 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/datepicker.css +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/datepicker/datepicker.css @@ -63,7 +63,13 @@ .p-datepicker-panel .ui-timepicker.ui-timepicker-timeinput input { text-align: center; - -moz-appearance: textfield !important; + -moz-appearance: textfield; +} + +.p-datepicker-panel .ui-timepicker.ui-timepicker-timeinput input::-webkit-outer-spin-button, +.p-datepicker-panel .ui-timepicker.ui-timepicker-timeinput input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; } .p-datepicker-panel .ui-timepicker.ui-timepicker-timeinput .ui-millisecond-picker input { diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/dialog/dialog.js b/primefaces/src/main/resources/META-INF/resources/primefaces/dialog/dialog.js index 39e5a73173..34a7617831 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/dialog/dialog.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/dialog/dialog.js @@ -939,15 +939,22 @@ PrimeFaces.widget.ConfirmDialog = PrimeFaces.widget.Dialog.extend({ if(el.hasClass('ui-confirmdialog-yes') && PrimeFaces.confirmSource) { var id = PrimeFaces.confirmSource.get(0); var js = PrimeFaces.confirmSource.data('pfconfirmcommand'); + var command = $(id); // Test if the function matches the pattern - if (PrimeFaces.ajax.Utils.isAjaxRequest(js)) { + if (PrimeFaces.ajax.Utils.isAjaxRequest(js) || command.is('a')) { // command is ajax=true PrimeFaces.csp.executeEvent(id, js, e); } else { // command is ajax=false - $(id).removeAttr("data-pfconfirmcommand").removeAttr("onclick").click(); + if (command.prop('onclick')) { + command.removeAttr("onclick"); + } + else { + command.off("click"); + } + command.removeAttr("data-pfconfirmcommand").click(); } PrimeFaces.confirmDialog.hide(); diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/growl/growl.js b/primefaces/src/main/resources/META-INF/resources/primefaces/growl/growl.js index 7ac96c50de..13507aecf7 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/growl/growl.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/growl/growl.js @@ -27,7 +27,9 @@ PrimeFaces.widget.Growl = PrimeFaces.widget.BaseWidget.extend({ this._super(cfg); //create container - this.jq = $('
'); + var styleClass = "ui-growl ui-widget"; + styleClass = this.cfg.sticky ? styleClass + " ui-growl-sticky" : styleClass; + this.jq = $('
'); this.jq.appendTo($(document.body)); //render messages @@ -40,7 +42,7 @@ PrimeFaces.widget.Growl = PrimeFaces.widget.BaseWidget.extend({ * @param {PrimeFaces.PartialWidgetCfg} cfg */ refresh: function(cfg) { - this.cfg = cfg; + this.cfg = cfg; this.show(cfg.msgs); this.removeScriptElement(this.id); @@ -77,7 +79,7 @@ PrimeFaces.widget.Growl = PrimeFaces.widget.BaseWidget.extend({ this.jq.css('z-index', PrimeFaces.nextZindex()); - if(!this.cfg.keepAlive) { + if (!this.cfg.keepAlive) { //clear previous messages this.removeAll(); } @@ -105,17 +107,17 @@ PrimeFaces.widget.Growl = PrimeFaces.widget.BaseWidget.extend({ markup += ''; markup += ''; // GitHub #5153 for screen readers - markup += '' + PrimeFaces.getAriaLabel('messages.'+msg.severity.toUpperCase()) + ''; + markup += '' + PrimeFaces.getAriaLabel('messages.' + msg.severity.toUpperCase()) + ''; markup += '
'; markup += ''; markup += '

'; markup += '
'; var message = $(markup), - summaryEL = message.find('span.ui-growl-title'), - detailEL = summaryEL.next(); + summaryEL = message.find('span.ui-growl-title'), + detailEL = summaryEL.next(); - if(this.cfg.escape) { + if (this.cfg.escape) { summaryEL.text(msg.summary); detailEL.text(msg.detail); } @@ -136,30 +138,30 @@ PrimeFaces.widget.Growl = PrimeFaces.widget.BaseWidget.extend({ */ bindEvents: function(message) { var $this = this, - sticky = this.cfg.sticky; + sticky = this.cfg.sticky; message.on("mouseover", function() { var msg = $(this); //visuals - if(!msg.is(':animated')) { + if (!msg.is(':animated')) { msg.find('div.ui-growl-icon-close:first').show(); } // clear hide timeout on mouseover - if(!sticky) { + if (!sticky) { clearTimeout(msg.data('timeout')); } }) - .on("mouseout", function() { - //visuals - $(this).find('div.ui-growl-icon-close:first').hide(); - - // setup hide timeout again after mouseout - if(!sticky) { - $this.setRemovalTimeout(message); - } - }); + .on("mouseout", function() { + //visuals + $(this).find('div.ui-growl-icon-close:first').hide(); + + // setup hide timeout again after mouseout + if (!sticky) { + $this.setRemovalTimeout(message); + } + }); //remove message on click of close icon var closeIcon = message.find('div.ui-growl-icon-close'); @@ -174,7 +176,7 @@ PrimeFaces.widget.Growl = PrimeFaces.widget.BaseWidget.extend({ }); //hide the message after given time if not sticky - if(!sticky) { + if (!sticky) { this.setRemovalTimeout(message); } }, diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/jquery/jquery.ui.pfextensions.js b/primefaces/src/main/resources/META-INF/resources/primefaces/jquery/jquery.ui.pfextensions.js index 7851f1be35..de51521217 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/jquery/jquery.ui.pfextensions.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/jquery/jquery.ui.pfextensions.js @@ -115,7 +115,11 @@ $.widget( "ui.sortable", $.ui.sortable, { var ev = new $.Event('remove'), orig = $.fn.remove; $.fn.remove = function() { - $(this).trigger(ev); + // Don't change JQuery.remove(selector) behavior, so trigger event only when remove is called without arguments. + if (!arguments || arguments.length === 0) { + $(this).trigger(ev); + } + return orig.apply(this, arguments); } })(); diff --git a/primefaces/src/main/resources/META-INF/resources/primefaces/tree/tree.vertical.js b/primefaces/src/main/resources/META-INF/resources/primefaces/tree/tree.vertical.js index 707148f438..37737fd856 100644 --- a/primefaces/src/main/resources/META-INF/resources/primefaces/tree/tree.vertical.js +++ b/primefaces/src/main/resources/META-INF/resources/primefaces/tree/tree.vertical.js @@ -655,7 +655,7 @@ PrimeFaces.widget.VerticalTree = PrimeFaces.widget.BaseTree.extend({ source = PF($(element.data('dragsourceid')).data('widget')), height = 20; - if(source.cfg.multipleDrag && element.find('.ui-treenode-content').hasClass('ui-state-highlight')) { + if(source.cfg.multipleDrag && element.hasClass('ui-treenode-content') && element.hasClass('ui-state-highlight')) { source.draggedSourceKeys = $this.findSelectedParentKeys(source.selections.slice()); height = 20 * (source.draggedSourceKeys.length || 1); } @@ -728,7 +728,7 @@ PrimeFaces.widget.VerticalTree = PrimeFaces.widget.BaseTree.extend({ dragNodeKey = $this.getRowKey(targetDragNode); - if(!transfer && dropNodeKey && dropNodeKey.indexOf(dragNodeKey) === 0) { + if(!transfer && dropNodeKey && dropNodeKey.indexOf('_' + dragNodeKey) === 0) { return; } @@ -892,7 +892,7 @@ PrimeFaces.widget.VerticalTree = PrimeFaces.widget.BaseTree.extend({ dragNodeKey = $this.getRowKey(targetDragNode); - if(!transfer && dropNodeKey && dropNodeKey.indexOf(dragNodeKey) === 0) { + if(!transfer && dropNodeKey && dropNodeKey.indexOf('_' + dragNodeKey) === 0) { return; } @@ -1015,7 +1015,7 @@ PrimeFaces.widget.VerticalTree = PrimeFaces.widget.BaseTree.extend({ var key = arr[i]; for(var j = 0; j < arr.length && key !== -1; j++) { var tempKey = arr[j]; - if(tempKey !== -1 && key.length > tempKey.length && key.indexOf(tempKey) === 0) { + if(tempKey !== -1 && key.length > tempKey.length && key.indexOf('_' + tempKey) === 0) { arr[i] = -1; } }