1/* 2 * Copyright (c) 2024 Republic of Reinvention BV <[email protected]>. All Rights Reserved. 3 * This file is part of project "cinematek-filmout-site" and can not be copied and/or distributed without 4 * the express permission and written consent of the legal responsible of Republic of Reinvention BV. 5 */ 6 7/** 8 * Created by bram on 15/03/2024. 9 */ 10base.plugin("blocks.imports.Dtable", ["base.core.Commons", "base.core.Security", "blocks.core.Broadcaster", "blocks.core.Notification", "blocks.core.Commons", "constants.blocks.core", "messages.blocks.core", "blocks.imports.Widget", "constants.blocks.imports.dtable", function (Commons, Security, Broadcaster, Notification, BlocksCommons, BlocksConstants, BlocksMessages, Widget, DtableConstants) 11{ 12 var Dtable = this; 13 14 this.COL_DATA_TH = 'th'; 15 this.COL_DATA_META = 'meta'; 16 this.COL_DATA_FIELD = 'field'; 17 18 var PREV_VAL_KEY = 'val-prev'; 19 20 this.init = function (tableEls, initCallback, filterCallback, sortCallback) 21 { 22 if (tableEls) { 23 tableEls.each(function (index) 24 { 25 var tableEl = $(this); 26 27 // let's search the wrapping block element around this table 28 // (see getAllImports() for details about the extra .element) 29 var parentBlock = BlocksCommons.getAllImports(tableEl, true)[0].element; 30 31 // this will hold metadata about 32 var columns = {}; 33 var rdfMetaParams = []; 34 35 var thEls = tableEl.find('tr th'); 36 thEls.each(function (index) 37 { 38 var thEl = $(this); 39 var fieldName = thEl.attr(DtableConstants.DTABLE_TH_FIELD_NAME_ATTR); 40 41 // the name of the field is the minimum we need to enable dynamic functions for the column 42 if (fieldName) { 43 44 var param = {}; 45 param[BlocksConstants.RDF_RES_TYPE_CURIE_PARAM] = fieldName; 46 rdfMetaParams.push(param); 47 48 columns[fieldName] = Commons.keyValObj( 49 Dtable.COL_DATA_TH, thEl, 50 // will be filled in below 51 Dtable.COL_DATA_META, undefined, 52 // a backlink to the key 53 Dtable.COL_DATA_FIELD, fieldName 54 ); 55 } 56 }); 57 58 // this will request all metadata in one roundtrip 59 var data = {}; 60 data[BlocksConstants.RDF_RES_TYPE_PARAM] = Commons.toJson64(rdfMetaParams); 61 $.getJSON(BlocksConstants.RDF_METAS_ENDPOINT, data) 62 .done(function (fieldMetas) 63 { 64 $.each(fieldMetas, function (index, fieldData) 65 { 66 // note that we sent the curie to the server, so use the curie as the key 67 var fieldName = fieldData[BlocksConstants.RDF_RES_TYPE_CURIE_PARAM]; 68 var fieldMeta = fieldData[BlocksConstants.DATA_PARAM]; 69 var columnData = columns[fieldName]; 70 var columnTh = columnData[Dtable.COL_DATA_TH]; 71 72 // Note: this will be null for internal fields 73 if (fieldMeta) { 74 // fill in the meta info and init the th 75 columnData[Dtable.COL_DATA_META] = fieldMeta; 76 initTh(columnTh, true); 77 } 78 // edge case: we always allow filtering on typeOf columns 79 else if (fieldName === BlocksConstants.INTERNAL_FIELD_TYPEOF_NAME || fieldName === BlocksConstants.INTERNAL_FIELD_TYPEOFLABEL_NAME) { 80 initTh(columnTh, true); 81 } 82 // note that unknown fields are returned as null 83 else { 84 // update 060924 this used to be addControl
84s: false, because we don't have metadata, 85 // but everything seems to work, so let's enable it and see what happens 86 initTh(columnTh, /*false*/ true); 87 } 88 }); 89 90 // now all the column data is filled in, we can create the event listeners 91 // Note that we need to use event propagation by listening on the parentBlock because we agreed that's the only one 92 // that need to be kept in place when altering its children. The caller should also leave the <thead> header 93 // alone, so the code below should always keep firing 94 parentBlock.on('change paste keyup', '.' + DtableConstants.DTABLE_TH_FILTER_CLASS + ' input', Commons.debounce( 95 function (event) 96 { 97 var inputEl = $(this); 98 var columnData = columns[inputEl.closest('th').attr(DtableConstants.DTABLE_TH_FIELD_NAME_ATTR)]; 99 100 var val = inputEl.val(); 101 var prevVal = inputEl.data(PREV_VAL_KEY); 102 inputEl.data(PREV_VAL_KEY, val); 103 // let's try to avoid double callback calls (but also double calls because of the multiple event types!) 104 if (Commons.isUnset(prevVal) || prevVal !== val) { 105 if (filterCallback) { 106 filterCallback(parentBlock, columnData, inputEl, val); 107 } 108 } 109 }, 110 500 111 ) 112 ); 113 114 // note that we don't allow sorting individually (too cumbersome to click on the icons) 115 // but it's possible to reactivate it 116 parentBlock.on('click', '.' + DtableConstants.DTABLE_TH_SORT_CLASS /*+ ' > *'*/, 117 function (event) 118 { 119 var clickedEl = $(this); 120 var columnData = columns[clickedEl.closest('th').attr(DtableConstants.DTABLE_TH_FIELD_NAME_ATTR)]; 121 122 var prevVal = clickedEl.data(PREV_VAL_KEY); 123 // this means asc is the default 124 var val = DtableConstants.DTABLE_SORT_VAL_ASC; 125 if (Commons.isSet(prevVal)) { 126 // we'll mimic intellij database manager and revert back to 'no specific sorting' when we cycled through 127 val = (prevVal === DtableConstants.DTABLE_SORT_VAL_ASC ? DtableConstants.DTABLE_SORT_VAL_DESC : undefined); 128 } 129 if (Commons.isSet(val)) { 130 clickedEl.data(PREV_VAL_KEY, val); 131 } 132 else { 133 clickedEl.removeData(PREV_VAL_KEY); 134 } 135 // let's try to avoid double callback calls (but also double calls because of the multiple event types!) 136 if (Commons.isUnset(prevVal) || prevVal !== val) { 137 if (sortCallback) { 138 sortCallback(parentBlock, columnData, clickedEl, val); 139 } 140 } 141 } 142 ); 143 144 // all done, let's call the initialized callback 145 if (initCallback) { 146 // don't add the tableEl because it will change on ajax reload 147 initCallback(parentBlock, columns); 148 } 149 }) 150 .fail(function (xhr, textStatus, exception) 151 { 152 Notification.jsonError(BlocksMessages.generalServerDataError, xhr, textStatus, exception); 153 }); 154 155 }); 156 } 157 }; 158
159 var initTh = function (thEl, addControls) 160 { 161 var filterDiv = thEl.find('.' + DtableConstants.DTABLE_TH_FILTER_CLASS); 162 var sortDiv = thEl.find('.' + DtableConstants.DTABLE_TH_SORT_CLASS); 163 164 // general flag to enable/disable the creation of controls 165 if (addControls) { 166 167 if (thEl.attr(DtableConstants.DTABLE_TH_FILTER_ENABLE_ATTR) === 'true') { 168 169 var filterInput = filterDiv.find('input'); 170 filterInput.removeAttr('disabled'); 171 172 // TODO WIP to offer the user a dropdown of possible values 173 // also see the notes about non-ajax facets in ResultsController, line 693 174 // var acOptions = {}; 175 // //acOptions[BlocksConstants.WIDGET_CONFIG_RESOURCE_AC_ENDPOINT] = CrbCommonsConstants.GET_FILM_SCREENING_RESOURCES_ENDPOINT + '?' + BlocksConstants.RDF_QUERY_PARAM + '='; 176 // //acOptions[BlocksConstants.WIDGET_CONFIG_RESOURCE_VAL_ENDPOINT] = CrbCommonsConstants.GET_FILM_SCREENING_RESOURCE_ENDPOINT + '?' + BlocksConstants.RDF_RES_URI_PARAM + '='; 177 // var dummyWidget = new Widget.Class(); 178 // dummyWidget.initAutocompleteWidget(filterInput, filterInput, 'data-value', acOptions, 179 // null, 180 // function (element, data) 181 // { 182 // // if (data) { 183 // // // save the current value in an attr on the input element, so the suggestion menu highlighting works as expected 184 // // acInput.attr(VALUE_ATTR, data.uri); 185 // // // there won't be any label dialog box, so generate one 186 // // labelInput.attr('value', Commons.format(CrbCommonsMessages.newFilmScreeningEventLabel, data.label)); 187 // // // the default property naming is to un-capitalize the type name (eg. crb:GuestFilm becomes crb:guestFilm) 188 // // var typeCurie = data.typeOf.split(':'); 189 // // parentInput.attr('name', typeCurie[0] + ':' + Commons.uncapitalize(typeCurie[1])); 190 // // // this will hold the real value of the parent resource, so let's sync the property name 191 // // parentInput.attr('value', data.uri); 192 // // } 193 // // else { 194 // // acInput.attr(VALUE_ATTR, ''); 195 // // labelInput.attr('value', ''); 196 // // parentInput.attr('name', ''); 197 // // parentInput.attr('value', ''); 198 // // } 199 // }, 200 // false); 201 } 202 203 if (thEl.attr(DtableConstants.DTABLE_TH_SORT_ENABLE_ATTR) === 'true') { 204 sortDiv.addClass('show'); 205 } 206 } 207 }; 208 209}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.