@oat-sa/tao-core-ui 1.64.1 → 1.64.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +339 -339
- package/README.md +22 -22
- package/dist/actionbar.js +92 -92
- package/dist/adder.js +109 -109
- package/dist/animable/absorbable/absorbable.js +29 -29
- package/dist/animable/absorbable/css/absorb.css +7 -7
- package/dist/animable/absorbable/css/absorb.css.map +1 -1
- package/dist/animable/pulsable/css/pulse.css +7 -7
- package/dist/animable/pulsable/css/pulse.css.map +1 -1
- package/dist/animable/pulsable/pulsable.js +23 -23
- package/dist/areaBroker.js +51 -51
- package/dist/autocomplete/css/autocomplete.css +7 -7
- package/dist/autocomplete/css/autocomplete.css.map +1 -1
- package/dist/autocomplete.js +384 -384
- package/dist/autoscroll.js +22 -22
- package/dist/badge/badge.js +35 -35
- package/dist/badge/css/badge.css +7 -7
- package/dist/badge/css/badge.css.map +1 -1
- package/dist/breadcrumbs/css/breadcrumbs.css +7 -7
- package/dist/breadcrumbs/css/breadcrumbs.css.map +1 -1
- package/dist/breadcrumbs.js +57 -57
- package/dist/btngrouper.js +64 -64
- package/dist/bulkActionPopup/css/bulkActionPopup.css +7 -7
- package/dist/bulkActionPopup/css/bulkActionPopup.css.map +1 -1
- package/dist/bulkActionPopup.js +91 -91
- package/dist/button.js +89 -89
- package/dist/calculator/css/calculator.css +10 -10
- package/dist/calculator/css/calculator.css.map +1 -1
- package/dist/calculator.js +51 -51
- package/dist/cascadingComboBox.js +34 -34
- package/dist/ckeditor/ckConfigurator.js +49 -49
- package/dist/ckeditor/dtdHandler.js +110 -110
- package/dist/class/css/selector.css +7 -7
- package/dist/class/css/selector.css.map +1 -1
- package/dist/class/selector.js +98 -98
- package/dist/component/alignable.js +81 -81
- package/dist/component/containable.js +37 -37
- package/dist/component/css/components.css +7 -7
- package/dist/component/css/components.css.map +1 -1
- package/dist/component/css/windowComponent.css +7 -7
- package/dist/component/css/windowComponent.css.map +1 -1
- package/dist/component/draggable.js +25 -25
- package/dist/component/placeable.js +70 -70
- package/dist/component/resizable.js +61 -61
- package/dist/component/stackable.js +20 -20
- package/dist/component/windowed.js +46 -46
- package/dist/component.js +140 -140
- package/dist/container.js +76 -76
- package/dist/contextualPopup/css/contextualPopup.css +7 -7
- package/dist/contextualPopup/css/contextualPopup.css.map +1 -1
- package/dist/contextualPopup.js +100 -100
- package/dist/dashboard/css/dashboard.css +7 -7
- package/dist/dashboard/css/dashboard.css.map +1 -1
- package/dist/dashboard.js +62 -62
- package/dist/datalist/css/datalist.css +7 -7
- package/dist/datalist/css/datalist.css.map +1 -1
- package/dist/datalist.js +147 -147
- package/dist/datatable/css/datatable.css +7 -7
- package/dist/datatable/css/datatable.css.map +1 -1
- package/dist/datatable/filterStrategy/filterStrategy.js +27 -27
- package/dist/datatable/filterStrategy/multiple.js +25 -25
- package/dist/datatable/filterStrategy/single.js +25 -25
- package/dist/datatable.js +377 -377
- package/dist/dateRange/css/dateRange.css +7 -7
- package/dist/dateRange/css/dateRange.css.map +1 -1
- package/dist/dateRange/dateRange.js +97 -97
- package/dist/datetime/css/picker.css +7 -7
- package/dist/datetime/css/picker.css.map +1 -1
- package/dist/datetime/picker.js +161 -161
- package/dist/deleter.js +79 -79
- package/dist/destination/css/selector.css +7 -7
- package/dist/destination/css/selector.css.map +1 -1
- package/dist/destination/selector.js +52 -52
- package/dist/dialog/alert.js +26 -26
- package/dist/dialog/confirm.js +27 -27
- package/dist/dialog/confirmDelete.js +31 -31
- package/dist/dialog.js +141 -141
- package/dist/disabler.js +90 -90
- package/dist/documentViewer/css/documentViewer.css +7 -7
- package/dist/documentViewer/css/documentViewer.css.map +1 -1
- package/dist/documentViewer/providers/pdfViewer/fallback/viewer.js +30 -30
- package/dist/documentViewer/providers/pdfViewer/pdfjs/areaBroker.js +25 -25
- package/dist/documentViewer/providers/pdfViewer/pdfjs/findBar.js +120 -120
- package/dist/documentViewer/providers/pdfViewer/pdfjs/pageView.js +89 -89
- package/dist/documentViewer/providers/pdfViewer/pdfjs/pagesManager.js +52 -52
- package/dist/documentViewer/providers/pdfViewer/pdfjs/searchEngine.js +112 -112
- package/dist/documentViewer/providers/pdfViewer/pdfjs/textManager.js +67 -67
- package/dist/documentViewer/providers/pdfViewer/pdfjs/viewer.js +81 -81
- package/dist/documentViewer/providers/pdfViewer/pdfjs/wrapper.js +111 -111
- package/dist/documentViewer/providers/pdfViewer.js +29 -29
- package/dist/documentViewer/viewerFactory.js +71 -71
- package/dist/documentViewer.js +86 -86
- package/dist/dropdown/css/dropdown.css +7 -7
- package/dist/dropdown/css/dropdown.css.map +1 -1
- package/dist/dropdown.js +84 -84
- package/dist/durationer.js +58 -58
- package/dist/dynamicComponent/css/dynamicComponent.css +7 -7
- package/dist/dynamicComponent/css/dynamicComponent.css.map +1 -1
- package/dist/dynamicComponent.js +103 -103
- package/dist/feedback.js +84 -84
- package/dist/figure/FigureStateActive.js +111 -111
- package/dist/filesender.js +26 -26
- package/dist/filter.js +34 -34
- package/dist/form/css/dropdownForm.css +7 -7
- package/dist/form/css/dropdownForm.css.map +1 -1
- package/dist/form/css/form.css +7 -7
- package/dist/form/css/form.css.map +1 -1
- package/dist/form/dropdownForm.js +99 -99
- package/dist/form/form.js +248 -248
- package/dist/form/simpleForm.js +71 -71
- package/dist/form/validator/css/validator.css +7 -7
- package/dist/form/validator/css/validator.css.map +1 -1
- package/dist/form/validator/renderer.js +52 -52
- package/dist/form/validator/validator.js +103 -103
- package/dist/form/widget/css/widget.css +7 -7
- package/dist/form/widget/css/widget.css.map +1 -1
- package/dist/form/widget/definitions.js +24 -24
- package/dist/form/widget/loader.js +16 -16
- package/dist/form/widget/providers/checkBox.js +62 -62
- package/dist/form/widget/providers/comboBox.js +46 -46
- package/dist/form/widget/providers/default.js +35 -35
- package/dist/form/widget/providers/hidden.js +37 -37
- package/dist/form/widget/providers/hiddenBox.js +58 -58
- package/dist/form/widget/providers/radioBox.js +57 -57
- package/dist/form/widget/providers/textArea.js +35 -35
- package/dist/form/widget/providers/textBox.js +34 -34
- package/dist/form/widget/widget.js +141 -141
- package/dist/form.js +10 -10
- package/dist/formValidator/formValidator.js +61 -61
- package/dist/formValidator/highlighters/highlighter.js +41 -41
- package/dist/formValidator/highlighters/message.js +29 -29
- package/dist/formValidator/highlighters/tooltip.js +32 -32
- package/dist/generis/form/css/form.css +7 -7
- package/dist/generis/form/css/form.css.map +1 -1
- package/dist/generis/form/form.js +73 -73
- package/dist/generis/validator/css/validator.css +7 -7
- package/dist/generis/validator/css/validator.css.map +1 -1
- package/dist/generis/validator/validator.js +38 -38
- package/dist/generis/widget/checkBox/checkBox.js +39 -39
- package/dist/generis/widget/comboBox/comboBox.js +32 -32
- package/dist/generis/widget/css/widget.css +7 -7
- package/dist/generis/widget/css/widget.css.map +1 -1
- package/dist/generis/widget/hiddenBox/hiddenBox.js +40 -40
- package/dist/generis/widget/loader.js +20 -20
- package/dist/generis/widget/textBox/textBox.js +27 -27
- package/dist/generis/widget/widget.js +47 -47
- package/dist/groupedComboBox.js +36 -36
- package/dist/groupvalidator.js +19 -19
- package/dist/hider.js +41 -41
- package/dist/highlighter.js +278 -278
- package/dist/image/ImgStateActive/extractLabel.js +20 -20
- package/dist/image/ImgStateActive/helper.js +16 -16
- package/dist/image/ImgStateActive/initHelper.js +85 -85
- package/dist/image/ImgStateActive/initMediaEditor.js +48 -48
- package/dist/image/ImgStateActive/mediaSizer.js +32 -32
- package/dist/image/ImgStateActive.js +104 -104
- package/dist/incrementer.js +58 -58
- package/dist/inplacer.js +87 -87
- package/dist/interactUtils.js +42 -42
- package/dist/itemButtonList/css/item-button-list.css +23 -23
- package/dist/itemButtonList/css/item-button-list.css.map +1 -1
- package/dist/itemButtonList.js +102 -102
- package/dist/keyNavigation/navigableDomElement.js +76 -76
- package/dist/keyNavigation/navigator.js +158 -158
- package/dist/listbox/css/listbox.css +7 -7
- package/dist/listbox/css/listbox.css.map +1 -1
- package/dist/listbox.js +84 -84
- package/dist/liststyler.js +57 -57
- package/dist/loadingButton/css/button.css +7 -7
- package/dist/loadingButton/css/button.css.map +1 -1
- package/dist/loadingButton/loadingButton.js +35 -35
- package/dist/lock.js +112 -112
- package/dist/login/login.js +87 -87
- package/dist/maths/calculator/basicCalculator.js +50 -50
- package/dist/maths/calculator/calculatorComponent.js +29 -29
- package/dist/maths/calculator/core/areaBroker.js +25 -25
- package/dist/maths/calculator/core/board.js +300 -300
- package/dist/maths/calculator/core/expression.js +98 -98
- package/dist/maths/calculator/core/labels.js +16 -16
- package/dist/maths/calculator/core/plugin.js +19 -19
- package/dist/maths/calculator/core/terms.js +26 -26
- package/dist/maths/calculator/core/tokenizer.js +98 -98
- package/dist/maths/calculator/core/tokens.js +75 -75
- package/dist/maths/calculator/css/calculator.css +7 -7
- package/dist/maths/calculator/css/calculator.css.map +1 -1
- package/dist/maths/calculator/defaultCalculator.js +23 -23
- package/dist/maths/calculator/plugins/core/degrad.js +22 -22
- package/dist/maths/calculator/plugins/core/history.js +45 -45
- package/dist/maths/calculator/plugins/core/remind.js +22 -22
- package/dist/maths/calculator/plugins/core/stepNavigation.js +31 -31
- package/dist/maths/calculator/plugins/keyboard/templateKeyboard/templateKeyboard.js +48 -48
- package/dist/maths/calculator/plugins/modifiers/pow10.js +35 -35
- package/dist/maths/calculator/plugins/modifiers/sign.js +90 -90
- package/dist/maths/calculator/plugins/screen/simpleScreen/simpleScreen.js +47 -47
- package/dist/maths/calculator/pluginsLoader.js +21 -21
- package/dist/maths/calculator/scientificCalculator.js +78 -78
- package/dist/mediaEditor/mediaEditorComponent.js +51 -51
- package/dist/mediaEditor/plugins/mediaAlignment/helper.js +16 -16
- package/dist/mediaEditor/plugins/mediaAlignment/mediaAlignmentComponent.js +47 -47
- package/dist/mediaEditor/plugins/mediaAlignment/style.css +7 -7
- package/dist/mediaEditor/plugins/mediaDimension/helper.js +70 -70
- package/dist/mediaEditor/plugins/mediaDimension/mediaDimensionComponent.js +140 -140
- package/dist/mediaEditor/plugins/mediaDimension/style.css +141 -141
- package/dist/mediaplayer/css/player.css +7 -7
- package/dist/mediaplayer/css/player.css.map +1 -1
- package/dist/mediaplayer/players/html5.js +52 -52
- package/dist/mediaplayer/players/youtube.js +39 -39
- package/dist/mediaplayer/players.js +18 -18
- package/dist/mediaplayer/support.js +55 -55
- package/dist/mediaplayer/utils/reminder.js +100 -100
- package/dist/mediaplayer/utils/timeObserver.js +92 -92
- package/dist/mediaplayer/youtubeManager.js +51 -51
- package/dist/mediaplayer.js +447 -447
- package/dist/mediasizer.js +122 -122
- package/dist/modal.js +87 -87
- package/dist/movableComponent.js +35 -35
- package/dist/pageSizeSelector.js +31 -31
- package/dist/pageStatus.js +33 -33
- package/dist/pagination/css/pagination.css +7 -7
- package/dist/pagination/css/pagination.css.map +1 -1
- package/dist/pagination/paginationStrategy.js +23 -23
- package/dist/pagination/providers/pages.js +24 -24
- package/dist/pagination/providers/simple.js +22 -22
- package/dist/pagination.js +45 -45
- package/dist/previewer.js +67 -67
- package/dist/progressbar.js +58 -58
- package/dist/propertySelector/css/propertySelector.css +7 -7
- package/dist/propertySelector/css/propertySelector.css.map +1 -1
- package/dist/propertySelector/propertySelector.js +86 -86
- package/dist/report.js +73 -73
- package/dist/resource/css/selector.css +7 -7
- package/dist/resource/css/selector.css.map +1 -1
- package/dist/resource/filters.js +60 -60
- package/dist/resource/list.js +53 -53
- package/dist/resource/selectable.js +92 -92
- package/dist/resource/selector.js +182 -182
- package/dist/resource/tree.js +91 -91
- package/dist/resourcemgr/css/resourcemgr.css +7 -7
- package/dist/resourcemgr/css/resourcemgr.css.map +1 -1
- package/dist/resourcemgr/fileBrowser.js +75 -75
- package/dist/resourcemgr/fileSelector.js +45 -45
- package/dist/resourcemgr/util/updatePermissions.js +4 -4
- package/dist/resourcemgr.js +49 -49
- package/dist/scroller.js +26 -26
- package/dist/searchModal/advancedSearch.js +155 -155
- package/dist/searchModal/css/advancedSearch.css +7 -7
- package/dist/searchModal/css/advancedSearch.css.map +1 -1
- package/dist/searchModal/css/searchModal.css +7 -7
- package/dist/searchModal/css/searchModal.css.map +1 -1
- package/dist/searchModal.js +134 -134
- package/dist/selecter.js +6 -6
- package/dist/stacker.js +43 -43
- package/dist/switch/css/switch.css +7 -7
- package/dist/switch/css/switch.css.map +1 -1
- package/dist/switch/switch.js +62 -62
- package/dist/tableModel.js +33 -33
- package/dist/tabs/css/tabs.css +12 -12
- package/dist/tabs/css/tabs.css.map +1 -1
- package/dist/tabs.js +220 -220
- package/dist/taskQueue/css/taskQueue.css +7 -7
- package/dist/taskQueue/css/taskQueue.css.map +1 -1
- package/dist/taskQueue/status.js +59 -59
- package/dist/taskQueue/table.js +54 -54
- package/dist/taskQueue/taskQueue.js +18 -18
- package/dist/taskQueue/taskQueueModel.js +102 -102
- package/dist/taskQueue.js +47 -47
- package/dist/taskQueueButton/css/taskable.css +7 -7
- package/dist/taskQueueButton/css/taskable.css.map +1 -1
- package/dist/taskQueueButton/css/treeButton.css +7 -7
- package/dist/taskQueueButton/css/treeButton.css.map +1 -1
- package/dist/taskQueueButton/standardButton.js +39 -39
- package/dist/taskQueueButton/taskable.js +41 -41
- package/dist/taskQueueButton/treeButton.js +43 -43
- package/dist/themeLoader.js +75 -75
- package/dist/themes.js +84 -84
- package/dist/toggler.js +57 -57
- package/dist/tooltip.js +41 -41
- package/dist/tooltipster.js +17 -17
- package/dist/transformer.js +117 -117
- package/dist/tristateCheckboxGroup/css/tristateCheckboxGroup.css +7 -7
- package/dist/tristateCheckboxGroup/css/tristateCheckboxGroup.css.map +1 -1
- package/dist/tristateCheckboxGroup.js +62 -62
- package/dist/uploader.js +145 -145
- package/dist/validator/validators.js +48 -48
- package/dist/validator.js +23 -23
- package/dist/waitForMedia.js +33 -33
- package/dist/waitingDialog/css/waitingDialog.css +7 -7
- package/dist/waitingDialog/css/waitingDialog.css.map +1 -1
- package/dist/waitingDialog/waitingDialog.js +54 -54
- package/package.json +110 -110
- package/scss/basic.scss +16 -16
- package/scss/ckeditor/skins/tao/scss/inc/_ck-icons.scss +60 -60
- package/scss/ckeditor/skins/tao/scss/inc/_tao.scss +59 -59
- package/scss/font/tao/tao.svg +235 -235
- package/scss/inc/_base.scss +495 -495
- package/scss/inc/_bootstrap.scss +6 -6
- package/scss/inc/_buttons.scss +114 -114
- package/scss/inc/_colors.scss +93 -93
- package/scss/inc/_feedback.scss +154 -154
- package/scss/inc/_flex-grid.scss +15 -15
- package/scss/inc/_fonts.scss +4 -4
- package/scss/inc/_forms.scss +832 -832
- package/scss/inc/_functions.scss +283 -283
- package/scss/inc/_jquery.nouislider.scss +254 -254
- package/scss/inc/_normalize.scss +528 -528
- package/scss/inc/_report.scss +67 -67
- package/scss/inc/_secondary-properties.scss +89 -89
- package/scss/inc/_select2.scss +634 -634
- package/scss/inc/_toolbars.scss +155 -155
- package/scss/inc/_tooltip.scss +312 -312
- package/scss/inc/_variables.scss +21 -21
- package/scss/inc/base/_highlight.scss +5 -5
- package/scss/inc/base/_list-style.scss +58 -58
- package/scss/inc/base/_svg.scss +3 -3
- package/scss/inc/base/_table.scss +62 -62
- package/scss/inc/fonts/_source-sans-pro.scss +29 -29
- package/scss/inc/fonts/_tao-icon-classes.scss +227 -227
- package/scss/inc/fonts/_tao-icon-def.scss +12 -12
- package/scss/inc/fonts/_tao-icon-vars.scss +241 -241
- package/src/actionbar/tpl/main.tpl +8 -8
- package/src/actionbar.js +251 -251
- package/src/adder.js +250 -250
- package/src/animable/absorbable/absorbable.js +134 -134
- package/src/animable/absorbable/css/absorb.css +7 -7
- package/src/animable/absorbable/css/absorb.css.map +1 -1
- package/src/animable/absorbable/scss/absorb.scss +37 -37
- package/src/animable/pulsable/css/pulse.css +7 -7
- package/src/animable/pulsable/css/pulse.css.map +1 -1
- package/src/animable/pulsable/pulsable.js +90 -90
- package/src/animable/pulsable/scss/pulse.scss +22 -22
- package/src/areaBroker.js +160 -160
- package/src/autocomplete/css/autocomplete.css +7 -7
- package/src/autocomplete/css/autocomplete.css.map +1 -1
- package/src/autocomplete/scss/autocomplete.scss +37 -37
- package/src/autocomplete.js +1027 -1027
- package/src/autoscroll.js +57 -57
- package/src/badge/badge.js +119 -119
- package/src/badge/css/badge.css +7 -7
- package/src/badge/css/badge.css.map +1 -1
- package/src/badge/scss/badge.scss +92 -92
- package/src/badge/tpl/badge.tpl +4 -4
- package/src/breadcrumbs/css/breadcrumbs.css +7 -7
- package/src/breadcrumbs/css/breadcrumbs.css.map +1 -1
- package/src/breadcrumbs/scss/breadcrumbs.scss +52 -52
- package/src/breadcrumbs/tpl/breadcrumbs.tpl +20 -20
- package/src/breadcrumbs.js +99 -99
- package/src/btngrouper.js +213 -213
- package/src/bulkActionPopup/css/bulkActionPopup.css +7 -7
- package/src/bulkActionPopup/css/bulkActionPopup.css.map +1 -1
- package/src/bulkActionPopup/scss/bulkActionPopup.scss +63 -63
- package/src/bulkActionPopup/tpl/layout.tpl +76 -76
- package/src/bulkActionPopup/tpl/select.tpl +8 -8
- package/src/bulkActionPopup.js +274 -274
- package/src/button/tpl/button.tpl +4 -4
- package/src/button.js +135 -135
- package/src/calculator/css/calculator.css +10 -10
- package/src/calculator/css/calculator.css.map +1 -1
- package/src/calculator/scss/calculator.scss +139 -139
- package/src/calculator.js +188 -188
- package/src/cascadingComboBox.js +126 -126
- package/src/ckeditor/ckConfigurator.js +742 -742
- package/src/ckeditor/dtdHandler.js +1030 -1030
- package/src/class/css/selector.css +7 -7
- package/src/class/css/selector.css.map +1 -1
- package/src/class/scss/selector.scss +101 -101
- package/src/class/selector.js +329 -329
- package/src/class/tpl/listItem.tpl +9 -9
- package/src/class/tpl/selector.tpl +10 -10
- package/src/component/alignable.js +274 -274
- package/src/component/containable.js +122 -122
- package/src/component/css/components.css +7 -7
- package/src/component/css/components.css.map +1 -1
- package/src/component/css/windowComponent.css +7 -7
- package/src/component/css/windowComponent.css.map +1 -1
- package/src/component/draggable.js +104 -104
- package/src/component/placeable.js +233 -233
- package/src/component/resizable.js +195 -195
- package/src/component/scss/components.scss +507 -507
- package/src/component/scss/windowComponent.scss +62 -62
- package/src/component/stackable.js +67 -67
- package/src/component/tpl/window.tpl +7 -7
- package/src/component/windowed.js +206 -206
- package/src/component.js +401 -401
- package/src/container.js +200 -200
- package/src/contextualPopup/css/contextualPopup.css +7 -7
- package/src/contextualPopup/css/contextualPopup.css.map +1 -1
- package/src/contextualPopup/scss/contextualPopup.scss +78 -78
- package/src/contextualPopup/tpl/popup.tpl +10 -10
- package/src/contextualPopup.js +294 -294
- package/src/css/basic.css +104 -104
- package/src/css/basic.css.map +1 -1
- package/src/dashboard/css/dashboard.css +7 -7
- package/src/dashboard/css/dashboard.css.map +1 -1
- package/src/dashboard/scss/dashboard.scss +93 -93
- package/src/dashboard/tpl/dashboard.tpl +16 -16
- package/src/dashboard/tpl/dashboardMetricsList.tpl +15 -15
- package/src/dashboard.js +179 -179
- package/src/datalist/css/datalist.css +7 -7
- package/src/datalist/css/datalist.css.map +1 -1
- package/src/datalist/scss/datalist.scss +116 -116
- package/src/datalist/tpl/list.tpl +24 -24
- package/src/datalist/tpl/main.tpl +44 -44
- package/src/datalist.js +500 -500
- package/src/datatable/css/datatable.css +7 -7
- package/src/datatable/css/datatable.css.map +1 -1
- package/src/datatable/filterStrategy/filterStrategy.js +70 -70
- package/src/datatable/filterStrategy/multiple.js +126 -126
- package/src/datatable/filterStrategy/single.js +108 -108
- package/src/datatable/scss/datatable.scss +149 -149
- package/src/datatable/tpl/button.tpl +6 -6
- package/src/datatable/tpl/layout.tpl +158 -158
- package/src/datatable.js +1056 -1056
- package/src/dateRange/css/dateRange.css +7 -7
- package/src/dateRange/css/dateRange.css.map +1 -1
- package/src/dateRange/dateRange.js +341 -341
- package/src/dateRange/scss/dateRange.scss +7 -7
- package/src/dateRange/tpl/select.tpl +18 -18
- package/src/datetime/css/picker.css +7 -7
- package/src/datetime/css/picker.css.map +1 -1
- package/src/datetime/picker.js +576 -576
- package/src/datetime/scss/picker.scss +192 -192
- package/src/datetime/tpl/picker.tpl +18 -18
- package/src/deleter/undo.tpl +6 -6
- package/src/deleter.js +296 -296
- package/src/destination/css/selector.css +7 -7
- package/src/destination/css/selector.css.map +1 -1
- package/src/destination/scss/selector.scss +36 -36
- package/src/destination/selector.js +195 -195
- package/src/destination/tpl/selector.tpl +13 -13
- package/src/dialog/alert.js +70 -70
- package/src/dialog/confirm.js +85 -85
- package/src/dialog/confirmDelete.js +95 -95
- package/src/dialog/tpl/body.tpl +24 -24
- package/src/dialog/tpl/buttons.tpl +6 -6
- package/src/dialog/tpl/checkbox.tpl +5 -5
- package/src/dialog.js +517 -517
- package/src/disabler.js +230 -230
- package/src/documentViewer/css/documentViewer.css +7 -7
- package/src/documentViewer/css/documentViewer.css.map +1 -1
- package/src/documentViewer/providers/pdfViewer/fallback/viewer.js +69 -69
- package/src/documentViewer/providers/pdfViewer/pdfjs/areaBroker.js +41 -41
- package/src/documentViewer/providers/pdfViewer/pdfjs/findBar.js +475 -475
- package/src/documentViewer/providers/pdfViewer/pdfjs/findBar.tpl +20 -20
- package/src/documentViewer/providers/pdfViewer/pdfjs/match.tpl +1 -1
- package/src/documentViewer/providers/pdfViewer/pdfjs/page.tpl +4 -4
- package/src/documentViewer/providers/pdfViewer/pdfjs/pageView.js +318 -318
- package/src/documentViewer/providers/pdfViewer/pdfjs/pagesManager.js +167 -167
- package/src/documentViewer/providers/pdfViewer/pdfjs/searchEngine.js +451 -451
- package/src/documentViewer/providers/pdfViewer/pdfjs/textManager.js +252 -252
- package/src/documentViewer/providers/pdfViewer/pdfjs/viewer.js +299 -299
- package/src/documentViewer/providers/pdfViewer/pdfjs/viewer.tpl +16 -16
- package/src/documentViewer/providers/pdfViewer/pdfjs/wrapper.js +351 -351
- package/src/documentViewer/providers/pdfViewer.js +93 -93
- package/src/documentViewer/scss/documentViewer.scss +184 -184
- package/src/documentViewer/viewerFactory.js +191 -191
- package/src/documentViewer.js +238 -238
- package/src/dropdown/css/dropdown.css +7 -7
- package/src/dropdown/css/dropdown.css.map +1 -1
- package/src/dropdown/scss/dropdown.scss +99 -99
- package/src/dropdown/tpl/dropdown.tpl +8 -8
- package/src/dropdown/tpl/list-item.tpl +4 -4
- package/src/dropdown.js +255 -255
- package/src/durationer.js +220 -220
- package/src/dynamicComponent/css/dynamicComponent.css +7 -7
- package/src/dynamicComponent/css/dynamicComponent.css.map +1 -1
- package/src/dynamicComponent/scss/dynamicComponent.scss +98 -98
- package/src/dynamicComponent/tpl/layout.tpl +17 -17
- package/src/dynamicComponent.js +553 -553
- package/src/feedback/feedback.tpl +7 -7
- package/src/feedback.js +295 -295
- package/src/figure/FigureStateActive.js +184 -184
- package/src/filesender.js +112 -112
- package/src/filter/template.tpl +5 -5
- package/src/filter.js +129 -129
- package/src/form/css/dropdownForm.css +7 -7
- package/src/form/css/dropdownForm.css.map +1 -1
- package/src/form/css/form.css +7 -7
- package/src/form/css/form.css.map +1 -1
- package/src/form/dropdownForm.js +281 -281
- package/src/form/form.js +688 -688
- package/src/form/scss/dropdownForm.scss +60 -60
- package/src/form/scss/form.scss +25 -25
- package/src/form/simpleForm.js +125 -125
- package/src/form/tpl/dropdownForm.tpl +4 -4
- package/src/form/tpl/form.tpl +7 -7
- package/src/form/validator/css/validator.css +7 -7
- package/src/form/validator/css/validator.css.map +1 -1
- package/src/form/validator/renderer.js +118 -118
- package/src/form/validator/scss/validator.scss +14 -14
- package/src/form/validator/tpl/message.tpl +1 -1
- package/src/form/validator/tpl/validator.tpl +1 -1
- package/src/form/validator/validator.js +220 -220
- package/src/form/widget/css/widget.css +7 -7
- package/src/form/widget/css/widget.css.map +1 -1
- package/src/form/widget/definitions.js +51 -51
- package/src/form/widget/loader.js +40 -40
- package/src/form/widget/providers/checkBox.js +138 -138
- package/src/form/widget/providers/comboBox.js +63 -63
- package/src/form/widget/providers/default.js +90 -90
- package/src/form/widget/providers/hidden.js +62 -62
- package/src/form/widget/providers/hiddenBox.js +152 -152
- package/src/form/widget/providers/radioBox.js +99 -99
- package/src/form/widget/providers/textArea.js +52 -52
- package/src/form/widget/providers/textBox.js +48 -48
- package/src/form/widget/scss/widget.scss +55 -55
- package/src/form/widget/tpl/checkBox.tpl +25 -25
- package/src/form/widget/tpl/comboBox.tpl +13 -13
- package/src/form/widget/tpl/hidden.tpl +1 -1
- package/src/form/widget/tpl/hiddenBox.tpl +17 -17
- package/src/form/widget/tpl/label.tpl +6 -6
- package/src/form/widget/tpl/radioBox.tpl +25 -25
- package/src/form/widget/tpl/textArea.tpl +8 -8
- package/src/form/widget/tpl/widget.tpl +8 -8
- package/src/form/widget/widget.js +372 -372
- package/src/form.js +47 -47
- package/src/formValidator/formValidator.js +253 -253
- package/src/formValidator/highlighters/highlighter.js +103 -103
- package/src/formValidator/highlighters/message.js +68 -68
- package/src/formValidator/highlighters/tooltip.js +78 -78
- package/src/generis/form/css/form.css +7 -7
- package/src/generis/form/css/form.css.map +1 -1
- package/src/generis/form/form.js +239 -239
- package/src/generis/form/readme.md +70 -70
- package/src/generis/form/scss/form.scss +23 -23
- package/src/generis/form/tpl/form.tpl +16 -16
- package/src/generis/validator/css/validator.css +7 -7
- package/src/generis/validator/css/validator.css.map +1 -1
- package/src/generis/validator/readme.md +46 -46
- package/src/generis/validator/scss/validator.scss +13 -13
- package/src/generis/validator/validator.js +128 -128
- package/src/generis/widget/checkBox/checkBox.js +112 -112
- package/src/generis/widget/checkBox/checkBox.tpl +18 -18
- package/src/generis/widget/comboBox/comboBox.js +66 -66
- package/src/generis/widget/comboBox/comboBox.tpl +12 -12
- package/src/generis/widget/css/widget.css +7 -7
- package/src/generis/widget/css/widget.css.map +1 -1
- package/src/generis/widget/hiddenBox/hiddenBox.js +131 -131
- package/src/generis/widget/hiddenBox/hiddenBox.tpl +16 -16
- package/src/generis/widget/loader.js +49 -49
- package/src/generis/widget/readme.md +59 -59
- package/src/generis/widget/scss/widget.scss +61 -61
- package/src/generis/widget/textBox/textBox.js +64 -64
- package/src/generis/widget/textBox/textBox.tpl +7 -7
- package/src/generis/widget/widget.js +164 -164
- package/src/generis/widget/widget.tpl +5 -5
- package/src/groupedComboBox.js +99 -99
- package/src/groupvalidator.js +84 -84
- package/src/hider.js +88 -88
- package/src/highlighter.js +1192 -1192
- package/src/image/ImgStateActive/extractLabel.js +29 -29
- package/src/image/ImgStateActive/helper.js +36 -36
- package/src/image/ImgStateActive/initHelper.js +137 -137
- package/src/image/ImgStateActive/initMediaEditor.js +92 -92
- package/src/image/ImgStateActive/mediaSizer.js +63 -63
- package/src/image/ImgStateActive.js +115 -115
- package/src/incrementer.js +309 -309
- package/src/inplacer.js +315 -315
- package/src/interactUtils.js +140 -140
- package/src/itemButtonList/css/item-button-list.css +23 -23
- package/src/itemButtonList/css/item-button-list.css.map +1 -1
- package/src/itemButtonList/scss/item-button-list.scss +236 -236
- package/src/itemButtonList/tpl/itemButtonList.tpl +21 -21
- package/src/itemButtonList.js +274 -274
- package/src/keyNavigation/navigableDomElement.js +285 -285
- package/src/keyNavigation/navigator.js +535 -535
- package/src/listbox/css/listbox.css +7 -7
- package/src/listbox/css/listbox.css.map +1 -1
- package/src/listbox/scss/listbox.scss +116 -116
- package/src/listbox/tpl/list.tpl +14 -14
- package/src/listbox/tpl/main.tpl +9 -9
- package/src/listbox.js +252 -252
- package/src/liststyler.js +155 -155
- package/src/loadingButton/css/button.css +7 -7
- package/src/loadingButton/css/button.css.map +1 -1
- package/src/loadingButton/loadingButton.js +110 -110
- package/src/loadingButton/scss/button.scss +41 -41
- package/src/loadingButton/tpl/button.tpl +5 -5
- package/src/lock/lock.tpl +16 -16
- package/src/lock.js +393 -393
- package/src/login/login.js +317 -317
- package/src/login/tpl/login.tpl +29 -29
- package/src/login/tpl/passwordReveal.tpl +7 -7
- package/src/maths/calculator/basicCalculator.js +55 -55
- package/src/maths/calculator/calculatorComponent.js +128 -128
- package/src/maths/calculator/core/areaBroker.js +38 -38
- package/src/maths/calculator/core/board.js +841 -841
- package/src/maths/calculator/core/expression.js +430 -430
- package/src/maths/calculator/core/labels.js +116 -116
- package/src/maths/calculator/core/plugin.js +40 -40
- package/src/maths/calculator/core/terms.js +459 -459
- package/src/maths/calculator/core/tokenizer.js +245 -245
- package/src/maths/calculator/core/tokens.js +178 -178
- package/src/maths/calculator/core/tpl/board.tpl +4 -4
- package/src/maths/calculator/css/calculator.css +7 -7
- package/src/maths/calculator/css/calculator.css.map +1 -1
- package/src/maths/calculator/defaultCalculator.js +66 -66
- package/src/maths/calculator/plugins/core/degrad.js +90 -90
- package/src/maths/calculator/plugins/core/history.js +166 -166
- package/src/maths/calculator/plugins/core/remind.js +96 -96
- package/src/maths/calculator/plugins/core/stepNavigation.js +175 -175
- package/src/maths/calculator/plugins/keyboard/templateKeyboard/defaultTemplate.tpl +36 -36
- package/src/maths/calculator/plugins/keyboard/templateKeyboard/templateKeyboard.js +91 -91
- package/src/maths/calculator/plugins/modifiers/pow10.js +143 -143
- package/src/maths/calculator/plugins/modifiers/sign.js +339 -339
- package/src/maths/calculator/plugins/screen/simpleScreen/defaultTemplate.tpl +3 -3
- package/src/maths/calculator/plugins/screen/simpleScreen/history.tpl +3 -3
- package/src/maths/calculator/plugins/screen/simpleScreen/simpleScreen.js +190 -190
- package/src/maths/calculator/pluginsLoader.js +46 -46
- package/src/maths/calculator/scientificCalculator.js +74 -74
- package/src/maths/calculator/scss/calculator.scss +396 -396
- package/src/maths/calculator/tpl/basicKeyboard.tpl +37 -37
- package/src/maths/calculator/tpl/basicScreen.tpl +2 -2
- package/src/maths/calculator/tpl/scientificKeyboard.tpl +61 -61
- package/src/maths/calculator/tpl/scientificScreen.tpl +3 -3
- package/src/mediaEditor/mediaEditorComponent.js +141 -141
- package/src/mediaEditor/plugins/mediaAlignment/helper.js +110 -110
- package/src/mediaEditor/plugins/mediaAlignment/mediaAlignmentComponent.js +99 -99
- package/src/mediaEditor/plugins/mediaAlignment/style.css +7 -7
- package/src/mediaEditor/plugins/mediaAlignment/tpl/mediaAlignment.tpl +25 -25
- package/src/mediaEditor/plugins/mediaDimension/helper.js +190 -190
- package/src/mediaEditor/plugins/mediaDimension/mediaDimensionComponent.js +561 -561
- package/src/mediaEditor/plugins/mediaDimension/style.css +141 -141
- package/src/mediaEditor/plugins/mediaDimension/tpl/mediaDimension.tpl +55 -55
- package/src/mediaEditor/tpl/editor.tpl +4 -4
- package/src/mediaplayer/css/player.css +7 -7
- package/src/mediaplayer/css/player.css.map +1 -1
- package/src/mediaplayer/players/html5.js +564 -564
- package/src/mediaplayer/players/youtube.js +323 -323
- package/src/mediaplayer/players.js +29 -29
- package/src/mediaplayer/readme.md +305 -305
- package/src/mediaplayer/scss/player.scss +569 -569
- package/src/mediaplayer/support.js +126 -126
- package/src/mediaplayer/tpl/audio.tpl +6 -6
- package/src/mediaplayer/tpl/player.tpl +37 -37
- package/src/mediaplayer/tpl/source.tpl +1 -1
- package/src/mediaplayer/tpl/video.tpl +6 -6
- package/src/mediaplayer/tpl/youtube.tpl +1 -1
- package/src/mediaplayer/utils/reminder.js +184 -184
- package/src/mediaplayer/utils/timeObserver.js +143 -143
- package/src/mediaplayer/youtubeManager.js +161 -161
- package/src/mediaplayer.js +1606 -1606
- package/src/mediasizer/mediasizer.tpl +55 -55
- package/src/mediasizer.js +635 -635
- package/src/modal.js +365 -365
- package/src/movableComponent.js +78 -78
- package/src/pageSizeSelector/tpl/pageSizeSelector.tpl +9 -9
- package/src/pageSizeSelector.js +106 -106
- package/src/pageStatus.js +147 -147
- package/src/pagination/css/pagination.css +7 -7
- package/src/pagination/css/pagination.css.map +1 -1
- package/src/pagination/paginationStrategy.js +53 -53
- package/src/pagination/providers/pages.js +161 -161
- package/src/pagination/providers/simple.js +74 -74
- package/src/pagination/providers/tpl/pages/page.tpl +1 -1
- package/src/pagination/providers/tpl/pages.tpl +8 -8
- package/src/pagination/providers/tpl/simple.tpl +7 -7
- package/src/pagination/scss/pagination.scss +111 -111
- package/src/pagination.js +237 -237
- package/src/previewer.js +300 -300
- package/src/progressbar.js +165 -165
- package/src/propertySelector/css/propertySelector.css +7 -7
- package/src/propertySelector/css/propertySelector.css.map +1 -1
- package/src/propertySelector/propertySelector.js +286 -286
- package/src/propertySelector/scss/propertySelector.scss +66 -66
- package/src/propertySelector/tpl/property-description.tpl +12 -12
- package/src/propertySelector/tpl/property-selector.tpl +6 -6
- package/src/report/feedback.tpl +11 -11
- package/src/report/layout.tpl +10 -10
- package/src/report.js +184 -184
- package/src/resource/css/selector.css +7 -7
- package/src/resource/css/selector.css.map +1 -1
- package/src/resource/filters.js +208 -208
- package/src/resource/list.js +200 -200
- package/src/resource/scss/_filters.scss +26 -26
- package/src/resource/scss/_resource-list.scss +107 -107
- package/src/resource/scss/_resource-tree.scss +205 -205
- package/src/resource/scss/selector.scss +187 -187
- package/src/resource/selectable.js +322 -322
- package/src/resource/selector.js +871 -871
- package/src/resource/tpl/filters.tpl +2 -2
- package/src/resource/tpl/list.tpl +7 -7
- package/src/resource/tpl/listNode.tpl +4 -4
- package/src/resource/tpl/selector.tpl +46 -46
- package/src/resource/tpl/tree.tpl +4 -4
- package/src/resource/tpl/treeNode.tpl +30 -30
- package/src/resource/tree.js +398 -398
- package/src/resourcemgr/css/resourcemgr.css +7 -7
- package/src/resourcemgr/css/resourcemgr.css.map +1 -1
- package/src/resourcemgr/fileBrowser.js +381 -381
- package/src/resourcemgr/filePreview.js +73 -73
- package/src/resourcemgr/fileSelector.js +322 -322
- package/src/resourcemgr/scss/resourcemgr.scss +254 -254
- package/src/resourcemgr/tpl/fileSelect.tpl +39 -39
- package/src/resourcemgr/tpl/folder.tpl +11 -11
- package/src/resourcemgr/tpl/layout.tpl +84 -84
- package/src/resourcemgr/tpl/rootFolder.tpl +13 -13
- package/src/resourcemgr/util/updatePermissions.js +53 -53
- package/src/resourcemgr.js +216 -216
- package/src/scroller.js +94 -94
- package/src/scss/basic.scss +16 -16
- package/src/searchModal/advancedSearch.js +638 -638
- package/src/searchModal/css/advancedSearch.css +7 -7
- package/src/searchModal/css/advancedSearch.css.map +1 -1
- package/src/searchModal/css/searchModal.css +7 -7
- package/src/searchModal/css/searchModal.css.map +1 -1
- package/src/searchModal/scss/advancedSearch.scss +171 -171
- package/src/searchModal/scss/searchModal.scss +393 -393
- package/src/searchModal/tpl/advanced-search.tpl +9 -9
- package/src/searchModal/tpl/info-message.tpl +3 -3
- package/src/searchModal/tpl/invalid-criteria-warning.tpl +10 -10
- package/src/searchModal/tpl/layout.tpl +27 -27
- package/src/searchModal/tpl/list-checkbox-criterion.tpl +17 -17
- package/src/searchModal/tpl/list-select-criterion.tpl +12 -12
- package/src/searchModal/tpl/text-criterion.tpl +11 -11
- package/src/searchModal.js +760 -760
- package/src/selecter.js +43 -43
- package/src/stacker.js +133 -133
- package/src/switch/css/switch.css +7 -7
- package/src/switch/css/switch.css.map +1 -1
- package/src/switch/scss/switch.scss +83 -83
- package/src/switch/switch.js +195 -195
- package/src/switch/tpl/switch.tpl +7 -7
- package/src/tableModel.js +112 -112
- package/src/tabs/css/tabs.css +12 -12
- package/src/tabs/css/tabs.css.map +1 -1
- package/src/tabs/scss/tabs.scss +50 -50
- package/src/tabs/tpl/panel.tpl +3 -3
- package/src/tabs/tpl/tabs.tpl +10 -10
- package/src/tabs.js +528 -528
- package/src/taskQueue/css/taskQueue.css +7 -7
- package/src/taskQueue/css/taskQueue.css.map +1 -1
- package/src/taskQueue/scss/taskQueue.scss +47 -47
- package/src/taskQueue/status.js +228 -228
- package/src/taskQueue/table.js +350 -350
- package/src/taskQueue/taskQueue.js +33 -33
- package/src/taskQueue/taskQueueModel.js +548 -548
- package/src/taskQueue/tpl/statusMessage.tpl +7 -7
- package/src/taskQueue.js +216 -216
- package/src/taskQueueButton/css/taskable.css +7 -7
- package/src/taskQueueButton/css/taskable.css.map +1 -1
- package/src/taskQueueButton/css/treeButton.css +7 -7
- package/src/taskQueueButton/css/treeButton.css.map +1 -1
- package/src/taskQueueButton/scss/taskable.scss +4 -4
- package/src/taskQueueButton/scss/treeButton.scss +34 -34
- package/src/taskQueueButton/standardButton.js +108 -108
- package/src/taskQueueButton/taskable.js +202 -202
- package/src/taskQueueButton/tpl/report.tpl +5 -5
- package/src/taskQueueButton/tpl/treeButton.tpl +6 -6
- package/src/taskQueueButton/treeButton.js +108 -108
- package/src/themeLoader.js +252 -252
- package/src/themes.js +162 -162
- package/src/toggler.js +200 -200
- package/src/tooltip/default.tpl +3 -3
- package/src/tooltip.js +160 -160
- package/src/tooltipster.js +25 -25
- package/src/transformer.js +327 -327
- package/src/tristateCheckboxGroup/css/tristateCheckboxGroup.css +7 -7
- package/src/tristateCheckboxGroup/css/tristateCheckboxGroup.css.map +1 -1
- package/src/tristateCheckboxGroup/scss/tristateCheckboxGroup.scss +15 -15
- package/src/tristateCheckboxGroup/tpl/li.tpl +6 -6
- package/src/tristateCheckboxGroup.js +207 -207
- package/src/uploader/fileEntry.tpl +6 -6
- package/src/uploader/uploader.tpl +32 -32
- package/src/uploader.js +594 -594
- package/src/validator/Report.js +10 -10
- package/src/validator/Validator.js +108 -108
- package/src/validator/validators.js +217 -217
- package/src/validator.js +262 -262
- package/src/waitForMedia.js +82 -82
- package/src/waitingDialog/css/waitingDialog.css +7 -7
- package/src/waitingDialog/css/waitingDialog.css.map +1 -1
- package/src/waitingDialog/scss/waitingDialog.scss +34 -34
- package/src/waitingDialog/waitingDialog.js +240 -240
package/src/searchModal.js
CHANGED
|
@@ -1,760 +1,760 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This program is free software; you can redistribute it and/or
|
|
3
|
-
* modify it under the terms of the GNU General Public License
|
|
4
|
-
* as published by the Free Software Foundation; under version 2
|
|
5
|
-
* of the License (non-upgradable).
|
|
6
|
-
*
|
|
7
|
-
* This program is distributed in the hope that it will be useful,
|
|
8
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10
|
-
* GNU General Public License for more details.
|
|
11
|
-
*
|
|
12
|
-
* You should have received a copy of the GNU General Public License
|
|
13
|
-
* along with this program; if not, write to the Free Software
|
|
14
|
-
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
15
|
-
*
|
|
16
|
-
* Copyright (c) 2021 (original work) Open Assessment Technologies SA ;
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import $ from 'jquery';
|
|
20
|
-
import _ from 'lodash';
|
|
21
|
-
import __ from 'i18n';
|
|
22
|
-
import context from 'context';
|
|
23
|
-
import layoutTpl from 'ui/searchModal/tpl/layout';
|
|
24
|
-
import resultsContainerTpl from 'ui/searchModal/tpl/results-container';
|
|
25
|
-
import infoMessageTpl from 'ui/searchModal/tpl/info-message';
|
|
26
|
-
import propertySelectButtonTpl from 'ui/searchModal/tpl/property-select-button';
|
|
27
|
-
import 'ui/searchModal/css/searchModal.css';
|
|
28
|
-
import component from 'ui/component';
|
|
29
|
-
import 'ui/modal';
|
|
30
|
-
import 'ui/datatable';
|
|
31
|
-
import store from 'core/store';
|
|
32
|
-
import resourceSelectorFactory from 'ui/resource/selector';
|
|
33
|
-
import propertySelectorFactory from 'ui/propertySelector/propertySelector';
|
|
34
|
-
import advancedSearchFactory from 'ui/searchModal/advancedSearch';
|
|
35
|
-
import request from 'core/dataProvider/request';
|
|
36
|
-
import urlUtil from 'util/url';
|
|
37
|
-
import 'select2';
|
|
38
|
-
import shortcutRegistry from 'util/shortcut/registry';
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Creates a searchModal instance
|
|
42
|
-
*
|
|
43
|
-
* @param {object} config
|
|
44
|
-
* @param {object} config.renderTo - DOM element where component will be rendered to
|
|
45
|
-
* @param {string} config.criterias - Search criteria to be set on component creation
|
|
46
|
-
* @param {boolean} config.searchOnInit - if init search must be triggered or not (stored results are used instead)
|
|
47
|
-
* @param {string} config.url - search endpoint to be set on datatable
|
|
48
|
-
* @param {string} config.rootClassUri - Uri for the root class of current context, required to init the class filter
|
|
49
|
-
* @param {bool} config.hideResourceSelector - if resourceSelector must be hidden
|
|
50
|
-
* @param {bool} config.hideCriteria - if the criteria must be hidden
|
|
51
|
-
* @param {string} config.placeholder - placeholder for input in template
|
|
52
|
-
* @param {string} config.classesUrl - the URL to the classes API (usually '/tao/RestResource/getAll')
|
|
53
|
-
* @param {string} config.classMappingUrl - the URL to the class mapping API (usually '/tao/ClassMetadata/getWithMapping')
|
|
54
|
-
* @param {string} config.statusUrl - the URL to the status API (usually '/tao/AdvancedSearch/status')
|
|
55
|
-
* @param {string} config.sortby - the default sorted column (usually 'label')
|
|
56
|
-
* @param {string} config.sortorder - the default sort order (usually 'asc')
|
|
57
|
-
* @returns {searchModal}
|
|
58
|
-
*/
|
|
59
|
-
export default function searchModalFactory(config) {
|
|
60
|
-
// @TODO: The consumer must be responsible for supplying the routes. The component must not hardcode endpoints.
|
|
61
|
-
const defaults = {
|
|
62
|
-
classesUrl: urlUtil.route('getAll', 'RestResource', 'tao'),
|
|
63
|
-
classMappingUrl: urlUtil.route('getWithMapping', 'ClassMetadata', 'tao'),
|
|
64
|
-
statusUrl: urlUtil.route('status', 'AdvancedSearch', 'tao'),
|
|
65
|
-
renderTo: 'body',
|
|
66
|
-
criterias: {},
|
|
67
|
-
searchOnInit: true,
|
|
68
|
-
maxListSize: 5,
|
|
69
|
-
sortby: 'label',
|
|
70
|
-
sortorder: 'asc'
|
|
71
|
-
};
|
|
72
|
-
// Private properties to be easily accessible by instance methods
|
|
73
|
-
let $container = null;
|
|
74
|
-
let controls = {};
|
|
75
|
-
let running = false;
|
|
76
|
-
let searchStore = null;
|
|
77
|
-
let selectedColumnsStore = null;
|
|
78
|
-
let resourceSelector = null;
|
|
79
|
-
let advancedSearch = null;
|
|
80
|
-
let propertySelectorInstance;
|
|
81
|
-
let availableColumns = [];
|
|
82
|
-
let availableIdentifiers = {};
|
|
83
|
-
let selectedColumns = [];
|
|
84
|
-
let dataCache;
|
|
85
|
-
|
|
86
|
-
// resorce selector
|
|
87
|
-
const isResourceSelector = !config.hideResourceSelector;
|
|
88
|
-
const rootClassUri = config.rootClassUri;
|
|
89
|
-
|
|
90
|
-
// Creates new component
|
|
91
|
-
const instance = component(
|
|
92
|
-
{
|
|
93
|
-
/**
|
|
94
|
-
* Tells if the advanced search is enabled.
|
|
95
|
-
* @returns {boolean}
|
|
96
|
-
*/
|
|
97
|
-
isAdvancedSearchEnabled() {
|
|
98
|
-
return advancedSearch && advancedSearch.isEnabled();
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
defaults
|
|
102
|
-
)
|
|
103
|
-
.setTemplate(layoutTpl)
|
|
104
|
-
.on('selected-store-updated', recreateDatatable)
|
|
105
|
-
.on('render', renderModal)
|
|
106
|
-
.on('destroy', destroyModal);
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Creates search modal, inits template selectors, inits search store, and once is created triggers initial search
|
|
110
|
-
* rootClassUri is sent to advancedSearch factory for disabling in whitelisted sections
|
|
111
|
-
*/
|
|
112
|
-
function renderModal() {
|
|
113
|
-
const promises = [];
|
|
114
|
-
initModal();
|
|
115
|
-
initUiSelectors();
|
|
116
|
-
advancedSearch = advancedSearchFactory({
|
|
117
|
-
renderTo: controls.$filtersContainer,
|
|
118
|
-
advancedCriteria: instance.config.criterias.advancedCriteria,
|
|
119
|
-
hideCriteria: instance.config.hideCriteria,
|
|
120
|
-
statusUrl: instance.config.statusUrl,
|
|
121
|
-
rootClassUri: rootClassUri
|
|
122
|
-
});
|
|
123
|
-
promises.push(initClassFilter());
|
|
124
|
-
promises.push(initStores());
|
|
125
|
-
Promise.all(promises)
|
|
126
|
-
.then(() => {
|
|
127
|
-
instance.trigger('ready');
|
|
128
|
-
controls.$searchButton.trigger('click');
|
|
129
|
-
})
|
|
130
|
-
.catch(e => instance.trigger('error', e));
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Removes search modal
|
|
135
|
-
*/
|
|
136
|
-
function destroyModal() {
|
|
137
|
-
$container.removeClass('modal').modal('destroy');
|
|
138
|
-
if (propertySelectorInstance) {
|
|
139
|
-
propertySelectorInstance.destroy();
|
|
140
|
-
}
|
|
141
|
-
$('.modal-bg').remove();
|
|
142
|
-
controls = {};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Creates search modal
|
|
147
|
-
*/
|
|
148
|
-
function initModal() {
|
|
149
|
-
$container = instance.getElement();
|
|
150
|
-
$container
|
|
151
|
-
.addClass('modal')
|
|
152
|
-
.on('closed.modal', () => instance.destroy())
|
|
153
|
-
.modal({
|
|
154
|
-
disableEscape: false,
|
|
155
|
-
width: $(window).width(),
|
|
156
|
-
modalCloseClass: 'modal-close-left'
|
|
157
|
-
})
|
|
158
|
-
.focus();
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Inits class filter selector
|
|
163
|
-
*/
|
|
164
|
-
function initClassFilter() {
|
|
165
|
-
return new Promise(resolve => {
|
|
166
|
-
if (!isResourceSelector) {
|
|
167
|
-
controls.$classFilterContainer.hide();
|
|
168
|
-
return resolve();
|
|
169
|
-
}
|
|
170
|
-
const initialClassUri =
|
|
171
|
-
instance.config.criterias && instance.config.criterias.class
|
|
172
|
-
? instance.config.criterias.class
|
|
173
|
-
: rootClassUri;
|
|
174
|
-
resourceSelector = resourceSelectorFactory(controls.$classTreeContainer, {
|
|
175
|
-
//set up the inner resource selector
|
|
176
|
-
selectionMode: 'single',
|
|
177
|
-
selectClass: true,
|
|
178
|
-
classUri: rootClassUri,
|
|
179
|
-
showContext: false,
|
|
180
|
-
showSelection: false
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// when a class query is triggered, update selector options with received resources
|
|
184
|
-
resourceSelector.on('query', params => {
|
|
185
|
-
const classOnlyParams = { ...params, classOnly: true };
|
|
186
|
-
const route = instance.config.classesUrl;
|
|
187
|
-
request(route, classOnlyParams)
|
|
188
|
-
.then(response => {
|
|
189
|
-
if (
|
|
190
|
-
response.permissions &&
|
|
191
|
-
response.permissions.data &&
|
|
192
|
-
response.permissions.supportedRights &&
|
|
193
|
-
response.permissions.supportedRights.length > 0
|
|
194
|
-
) {
|
|
195
|
-
manageClassTreePermissions(response);
|
|
196
|
-
}
|
|
197
|
-
resourceSelector.update(response.resources, classOnlyParams);
|
|
198
|
-
})
|
|
199
|
-
.catch(e => instance.trigger('error', e));
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
/*
|
|
203
|
-
* the first time selector opions are updated the root class is selected. Promise is
|
|
204
|
-
* resolved so init process continues only when class input value has been set
|
|
205
|
-
*/
|
|
206
|
-
resourceSelector.on('update', () => {
|
|
207
|
-
resourceSelector.off('update');
|
|
208
|
-
|
|
209
|
-
resourceSelector.select(initialClassUri);
|
|
210
|
-
resolve();
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// then new class is selected, set its label into class filter input and hide filter container, then request class properties
|
|
214
|
-
resourceSelector.on('change', selectedValue => {
|
|
215
|
-
/*
|
|
216
|
-
* on searchModal init we set manually the selector to the provided config.rootClassUri. When a selector
|
|
217
|
-
* is set manually Selector component execs @clearSelection which triggers a change event
|
|
218
|
-
* with an empty object as param. We catch this undesired behaviour here
|
|
219
|
-
*/
|
|
220
|
-
if (_.isEmpty(selectedValue)) {
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
const classUri = _.map(selectedValue, 'classUri')[0];
|
|
224
|
-
const label = _.map(selectedValue, 'label')[0];
|
|
225
|
-
const uri = _.map(selectedValue, 'uri')[0];
|
|
226
|
-
const route = urlUtil.build(instance.config.classMappingUrl, {
|
|
227
|
-
classUri,
|
|
228
|
-
maxListSize: instance.config.maxListSize
|
|
229
|
-
});
|
|
230
|
-
controls.$classFilterInput.html(label);
|
|
231
|
-
controls.$classFilterInput.data('uri', uri);
|
|
232
|
-
controls.$classTreeContainer.hide();
|
|
233
|
-
advancedSearch
|
|
234
|
-
.updateCriteria(route)
|
|
235
|
-
.then(() => instance.trigger('criteriaListUpdated'))
|
|
236
|
-
.catch(e => instance.trigger('error', e));
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
setResourceSelectorUIBehaviour();
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Loops through each class in received class tree and sets access mode to 'denied' on private classes
|
|
245
|
-
* so are disabled on class tree
|
|
246
|
-
* @param {object} classTree - class tree received by server, containing resources (classes) and permissions
|
|
247
|
-
*/
|
|
248
|
-
function manageClassTreePermissions(classTree) {
|
|
249
|
-
const disableBlockedClasses = function (resources) {
|
|
250
|
-
_.forEach(resources, (resource, index, array) => {
|
|
251
|
-
if (
|
|
252
|
-
classTree.permissions.data[resource.uri] &&
|
|
253
|
-
classTree.permissions.data[resource.uri].find(permission => permission === 'READ')
|
|
254
|
-
) {
|
|
255
|
-
if (resource.children) {
|
|
256
|
-
disableBlockedClasses(resource.children);
|
|
257
|
-
}
|
|
258
|
-
} else {
|
|
259
|
-
array[index].accessMode = 'denied';
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
};
|
|
263
|
-
disableBlockedClasses(classTree.resources);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Inits template selectors, buttons behaviour, scroll animation,
|
|
268
|
-
* and sets initial search query on search input
|
|
269
|
-
*/
|
|
270
|
-
function initUiSelectors() {
|
|
271
|
-
controls = {
|
|
272
|
-
$searchButton: $('.btn-search', $container),
|
|
273
|
-
$clearButton: $('.btn-clear', $container),
|
|
274
|
-
$searchInput: $('.generic-search-input', $container),
|
|
275
|
-
$classFilterInput: $('.class-filter', $container),
|
|
276
|
-
$classTreeContainer: $('.class-tree', $container),
|
|
277
|
-
$classFilterContainer: $('.class-filter-container', $container),
|
|
278
|
-
$filtersContainer: $('.filters-container', $container),
|
|
279
|
-
$contentArea: $('.content-area', $container),
|
|
280
|
-
$contentToolbar: $('.content-toolbar', $container)
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
controls.$searchButton.on('click', search);
|
|
284
|
-
controls.$clearButton.on('click', clear);
|
|
285
|
-
const shortcuts = shortcutRegistry(controls.$searchInput);
|
|
286
|
-
shortcuts.clear().add('enter', search);
|
|
287
|
-
controls.$searchInput.val(
|
|
288
|
-
instance.config.criterias && instance.config.criterias.search ? instance.config.criterias.search : ''
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Sets required listeners to properly manage resourceSelector visualization
|
|
294
|
-
*/
|
|
295
|
-
function setResourceSelectorUIBehaviour() {
|
|
296
|
-
$container.on('mousedown', () => {
|
|
297
|
-
controls.$classTreeContainer.hide();
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Pressing space, enter, esc, backspace
|
|
302
|
-
* on class filter input will toggle resource selector
|
|
303
|
-
*/
|
|
304
|
-
const shortcuts = shortcutRegistry(controls.$classFilterInput);
|
|
305
|
-
shortcuts.add('enter', () => controls.$classTreeContainer.show());
|
|
306
|
-
shortcuts.add('space', () => controls.$classTreeContainer.show());
|
|
307
|
-
shortcuts.add('backspace', () => controls.$classTreeContainer.hide());
|
|
308
|
-
shortcuts.add('escape', () => controls.$classTreeContainer.hide(), { propagate: false });
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* clicking on class filter container will toggle resource selector
|
|
312
|
-
*/
|
|
313
|
-
controls.$classFilterContainer.on('click', () => {
|
|
314
|
-
controls.$classTreeContainer.toggle();
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* clicking on class filter container will
|
|
319
|
-
* stopPropagation to prevent be closed
|
|
320
|
-
* by searchModal.mouseDown listener
|
|
321
|
-
*/
|
|
322
|
-
controls.$classFilterContainer.on('mousedown', e => {
|
|
323
|
-
e.stopPropagation();
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// clicking on resource selector will stopPropagation to prevent be closed by searchModal.mouseDown listener
|
|
327
|
-
controls.$classTreeContainer.on('mousedown', e => {
|
|
328
|
-
e.stopPropagation();
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Loads search store so it is accessible in the component
|
|
334
|
-
* @returns {Promise}
|
|
335
|
-
*/
|
|
336
|
-
function initStores() {
|
|
337
|
-
return Promise.all([
|
|
338
|
-
store('search').then(updatedStore => (searchStore = updatedStore)),
|
|
339
|
-
store('selectedColumns').then(updatedStore => (selectedColumnsStore = updatedStore))
|
|
340
|
-
]).catch(e => instance.trigger('error', e));
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Performs a search query
|
|
345
|
-
* @param query - The searched terms
|
|
346
|
-
* @param classFilterUri - The URI of the node class
|
|
347
|
-
* @param [params] - Additional parameters
|
|
348
|
-
* @returns {Promise}
|
|
349
|
-
*/
|
|
350
|
-
const searchQuery = (query, classFilterUri, params = {}) => {
|
|
351
|
-
return new Promise((resolve, reject) => {
|
|
352
|
-
$.ajax({
|
|
353
|
-
url: instance.config.url,
|
|
354
|
-
type: 'POST',
|
|
355
|
-
data: { ...params, query: query, parentNode: classFilterUri, structure: context.shownStructure },
|
|
356
|
-
dataType: 'json'
|
|
357
|
-
})
|
|
358
|
-
.done(resolve)
|
|
359
|
-
.fail(reject);
|
|
360
|
-
});
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Performs the search query, preventing to send too many requests
|
|
365
|
-
* @param query - The searched terms
|
|
366
|
-
* @param classFilterUri - The URI of the node class
|
|
367
|
-
* @param [params] - Additional parameters
|
|
368
|
-
*/
|
|
369
|
-
const searchHandler = (query, classFilterUri, params = {}) => {
|
|
370
|
-
if (running === false) {
|
|
371
|
-
running = true;
|
|
372
|
-
searchQuery(query, classFilterUri, params)
|
|
373
|
-
.then(data => data.data)
|
|
374
|
-
.then(buildDataModel)
|
|
375
|
-
.then(filterSelectedColumns)
|
|
376
|
-
.then(appendDefaultDatasetToDatatable)
|
|
377
|
-
.then(buildSearchResultsDatatable)
|
|
378
|
-
.catch(e => instance.trigger('error', e))
|
|
379
|
-
.then(() => (running = false));
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Request search results and manages its results
|
|
385
|
-
*/
|
|
386
|
-
function search() {
|
|
387
|
-
searchHandler(buildComplexQuery(), getClassFilterUri());
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Returns selected class filter of rootClassUri
|
|
392
|
-
*/
|
|
393
|
-
function getClassFilterUri() {
|
|
394
|
-
return isResourceSelector ? controls.$classFilterInput.data('uri').trim() : rootClassUri;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* build final complex query appending every filter
|
|
399
|
-
*/
|
|
400
|
-
function buildComplexQuery() {
|
|
401
|
-
let query = controls.$searchInput.val().trim();
|
|
402
|
-
query += advancedSearch.getAdvancedCriteriaQuery(query !== '');
|
|
403
|
-
|
|
404
|
-
return query;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/*
|
|
408
|
-
* If search on init is not required, extends data with stored dataset
|
|
409
|
-
* @param {object} data - search configuration including model and endpoint for datatable
|
|
410
|
-
* @returns {Promise}
|
|
411
|
-
*/
|
|
412
|
-
function appendDefaultDatasetToDatatable(data) {
|
|
413
|
-
return new Promise(function (resolve, reject) {
|
|
414
|
-
// If no search on init, get dataset from searchStore
|
|
415
|
-
if (instance.config.searchOnInit === false) {
|
|
416
|
-
Promise.all([searchStore.getItem('results'), searchStore.getItem('options')])
|
|
417
|
-
.then(fromStore => {
|
|
418
|
-
instance.config.searchOnInit = true;
|
|
419
|
-
data.storedSearchResults = fromStore[0];
|
|
420
|
-
data.storedSearchOptions = fromStore[1];
|
|
421
|
-
resolve(data);
|
|
422
|
-
})
|
|
423
|
-
.catch(e => {
|
|
424
|
-
reject(
|
|
425
|
-
new Error('Error appending default dataset from searchStore to datatable', { cause: e })
|
|
426
|
-
);
|
|
427
|
-
});
|
|
428
|
-
} else {
|
|
429
|
-
resolve(data);
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Replaces empty value by a placeholder.
|
|
436
|
-
* @param value
|
|
437
|
-
* @returns {string|*}
|
|
438
|
-
*/
|
|
439
|
-
const emptyValueTransform = value => {
|
|
440
|
-
let testedValue = value;
|
|
441
|
-
if (Array.isArray(testedValue)) {
|
|
442
|
-
testedValue = testedValue[0];
|
|
443
|
-
}
|
|
444
|
-
if ('string' === typeof testedValue) {
|
|
445
|
-
testedValue = testedValue.trim();
|
|
446
|
-
}
|
|
447
|
-
return testedValue === '' || testedValue === null || typeof testedValue === 'undefined' ? '-' : value;
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* Refines the columns to be compatible with the datatable model
|
|
452
|
-
* @param {object[]} columns
|
|
453
|
-
* @returns {object[]}
|
|
454
|
-
*/
|
|
455
|
-
function columnsToModel(columns) {
|
|
456
|
-
if (!Array.isArray(columns)) {
|
|
457
|
-
return [];
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
return columns.map(column => {
|
|
461
|
-
const { id, sortId, label, sortable, isDuplicated } = column;
|
|
462
|
-
let alias, comment, classLabel;
|
|
463
|
-
if (isDuplicated) {
|
|
464
|
-
alias = column.alias;
|
|
465
|
-
classLabel = column.classLabel; // needed by the property selector
|
|
466
|
-
comment = column.classLabel; // needed by the datatable
|
|
467
|
-
}
|
|
468
|
-
return { id, sortId, label, alias, classLabel, comment, sortable, transform: emptyValueTransform };
|
|
469
|
-
});
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Refines the data model for the datatable
|
|
474
|
-
* @param {object} data - search configuration including model and endpoint for datatable
|
|
475
|
-
* @returns {object} The data configuration refined with the data model for the datatrable
|
|
476
|
-
*/
|
|
477
|
-
function buildDataModel(data) {
|
|
478
|
-
//save availableColumns to memory
|
|
479
|
-
availableIdentifiers = {};
|
|
480
|
-
availableColumns = data.settings.availableColumns;
|
|
481
|
-
|
|
482
|
-
// The support for the old data.model coming from the server has been removed from the commit
|
|
483
|
-
// https://github.com/oat-sa/tao-core-ui-fe/commit/ae6c16a9199f9fc808bc8a37d2ddfce437a62e9c
|
|
484
|
-
// The data model is now coming from the settings carried on by the searchParams request.
|
|
485
|
-
data.model = columnsToModel(availableColumns);
|
|
486
|
-
data.model.forEach(column => (availableIdentifiers[column.id] = true));
|
|
487
|
-
|
|
488
|
-
// adjust the default sorting and pagination
|
|
489
|
-
let { sortby, sortorder, page } = instance.config;
|
|
490
|
-
|
|
491
|
-
if (!sortorder || !['asc', 'desc'].includes(sortorder)) {
|
|
492
|
-
sortorder = 'asc';
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
const sortIdentifiers = [];
|
|
496
|
-
data.model.forEach(column => {
|
|
497
|
-
sortIdentifiers.push(column.sortId || column.id);
|
|
498
|
-
if (column.sortId && column.id === sortby) {
|
|
499
|
-
sortby = column.sortId;
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
|
-
if (!sortIdentifiers.includes(sortby)) {
|
|
503
|
-
// unknown sort identifier is rejected for safety
|
|
504
|
-
sortby = void 0;
|
|
505
|
-
sortorder = void 0;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
data.pageConfig = { sortby, sortorder, page };
|
|
509
|
-
|
|
510
|
-
dataCache = _.cloneDeep(data);
|
|
511
|
-
return data;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/**
|
|
515
|
-
* Filters datatble model based on stored selected columns
|
|
516
|
-
* @param {Object} data data containing available columns and model for datatable
|
|
517
|
-
* @returns {Promise} promise which resolves with filtered data.model
|
|
518
|
-
*/
|
|
519
|
-
function filterSelectedColumns(data) {
|
|
520
|
-
return selectedColumnsStore
|
|
521
|
-
.getItem(rootClassUri)
|
|
522
|
-
.then(storedSelectedColumnIds => {
|
|
523
|
-
selectedColumns = [];
|
|
524
|
-
|
|
525
|
-
if (storedSelectedColumnIds && storedSelectedColumnIds.length) {
|
|
526
|
-
storedSelectedColumnIds.forEach(id => {
|
|
527
|
-
if (availableIdentifiers[id]) {
|
|
528
|
-
selectedColumns.push(id);
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
if (!selectedColumns.length) {
|
|
534
|
-
selectedColumns = data.settings.availableColumns.reduce((acc, column) => {
|
|
535
|
-
if (column.default) {
|
|
536
|
-
acc.push(column.id);
|
|
537
|
-
}
|
|
538
|
-
return acc;
|
|
539
|
-
}, []);
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
data.model = data.model.filter(column => selectedColumns.includes(column.id));
|
|
543
|
-
return data;
|
|
544
|
-
})
|
|
545
|
-
.catch(e => {
|
|
546
|
-
instance.trigger('error', e);
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Creates a datatable with search results
|
|
552
|
-
* @param {object} data - search configuration including model and endpoint for datatable
|
|
553
|
-
*/
|
|
554
|
-
function buildSearchResultsDatatable(data) {
|
|
555
|
-
// Note: the table container needs to be recreated because datatable is storing data in it.
|
|
556
|
-
// Keeping the table container introduces a DOM pollution.
|
|
557
|
-
// It is faster and cleaner to recreate the container than cleaning it explicitly.
|
|
558
|
-
const $tableContainer = $(resultsContainerTpl());
|
|
559
|
-
const $contentContainer = controls.$contentArea.empty();
|
|
560
|
-
$contentContainer.append($tableContainer);
|
|
561
|
-
$tableContainer.on('load.datatable', searchResultsLoaded);
|
|
562
|
-
|
|
563
|
-
const { sortby, sortorder, page } = data.storedSearchOptions || data.pageConfig;
|
|
564
|
-
|
|
565
|
-
//create datatable
|
|
566
|
-
$tableContainer.datatable(
|
|
567
|
-
{
|
|
568
|
-
url: data.url,
|
|
569
|
-
model: data.model,
|
|
570
|
-
sortby,
|
|
571
|
-
sortorder,
|
|
572
|
-
page,
|
|
573
|
-
labels: {
|
|
574
|
-
actions: ''
|
|
575
|
-
},
|
|
576
|
-
actions: [
|
|
577
|
-
{
|
|
578
|
-
id: 'go-to-item',
|
|
579
|
-
label: __('View'),
|
|
580
|
-
action: function openResource(uri, updatedData) {
|
|
581
|
-
instance.trigger('refresh', uri, updatedData);
|
|
582
|
-
instance.destroy();
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
],
|
|
586
|
-
params: {
|
|
587
|
-
params: data.params,
|
|
588
|
-
filters: data.filters,
|
|
589
|
-
rows: 20
|
|
590
|
-
}
|
|
591
|
-
},
|
|
592
|
-
data.storedSearchResults
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
function getTableOptions() {
|
|
597
|
-
const $tableContainer = $('.results-container', $container);
|
|
598
|
-
return _.cloneDeep($tableContainer.data('ui.datatable') || {});
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
/**
|
|
602
|
-
* Filters data from cache by selected and recreates datatable
|
|
603
|
-
* @params {object} options - Additional options to be given to the datatable
|
|
604
|
-
*/
|
|
605
|
-
function recreateDatatable(options = {}) {
|
|
606
|
-
const data = Object.assign(_.cloneDeep(dataCache), options);
|
|
607
|
-
filterSelectedColumns(data).then(buildSearchResultsDatatable);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
/**
|
|
611
|
-
* Triggered on load.datatable event, it updates searchStore and manages possible exceptions
|
|
612
|
-
* @param {object} e - load.datatable event
|
|
613
|
-
* @param {object} dataset - datatable dataset
|
|
614
|
-
*/
|
|
615
|
-
function searchResultsLoaded(e, dataset) {
|
|
616
|
-
const $contentToolbar = controls.$contentToolbar.empty();
|
|
617
|
-
if (instance.isAdvancedSearchEnabled()) {
|
|
618
|
-
const $manageColumnsBtn = $(propertySelectButtonTpl());
|
|
619
|
-
$contentToolbar.append($manageColumnsBtn);
|
|
620
|
-
$manageColumnsBtn.on('click', handleManageColumnsBtnClick);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
const { sortby, sortorder } = getTableOptions();
|
|
624
|
-
|
|
625
|
-
if (dataset.records === 0) {
|
|
626
|
-
replaceSearchResultsDatatableWithMessage('no-matches');
|
|
627
|
-
}
|
|
628
|
-
instance.trigger('datatable-loaded');
|
|
629
|
-
updateSearchStore({
|
|
630
|
-
action: 'update',
|
|
631
|
-
dataset,
|
|
632
|
-
options: { sortby, sortorder },
|
|
633
|
-
context: context.shownStructure,
|
|
634
|
-
criterias: {
|
|
635
|
-
search: controls.$searchInput && controls.$searchInput.val(),
|
|
636
|
-
class: isResourceSelector ? _.map(resourceSelector.getSelection(), 'uri')[0] : rootClassUri,
|
|
637
|
-
advancedCriteria: advancedSearch.getState()
|
|
638
|
-
}
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
/**
|
|
643
|
-
* Handler for manage columns button click
|
|
644
|
-
*/
|
|
645
|
-
function handleManageColumnsBtnClick() {
|
|
646
|
-
const selected = selectedColumns;
|
|
647
|
-
const available = columnsToModel(availableColumns);
|
|
648
|
-
|
|
649
|
-
if (!propertySelectorInstance) {
|
|
650
|
-
const { bottom: btnBottom, right: btnRight } = this.getBoundingClientRect();
|
|
651
|
-
const { top: containerTop, right: containerRight } = $container.get(0).getBoundingClientRect();
|
|
652
|
-
const position = {
|
|
653
|
-
top: btnBottom - containerTop,
|
|
654
|
-
right: containerRight - btnRight
|
|
655
|
-
};
|
|
656
|
-
propertySelectorInstance = propertySelectorFactory({
|
|
657
|
-
renderTo: $container,
|
|
658
|
-
data: {
|
|
659
|
-
position,
|
|
660
|
-
available,
|
|
661
|
-
selected
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
propertySelectorInstance.on('select', selection => {
|
|
665
|
-
if (
|
|
666
|
-
selection.length !== selectedColumns.length ||
|
|
667
|
-
selection.some(columnId => !selectedColumns.includes(columnId))
|
|
668
|
-
) {
|
|
669
|
-
//update table
|
|
670
|
-
selectedColumns = selection;
|
|
671
|
-
const { sortby, sortorder, page } = getTableOptions();
|
|
672
|
-
updateSelectedStore({ selection, sortby, sortorder, page });
|
|
673
|
-
}
|
|
674
|
-
});
|
|
675
|
-
} else {
|
|
676
|
-
propertySelectorInstance.setData({ available, selected });
|
|
677
|
-
propertySelectorInstance.toggle();
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
/**
|
|
682
|
-
* Updates searchStore. If action is 'clear', searchStore is claread. If not, received
|
|
683
|
-
* data is assigned to searchStore. Once all actions have been done,
|
|
684
|
-
* store-updated event is triggered
|
|
685
|
-
* @param {object} data - data to store
|
|
686
|
-
*/
|
|
687
|
-
function updateSearchStore(data) {
|
|
688
|
-
const promises = [];
|
|
689
|
-
if (data.action === 'clear') {
|
|
690
|
-
promises.push(searchStore.clear());
|
|
691
|
-
} else if (data.action === 'update') {
|
|
692
|
-
promises.push(searchStore.setItem('criterias', data.criterias));
|
|
693
|
-
promises.push(searchStore.setItem('context', data.context));
|
|
694
|
-
promises.push(searchStore.setItem('options', data.options));
|
|
695
|
-
promises.push(
|
|
696
|
-
data.dataset.records === 0
|
|
697
|
-
? searchStore.removeItem('results')
|
|
698
|
-
: searchStore.setItem('results', data.dataset)
|
|
699
|
-
);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
Promise.all(promises)
|
|
703
|
-
.then(() => instance.trigger('store-updated'))
|
|
704
|
-
.catch(e => instance.trigger('error', e));
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
/**
|
|
708
|
-
*
|
|
709
|
-
* @param {object} update - The changed configuration
|
|
710
|
-
* @param {Array<string>} update.selection - array of column ids to display
|
|
711
|
-
* @param {string} update.sortby - The sorted column
|
|
712
|
-
* @param {string} update.sortorder - The sort order
|
|
713
|
-
* @param {number} update.page - The current page
|
|
714
|
-
* @returns
|
|
715
|
-
*/
|
|
716
|
-
function updateSelectedStore({ selection = [], sortby = 'id', sortorder = 'asc', page = 1 } = {}) {
|
|
717
|
-
const storedSearchOptions = { sortby, sortorder, page };
|
|
718
|
-
return selectedColumnsStore
|
|
719
|
-
.setItem(rootClassUri, selection)
|
|
720
|
-
.then(() => instance.trigger('selected-store-updated', { storedSearchOptions }))
|
|
721
|
-
.catch(e => instance.trigger('error', e));
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Clear search input, criteria and results from both, view and store.
|
|
726
|
-
* Also sets every criterion on criteriaState to unredered and
|
|
727
|
-
* undefined value
|
|
728
|
-
*/
|
|
729
|
-
function clear() {
|
|
730
|
-
controls.$searchInput.val('');
|
|
731
|
-
advancedSearch.clear();
|
|
732
|
-
isResourceSelector && resourceSelector.select(rootClassUri);
|
|
733
|
-
replaceSearchResultsDatatableWithMessage('no-query');
|
|
734
|
-
updateSearchStore({ action: 'clear' });
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
/**
|
|
738
|
-
* Removes datatable container and displays a message instead
|
|
739
|
-
* @param {string} reason - reason why datatable is not rendered, to display appropiate message
|
|
740
|
-
*/
|
|
741
|
-
function replaceSearchResultsDatatableWithMessage(reason) {
|
|
742
|
-
let message = '';
|
|
743
|
-
let icon = '';
|
|
744
|
-
|
|
745
|
-
if (reason === 'no-query') {
|
|
746
|
-
message = __('Please define your search in the search panel.');
|
|
747
|
-
icon = 'icon-find';
|
|
748
|
-
} else if (reason === 'no-matches') {
|
|
749
|
-
message = __('No item found. Please try other search criteria.');
|
|
750
|
-
icon = 'icon-info';
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
const infoMessage = infoMessageTpl({ message, icon });
|
|
754
|
-
controls.$contentToolbar.empty();
|
|
755
|
-
controls.$contentArea.empty().append(infoMessage);
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
// return initialized instance of searchModal
|
|
759
|
-
return instance.init(config);
|
|
760
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This program is free software; you can redistribute it and/or
|
|
3
|
+
* modify it under the terms of the GNU General Public License
|
|
4
|
+
* as published by the Free Software Foundation; under version 2
|
|
5
|
+
* of the License (non-upgradable).
|
|
6
|
+
*
|
|
7
|
+
* This program is distributed in the hope that it will be useful,
|
|
8
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
9
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
10
|
+
* GNU General Public License for more details.
|
|
11
|
+
*
|
|
12
|
+
* You should have received a copy of the GNU General Public License
|
|
13
|
+
* along with this program; if not, write to the Free Software
|
|
14
|
+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
15
|
+
*
|
|
16
|
+
* Copyright (c) 2021 (original work) Open Assessment Technologies SA ;
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import $ from 'jquery';
|
|
20
|
+
import _ from 'lodash';
|
|
21
|
+
import __ from 'i18n';
|
|
22
|
+
import context from 'context';
|
|
23
|
+
import layoutTpl from 'ui/searchModal/tpl/layout';
|
|
24
|
+
import resultsContainerTpl from 'ui/searchModal/tpl/results-container';
|
|
25
|
+
import infoMessageTpl from 'ui/searchModal/tpl/info-message';
|
|
26
|
+
import propertySelectButtonTpl from 'ui/searchModal/tpl/property-select-button';
|
|
27
|
+
import 'ui/searchModal/css/searchModal.css';
|
|
28
|
+
import component from 'ui/component';
|
|
29
|
+
import 'ui/modal';
|
|
30
|
+
import 'ui/datatable';
|
|
31
|
+
import store from 'core/store';
|
|
32
|
+
import resourceSelectorFactory from 'ui/resource/selector';
|
|
33
|
+
import propertySelectorFactory from 'ui/propertySelector/propertySelector';
|
|
34
|
+
import advancedSearchFactory from 'ui/searchModal/advancedSearch';
|
|
35
|
+
import request from 'core/dataProvider/request';
|
|
36
|
+
import urlUtil from 'util/url';
|
|
37
|
+
import 'select2';
|
|
38
|
+
import shortcutRegistry from 'util/shortcut/registry';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a searchModal instance
|
|
42
|
+
*
|
|
43
|
+
* @param {object} config
|
|
44
|
+
* @param {object} config.renderTo - DOM element where component will be rendered to
|
|
45
|
+
* @param {string} config.criterias - Search criteria to be set on component creation
|
|
46
|
+
* @param {boolean} config.searchOnInit - if init search must be triggered or not (stored results are used instead)
|
|
47
|
+
* @param {string} config.url - search endpoint to be set on datatable
|
|
48
|
+
* @param {string} config.rootClassUri - Uri for the root class of current context, required to init the class filter
|
|
49
|
+
* @param {bool} config.hideResourceSelector - if resourceSelector must be hidden
|
|
50
|
+
* @param {bool} config.hideCriteria - if the criteria must be hidden
|
|
51
|
+
* @param {string} config.placeholder - placeholder for input in template
|
|
52
|
+
* @param {string} config.classesUrl - the URL to the classes API (usually '/tao/RestResource/getAll')
|
|
53
|
+
* @param {string} config.classMappingUrl - the URL to the class mapping API (usually '/tao/ClassMetadata/getWithMapping')
|
|
54
|
+
* @param {string} config.statusUrl - the URL to the status API (usually '/tao/AdvancedSearch/status')
|
|
55
|
+
* @param {string} config.sortby - the default sorted column (usually 'label')
|
|
56
|
+
* @param {string} config.sortorder - the default sort order (usually 'asc')
|
|
57
|
+
* @returns {searchModal}
|
|
58
|
+
*/
|
|
59
|
+
export default function searchModalFactory(config) {
|
|
60
|
+
// @TODO: The consumer must be responsible for supplying the routes. The component must not hardcode endpoints.
|
|
61
|
+
const defaults = {
|
|
62
|
+
classesUrl: urlUtil.route('getAll', 'RestResource', 'tao'),
|
|
63
|
+
classMappingUrl: urlUtil.route('getWithMapping', 'ClassMetadata', 'tao'),
|
|
64
|
+
statusUrl: urlUtil.route('status', 'AdvancedSearch', 'tao'),
|
|
65
|
+
renderTo: 'body',
|
|
66
|
+
criterias: {},
|
|
67
|
+
searchOnInit: true,
|
|
68
|
+
maxListSize: 5,
|
|
69
|
+
sortby: 'label',
|
|
70
|
+
sortorder: 'asc'
|
|
71
|
+
};
|
|
72
|
+
// Private properties to be easily accessible by instance methods
|
|
73
|
+
let $container = null;
|
|
74
|
+
let controls = {};
|
|
75
|
+
let running = false;
|
|
76
|
+
let searchStore = null;
|
|
77
|
+
let selectedColumnsStore = null;
|
|
78
|
+
let resourceSelector = null;
|
|
79
|
+
let advancedSearch = null;
|
|
80
|
+
let propertySelectorInstance;
|
|
81
|
+
let availableColumns = [];
|
|
82
|
+
let availableIdentifiers = {};
|
|
83
|
+
let selectedColumns = [];
|
|
84
|
+
let dataCache;
|
|
85
|
+
|
|
86
|
+
// resorce selector
|
|
87
|
+
const isResourceSelector = !config.hideResourceSelector;
|
|
88
|
+
const rootClassUri = config.rootClassUri;
|
|
89
|
+
|
|
90
|
+
// Creates new component
|
|
91
|
+
const instance = component(
|
|
92
|
+
{
|
|
93
|
+
/**
|
|
94
|
+
* Tells if the advanced search is enabled.
|
|
95
|
+
* @returns {boolean}
|
|
96
|
+
*/
|
|
97
|
+
isAdvancedSearchEnabled() {
|
|
98
|
+
return advancedSearch && advancedSearch.isEnabled();
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
defaults
|
|
102
|
+
)
|
|
103
|
+
.setTemplate(layoutTpl)
|
|
104
|
+
.on('selected-store-updated', recreateDatatable)
|
|
105
|
+
.on('render', renderModal)
|
|
106
|
+
.on('destroy', destroyModal);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Creates search modal, inits template selectors, inits search store, and once is created triggers initial search
|
|
110
|
+
* rootClassUri is sent to advancedSearch factory for disabling in whitelisted sections
|
|
111
|
+
*/
|
|
112
|
+
function renderModal() {
|
|
113
|
+
const promises = [];
|
|
114
|
+
initModal();
|
|
115
|
+
initUiSelectors();
|
|
116
|
+
advancedSearch = advancedSearchFactory({
|
|
117
|
+
renderTo: controls.$filtersContainer,
|
|
118
|
+
advancedCriteria: instance.config.criterias.advancedCriteria,
|
|
119
|
+
hideCriteria: instance.config.hideCriteria,
|
|
120
|
+
statusUrl: instance.config.statusUrl,
|
|
121
|
+
rootClassUri: rootClassUri
|
|
122
|
+
});
|
|
123
|
+
promises.push(initClassFilter());
|
|
124
|
+
promises.push(initStores());
|
|
125
|
+
Promise.all(promises)
|
|
126
|
+
.then(() => {
|
|
127
|
+
instance.trigger('ready');
|
|
128
|
+
controls.$searchButton.trigger('click');
|
|
129
|
+
})
|
|
130
|
+
.catch(e => instance.trigger('error', e));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Removes search modal
|
|
135
|
+
*/
|
|
136
|
+
function destroyModal() {
|
|
137
|
+
$container.removeClass('modal').modal('destroy');
|
|
138
|
+
if (propertySelectorInstance) {
|
|
139
|
+
propertySelectorInstance.destroy();
|
|
140
|
+
}
|
|
141
|
+
$('.modal-bg').remove();
|
|
142
|
+
controls = {};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Creates search modal
|
|
147
|
+
*/
|
|
148
|
+
function initModal() {
|
|
149
|
+
$container = instance.getElement();
|
|
150
|
+
$container
|
|
151
|
+
.addClass('modal')
|
|
152
|
+
.on('closed.modal', () => instance.destroy())
|
|
153
|
+
.modal({
|
|
154
|
+
disableEscape: false,
|
|
155
|
+
width: $(window).width(),
|
|
156
|
+
modalCloseClass: 'modal-close-left'
|
|
157
|
+
})
|
|
158
|
+
.focus();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Inits class filter selector
|
|
163
|
+
*/
|
|
164
|
+
function initClassFilter() {
|
|
165
|
+
return new Promise(resolve => {
|
|
166
|
+
if (!isResourceSelector) {
|
|
167
|
+
controls.$classFilterContainer.hide();
|
|
168
|
+
return resolve();
|
|
169
|
+
}
|
|
170
|
+
const initialClassUri =
|
|
171
|
+
instance.config.criterias && instance.config.criterias.class
|
|
172
|
+
? instance.config.criterias.class
|
|
173
|
+
: rootClassUri;
|
|
174
|
+
resourceSelector = resourceSelectorFactory(controls.$classTreeContainer, {
|
|
175
|
+
//set up the inner resource selector
|
|
176
|
+
selectionMode: 'single',
|
|
177
|
+
selectClass: true,
|
|
178
|
+
classUri: rootClassUri,
|
|
179
|
+
showContext: false,
|
|
180
|
+
showSelection: false
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// when a class query is triggered, update selector options with received resources
|
|
184
|
+
resourceSelector.on('query', params => {
|
|
185
|
+
const classOnlyParams = { ...params, classOnly: true };
|
|
186
|
+
const route = instance.config.classesUrl;
|
|
187
|
+
request(route, classOnlyParams)
|
|
188
|
+
.then(response => {
|
|
189
|
+
if (
|
|
190
|
+
response.permissions &&
|
|
191
|
+
response.permissions.data &&
|
|
192
|
+
response.permissions.supportedRights &&
|
|
193
|
+
response.permissions.supportedRights.length > 0
|
|
194
|
+
) {
|
|
195
|
+
manageClassTreePermissions(response);
|
|
196
|
+
}
|
|
197
|
+
resourceSelector.update(response.resources, classOnlyParams);
|
|
198
|
+
})
|
|
199
|
+
.catch(e => instance.trigger('error', e));
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
/*
|
|
203
|
+
* the first time selector opions are updated the root class is selected. Promise is
|
|
204
|
+
* resolved so init process continues only when class input value has been set
|
|
205
|
+
*/
|
|
206
|
+
resourceSelector.on('update', () => {
|
|
207
|
+
resourceSelector.off('update');
|
|
208
|
+
|
|
209
|
+
resourceSelector.select(initialClassUri);
|
|
210
|
+
resolve();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// then new class is selected, set its label into class filter input and hide filter container, then request class properties
|
|
214
|
+
resourceSelector.on('change', selectedValue => {
|
|
215
|
+
/*
|
|
216
|
+
* on searchModal init we set manually the selector to the provided config.rootClassUri. When a selector
|
|
217
|
+
* is set manually Selector component execs @clearSelection which triggers a change event
|
|
218
|
+
* with an empty object as param. We catch this undesired behaviour here
|
|
219
|
+
*/
|
|
220
|
+
if (_.isEmpty(selectedValue)) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const classUri = _.map(selectedValue, 'classUri')[0];
|
|
224
|
+
const label = _.map(selectedValue, 'label')[0];
|
|
225
|
+
const uri = _.map(selectedValue, 'uri')[0];
|
|
226
|
+
const route = urlUtil.build(instance.config.classMappingUrl, {
|
|
227
|
+
classUri,
|
|
228
|
+
maxListSize: instance.config.maxListSize
|
|
229
|
+
});
|
|
230
|
+
controls.$classFilterInput.html(label);
|
|
231
|
+
controls.$classFilterInput.data('uri', uri);
|
|
232
|
+
controls.$classTreeContainer.hide();
|
|
233
|
+
advancedSearch
|
|
234
|
+
.updateCriteria(route)
|
|
235
|
+
.then(() => instance.trigger('criteriaListUpdated'))
|
|
236
|
+
.catch(e => instance.trigger('error', e));
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
setResourceSelectorUIBehaviour();
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Loops through each class in received class tree and sets access mode to 'denied' on private classes
|
|
245
|
+
* so are disabled on class tree
|
|
246
|
+
* @param {object} classTree - class tree received by server, containing resources (classes) and permissions
|
|
247
|
+
*/
|
|
248
|
+
function manageClassTreePermissions(classTree) {
|
|
249
|
+
const disableBlockedClasses = function (resources) {
|
|
250
|
+
_.forEach(resources, (resource, index, array) => {
|
|
251
|
+
if (
|
|
252
|
+
classTree.permissions.data[resource.uri] &&
|
|
253
|
+
classTree.permissions.data[resource.uri].find(permission => permission === 'READ')
|
|
254
|
+
) {
|
|
255
|
+
if (resource.children) {
|
|
256
|
+
disableBlockedClasses(resource.children);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
array[index].accessMode = 'denied';
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
disableBlockedClasses(classTree.resources);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Inits template selectors, buttons behaviour, scroll animation,
|
|
268
|
+
* and sets initial search query on search input
|
|
269
|
+
*/
|
|
270
|
+
function initUiSelectors() {
|
|
271
|
+
controls = {
|
|
272
|
+
$searchButton: $('.btn-search', $container),
|
|
273
|
+
$clearButton: $('.btn-clear', $container),
|
|
274
|
+
$searchInput: $('.generic-search-input', $container),
|
|
275
|
+
$classFilterInput: $('.class-filter', $container),
|
|
276
|
+
$classTreeContainer: $('.class-tree', $container),
|
|
277
|
+
$classFilterContainer: $('.class-filter-container', $container),
|
|
278
|
+
$filtersContainer: $('.filters-container', $container),
|
|
279
|
+
$contentArea: $('.content-area', $container),
|
|
280
|
+
$contentToolbar: $('.content-toolbar', $container)
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
controls.$searchButton.on('click', search);
|
|
284
|
+
controls.$clearButton.on('click', clear);
|
|
285
|
+
const shortcuts = shortcutRegistry(controls.$searchInput);
|
|
286
|
+
shortcuts.clear().add('enter', search);
|
|
287
|
+
controls.$searchInput.val(
|
|
288
|
+
instance.config.criterias && instance.config.criterias.search ? instance.config.criterias.search : ''
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Sets required listeners to properly manage resourceSelector visualization
|
|
294
|
+
*/
|
|
295
|
+
function setResourceSelectorUIBehaviour() {
|
|
296
|
+
$container.on('mousedown', () => {
|
|
297
|
+
controls.$classTreeContainer.hide();
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Pressing space, enter, esc, backspace
|
|
302
|
+
* on class filter input will toggle resource selector
|
|
303
|
+
*/
|
|
304
|
+
const shortcuts = shortcutRegistry(controls.$classFilterInput);
|
|
305
|
+
shortcuts.add('enter', () => controls.$classTreeContainer.show());
|
|
306
|
+
shortcuts.add('space', () => controls.$classTreeContainer.show());
|
|
307
|
+
shortcuts.add('backspace', () => controls.$classTreeContainer.hide());
|
|
308
|
+
shortcuts.add('escape', () => controls.$classTreeContainer.hide(), { propagate: false });
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* clicking on class filter container will toggle resource selector
|
|
312
|
+
*/
|
|
313
|
+
controls.$classFilterContainer.on('click', () => {
|
|
314
|
+
controls.$classTreeContainer.toggle();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* clicking on class filter container will
|
|
319
|
+
* stopPropagation to prevent be closed
|
|
320
|
+
* by searchModal.mouseDown listener
|
|
321
|
+
*/
|
|
322
|
+
controls.$classFilterContainer.on('mousedown', e => {
|
|
323
|
+
e.stopPropagation();
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// clicking on resource selector will stopPropagation to prevent be closed by searchModal.mouseDown listener
|
|
327
|
+
controls.$classTreeContainer.on('mousedown', e => {
|
|
328
|
+
e.stopPropagation();
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Loads search store so it is accessible in the component
|
|
334
|
+
* @returns {Promise}
|
|
335
|
+
*/
|
|
336
|
+
function initStores() {
|
|
337
|
+
return Promise.all([
|
|
338
|
+
store('search').then(updatedStore => (searchStore = updatedStore)),
|
|
339
|
+
store('selectedColumns').then(updatedStore => (selectedColumnsStore = updatedStore))
|
|
340
|
+
]).catch(e => instance.trigger('error', e));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Performs a search query
|
|
345
|
+
* @param query - The searched terms
|
|
346
|
+
* @param classFilterUri - The URI of the node class
|
|
347
|
+
* @param [params] - Additional parameters
|
|
348
|
+
* @returns {Promise}
|
|
349
|
+
*/
|
|
350
|
+
const searchQuery = (query, classFilterUri, params = {}) => {
|
|
351
|
+
return new Promise((resolve, reject) => {
|
|
352
|
+
$.ajax({
|
|
353
|
+
url: instance.config.url,
|
|
354
|
+
type: 'POST',
|
|
355
|
+
data: { ...params, query: query, parentNode: classFilterUri, structure: context.shownStructure },
|
|
356
|
+
dataType: 'json'
|
|
357
|
+
})
|
|
358
|
+
.done(resolve)
|
|
359
|
+
.fail(reject);
|
|
360
|
+
});
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Performs the search query, preventing to send too many requests
|
|
365
|
+
* @param query - The searched terms
|
|
366
|
+
* @param classFilterUri - The URI of the node class
|
|
367
|
+
* @param [params] - Additional parameters
|
|
368
|
+
*/
|
|
369
|
+
const searchHandler = (query, classFilterUri, params = {}) => {
|
|
370
|
+
if (running === false) {
|
|
371
|
+
running = true;
|
|
372
|
+
searchQuery(query, classFilterUri, params)
|
|
373
|
+
.then(data => data.data)
|
|
374
|
+
.then(buildDataModel)
|
|
375
|
+
.then(filterSelectedColumns)
|
|
376
|
+
.then(appendDefaultDatasetToDatatable)
|
|
377
|
+
.then(buildSearchResultsDatatable)
|
|
378
|
+
.catch(e => instance.trigger('error', e))
|
|
379
|
+
.then(() => (running = false));
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Request search results and manages its results
|
|
385
|
+
*/
|
|
386
|
+
function search() {
|
|
387
|
+
searchHandler(buildComplexQuery(), getClassFilterUri());
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Returns selected class filter of rootClassUri
|
|
392
|
+
*/
|
|
393
|
+
function getClassFilterUri() {
|
|
394
|
+
return isResourceSelector ? controls.$classFilterInput.data('uri').trim() : rootClassUri;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* build final complex query appending every filter
|
|
399
|
+
*/
|
|
400
|
+
function buildComplexQuery() {
|
|
401
|
+
let query = controls.$searchInput.val().trim();
|
|
402
|
+
query += advancedSearch.getAdvancedCriteriaQuery(query !== '');
|
|
403
|
+
|
|
404
|
+
return query;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/*
|
|
408
|
+
* If search on init is not required, extends data with stored dataset
|
|
409
|
+
* @param {object} data - search configuration including model and endpoint for datatable
|
|
410
|
+
* @returns {Promise}
|
|
411
|
+
*/
|
|
412
|
+
function appendDefaultDatasetToDatatable(data) {
|
|
413
|
+
return new Promise(function (resolve, reject) {
|
|
414
|
+
// If no search on init, get dataset from searchStore
|
|
415
|
+
if (instance.config.searchOnInit === false) {
|
|
416
|
+
Promise.all([searchStore.getItem('results'), searchStore.getItem('options')])
|
|
417
|
+
.then(fromStore => {
|
|
418
|
+
instance.config.searchOnInit = true;
|
|
419
|
+
data.storedSearchResults = fromStore[0];
|
|
420
|
+
data.storedSearchOptions = fromStore[1];
|
|
421
|
+
resolve(data);
|
|
422
|
+
})
|
|
423
|
+
.catch(e => {
|
|
424
|
+
reject(
|
|
425
|
+
new Error('Error appending default dataset from searchStore to datatable', { cause: e })
|
|
426
|
+
);
|
|
427
|
+
});
|
|
428
|
+
} else {
|
|
429
|
+
resolve(data);
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Replaces empty value by a placeholder.
|
|
436
|
+
* @param value
|
|
437
|
+
* @returns {string|*}
|
|
438
|
+
*/
|
|
439
|
+
const emptyValueTransform = value => {
|
|
440
|
+
let testedValue = value;
|
|
441
|
+
if (Array.isArray(testedValue)) {
|
|
442
|
+
testedValue = testedValue[0];
|
|
443
|
+
}
|
|
444
|
+
if ('string' === typeof testedValue) {
|
|
445
|
+
testedValue = testedValue.trim();
|
|
446
|
+
}
|
|
447
|
+
return testedValue === '' || testedValue === null || typeof testedValue === 'undefined' ? '-' : value;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Refines the columns to be compatible with the datatable model
|
|
452
|
+
* @param {object[]} columns
|
|
453
|
+
* @returns {object[]}
|
|
454
|
+
*/
|
|
455
|
+
function columnsToModel(columns) {
|
|
456
|
+
if (!Array.isArray(columns)) {
|
|
457
|
+
return [];
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return columns.map(column => {
|
|
461
|
+
const { id, sortId, label, sortable, isDuplicated } = column;
|
|
462
|
+
let alias, comment, classLabel;
|
|
463
|
+
if (isDuplicated) {
|
|
464
|
+
alias = column.alias;
|
|
465
|
+
classLabel = column.classLabel; // needed by the property selector
|
|
466
|
+
comment = column.classLabel; // needed by the datatable
|
|
467
|
+
}
|
|
468
|
+
return { id, sortId, label, alias, classLabel, comment, sortable, transform: emptyValueTransform };
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Refines the data model for the datatable
|
|
474
|
+
* @param {object} data - search configuration including model and endpoint for datatable
|
|
475
|
+
* @returns {object} The data configuration refined with the data model for the datatrable
|
|
476
|
+
*/
|
|
477
|
+
function buildDataModel(data) {
|
|
478
|
+
//save availableColumns to memory
|
|
479
|
+
availableIdentifiers = {};
|
|
480
|
+
availableColumns = data.settings.availableColumns;
|
|
481
|
+
|
|
482
|
+
// The support for the old data.model coming from the server has been removed from the commit
|
|
483
|
+
// https://github.com/oat-sa/tao-core-ui-fe/commit/ae6c16a9199f9fc808bc8a37d2ddfce437a62e9c
|
|
484
|
+
// The data model is now coming from the settings carried on by the searchParams request.
|
|
485
|
+
data.model = columnsToModel(availableColumns);
|
|
486
|
+
data.model.forEach(column => (availableIdentifiers[column.id] = true));
|
|
487
|
+
|
|
488
|
+
// adjust the default sorting and pagination
|
|
489
|
+
let { sortby, sortorder, page } = instance.config;
|
|
490
|
+
|
|
491
|
+
if (!sortorder || !['asc', 'desc'].includes(sortorder)) {
|
|
492
|
+
sortorder = 'asc';
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const sortIdentifiers = [];
|
|
496
|
+
data.model.forEach(column => {
|
|
497
|
+
sortIdentifiers.push(column.sortId || column.id);
|
|
498
|
+
if (column.sortId && column.id === sortby) {
|
|
499
|
+
sortby = column.sortId;
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
if (!sortIdentifiers.includes(sortby)) {
|
|
503
|
+
// unknown sort identifier is rejected for safety
|
|
504
|
+
sortby = void 0;
|
|
505
|
+
sortorder = void 0;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
data.pageConfig = { sortby, sortorder, page };
|
|
509
|
+
|
|
510
|
+
dataCache = _.cloneDeep(data);
|
|
511
|
+
return data;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Filters datatble model based on stored selected columns
|
|
516
|
+
* @param {Object} data data containing available columns and model for datatable
|
|
517
|
+
* @returns {Promise} promise which resolves with filtered data.model
|
|
518
|
+
*/
|
|
519
|
+
function filterSelectedColumns(data) {
|
|
520
|
+
return selectedColumnsStore
|
|
521
|
+
.getItem(rootClassUri)
|
|
522
|
+
.then(storedSelectedColumnIds => {
|
|
523
|
+
selectedColumns = [];
|
|
524
|
+
|
|
525
|
+
if (storedSelectedColumnIds && storedSelectedColumnIds.length) {
|
|
526
|
+
storedSelectedColumnIds.forEach(id => {
|
|
527
|
+
if (availableIdentifiers[id]) {
|
|
528
|
+
selectedColumns.push(id);
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (!selectedColumns.length) {
|
|
534
|
+
selectedColumns = data.settings.availableColumns.reduce((acc, column) => {
|
|
535
|
+
if (column.default) {
|
|
536
|
+
acc.push(column.id);
|
|
537
|
+
}
|
|
538
|
+
return acc;
|
|
539
|
+
}, []);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
data.model = data.model.filter(column => selectedColumns.includes(column.id));
|
|
543
|
+
return data;
|
|
544
|
+
})
|
|
545
|
+
.catch(e => {
|
|
546
|
+
instance.trigger('error', e);
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Creates a datatable with search results
|
|
552
|
+
* @param {object} data - search configuration including model and endpoint for datatable
|
|
553
|
+
*/
|
|
554
|
+
function buildSearchResultsDatatable(data) {
|
|
555
|
+
// Note: the table container needs to be recreated because datatable is storing data in it.
|
|
556
|
+
// Keeping the table container introduces a DOM pollution.
|
|
557
|
+
// It is faster and cleaner to recreate the container than cleaning it explicitly.
|
|
558
|
+
const $tableContainer = $(resultsContainerTpl());
|
|
559
|
+
const $contentContainer = controls.$contentArea.empty();
|
|
560
|
+
$contentContainer.append($tableContainer);
|
|
561
|
+
$tableContainer.on('load.datatable', searchResultsLoaded);
|
|
562
|
+
|
|
563
|
+
const { sortby, sortorder, page } = data.storedSearchOptions || data.pageConfig;
|
|
564
|
+
|
|
565
|
+
//create datatable
|
|
566
|
+
$tableContainer.datatable(
|
|
567
|
+
{
|
|
568
|
+
url: data.url,
|
|
569
|
+
model: data.model,
|
|
570
|
+
sortby,
|
|
571
|
+
sortorder,
|
|
572
|
+
page,
|
|
573
|
+
labels: {
|
|
574
|
+
actions: ''
|
|
575
|
+
},
|
|
576
|
+
actions: [
|
|
577
|
+
{
|
|
578
|
+
id: 'go-to-item',
|
|
579
|
+
label: __('View'),
|
|
580
|
+
action: function openResource(uri, updatedData) {
|
|
581
|
+
instance.trigger('refresh', uri, updatedData);
|
|
582
|
+
instance.destroy();
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
],
|
|
586
|
+
params: {
|
|
587
|
+
params: data.params,
|
|
588
|
+
filters: data.filters,
|
|
589
|
+
rows: 20
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
data.storedSearchResults
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function getTableOptions() {
|
|
597
|
+
const $tableContainer = $('.results-container', $container);
|
|
598
|
+
return _.cloneDeep($tableContainer.data('ui.datatable') || {});
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Filters data from cache by selected and recreates datatable
|
|
603
|
+
* @params {object} options - Additional options to be given to the datatable
|
|
604
|
+
*/
|
|
605
|
+
function recreateDatatable(options = {}) {
|
|
606
|
+
const data = Object.assign(_.cloneDeep(dataCache), options);
|
|
607
|
+
filterSelectedColumns(data).then(buildSearchResultsDatatable);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Triggered on load.datatable event, it updates searchStore and manages possible exceptions
|
|
612
|
+
* @param {object} e - load.datatable event
|
|
613
|
+
* @param {object} dataset - datatable dataset
|
|
614
|
+
*/
|
|
615
|
+
function searchResultsLoaded(e, dataset) {
|
|
616
|
+
const $contentToolbar = controls.$contentToolbar.empty();
|
|
617
|
+
if (instance.isAdvancedSearchEnabled()) {
|
|
618
|
+
const $manageColumnsBtn = $(propertySelectButtonTpl());
|
|
619
|
+
$contentToolbar.append($manageColumnsBtn);
|
|
620
|
+
$manageColumnsBtn.on('click', handleManageColumnsBtnClick);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const { sortby, sortorder } = getTableOptions();
|
|
624
|
+
|
|
625
|
+
if (dataset.records === 0) {
|
|
626
|
+
replaceSearchResultsDatatableWithMessage('no-matches');
|
|
627
|
+
}
|
|
628
|
+
instance.trigger('datatable-loaded');
|
|
629
|
+
updateSearchStore({
|
|
630
|
+
action: 'update',
|
|
631
|
+
dataset,
|
|
632
|
+
options: { sortby, sortorder },
|
|
633
|
+
context: context.shownStructure,
|
|
634
|
+
criterias: {
|
|
635
|
+
search: controls.$searchInput && controls.$searchInput.val(),
|
|
636
|
+
class: isResourceSelector ? _.map(resourceSelector.getSelection(), 'uri')[0] : rootClassUri,
|
|
637
|
+
advancedCriteria: advancedSearch.getState()
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Handler for manage columns button click
|
|
644
|
+
*/
|
|
645
|
+
function handleManageColumnsBtnClick() {
|
|
646
|
+
const selected = selectedColumns;
|
|
647
|
+
const available = columnsToModel(availableColumns);
|
|
648
|
+
|
|
649
|
+
if (!propertySelectorInstance) {
|
|
650
|
+
const { bottom: btnBottom, right: btnRight } = this.getBoundingClientRect();
|
|
651
|
+
const { top: containerTop, right: containerRight } = $container.get(0).getBoundingClientRect();
|
|
652
|
+
const position = {
|
|
653
|
+
top: btnBottom - containerTop,
|
|
654
|
+
right: containerRight - btnRight
|
|
655
|
+
};
|
|
656
|
+
propertySelectorInstance = propertySelectorFactory({
|
|
657
|
+
renderTo: $container,
|
|
658
|
+
data: {
|
|
659
|
+
position,
|
|
660
|
+
available,
|
|
661
|
+
selected
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
propertySelectorInstance.on('select', selection => {
|
|
665
|
+
if (
|
|
666
|
+
selection.length !== selectedColumns.length ||
|
|
667
|
+
selection.some(columnId => !selectedColumns.includes(columnId))
|
|
668
|
+
) {
|
|
669
|
+
//update table
|
|
670
|
+
selectedColumns = selection;
|
|
671
|
+
const { sortby, sortorder, page } = getTableOptions();
|
|
672
|
+
updateSelectedStore({ selection, sortby, sortorder, page });
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
} else {
|
|
676
|
+
propertySelectorInstance.setData({ available, selected });
|
|
677
|
+
propertySelectorInstance.toggle();
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Updates searchStore. If action is 'clear', searchStore is claread. If not, received
|
|
683
|
+
* data is assigned to searchStore. Once all actions have been done,
|
|
684
|
+
* store-updated event is triggered
|
|
685
|
+
* @param {object} data - data to store
|
|
686
|
+
*/
|
|
687
|
+
function updateSearchStore(data) {
|
|
688
|
+
const promises = [];
|
|
689
|
+
if (data.action === 'clear') {
|
|
690
|
+
promises.push(searchStore.clear());
|
|
691
|
+
} else if (data.action === 'update') {
|
|
692
|
+
promises.push(searchStore.setItem('criterias', data.criterias));
|
|
693
|
+
promises.push(searchStore.setItem('context', data.context));
|
|
694
|
+
promises.push(searchStore.setItem('options', data.options));
|
|
695
|
+
promises.push(
|
|
696
|
+
data.dataset.records === 0
|
|
697
|
+
? searchStore.removeItem('results')
|
|
698
|
+
: searchStore.setItem('results', data.dataset)
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
Promise.all(promises)
|
|
703
|
+
.then(() => instance.trigger('store-updated'))
|
|
704
|
+
.catch(e => instance.trigger('error', e));
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
*
|
|
709
|
+
* @param {object} update - The changed configuration
|
|
710
|
+
* @param {Array<string>} update.selection - array of column ids to display
|
|
711
|
+
* @param {string} update.sortby - The sorted column
|
|
712
|
+
* @param {string} update.sortorder - The sort order
|
|
713
|
+
* @param {number} update.page - The current page
|
|
714
|
+
* @returns
|
|
715
|
+
*/
|
|
716
|
+
function updateSelectedStore({ selection = [], sortby = 'id', sortorder = 'asc', page = 1 } = {}) {
|
|
717
|
+
const storedSearchOptions = { sortby, sortorder, page };
|
|
718
|
+
return selectedColumnsStore
|
|
719
|
+
.setItem(rootClassUri, selection)
|
|
720
|
+
.then(() => instance.trigger('selected-store-updated', { storedSearchOptions }))
|
|
721
|
+
.catch(e => instance.trigger('error', e));
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Clear search input, criteria and results from both, view and store.
|
|
726
|
+
* Also sets every criterion on criteriaState to unredered and
|
|
727
|
+
* undefined value
|
|
728
|
+
*/
|
|
729
|
+
function clear() {
|
|
730
|
+
controls.$searchInput.val('');
|
|
731
|
+
advancedSearch.clear();
|
|
732
|
+
isResourceSelector && resourceSelector.select(rootClassUri);
|
|
733
|
+
replaceSearchResultsDatatableWithMessage('no-query');
|
|
734
|
+
updateSearchStore({ action: 'clear' });
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Removes datatable container and displays a message instead
|
|
739
|
+
* @param {string} reason - reason why datatable is not rendered, to display appropiate message
|
|
740
|
+
*/
|
|
741
|
+
function replaceSearchResultsDatatableWithMessage(reason) {
|
|
742
|
+
let message = '';
|
|
743
|
+
let icon = '';
|
|
744
|
+
|
|
745
|
+
if (reason === 'no-query') {
|
|
746
|
+
message = __('Please define your search in the search panel.');
|
|
747
|
+
icon = 'icon-find';
|
|
748
|
+
} else if (reason === 'no-matches') {
|
|
749
|
+
message = __('No item found. Please try other search criteria.');
|
|
750
|
+
icon = 'icon-info';
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const infoMessage = infoMessageTpl({ message, icon });
|
|
754
|
+
controls.$contentToolbar.empty();
|
|
755
|
+
controls.$contentArea.empty().append(infoMessage);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// return initialized instance of searchModal
|
|
759
|
+
return instance.init(config);
|
|
760
|
+
}
|