1// console.log( 'FF Ajax V2 '); 2 3function FF_Ajax_2(options){ 4 5 if( !options.container ) return; 6 var _ = this; 7 8 _.options = options; 9 10 _.set_option('action', 'ff_ajax_query'); 11 _.set_option('type', 'default'); 12 13 _.container = options.container; 14 _.listings_con = _.container.querySelector('.ajax-loop'); 15 16 _.original_query_args = { ...options.query_args }; // copy original args for restoration later 17 18 _.filters = { 19 meta_query: {}, 20 tax_query: {}, 21 }; 22 23 _.ajax_request = null; 24 25 // filter indicators 26 _.filter_indicators_con = null; 27 if( typeof options.filter_indicators !== 'undefined' ) { 28 _.filter_indicators_con = _.container.querySelector(options.filter_indicators); 29 _.filter_indicators = {}; 30 } 31 32 _.load_more_init(); 33 _.filter_fields_init(); 34 35 _.container.classList.add('ff_ajax_init'); 36 37 console.log(_); 38} 39 40FF_Ajax_2.prototype.set_option = function(property, defaut_value){ 41 if( typeof this.options[property] !== 'undefined' ) { 42 this[property] =this.options[property]; 43 } 44 else { 45 this[property] = defaut_value; 46 } 47} 48 49FF_Ajax_2.prototype.filter_fields_init = function(){ 50 var _ = this; 51 _.container.querySelectorAll('.ajax_filter').forEach(field=>{ 52 if( field.nodeName == 'SELECT' ) { 53 _.filter_field_dropdown(field); 54 } 55 else if( field.classList.contains('toggle_field') ) { 56 _.filter_field_toggle(field); 57 } 58 else if( field.classList.contains('date') ) { 59 _.filter_field_date(field); 60 } 61 }) 62} 63 64FF_Ajax_2.prototype.filter_field_dropdown = function(field){ 65 var _ = this; 66 field.addEventListener('change', ()=>{ 67 68 var type = field.dataset.type; 69 var key = ( type == 'tax_query' ) ? field.dataset.taxonomy : field.dataset.metaKey; 70 71 // var filter_indicator_label = field.value; 72 // if ( typeof field.dataset.indicatorSuffix !== 'undefined' ) { 73 // filter_indicator_label = field.value +' '+ field.dataset.indicatorSuffix; 74 // } 75 76 var value = field.value; 77 var value_label = field.selectedOptions[0].text; 78 79 var filter_key = field.dataset.filterKey; 80 81 _.update_filter_query( type, key, value, filter_key ); 82 83 _.add_filter_indicator( type, key, value, value_label ); 84 85 field.value = ''; // reset field back to blank 86 87 _.apply_filters(); 88 }) 89} 90 91FF_Ajax_2.prototype.filter_field_toggle = function(field){ 92 var _ = this; 93 // console.log('filter_field_toggle', field); 94 var toggle = field.querySelector('.toggle'); 95 var type = field.dataset.type; 96 var key = ( type == 'tax_query' ) ? field.dataset.taxonomy : field.dataset.metaKey; 97 98 toggle.addEventListener('click',()=>{ 99 100 if( field.classList.contains('selected') ) { 101 // un-select 102 _.remove_filter_query(type, key); 103 } 104 else { 105 // select 106 _.update_filter_query(type, key, 1); 107 } 108 109 field.classList.toggle('selected'); 110 111 _.apply_filters(); 112 113 }); 114} 115 116FF_Ajax_2.prototype.filter_field_date = function(field){ 117 var _ = this; 118 119 var filter_key = field.dataset.metaKey; 120 var compare = field.dataset.compare; 121 122 var field_con = field.parentElement; 123 var label = field_con.querySelector('.l'); 124 125 var clear = null; 126 127 var dp = jQuery(field).datepicker({ 128 onSelect: function(dateText, instance){ 129 console.log('on select'); 130 label.textContent = field.value; 131 132 var value = _.date_query_format(field.value); 133 _.filters[filter_key] = value; 134 135 if( !clear ) { 136 // clear button 137 clear = document.createElement('div'); 138 clear.classList.add('clear'); 139 clear.addEventListener('click',()=>{ 140 clear.remove(); 141 delete _.filters[filter_key]; 142 clear = null; 143 label.textContent = label.dataset.label; 144 field.value = ''; 145 146 // _.update_filter_query_date(filter_key, '', compare); 147 148 _.update_filter_query( 'meta_query', filter_key, '' ); 149 150 _.apply_filters(); 151 152 // remove date field limits 153 set_date_field_min_max(filter_key, null); 154 }) 155 field_con.append(clear); 156 } 157 158 _.update_filter_query( 'meta_query', filter_key, value, filter_key, compare); 159 // _.update_filter_query_date(filter_key, value, compare); 160 _.apply_filters(); 161 162 // set date field limits 163 set_date_field_min_max(filter_key, field.value); 164 165 } 166 });
167 168 if( field.classList.contains('date_from') ) { 169 _.date_from_field = dp; 170 } 171 172 if( field.classList.contains('date_to') ) { 173 _.date_to_field = dp; 174 } 175 176 if( typeof _.options.min_date !== 'undefined' ) { 177 178 if( typeof _.date_from_field !== 'undefined' ) { 179 _.date_from_field.datepicker( "option", "minDate", _.options.min_date ); 180 } 181 if( typeof _.date_to_field !== 'undefined' ) { 182 _.date_to_field.datepicker( "option", "minDate", _.options.min_date ); 183 } 184 185 // fix for datepicker showing on the bottom of the page after setting an option 186 var temp = document.getElementById('ui-datepicker-div'); 187 if( temp ) { 188 temp.style.display = 'none'; 189 } 190 } 191 192 function set_date_field_min_max(filter_key, value){ 193 if( filter_key == 'start_date' && typeof _.date_to_field !== 'undefined' ) { 194 _.date_to_field.datepicker( "option", "minDate", value ); 195 } 196 if( filter_key == 'end_date' && typeof _.date_from_field !== 'undefined' ) { 197 _.date_from_field.datepicker( "option", "maxDate", value ); 198 } 199 } 200} 201 202// FF_Ajax_2.prototype.filter_field_date2 = function(field){ 203// var _ = this; 204 205// var filter_key = field.dataset.metaKey; 206// var compare = field.dataset.compare; 207 208// var field_con = field.parentElement; 209// var label = field_con.querySelector('.l'); 210 211// var clear = null; 212 213// var dp = jQuery(field).datepicker({ 214// onSelect: function(dateText, instance){ 215 216// label.textContent = field.value; 217 218// var value = _.date_query_format(field.value); 219// _.filters[filter_key] = value; 220 221// if( !clear ) { 222// // clear button 223// clear = document.createElement('div'); 224// clear.classList.add('clear'); 225// clear.addEventListener('click',()=>{ 226// clear.remove(); 227// delete _.filters[filter_key]; 228// clear = null; 229// label.textContent = label.dataset.label; 230// field.value = ''; 231 232// // _.update_filter_query_date(filter_key, '', compare); 233 234// _.update_filter_query( 'meta_query', filter_key, '' ); 235 236// _.apply_filters(); 237 238// // remove date field limits 239// set_date_field_min_max(filter_key, null); 240// }) 241// field_con.append(clear); 242// } 243 244// _.update_filter_query( 'meta_query', filter_key, value, filter_key, compare); 245// // _.update_filter_query_date(filter_key, value, compare); 246// _.apply_filters(); 247 248// // set date field limits 249// set_date_field_min_max(filter_key, field.value); 250// } 251// }); 252 253// if( field.classList.contains('date_from') ) { 254// _.date_from_field = dp; 255 256// if( typeof _.options.min_date !== 'undefined' ) { 257// _.date_from_field.datepicker( "option", "minDate", _.options.min_date ); 258// } 259// } 260 261// if( field.classList.contains('date_to') ) { 262// _.date_to_field = dp; 263// } 264 265// function set_date_field_min_max(filter_key, value){ 266// if( filter_key == 'start_date' && typeof _.date_to_field !== 'undefined' ) { 267// _.date_to_field.datepicker( "option", "minDate", value ); 268// } 269// if( filter_key == 'end_date' && typeof _.date_from_field !== 'undefined' ) { 270// _.date_from_field.datepicker( "option", "maxDate", value ); 271// } 272// } 273 274// } 275 276FF_Ajax_2.prototype.update_filter_query = function( type, key, value, filter_key = '', compare = '', compare_type = '' ){ 277 278 var _ = this; 279 280 if( type == 'post_type' ) { 281 _.options.query_args.post_type = ( value) ? value : _.original_query_args.post_type; 282 return; 283 } 284 285 if( typeof _.options.query_args[type] === 'undefined' ) {
286 _.options.query_args[type] = []; 287 } 288 289 if( !filter_key ) { 290 filter_key = key; 291 } 292 293 // console.log('update_filter_query', { type, key, value, filter_key }) 294 295 _.filters[type][key] = value; 296 297 // var type_key_name = 'taxonomy'; 298 var type_value_name = 'terms'; 299 300 if( type == 'meta_query' ) { 301 // type_key_name = 'key'; 302 type_value_name = 'value'; 303 } 304 305 // All - reset 306 if( value == 'all' || !value ) { 307 for( var i = 0; i < _.options.query_args[type].length; i++ ) { 308 // if( _.options.query_args[type][i][type_key_name] == key ) { 309 if( _.options.query_args[type][i].filter_key == filter_key ) { 310 _.options.query_args[type].splice(i, 1); 311 return; 312 } 313 } 314 return; 315 } 316 317 // check if term clause is present 318 var found = false; 319 for( var i = 0; i < _.options.query_args[type].length; i++ ) { 320 // if( _.options.query_args[type][i][type_key_name] == key ) { 321 if( _.options.query_args[type][i].filter_key == filter_key ) { 322 _.options.query_args[type][i][type_value_name] = value; 323 found = true; 324 break; 325 } 326 } 327 328 // clause not found, create new 329 if( !found ) { 330 331 var clause = { 332 taxonomy: key, 333 field: 'slug', 334 terms: value, 335 }; 336 337 if( type == 'meta_query' ) { 338 clause = { 339 key: key, 340 value: value, 341 compare: compare ? compare : '=', 342 }; 343 344 if( compare_type ) { 345 clause.type = compare_type; 346 } 347 } 348 349 clause.filter_key = filter_key; 350 351 // console.log({ 352 // type, 353 // clause, 354 // query_args: _.options.query_args, 355 // }) 356 357 _.options.query_args[type].push(clause); 358 } 359 360 // console.log( 'update_filter_query', _.options.query_args ); 361} 362 363FF_Ajax_2.prototype.update_filter_query_date = function(key, value, compare){ 364 365 var _ = this; 366 367 var query_type = 'meta_query'; 368 369 if( typeof _.options.query_args[query_type] === 'undefined' ) { 370 _.options.query_args[query_type] = []; 371 } 372 373 console.log('update_filter_query_date', {query_type, key, value, compare, args: _.options.query_args[query_type]}); 374 375 // var type_key_name = 'key'; 376 var type_value_name = 'value'; 377 378 var found = false; 379 380 for( var i = 0; i < _.options.query_args[query_type].length; i++ ) { 381 var clause = _.options.query_args[query_type][i]; 382 383 if( clause.key == key && clause.compare == compare ) { 384 // remove 385 if( !value ) { 386 _.options.query_args[query_type].splice(i, 1); 387 return; 388 } 389 390 // update 391 _.options.query_args[query_type][i][type_value_name] = value; 392 found = true; 393 break; 394 } 395 } 396 397 // clause not found, create new 398 if( !found ) { 399 _.options.query_args[query_type].push({ 400 key, 401 value, 402 compare, 403 type: 'DATE', 404 }); 405 } 406 407 // console.log( _.options.query_args[query_type] ); 408} 409 410FF_Ajax_2.prototype.remove_filter_query = function(type, key){ 411 var _ = this; 412 413 if( type == 'post_type' ) { 414 _.options.query_args.post_type = _.original_query_args.post_type; 415 return; 416 } 417 418 // var type_key_name = 'taxonomy'; 419 // if( type == 'meta_query' ) { 420 // type_key_name = 'key'; 421 // } 422 423 for( var i = 0; i < _.options.query_args[type].length; i++ ) { 424 // if( _.options.query_args[type][i][type_key_name] == key ) { 425 if( _.options.query_args[type][i].filter_key == key ) { 426 _.options.query_args[type].splice(i, 1); 427 return; 428 } 429 } 430} 431 432FF_Ajax_2.prototype.query = function(callback){ 433 434 var _ = this; 435 436 _.container.classList.add('ajax_loading') 437 438 if( _.ajax_request && typeof _.ajax_request.abort !== 'undefined' ) { 439 _.ajax_request.abort(); // abort previous request 440 } 441 442 var data = { 443 action: _.action, 444 type: _.type, 445 filters: _.filters, 446 query_args: _.options.query_args, 447 page: _.page, 448 } 449 450 // console.log('query', data); 451 452 _.ajax_request = jQuery.ajax({ 453 url: site_data.ajax_url, 454 type: "post", 455 data: data, 456 dataType : "json", 457 }).done(function(res){ 458 459 console.log('query result', res ); 460 461 if( !res.result ) { 462 jQuery(_.listings_con).html(_.options.no_results_html); 463 _.load_more_con.classList.add('hide'); 464 } 465 else { 466 467 var html_items = jQuery(res.html); 468 469 if( _.page != 1 ) { 470 // append, used for load more 471 jQuery(_.listings_con).append(html_items); 472 } else { 473 // replace content 474 jQuery(_.listings_con).html(html_items); 475 } 476 477 _.check_have_more_posts(res); 478 479 jQuery('body').trigger('ff_ajax_after_query', [ _, html_items ]); 480 481 } 482 483 if( typeof callback === 'function' ) callback(res); 484 485 _.container.classList.remove('ajax_loading') 486 });
487 488} 489 490FF_Ajax_2.prototype.apply_filters = function(){ 491 var _ = this; 492 _.page = 1; 493 console.log('apply_filters', _.filters, _.options.query_args ); 494 _.query(); 495} 496 497FF_Ajax_2.prototype.add_filter_indicator = function( type, key, value, label ){ 498 499 // console.log('add_filter_indicator', { key, value, type }) 500 var _ = this; 501 502 if( !_.filter_indicators_con ) return; 503 504 // console.log( 'add_filter_indicator', { key, value } ) 505 if( typeof _.filter_indicators[key] === 'undefined' ) { 506 // add new 507 _.create_filter_indicator_item( type, key, value, label ); 508 509 } else { 510 // update existing 511 _.update_filter_indicator_item( type, key, value, label ); 512 } 513} 514 515FF_Ajax_2.prototype.create_filter_indicator_item = function( type, key, value, label ){ 516 var _ = this; 517 518 // create element 519 var el = document.createElement('div'); 520 el.classList.add('filter_indicator'); 521 522 // text 523 var text = document.createElement('div'); 524 text.classList.add('text'); 525 526 if( !label ) label = value; 527 text.textContent = label; 528 529 el.append(text); 530 531 // remove button 532 var remove_btn = document.createElement('div'); 533 remove_btn.classList.add('remove'); 534 el.append(remove_btn); 535 536 remove_btn.addEventListener('click', ()=>{ 537 _.remove_filter_indicator(el, type, key); 538 }); 539 540 _.filter_indicators[key] = { 541 el: el, 542 text: text, 543 remove_btn: remove_btn 544 } 545 546 _.filter_indicators_con.append(el); 547} 548 549FF_Ajax_2.prototype.remove_filter_indicator = function(el, type, key){ 550 var _ = this; 551 el.remove(); 552 553 if( typeof _.filters[type] !== 'undefined' ) { 554 delete _.filters[type][key]; 555 } 556 557 delete _.filter_indicators[key]; 558 559 _.remove_filter_query(type, key); 560 _.apply_filters(); 561} 562 563FF_Ajax_2.prototype.update_filter_indicator_item = function( type, key, value, label ){ 564 var _ = this; 565 566 if( !value ) { 567 // empty value selected, remove 568 // update - this won't trigger anymore 569 _.filter_indicators[key].el.remove(); 570 571 if( typeof _.filters[type] !== 'undefined' ) { 572 delete _.filters[type][key]; 573 } 574 575 delete _.filter_indicators[key]; 576 577 return; 578 } 579 580 if( !label ) label = value; 581 582 // change 583 _.filter_indicators[key].text.textContent = label; 584} 585 586FF_Ajax_2.prototype.load_more_init = function(){ 587 var _ = this; 588 589 _.page = 1; 590 591 _.load_more_loading = false; 592 _.load_more_con = _.container.querySelector('.load-more-con'); 593 _.load_more_btn = _.load_more_con.querySelector('.load_more_btn'); 594 _.have_more_posts = !_.load_more_con.classList.contains('hide'); 595 596 _.load_more_btn.addEventListener('click', ()=>{ 597 // console.log('load more click'); 598 if( !_.have_more_posts ) return; 599 if( _.load_more_loading ) return; 600 _.load_more_loading = true; 601 _.page++; 602 _.load_more_btn.classList.add('loading'); 603 _.query(res =>{ 604 console.log('after load more', res); 605 _.load_more_loading = false; 606 _.load_more_btn.classList.remove('loading'); 607 }); 608 }); 609 610} 611 612FF_Ajax_2.prototype.check_have_more_posts = function(res){ 613 var _ = this; 614 _.have_more_posts = res.have_more_posts; 615 616 if( _.have_more_posts ) { 617 _.load_more_con.classList.remove('hide'); 618 } else { 619 _.load_more_con.classList.add('hide'); 620 } 621} 622 623FF_Ajax_2.prototype.date_query_format = function(date_text){ 624 var temp = date_text.split('/'); 625 626 // Y-m-d 627 // return temp[2] +'-'+ temp[0] +'-'+ temp[1]; 628 629 // Ymd 630 return temp[2] + temp[0] + temp[1]; 631}
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.