1/* 2 * flexibleSearch.js 3 * 4 * Copyright (c) Tomohiro Okuwaki / bit part LLC (http://bit-part.net/) 5 * 6 * Since : 2010-11-12 7 * Update : 2017-06-24 8 * Version: 2.3.1 9 * Comment: Please use this with Movable Type :) 10 * 11 * You have to include "mustache.js" before "flexibleSearch.js". 12 * Maybe... jQuery 1.7.x later 13 * 14-*/ 15 16(function ($) { 17 $.fn.flexibleSearch = function (options) { 18 var op = $.extend({}, $.fn.flexibleSearch.defaults, options); 19 var $this = this; 20 21 // ======================================================================= 22 // Search Form HTML <start> 23 // 24 25 if (op.searchFormCreation) { 26 27 // Advanced Form HTML <start> 28 var advancedFormTmpl = []; 29 var advancedFormHTML = ""; 30 if (op.advancedFormObj !== null) { 31 // input:hidden 32 if ("hidden" in op.advancedFormObj) { 33 advancedFormTmpl.push([ 34 '<div class="fs-advanced-hidden" style="display:none;">', 35 '{{#hidden}}', 36 '<input type="hidden"', 37 '{{#id}} id="{{id}}"{{/id}}', 38 '{{#name}} name="{{name}}"{{/name}}', 39 '{{#value}} value="{{value}}"{{/value}}>', 40 '{{/hidden}}', 41 '</div>' 42 ].join("")); 43 } 44 45 // input:text 46 if ("text" in op.advancedFormObj) { 47 advancedFormTmpl.push([ 48 '<div class="fs-advanced-text">', 49 '{{#text}}', 50 '{{#label}}', 51 '<label{{#id}} id="{{id}}-label"{{/id}}{{#name}} for="{{name}}"{{/name}} class="fs-text{{#name}} fs-{{name}}{{/name}}">', 52 '{{/label}}', 53 '<input type="text"', 54 '{{#id}} id="{{id}}"{{/id}}', 55 '{{#name}} name="{{name}}"{{/name}}', 56 '{{#value}} value="{{value}}"{{/value}}', 57 '{{#placeholder}} placeholder="{{placeholder}}"{{/placeholder}}>', 58 '{{#label}}', 59 '{{label}}</label>', 60 '{{/label}}', 61 '{{/text}}', 62 '</div>' 63 ].join("")); 64 } 65 66 // input:checkbox 67 if ("checkbox" in op.advancedFormObj) { 68 advancedFormTmpl.push([ 69 '<div class="fs-advanced-checkbox">', 70 '{{#checkbox}}', 71 '{{#label}}', 72 '<label{{#id}} id="{{id}}-label"{{/id}}{{#name}} for="{{name}}"{{/name}} class="fs-checkbox{{#name}} fs-{{name}}{{/name}}">', 73 '{{/label}}', 74 '<input type="checkbox"', 75 '{{#id}} id="{{id}}"{{/id}}', 76 '{{#name}} name="{{name}}"{{/name}}', 77 '{{#value}} value="{{value}}"{{/value}}', 78 '{{#checked}} checked="checked"{{/checked}}>', 79 '{{#label}}', 80 '{{label}}</label>', 81 '{{/label}}', 82 '{{/checkbox}}', 83 '</div>' 84 ].join("")); 85 } 86 87 // input:radio 88 if ("radio" in op.advancedFormObj) { 89 advancedFormTmpl.push([ 90 '<div class="fs-advanced-radio">', 91 '{{#radio}}', 92 '{{#label}}', 93 '<label{{#id}} id="{{id}}-label"{{/id}}{{#name}} for="{{name}}"{{/name}} class="fs-radio{{#name}} fs-{{name}}{{/name}}">', 94 '{{/label}}', 95 '<input type="radio"', 96 '{{#id}} id="{{id}}"{{/id}}', 97 '{{#name}} name="{{name}}"{{/name}}', 98 '{{#value}} value="{{value}}"{{/value}}', 99 '{{#checked}} checked="checked"{{/checked}}>', 100 '{{#label}}', 101 '{{label}}</label>', 102 '{{/label}}', 103 '{{/radio}}', 104 '</div>' 105 ].join("")); 106 } 107 108 // Make HTML of hidden, text, checkbox and radio 109 advancedFormHTML = Mustache.render(advancedFormTmpl.join(""), op.advancedFormObj); 110 111 // input:select 112 if ("select" in op.advancedFormObj) { 113 var advancedFormSelectObj = { 114 "selects": op.advancedFormObj.select, 115 "options": function () { 116 var optionObj = this.option; 117 var optionSet = []; 118 for (var i = 0, l = optionObj.length; i < l; i++) { 119 var slctd = optionObj[i].selected ? " selected": ""; 120 optionSet.push('<option value="' + optionObj[i].value + '"' + slctd + '>
120' + optionObj[i].label +'</option>'); 121 } 122 return optionSet.join(""); 123 } 124 }; 125 var advancedFormSelectTmpl = [ 126 '<div class="fs-advanced-select">', 127 '{{#selects}}', 128 '<select{{#id}} id="{{id}}"{{/id}}{{#name}} name="{{name}}"{{/name}}{{#size}} size="{{size}}"{{/size}}{{#multiple}} multiple{{/multiple}} class="fs-select{{#name}} fs-{{name}}{{/name}}">', 129 '{{{options}}}', 130 '</select>', 131 '{{/selects}}', 132 '</div>' 133 ].join(""); 134 135 // Make HTML of select 136 advancedFormHTML += Mustache.render(advancedFormSelectTmpl, advancedFormSelectObj); 137 } 138 } 139 // Advanced Form HTML </end> 140 141 // Search Form <start> 142 // 143 // * {{action}} (= op.searchFormAction) 144 // * {{type}} (= op.searchFormInputType) 145 // * {{placeholder}} (= op.searchFormInputPlaceholder) 146 // * {{submitBtnText}} (= op.searchFormSubmitBtnText) 147 var searchFormObj = { 148 action: op.searchFormAction, 149 type: op.searchFormInputType, 150 placeholder: op.searchFormInputPlaceholder, 151 submitBtnText: op.searchFormSubmitBtnText 152 }; 153 var searchFormHTML = ""; 154 if (op.limit !== null && typeof op.limit === 'number') { 155 op.paginateCount = op.limit; 156 } 157 if (op.searchFormHTML !== null) { 158 searchFormHTML = op.searchFormHTML; 159 } 160 else { 161 var searchFormTmpl = [ 162 '<form action="{{action}}" method="GET">', 163 '<input type="hidden" name="offset" value="0">', 164 '<input type="hidden" name="limit" value="' + op.paginateCount + '">', 165 '<input type="{{type}}" name="search" placeholder="{{placeholder}}" class="fs-text fs-search">', 166 '<input type="submit" value="{{submitBtnText}}" class="fs-btn fs-submit">', 167 advancedFormHTML, // Advanced Form 168 '</form>' 169 ].join(""); 170 171 // Make search form HTML 172 searchFormHTML = Mustache.render(searchFormTmpl, searchFormObj); 173 } 174 // Search Form </end> 175 176 // Insert into DOM 177 $this[0].innerHTML = searchFormHTML; 178 } 179 180 // 181 // Search Form HTML </end> 182 // ----------------------------------------------------------------------- 183 184 // ======================================================================= 185 // Result Block Template <start> 186 // 187 188 // Search Result Loading Image <start> 189 var resultLoadingHTML = ""; 190 if (op.loadingImgHTML !== null) {
191 resultLoadingHTML = op.loadingImgHTML; 192 } 193 else if (op.loadingImgPath) { 194 resultLoadingHTML = '<span class="fs-loading"><img src="' + op.loadingImgPath + '" alt=""></span>'; 195 } 196 // Search Result Loading Image </end> 197 198 // Search Result Message <start> 199 // 200 // * {{keywords}} 201 // * {{count}} 202 // * {{firstPage}} 203 // * {{lastPage}} 204 // * {{currentPage}} 205 var resultMsgTmpl = ""; 206 if (op.resultMsgTmpl !== null) { 207 resultMsgTmpl = op.resultMsgTmpl; 208 } 209 else { 210 resultMsgTmpl = [ 211 '<div{{#id}} id="{{id}}"{{/id}}{{#classname}} class="{{classname}}"{{/classname}}>', 212 '<p>', 213 '{{#keywords}}ã{{keywords}}ãã {{/keywords}}', 214 '{{#count}}{{count}} ä»¶è¦ã¤ããã¾ããã{{/count}}', 215 '{{^count}}è¦ã¤ããã¾ããã§ããã{{/count}}', 216 '{{#count}}ï¼{{lastPage}} ãã¼ã¸ä¸ {{currentPage}} ãã¼ã¸ç®ã表示ï¼{{/count}}', 217 // 'ï¼{{firstPage}}ã{{lastPage}} ãã¼ã¸ä¸ {{currentPage}} ãã¼ã¸ç®ã表示ï¼', 218 '</p>', 219 '</div>' 220 ].join(""); 221 } 222 // Search Result Message </end> 223 224 // Search Result Item <start> 225 // 226 // * keys used in your JSON 227 var resultItemTmpl = ""; 228 if (op.resultItemTmpl !== null) { 229 resultItemTmpl = op.resultItemTmpl; 230 } 231 else { 232 resultItemTmpl = [ 233 '<div id="' + op.resultBlockId + '-items">', 234 '<ul>', 235 '{{#items}}', 236 '<li>{{&title}}</li>', 237 '{{/items}}', 238 '</ul>', 239 '</div>' 240 ].join(""); 241 } 242 // Search Result Item </end> 243 244 // Paginate <start> 245 // 246 // * {{paginateId}} 247 // * {{¤t}} 248 // * {{.}} 249 var paginateTmpl = ""; 250 if (op.paginateTmpl !== null) { 251 paginateTmpl = op.paginateTmpl; 252 } 253 else { 254 paginateTmpl = [ 255 '<div{{#id}} id="{{id}}"{{/id}}{{#classname}} class="{{classname}}"{{/classname}}>', 256 '<ul>', 257 258 '{{#showTurnPage}}', 259 '{{#exceptFirst}}', 260 '<li class="fs-prev"><span><a class="fs-prev-link fs-turn-page-link" href="#" title="{{prevPageText}}">{{prevPageText}}</a></span></li>', 261 '{{/exceptFirst}}', 262 '{{/showTurnPage}}', 263 264 '{{#page}}', 265 '{{#checkRange}}', 266 '<li class="{{current}}"{{#hidePageNumber}} style="display:none;"{{/hidePageNumber}}><span><a class="fs-page-link {{currentLink}}" href="#" title="{{pageNumber}}">{{pageNumber}}</a></span></li>', 267 '{{/checkRange}}', 268 '{{/page}}', 269 270 '{{#showTurnPage}}', 271 '{{#exceptLast}}', 272 '<li class="fs-next"><span><a class="fs-next-link fs-turn-page-link" href="#" title="{{nextPageText}}">{{nextPageText}}</a></span></li>', 273 '{{/exceptLast}}', 274 '{{/showTurnPage}}', 275 276 '</ul>', 277 '</div>' 278 ].join(""); 279 } 280 // Paginate </end> 281 282 // 283 // Result Block Template </end> 284 // ----------------------------------------------------------------------- 285 286 // ======================================================================= 287 // Get parameters and serialize parameters <start> 288 // 289 290 // Serialize parameters 291 $this.find("form").on("submit", function (e) { 292 e.preventDefault(); 293 var url = $(this).attr("action") || location.href.replace(/\?.*/, ""); 294 var params = $(this).serializeArray(); 295 var postParams = [];
296 for (var i = -1, n = params.length; ++i < n;) { 297 if (params[i].name === "search") { 298 postParams.push({name:"search",value:$.trim(params[i].value.replace(/[ |ã]+/g, " "))}); 299 }else if (params[i].name == "cate[]" || params[i].name == "site[]") { 300 }else{ 301 postParams.push(params[i]); 302 } 303 } 304 var cates=[]; 305 $("#catelistUl").children().each(function(index) { 306 cateLoop(this,cates); 307 }); 308 postParams.push({name:"cate[]",value:cates.join(",")}); 309 cates=[]; 310 $("#sitelistUl").children().each(function(index) { 311 cateLoop(this,cates); 312 }); 313 postParams.push({name:"site[]",value:cates.join(",")}); 314 postParams = op.submitAction(postParams); 315 var serializeParams = $.param(postParams); 316 if (serializeParams) { 317 url = url + "?" + serializeParams; 318 } 319 location.href = url; 320 return false; 321 }); 322 323 var paramStr = decodeURIComponent(location.search.replace(/^\?/, "")); 324 325 // Set initial parameters 326 if (paramStr === '' && op.initialParameter !== null && typeof op.initialParameter === 'string') { 327 paramStr = decodeURIComponent(op.initialParameter.replace(/^\?/, "")); 328 } 329 330 // 331 // Get parameters and serialize parameters </end> 332 // ----------------------------------------------------------------------- 333 334 // ======================================================================= 335 // Preload search data files <start> 336 // 337 338 if (paramStr === "") { 339 switch (typeof op.searchDataPathPreload) { 340 case "string": 341 $.ajax({ 342 type: "GET", 343 cache: true, 344 dataType: "json", 345 url: op.searchDataPathPreload 346 }); 347 break; 348 case "object": 349 if (op.searchDataPathPreload === null || op.searchDataPathPreload === "") { 350 break; 351 } 352 if (op.searchDataPathPreload.length) { 353 for (var i = -1, n = op.searchDataPathPreload.length; ++i < n;) { 354 $.ajax({ 355 type: "GET", 356 cache: true, 357 dataType: "json", 358 url: op.searchDataPathPreload[i] 359 }); 360 } 361 } 362 else { 363 for (var key in op.searchDataPathPreload) { 364 $.ajax({ 365 type: "GET", 366 cache: true, 367 dataType: "json", 368 url: op.searchDataPathPreload[key] 369 }); 370 } 371 } 372 break; 373 } 374 return false; 375 } 376 377 // 378 // Preload search data files </end> 379 // ----------------------------------------------------------------------- 380 381 // Search Result Loading Image 382 if (resultLoadingHTML) { 383 document.getElementById(op.resultBlockId).innerHTML = resultLoadingHTML; 384 } 385 386 // Set values to Search Form 387 var searchWords = []; 388 var paramAry = paramStr.split(/&|%26/); 389 var paramObj = {}; 390 var paramExistArry = []; 391 var advancedSearchObj = {}; 392 var limit = (op.limit !== null && typeof op.limit === 'number') ? op.limit: 10; 393 var offset = 0; 394 var sortBy = ""; 395 var sortOrder = ""; 396 var sortType = ""; 397 var jsonPath = ""; 398 var dataId = ""; 399 var api = false; 400 var excludeParams = ["search", "dataId", "offset", "limit", "sortBy", "sortOrder", "sortType"]; 401 if (op.simplePaginate === true) { 402 excludeParams.push("page"); 403 } 404 if (op.excludeParams !== null) { 405 $.merge(excludeParams, op.excludeParams.toLowerCase().split(",")); 406 } 407
408 for (var i = -1, n = paramAry.length; ++i < n;) { 409 var param = paramAry[i].split("="); 410 var key = param[0]; 411 var value = param[1] || ""; 412 paramObj[key] = value; 413 // Set "advancedSearchObj" and "searchWords" 414 switch (key) { 415 case "search": 416 value = (value === "+") ? "" : value; // If value is " ", it is "+" on URL. 417 searchWords = value.split(/\+| |%20/); 418 break; 419 case "offset": 420 offset = value; 421 break; 422 case "limit": 423 limit = (op.limit !== null && typeof op.limit === 'number') ? op.limit: value; 424 break; 425 case "dataId": 426 dataId = value; 427 break; 428 case "sortBy": 429 sortBy = value.toLowerCase(); 430 break; 431 case "sortOrder": 432 sortOrder = value.toLowerCase(); 433 break; 434 case "sortType": 435 sortType = value.toLowerCase(); 436 break; 437 } 438 439 // Restore search condition 440 if (key === "offset" || key === "limit") { 441 continue; 442 } 443 if (op.simplePaginate === true && key === "page") { 444 continue; 445 } 446 if(key.indexOf("[]") > -1){ 447 if(value==""){ 448 paramObj[key] = []; 449 }else{ 450 $this.find("[name='" + key + "']").each(function () { 451 values = value.split(","); 452 var type = $(this).attr('type'); 453 if (values.indexOf($(this).val()) > -1) { 454 $(this).prop("checked", true); 455 $(this).change(); 456 } 457 paramObj[key] = values; 458 }); 459 } 460 461 }else{ 462 $this.find("[name='" + key + "']").each(function () { 463 var tagname = this.tagName.toLowerCase(); 464 switch (tagname) { 465 case "input": 466 var type = $(this).attr('type'); 467 if (type === "checkbox" && $(this).val() === value) { 468 $(this).prop("checked", true); 469 } 470 else if (type === "radio" && $(this).val() === value) { 471 $(this).prop("checked", true); 472 } 473 else if (type === "text" || type === "search" || type === "hidden") { 474 if (key === "search") { 475 $(this).val(value.replace(/\+/g," ")); 476 } else { 477 $(this).val(value); 478 } 479 } 480 break; 481 case "select": 482 $(this).find("option").each(function () { 483 if ($(this).val() === value) { 484 $(this).prop("selected", true); 485 } 486 else if (value === "" && $(this).val() === " ") { 487 $(this).prop("selected", true); 488 } 489 }); 490 break; 491 } 492 }); 493 } 494 495 // Set advancedSearchObj. This object is used in original search. 496 if (value !== "") { 497 value = value.replace(/\+/g, " "); 498 if ($.inArray(key, excludeParams) !== -1) { 499 continue; 500 } 501 if ($.inArray(key, paramExistArry) !== -1) { 502 advancedSearchObj[key] += "," + value; 503 } 504 else { 505 advancedSearchObj[key] = value; 506 } 507 } 508 paramExistArry.push(key); 509 } // for 510 511 // For simple paginate option 512 if (op.simplePaginate === true && typeof paramObj["page"] !== 'undefined') { 513 if (/all/i.test(paramObj["page"])) { 514 offset = 0; 515 limit = 100000000; 516 } 517 else { 518 offset = (paramObj["page"] - 1) * limit; 519 } 520 } 521 522 // Set paramKeyCount 523 var paramKeyCount = 0; 524 for (var key in advancedSearchObj) { 525 paramKeyCount++; 526 } 527 528 // ======================================================================= 529 // Set JSON path and using Data API <start> 530 // 531 532 // Set jsonPath 533 switch (typeof op.searchDataPath) { 534 case "string": 535 jsonPath = op.searchDataPath; 536 break; 537 case "object": 538 if (dataId === "") { 539 window.alert("dataId is required."); 540 return; 541 } 542 else { 543 if (op.dataApiDataIds !== null && $.inArray(dataId, op.dataApiDataIds.split(",")) !== -1) { 544 api = true; 545 if (op.dataApiParams !== null) { 546 paramStr += (paramStr !== "") ? "&" + $.param(op.dataApiParams): $.param(op.dataApiParams); 547 } 548 } 549 jsonPath = op.searchDataPath[dataId]; 550 } 551 break; 552 } 553 554 // 555 // Set JSON path and using Data API </end> 556 // ----------------------------------------------------------------------- 557 558 // ======================================================================= 559 // Search <start> 560 // 561 if (api) { 562 jsonPath += "?" + paramStr; 563 } 564 $.ajax({ 565 type: "GET", 566 cache: op.cache, 567 dataType: "json", 568 url: jsonPath, 569 error: function (jqXHR, textStatus, errorThrown) { 570 op.ajaxError(jqXHR, textStatus, errorThrown); 571 }, 572 success: function (response) { 573 var resultJSON = {}; 574 if (api) { 575 // Data API 576 resultJSON = response; 577 } 578 else { 579 // Original JSON 580 // Clone the items 581 var cloneItems = $.grep(response.items, function () { 582 return true; 583 }); 584 // Advanced Search 585 cloneItems = $.grep(cloneItems, function (item, i) { 586 return jsonAdvancedSearch (item, advancedSearchObj, paramKeyCount, "like", op.advancedSearchCond); 587 }); 588 589 // Search by keywords 590 cloneItems = $.grep(cloneItems, function (item, i) { 591 return jsonKeywordsSearch (item, searchWords); 592 }); 593 594 // äºåå å·¥ 595 if (op.modifyCloneJSON !== null && typeof op.modifyCloneJSON === "function") { 596 cloneItems = op.modifyCloneJSON(cloneItems); 597 } 598 // Do custom search 599 if (op.customSearch !== null && typeof op.customSearch === "function") { 600 cloneItems = $.grep(cloneItems, function (item, i) { 601 return op.customSearch(item, paramObj); 602 }); 603 } 604 605 // Set resultJSON 606 var limitIdx = Number(limit) + Number(offset); 607 resultJSON.totalResults = cloneItems.length; 608 609 // Sort 610 if (resultJSON.totalResults !== 0 && sortBy !== "" && sortBy in cloneItems[0]) { 611 if (sortOrder !== "ascend") { 612 sortOrder = "descend"; 613 } 614 if (sortType !== "numeric") { 615 sortType = "string"; 616 } 617 objectSort(cloneItems, sortBy, sortOrder, sortType); 618 } 619 620 // Custom Sort 621 if (op.customSort !== null && typeof op.customSort === "function") { 622 cloneItems = op.customSort(cloneItems, paramObj); 623 } 624 625 resultJSON.items = $.grep(cloneItems, function (item, i) { 626 if (i < offset) { 627 return false;
628 } 629 else if (i >= limitIdx) { 630 return false; 631 } 632 else { 633 return true; 634 } 635 }); 636 } 637 // Paginate 638 var currentPage = Math.ceil(offset / limit) + 1; 639 var realMaxPageCount = Math.ceil(resultJSON.totalResults / limit); 640 var maxPageCount = op.maxPageCount ? op.maxPageCount : 100; 641 var forwordRange = ((maxPageCount % 2) == 0) ? (maxPageCount / 2) - 1 : Math.floor(maxPageCount / 2); 642 var backwardRange = ((maxPageCount % 2) == 0) ? maxPageCount / 2 : Math.floor(maxPageCount / 2); 643 var startPage, lastPage; 644 if (realMaxPageCount <= maxPageCount) { 645 startPage = 1; 646 lastPage = realMaxPageCount; 647 } 648 else { 649 startPage = currentPage - forwordRange; 650 lastPage = currentPage + backwardRange; 651 if (startPage < 1) { 652 startPage = 1; 653 lastPage = maxPageCount; 654 } 655 else { 656 if (lastPage > realMaxPageCount) { 657 backwardRange = realMaxPageCount - currentPage; 658 lastPage = realMaxPageCount; 659 forwordRange = maxPageCount - backwardRange; 660 startPage = currentPage - forwordRange; 661 } 662 } 663 } 664 var pageList = []; 665 for (var i = 0, n = realMaxPageCount; ++i <= n;) { 666 pageList.push({pageNumber: i}); 667 } 668 var paginateJSON = { 669 id: op.paginateId, 670 classname: op.paginateClassName, 671 page: pageList, 672 hidePageNumber: op.hidePageNumber, 673 showTurnPage: op.showTurnPage, 674 prevPageText: op.prevPageText, 675 nextPageText: op.nextPageText, 676 isFirst: function(){ 677 return currentPage === 1; 678 }, 679 isLast: function(){ 680 if (!pageList.length) { 681 return true; 682 } 683 return currentPage === pageList.length; 684 }, 685 exceptFirst: function(){ 686 return currentPage !== 1; 687 }, 688 exceptLast: function(){ 689 return pageList.length > 0 && currentPage !== pageList.length; 690 }, 691 checkRange: function(){ 692 return this.pageNumber >= startPage && this.pageNumber <= lastPage; 693 }, 694 current: function () { 695 if (this.pageNumber === currentPage) { 696 return 'fs-current'; 697 } 698 else if (this.pageNumber === (currentPage - 1)) { 699 return "fs-current-prev"; 700 } 701 else if (this.pageNumber === (currentPage + 1)) { 702 return "fs-current-next"; 703 } 704 else { 705 return ""; 706 } 707 }, 708 isCurrent: function(){ 709 return this.pageNumber === currentPage; 710 }, 711 lastPage: function () { 712 return paginateJSON.page.length; 713 }, 714 currentLink: function () { 715 if (this.pageNumber === currentPage) { 716 return 'fs-current-link'; 717 } 718 else if (this.pageNumber === (currentPage - 1)) { 719 return "fs-current-prev-link"; 720 } 721 else if (this.pageNumber === (currentPage + 1)) { 722 return "fs-current-next-link"; 723 } 724 else { 725 return ""; 726 } 727 }, 728 currentCountFrom: function () { 729 return offset - 0 + 1; 730 }, 731 currentCountTo: function () { 732 var num = offset - 0 + limit; 733 var res = num < resultJSON.totalResults ? num : resultJSON.totalResults; 734 return res - 0; 735 }, 736 totalResults: resultJSON.totalResults, 737 count: resultJSON.totalResults, 738 currentPage: currentPage 739 }; 740 var paginateHTML = Mustache.render(paginateTmpl, paginateJSON); 741 742 // Result message 743 var resultMsgObj = { 744 id: op.resultMsgId ? op.resultMsgId : '', 745 classname: op.resultMsgClassName ? op.resultMsgClassName : '', 746 keywords: searchWords.join(', '), 747 keywordArray: searchWords.join('') !== '' ? searchWords : null, 748 count: resultJSON.totalResults, 749 metaTitle: document.title, 750 firstPage: function () { 751 return paginateJSON.page[0].pageNumber; 752 }, 753 lastPage: function () { 754 return paginateJSON.page.length; 755 }, 756 currentPage: currentPage 757 }; 758 var resultMsgHTML = Mustache.render(resultMsgTmpl, resultMsgObj); 759 760 // Set the meta title 761 if (op.resultMetaTitleRewrite) { 762 var resultMetaTitleTmpl = (op.resultMetaTitleTmpl) ? op.resultMetaTitleTmpl : [ 763 // '{{#keywords}}{{keywords}}{{/keywords}}', 764 '{{#keywordArray}}{{.}} {{/keywordArray}}', 765 '{{#count}} {{count}}ä»¶{{/count}}', 766 '{{#count}} {{currentPage}}/{{lastPage}}{{/count}}', 767 '{{#metaTitle}} | {{metaTitle}}{{/metaTitle}}'
768 ].join(""); 769 var resultMetaTitleHTML = Mustache.render(resultMetaTitleTmpl, resultMsgObj); 770 document.title = resultMetaTitleHTML; 771 } 772 773 // Show result 774 if (op.modifyResultJSON !== null && typeof op.modifyResultJSON === "function") { 775 resultJSON = op.modifyResultJSON(resultJSON); 776 } 777 var resultItemHTML = Mustache.render(resultItemTmpl, resultJSON); 778 779 // Callback 780 if (op.modifyResultMsgHTML !== null && typeof op.modifyResultMsgHTML === "function") { 781 resultMsgHTML = op.modifyResultMsgHTML(resultMsgHTML); 782 } 783 if (op.modifyResultItemHTML !== null && typeof op.modifyResultItemHTML === "function") { 784 resultItemHTML = op.modifyResultItemHTML(resultItemHTML); 785 } 786 if (op.modifyPaginateHTML !== null && typeof op.modifyPaginateHTML === "function") { 787 paginateHTML = op.modifyPaginateHTML(paginateHTML); 788 } 789 790 // Search Result Block HTML 791 var resultAllHTML = ''; 792 793 // Add result message HTML 794 if (op.resultMsgInsertMethods === null) { 795 resultAllHTML += resultMsgHTML; 796 } 797 // Add result items HTML 798 resultAllHTML += resultItemHTML; 799 // Add paginate HTML 800 if (realMaxPageCount === 1 && op.hideOnePagePaginate === true) { 801 // nothing to do 802 } 803 else if (op.paginateInsertMethods === null) { 804 resultAllHTML += paginateHTML; 805 } 806 807 // Add all of result HTML to DOM 808 document.getElementById(op.resultBlockId).innerHTML = resultAllHTML; 809 810 // Add result message HTML to DOM 811 if (op.resultMsgInsertMethods !== null) { 812 for (var i = 0, l = op.resultMsgInsertMethods.length; i < l; i++) { 813 $(op.resultMsgInsertMethods[i].selector)[op.resultMsgInsertMethods[i].method](resultMsgHTML); 814 } 815 } 816 // Add paginate HTML to DOM 817 if (realMaxPageCount === 1 && op.hideOnePagePaginate === true) { 818 // nothing to do 819 } 820 else if (op.paginateInsertMethods !== null) { 821 for (var i = 0, l = op.paginateInsertMethods.length; i < l; i++) { 822 $(op.paginateInsertMethods[i].selector)[op.paginateInsertMethods[i].method](paginateHTML); 823 } 824 } 825 826 // Callback 827 if (op.resultComplete !== null && typeof op.resultComplete === "function") { 828 op.resultComplete(resultJSON.totalResults); 829 } 830 831 // Bind pageLink() to paginate link 832 var paginateSelector = op.paginateId ? "#" + op.paginateId : "." + op.paginateClassName; 833 $(paginateSelector) 834 .on("click", "a.fs-page-link", function (e) { 835 e.preventDefault(); 836 var page = $(this).attr("title"); 837 var offset = (Number(page) - 1) * Number(limit); 838 var url = location.href.replace(/\?.*/g, ''); 839 var query = location.search ? location.search.replace(/^\?/, '') : op.initialParameter; 840 if (op.simplePaginate === true) { 841 if (query.indexOf('page=') === -1) { 842 query += query ? '&page=' + page : 'page=' + page; 843 } 844 else { 845 query = query.replace(/page=[0-9]+/, 'page=' + page); 846 } 847 query = query.replace(/&?offset=[0-9]+/g, ''); 848 } 849 else { 850 if (query.indexOf('offset=') === -1) { 851 query += query ? '&offset=' + offset : 'offset=' + offset; 852 } 853 else { 854 query = query.replace(/offset=[0-9]+/, 'offset=' + offset); 855 } 856 query = query.replace(/&?offset=0/, ''); 857 } 858 if (query) { 859 url += "?" + query.replace(/^&+/, ''); 860 } 861 location.href = url; 862 }) 863 .on("click", "a.fs-turn-page-link", function (e) { 864 e.preventDefault(); 865 if ($(this).hasClass('fs-prev-link')) { 866 $(e.delegateTarget).find('.fs-current-prev-link').trigger('click'); 867 } 868 else if ($(this).hasClass('fs-next-link')) { 869 $(e.delegateTarget).find('.fs-current-next-link').trigger('click'); 870 } 871 }); 872 } // success 873 }); // ajax 874 875 // 876 // Search </end> 877 // ----------------------------------------------------------------------- 878 879 // ======================================================================= 880 // Functions <start> 881 // 882function cateLoop(li,cates){ 883 if($(li).children("input").is(':checked')){ 884 cates.push($(li).children("input").val()); 885 }else{ 886 if($(li).children("ul").length >0){ 887 $(li).children("ul").children("li").each(function(index) { 888 cateLoop(this,cates); 889 }); 890 } 891 } 892 893} 894 895 function jsonAdvancedSearch (obj, advancedSearchObj, paramKeyCount, matchType, cond) { 896 var matched = 0; 897 if (matchType === "like") { 898 for (var key in advancedSearchObj) { 899 var valueArray = advancedSearchObj[key].split(",");
900 var valueArrayLength = valueArray.length; 901 var _matched = 0; 902 for (var i = -1, n = valueArrayLength; ++i < n;) { 903 var reg = new RegExp(valueArray[i].replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1"), "i"); 904 if (typeof obj[key] === "undefined" || typeof obj[key] === "string" && reg.test(obj[key])) { 905 if (cond === 'AND' || cond === 'and') { 906 _matched++; 907 } 908 else { 909 matched++; 910 break; 911 } 912 } 913 // else if (obj[key] && typeof obj[key] === "object" && obj[key].length) { 914 // for (var i = -1, n = obj[key].length; ++i < n;) { 915 // if (reg.test(obj[key])) return true; 916 // } 917 // } 918 } 919 if (cond === 'AND' || cond === 'and') { 920 if (_matched === valueArrayLength) { 921 matched++; 922 } 923 } 924 } 925 return matched === paramKeyCount; 926 } 927 else { 928 for (var key in advancedSearchObj) { 929 if (obj[key] && typeof obj[key] === "string" && obj[key] !== advancedSearchObj[key]) { 930 return false; 931 } 932 // else if (obj[key] && typeof obj[key] === "object" && obj[key].length) { 933 // for (var i = -1, n = obj[key].length; ++i < n;) { 934 // return advancedSearchObj[key] === obj[key][i]; 935 // } 936 // } 937 } 938 } 939 return matched; 940 } 941 942 function jsonKeywordsSearch (obj, keywordsArray) { 943 var keywordsCount = keywordsArray.length; 944 var keywordsMutchCount = 0; 945 for (var i = -1; ++i < keywordsCount;) { 946 var reg = new RegExp(keywordsArray[i].replace(/([.*+?^=!:${}()|[\]\/\\])/g, "\\$1"), "i"); 947 // if (reg.test(obj[key])) keyMatch++; 948 for (var key in obj) { 949 if (reg.test(obj[key])) { 950 keywordsMutchCount++; 951 break; 952 } 953 } 954 } 955 return (keywordsCount === keywordsMutchCount); 956 } 957 958 // Sort object. 959 // @paran {Array} array JSON 960 // @paran {String} sortBy Sort by this property's value. 961 // @paran {String} sortOrder ascend or descend. 962 // @paran {String} sortType numeric or string. 963 function objectSort (array, sortBy, sortOrder, sortType) { 964 if (!sortBy && typeof sortBy !== "string") { 965 return; 966 } 967 sortOrder = (sortOrder === 'ascend') ? -1 : 1; 968 array.sort(function(obj1, obj2){ 969 var v1 = obj1[sortBy]; 970 var v2 = obj2[sortBy]; 971 if (sortType === 'numeric') { 972 v1 = v1 - 0; 973 v2 = v2 - 0; 974 } 975 else if (sortType === 'string') { 976 v1 = '' + v1; 977 v2 = '' + v2; 978 } 979 if (v1 < v2) { 980 return 1 * sortOrder; 981 } 982 if (v1 > v2) { 983 return -1 * sortOrder; 984 } 985 return 0; 986 }); 987 } 988 989 // 990 // Functions </end> 991 // ----------------------------------------------------------------------- 992 }; 993 $.fn.flexibleSearch.defaults = { 994 initialParameter: null, 995 // The limit parameter is overwritten and locked as this value. 996 limit: null, 997 // If you want to use 'page' parameter without 'limit' and 'offset', set true to this option. 998 simplePaginate: false, 999 // Path 1000 searchDataPath: "/flexibleSearch/search.json", 1001 searchDataPathPreload: null, 1002 1003 // Data API 1004 dataApiDataIds: null, 1005 dataApiParams: null, 1006 1007 // Performance 1008 cache: true, // I recommend "true". 1009 1010 // Search Form 1011 searchFormCreation: true, 1012 searchFormHTML: null, 1013 searchFormAction: "", 1014 searchFormInputType: "search", 1015 searchFormInputPlaceholder: "Search words", 1016 searchFormSubmitBtnText: "Search", 1017 1018 // Advanced Search Form 1019 advancedFormObj: null, 1020 advancedSearchCond: 'OR', // 'AND' 1021 1022 // Result Block 1023 loadingImgPath: "/flexibleSearch/loading.gif", 1024 loadingImgHTML: null, 1025
1026 resultBlockId: "fs-result", 1027 resultItemTmpl: null, 1028 1029 resultMsgId: null, 1030 resultMsgClassName: "fs-result-msg", 1031 resultMsgTmpl: null, 1032 1033 resultMetaTitleRewrite: true, 1034 resultMetaTitleTmpl: null, 1035 1036 // You can set an array including plane object which has two properties, 1037 // method property and selector property. 1038 // e.g. 1039 // resultMsgInsertMethods: [ 1040 // { 1041 // "selector": "foo", 1042 // "method": "append" 1043 // } 1044 // ], 1045 resultMsgInsertMethods: null, 1046 1047 // Paginate 1048 paginateId: null, 1049 paginateClassName: "fs-paginate", 1050 paginateTmpl: null, 1051 paginateCount: 10, 1052 hidePageNumber: false, 1053 showTurnPage: true, 1054 prevPageText: 'Prev', 1055 nextPageText: 'Next', 1056 maxPageCount: 10, 1057 // If you want to hide one page pagination, set true. 1058 hideOnePagePaginate: false, 1059 // You can set an array including plane object which has two properties, 1060 // method property and selector property. 1061 // e.g. 1062 // paginateInsertMethods: [ 1063 // { 1064 // "selector": "foo", 1065 // "method": "append" 1066 // } 1067 // ], 1068 paginateInsertMethods: null, 1069 1070 // Submit 1071 submitAction: function (paramArray) { 1072 return paramArray; 1073 }, 1074 1075 // Ajax 1076 ajaxError: function (jqXHR, textStatus, errorThrown) { 1077 window.alert(textStatus); 1078 }, 1079 1080 // Callbacks 1081 1082 // you can search in your logic. 1083 // e.g. 1084 // customSearch: function(item, paramObj){ 1085 // // item : Each item in items 1086 // // paramObj : Plane object of parameters 1087 // // The item is removed when return false 1088 // return true or false; 1089 // }, 1090 customSearch: null, 1091 1092 // You can modify the search result JSON. 1093 // e.g. 1094 // modifyResultJSON = function(json){ 1095 // json["fullName"] = function(){ 1096 // return this.firstName + " " + this.lastName; 1097 // }; 1098 // return json; 1099 // }, 1100 modifyResultJSON: null, 1101 modifyResultMsgHTML: null, 1102 modifyResultItemHTML: null, 1103 modifyPaginateHTML: null, 1104 resultComplete: null, 1105 1106 excludeParams: null, 1107 dummy: false 1108 }; 1109})(jQuery);
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.