1/** 2 * Some utility functions for date time adding and reconversion 3 */ 4 5 6function getRegionDateFormat() { 7 return gettext('date_format_place_holder') !== "date_format_place_holder" ? gettext('date_format_place_holder') : "MM/DD/YYYY" 8} 9 10var Utils = Utils || { 11 //add one more day into a date object 12 addDays: function (date, amount) { 13 var tzOff = date.getTimezoneOffset() * 60 * 1000, 14 t = date.getTime(), 15 d = new Date(), 16 tzOff2; 17 18 t += (1000 * 60 * 60 * 24) * amount; 19 d.setTime(t); 20 21 tzOff2 = d.getTimezoneOffset() * 60 * 1000; 22 if (tzOff != tzOff2) { 23 var diff = tzOff2 - tzOff; 24 t += diff; 25 d.setTime(t); 26 } 27 return d; 28 }, 29 getStringfromDate: function (date) { 30 //get component of date from it 31 var day = date.getDate(); 32 var month = date.getMonth(); 33 var year = date.getFullYear(); 34 35 //since the function return month in 0-11 format 36 month = month + 1; 37 38 //add 0 to day or month in some cases below 39 day = (day < 10 ? '0' : '') + day; 40 month = (month < 10 ? '0' : '') + month; 41 42 return month + '/' + day + '/' + year; 43 }, 44 //a compilation of those functions 45 addDayToString: function (date, amount) { 46 var dateObj = new Date(date); 47 var adjustedDateObj = Utils.addDays(dateObj, amount); 48 return Utils.getStringfromDate(adjustedDateObj); 49 } 50}; 51 52function debounce(fn, delay) { 53 let timer = null; 54 return function () { 55 const context = this; 56 const args = arguments; 57 58 clearTimeout(timer); 59 timer = setTimeout(function () { 60 fn.apply(context, args); 61 }, delay); 62 }; 63} 64 65/* Submission */ 66Searcher.extend('MainSearchOpts', { 67 init: function (el, opts) { 68 this._super(el, opts); 69 70 this.refresh = false; 71 this.target = "/search/search"; 72 this.content = $(".js-search-result"); 73 this.hits = $(".js-result-text"); 74 this.pagination = $(".js-pagination"); 75 this.export_button = $("#export_button"); 76 this.save_tooltip = $(".save_icon"); 77 this.view_tooltip = $(".view_fav"); 78 this.keyword_search = $("#keyword-in"); 79 this.template_id = this.options.query.template_id; 80 81 this.query = debounce(this.query.bind(this), 500); 82 }, 83 "query": function (save_offset, refresh_hits) { 84 if (save_offset === undefined) { 85 this.query_ob.remove_offset(); 86 } else if (save_offset) { 87 //var y_scroll = $("#results_and_filters_holder").offset().top; //Top of the actual results 88 //window.scrollTo(0, y_scroll); 89 } 90 var kws = this.build_search_text(); 91 // console.log("keyword search: " + kws); 92 if (kws.length > 0) { 93 this.query_ob.add_searchtext(kws); 94 } else { 95 this.query_ob.remove_searchtext(); 96 } 97 this._super(refresh_hits);//refresh_hits can be undefined, we'll catch it in superclass. 98 $("#limit").val(this.query_ob.limit); 99 }, 100 escapeHtml: function (value) { 101 return String(value || ''); 102 }, 103 build_search_text: function () { 104 var search_text = ""; 105 var template_id = this.template_id; 106 var self = this; 107 108 if (typeof(window.smartSearchQuery)!=='undefined' && typeof(window.smartSearchQuery.value)!=='undefined') { 109 // Check if element with class query_form has class hidden or not using Jquery 110 // If it has class hidden, then return the value of the smart search query 111 // Else, return the value of the search input 112 if (!$('.query_form').hasClass('hidden')) {
113 return window.smartSearchQuery.value(); 114 } 115 } 116 var val = $.trim($('.js-search-input').val()); 117 if (template_id) { 118 return val; 119 } 120 $(".js-search-input").each(function () { 121 if ($(this).attr("default") == "on") { 122 return true; //Skip defaults 123 } 124 125 var ktype = $(this).attr("ktype"); 126 var input = self.escapeHtml($(this).val()).trim(); 127 128 if (input.length > 0) { 129 130 var extractReg = /[-]?\"[^\"]*\"|[+]?\"[^\"]*\"|[-]?\'[^\'']*\'|[+]?\'[^\'']*\'|\S+/gi; 131 var checkQuoteReg = /[-]?\"[^\"]*\"|[+]?\"[^\"]*\"|[-]?\'[^\'']*\'|[+]?\'[^\'']*\'+/gi; 132 133 //GS 2.6.2: support comma as separators as well 134 testCommaInput = [input]; 135 136 var usedComma = testCommaInput.length > 1; 137 138 for (var i = 0; i < testCommaInput.length; i++) { 139 140 var values; 141 142 inputItem = jQuery.trim(testCommaInput[i]); 143 //if comma is used, and a part of it is not using quotes, treat it as one phrase 144 var testMatches = inputItem.match(checkQuoteReg); 145 //also check if this is a phrase or a word 146 var checkSpaces = inputItem.replace(/ +/g, ' ').split(' '); 147 if (!testMatches && checkSpaces.length > 1 && usedComma) { 148 //add quote to the inputItem 149 inputItem = '"' + inputItem + '"'; 150 values = [inputItem]; 151 } else { 152 values = inputItem.match(extractReg); 153 } 154 if (values) { 155 var full = true; 156 $(values).each(function () { 157 value = $.trim(this); 158 if (value.length > 0) { 159 var first = value[0]; 160 if (first == '+' || first == '-') value = value.substring(1); 161 var quoted = value.length > 1 && value[0] == value[value.length - 1] && (value[0] == '"' || value[0] == '\''); 162 if (quoted) value = value.substring(1, value.length - 1); 163 if (value[0] == "(") quoted = true; 164 165 if (value.length > 0) { 166 if (ktype == "exclude") { 167 search_text += ' ' + (value[0] != '-' ? '-' : '') + (quoted ? '"' + value + '"' : value); 168 } else if (ktype == "all") { 169 search_text += ' ' + (value[0] != '+' ? '+' : '') + (quoted ? '"' + value + '"' : value); 170 } else if (ktype == "in") { 171 search_text += ' ' + (quoted ? '"' + value + '"' : value); 172 } else if (ktype == "exact") { 173 full = full && !quoted; 174 } 175 } 176 } 177 }); 178 if (ktype == "exact") { 179 if (full) { 180 search_text += ' +"' + inputItem + '"'; 181 } else { 182 $(values).each(function () { 183 value = $.trim(this); 184 if (value.length > 0) { 185 var first = value[0]; 186 if (first == '+' || first == '-') value = value.substring(1); 187 var quoted = value.length > 1 && value[0] == value[value.length - 1] && (value[0] == '"' || value[0] == '\''); 188 if (quoted) value = value.substring(1, value.length - 1); 189 190 if (value.length > 0) { 191 search_text += ' +"' + value + '"'; 192 } 193 } 194 }); 195 } 196 } 197 } 198 } 199 } 200 }); 201 var keyword_text = $.trim(search_text); 202 // 203 // if (typeof(window.smartSearchQuery)!=='undefined' && typeof(window.smartSearchQuery.value)!=='undefined') { 204 // // Check if element with class query_form has class hidden or not using Jquery 205 // // If it has class hidden, then return the value of the smart search query 206 // // Else, return the value of the search input 207 // if ($('.query_form').hasClass('hidden')) { 208 // window.smartSearchQuery.setVal(keyword_text); 209 // } 210 // } 211 return keyword_text; 212 } 213}); 214 215$.Controller("SortHandler", { 216 init: function (el, opts) { 217 var control = this; 218 this.element.sortable({ 219 handle: ".advanced_item", 220 placeholder: "advanced_holder_highlight", 221 update: function () { 222 control.update_order(); 223 } 224 }); 225 226 this.original_order = ["subject", "sponsors", "earliest_submission", "type", "grant_types", "status", "is_limited", "applicant_types"]; 227 228 this.element.hide(); 229 this.set_order(); 230 this.element.show(); 231 232 this.set_hidden(); 233 }, 234 ".advanced_minimize_holder click": function (el, ev) { 235 this.minimize(el); 236 this.update_hidden(); 237 }, 238 minimize: function (el) { 239 var maximize = $(".advanced_maximize", el); 240 if (maximize.length == 0) { 241 el.append("<div class='advanced_maximize'></div>"); 242 el.parents(".advanced_holder").find(".options").slide
242Up(); 243 } else { 244 maximize.remove(); 245 el.parents(".advanced_holder").find(".options").slideDown(); 246 } 247 }, 248 update_order: function () { 249 var order = this.element.sortable("toArray", { attribute: "for" }); 250 251 var same = true; 252 for (i = 0; i < order.length; i++) { 253 if (order[i] != this.original_order[i]) { 254 same = false; 255 break; 256 } 257 } 258 259 if (same) { 260 $.cookie('filter_order', null, { path: '/' }); 261 } else { 262 $.cookie('filter_order', { "order": order }, { expires: 3600, path: '/' }); 263 } 264 }, 265 set_order: function () { 266 var order = $.cookie("filter_order"); 267 if (order == null) { 268 return true; 269 } 270 271 var objects = {}; 272 273 this.element.find("li").each(function () { 274 var for_li = $(this).attr("for"); 275 276 if (jQuery.inArray(for_li, order['order']) < 0) { 277 order['order'].push(for_li); 278 } 279 280 objects[for_li] = $(this).detach(); 281 }); 282 283 var control = this; 284 $.each(order['order'], function (i, v) { 285 control.element.append(objects[v]); 286 }); 287 }, 288 update_hidden: function () { 289 var control = this; 290 var hidden_list = {}; 291 this.element.find(".advanced_maximize").each(function () { 292 var for_li = $(this).parents(".advanced_holder").attr("for"); 293 hidden_list[for_li] = true; 294 }); 295 296 if ($.isEmptyObject(hidden_list)) { 297 $.cookie('filter_hidden', null, { path: '/' }); 298 } else { 299 $.cookie('filter_hidden', hidden_list, { expires: 3600, path: '/' }); 300 } 301 }, 302 set_hidden: function () { 303 /*If we need to, this can be inlined with set_order, 304 since we iterate over the pieces anyway, except we don't 305 if they're in natural order already*/ 306 var hidden = $.cookie("filter_hidden"); 307 if (hidden == null) { 308 return true; 309 } 310 control = this; 311 $.each(hidden, function (i, v) { 312 /*Uh.... */ 313 var mini = control.element.find("li[for='" + i + "']").find(".advanced_minimize_holder"); 314 control.minimize(mini); 315 }); 316 } 317}); 318 319 320/*Search Tools*/ 321MainSearchOpts.extend("SearchTools", { 322 init: function (el, opts) { 323 this._super(el, opts); 324 325 this.out_pickerr = this.options.export_picker; //By Deep 326 327 if (this.query_ob.edit === true) { 328 $(".js-action-save").addClass('disabled'); 329 } 330 331 $('.save-search-popup').save_alert_form({ "query": this.query_ob }); 332 $('.load-search-popup').load_alert_form({ "query": this.query_ob }); 333 334 this.exportOptionsPopover = new PopoverUtils({ 335 trigger: '#export-grant-selection-trigger', 336 content: '#export-grant-selection', 337 ignoreCloseEl: ".js-action-export", 338 id: "Export Popover" 339 }) 340 341 this.selectedGrantIds = []; 342 $(document).on("czd_grant_selection_change", function (_, data){ 343 this.selectedGrantIds = Array.from(data.selectedGrants) 344 }.bind(this)); 345 346 //preventing non-reloading nature of the remote modal call 347 // $(document).on('hidden.bs.modal', '.save-search-popup', function () { 348 // $(this).find('.modal-content').html(''); 349 // $(this).removeData('bs.modal'); 350 // }); 351 }, 352 ".js-action-export click": function (el, ev) { 353 if (el.hasClass("disabled")) { 354 return false; 355 } 356 if (this.selectedGrantIds.length) { 357 this.exportOptionsPopover.togglePopover() 358 return; 359 } 360 361 this.out_pickerr.export_picker("show_picker", el); 362 }, 363 // Export options handler 364 '.js-export-selected-grants click': function (el) { 365 this.out_pickerr.export_picker("show_picker", el, { 366 selectedGrantIds: this.selectedGrantIds 367 }); 368 }, 369 '.js-export-all-result click': function (el) {
370 this.out_pickerr.export_picker("show_picker", el); 371 }, 372 "#sort change": function (el) { 373 this.query_ob.add_sortby(el.val()); 374 this.query(undefined, false);//We don't want to save the page, but we do want to block hit refresh.. 375 //2.4.1: trackers 376 _trackGSEvent( 377 '2.0-Search', 378 'sort_change', 379 el.val() 380 ); 381 }, 382 "#direction change": function (el) { 383 this.query_ob.sortby = $("#sort").val(); 384 this.query_ob.add_sortDirection(el.val()); 385 this.query(undefined, false);//We don't want to save the page, but we do want to block hit refresh.. 386 //2.4.1: trackers 387 _trackGSEvent( 388 '2.0-Search', 389 'sort_direction_change', 390 el.val() 391 ); 392 }, 393 "#limit change": function (el) { 394 this.query_ob.add_limit(el.val()); 395 this.query(undefined, false);//We don't want to save the page, but we do want to block hit refresh.. 396 //2.4.1: trackers 397 _trackGSEvent( 398 '2.0-Search', 399 'limit_change', 400 el.val() 401 ); 402 }, 403 ".js-action-save click": function (el, ev) { 404 if (el.hasClass("disabled")) { 405 ev.preventDefault(); 406 return false; 407 } 408 //disable caching on IE8 by using timestamp 409 var date = new Date(); 410 $('.save-search-popup').data('js-refocus-target', '.btn-action-save').modal({ 411 remote: "/user/render_save_alert_form?t=" + date.getTime() 412 }); 413 414 //2.4.1: trackers 415 _trackGSEvent( 416 '2.0-Search', 417 'save_search_open', 418 '' 419 ); 420 }, 421 ".js-action-load click": function (el, ev) { 422 if (el.hasClass("disabled")) { 423 ev.preventDefault(); 424 return false; 425 } 426 var date = new Date(); 427 $('.load-search-popup').data('js-refocus-target', '.btn-action-save').modal({ 428 remote: "/user/render_load_alert_form?t=" + date.getTime() 429 }); 430 431 //2.4.1: trackers 432 _trackGSEvent( 433 '2.0-Search', 434 'load_search_open', 435 '' 436 ); 437 }, 438 ".js-action-share click": function (el, ev) {
439 this.getSearchUrl(function (url) { 440 if (el.hasClass("disabled")) { 441 ev.preventDefault(); 442 return false; 443 } 444 var date = new Date(); 445 446 $("#shared-link").val(url); 447 $('.share-search-popup').data('js-refocus-target', el).modal('show'); 448 449 //2.4.1: trackers 450 _trackGSEvent( 451 '2.0-Search', 452 'shared_search_open', 453 '' 454 ); 455 }, function () { /** error callback */ 456 bootbox.alert('There were some problems with sharing search right now, please try again in a short while!'); 457 }); 458 }, 459 // Get Search Url 460 // Params: callback function for when Done 461 // @params function cbError callback when the function got an error 462 getSearchUrl: function (cbDone, cbError) { 463 var control = this; 464 var search_params = this.query_ob.construct(false); 465 var editorMode ='basic'; 466 if($('.query_form').length>0 && !$('.query_form').hasClass('hidden')) { 467 editorMode='advanced'; 468 } 469 var search_text = this.build_search_text(); 470 solr_search = null; 471 if (search_params) { 472 solr_search = search_params['qs']; 473 } 474 if (this.query_ob.sortby) { 475 var sort_field = this.query_ob.sortby; 476 var sort_direction = this.query_ob.sortDirection; 477 var input = JSON.stringify({ 'solr_search': solr_search, 'search_text': search_text, 'sort_field': sort_field, 'editor_mode': editorMode, 'sort_direction': sort_direction }); 478 } 479 else { 480 var input = JSON.stringify({ 'solr_search': solr_search, 'search_text': search_text, 'editor_mode': editorMode }); 481 } 482 483 $.ajax({ 484 type: "POST", 485 url: "/search/get_shared_search_url", 486 data: { 487 input: input 488 }, 489 dataType: "json", 490 success: function (response) { 491 if (response && response.status === 1) { 492 if (cbDone) 493 cbDone(response.data); 494 } 495 else { 496 if (typeof (cbError) == 'function') { 497 cbError(response.message); 498 } 499 } 500 }, 501 error: function (xhr, status, errorThrown) { 502 if (typeof (cbError) == 'function') { 503 cbError(response.message); 504 } 505 } 506 }); 507 }, 508}); 509 510/*Loader*/ 511MainSearchOpts.extend("QueryLoader", { 512 init: function (el, opts) { 513 this._super(el, opts); 514 515 if (typeof (opts.applicant_locations_filter) != 'undefined') { 516 this.applicantLocationFilter = opts.applicant_locations_filter; 517 } 518 519 if (typeof (opts.activity_locations_filter) != 'undefined') { 520 this.activityLocationFilter = opts.activity_locations_filter; 521 } 522 523 if (typeof (opts.amount_filter) != 'undefined') { 524 this.amountFilter = opts.amount_filter; 525 } 526 527 if (typeof (opts.cfda_filter) != 'undefined') { 528 this.cfdaFilter = opts.cfda_filter; 529 } 530 531 if (typeof (opts.applicant_type_filter) != 'undefined') { 532 this.applicantTypeFilter = opts.applicant_type_filter; 533 } 534 535 if (typeof (opts.sponsor_filter) != 'undefined') { 536 this.sponsorFilter = opts.sponsor_filter; 537 } 538 if (typeof (opts.sponsor_country_filter) != 'undefined') { 539 this.sponsorCountryFilter = opts.sponsor_country_filter; 540 } 541 542 if (typeof (opts.citizenship_filter) != 'undefined') { 543 this.citizenshipFilter = opts.citizenship_filter; 544 } 545 546 this.searchFilterToggle = typeof (opts.searchFilterToggle) != 'undefined' ? opts.searchFilterToggle : null; 547 548 this.func_map = { 549 "subject": this.set_subject, 550 "sponsors": this.set_sponsors, 551 "earliest_submission": this.set_date, 552 "type": this.set_advanced_input, 553 "grant_types": this.set_advanced_input, 554 "status": this.set_advanced_input, 555 "is_limited": this.set_advanced_input, 556 // "applicant_locations": this.set_applicant_locations 557 558 /*"type":this.set_advanced, 559 "grant_types":this.set_advanced, 560 "status":this.set_basic, 561 "is_limited":this.set_basic, 562 "applicant_types":this.set_basic*/ 563 }; 564 this.render(); 565 }, 566 render: function () { 567 //console.log("QueryLoader render"); 568 //Clear keywords - contained within this controller 569 //query_loader('render'); 570 if (this.element.find(".js-search-input").length > 0) 571 this.element.find(".js-search-input").val(""); 572 573 //Clear categories 574 $(".js-category-items").selected_categories("clear_selected", false); 575 576 //Clear dates 577 // $('#date-filter .js-clear-input > a').click(); 578 $("#date-filter").date_filter("clear_input", false); 579 $("#date-filter").date_filter("clear_relative_deadline", false); 580 581 //The rest 582 $('.js-advanced-input').removeClass('input-active').removeClass('input-negative'); 583 $('.advanced-input-control-negative').removeClass('active'); 584 $('.advanced-input-control-positive').removeClass('active'); 585 586 //sort by also needs resetting (GS 2.5 fix) 587 $('#sort').val(''); 588 $('#direction').val(''); 589 590 $('#limit').val(''); 591 592 this.load_limit(); 593 594 this.load_offset(); 595 596 this.load_sortby(); 597 this.load_sortDirection(); 598 599 this.load_searchtext(); 600 this.load_advanced();//This will also unhide any filters that are active 601 this.load_relative_deadline(); 602 603 this.load_amount(this); //if there is anything to load 604 605 this.load_cfda(this); 606 607 this.load_applicant_type(this); 608 609 this.load_sponsor(this); 610 611 this.load_sponsor_country(this); 612 613 this.load_applicant_locations(this); 614 615 this.load_activity_locations(this); 616 617 this.load_citizenship(this); 618 619 this.query(true); 620 621 if (this.searchFilterToggle != null) 622 this.searchFilterToggle.checkOpenFilter(); 623 }, 624 load_limit: function () { 625 $("#limit").val(this.query_ob.limit); 626 }, 627 load_offset: function () { 628 //Offset always points to the next page, so if we don't "rewind," then refreshing will move up pages 629 // pos = $.inArray(this.query_ob.current_offset, this.query_ob.offset) - 1; 630 // if (pos < 0) { 631 // pos = 0; 632 // } 633 // var offset = this.query_ob.offset; 634 // this.query_ob.add_offset(offset[pos]); 635 }, 636 load_sortby: function () { 637 $("#sort").val(this.query_ob.sortby); 638 this.query_ob.add_sortby(this.query_ob.sortby, false); 639 }, 640 load_sortDirection: function () { 641 $("#direction").val(this.query_ob.sortDirection); 642 this.query_ob.add_sortDirection(this.query_ob.sortDirection); 643 }, 644 load_searchtext: function () { 645 // If the search text is null or undefine, assign "" into that 646 if (this.query_ob.search_text == null || this.query_ob.search_text == undefined) { 647 this.query_ob.search_text = ""; 648 } 649 650 // Check if this.query_ob.search_text is advance mode or not by check if query including title:(), description:(, AND, OR 651 var isAdvanceMode = this.query_ob.search_mode == "advanced" ? true : false;
652 window.isBasicMode = !isAdvanceMode; 653 654 if ((typeof(window.smartSearchQuery)!=='undefined' && typeof(window.smartSearchQuery.value)!=='undefined') || isAdvanceMode) { 655 window.smartSearchQuery.setVal(this.query_ob.search_text); 656 // Wait for a small delay before refreshing the view 657 setTimeout(() => { 658 window.smartSearchQuery.refreshView(); 659 }, 100); 660 if (typeof(window.smartSearchResponse)!=='undefined' && typeof(window.smartSearchResponse.original_query)!=='undefined') { 661 // Fill in text area with id smart-search-prompt with the original query 662 $('#smart-search-prompt').val(window.smartSearchResponse.original_query); 663 } 664 // return ; 665 } 666 // If the search text is not in advance mode, then fill in the search input 667 if(isAdvanceMode == false){ 668 var values = this.query_ob.search_text.match(/[[^\]]*\]|[-]?\"[^\"]*\"|[+]?\"[^\"]*\"|[[^\]]*\]|[-]?\'[^\'']*\'|[+]?\'[^\'']*\'|\S+/gi); 669 var normalize = function (str) { 670 if (typeof str == 'string') { 671 if (str.length > 0 && (str[0] == '+' || str[0] == '-')) { 672 str = str.substring(1); 673 } 674 if (str.length > 1 && (str[0] == '\'' && str[str.length - 1] == '\'')) { 675 str = '"' + str.substring(1, str.length - 2) + '"'; 676 } 677 // if (str.length > 1 && (str[0] == '"' && str[str.length-1] == '"')) { 678 // str = str.substring(1, str.length-2); 679 // } 680 } 681 return str; 682 }; 683 var keyword_box = { 684 "in": [], 685 "exact": [], 686 "all": [], 687 "exclude": [] 688 }; 689 if (values != null) { 690 $(values).each(function () { 691 var value = $.trim(this); 692 if (value.length > 0) { 693 var first = value[0]; 694 if (first == '+' || first == '-') value = value.substring(1); 695 var quoted = value.length > 1 && value[0] == value[value.length - 1] && (value[0] == '"' || value[0] == '\''); 696 if (quoted) value = value.substring(1, value.length - 1); 697 698 if (first == '-') { 699 keyword_box['exclude'].push(quoted ? '"' + value + '"' : value); 700 } else if (first == '+') { 701 keyword_box['all'].push(quoted ? '"' + value + '"' : value); 702 } else { 703 keyword_box['in'].push(quoted ? '"' + value + '"' : value); 704 } 705 } 706 }); 707 } 708 709 $.each(keyword_box, function (i, v) { 710 try { 711 if (v.length > 0) { 712 var value = v.join(" "); 713 if (i == "exact" && v.length == 1 && (value.length > 1 && value[0] == value[value.length - 1] && (value[0] == '"' || value[0] == '\''))) value = value.substring(1, value.length - 1); 714 var el = $("#keyword-" + i + ""); 715 el.attr("default", "off"); 716 el.val(value); 717 } 718 } catch (e) { } 719 }); 720 721 if (keyword_box["exact"].length > 0 || 722 keyword_box["in"].length > 0 || 723 keyword_box["exclude"].length > 0) { 724 725 $(".js-keyword-options").addClass('advanced'); 726 } 727 $(".more-operator").removeClass('hidden'); 728 $('.less-operator').addClass('hidden'); 729 $('.keyword_form').removeClass('hidden'); 730 $('.query_form').addClass('hidden'); 731 $('.suggested-keyword-old-ctn').removeClass('hidden'); 732 } 733 else{ 734 $(".more-operator").addClass('hidden'); 735 $('.less-operator').removeClass('hidden'); 736 $('.keyword_form').addClass('hidden'); 737 $('.query_form').removeClass('hidden'); 738 $('.suggested-keyword-old-ctn').addClass('hidden'); 739 } 740 }, 741 load_advanced: function () { 742 var control = this; 743 var filter_hidden = $.cookie("filter_hidden"); 744 if (filter_hidden == null) { 745 filter_hidden = {}; 746 } 747 $(".js-filter-item").each(function () { 748 var attr_for = $(this).attr("for"); 749 750 if (!(attr_for in control.query_ob.advanced)) { 751 return true; 752 } 753 754 delete filter_hidden[attr_for]; //Any filter in use should not be minimized 755 756 var func = control.func_map[attr_for]; 757 if (typeof (func) == 'function') { 758 func($(this), control, attr_for); 759 } 760 }); 761 762 //when we query with both continuous status, and deadline 763 //the continuous status will be ignored 764 //we wouldn't need to change anything on logic side 765 //but we should show something that is more explicit to users 766 //deactivate it if it is active, then disable the button 767 768 var continuousButton = $('.status-filter-Continuous'); 769 if (control.query_ob.advanced && control.query_ob.advanced['status']) { 770 if (Object.keys(control.query_ob.advanced['status']).length == 1 && control.query_ob.advanced['status']['Continuous'] && control.query_ob.advanced['earliest_submission']){ 771 //remove logically 772 control.query_ob.remove_advanced("status", 'Continuous'); 773 //then aesthetically 774 continuousButton.removeClass('input-active'); 775 } 776 } 777 778 // if (control.query_ob.advanced && control.query_ob.advanced['earliest_submission']) { 779 // //remove logically 780 // control.query_ob.remove_advanced("status", 'Continuous'); 781 // //then aesthetically 782 // continuousButton.removeClass('input-active'); 783 784 // continuousButton 785 // .addClass('disabled').attr('aria-disabled', 'true') 786 // .attr('title', 'This option is unavailable when a deadline is selected.'); 787 // } 788 789 // if ( typeof(control.query_ob.advanced['has_applicant_locations']) != 'undefined' && typeof(control.query_ob.advanced['has_applicant_locations']['1']) != 'undefined' ){ 790 // $('.include-unspecified input').prop('checked', true); 791 // }else{ 792 // $('.include-unspecified input').prop('checked', false); 793 // } 794 795 if ($.isEmptyObject(filter_hidden)) {//Update the filter hidden cookie 796 $.cookie('filter_hidden', null, { path: '/' }); 797 } else { 798 $.cookie('filter_hidden', filter_hidden, { expires: 3600, path: '/' }); 799 } 800 }, 801 load_relative_deadline: function () { 802 var control = this; 803 if ("relative_deadline" in control.query_ob.advanced) { 804 $.each(control.query_ob.advanced["relative_deadline"], function (index, ob) { 805 //remove logically 806 // var continuousButton = $('.status-filter-Continuous'); 807 // control.query_ob.remove_advanced("status", 'Continuous'); 808 // //then aesthetically 809 // continuousButton.removeClass('input-active'); 810 811 // continuousButton 812 // .addClass('disabled').attr('aria-disabled', 'true') 813 // .attr('title', 'This option is unavailable when a deadline is selected.'); 814 815 $("#relative-deadline-type").val(ob['type']); 816 $("#relative-deadline-direction").val(ob['direction']); 817 $("#relative-deadline-count").val(ob['count']); 818 $("#relative-deadline-unit").val(ob['unit']); 819 }); 820 821 $('.button-change-deadline-mode .relative-option').trigger('click'); 822 } 823 }, 824 set_subject: function (el, control) { 825 var selected_categories = $(".js-category-items"); 826 827 $.each(control.query_ob.advanced['subject'], function (i, v) { 828 selected_categories.selected_categories("add_element", i, false); 829 }); 830 831 }, 832 set_sponsors: function (el, control) {
833 var selected_sponsors = $(".js-sponsor-items"); 834 $.each(control.query_ob.advanced['sponsors'], function (i, v) { 835 selected_sponsors.selected_sponsors("add_element", i, false); 836 }); 837 838 }, 839 set_date: function (el, control) { 840 if ("earliest_submission" in control.query_ob.advanced) { 841 $('.button-change-deadline-mode .absolute-option').trigger('click'); 842 $.each(control.query_ob.advanced["earliest_submission"], function (i, v) { 843 if (v == ">") { 844 var date = control.convertQueryToLocalDate(i); 845 $("#date-before").val(date).trigger("change"); 846 $('#date-before').attr('old_date', i); 847 } else if (v == "<") { 848 i = Utils.addDayToString(i, -1); 849 var date = control.convertQueryToLocalDate(i) 850 $("#date-after").val(date).trigger("change"); 851 $('#date-after').attr('old_date', Utils.addDayToString(i, 1)); 852 } 853 var minDate = new Date(control.dateTimeConvertable($("#date-before"))); 854 var maxDate = new Date(control.dateTimeConvertable($('#date-after'))); 855 $("#date-before").duet_date_picker("option", "maxDate", maxDate); 856 $("#date-after").duet_date_picker("option", "minDate", minDate); 857 }); 858 el.date_filter("add_clear", $("#date-before")); 859 } 860 }, 861 convertQueryToLocalDate: function (date) { 862 var format = gettext("date_format_place_holder"); 863 return moment(date).format(format); 864 }, 865 set_advanced_input: function (el, control, attr_for) { 866 jQuery.each(el.find(".js-advanced-input"), function (idx, elm) { 867 var val = $(elm).val(); 868 if (control.query_ob.advanced[attr_for] && control.query_ob.advanced[attr_for][val]) { 869 var operator = control.query_ob.advanced[attr_for][val]; 870 871 if (operator == '!=') { 872 $(elm).addClass('input-negative').attr('aria-pressed', 'true'); 873 $(elm).siblings('.advanced-input-control-negative').addClass('active').attr('aria-pressed', 'true'); 874 } else if (operator == '=') { 875 $(elm).addClass('input-active').attr('aria-pressed', 'true'); 876 $(elm).siblings('.advanced-input-control-positive').addClass('active').attr('aria-pressed', 'true'); 877 } 878 } 879 }); 880 }, 881 /*set_advanced: function(el, control, attr_for) { 882 el.find(".advanced_input").each(function(){ 883 var input_el = $(this).find("input.advanced_input_button"); 884 var input_val = input_el.val(); 885 if (input_val in control.query_ob.advanced[attr_for]) { 886 el.advanced_filter("toggle_advanced_selected", input_el); 887 888 var operator = control.query_ob.advanced[attr_for][input_val]; 889 $(this).find("select.advanced_input_select").data("selectBox-selectBoxIt").selectOption(operator); 890 } 891 }); 892 }, 893 set_basic: function(el, control, attr_for) { 894 el.find(".advanced_input_basic").each(function(){ 895 var input_el = $(this); 896 var input_val = input_el.val(); 897 if (input_val in control.query_ob.advanced[attr_for]) { 898 el.advanced_filter("toggle_basic_selected", input_el); 899 } 900 }); 901 } 902 set_locations: function(el, control){ 903 if ( typeof(control.query_ob.advanced['grant_location']) == 'undefined' ){ 904 return; 905 } 906 for ( var location in control.query_ob.advanced['grant_location'] ){ 907 control.locationFilter.addFilter(location, control.query_ob.advanced['grant_location'][location]); 908 } 909 },*/ 910 load_applicant_locations: function (control) { 911 control.applicantLocationFilter.load(); 912 }, 913 load_activity_locations: function (control) { 914 control.activityLocationFilter.load(); 915 }, 916 load_amount: function (control) { 917 control.amountFilter.load(); 918 }, 919 load_cfda: function (control) { 920 control.cfdaFilter.load(); 921 }, 922 load_applicant_type: function (control) { 923 control.applicantTypeFilter.load(); 924 }, 925 load_sponsor: function (control) { 926 control.sponsorFilter.load(); 927 }, 928 load_sponsor_country: function (control) { 929 control.sponsorCountryFilter.load(); 930 }, 931 load_citizenship: function (control) { 932 control.citizenshipFilter.load(); 933 }, 934 dateTimeConvertable: function (date_picker) { 935 //when access datepicker without choosing date it is default to 1/1/1970 when new date a null date 936 if (typeof date_picker === "string") { 937 var format = getRegionDateFormat(); // get local format 938 return moment(date_picker, format).format("MM/DD/YYYY"); // convert it back to en-us for search 939 }else if (date_picker instanceof jQuery && typeof date_picker.duet_date_picker === "function"){ 940 var datepicker_string = date_picker.duet_date_picker("getDate") || ""; 941 if (!datepicker_string) return datepicker_string; 942 var format = date_picker.next("duet-date-picker").attr("format"); 943 return moment(datepicker_string, format).format("MM/DD/YYYY"); // convert it back to en-us for search 944 }else { 945 return "" 946 } 947 }, 948}); 949 950/*Search Box*/ 951MainSearchOpts.extend("SearchBox", { 952 init: function (el, opts) { 953 this._super(el, opts); 954 955 this.extra_search = $(".js-extra-search"); 956 this.primary_search = $("#keyword-in"); 957 958 /*$(".search_input").one("keypress focus click", function(){ 959 if ($(this).attr("default") == "off") { 960 return true; 961 } 962 $(this).attr("default", "off"); 963 $(this).val(""); 964 });*/ 965 this._sanitizeTextField = function () { 966 jQuery.each(this.element.find(".js-search-input"), function (idx, elm) { 967 var val = jQuery.trim($(elm).val()); 968 if (val === '') { 969 $(elm).val(""); 970 } 971 }); 972 } 973 974 // this._check = function(){ 975 // let check = 0; 976 // jQuery.each( this.element.find(".js-search-input"), function(idx, elm){ 977 // var val = jQuery.trim( $(elm).val() ); 978 // if ( val === '' ){ 979 // $(elm).val(""); 980 // } else { 981 // check = 1; 982 // } 983 // }); 984 // if ( check==0 ) { 985 // this.element.toggleClass('advanced'); 986 // } 987 // this.element.toggleClass('advanced'); 988 // } 989 }, 990 ".js-search-advanced-toggle click": function (el, ev) { 991 this.element.toggleClass('advanced'); 992 }, 993 ".js-search-submit click": function (el, ev) { 994 console.log('search submit'); 995 this._sanitizeTextField(); 996 this._fireSearchKeywordEvent(); 997 this.query(); 998 }, 999 '.js-search-input keypress': function (el, ev) { 1000 if (ev.keyCode == 13) { 1001 // this._check(); 1002 this._sanitizeTextField(); 1003 this._fireSearchKeywordEvent(); 1004 this.query(); 1005 } 1006 }, 1007 _fireSearchKeywordEvent: function () { 1008 var keywordsVal = []; 1009 jQuery.each($('.js-search-input'), function (idx, el) { 1010 var searchVal = jQuery.trim($(el).val()); 1011 var type = $(el).attr('ktype'); 1012 if (searchVal.length > 0) { 1013 keywordsVal.push(type + ' - ' + searchVal); 1014 } 1015 }); 1016 if (keywordsVal.length > 0) { 1017 _trackGSEvent( 1018 '2.0-Search', 1019 'search_by_keyword', 1020 keywordsVal.join(' === ') 1021 ); 1022 } 1023 }, 1024 ".js-action-reset click": function (el, ev) { 1025 //This will remove current search results 1026 // this.set_empty(); 1027 //This will remove all search things. 1028 this.query_ob.set_default(); 1029 $('.suggested-keyword-old-ctn').empty(); 1030 // Check if has window.smartSearchQuery then reset it 1031 if (typeof(window.smartSearchQuery)!=='undefined') { 1032 window.smartSearchQuery.setVal(""); 1033 // Check if more operator has been hidden 1034 if ($('.more-operator').hasClass('hidden')) { 1035 window.smartSearchQuery.refreshView(); 1036 } 1037 } 1038 if (typeof(window.triggerTransfer)!=='undefined') { 1039 window.triggerTransfer = true; 1040 } 1041 $("#smart-search-prompt").val(""); 1042 // Code here 1043 $(".suggested-ctn").show(); 1044 1045 //This will render default view 1046 $("body").query_loader('render'); 1047 1048 _trackGSEvent( 1049 '2.0-Search', 1050 'reset_search', 1051 '' 1052 ); 1053 1054 } 1055 1056});
1057/*Date Filter*/ 1058MainSearchOpts.extend("DateFilter", { 1059 init: function (el, opts) { 1060 this._super(el, opts); 1061 this.DEFAULT_DATEPICKER_VAL = ""; 1062 var elements = { 1063 'btnChangeMode': '.button-change-deadline-mode .mode-options', 1064 'btnModeAbsolute': '.button-change-deadline-mode .absolute-option', 1065 'btnModeRelative': '.button-change-deadline-mode .relative-option', 1066 'panelAbsoluteDeadline': '.panel-deadline-absolute', 1067 'panelRelativeDeadline': '.panel-deadline-relative', 1068 'deadlineType': '#relative-deadline-type', 1069 'deadlineDirection': '#relative-deadline-direction', 1070 'deadlineCount': '#relative-deadline-count', 1071 'deadlineUnit': '#relative-deadline-unit', 1072 'deadline.applyFilter': '.button-refresh-filter-deadline', 1073 'deadline.resetFilter': '.button-reset-filter-relative-deadline' 1074 1075 } 1076 function elm(name) { 1077 return $(elements[name]); 1078 } 1079 1080 var control = this; 1081 elm('btnModeAbsolute').on('click', function () { 1082 if (elm('btnModeAbsolute').hasClass('active')) 1083 return; 1084 elm('btnModeAbsolute').removeClass('btn-default').addClass('active btn-dark-blue'); 1085 elm('btnModeRelative').removeClass('active btn-dark-blue').addClass('btn-default'); 1086 elm('panelAbsoluteDeadline').removeClass('hidden'); 1087 elm('panelRelativeDeadline').addClass('hidden'); 1088 control.clear_relative_deadline(true, true); 1089 // $('.status-filter-Continuous') 1090 // .removeClass('disabled') 1091 // .removeAttr('aria-disabled') 1092 // .removeAttr('title'); 1093 // filter date 1094 var dateBefore = control.dateTimeConvertable($('#date-before')), dateAfter = control.dateTimeConvertable($('#date-after')); 1095 if (dateBefore) { 1096 control.query_ob.add_advanced("earliest_submission", dateBefore, '>'); 1097 // control.query_ob.remove_advanced("status", 'Continuous'); 1098 // $('.status-filter-Continuous').removeClass('input-active'); 1099 // $('.status-filter-Continuous') 1100 // .addClass('disabled').attr('aria-disabled', 'true') 1101 // .attr('title', 'This option is unavailable when a deadline is selected.'); 1102 } 1103 if (dateAfter) { 1104 dateAfter = Utils.addDayToString(dateAfter, 1); 1105 control.query_ob.add_advanced("earliest_submission", dateAfter, '<'); 1106 // control.query_ob.remove_advanced("status", 'Continuous'); 1107 // $('.status-filter-Continuous').removeClass('input-active'); 1108 // $('.status-filter-Continuous') 1109 // .addClass('disabled').attr('aria-disabled', 'true') 1110 // .attr('title', 'This option is unavailable when a deadline is selected.'); 1111 } 1112 control.query(); 1113 1114 }); 1115 elm('btnModeRelative').on('click', function () { 1116 if (elm('btnModeRelative').hasClass('active')) 1117 return; 1118 elm('btnModeRelative').removeClass('btn-default').addClass('active btn-dark-blue'); 1119 elm('btnModeAbsolute').removeClass('active btn-dark-blue').addClass('btn-default'); 1120 elm('panelRelativeDeadline').removeClass('hidden'); 1121 elm('panelAbsoluteDeadline').addClass('hidden'); 1122 control.clear_input(true, true); 1123 elm('deadlineCount').removeClass('has-error-count'); 1124 // $('.status-filter-Continuous') 1125 // .removeClass('disabled') 1126 // .removeAttr('aria-disabled') 1127 // .removeAttr('title'); 1128 elm('deadline.applyFilter').trigger('click', true); 1129 }); 1130 elm('deadlineType').on('change', function () { 1131 var valueType = elm('deadlineType').val(); 1132 if (valueType == 'from') { 1133 elm('deadlineDirection').val('last').attr('disabled', 'disabled'); 1134 } else if (valueType == 'after') { 1135 elm('deadlineDirection').val('next').attr('disabled', 'disabled'); 1136 } else { 1137 elm('deadlineDirection').removeAttr('disabled'); 1138 } 1139 }); 1140 elm('deadlineUnit').on('change', function () { 1141 var valueCount = $.trim(elm('deadlineCount').val()), 1142 valueUnit = elm('deadlineUnit').val(); 1143 control.set_max_input_relative_deadline(); 1144 if (valueUnit == 'month' && valueCount > 120) { 1145 elm('deadlineCount').val(120); 1146 } 1147 if (valueUnit == 'week' && valueCount > 520) { 1148 elm('deadlineCount').val(520); 1149 } 1150 if (valueUnit == 'day' && valueCount > 3650) { 1151 elm('deadlineCount').val(3650); 1152 } 1153 }); 1154 elm('deadlineCount').on('input', function () { 1155 elm('deadlineCount').removeClass('has-error-count'); 1156 elm('deadlineCount').tooltip('disable'); 1157 }); 1158 1159 elm('deadline.applyFilter').on('click', function (e, load) { 1160 var valueCount = Number($.trim(elm('deadlineCount').val())); 1161 control.set_max_input_relative_deadline(); 1162
1163 if (valueCount && Number.isInteger(Number(valueCount)) && Number(valueCount) > 0) { 1164 var valueType = elm('deadlineType').val(), 1165 valueDirection = elm('deadlineDirection').val(), 1166 valueUnit = elm('deadlineUnit').val(); 1167 if (valueUnit == 'month' && valueCount > 120) { 1168 valueCount = 120; 1169 } 1170 if (valueUnit == 'week' && valueCount > 520) { 1171 valueCount = 520; 1172 } 1173 if (valueUnit == 'day' && valueCount > 3650) { 1174 valueCount = 3650; 1175 } 1176 elm('deadlineCount').val(valueCount); 1177 var values = { 'type': valueType, 'direction': valueDirection, 'count': valueCount, 'unit': valueUnit }; 1178 control.query_ob.add_advanced("relative_deadline", values, '='); 1179 1180 // control.clear_input(true, true); 1181 1182 var continuousButton = $('.status-filter-Continuous'); 1183 1184 if (control.query_ob.advanced && control.query_ob.advanced['status']) { 1185 if (Object.keys(control.query_ob.advanced['status']).length == 1 && control.query_ob.advanced['status']['Continuous']){ 1186 //remove logically 1187 control.query_ob.remove_advanced("status", 'Continuous'); 1188 //then aesthetically 1189 continuousButton.removeClass('input-active'); 1190 } 1191 } 1192 1193 elm('deadlineCount').removeClass('has-error-count'); 1194 control.query(); 1195 1196 } else if (!load) { 1197 // control.clear_relative_deadline(true); 1198 elm('deadlineCount').addClass('has-error-count'); 1199 elm('deadlineCount').attr('data-original-title', 'The number of time units must be a positive integer!'); 1200 elm('deadlineCount').tooltip('enable'); 1201 } else { 1202 control.query(); 1203 } 1204 1205 }); 1206 1207 elm('deadline.resetFilter').on('click', function () { 1208 control.clear_relative_deadline(true); 1209 }); 1210 1211 1212 $('#date-filter .js-date-input').duet_date_picker({ 1213 dateFormat: getRegionDateFormat(), 1214 allowClear: false, 1215 onChange: function(date) { 1216 //since we did some prevention, and add 1 to the right end side, the date value will never coincide 1217 date = control.dateTimeConvertable(date) 1218 1219 var el = $(this); 1220 var old_date = el.attr("old_date"); 1221 1222 var operator = el.attr('id') === 'date-before' ? '>' : '<'; 1223 1224 //in "<" case, we need to plus 1 day into date value, to really include that day into the search 1225 if (operator === '<') { 1226 date = Utils.addDayToString(date, 1); 1227 var anotherElm = $('#date-before'); 1228 } else { 1229 var anotherElm = $('#date-after'); 1230 } 1231 var validDate = control.isValidDateMoment(anotherElm.val()); 1232 if(!validDate){ 1233 control.query_ob.remove_advanced("earliest_submission"); 1234 anotherElm.val(null); 1235 anotherElm.trigger('autocomplete_selected'); 1236 } 1237 1238 if (typeof (old_date) !== 'undefined' && old_date !== "") { 1239 //only if it is the same kind of operator 1240 control.query_ob.remove_advanced("earliest_submission", old_date); 1241 } 1242 1243 el.attr("old_date", date); 1244 control.clear_relative_deadline(true, true); 1245 1246 control.query_ob.add_advanced("earliest_submission", date, operator); 1247 control.add_clear(el); 1248 1249 //when we query with both continuous status, and deadline 1250 //the continuous status will be ignored 1251 //we wouldn't need to change anything on logic side 1252 //but we should show something that is more explicit to users 1253 //deactivate it if it is active, then disable the button 1254 1255 var continuousButton = $('.status-filter-Continuous'); 1256 1257 if (control.query_ob.advanced && control.query_ob.advanced['status']) { 1258 if (Object.keys(control.query_ob.advanced['status']).length == 1 && control.query_ob.advanced['status']['Continuous']){ 1259 //remove logically 1260 control.query_ob.remove_advanced("status", 'Continuous'); 1261 //then aesthetically 1262 continuousButton.removeClass('input-active'); 1263 } 1264 } 1265 1266 // continuousButton 1267 // .addClass('disabled').attr('aria-disabled', 'true') 1268 // .attr('title', 'This option is unavailable when a deadline is selected.'); 1269 1270 control.query(); 1271 $(this).trigger('autocomplete_selected'); 1272 } 1273 }); 1274 1275 //if min date is set, max date must be higher 1276 $("#date-before").on('autocomplete_selected', function () { 1277 var minDate = control.dateTimeConvertable($(this)); 1278 $("#date-after").duet_date_picker("option", "minDate", new Date(minDate)); 1279 _trackGSEvent( 1280 '2.0-Search', 1281 'deadline_lower', 1282 minDate 1283 ); 1284 }); 1285 1286 //if max date is set, min date must be lower 1287 $("#date-after").on('autocomplete_selected', function () { 1288 var maxDate = control.dateTimeConvertable($(this)); 1289 $("#date-before").duet_date_picker("option", "maxDate", new Date(maxDate)); 1290 _trackGSEvent( 1291 '2.0-Search', 1292 'deadline_upper', 1293 maxDate 1294 ); 1295 }); 1296 //click on the clean deadline button 1297 $('#date-filter .js-clear-input > button').on('click', function (el) { 1298 control.clear_input(true); 1299 }); 1300 }, 1301 isValidDateMoment: function (dateString) { 1302 // moment(dateString, format, strict_parsing_boolean) 1303 // Passing true as the third argument enables strict parsing. 1304 var format = gettext("date_format_place_holder") || "MM/DD/YYYY"; // get local format 1305 return dateString.length === format.length && moment(dateString, format, true).isValid(); 1306 }, 1307 set_max_input_relative_deadline: function () { 1308 var valueUnit = $('#relative-deadline-unit').val(); 1309 if (valueUnit == 'month') { 1310 $('#relative-deadline-count').attr('max', 120); 1311 } 1312 if (valueUnit == 'week') { 1313 $('#relative-deadline-count').attr('max', 520); 1314 } 1315 if (valueUnit == 'day') { 1316 $('#relative-deadline-count').attr('max', 3650); 1317 } 1318 1319 },
1320 clear_input: function (refresh, relativeDeadline) { 1321 if (!relativeDeadline) { 1322 $('#date-filter .js-clear-input').addClass('hidden'); 1323 $("#date-filter .js-date-input").duet_date_picker("option", "maxDate", null); 1324 $("#date-filter .js-date-input").duet_date_picker("option", "minDate", null); 1325 $('#date-filter .js-date-input').val(this.DEFAULT_DATEPICKER_VAL).trigger("change"); 1326 1327 //no more deadlines, we can restore the status button with Continuous value 1328 // $('.status-filter-Continuous') 1329 // .removeClass('disabled') 1330 // .removeAttr('aria-disabled') 1331 // .removeAttr('title'); 1332 } 1333 1334 if (refresh) { 1335 this.query_ob.remove_advanced("earliest_submission"); 1336 if (!relativeDeadline) 1337 this.query(); 1338 } 1339 }, 1340 clear_relative_deadline: function (refresh, dateDeadline) { 1341 if (!dateDeadline) { 1342 $('#relative-deadline-type').val('within'); 1343 $('#relative-deadline-direction').val('next'); 1344 $('#relative-deadline-count').val(''); 1345 $('#relative-deadline-unit').val('month'); 1346 $('#relative-deadline-direction') 1347 .removeAttr('disabled'); 1348 // $('.status-filter-Continuous') 1349 // .removeClass('disabled') 1350 // .removeAttr('aria-disabled') 1351 // .removeAttr('title'); 1352 $('#relative-deadline-count').removeClass('has-error-count'); 1353 } 1354 if (refresh) { 1355 this.query_ob.remove_advanced("relative_deadline"); 1356 if (!dateDeadline) 1357 this.query(); 1358 } 1359 }, 1360 add_clear: function (base_elem) { 1361 var formItemElm = $(base_elem).closest('#date-filter'); 1362 var clearElm = formItemElm.find('.js-clear-input'); 1363 1364 clearElm.removeClass('hidden'); 1365 }, 1366 dateTimeConvertable: function (date_picker) { 1367 //when access datepicker without choosing date it is default to 1/1/1970 when new date a null date 1368 if (typeof date_picker === "string") { 1369 var format = gettext("date_format_place_holder") || "MM/DD/YYYY"; // get local format 1370 return moment(date_picker, format).format("MM/DD/YYYY"); // convert it back to en-us for search 1371 }else if (date_picker instanceof jQuery && typeof date_picker.duet_date_picker === "function"){ 1372 var datepicker_string = date_picker.duet_date_picker("getDate") || ""; 1373 if (!datepicker_string) return datepicker_string; 1374 var format = date_picker.next("duet-date-picker").attr("format"); 1375 return moment(datepicker_string, format).format("MM/DD/YYYY"); // convert it back to en-us for search 1376 }else { 1377 return "" 1378 } 1379 }, 1380}); 1381 1382/*Category Filter*/ 1383MainSearchOpts.extend("CategoryFilter", { 1384 init: function (el, opts) { 1385 this._super(el, opts); 1386 1387 this.picker = this.options.picker; 1388 this.selected = this.options.selected; 1389 1390 var control = this; 1391 1392 //Category picker stuff 1393 this.picker = $("#category-modal"); 1394 this.picker.category_picker({ 1395 "trunc_len": 30, 1396 "callback": function (lt) { 1397 control.query_ob.remove_advanced("subject"); 1398 $.each(lt, function (i, v) { 1399 control.query_ob.add_advanced("subject", i, "="); 1400 }); 1401 control.query(); 1402 } 1403 });//On select from picker box. 1404 1405 this.selected = $(".js-category-items"); 1406 this.selected.selected_categories({ 1407 "trunc_len": 30, 1408 "callback": function (val) { 1409 if (typeof (val) != 'undefined') { 1410 control.query_ob.remove_advanced("subject", val); 1411 control.query(); 1412 } 1413 } 1414 });//On click to remove 1415 1416 var control = this; 1417 var searchbox = $(el).find("#categories"); 1418 1419 searchbox.one("keypress focus click", function () { 1420 $(this).attr("default", "off"); 1421 $(this).val(""); 1422 }); 1423 1424 searchbox.autocomplete({ 1425 source: function (request, response) { 1426 $.getJSON("/search/db_autosuggest", { term: request.term, suggest_type: "category" }, response); 1427 }, 1428 select: function (el, ui) { 1429 control.selected.selected_categories("add_element", ui.item.value); 1430 $(this).val(''); 1431 1432 control.query_ob.add_advanced("subject", ui.item.value, "="); 1433 control.query(); 1434 1435 _trackGSEvent( 1436 '2.0-Search', 1437 'category_search', 1438 ui.item.value 1439 ); 1440 1441 return false;
1442 }, 1443 close: function (el, ui) { 1444 //$(this).val(''); 1445 return false; 1446 }, 1447 autoFocus: true 1448 }); 1449 1450 }, 1451 ".js-category-select click": function (el, ev) { 1452 if (this.picker.is(":visible")) { 1453 this.picker.category_picker("hide_picker"); 1454 } else { 1455 var selected = $(".js-category-items").selected_categories("get_data").data('js-selected-items'); 1456 this.picker.category_picker("show_picker", selected); 1457 } 1458 } 1459}); 1460/*Sponsor Filter*/ 1461/*MainSearchOpts.extend("SponsorFilter", { 1462 init: function(el, opts) { 1463 this._super(el, opts); 1464 1465 var control = this; 1466 var searchbox = $(el).find("#sponsors"); 1467 1468 //Sponsor picker stuff 1469 this.picker = $("#sponsor-modal"); 1470 this.picker.sponsor_picker({ 1471 "trunc_len": 60, 1472 "callback": function(lt) { 1473 control.query_ob.remove_advanced("sponsors"); 1474 $.each(lt, function(i, v){ 1475 control.query_ob.add_advanced("sponsors", i, "="); 1476 }); 1477 control.query(); 1478 } 1479 }); 1480 1481 this.selected = $(".js-sponsor-items"); 1482 this.selected.selected_sponsors({ 1483 "trunc_len": 30, 1484 "callback": function(val) { 1485 if ( typeof(val) != 'undefined' ){ 1486 control.query_ob.remove_advanced("sponsors", val); 1487 control.query(); 1488 } 1489 } 1490 }); 1491 1492 searchbox.one("keypress focus click", function(){ 1493 $(this).attr("default", "off"); 1494 $(this).val(""); 1495 }); 1496 1497 searchbox.autocomplete({ 1498 source: function(request, response) { 1499 $.getJSON("/search/db_autosuggest", { term: request.term, suggest_type: "sponsor" }, response); 1500 }, 1501 select: function(el, ui) { 1502 control.selected.selected_sponsors("add_element", ui.item.value); 1503 $(this).val(''); 1504 control.query_ob.add_advanced("sponsors", ui.item.value, "="); 1505 control.query(); 1506 1507 _trackGSEvent( 1508 '2.0-Search', 1509 'sponsor_search', 1510 ui.item.value 1511 ); 1512 return false; 1513 }, 1514 close: function(el, ui) { 1515 //$(this).val(''); 1516 return false; 1517 }, 1518 autoFocus: true 1519 }); 1520 }, 1521 ".js-sponsor-select click": function(el, ev){ 1522 if (this.picker.is(":visible")) { 1523 this.picker.sponsor_picker("hide_picker"); 1524 } else { 1525 var selected = $(".js-sponsor-items").selected_sponsors("get_data").data('js-selected-items'); 1526 this.picker.sponsor_picker("show_picker", selected); 1527 } 1528 } 1529});*/ 1530 1531 1532MainSearchOpts.extend("AdvancedFilter", { 1533 init: function (el, opts) { 1534 this._super(el, opts); 1535 1536 this.for_attr = this.element.attr("for"); 1537 var control = this; 1538 1539 this.negative_support = opts.negative_support; 1540 1541 //negative filter enabled 1542 if (opts.negative_support === true) { 1543 this.element.find('.advanced-input-control-negative').on('click', function (event) { 1544 var controlEl = $(event.currentTarget); 1545 var el = controlEl.siblings('.advanced-input'); 1546 control.query_ob.remove_advanced(control.for_attr, el.val()); 1547 1548 if (!el.hasClass("input-negative")) { 1549 control.query_ob.add_advanced(control.for_attr, el.val(), "!="); 1550 control.fireEventAction(control.for_attr, false, el.val()); 1551 } 1552 el.removeClass('input-active').toggleClass("input-negative"); 1553 1554 controlEl.toggleClass('active'); 1555 1556 if (controlEl.hasClass('active')) { 1557 controlEl.attr('aria-pressed', 'true'); 1558 } else { 1559 controlEl.attr('aria-pressed', 'false'); 1560 } 1561 1562 controlEl.siblings('.advanced-input-control-positive').removeClass('active').attr('aria-pressed', 'false'); 1563 control.query(); 1564 }); 1565 this.element.find('.advanced-input-control-positive').on('click', function (event) { 1566 var controlEl = $(event.currentTarget); 1567 controlEl.siblings('.advanced-input').click(); 1568 }); 1569 } 1570 }, 1571 ".advanced-input click": function (el, ev) { 1572 var control = this; 1573 if ($(el).hasClass('disabled')) { 1574 return; 1575 }; 1576 this.query_ob.remove_advanced(this.for_attr, el.val()); 1577 if (!el.hasClass("input-active")) { 1578 this.query_ob.add_advanced(this.for_attr, el.val(), "="); 1579 control.fireEventAction(control.for_attr, true, el.val()); 1580 } 1581 1582 if (control.for_attr == "status"){ 1583 control.onStatusAction(control); 1584 } 1585 1586 el.removeClass('input-negative').toggleClass("input-active"); 1587 1588 if (control.negative_support === false) { 1589 if (el.hasClass('input-active')) { 1590 el.attr('aria-pressed', 'true'); 1591 } else { 1592 el.attr('aria-pressed', 'false'); 1593 } 1594 } 1595 1596 el.siblings('.advanced-input-control-negative').removeClass('active').attr('aria-pressed', 'false'); 1597 el.siblings('.advanced-input-control-positive').toggleClass('active'); 1598 1599 if (el.siblings('.advanced-input-control-positive').hasClass('active')) { 1600 el.siblings('.advanced-input-control-positive').attr('aria-pressed', 'true'); 1601 } else { 1602 el.siblings('.advanced-input-control-positive').attr('aria-pressed', 'false'); 1603 } 1604 1605 this.query(); 1606 }, 1607 ".advanced-input keypress": function (el, ev) { 1608 if (ev.which == 32 /* space */) { 1609 if ($(el).hasClass('disabled')) { 1610 return; 1611 }; 1612 $(el).click(); 1613 } 1614 }, 1615 fireEventAction: function (forAttr, positive, value) { 1616 var eventName; 1617 1618 switch (forAttr) { 1619 case 'type': 1620 eventName = 'sponsor_type'; 1621 break; 1622 case 'grant_types': 1623 eventName = 'grant_type'; 1624 break; 1625 case 'status': 1626 eventName = 'status'; 1627 break; 1628 case 'is_limited': 1629 eventName = 'submission'; 1630 break; 1631 case 'applicant_types': 1632 eventName = 'applicant_type'; 1633 break; 1634 // case 'grant_location': 1635 // eventName = 'grant_location'; 1636 // break; 1637 } 1638 1639 var eventSign = positive ? '_positive' : '_negative'; 1640 1641 //2.4.1: trackers 1642 _trackGSEvent( 1643 '2.0-Search', 1644 eventName + eventSign, 1645 value 1646 ); 1647 }, 1648 onStatusAction: function(control){ 1649 if (control.query_ob.advanced && control.query_ob.advanced['status']) { 1650 if (Object.keys(control.query_ob.advanced['status']).length == 1 && control.query_ob.advanced['status']['Continuous']){ 1651 control.query_ob.remove_advanced("earliest_submission"); 1652 $("#date-filter").date_filter("clear_input", true); 1653 $("#date-filter").date_filter("clear_relative_deadline", true); 1654 } 1655 } 1656 } 1657}); 1658 1659MainSearchOpts.extend("PaginationHelper", { 1660 init: function (el, opts) { 1661 this._super(el, opts); 1662 }, 1663 onPageClicked: function(e, page){ 1664 if (typeof (window.searchQ) != 'undefined' && window.searchQ !== null) { 1665 return; 1666 }
1667 this.query_ob.is_change_page = true; 1668 this.query_ob.current_page = page; 1669 this.query(true, false); 1670 $('.search-pagination .paginator ul').not($(e.currentTarget)).bootstrapPaginator("setOptions", { currentPage: page }); 1671 }, 1672 update_page: function (hits, per_page) { 1673 var totalPageNum = Math.ceil(hits / per_page); 1674 var self = this; 1675 if (totalPageNum > 1) { 1676 $('.search-pagination .paginator ul').bootstrapPaginator({ 1677 currentPage: this.query_ob.current_page, 1678 totalPages: totalPageNum, 1679 bootstrapMajorVersion: 3, 1680 onPageClicked: function(e, originalEvent, type, page){ self.onPageClicked(e, page) }.bind(this), 1681 pageUrl: '#search-main', 1682 }); 1683 $('.paginator ul').removeClass("hidden"); 1684 } else { 1685 $('.paginator ul').addClass("hidden"); 1686 } 1687 1688 if (hits === 0) { 1689 this.element.addClass('hidden'); 1690 return true; 1691 } else { 1692 this.element.removeClass('hidden'); 1693 } 1694 } 1695}); 1696 1697MainSearchOpts.extend("SaveAlertForm", { 1698 /*All these selectors should be at runtime so that we don't have to rebind the controller*/ 1699 init: function (el, opts) { 1700 this._super(el, opts); 1701 var control = this; 1702 1703 /** @type {Object} define save mode */ 1704 this.mode = { 1705 UPDATE: 'existing', 1706 NEW: 'new' 1707 }; 1708 this.currentMode = this.mode.NEW; 1709 1710 /** @type {Object} defined message error / complete */ 1711 this.feedbackMsg = { 1712 SUCCESS: 'Save updated!', 1713 ERROR: 'Save not updated! Please try again!', 1714 NEW_ERROR: 'Please select a name for your new search or update an existing one!', 1715 UPDATE_ERROR: 'Please select an existing search to update!' 1716 }; 1717 /** @type {Object} define type of feedback message */ 1718 this.feedbackMode = { 1719 SUCCESS: 'good', 1720 FAILURE: 'fail' 1721 }; 1722 1723 this.triggerReload = false; 1724 1725 this.element.on("hidden.bs.modal", function () { 1726 $(this).find('.modal-content').html(''); 1727 $(this).removeData('bs.modal'); 1728 control.hideFeedback(); 1729 if (control.triggerReload) { 1730 window.location = window.location.protocol + '//' + window.location.host + window.location.pathname; 1731 } 1732 }); 1733 }, 1734 'input[name="save-options"] change': function (el, ev) { 1735 this.hideFeedback(); 1736 var mode = el.val(); 1737 this.element.find('.js-options').removeClass('active'); 1738 el.closest('.js-options').addClass('active'); 1739 //if there is a mode change, reset frequency 1740 if (this.currentMode == this.mode.UPDATE && mode == this.mode.NEW) { 1741 this.element.find('.js-save-frequency').val(""); 1742 this.element.find('input[name="ignore-no-grants"][value=0]').prop('checked', true); 1743 } 1744 $('input[name="ignore-updated-grants"][value="1"]').prop('checked', true); 1745 this.currentMode = mode; 1746 if (mode === this.mode.UPDATE) { 1747 this.updateFrequency(this.element.find('.js-saved-items')); 1748 $('.option-template').addClass('hidden'); 1749 } else { 1750 this.element.find('.js-new-save-input').focus(); 1751 $('.option-template').removeClass('hidden'); 1752 } 1753 }, 1754 //on focus on saved items select, choose correct options 1755 '.js-saved-items change': function (el, ev) { 1756 this.hideFeedback(); 1757 this.element.find('input[name="save-options"][value=' + this.mode.UPDATE + ']').prop('checked', true); 1758 this.currentMode = this.mode.UPDATE; 1759 this.updateFrequency(this.element.find('.js-saved-items')); 1760 $('.option-template').addClass('hidden'); 1761 1762 $('.js-new-save-input').val(''); 1763 }, 1764 '.js-save-frequency change': function (el, ev) { 1765 this.hideFeedback(); 1766 }, 1767 '.js-new-save-input input': function (el, ev) { 1768 var inputValue = $.trim(el.val()); 1769 if (inputValue.length > 0) { 1770 this.hideFeedback(); 1771 if (this.currentMode == this.mode.UPDATE) { 1772 this.element.find('.js-save-frequency').val(""); 1773 this.element.find('input[name="ignore-no-grants"][value=0]').prop('checked', true); 1774 } 1775 this.element.find('input[name="save-options"][value=' + this.mode.NEW + ']').prop('checked', true); 1776 this.currentMode = this.mode.NEW; 1777 $('.option-template').removeClass('hidden'); 1778 } 1779 }, 1780 1781 '.js-new-save-input focus': function (el, ev) { 1782 this.hideFeedback(); 1783 }, 1784 updateFrequency: function (select_box) { 1785 var selected = $('option:selected', select_box); 1786 1787 if (selected.attr("set") == "1") { 1788 this.element.find('.js-save-frequency').val(selected.attr("freq")); 1789 } else { 1790 this.element.find('.js-save-frequency').val(""); 1791 } 1792 if (selected.attr("value") != ''){ 1793 this.element.find('input[name="ignore-no-grants"][value=' + (selected.attr("ignore_no_grants") == "1" ? "1" : "0") + ']').prop('checked', true); 1794 this.element.find('input[name="ignore-updated-grants"][value=' + (selected.attr("ignore_updated_grants") == "1" ? "1": "0") + ']').prop('checked', true); 1795 } 1796 }, 1797 '.js-action-save-submit click': function (el, ev) { 1798 this.hideFeedback(); 1799 var control = this; 1800 1801 var state = this.element.find("input[name='save-options']:checked").val(); 1802 1803 var search_id = null; 1804 var search_name = null; 1805 1806 var search_params = this.query_ob.construct(false); 1807 var search_text = this.build_search_text(); 1808 var frequency = this.element.find(".js-save-frequency").val(); 1809 var ignore_no_grants = this.element.find('input[name="ignore-no-grants"]:checked').val(); 1810 var sort_field = $('#sort option:selected').val(); 1811 var sort_direction = $('#direction option:selected').val(); 1812 var search_mode = window.isBasicMode ? 'basic' : 'advanced'; 1813 1814 var ignore_updated_grant = this.element.find('input[name="ignore-updated-grants"]:checked').val(); 1815 if (state == "new") { 1816 search_name = $.trim(this.element.find(".js-new-save-input").val()); 1817 if (search_name.length === 0) {
1818 this.showFeedback(this.feedbackMsg.NEW_ERROR, this.feedbackMode.FAILURE); 1819 return false; 1820 } 1821 search_id = -1; 1822 //2.4.1: trackers 1823 _trackGSEvent( 1824 '2.0-Search', 1825 'save_search_submit', 1826 'New' + ' - ' + search_name + ' - ' + frequency 1827 ); 1828 } else { 1829 search_id = $.trim(this.element.find('.js-saved-items option:selected').val()); 1830 search_name = this.element.find('.js-saved-items option:selected').text(); 1831 1832 if (search_id === "") { 1833 this.showFeedback(this.feedbackMsg.UPDATE_ERROR, this.feedbackMode.FAILURE); 1834 return false; 1835 } 1836 1837 //2.4.1: trackers 1838 _trackGSEvent( 1839 '2.0-Search', 1840 'save_search_submit', 1841 'Override' + ' - ' + search_name + ' - ' + frequency 1842 ); 1843 } 1844 1845 $.ajax({ 1846 type: "POST", 1847 url: "/user/update_search", 1848 data: { 1849 "solr_search": search_params['qs'], 1850 "search_text": search_text, 1851 "search_id": search_id, 1852 "search_name": search_name, 1853 "frequency": frequency, 1854 "ignore_no_grants": ignore_no_grants, 1855 "sort_field": sort_field, 1856 "sort_direction": sort_direction, 1857 "search_mode": search_mode, 1858 "ignore_updated_grant": ignore_updated_grant 1859 }, 1860 dataType: "json", 1861 beforeSend: function () { 1862 control.element.find('.js-action-save-submit').attr('disabled', 'disabled'); 1863 }, 1864 success: function (response) { 1865 if (response.status == 1) { 1866 if (state != "new") { 1867 control.triggerReload = true; 1868 } 1869 control.showFeedback(response.msg, control.feedbackMode.SUCCESS); 1870 setTimeout(function () { 1871 control.element.modal('hide'); 1872 }, 2000); 1873 } else { 1874 control.element.find('.js-action-save-submit').removeAttr('disabled'); 1875 control.showFeedback(response.error, control.feedbackMode.FAILURE); 1876 } 1877 }, 1878 error: function () { 1879 control.element.find('.js-action-save-submit').removeAttr('disabled'); 1880 control.showFeedback(control.feedbackMsg.ERROR, control.feedbackMode.FAILURE); 1881 } 1882 }); 1883 }, 1884 showFeedback: function (message, type) { 1885 this.hideFeedback(); 1886 this.element.find('.js-alert-' + type).html(message).removeClass('hidden'); 1887 }, 1888 hideFeedback: function () { 1889 this.element.find('.js-alert').addClass('hidden'); 1890 } 1891}); 1892 1893MainSearchOpts.extend("LoadAlertForm", { 1894 /*All these selectors should be at runtime so that we don't have to rebind the controller*/ 1895 init: function (el, opts) { 1896 this._super(el, opts); 1897 var control = this; 1898 1899 /** @type {Object} define type of feedback message */ 1900 this.feedbackMode = { 1901 SUCCESS: 'good', 1902 FAILURE: 'fail' 1903 }; 1904 1905 this.triggerReload = false; 1906 1907 this.element.on("loaded.bs.modal", function () { 1908 if (control.element.find('.js-saved-items option[is_default="1"]').length > 0) { 1909 control.element.find('.js-saved-items option[is_default="1"]').prop("selected", true); 1910 control.element.find('.js-saved-items').trigger('change'); 1911 } 1912 }); 1913 1914 this.element.on("hidden.bs.modal", function () { 1915 $(this).find('.modal-content').html(''); 1916 $(this).removeData('bs.modal'); 1917 control.hideFeedback(); 1918 if (control.triggerReload) { 1919 window.location = window.location.protocol + '//' + window.location.host + window.location.pathname; 1920 } 1921 }); 1922 }, 1923 //on focus on saved items select, choose correct options 1924 '.js-saved-items change': function (el, ev) { 1925 this.hideFeedback(); 1926 var control = this, 1927 select_box = this.element.find('.js-saved-items option:selected'), 1928 value = select_box.attr('value'), 1929 is_default = select_box.attr('is_default'); 1930 if (value != '') { 1931 this.element.find('.js-action-load-submit').removeAttr('disabled'); 1932 this.element.find('.default-saved-search').removeAttr('disabled'); 1933 this.element.find('.default-saved-search').prop('checked', is_default === '1'); 1934 this.element.find('.set-as-default-container').removeClass('hidden'); 1935 } else { 1936 this.element.find('.js-action-load-submit').attr('disabled', 'disabled'); 1937 this.element.find('.default-saved-search').prop('checked', false); 1938 this.element.find('.default-saved-search').attr('disabled', 'disabled'); 1939 this.element.find('.set-as-default-container').addClass('hidden'); 1940 } 1941 }, 1942 '.default-saved-search click': function (el, ev) { 1943 this.hideFeedback(); 1944 var control = this, 1945 select_box = this.element.find('.js-saved-items option:selected'), 1946 value = select_box.attr('value'), 1947 is_default = el.prop('checked'); 1948 1949 $.ajax({ 1950 type: "POST", 1951 url: "/user/mark_default_alert", 1952 data: { 1953 search_id: value, 1954 is_default: is_default ? '1' : '0' 1955 }, 1956 dataType: "json", 1957 beforeSend: function () { 1958 el.attr('disabled', 'disabled'); 1959 }, 1960 success: function (response) { 1961 el.removeAttr('disabled'); 1962 if (response.code == '1') { 1963 control.triggerReload = true; 1964 control.showFeedback(response.msg, control.feedbackMode.SUCCESS); 1965 if (is_default) { 1966 control.element.find('.js-saved-items option').each(function () { 1967 var option = $(this); 1968 option.text(option.text().replace(' (Set as Default)', '')); 1969 option.attr('is_default', '0'); 1970 }); 1971 control.element.find('.js-saved-items option:selected').each(function () { 1972 var option = $(this); 1973 option.text(option.text() + ' (Set as Default)'); 1974 option.attr('is_default', '1'); 1975 }); 1976 } else { 1977 control.element.find('.js-saved-items option:selected').each(function () { 1978 var option = $(this); 1979 option.text(option.text().replace(' (Set as Default)', '')); 1980 option.attr('is_default', '0'); 1981 }); 1982 } 1983 } else { 1984 el.prop('checked', !is_default); 1985 control.showFeedback(response.error, control.feedbackMode.FAILURE); 1986 } 1987 }, 1988 error: function () { 1989 el.removeAttr('disabled'); 1990 el.prop('checked', !is_default); 1991 control.showFeedback('Your request could not be handled at the moment! Please try again in a short while!', control.feedbackMode.FAILURE); 1992 } 1993 }); 1994 }, 1995 '.js-action-load-submit click': function (el, ev) { 1996 1997 var control = this, 1998 select_box = this.element.find('.js-saved-items option:selected'), 1999 keywords = select_box.attr('keywords'), 2000 query = select_box.attr('query'), 2001 is_default = select_box.attr('is_default'), 2002 sort_field = select_box.attr('sort_field'); 2003 sort_direction = select_box.attr('sort_direction'); 2004 search_mode = select_box.attr('search_mode'); 2005 if (search_mode === 'advanced'){ 2006 window.isBasicMode = false;
2007 } 2008 else{ 2009 window.isBasicMode = true; 2010 } 2011 2012 _trackGSEvent( 2013 '2.0-Search', 2014 'load_search_submit', 2015 select_box[0].innerText + ' - ' + is_default 2016 ); 2017 $('.suggested-keyword-old-ctn').empty(); 2018 if (typeof(window.smartSearchQuery)!=='undefined' && typeof(window.smartSearchQuery.value)!=='undefined') { 2019 window.smartSearchQuery.setVal(""); 2020 // Check if more operator has been hidden 2021 if ($('.more-operator').hasClass('hidden')) { 2022 window.smartSearchQuery.refreshView(); 2023 } 2024 2025 } 2026 this.query_ob.override_default(!!query ? JSON.parse(query) : [], is_default); 2027 this.query_ob.add_searchtext(keywords, is_default); 2028 if (sort_field) { 2029 this.query_ob.add_sortby(sort_field); 2030 } 2031 if (sort_direction){ 2032 this.query_ob.add_sortDirection(sort_direction); 2033 } 2034 if (!control.triggerReload) { 2035 $("body").query_loader('render'); 2036 } 2037 control.element.modal('hide'); 2038 }, 2039 showFeedback: function (message, type) { 2040 this.hideFeedback(); 2041 this.element.find('.js-alert-' + type).html(message).removeClass('hidden'); 2042 }, 2043 hideFeedback: function () { 2044 this.element.find('.js-alert').addClass('hidden'); 2045 } 2046}); 2047 2048$.Controller('SaveTooltips', { 2049 init: function (el, opts) { 2050 var user_id = opts['user_id']; 2051 if (user_id && user_id != "None" && user_id != "-1") 2052 this.content = "Click here to add this grant to your favorites."; 2053 else 2054 this.content = "Please log in or sign-up to add this grant to your favorites."; 2055 //czd_tooltip($(el), {"content":this.content}); 2056 } 2057}); 2058 2059$.Controller('ViewTooltips', { 2060 init: function (el, opts) { 2061 var user_id = opts['user_id']; 2062 if (user_id && user_id != "None" && user_id != "-1") 2063 this.content = "This grant is in your favorites. You can go to your account to view it. <br>Or you can click on this star to remove this grant from your favorites."; 2064 else 2065 this.content = "Please log in or sign-up to view this grant in your favorites."; 2066 //czd_tooltip($(el), {"content":this.content}); 2067 } 2068}); 2069 2070$.Controller('CommentButton', 2071{ 2072 flag: "", 2073 comment: "", 2074 offset: "", 2075 field: "", 2076 display: "", 2077 grant_id: "", 2078 grant_title: "", 2079 init: function(el) { 2080 this.flag = el; 2081 this.field = $(el).attr("field"); 2082 this.display = $(el).attr("display"); 2083 this.grant_id = $(el).attr("grant_id"); 2084 this.grant_title = $(el).parents('div.description').siblings('div.title').children('a.grant-url').text(); 2085 this.offset = $(el).offset(); 2086 }, 2087 click: function(el) { 2088 if ( $(el).hasClass('disabled') ){ 2089 return; 2090 } 2091 this.comment = $(el).attr("comment"); 2092 var last_modified = $(el).attr("last_modified"); 2093 $('#comment-modal').comment_form({'elm': el, 'comment':this.comment, 'field':this.field, 'display':this.display, 'position':this.offset, 'flag':this.flag, 'grant_id':this.grant_id, 'grant_title':this.grant_title, 'last_modified':last_modified}); 2094 } 2095}); 2096 2097$.Controller('CommentForm', 2098{ 2099 field : "", 2100 form: "", 2101 flag: "", 2102 grant_id: "", 2103 grant_title: "", 2104 init : function(el, opts) { 2105 var me = this; 2106 this.form = el; 2107 this.field = opts['field']; 2108 this.flag = opts['flag']; 2109 this.grant_id = opts['grant_id']; 2110 this.grant_title = opts['grant_title']; 2111 if(typeof opts['last_modified'] != 'undefined' && opts['last_modified'] !== "") { 2112 this.element.find(".js-last-submitted").text('Submitted on '+opts['last_modified'].split(' ')[0]); 2113 } else { 2114 this.element.find(".js-last-submitted").text(''); 2115 } 2116 this.element.find(".js-comment-content").val(opts['comment']); 2117 this.element.find(".js-content-type").text(opts['display']); 2118 2119 this.element.one('hidden.bs.modal', function(){ 2120 $(this).comment_form('destroy'); 2121 }); 2122 2123 this.element.one('shown.bs.modal', function () { 2124 //hide error 2125 var errorElm = me.element.find('.js-report-error'); 2126 errorElm.addClass('hidden'); 2127 // focus on comment-content 2128 var inputElm = me.element.find('.js-comment-content'); 2129 inputElm.focus(); 2130 inputElm[0].setSelectionRange(inputElm.val().length, inputElm.val().length); 2131 }) 2132 2133 this.element.data('js-refocus-target', opts['elm']).modal('show'); 2134 }, 2135 ".js-action-comment-submit click": function (el, opts) { 2136 // they're going out of scope in that anon class 2137 var rootElm = this.element; 2138 var form = this.form; 2139 var field = this.field; 2140 var flag = this.flag; 2141 var grant_id = this.grant_id; 2142 var grant_title = this.grant_title; 2143 var inputElm = rootElm.find('.js-comment-content'); 2144 var errorElm = rootElm.find('.js-report-error'); 2145 2146 //hide error 2147 errorElm.addClass('hidden'); 2148 2149 var val = jQuery.trim( inputElm.val() ); 2150 2151 if ( val === '' ){ 2152 errorElm.html('Your report must not be blank!').removeClass('hidden'); 2153 setTimeout(() => { 2154 errorElm.addClass('hidden'); 2155 }, 1000); 2156 return; 2157 } 2158 2159 $.ajax({ 2160 type: 'POST', 2161 url: '/grant/comment', 2162 data: { 2163 "grant_id" : grant_id, 2164 "field" : field, 2165 "comment": inputElm.val(), 2166 "grant_title": grant_title 2167 }, 2168 success: function(response) { 2169 //alert(response); 2170 $(flag).attr("last_modified", response.date); 2171 $(flag).attr("comment", inputElm.val()); 2172 $(flag).attr("src", "/public/img/report_existing.png"); 2173 rootElm.modal('hide'); 2174 } 2175 }); 2176 } 2177}); 2178 2179function log_export() { 2180 var timediff = new Date().getTime() - _curtime;
2181 _gaq.push(['_trackEvent', 'postsearch', 'export_time', timediff.toString()]); 2182 _gaq.push(['_trackEvent', 'postsearch', 'export_preclick', query.get_results_clicked()]); 2183 //Can get export total by looking at unique number of either of these 2184} 2185 2186//Controller to handle the toggle of search filters 2187/** 2188 * View for SearchFilterToggle 2189 * TODO: REmove this 2190 * @return SearchFilterToggle an instance of the view class 2191 */ 2192var SearchFilterToggle = SearchFilterToggle || function (query) { 2193 2194 var me = this; 2195 2196 me.query = query; 2197 2198 /* Element list */ 2199 var elements = { 2200 'sponsors': '#sponsor-filter', 2201 'sponsor_id': '#sponsor-filter', 2202 'categories': '#category-filter', 2203 'amount': '#amount-filter', 2204 'status': '#status-filter', 2205 'deadline': '#date-filter', 2206 'sponsorType': '#sponsor-type-filter', 2207 'grantType': '#type-filter', 2208 'applicantLocations': '#location-filter', 2209 'activityLocations': '#activity-location-filter', 2210 'submission': '#submission-filter', 2211 'applicantType': '#applicant-filter', 2212 'cfdaNum': '#cfda-filter', 2213 'citizenship': '#citizenship-filter', 2214 'sponsorCountry': '#sponsor-country-filter', 2215 2216 //generalization 2217 'filter': '.js-filter-item', 2218 'filter.close': '.toggle-icon-close', 2219 'filter.open': '.toggle-icon-open', 2220 'filter.toggle': '.accordion-toggle', 2221 'excludeLocation': 'excluded-location', 2222 'excludeSponsor': 'excluded-sponsor-list', 2223 'excludeActivityLocation': 'activity-excluded-location', 2224 'excludeCitizenship': 'excluded-citizenships' 2225 }; 2226 2227 /* Element getter */ 2228 function elm(name) { 2229 return $(elements[name]); 2230 } 2231 2232 /** 2233 * contains all event handlers for the view 2234 * @type {Object} 2235 */ 2236 var eventHandlers = { 2237 }; 2238 2239 /** 2240 * map of filter name, used for knowing which filter group we should update. 2241 * @type {Object} 2242 */ 2243 var map = { 2244 'sponsors': 'sponsors', 2245 'sponsor_id': 'sponsor_id', 2246 'subject': 'categories', 2247 'currency': 'amount', 2248 'amount_per_grant_max': 'amount', 2249 'amount_per_grant_min': 'amount', 2250 'status': 'status', 2251 'earliest_submission': 'deadline', 2252 'relative_deadline': 'deadline', 2253 'type': 'sponsorType', 2254 'grant_types': 'grantType', 2255 'applicant_locations': 'applicantLocations', 2256 'activity_locations': 'activityLocations', 2257 'is_limited': 'submission', 2258 'applicant_type_ids': 'applicantType', 2259 'cfda_numbers': 'cfdaNum', 2260 'citizenship': 'citizenship', 2261 'sponsor_country': 'sponsorCountry' 2262 2263 }; 2264 2265 //reverse map to check for filters. 2266 var reverseMap = {}; 2267 for (var item in map) { 2268 if (!map.hasOwnProperty(item)) { 2269 continue; 2270 } 2271 if (typeof (reverseMap[map[item]]) == 'undefined') { 2272 reverseMap[map[item]] = [] 2273 } 2274 reverseMap[map[item]].push(item); 2275 } 2276 2277 /** 2278 * check and open any filter if it has any conditions up 2279 * @param {string} name a specific filter name, every filters if name is null 2280 * @return {None} 2281 */ 2282 function checkOpenFilter(name) { 2283 if (!name) { 2284 for (var item in reverseMap) { 2285 if (!reverseMap.hasOwnProperty(item)) { 2286 continue; 2287 } 2288 _checkOpenFilter(item); 2289 } 2290 } else { 2291 _checkOpenFilter(name); 2292 } 2293 } 2294 2295 /** 2296 * function that handle check of each single item 2297 * @param {string} name name of the filter, cannot be none anymore 2298 * @return {None} 2299 */ 2300 function _checkOpenFilter(name) { 2301 if (_checkIfActive(name) === true) { 2302 if (elm(name).length > 0) { 2303 elm(name).collapse('show'); 2304 } 2305 } 2306 } 2307 2308 function _checkIfActive(name) { 2309 //check all the items of the reverseMap item 2310 //if it appear in query object then open it 2311 if (typeof (reverseMap[name]) == 'undefined') { 2312 return; 2313 } 2314 var checkList = reverseMap[name]; 2315 var open = false;
2316 for (var i = 0; i < checkList.length; i++) { 2317 if (typeof (me.query.advanced[checkList[i]]) != 'undefined' && !$.isEmptyObject(me.query.advanced[checkList[i]])) { 2318 open = true; 2319 break; 2320 } 2321 } 2322 return open; 2323 } 2324 2325 /** reset the panel effect */ 2326 function checkActiveFilter(name) { 2327 if (!name) { 2328 for (var item in reverseMap) { 2329 if (!reverseMap.hasOwnProperty(item)) { 2330 continue; 2331 } 2332 _checkFilter(item); 2333 } 2334 } else { 2335 _checkFilter(name); 2336 } 2337 } 2338 2339 function _checkFilter(name) { 2340 if (elm(name).length === 0) { 2341 return; 2342 } 2343 if (_checkIfActive(name) === true) { 2344 elm(name).prev().addClass('search-panel-active'); 2345 } else { 2346 elm(name).prev().removeClass('search-panel-active'); 2347 } 2348 } 2349 2350 /** 2351 * bind event handlers to their according triggers 2352 * @return {None} 2353 */ 2354 function bindEvents() { 2355 //when shown, change the color of panel title to default + icon 2356 elm('filter').on('shown.bs.collapse', function (e) { 2357 if (e.target.id == elements["excludeLocation"] || e.target.id == elements["excludeSponsor"] || e.target.id == elements["excludeActivityLocation"] || e.target.id == elements["excludeCitizenship"]) { 2358 return; 2359 } 2360 var panelTitleElm = $(this).prev(); /*previous item = heading*/ 2361 panelTitleElm 2362 .find(elements['filter.open']).addClass('hidden') 2363 .end() /* reset chain */ 2364 .find(elements['filter.close']).removeClass('hidden') 2365 .end() 2366 .find(elements['filter.toggle']).attr('aria-expanded', 'true'); 2367 }); 2368 //when hidden, change the color of panel title to active if there is something there + icon 2369 elm('filter').on('hidden.bs.collapse', function (e) { 2370 if (e.target.id == elements["excludeLocation"] || e.target.id == elements["excludeSponsor"] || e.target.id == elements["excludeActivityLocation"] || e.target.id == elements["excludeCitizenship"]) { 2371 return; 2372 } 2373 var panelTitleElm = $(this).prev(); /*previous item = heading*/ 2374 panelTitleElm 2375 .find(elements['filter.close']).addClass('hidden') 2376 .end() /* reset chain */ 2377 .find(elements['filter.open']).removeClass('hidden') 2378 .end() 2379 .find(elements['filter.toggle']).attr('aria-expanded', 'false'); 2380 }); 2381 //if search reset is clicked ==> also restore the state of panel titles 2382 //to cover all the cases 2383 $(document).on('czd_search_filter_before_change', function (e) { 2384 checkActiveFilter(); 2385 }); 2386 2387 elm('filter.toggle').on('click', function () { 2388 }); 2389 2390 elm('filter.toggle').on('keydown', function (event) { 2391 if (event.which === 32) { 2392 event.preventDefault(); 2393 $(event.currentTarget).click(); 2394 } 2395 }); 2396 } 2397 2398 /** 2399 * initialize function 2400 * @return {None} 2401 */ 2402 function init() { 2403 bindEvents(); 2404 } 2405 2406 //run initialization function 2407 init(); 2408 2409 //expose any method / attributes here 2410 return { 2411 checkOpenFilter: checkOpenFilter 2412 }; 2413 2414}; 2415 2416 2417//all search filter tooltips should be initialized 2418$(document).ready(function () { 2419 2420 //2.9: the goto filter 2421 $('.gotofilter').on('change', function (e) { 2422 var pivot = $(this).val(); 2423 var topVal; 2424 var element = null; 2425 if (pivot === '') { 2426 return; 2427 } else { 2428 element = $('[js-pivot="' + pivot + '"]'); 2429 if (element.length === 0) { 2430 return; 2431 } else { 2432 topVal = element.offset().top; 2433 } 2434 } 2435 _trackGSEvent( 2436 '2.0-Index', 2437 'filter_shortcut', 2438 pivot 2439 ); 2440 2441 $('html, body').animate({ 2442 'scrollTop': Math.max(0, topVal - 70) //the buffer 2443 }, 800, function () { 2444 $('.gotofilter').val(''); 2445 if (element !== null) { 2446 element.find('.accordion-toggle').focus(); 2447 element.find(".panel-collapse").collapse('show'); 2448 } 2449 }); 2450 }); 2451 2452 $('.back-top-from-filter a').on('click', function () { 2453 $('html, body').animate({ 2454 'scrollTop': 0 2455 }, 800, function () { 2456 $('.skip-nav.skip-main').focus(); 2457 }); 2458 }); 2459 2460 $('.search-filter-tooltip').each(function () { 2461 $(this).attr('aria-label', $(this).attr('title')); 2462 }); 2463 $('.search-filter-tooltip').tooltip({ 2464 container: 'body' 2465 }); 2466 2467 //init the share url popup to spare the trouble of handling load callback 2468 $('.share-search-popup').modal({ 2469 remote: "/search/get_shared_search_template", 2470 show: false, 2471 }); 2472 $(document).on('mouseenter touchstart focus', 'button.comment_button', function () { 2473 if (!$(this).controller('CommentButton')) { 2474 //init comments 2475 $(this).comment_button(); 2476 } 2477 }); 2478 2479 // Duy Dinh Init Accessilibity to tag list 2480 if (window.czdAccess) { 2481 window.czdAccess.addAccessibilityToButtonGroup($(".tag-container")) 2482 window.czdAccess.addAccessibilityToDropDown(".czd-dropdown", "GrantSaveLoadDropDown") 2483 } 2484});
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.