1const component_kikjobs_jobhighlighter = { 2 3 CONSTANTS: { 4 namespace: 'kikjobs-jobhighlighter', 5 debugLevel: 'production', 6 keys: { 7 cache: { 8 identifier: 'cache-kikjobs-jobhighlighter', 9 instances: 'instances', 10 filterOptions: 'filterOptions', 11 cache: 'cache', 12 }, 13 selectors: { 14 root: 'root', 15 listeners: ['area','level'], 16 option: 'option', 17 }, 18 ajax: { 19 requestType: 'requestType', 20 filterSource: 'filterSource', 21 } 22 }, 23 ajax: { 24 requestType: 'getFilterOptions', 25 }, 26 formKeys: { 27 all: function () { 28 const obj = component_kikjobs_jobhighlighter; 29 return [obj.CONSTANTS.formKeys.area,obj.CONSTANTS.formKeys.level]; 30 }, 31 area:'tx_kikjobs_list[query][area]', 32 level:'tx_kikjobs_list[query][level]', 33 }, 34 state: { 35 default: { 36 elements: { 37 root: null, 38 area: null, 39 level: null, 40 }, 41 initialized: false, 42 options: null, 43 identifier: null, 44 busy: false 45 } 46 }, 47 options: { 48 default: { 49 identifier: 'kikjobs-jobhighlighter-root-large', 50 xPath: { 51 all: '//form[contains(@data-js-identifier,"kikjobs-jobhighlighter-root")]', 52 root: '//form[@data-js-identifier="kikjobs-jobhighlighter-root-large"]', 53 area: '//form[@data-js-identifier="kikjobs-jobhighlighter-root-large"]//select[@name="tx_kikjobs_list[query][area]"]', 54 level: '//form[@data-js-identifier="kikjobs-jobhighlighter-root-large"]//select[@name="tx_kikjobs_list[query][level]"]', 55 }, 56 ajax: { 57 actionType: 925381 58 }, 59 }, 60 withIdentifier: (identifier) => { 61 let obj = component_kikjobs_jobhighlighter; 62 let options = {...obj.CONSTANTS.options.default}; 63 let newXPath = {},xpath; 64 for(let key in options.xPath) { 65 xpath = options.xPath[key].replace(options.identifier,identifier); 66 newXPath[key]=xpath; 67 } 68 options.identifier = identifier; 69 options.xPath = newXPath; 70 obj.debug(null,'Created options',{identifier: identifier, options:options,xpath:newXPath}); 71 return options; 72 } 73 }, 74 cache: { 75 default: { 76 instances: [], 77 filterOptions: [], 78 cache: [] 79 } 80 } 81 }, 82 createInstance: function (_options) { 83 let obj = component_kikjobs_jobhighlighter; 84 let state = {...obj.CONSTANTS.state.default}; 85 state.options = _options??obj.CONSTANTS.options.default; 86 return { 'State': state, 'Creator': obj }; 87 }, 88 init: function () { 89 let obj = component_kikjobs_jobhighlighter; 90 obj.debug(null,'Initializing'); 91 let element, instance, identifier, 92 options = obj.CONSTANTS.options.default, 93 instances=[], 94 result = obj.xPath(options.xPath.all,document,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE), 95 len = result.snapshotLength; 96 for(let index=0;
96index<len;index++){ 97 element = result.snapshotItem(index); 98 identifier = element.getAttribute('data-js-identifier'); 99 options = obj.CONSTANTS.options.withIdentifier(identifier); 100 obj.debug(null, 'Options w. Identifier', options); 101 instance = obj.createInstance(options); 102 instance.State.identifier = identifier; 103 instance.State.options = options; 104 obj.debug(instance,'State after reg', instance.State); 105 obj._linkDOMElements(instance,element); 106 obj.debug(instance,'Created instance',{identifier:instance.State.identifier,state:instance.State}); 107 obj._registerListeners(instance); 108 instances.push(instance); 109 } 110 111 if(instances.length<1) { 112 obj.debug(null,'No instances'); 113 return instances; 114 } 115 116 let cache = obj.getCacheData(); 117 let filterOptions = obj._initializeFilterOptions(instances[0]); 118 cache[obj.CONSTANTS.keys.cache.instances] = instances; 119 cache[obj.CONSTANTS.keys.cache.filterOptions] = filterOptions; 120 obj.setCacheData(cache); 121 obj.debug(cache[instances[0]],'Initialized Window-Cache', cache.filterOptions); 122 123 return instances; 124 }, 125 xPath: function (selector, _origin = null,resultType=4) { 126 let origin = _origin??document; 127 return document.evaluate(selector, origin, null,resultType); 128 }, 129 onChange: function (instance, key) { 130 let obj = component_kikjobs_jobhighlighter; 131 let value = obj.tryKey(instance,obj.CONSTANTS.formKeys[key],obj.getFilterValues(instance),""); 132 if(value==="") { 133 return obj.resetFilterOptions(instance,key); 134 } 135 obj.debug(instance,'change-event', {instance: instance.State.identifier, key: key, value: value}); 136 let values=(obj.getFilterValues(instance)); 137 138 // Submit the form immediately, when 'Ausbildung' is selected 139 if (values[obj.CONSTANTS.formKeys.level] === 'education' && values[obj.CONSTANTS.formKeys.area] === '') { 140 instance.State.elements.root.submit(); 141 } 142 obj.refreshFilters(instance, key); 143 return instance; 144 }, 145 resetFilterOptions: function (instance, sourceKey) { 146 let obj = component_kikjobs_jobhighlighter; 147 obj.debug(instance,'Resetting filter options triggered by', sourceKey); 148 obj.CONSTANTS.keys.selectors.listeners.forEach( 149 (key)=>{ 150 let element = obj.xPath(instance.State.options.xPath[key],document).iterateNext(); 151 if(key === sourceKey) { 152 return; 153 } 154 let cache = obj.getOriginalFilterState(instance,key); 155 let selectedValue = element.value; 156 //let xpath = instance.State.options.xPath[key]; 157 //obj.debug(instance, 'Resetting...', {key:key, identifier: instance.State.identifier, cache: cache, old:element, html: cache.html }); 158 element.querySelectorAll('option').forEach( 159 (option)=>{ 160 if(option.value!==""&&option.value!==selectedValue) { 161 option.remove(); 162 } 163 } 164 ); 165 cache.html.querySelectorAll('option').forEach( 166 (option)=>{ 167 if(option.value!==""&&option.value!==selectedValue) { 168 element.appendChild(option.cloneNode(true)); 169 } 170 } 171 ); 172 } 173 ); 174 return instance; 175 }, 176 getOriginalFilterState: function (instance, key) { 177 let obj = component_kikjobs_jobhighlighter; 178 let cache = obj.getCacheData(instance); 179 cache = cache[obj.CONSTANTS.keys.cache.filterOptions]; 180 obj.debug(instance,'cache-data',cache); 181 return cache[key]; 182 }, 183 limitFilterOptions: function (instance, key, allowedOptions) { 184 let obj = component_kikjobs_jobhighlighter; 185 let element = obj.xPath(instance.State.options.xPath[key],document).iterateNext(); 186 let cache = obj.getOriginalFilterState(instance,key); 187 let selectedValue = element.value; 188 element.querySelectorAll('option').forEach( 189 (option)=>{ 190 if(option.value!==""&&option.value!==selectedValue) { 191 option.remove(); 192 } 193 } 194 ); 195 cache.html.querySelectorAll('option').forEach( 196 (option)=>{ 197 if(option.value!==""&&option.value!==selectedValue&&allowedOptions.indexOf(option.value)>-1) { 198 element.appendChild(option.cloneNode(true)); 199 } 200 } 201 ); 202 }, 203 refreshFilters: function (instance, key) { 204 let obj = component_kikjobs_jobhighlighter; 205 obj.debug(instance,'refreshing filters...',instance.State.identifier); 206 if(instance.State.busy) { 207 obj.debug(instance, 'busy...', instance.State.identifier); 208 return; 209 } 210 instance.State.busy = true; 211 let action = instance.State.elements.root.getAttribute('action'); 212 let data = obj.getFormData(instance); 213 data.set(obj.CONSTANTS.keys.ajax.requestType, obj.CONSTANTS.ajax.requestType); 214 data.set(obj.CONSTANTS.keys.ajax.filterS
214ource, key); 215 216 obj.setBusy(instance,true); 217 fetch( 218 action + '?type='+instance.State.options.ajax.actionType,{ 219 method: 'POST', 220 body: data, 221 } 222 ).then(response => response.text()).then( 223 text => { 224 let filterData; 225 try { 226 filterData = JSON.parse(text); 227 }catch (e) { 228 obj.debug(instance, 'could not parse ajax response'); 229 instance.State.busy = false; 230 obj.setBusy(instance,false); 231 return; 232 } 233 obj.debug(instance,'Response for filter',{key: key, result: filterData.area}); 234 obj.onFilterRefreshData(instance,key,filterData); 235 obj.setBusy(instance,false); 236 instance.State.busy = false; 237 } 238 ); 239 return instance; 240 }, 241 onFilterRefreshData: function (instance,sourceKey,availableFilters) { 242 let obj = component_kikjobs_jobhighlighter; 243 obj.CONSTANTS.keys.selectors.listeners.forEach( 244 (key)=>{ 245 if(key === sourceKey) { 246 return; 247 } 248 let allowed = []; 249 availableFilters[key].forEach( 250 (filter)=>{ 251 allowed.push(filter[key]); 252 } 253 ); 254 obj.debug(instance,'Allowed for key',[key,allowed]); 255 obj.limitFilterOptions(instance,key,allowed) 256 } 257 ); 258 return instance; 259 }, 260 getFormData: function (instance) { 261 let obj = component_kikjobs_jobhighlighter; 262 263 let element = obj.xPath(instance.State.options.xPath.root,document).iterateNext(); 264 let result = new FormData(element); 265 obj.debug(instance,'fetching form-data',{'root':instance.State.options.xPath.root,'identifier':instance.State.identifier,'data':Object.fromEntries(result)}); 266 return result; 267 }, 268 getCacheData: function () { 269 let obj = component_kikjobs_jobhighlighter; 270 if(window[obj.CONSTANTS.keys.cache] === undefined) { 271 window[obj.CONSTANTS.keys.cache] = obj.CONSTANTS.cache.default; 272 } 273 return window[obj.CONSTANTS.keys.cache]; 274 }, 275 setCacheData: function (data) { 276 let obj = component_kikjobs_jobhighlighter; 277 window[obj.CONSTANTS.keys.cache] = data; 278 }, 279 getFilterValues: function (instance) { 280 let obj = component_kikjobs_jobhighlighter; 281 let element = obj.xPath(instance.State.options.xPath.root,document).iterateNext(); 282 let formData = new FormData(element); 283 formData = Object.fromEntries(formData); 284 let result = {}, key = null, formKeys = obj.CONSTANTS.formKeys.all(); 285 for(let index in formKeys) { 286 key = formKeys[index]; 287 result[key] = formData[key]; 288 } 289 return result; 290 }, 291 tryKey: function (instance,key,options,fallback=null) { 292 try { 293 return options[key]??fallback; 294 }catch(e) { 295 return fallback; 296 } 297 }, 298 setBusy: function (instance,mode) { 299 let obj = component_kikjobs_jobhighlighter; 300 obj.debug(instance,'Loading state',{mode: mode, identifier: instance.State.identifier, xPath: instance.State.options.xPath}); 301 obj.CONSTANTS.keys.selectors.listeners.forEac
301h( 302 (key)=>{ 303 let element = obj.xPath(instance.State.options.xPath[key],document).iterateNext(); 304 //let element = instance.State.elements[key]; 305 element.disabled = mode; 306 } 307 ); 308 }, 309 _linkDOMElements: function (instance, rootElement=null) { 310 let obj = component_kikjobs_jobhighlighter; 311 let state = instance.State, el = null; 312 obj.debug(instance, 'Registering elements', state.identifier); 313 for(let key in state.elements) { 314 if(key === obj.CONSTANTS.keys.selectors.root) { 315 el = rootElement??obj.xPath(state.options.xPath.root).iterateNext(); 316 state.elements[key] = el; 317 continue; 318 } 319 let xpath = instance.State.options.xPath[key]; 320 obj.debug(instance,'xpath',xpath); 321 let el_snapshots = obj.xPath(xpath, state.elements.root,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); 322 let len = el_snapshots.snapshotLength; 323 [0..len].forEach( 324 (index)=>{ 325 el = el_snapshots.snapshotItem(index); 326 state.elements[key] = el; 327 } 328 ); 329 } 330 instance.State = {...state}; 331 return instance; 332 }, 333 _registerListeners:function (instance) { 334 let obj = component_kikjobs_jobhighlighter; 335 let state = instance.State; 336 let element; 337 obj.CONSTANTS.keys.selectors.listeners.forEach( 338 (key)=>{ 339 element = state.elements[key]; 340 if(!element) { 341 obj.debug(instance,'invalid element', state.elements); 342 return; 343 } 344 obj.debug(instance, 'Registering onChange', element); 345 element.addEventListener( 346 'change',()=>{ 347 obj.onChange(instance,key); 348 } 349 ); 350 } 351 ); 352 353 return instance; 354 }, 355 _initializeFilterOptions:function (instance = null) { 356 let obj = component_kikjobs_jobhighlighter; 357 if(instance === null) { 358 obj.debug(instance, 'No valid instance'); 359 return; 360 } 361 let result = {}, element; 362 obj.CONSTANTS.keys.selectors.listeners.forEach( 363 (identifier)=>{ 364 365 element = instance.State.elements[identifier]; 366 console.log(instance.State.elements); 367 let parser = new DOMParser(); 368 let htmlNode = parser.parseFromString(element.innerHTML, "text/html"); 369 result[identifier]={html: htmlNode}; 370 /* 371 result[identifier] = [];
372 element.querySelectorAll(obj.CONSTANTS.keys.selectors.option).forEach((option)=>{ 373 result[identifier].push({label: option.innerHTML, value: option.value}); 374 });*/ 375 } 376 ); 377 obj.debug(null,'Cached data',{result:result}) 378 return result; 379 }, 380 debug: function (instance=null, message, context=null) { 381 let obj = component_kikjobs_jobhighlighter; 382 if(obj.CONSTANTS.debugLevel==='production') { 383 return; 384 } 385 console.log( 386 '#'+obj.CONSTANTS.namespace+': '+message, context 387 ); 388 } 389 } 390 window.addEventListener( 391 'load',function () { 392 let obj = component_kikjobs_jobhighlighter; 393 component_kikjobs_jobhighlighter.init(); 394 } 395 );
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.