1var j = jQuery.noConflict(); 2function CustomMarker( options ) { 3 this.latlng = new google.maps.LatLng({lat: options.position.lat, lng: options.position.lng}); 4 this.setMap(options.map); 5 this.templateData = options.templateData; 6 this.markerData = { 7 pin : options.markerPin 8 }; 9} 10 11 12CustomMarker.prototype = new google.maps.OverlayView(); 13 14CustomMarker.prototype.draw = function() { 15 16 var self = this; 17 18 var div = this.div; 19 20 if (!div) { 21 22 div = this.div = document.createElement('div'); 23 var title = this.templateData.title, 24 title = title.toLowerCase(), 25 title = title.replace(/ /g,'-'); 26 div.className = 'qode-map-marker-holder'; 27 div.setAttribute("id", title); 28 29 var markerInfoTemplate = _.template( j('.qode-info-window-template').html() ); 30 markerInfoTemplate = markerInfoTemplate( self.templateData ); 31 32 var markerTemplate = _.template( j('.qode-marker-template').html() ); 33 markerTemplate = markerTemplate( self.markerData ); 34 35 j(div).append(markerInfoTemplate); 36 j(div).append(markerTemplate); 37 38 div.style.position = 'absolute'; 39 div.style.cursor = 'pointer'; 40 41 var panes = this.getPanes(); 42 panes.overlayImage.appendChild(div); 43 } 44 45 var point = this.getProjection().fromLatLngToDivPixel(this.latlng); 46 47 if (point) { 48 div.style.left = (point.x) + 'px'; 49 div.style.top = (point.y) + 'px'; 50 } 51}; 52 53CustomMarker.prototype.remove = function() { 54 if (this.div) { 55 this.div.parentNode.removeChild(this.div); 56 this.div = null; 57 } 58}; 59 60CustomMarker.prototype.getPosition = function() { 61 return this.latlng; 62}; 63(function($) { 64 "use strict"; 65 66 var maps = {}; 67 qode.modules.maps = maps; 68 qode.modules.maps.qodeInitMultipleListingMap = qodeInitMultipleListingMap; 69 qode.modules.maps.qodeInitSingleListingMap = qodeInitSingleListingMap; 70 qode.modules.maps.qodeInitMobileMap = qodeInitMobileMap; 71 qode.modules.maps.qodeGoogleMaps = {}; 72 73 $(document).ready(qodeOnDocumentReady); 74 $(window).load(qodeOnWindowLoad); 75 $(window).resize(qodeOnWindowResize); 76 $(window).scroll(qodeOnWindowScroll); 77 78 function qodeOnDocumentReady() {} 79 80 function qodeOnWindowLoad() { 81 qodeInitSingleListingMap(); 82 qodeInitMultipleListingMap(); 83 qodeInitMobileMap(); 84 } 85 86 function qodeOnWindowResize() {} 87 88 function qodeOnWindowScroll() {} 89 90 function qodeInitSingleListingMap() { 91 var mapHolder = $('#qode-ls-single-map-holder'); 92 if ( mapHolder.length ) { 93 qode.modules.maps.qodeGoogleMaps.getDirectoryItemAddress({ 94 mapHolder: 'qode-ls-single-map-holder' 95 }); 96 } 97 } 98 99 function qodeInitMultipleListingMap() { 100 var mapHolder = $('#qode-ls-multiple-map-holder'); 101 if ( mapHolder.length ) { 102 qode.modules.maps.qodeGoogleMaps.getDirectoryItemsAddresses({ 103 mapHolder: 'qode-ls-multiple-map-holder', 104 hasFilter: true 105 }); 106 } 107 } 108 109 qode.modules.maps.qodeGoogleMaps = { 110 111 //Object varibles 112 mapHolder : {}, 113 map : {}, 114 markers : {}, 115 radius : {}, 116 117 /** 118 * Returns map with single address 119 * 120 * @param options 121 */ 122 getDirectoryItemAddress : function( options ) { 123 /** 124 * use qodeMapsVars to get variables for address, latitude, longitude by default 125 */ 126 var defaults = { 127 location : qodeSingleMapVars.single['currentListing'].location, 128 type : qodeSingleMapVars.single['currentListing'].listingType, 129 zoom : 16, 130 mapHolder : '', 131 draggable : qodeMapsVars.global.draggable, 132 mapTypeControl : qodeMapsVars.global.mapTypeControl, 133 scrollwheel : qodeMapsVars.global.scrollable, 134 streetViewControl : qodeMapsVars.global.streetViewControl, 135 zoomControl : qodeMapsVars.global.zoomControl, 136 title : qodeSingleMapVars.single['currentListing'].title, 137 content : '', 138 styles: qodeMapsVars.global.mapStyle, 139 markerPin : qodeSingleMapVars.single['currentListing'].markerPin, 140 featuredImage : qodeSingleMapVars.single['currentListing'].featuredImage, 141 itemUrl : qodeSingleMapVars.single['currentListing'].itemUrl 142 }; 143 var settings = $.extend( {}, defaults, options ); 144 145 //Save variables for later usage 146 this.mapHolder = settings.mapHolder; 147 148 //Get map holder 149 var mapHolder = document.getElementById( settings.mapHolder ); 150 151 //Initialize map 152 var map = new google.maps.Map( mapHolder, { 153 zoom : settings.zoom, 154 draggable : settings.draggable, 155 mapTypeControl : settings.mapTypeControl, 156 scrollwheel : settings.scrollwheel, 157 streetViewControl : settings.streetViewControl, 158 zoomControl : settings.zoomControl 159 }); 160 161 //Set map style 162 map.setOptions({ 163 styles: settings.styles 164 }); 165 166 //Try to locate by latitude and longitude 167 if ( typeof settings.location !== 'undefined' && settings.location !== null) { 168 var latLong = { 169 lat : parseFloat(settings.location.latitude), 170 lng : parseFloat(settings.location.longitude) 171 }; 172 //Set map center to location 173 map.setCenter(latLong); 174 //Add marker to map 175 176 var templateData = { 177 title : settings.title, 178 address : settings.location.address, 179 featuredImage : settings.featuredImage, 180 itemUrl : settings.itemUrl 181 }; 182 183 var customMarker = new CustomMarker({ 184 map : map, 185 position : latLong, 186 templateData : templateData, 187 markerPin : settings.markerPin 188 }); 189 190 this.initMarkerInfo(); 191 192 } 193 194 }, 195 196 /** 197 * Returns map with multiple addresses 198 * 199 * @param options 200 */ 201 getDirectoryItemsAddresses : function( options ) { 202 var defaults = { 203 geolocation : false, 204 mapHolder : 'qode-ls-multiple-map-holder', 205 addresses : qodeMultipleMapVars.multiple.addresses, 206 draggable : qodeMapsVars.global.draggable, 207 mapTypeControl : qodeMapsVars.global.mapTypeControl, 208 scrollwheel : qodeMapsVars.global.scrollable, 209 streetViewControl : qodeMapsVars.global.streetViewControl, 210 zoomControl : qodeMapsVars.global.zoomControl, 211 zoom : 16, 212 styles: qodeMapsVars.global.mapStyle, 213 radius : 50, //radius for marker visibility, in km 214 hasFilter : false 215 }; 216 var settings = $.extend({}, defaults, options ); 217 218 //Get map holder 219 var mapHolder = document.getElementById( settings.mapHolder ); 220 221 //Initialize map 222 var map = new google.maps.Map( mapHolder, { 223 zoom : settings.zoom, 224 draggable : settings.draggable, 225 mapTypeControl : settings.mapTypeControl, 226 scrollwheel : settings.scrollwheel, 227 streetViewControl : settings.streetViewControl, 228 zoomControl : settings.zoomControl 229 }); 230 231 //Save variables for later usage 232 this.mapHolder = settings.mapHolder; 233 this.map = map; 234 this.radius = settings.radius; 235 236 //Set map style 237 map.setOptions({ 238 styles: settings.styles 239 }); 240 241 //If geolocation enabled set map center to user location
242 if ( navigator.geolocation && settings.geolocation ) { 243 this.centerOnCurrentLocation(); 244 } 245 246 //Filter addresses, remove items without latitude and longitude 247 var addresses = [], 248 addressesLength = settings.addresses.length; 249 if(settings.addresses.length !== null){ 250 for ( var i = 0; i < addressesLength; i++ ) { 251 var location = settings.addresses[i].location; 252 if ( typeof location !== 'undefined' && location !== null ) { 253 254 if ( location.latitude !== '' && location.longitude !== '' ) { 255 addresses.push(settings.addresses[i]); 256 } 257 } 258 } 259 } 260 261 262 //Center map and set borders of map 263 this.setMapBounds( addresses ); 264 265 //Add markers to the map 266 this.addMultipleMarkers( addresses ); 267 268 }, 269 270 /** 271 * Add multiple markers to map 272 */ 273 addMultipleMarkers : function( markersData ) { 274 275 var map = this.map; 276 277 var markers = []; 278 //Loop through markers 279 var len = markersData.length; 280 for ( var i = 0; i < len; i++ ) { 281 282 var latLng = { 283 lat: parseFloat(markersData[i].location.latitude), 284 lng: parseFloat(markersData[i].location.longitude) 285 }; 286 287 //Custom html markers 288 //Insert marker data into info window template 289 var templateData = { 290 title : markersData[i].title, 291 address : markersData[i].location.address, 292 featuredImage : markersData[i].featuredImage, 293 itemUrl : markersData[i].itemUrl 294 }; 295 296 var customMarker = new CustomMarker({ 297 position : latLng, 298 map : map, 299 templateData : templateData, 300 markerPin : markersData[i].markerPin 301 }); 302 303 markers.push(customMarker); 304 305 } 306 307 this.markers = markers; 308 309 //Init map clusters ( Grouping map markers at small zoom values ) 310 this.initMapClusters(); 311 312 //Init marker info 313 this.initMarkerInfo(); 314 315 //Init visible circle area around center of map 316 var that = this; 317 google.maps.event.addListener(map, 'idle', function(){ 318 var visibleRadius = new google.maps.Circle({ 319 strokeColor: '#FF0000', 320 strokeOpacity: 0, 321 strokeWeight: 0,
322 fillColor: '#FF0000', 323 fillOpacity: 0, 324 map: map, 325 center: map.getCenter(), 326 radius: that.radius * 1000 //in meters 327 }); 328 //Display only markers in circle 329 //that.refreshCircleAreaMarkers( visibleRadius.getBounds() ); 330 }); 331 332 }, 333 334 /** 335 * Set map bounds for Map with multiple markers 336 * 337 * @param addressesArray 338 */ 339 setMapBounds : function( addressesArray ) { 340 341 var bounds = new google.maps.LatLngBounds(); 342 for ( var i = 0; i < addressesArray.length; i++ ) { 343 bounds.extend( new google.maps.LatLng( parseFloat(addressesArray[i].location.latitude), parseFloat(addressesArray[i].location.longitude) ) ); 344 } 345 346 this.map.fitBounds( bounds ); 347 348 }, 349 350 /** 351 * Init map clusters for grouping markers on small zoom values 352 */ 353 initMapClusters : function() { 354 355 //Activate clustering on multiple markers 356 var markerClusteringOptions = { 357 minimumClusterSize: 2, 358 maxZoom: 12, 359 styles : [{ 360 width: 50, 361 height: 60, 362 url: '', 363 textSize: 12 364 }] 365 }; 366 var markerClusterer = new MarkerClusterer(this.map, this.markers, markerClusteringOptions); 367 368 }, 369 370 initMarkerInfo : function() { 371 372 $(document).on('click', '.qode-map-marker', function() { 373 var self = $(this), 374 markerHolders = $('.qode-map-marker-holder'), 375 infoWindows = $('.qode-info-window'), 376 markerHolder = self.parent('.qode-map-marker-holder'), 377 infoWindow = self.siblings('.qode-info-window'); 378 379 if ( markerHolder.hasClass('active') ) { 380 markerHolder.removeClass( 'active' ); 381 infoWindow.fadeOut(0); 382 } else { 383 markerHolders.removeClass('active'); 384 infoWindows.fadeOut(0); 385 markerHolder.addClass('active'); 386 infoWindow.fadeIn(300); 387 } 388 389 }); 390 391 }, 392 /** 393 * Info Window for displaying data on map markers 394 * 395 * @returns {google.maps.InfoWindow} 396 */ 397 addInfoWindow : function() { 398 399 var contentString = ''; 400 var infoWindow = new google.maps.InfoWindow({ 401 content: contentString 402 }); 403 return infoWindow; 404 405 }, 406 407 /** 408 * If geolocation enabled center map on users current position 409 */ 410 centerOnCurrentLocation : function() { 411 var map = this.map; 412 navigator.geolocation.getCurrentPosition( 413 function(position){ 414 var center = { 415 lat : position.coords.latitude, 416 lng : position.coords.longitude 417 }; 418 map.setCenter(center); 419 } 420 ); 421 }, 422 423 /** 424 * Refresh area for visible markers 425 * 426 * @param circleArea 427 */ 428 refreshCircleAreaMarkers : function( circleArea ) { 429 430 var length = this.markers.length; 431 for ( var i = 0; i < length; i++ ) { 432 if ( circleArea.contains( this.markers[i].getPosition() ) ) { 433 this.markers[i].setVisible(true); 434 } else { 435 this.markers[i].setVisible(false); 436 } 437 } 438 439 }, 440 441 }; 442 443 function qodeInitMobileMap() { 444 445 var mapOpener = $('.qode-listing-view-larger-map a'), 446 mapOpenerIcon = mapOpener.children('i'), 447 mapHolder = $('.qode-map-holder'); 448 if (mapOpener.length) { 449 mapOpener.click(function(e){ 450 e.preventDefault(); 451 if (mapHolder.hasClass('qode-fullscreen-map')) { 452 mapHolder.removeClass('qode-fullscreen-map'); 453 mapOpenerIcon.removeClass('icon-basic-magnifier-minus'); 454 mapOpenerIcon.addClass('icon-basic-magnifier-plus'); 455 } else { 456 mapHolder.addClass('qode-fullscreen-map'); 457 mapOpenerIcon.removeClass('icon-basic-magnifier-plus'); 458 mapOpenerIcon.addClass('icon-basic-magnifier-minus'); 459 } 460 qode.modules.maps.qodeGoogleMaps.getDirectoryItemsAddresses(); 461 }); 462 } 463 } 464 465})(jQuery); 466(function($) { 467 468 var listingsSelect = {}; 469 qode.modules.listingsSelect = listingsSelect; 470 listingsSelect.qodeOnDocumentReady = qodeOnDocumentReady; 471 listingsSelect.qodeOnWindowLoad = qodeOnWindowLoad; 472 listingsSelect.qodeOnWindowResize = qodeOnWindowResize; 473 listingsSelect.qodeOnWindowScroll = qodeOnWindowScroll; 474 475 $(document).ready(qodeOnDocumentReady); 476 $(window).load(qodeOnWindowLoad); 477 $(window).resize(qodeOnWindowResize); 478 $(window).scroll(qodeOnWindowScroll); 479 480 listingsSelect.qodeSelect2Fields = qodeSelect2Fields; 481 listingsSelect.qodeInitSelect2Field = qodeInitSelect2Field; 482 483 484 function qodeOnDocumentReady() { 485 qodeSelect2Fields(); 486 } 487 function qodeOnWindowLoad() {} 488 function qodeOnWindowResize() {} 489 function qodeOnWindowScroll() {} 490 491 function qodeSelect2Fields(){ 492 493 var defaultSelectFields = $( 494 '.qode-ls-adv-search-holder select, ' + 495 '.qode-ls-main-search-holder-part select, ' + 496 '.qode-ls-archive-holder select, ' + 497 '.qode-ls-single-comments .qode-ls-single-sort, ' + 498 '.qode-membership-dashboard-page select' 499 500 );
501 if(defaultSelectFields.length){ 502 defaultSelectFields.each(function(){ 503 qodeInitSelect2Field($(this)); 504 }); 505 } 506 507 } 508 509 function qodeInitSelect2Field(field){ 510 if(qode.modules.listings.qodeIsValidObject(field)){ 511 field.select2({ 512 513 }); 514 } 515 } 516 517})(jQuery); 518(function($) { 519 520 var listings = {}; 521 qode.modules.listings = listings; 522 listings.qodeOnDocumentReady = qodeOnDocumentReady; 523 listings.qodeOnWindowLoad = qodeOnWindowLoad; 524 listings.qodeOnWindowResize = qodeOnWindowResize; 525 listings.qodeOnWindowScroll = qodeOnWindowScroll; 526 527 $(document).ready(qodeOnDocumentReady); 528 $(window).load(qodeOnWindowLoad); 529 $(window).resize(qodeOnWindowResize); 530 $(window).scroll(qodeOnWindowScroll); 531 532 listings.qodeInitListingTypeCustomFields = qodeInitListingTypeCustomFields; 533 listings.qodeGetListingTypeCustomFieldsOnChange = qodeGetListingTypeCustomFieldsOnChange; 534 listings.qodeInitListingMainSearch = qodeInitListingMainSearch; 535 listings.qodeBindTitles = qodeBindTitles; 536 listings.qodeShowHideButton = qodeShowHideButton; 537 listings.qodeReinitMultipleGoogleMaps = qodeReinitMultipleGoogleMaps; 538 listings.qodeBindTitles = qodeBindTitles; 539 listings.qodeIsValidObject = qodeIsValidObject; 540 541 function qodeOnDocumentReady() { 542 qodeInitListingTypeCustomFields(); 543 qodeGetListingTypeCustomFieldsOnChange(); 544 qodeInitListingMainSearch(); 545 qodeBindTitles(); 546 } 547 function qodeOnWindowLoad() {} 548 function qodeOnWindowResize() {} 549 function qodeOnWindowScroll() {} 550 551 function qodeInitListingMainSearch(){ 552 var container = $('.qode-ls-main-search-holder'); 553 if(container.length){ 554 container.each(function(){ 555 var thisContainer = $(this), 556 keywordSearch = thisContainer.find('.qode-ls-main-search-keyword'), 557 availableListings = qodeListingTitles.titles; 558 559 keywordSearch.autocomplete({ 560 source: availableListings 561 }); 562 563 }); 564 } 565 } 566 567 function qodeInitListingTypeCustomFields(){ 568 569 var typeField = $('.job-manager-form .fieldset-job_type #job_type'); 570 var typeFieldVal = typeField.val(); 571 qodeAddListingTypeItems(typeFieldVal); 572 qodeDeleteListingTypeItems(typeFieldVal); 573 574 } 575 576 function qodeGetListingTypeCustomFieldsOnChange(){ 577 578 var typeField = $('.job-manager-form .fieldset-job_type #job_type'); 579 typeField.on('change', function(){ 580 var thisField = $(this); 581 var thisFieldVal = thisField.val(); 582 qodeAddListingTypeItems(thisFieldVal); 583 qodeDeleteListingTypeItems(thisFieldVal); 584 }); 585 586 } 587 588 function qodeAddListingTypeItems(types){ 589 590 if(typeof types !== 'undefined' && types !== null && types.length){ 591 //there is minimum one selected type 592 if(types instanceof Array) { 593 var i; 594 for (i = 0; i < types.length; i++) { 595 if ($.inArray(types[i], qodeListingGlobalVars.vars.selectedTypes) > -1) { 596 } 597 else { 598 //element is in not in array, add it 599 qodeGetListingTypeField(types[i]); 600 } 601 } 602 } else { 603 if ($.inArray(types, qodeListingGlobalVars.vars.selectedTypes) > -1) { 604 605 } 606 else { 607 //element is in not in array, add it 608 qodeGetListingTypeField(types); 609 } 610 } 611 }else{ 612 //there is no selected types 613 qodeDeleteAllListingTypeFields(); 614 } 615 616 } 617 618 function qodeDeleteListingTypeItems(types){ 619 if(typeof types !== 'undefined' && types !== null && types.length){ 620 621 //there is minimum one selected type 622 var i; 623 for(i = 0; i < qodeListingGlobalVars.vars.selectedTypes.length; i++){ 624 if($.inArray(qodeListingGlobalVars.vars.selectedTypes[i],types) > -1){ 625 } 626 else{ 627 //element is in not in array, add it 628 qodeDeleteListingTypeField(qodeListingGlobalVars.vars.selectedTypes[i]); 629 } 630 } 631 632 }else{ 633 //there is no selected types 634 qodeDeleteAllListingTypeFields(); 635 } 636 } 637 638 function qodeGetListingTypeField(itemId){ 639 var form = $('.job-manager-form'); 640 var formAction = form.attr('action'); 641 642 //get current post id if is set 643 // this id is set on edit job pages and we need it to get custom field values 644 var actionArray = formAction.split('='); 645 var currentPostId = actionArray[actionArray.length - 1]; 646 647 var container = $('.job-manager-form .fieldset-job_type'); 648 var data = { 649 selectedType: itemId, 650 action: 'qode_listing_type_get_custom_fields' 651 }; 652 if(typeof currentPostId !== 'undefined' && currentPostId !== 'false'){ 653 data['currentPostId'] = currentPostId; 654 } 655 $.ajax({ 656 type: "POST", 657 url: QodeListingAjaxUrl, 658 data: data, 659 success: function (data) { 660 if (data === 'error') { 661 //error handler 662 }else{ 663 //set new item in global var
664 qodeListingGlobalVars.vars.selectedTypes.push(itemId); 665 response = $.parseJSON(data); 666 responseHtml = response.html; 667 setTimeout(function(){ 668 container.after(responseHtml); 669 qodeReinitAdditionalSelectFields(); 670 },300); 671 } 672 } 673 }); 674 675 } 676 677 function qodeReinitAdditionalSelectFields() { 678 var selectFields = $('.job-manager-form .qode-ls-type-field-wrapper select'); 679 if(selectFields.length){ 680 selectFields.each(function () { 681 $(this).select2(); 682 }); 683 } 684 } 685 686 function qodeDeleteListingTypeField(itemId){ 687 688 var typeFieldWrappers = $('.qode-ls-type-field-wrapper '); 689 690 if(typeFieldWrappers.length){ 691 typeFieldWrappers.each(function(){ 692 var thisFieldWrapper = $(this); 693 var id = thisFieldWrapper.attr('id'); 694 695 if(id === itemId){ 696 setTimeout(function(){ 697 thisFieldWrapper.remove(); 698 //remove current element from global array 699 var index = qodeListingGlobalVars.vars.selectedTypes.indexOf(itemId); 700 qodeListingGlobalVars.vars.selectedTypes.splice(index, 1); 701 },300); 702 }; 703 704 }); 705 } 706 } 707 708 function qodeDeleteAllListingTypeFields(){ 709 var typeFieldWrappers = $('.qode-ls-type-field-wrapper '); 710 711 if(typeFieldWrappers.length){ 712 typeFieldWrappers.each(function() { 713 var thisFieldWrapper = $(this); 714 thisFieldWrapper.remove(); 715 }); 716 } 717 } 718 719 function qodeReinitMultipleGoogleMaps(addresses, action){ 720 721 if(action === 'append'){ 722 723 var mapObjs = qodeMultipleMapVars.multiple.addresses; 724 mapObjs = qodeMultipleMapVars.multiple.addresses.concat(addresses); 725 qodeMultipleMapVars.multiple.addresses = mapObjs; 726 727 qode.modules.maps.qodeGoogleMaps.getDirectoryItemsAddresses({ 728 addresses: mapObjs 729 }); 730 } 731 else if(action === 'replace'){ 732 733 qodeMultipleMapVars.multiple.addresses = addresses; 734 qode.modules.maps.qodeGoogleMaps.getDirectoryItemsAddresses({ 735 addresses: addresses 736 }); 737 738 } 739 } 740 741 function qodeShowHideButton(button, nextPage, maxNumPages){ 742 743 if(typeof button !== 'undefined' && button !== false && button !== null ){ 744 if(nextPage <= maxNumPages){ 745 button.show(); 746 }else{ 747 button.hide(); 748 } 749 } 750 751 } 752 753 function qodeListingArchiveInitBack() { 754 755 window.addEventListener("popstate", function(e) { // if a back or forward button is clicked 756 location.reload(); 757 }); 758 759 } 760 761 function qodeBindTitles() { 762 763 var maps = $('.qode-ls-archive-map-holder'), 764 lists = $('.qode-ls-archive-items'); 765 if (maps.length && lists.length){ 766 maps.each(function(){ 767 var listItems = lists.find('.qode-listing-archive-item'); 768 769 listItems.each(function(){ 770 var listItem = $(this); 771 listItem.mouseenter(function(){ 772 var itemId = listItem.attr('id'); 773 if ($('.qode-map-marker-holder').length) { 774 $('.qode-map-marker-holder').each(function(){ 775 var markerHolder = $(this), 776 markerId = markerHolder.attr('id'); 777 if (itemId == markerId) { 778 markerHolder.addClass('active'); 779 setTimeout(function(){ 780 },300); 781 } else { 782 markerHolder.removeClass('active'); 783 } 784 }); 785 } 786 }); 787 }); 788 789 lists.mouseleave(function(){ 790 $('.qode-map-marker-holder').removeClass('active'); 791 }); 792 }); 793 } 794 } 795 796 function qodeIsValidObject(object){ 797 if(typeof(object !== 'undefined') && object !== 'false' && object !== '' && object !== undefined){ 798 return true; 799 } 800 return false; 801 } 802 803})(jQuery); 804/** 805 * @name MarkerClusterer for Google Maps v3 806 * @version version 1.0 807 * @author Luke Mahe 808 * @fileoverview 809 * The library creates and manages per-zoom-level clusters for large amounts of 810 * markers. 811 * <br/> 812 * This is a v3 implementation of the 813 * <a href="http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/" 814 * >v2 MarkerClusterer</a>. 815 */ 816 817/** 818 * Licensed under the Apache License, Version 2.0 (the "License"); 819 * you may not use this file except in compliance with the License. 820 * You may obtain a copy of the License at 821 * 822 * http://www.apache.org/licenses/LICENSE-2.0 823 * 824 * Unless required by applicable law or agreed to in writing, softw
824are 825 * distributed under the License is distributed on an "AS IS" BASIS, 826 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 827 * See the License for the specific language governing permissions and 828 * limitations under the License. 829 */ 830 831 832/** 833 * A Marker Clusterer that clusters markers. 834 * 835 * @param {google.maps.Map} map The Google map to attach to. 836 * @param {Array.<google.maps.Marker>=} opt_markers Optional markers to add to 837 * the cluster. 838 * @param {Object=} opt_options support the following options: 839 * 'gridSize': (number) The grid size of a cluster in pixels. 840 * 'maxZoom': (number) The maximum zoom level that a marker can be part of a 841 * cluster. 842 * 'zoomOnClick': (boolean) Whether the default behaviour of clicking on a 843 * cluster is to zoom into it. 844 * 'averageCenter': (boolean) Wether the center of each cluster should be 845 * the average of all markers in the cluster. 846 * 'minimumClusterSize': (number) The minimum number of markers to be in a 847 * cluster before the markers are hidden and a count 848 * is shown. 849 * 'styles': (object) An object that has style properties: 850 * 'url': (string) The image url. 851 * 'height': (number) The image height. 852 * 'width': (number) The image width. 853 * 'anchor': (Array) The anchor position of the label text. 854 * 'textColor': (string) The text color. 855 * 'textSize': (number) The text size. 856 * 'backgroundPosition': (string) The position of the backgound x, y. 857 * 'iconAnchor': (Array) The anchor position of the icon x, y. 858 * @constructor 859 * @extends google.maps.OverlayView 860 */ 861function MarkerClusterer(map, opt_markers, opt_options) { 862 // MarkerClusterer implements google.maps.OverlayView interface. We use the 863 // extend function to extend MarkerClusterer with google.maps.OverlayView 864 // because it might not always be available when the code is defined so we 865 // look for it at the last possible moment. If it doesn't exist now then 866 // there is no point going ahead :) 867 this.extend(MarkerClusterer, google.maps.OverlayView); 868 this.map_ = map; 869 870 /** 871 * @type {Array.<google.maps.Marker>} 872 * @private 873 */ 874 this.markers_ = []; 875 876 /** 877 * @type {Array.<Cluster>} 878 */ 879 this.clusters_ = []; 880 881 this.sizes = [53, 56, 66, 78, 90]; 882 883 /** 884 * @private 885 */ 886 this.styles_ = []; 887 888 /** 889 * @type {boolean} 890 * @private 891 */ 892 this.ready_ = false; 893 894 var options = opt_options || {}; 895 896 /** 897 * @type {number} 898 * @private 899 */ 900 this.gridSize_ = options['gridSize'] || 60; 901 902 /** 903 * @private 904 */ 905 this.minClusterSize_ = options['minimumClusterSize'] || 2; 906 907 908 /** 909 * @type {?number} 910 * @private 911 */ 912 this.maxZoom_ = options['maxZoom'] || null; 913 914 this.styles_ = options['styles'] || []; 915 916 /** 917 * @type {string} 918 * @private 919 */ 920 this.imagePath_ = options['imagePath'] || 921 this.MARKER_CLUSTER_IMAGE_PATH_; 922 923 /** 924 * @type {string} 925 * @private 926 */ 927 this.imageExtension_ = options['imageExtension'] || 928 this.MARKER_CLUSTER_IMAGE_EXTENSION_; 929 930 /** 931 * @type {boolean} 932 * @private 933 */ 934 this.zoomOnClick_ = true; 935 936 if (options['zoomOnClick'] != undefined) { 937 this.zoomOnClick_ = options['zoomOnClick']; 938 } 939 940 /** 941 * @type {boolean} 942 * @private 943 */ 944 this.averageCenter_ = false; 945 946 if (options['averageCenter'] != undefined) { 947 this.averageCenter_ = options['averageCenter']; 948 } 949 950 this.setupStyles_(); 951 952 this.setMap(map); 953 954 /** 955 * @type {number} 956 * @private 957 */ 958 this.prevZoom_ = this.map_.getZoom(); 959 960 // Add the map event listeners 961 var that = this; 962 google.maps.event.addListener(this.map_, 'zoom_changed', function() { 963 var zoom = that.map_.getZoom(); 964 965 if (that.prevZoom_ != zoom) { 966 that.prevZoom_ = zoom; 967 that.resetViewport(); 968 } 969 }); 970 971 google.maps.event.addListener(this.map_, 'idle', function() { 972 that.redraw(); 973 }); 974 975 // Finally, add the markers 976 if (opt_markers && opt_markers.length) { 977 this.addMarkers(opt_markers, false); 978 } 979} 980 981 982/** 983 * The marker cluster image path. 984 * 985 * @type {string} 986 * @private 987 */ 988MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ = 989 'https://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/' + 990 'images/m'; 991 992 993/** 994 * The marker cluster image path. 995 * 996 * @type {string} 997 * @private 998 */ 999MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png'; 1000 1001 1002/** 1003 * Extends a objects prototype by anothers. 1004 * 1005 * @param {Object} obj1 The object to be extended. 1006 * @param {Object} obj2 The object to extend with. 1007 * @return {Object} The new extended object. 1008 * @ignore 1009 */ 1010MarkerClusterer.prototype.extend = function(obj1, obj2) { 1011 return (function(object) { 1012 for (var property in object.prototype) { 1013 this.prototype[property] = object.prototype[property]; 1014 } 1015 return this; 1016 }).apply(obj1, [obj2]); 1017}; 1018 1019 1020/** 1021 * Implementaion of the interface method. 1022 * @ignore 1023 */ 1024MarkerClusterer.prototype.onAdd = function() { 1025 this.setReady_(true); 1026}; 1027 1028/** 1029 * Implementaion of the interface method. 1030 * @ignore 1031 */ 1032MarkerClusterer.prototype.draw = function() {}; 1033 1034/** 1035 * Sets up the styles object. 1036 * 1037 * @private 1038 */ 1039MarkerClusterer.prototype.setupStyles_ = function() { 1040 if (this.styles_.length) { 1041 return; 1042 } 1043 1044 for (var i = 0, size; size = this.sizes[i]; i++) { 1045 this.styles_.push({ 1046 url: this.imagePath_ + (i + 1) + '.' + this.imageExtension_, 1047 height: size, 1048 width: size 1049 }); 1050 } 1051}; 1052 1053/** 1054 * Fit the map to the bounds of the markers in the clusterer. 1055 */ 1056MarkerClusterer.prototype.fitMapToMarkers = function() { 1057 var markers = this.getMarkers(); 1058 var bounds = new google.maps.LatLngBounds(); 1059 for (var i = 0, marker; marker = markers[i]; i++) { 1060 bounds.extend(marker.getPosition()); 1061 } 1062 1063 this.map_.fitBounds(bounds); 1064}; 1065 1066 1067/** 1068 * Sets the styles. 1069 * 1070 * @param {Object} styles The style to set. 1071 */ 1072MarkerClusterer.prototype.setStyles = function(styles) { 1073 this.styles_ = styles; 1074}; 1075 1076 1077/** 1078 * Gets the styles. 1079 * 1080 * @return {Object} The styles object. 1081 */ 1082MarkerClusterer.prototype.getStyles = function() { 1083 return this.styles_; 1084}; 1085 1086 1087/** 1088 * Whether zoom on click is set. 1089 * 1090 * @return {boolean} True if zoomOnClick_ is set. 1091 */ 1092MarkerClusterer.prototype.isZoomOnClick = function() { 1093 return this.zoomOnClick_; 1094}; 1095 1096/** 1097 * Whether average center is set. 1098 * 1099 * @return {boolean} True if averageCenter_ is set. 1100 */ 1101MarkerClusterer.prototype.isAverageCenter = function() { 1102 return this.averageCenter_; 1103}; 1104 1105 1106/** 1107 * Returns the array of markers in the clusterer. 1108 * 1109 * @return {Array.<google.maps.Marker>} The markers. 1110 */ 1111MarkerClusterer.prototype.getMarkers = function() { 1112 return this.markers_; 1113}; 1114 1115 1116/** 1117 * Returns the number of markers in the clusterer 1118 * 1119 * @return {Number} The number of markers. 1120 */ 1121MarkerClusterer.prototype.getTotalMarkers = function() { 1122 return this.markers_.length; 1123}; 1124 1125 1126/** 1127 * Sets the max zoom for the clusterer. 1128 * 1129 * @param {number} maxZoom The max zoom level. 1130 */ 1131MarkerClusterer.prototype.setMaxZoom = function(maxZoom) { 1132 this.maxZoom_ = maxZoom; 1133}; 1134 1135 1136/** 1137 * Gets the max zoom for the clusterer. 1138 * 1139 * @return {number} The max zoom level. 1140 */ 1141MarkerClusterer.prototype.getMaxZoom = function() { 1142 return this.maxZoom_; 1143}; 1144 1145 1146/** 1147 * The function for calculating the cluster icon image. 1148 * 1149 * @param {Array.<google.maps.Marker>} markers The markers in the clusterer. 1150 * @param {number} numStyles The number of styles available. 1151 * @return {Object} A object properties: 'text' (string) and 'index' (number). 1152 * @private 1153 */ 1154MarkerClusterer.prototype.calculator_ = function(markers, numStyles) { 1155 var index = 0; 1156 var count = markers.length; 1157 var dv = count; 1158 while (dv !== 0) { 1159 dv = parseInt(dv / 10, 10); 1160 index++; 1161 } 1162 1163 index = Math.min(index, numStyles); 1164 return { 1165 text: count, 1166 index: index 1167 }; 1168}; 1169 1170 1171/** 1172 * Set the calculator function. 1173 * 1174 * @param {function(Array, number)} calculator The function to set as the 1175 * calculator. The function should return a object properties: 1176 * 'text' (string) and 'index' (number). 1177 * 1178 */ 1179MarkerClusterer.prototype.setCalculator = function(calculator) { 1180 this.calculator_ = calculator; 1181}; 1182 1183 1184/** 1185 * Get the calculator function. 1186 * 1187 * @return {function(Array, number)} the calculator function. 1188 */ 1189MarkerClusterer.prototype.getCalculator = function() { 1190 return this.calculator_; 1191}; 1192 1193 1194/** 1195 * Add an array of markers to the clusterer. 1196 * 1197 * @param {Array.<google.maps.Marker>} markers The markers to add. 1198 * @param {boolean=}
1198 opt_nodraw Whether to redraw the clusters. 1199 */ 1200MarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) { 1201 for (var i = 0, marker; marker = markers[i]; i++) { 1202 this.pushMarkerTo_(marker); 1203 } 1204 if (!opt_nodraw) { 1205 this.redraw(); 1206 } 1207}; 1208 1209 1210/** 1211 * Pushes a marker to the clusterer. 1212 * 1213 * @param {google.maps.Marker} marker The marker to add. 1214 * @private 1215 */ 1216MarkerClusterer.prototype.pushMarkerTo_ = function(marker) { 1217 marker.isAdded = false; 1218 if (marker['draggable']) { 1219 // If the marker is draggable add a listener so we update the clusters on 1220 // the drag end. 1221 var that = this; 1222 google.maps.event.addListener(marker, 'dragend', function() { 1223 marker.isAdded = false; 1224 that.repaint(); 1225 }); 1226 } 1227 this.markers_.push(marker); 1228}; 1229 1230 1231/** 1232 * Adds a marker to the clusterer and redraws if needed. 1233 * 1234 * @param {google.maps.Marker} marker The marker to add. 1235 * @param {boolean=} opt_nodraw Whether to redraw the clusters. 1236 */ 1237MarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) { 1238 this.pushMarkerTo_(marker); 1239 if (!opt_nodraw) { 1240 this.redraw(); 1241 } 1242}; 1243 1244 1245/** 1246 * Removes a marker and returns true if removed, false if not 1247 * 1248 * @param {google.maps.Marker} marker The marker to remove 1249 * @return {boolean} Whether the marker was removed or not 1250 * @private 1251 */ 1252MarkerClusterer.prototype.removeMarker_ = function(marker) { 1253 var index = -1; 1254 if (this.markers_.indexOf) { 1255 index = this.markers_.indexOf(marker); 1256 } else { 1257 for (var i = 0, m; m = this.markers_[i]; i++) { 1258 if (m == marker) { 1259 index = i; 1260 break; 1261 } 1262 } 1263 } 1264 1265 if (index == -1) { 1266 // Marker is not in our list of markers. 1267 return false; 1268 } 1269 1270 marker.setMap(null); 1271 1272 this.markers_.splice(index, 1); 1273 1274 return true; 1275}; 1276 1277 1278/** 1279 * Remove a marker from the cluster. 1280 * 1281 * @param {google.maps.Marker} marker The marker to remove. 1282 * @param {boolean=} opt_nodraw Optional boolean to force no redraw. 1283 * @return {boolean} True if the marker was removed. 1284 */ 1285MarkerClusterer.prototype.removeMarker = function(marker, opt_nodraw) { 1286 var removed = this.removeMarker_(marker); 1287 1288 if (!opt_nodraw && removed) { 1289 this.resetViewport(); 1290 this.redraw(); 1291 return true; 1292 } else { 1293 return false; 1294 } 1295}; 1296 1297 1298/** 1299 * Removes an array of markers from the cluster. 1300 * 1301 * @param {Array.<google.maps.Marker>} markers The markers to remove. 1302 * @param {boolean=} opt_nodraw Optional boolean to force no redraw. 1303 */ 1304MarkerClusterer.prototype.removeMarkers = function(markers, opt_nodraw) { 1305 var removed = false; 1306 1307 for (var i = 0, marker; marker = markers[i]; i++) { 1308 var r = this.removeMarker_(marker); 1309 removed = removed || r; 1310 } 1311 1312 if (!opt_nodraw && removed) { 1313 this.resetViewport(); 1314 this.redraw(); 1315 return true; 1316 } 1317}; 1318 1319 1320/** 1321 * Sets the clusterer's ready state. 1322 * 1323 * @param {boolean} ready The state. 1324 * @private 1325 */ 1326MarkerClusterer.prototype.setReady_ = function(ready) { 1327 if (!this.ready_) { 1328 this.ready_ = ready; 1329 this.createClusters_(); 1330 } 1331}; 1332 1333 1334/** 1335 * Returns the number of clusters in the clusterer. 1336 * 1337 * @return {number} The number of clusters. 1338 */ 1339MarkerClusterer.prototype.getTotalClusters = function() { 1340 return this.clusters_.length; 1341}; 1342 1343 1344/** 1345 * Returns the google map that the clusterer is associated with. 1346 * 1347 * @return {google.maps.Map} The map. 1348 */ 1349MarkerClusterer.prototype.getMap = function() { 1350 return this.map_; 1351}; 1352 1353 1354/** 1355 * Sets the google map that the clusterer is associated with. 1356 * 1357 * @param {google.maps.Map} map The map. 1358 */ 1359MarkerClusterer.prototype.setMap = function(map) { 1360 this.map_ = map; 1361}; 1362 1363 1364/** 1365 * Returns the size of the grid. 1366 * 1367 * @return {number} The grid size. 1368 */ 1369MarkerClusterer.prototype.getGridSize = function() { 1370 return this.gridSize_; 1371}; 1372 1373 1374/** 1375 * Sets the size of the grid. 1376 * 1377 * @param {number} size The grid size. 1378 */ 1379MarkerClusterer.prototype.setGridSize = function(size) { 1380 this.gridSize_ = size; 1381}; 1382 1383 1384/** 1385 * Returns the min cluster size. 1386 * 1387 * @return {number} The grid size. 1388 */ 1389MarkerClusterer.prototype.getMinClusterSize = function() { 1390 return this.minClusterSize_; 1391}; 1392 1393/** 1394 * Sets the min cluster size. 1395 * 1396 * @param {number} size The grid size. 1397 */ 1398MarkerClusterer.prototype.setMinClusterSize = function(size) { 1399 this.minClusterSize_ = size; 1400}; 1401 1402 1403/** 1404 * Extends a bounds object by the grid size. 1405 * 1406 * @param {google.maps.LatLngBounds} bounds The bounds to extend. 1407 * @return {google.maps.LatLngBounds}
1407 The extended bounds. 1408 */ 1409MarkerClusterer.prototype.getExtendedBounds = function(bounds) { 1410 var projection = this.getProjection(); 1411 1412 // Turn the bounds into latlng. 1413 var tr = new google.maps.LatLng(bounds.getNorthEast().lat(), 1414 bounds.getNorthEast().lng()); 1415 var bl = new google.maps.LatLng(bounds.getSouthWest().lat(), 1416 bounds.getSouthWest().lng()); 1417 1418 // Convert the points to pixels and the extend out by the grid size. 1419 var trPix = projection.fromLatLngToDivPixel(tr); 1420 trPix.x += this.gridSize_; 1421 trPix.y -= this.gridSize_; 1422 1423 var blPix = projection.fromLatLngToDivPixel(bl); 1424 blPix.x -= this.gridSize_; 1425 blPix.y += this.gridSize_; 1426 1427 // Convert the pixel points back to LatLng 1428 var ne = projection.fromDivPixelToLatLng(trPix); 1429 var sw = projection.fromDivPixelToLatLng(blPix); 1430 1431 // Extend the bounds to contain the new bounds. 1432 bounds.extend(ne); 1433 bounds.extend(sw); 1434 1435 return bounds; 1436}; 1437 1438 1439/** 1440 * Determins if a marker is contained in a bounds. 1441 * 1442 * @param {google.maps.Marker} marker The marker to check. 1443 * @param {google.maps.LatLngBounds} bounds The bounds to check against. 1444 * @return {boolean} True if the marker is in the bounds. 1445 * @private 1446 */ 1447MarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) { 1448 return bounds.contains(marker.getPosition()); 1449}; 1450 1451 1452/** 1453 * Clears all clusters and markers from the clusterer. 1454 */ 1455MarkerClusterer.prototype.clearMarkers = function() { 1456 this.resetViewport(true); 1457 1458 // Set the markers a empty array. 1459 this.markers_ = []; 1460}; 1461 1462 1463/** 1464 * Clears all existing clusters and recreates them. 1465 * @param {boolean} opt_hide To also hide the marker. 1466 */ 1467MarkerClusterer.prototype.resetViewport = function(opt_hide) { 1468 // Remove all the clusters 1469 for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { 1470 cluster.remove(); 1471 } 1472 1473 // Reset the markers to not be added and to be invisible. 1474 for (var i = 0, marker; marker = this.markers_[i]; i++) { 1475 marker.isAdded = false; 1476 if (opt_hide) { 1477 marker.setMap(null); 1478 } 1479 } 1480 1481 this.clusters_ = []; 1482}; 1483 1484/** 1485 * 1486 */ 1487MarkerClusterer.prototype.repaint = function() { 1488 var oldClusters = this.clusters_.slice(); 1489 this.clusters_.length = 0; 1490 this.resetViewport(); 1491 this.redraw(); 1492 1493 // Remove the old clusters. 1494 // Do it in a timeout so the other clusters have been drawn first. 1495 window.setTimeout(function() { 1496 for (var i = 0, cluster; cluster = oldClusters[i]; i++) { 1497 cluster.remove(); 1498 } 1499 }, 0); 1500}; 1501 1502 1503/** 1504 * Redraws the clusters. 1505 */ 1506MarkerClusterer.prototype.redraw = function() { 1507 this.createClusters_(); 1508}; 1509 1510 1511/** 1512 * Calculates the distance between two latlng locations in km. 1513 * @see http://www.movable-type.co.uk/scripts/latlong.html 1514 * 1515 * @param {google.maps.LatLng} p1 The first lat lng point. 1516 * @param {google.maps.LatLng} p2 The second lat lng point. 1517 * @return {number} The distance between the two points in km. 1518 * @private 1519 */ 1520MarkerClusterer.prototype.distanceBetweenPoints_ = function(p1, p2) { 1521 if (!p1 || !p2) { 1522 return 0; 1523 } 1524 1525 var R = 6371; // Radius of the Earth in km 1526 var dLat = (p2.lat() - p1.lat()) * Math.PI / 180; 1527 var dLon = (p2.lng() - p1.lng()) * Math.PI / 180; 1528 var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + 1529 Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) * 1530 Math.sin(dLon / 2) * Math.sin(dLon / 2); 1531 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 1532 var d = R * c; 1533 return d; 1534}; 1535 1536 1537/** 1538 * Add a marker to a cluster, or creates a new cluster. 1539 * 1540 * @param {google.maps.Marker} marker The marker to add. 1541 * @private 1542 */ 1543MarkerClusterer.prototype.addToClosestCluster_ = function(marker) { 1544 var distance = 40000; // Some large number 1545 var clusterToAddTo = null; 1546 var pos = marker.getPosition(); 1547 for (var i = 0, cluster; cluster = this.clusters_[i]; i++) { 1548 var center = cluster.getCenter(); 1549 if (center) { 1550 var d = this.distanceBetweenPoints_(center, marker.getPosition()); 1551 if (d < distance) { 1552 distance = d; 1553 clusterToAddTo = cluster; 1554 } 1555 } 1556 } 1557 1558 if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) { 1559 clusterToAddTo.addMarker(marker); 1560 } else { 1561 var cluster = new Cluster(this); 1562 cluster.addMarker(marker);
1563 this.clusters_.push(cluster); 1564 } 1565}; 1566 1567 1568/** 1569 * Creates the clusters. 1570 * 1571 * @private 1572 */ 1573MarkerClusterer.prototype.createClusters_ = function() { 1574 if (!this.ready_) { 1575 return; 1576 } 1577 1578 // Get our current map view bounds. 1579 // Create a new bounds object so we don't affect the map. 1580 var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(), 1581 this.map_.getBounds().getNorthEast()); 1582 var bounds = this.getExtendedBounds(mapBounds); 1583 1584 for (var i = 0, marker; marker = this.markers_[i]; i++) { 1585 if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) { 1586 this.addToClosestCluster_(marker); 1587 } 1588 } 1589}; 1590 1591 1592/** 1593 * A cluster that contains markers. 1594 * 1595 * @param {MarkerClusterer} markerClusterer The markerclusterer that this 1596 * cluster is associated with. 1597 * @constructor 1598 * @ignore 1599 */ 1600function Cluster(markerClusterer) { 1601 this.markerClusterer_ = markerClusterer; 1602 this.map_ = markerClusterer.getMap(); 1603 this.gridSize_ = markerClusterer.getGridSize(); 1604 this.minClusterSize_ = markerClusterer.getMinClusterSize(); 1605 this.averageCenter_ = markerClusterer.isAverageCenter(); 1606 this.center_ = null; 1607 this.markers_ = []; 1608 this.bounds_ = null; 1609 this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getStyles(), 1610 markerClusterer.getGridSize()); 1611} 1612 1613/** 1614 * Determins if a marker is already added to the cluster. 1615 * 1616 * @param {google.maps.Marker} marker The marker to check. 1617 * @return {boolean} True if the marker is already added. 1618 */ 1619Cluster.prototype.isMarkerAlreadyAdded = function(marker) { 1620 if (this.markers_.indexOf) { 1621 return this.markers_.indexOf(marker) != -1; 1622 } else { 1623 for (var i = 0, m; m = this.markers_[i]; i++) { 1624 if (m == marker) { 1625 return true; 1626 } 1627 } 1628 } 1629 return false; 1630}; 1631 1632 1633/** 1634 * Add a marker the cluster. 1635 * 1636 * @param {google.maps.Marker} marker The marker to add. 1637 * @return {boolean} True if the marker was added. 1638 */ 1639Cluster.prototype.addMarker = function(marker) { 1640 if (this.isMarkerAlreadyAdded(marker)) { 1641 return false; 1642 } 1643 1644 if (!this.center_) { 1645 this.center_ = marker.getPosition(); 1646 this.calculateBounds_(); 1647 } else { 1648 if (this.averageCenter_) { 1649 var l = this.markers_.length + 1; 1650 var lat = (this.center_.lat() * (l-1) + marker.getPosition().lat()) / l; 1651 var lng = (this.center_.lng() * (l-1) + marker.getPosition().lng()) / l; 1652 this.center_ = new google.maps.LatLng(lat, lng); 1653 this.calculateBounds_(); 1654 } 1655 } 1656 1657 marker.isAdded = true; 1658 this.markers_.push(marker); 1659 1660 var len = this.markers_.length; 1661 if (len < this.minClusterSize_ && marker.getMap() != this.map_) { 1662 // Min cluster size not reached so show the marker. 1663 marker.setMap(this.map_); 1664 } 1665 1666 if (len == this.minClusterSize_) { 1667 // Hide the markers that were showing. 1668 for (var i = 0; i < len; i++) { 1669 this.markers_[i].setMap(null); 1670 } 1671 } 1672 1673 if (len >= this.minClusterSize_) { 1674 marker.setMap(null); 1675 } 1676 1677 this.updateIcon(); 1678 return true; 1679}; 1680 1681 1682/** 1683 * Returns the marker clusterer that the cluster is associated with. 1684 * 1685 * @return {MarkerClusterer} The associated marker clusterer. 1686 */ 1687Cluster.prototype.getMarkerClusterer = function() { 1688 return this.markerClusterer_; 1689}; 1690 1691 1692/** 1693 * Returns the bounds of the cluster. 1694 * 1695 * @return {google.maps.LatLngBounds} the cluster bounds. 1696 */ 1697Cluster.prototype.getBounds = function() { 1698 var bounds = new google.maps.LatLngBounds(this.center_, this.center_); 1699 var markers = this.getMarkers(); 1700 for (var i = 0, marker; marker = markers[i]; i++) { 1701 bounds.extend(marker.getPosition()); 1702 } 1703 return bounds; 1704}; 1705 1706 1707/** 1708 * Removes the cluster 1709 */ 1710Cluster.prototype.remove = function() { 1711 this.clusterIcon_.remove(); 1712 this.markers_.length = 0; 1713 delete this.markers_; 1714}; 1715 1716 1717/** 1718 * Returns the center of the cluster. 1719 * 1720 * @return {number} The cluster center. 1721 */ 1722Cluster.prototype.getSize = function() { 1723 return this.markers_.length; 1724}; 1725 1726 1727/** 1728 * Returns the center of the cluster. 1729 * 1730 * @return {Array.<google.maps.Marker>} The cluster center. 1731 */ 1732Cluster.prototype.getMarkers = function() { 1733 return this.markers_; 1734}; 1735 1736 1737/** 1738 * Returns the center of the cluster. 1739 * 1740 * @return {google.maps.LatLng} The cluster center. 1741 */ 1742Cluster.prototype.getCenter = function() { 1743 return this.center_; 1744}; 1745 1746 1747/**
1748 * Calculated the extended bounds of the cluster with the grid. 1749 * 1750 * @private 1751 */ 1752Cluster.prototype.calculateBounds_ = function() { 1753 var bounds = new google.maps.LatLngBounds(this.center_, this.center_); 1754 this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds); 1755}; 1756 1757 1758/** 1759 * Determines if a marker lies in the clusters bounds. 1760 * 1761 * @param {google.maps.Marker} marker The marker to check. 1762 * @return {boolean} True if the marker lies in the bounds. 1763 */ 1764Cluster.prototype.isMarkerInClusterBounds = function(marker) { 1765 return this.bounds_.contains(marker.getPosition()); 1766}; 1767 1768 1769/** 1770 * Returns the map that the cluster is associated with. 1771 * 1772 * @return {google.maps.Map} The map. 1773 */ 1774Cluster.prototype.getMap = function() { 1775 return this.map_; 1776}; 1777 1778 1779/** 1780 * Updates the cluster icon 1781 */ 1782Cluster.prototype.updateIcon = function() { 1783 var zoom = this.map_.getZoom(); 1784 var mz = this.markerClusterer_.getMaxZoom(); 1785 1786 if (mz && zoom > mz) { 1787 // The zoom is greater than our max zoom so show all the markers in cluster. 1788 for (var i = 0, marker; marker = this.markers_[i]; i++) { 1789 marker.setMap(this.map_); 1790 } 1791 return; 1792 } 1793 1794 if (this.markers_.length < this.minClusterSize_) { 1795 // Min cluster size not yet reached. 1796 this.clusterIcon_.hide(); 1797 return; 1798 } 1799 1800 var numStyles = this.markerClusterer_.getStyles().length; 1801 var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles); 1802 this.clusterIcon_.setCenter(this.center_); 1803 this.clusterIcon_.setSums(sums); 1804 this.clusterIcon_.show(); 1805}; 1806 1807 1808/** 1809 * A cluster icon 1810 * 1811 * @param {Cluster} cluster The cluster to be associated with. 1812 * @param {Object} styles An object that has style properties: 1813 * 'url': (string) The image url. 1814 * 'height': (number) The image height. 1815 * 'width': (number) The image width. 1816 * 'anchor': (Array) The anchor position of the label text. 1817 * 'textColor': (string) The text color. 1818 * 'textSize': (number) The text size. 1819 * 'backgroundPosition: (string) The background postition x, y. 1820 * @param {number=} opt_padding Optional padding to apply to the cluster icon. 1821 * @constructor 1822 * @extends google.maps.OverlayView 1823 * @ignore 1824 */ 1825function ClusterIcon(cluster, styles, opt_padding) { 1826 cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView); 1827 1828 this.styles_ = styles; 1829 this.padding_ = opt_padding || 0; 1830 this.cluster_ = cluster; 1831 this.center_ = null; 1832 this.map_ = cluster.getMap(); 1833 this.div_ = null; 1834 this.sums_ = null; 1835 this.visible_ = false; 1836 1837 this.setMap(this.map_); 1838} 1839 1840 1841/** 1842 * Triggers the clusterclick event and zoom's if the option is set. 1843 * 1844 * @param {google.maps.MouseEvent} event The event to propagate 1845 */ 1846ClusterIcon.prototype.triggerClusterClick = function(event) { 1847 var markerClusterer = this.cluster_.getMarkerClusterer(); 1848 1849 // Trigger the clusterclick event. 1850 google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_, event); 1851 1852 if (markerClusterer.isZoomOnClick()) { 1853 // Zoom into the cluster. 1854 this.map_.fitBounds(this.cluster_.getBounds()); 1855 } 1856}; 1857 1858 1859/** 1860 * Adding the cluster icon to the dom. 1861 * @ignore 1862 */ 1863ClusterIcon.prototype.onAdd = function() { 1864 this.div_ = document.createElement('DIV'); 1865 this.div_.className = 'qode-cluster-marker'; 1866 if (this.visible_) { 1867 var pos = this.getPosFromLatLng_(this.center_); 1868 this.div_.style.cssText = this.createCss(pos); 1869 this.div_.innerHTML = '<div class="qode-cluster-marker-inner">' + 1870 '<span class="qode-cluster-marker-number">' + this.sums_.text + '</span>' + 1871 '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"' + 1872 'width="56px" height="67.316px" viewBox="0 0 56 67.316" enable-background="new 0 0 56 67.316" xml:space="preserve">' + 1873 '<path fill="#1CB5C1" d="M55.939,27.722c-0.054-7.367-2.957-14.287-8.176-19.494c-5.27-5.26-12.28-8.161-19.736-8.157' + 1874 'c-7.456-0.004-14.47,2.895-19.743,8.157c-5.267,5.255-8.172,12.255-8.171,19.697C0.113,35.363,3.018,42.359,8.29,47.62' + 1875 'l19.738,19.696l19.513-19.472l0.08-0.078c0.05-0.051,0.098-0.099,0.143-0.143c0.
1875052-0.053,0.099-0.099,0.146-0.147l0.074-0.071' + 1876 'L49,46.305C53.535,41.163,55.997,34.617,55.939,27.722z"/>' + 1877 '</svg></div>'; 1878 } 1879 1880 var panes = this.getPanes(); 1881 panes.overlayMouseTarget.appendChild(this.div_); 1882 1883 var that = this; 1884 google.maps.event.addDomListener(this.div_, 'click', function(event) { 1885 that.triggerClusterClick(event); 1886 }); 1887}; 1888 1889 1890/** 1891 * Returns the position to place the div dending on the latlng. 1892 * 1893 * @param {google.maps.LatLng} latlng The position in latlng. 1894 * @return {google.maps.Point} The position in pixels. 1895 * @private 1896 */ 1897ClusterIcon.prototype.getPosFromLatLng_ = function(latlng) { 1898 var pos = this.getProjection().fromLatLngToDivPixel(latlng); 1899 1900 if (typeof this.iconAnchor_ === 'object' && this.iconAnchor_.length === 2) { 1901 pos.x -= this.iconAnchor_[0]; 1902 pos.y -= this.iconAnchor_[1]; 1903 } else { 1904 pos.x -= parseInt(this.width_ / 2, 10); 1905 pos.y -= parseInt(this.height_ / 2, 10); 1906 } 1907 return pos; 1908}; 1909 1910 1911/** 1912 * Draw the icon. 1913 * @ignore 1914 */ 1915ClusterIcon.prototype.draw = function() { 1916 if (this.visible_) { 1917 var pos = this.getPosFromLatLng_(this.center_); 1918 this.div_.style.top = pos.y + 'px'; 1919 this.div_.style.left = pos.x + 'px'; 1920 } 1921}; 1922 1923 1924/** 1925 * Hide the icon. 1926 */ 1927ClusterIcon.prototype.hide = function() { 1928 if (this.div_) { 1929 this.div_.style.display = 'none'; 1930 } 1931 this.visible_ = false; 1932}; 1933 1934 1935/** 1936 * Position and show the icon. 1937 */ 1938ClusterIcon.prototype.show = function() { 1939 if (this.div_) { 1940 var pos = this.getPosFromLatLng_(this.center_); 1941 this.div_.style.cssText = this.createCss(pos); 1942 this.div_.style.display = ''; 1943 } 1944 this.visible_ = true; 1945}; 1946 1947 1948/** 1949 * Remove the icon from the map 1950 */ 1951ClusterIcon.prototype.remove = function() { 1952 this.setMap(null); 1953}; 1954 1955 1956/** 1957 * Implementation of the onRemove interface. 1958 * @ignore 1959 */ 1960ClusterIcon.prototype.onRemove = function() { 1961 if (this.div_ && this.div_.parentNode) { 1962 this.hide(); 1963 this.div_.parentNode.removeChild(this.div_); 1964 this.div_ = null; 1965 } 1966}; 1967 1968 1969/** 1970 * Set the sums of the icon. 1971 * 1972 * @param {Object} sums The sums containing: 1973 * 'text': (string) The text to display in the icon. 1974 * 'index': (number) The style index of the icon. 1975 */ 1976ClusterIcon.prototype.setSums = function(sums) { 1977 this.sums_ = sums; 1978 this.text_ = sums.text; 1979 this.index_ = sums.index; 1980 if (this.div_) { 1981 this.div_.innerHTML = sums.text; 1982 } 1983 1984 this.useStyle(); 1985}; 1986 1987 1988/** 1989 * Sets the icon to the the styles. 1990 */ 1991ClusterIcon.prototype.useStyle = function() { 1992 var index = Math.max(0, this.sums_.index - 1); 1993 index = Math.min(this.styles_.length - 1, index); 1994 var style = this.styles_[index]; 1995 this.url_ = style['url']; 1996 this.height_ = style['height']; 1997 this.width_ = style['width']; 1998 this.textColor_ = style['textColor']; 1999 this.anchor_ = style['anchor']; 2000 this.textSize_ = style['textSize']; 2001 this.backgroundPosition_ = style['backgroundPosition']; 2002 this.iconAnchor_ = style['iconAnchor']; 2003}; 2004 2005 2006/** 2007 * Sets the center of the icon. 2008 * 2009 * @param {google.maps.LatLng} center The latlng to set as the center. 2010 */ 2011ClusterIcon.prototype.setCenter = function(center) { 2012 this.center_ = center; 2013}; 2014 2015 2016/** 2017 * Create the css text based on the position of the icon. 2018 * 2019 * @param {google.maps.Point} pos The position. 2020 * @return {string} The css style text. 2021 */ 2022ClusterIcon.prototype.createCss = function(pos) { 2023 var style = []; 2024 style.push('background-image:url(' + this.url_ + ');'); 2025 var backgroundPosition = this.backgroundPosition_ ? this.backgroundPosition_ : '0 0'; 2026 style.push('background-position:' + backgroundPosition + ';'); 2027 2028 if (typeof this.anchor_ === 'object') { 2029 if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 && 2030 this.anchor_[0] < this.height_) { 2031 style.push('height:' + (this.height_ - this.anchor_[0]) + 2032 'px; padding-top:' + this.anchor_[0] + 'px;'); 2033 } else if (typeof this.anchor_[0] === 'number' && this.anchor_[0] < 0 && 2034 -this.anchor_[0] < this.height_) { 2035 style.push('height:' + this.height_ + 'px; line-height:' + (this.height_ + this.anchor_[0]) + 2036 'px;'); 2037 } else { 2038 style.push('height:' + this.height_ + 'px; line-height:' + this.height_ + 2039 'px;'); 2040 } 2041 if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 && 2042 this.anchor_[1] < this.width_) { 2043 style.push('width:' + (this.width_ - this.anchor_[1]) + 2044 'px; padding-left:' + this.anchor_[1] + 'px;'); 2045 } else { 2046 style.push('width:' + this.width_ + 'px; text-align:center;'); 2047 } 2048 } else { 2049 style.push('height:' + this.height_ + 'px; line-height:' + 2050 this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;'); 2051 } 2052 2053 var txtColor = this.textColor_ ? this.textColor_ : 'black'; 2054 var txtSize = this.textSize_ ? this.textSize_ : 11; 2055 2056 style.push('cursor:pointer; top:' + pos.y + 'px; left:' + 2057 pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' + 2058 txtSize + 'px; font-family:Arial,sans-serif; font-weight:bold'); 2059 return style.join(''); 2060}; 2061 2062 2063// Export Symbols for Closure
2064// If you are not going to compile with closure then you can remove the 2065// code below. 2066window['MarkerClusterer'] = MarkerClusterer; 2067MarkerClusterer.prototype['addMarker'] = MarkerClusterer.prototype.addMarker; 2068MarkerClusterer.prototype['addMarkers'] = MarkerClusterer.prototype.addMarkers; 2069MarkerClusterer.prototype['clearMarkers'] = 2070 MarkerClusterer.prototype.clearMarkers; 2071MarkerClusterer.prototype['fitMapToMarkers'] = 2072 MarkerClusterer.prototype.fitMapToMarkers; 2073MarkerClusterer.prototype['getCalculator'] = 2074 MarkerClusterer.prototype.getCalculator; 2075MarkerClusterer.prototype['getGridSize'] = 2076 MarkerClusterer.prototype.getGridSize; 2077MarkerClusterer.prototype['getExtendedBounds'] = 2078 MarkerClusterer.prototype.getExtendedBounds; 2079MarkerClusterer.prototype['getMap'] = MarkerClusterer.prototype.getMap; 2080MarkerClusterer.prototype['getMarkers'] = MarkerClusterer.prototype.getMarkers; 2081MarkerClusterer.prototype['getMaxZoom'] = MarkerClusterer.prototype.getMaxZoom; 2082MarkerClusterer.prototype['getStyles'] = MarkerClusterer.prototype.getStyles; 2083MarkerClusterer.prototype['getTotalClusters'] = 2084 MarkerClusterer.prototype.getTotalClusters; 2085MarkerClusterer.prototype['getTotalMarkers'] = 2086 MarkerClusterer.prototype.getTotalMarkers; 2087MarkerClusterer.prototype['redraw'] = MarkerClusterer.prototype.redraw; 2088MarkerClusterer.prototype['removeMarker'] = 2089 MarkerClusterer.prototype.removeMarker; 2090MarkerClusterer.prototype['removeMarkers'] = 2091 MarkerClusterer.prototype.removeMarkers; 2092MarkerClusterer.prototype['resetViewport'] = 2093 MarkerClusterer.prototype.resetViewport; 2094MarkerClusterer.prototype['repaint'] = 2095 MarkerClusterer.prototype.repaint; 2096MarkerClusterer.prototype['setCalculator'] = 2097 MarkerClusterer.prototype.setCalculator; 2098MarkerClusterer.prototype['setGridSize'] = 2099 MarkerClusterer.prototype.setGridSize; 2100MarkerClusterer.prototype['setMaxZoom'] = 2101 MarkerClusterer.prototype.setMaxZoom; 2102MarkerClusterer.prototype['onAdd'] = MarkerClusterer.prototype.onAdd; 2103MarkerClusterer.prototype['draw'] = MarkerClusterer.prototype.draw; 2104 2105Cluster.prototype['getCenter'] = Cluster.prototype.getCenter; 2106Cluster.prototype['getSize'] = Cluster.prototype.getSize; 2107Cluster.prototype['getMarkers'] = Cluster.prototype.getMarkers; 2108 2109ClusterIcon.prototype['onAdd'] = ClusterIcon.prototype.onAdd; 2110ClusterIcon.prototype['draw'] = ClusterIcon.prototype.draw; 2111ClusterIcon.prototype['onRemove'] = ClusterIcon.prototype.onRemove; 2112(function($) { 2113 'use strict'; 2114 2115 var listingArchive = {}; 2116 qode.modules.listingArchive = listingArchive; 2117 2118 listingArchive.qodeOnDocumentReady = qodeOnDocumentReady; 2119 2120 $(document).ready(qodeOnDocumentReady); 2121 2122 listingArchive.qodeInitArchiveSearch = qodeInitArchiveSearch; 2123 listingArchive.qodeRenderAmenities = qodeRenderAmenities; 2124 listingArchive.qodeGetArchiveSearchResponse = qodeGetArchiveSearchResponse; 2125 listingArchive.qodeUpdateListingsNumber = qodeUpdateListingsNumber; 2126 2127 2128 /* 2129 All functions to be called on $(document).ready() should be in this function 2130 */ 2131 function qodeOnDocumentReady() { 2132 qodeInitArchiveSearch(); 2133 qodeFindUserLocation(); 2134 qodeInitRangeSlider(); 2135 } 2136 2137 function qodeInitArchiveSearch(){ 2138 var container = $('.qode-ls-archive-holder'); 2139 2140 if(container.length){ 2141 container.each(function(){ 2142 2143 var thisContainer = $(this), 2144 keywordSearch = thisContainer.find('.qode-archive-keyword-search'), 2145 typeSearch = thisContainer.find('.qode-archive-type-search'), 2146 typeSearchVal = typeSearch.val(), 2147 addressSearch = document.getElementById('qode-archive-places-search'), 2148 amenitiesHolder = thisContainer.find('.qode-listing-type-amenities-holder'), 2149 submitButton = thisContainer.find('.qode-archive-submit-button'), 2150 loadMoreButton = thisContainer.find('.qode-listing-archive-load-more'), 2151 availableListings = qodeListingTitles.titles, 2152 currentVar = qodeListingArchiveVar.searchParams; 2153 2154 qodeUpdateListingsNumber(thisContainer, currentVar['foundPosts']); 2155 2156 keywordSearch.autocomplete({ 2157 source: availableListings 2158 }); 2159 2160 //check if type is set on page load 2161 if(typeof typeSearchVal !== "undefined" && typeSearchVal !== false && typeSearchVal !== null){ 2162 qodeRenderAmenities(amenitiesHolder, typeSearchVal); 2163 } 2164 typeSearch.on('change', function(){ 2165 var typeValue = $(this).val(); 2166 qodeRenderAmenities(amenitiesHolder, typeValue); 2167 }); 2168 2169 //get address and distance on address change 2170 qodeGetAddressFieldParams(addressSearch); 2171 2172 2173 submitButton.on('click', function(){ 2174 qodeGetArchiveSearchResponse(thisContainer, false); 2175 });
2176 if( typeof loadMoreButton !== 'undefined' && loadMoreButton !== null){ 2177 loadMoreButton.on('click', function(){ 2178 qodeGetArchiveSearchResponse(thisContainer, true); 2179 }); 2180 } 2181 2182 qode.modules.listings.qodeShowHideButton(loadMoreButton, currentVar['nextPage'], currentVar['maxPage']); 2183 2184 }); 2185 } 2186 } 2187 2188 function qodeUpdateListingsNumber(container, currentNumber){ 2189 2190 var holder = container.find('.qode-ls-archive-items-number span'); 2191 holder.html(currentNumber); 2192 2193 } 2194 2195 function qodeRenderAmenities(holder, typeId){ 2196 holder.fadeOut(300); 2197 holder.removeClass('qode-opened'); 2198 if(typeof typeId !== 'undefined' && typeId !== false && typeId !== ''){ 2199 var ajaxData = { 2200 typeId: typeId, 2201 action: 'qode_listing_get_listing_type_amenities_html' 2202 } 2203 $.ajax({ 2204 type: "POST", 2205 url: QodeListingAjaxUrl, 2206 data: ajaxData, 2207 success: function (data) { 2208 if (data === 'error') { 2209 //error handler 2210 }else{ 2211 var response = $.parseJSON(data); 2212 var responseHtml = response.html; 2213 if(responseHtml !== ''){ 2214 holder.fadeIn(300, function(){ 2215 holder.addClass('qode-opened'); 2216 holder.html(responseHtml); 2217 }); 2218 } 2219 } 2220 } 2221 }); 2222 } 2223 } 2224 2225 function qodeGetArchiveSearchResponse(container, loadMoreFlag){ 2226 2227 var keywordSearch = container.find('.qode-archive-keyword-search'), 2228 typeSearch = container.find('.qode-archive-type-search'), 2229 amenitiesArray = container.find('.qode-amenity-field'), 2230 loadMoreButton = container.find('.qode-listing-archive-load-more'), 2231 addressInput = container.find('.qode-archive-places-search'), 2232 itemHolder = container.find('.qode-ls-archive-items-inner'), 2233 distance = container.find('.qode-rangle-slider-response'), 2234 dist = 5, //set default distance value 2235 currentVar = qodeListingArchiveVar.searchParams; 2236 2237 2238 currentVar['keyword'] = keywordSearch.val(); 2239 currentVar['type'] = typeSearch.select2('val'); 2240 currentVar['amenities'] = {}; 2241 2242 if(amenitiesArray.length){ 2243 amenitiesArray.each(function(){ 2244 2245 var thisField = $(this); 2246 var fieldVal; 2247 var fieldNameAttr = thisField.attr('name'); 2248 2249 fieldVal = thisField.is(':checked'); 2250 currentVar['amenities'][fieldNameAttr] = fieldVal; 2251 }); 2252 } 2253 2254 if(loadMoreFlag){ 2255 currentVar['enableLoadMore'] = true; 2256 }else{ 2257 currentVar['enableLoadMore'] = false; 2258 currentVar['nextPage'] = '2'; 2259 } 2260 2261 2262 //take distance. Note that lat and long address params are set in qodeGetAddressFieldParams function 2263 2264 if(qode.modules.listings.qodeIsValidObject(distance)){ 2265 var distanceValue = distance.text(); 2266 if(distanceValue !== ''){ 2267 dist = distanceValue; 2268 } 2269 } 2270 2271 currentVar['locationDist'] = dist; 2272 2273 //reset locationObject if address input field is empty 2274 if(addressInput.val() === ''){ 2275 if(currentVar['locationObject'] !== null && typeof currentVar['locationObject'] !== 'undefined'){ 2276 currentVar['locationObject'] = {}; 2277 } 2278 } 2279 2280 var ajaxData = { 2281 action: 'qode_listing_get_archive_search_response', 2282 searchParams: currentVar 2283 } 2284 2285 $.ajax({ 2286 type: "POST", 2287 url: QodeListingAjaxUrl, 2288 data: ajaxData, 2289 success: function (data) { 2290 if (data === 'error') { 2291 //error handler 2292 }else{ 2293 var response = $.parseJSON(data); 2294 2295 //update current post number 2296 var foundPosts = response.foundPosts; 2297 qodeUpdateListingsNumber(container, foundPosts); 2298 2299 var mapObjs = response.mapAddresses; 2300 var mapAddresses = ''; 2301 if(mapObjs !== null){ 2302 mapAddresses = mapObjs['addresses']; 2303 } 2304 2305 //update maxNumPages after each ajax response 2306 currentVar['maxPage'] = response.maxNumPages; 2307 2308 //if is clicked load more button 2309 if(loadMoreFlag){ 2310 //update nextPage after each ajax response 2311 currentVar['nextPage']++; 2312 2313 //if new map objects are sent via ajax, update global map objects 2314 if(mapAddresses !== ''){ 2315 qode.modules.listings.qodeReinitMultipleGoogleMaps(mapAddresses, 'append'); 2316 } 2317 itemHolder.append(response.html); 2318 } 2319 else{ 2320 //update multiple map addressess object 2321 if(mapAddresses !== ''){ 2322 qode.modules.listings.qodeReinitMultipleGoogleMaps(mapAddresses, 'replace'); 2323 } 2324 2325 //get new listings html 2326 itemHolder.html(response.html); 2327 } 2328 2329 //reinit bindTitles function 2330 qode.modules.listings.qodeBindTitles(); 2331 2332 //show button 2333 qode.modules.listings.qodeShowHideButton(loadMoreButton, currentVar['nextPage'], currentVar['maxPage']); 2334 2335 //reinit global archive var object 2336 qodeListingArchiveVar.searchParams = currentVar; 2337 } 2338 } 2339 }); 2340 2341 } 2342 2343 function qodeGetAddressFieldParams(addressInput){ 2344 2345 if ( qode.modules.listings.qodeIsValidObject(addressInput) ) { 2346 2347 //Init Places search 2348 var autocomplete = new google.maps.places.Autocomplete(addressInput); 2349 //take initial value 2350 2351 autocomplete.addListener('place_changed', function(){ 2352 //take value after change 2353 qodeGetAddressAutocompleteResponse(autocomplete); 2354 }); 2355 } 2356 } 2357 2358 function qodeGetAddressAutocompleteResponse(autocomplete){ 2359 var place = autocomplete.getPlace(), 2360 location = place.geometry.location; 2361 2362 if(qode.modules.listings.qodeIsValidObject(location)){ 2363 2364 if(qode.modules.listings.qodeIsValidObject(location.lat()) && qode.modules.listings.qodeIsValidObject(location.lng())){ 2365 qodeSetListingAddressParams(location.lat(), location.lng()); 2366 } 2367 2368 } 2369 2370 } 2371 2372 function qodeSetListingAddressParams(latitude, longitude){ 2373 2374 var locationObject = {}; 2375 locationObject['lat'] = latitude; 2376 locationObject['long'] = longitude; 2377 2378 qodeListingArchiveVar.searchParams['locationObject'] = locationObject; 2379 2380 } 2381 2382 function qodeInitRangeSlider(){ 2383 2384 var selectorHolder = $('.qode-listing-places-dist-holder'); 2385 var slider = selectorHolder.find('.qode-rangle-slider'); 2386 var output = selectorHolder.find('.qode-rangle-slider-response');; 2387 2388 // Basic rangeslider initialization 2389 slider.rangeslider({ 2390 polyfill: false, 2391 onInit: function(position, value) { 2392 qodeListingSetCurrentDistance(value); 2393 }, 2394 onSlide: function(position, value) { 2395 qodeListingSetCurrentDistance(value); 2396 } 2397 }); 2398 2399 function qodeListingSetCurrentDistance(value){ 2400 output.text(value); 2401 } 2402 2403 } 2404 2405 function qodeFindUserLocation(){ 2406 2407 var location = $('.qode-archive-current-location'); 2408 2409 location.on('click', function(){ 2410 2411 if (!navigator.geolocation){ 2412 alert('Geolocation is not supported by your browser'); 2413 return; 2414 } 2415 2416 var thisLocationField = $(this); 2417 var addressField = thisLocationField.next('.qode-archive-places-search'); 2418 var address = ''; 2419 2420 function success(position) { 2421 2422 var latitude = position.coords.latitude; 2423 var longitude = position.coords.longitude; 2424 2425
2426 var GEOCODING = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + latitude + '%2C' + longitude + '&language=en'; 2427 2428 $.getJSON(GEOCODING).done(function(location) { 2429 address = location.results[0].formatted_address; 2430 addressField.val(address); 2431 }); 2432 2433 qodeSetListingAddressParams(latitude, longitude); 2434 } 2435 2436 function error(error) { 2437 2438 if(error.code === 1 && error.message === 'Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).'){ 2439 2440 $.getJSON("http://jsonip.com/?callback=?", function (data) { 2441 2442 if(qode.modules.listings.qodeIsValidObject(data.ip)){ 2443 2444 $.getJSON('http://ip-api.com/json/'+data.ip, function(response) { 2445 2446 if(qode.modules.listings.qodeIsValidObject(response.lat) && qode.modules.listings.qodeIsValidObject(response.lon)) { 2447 2448 $.getJSON('http://maps.googleapis.com/maps/api/geocode/json?latlng='+response.lat+','+response.lon+'&sensor=true', function(response){ 2449 address = response.results[0].formatted_address; 2450 addressField.val(address); 2451 }); 2452 qodeSetListingAddressParams(response.lat, response.lon); 2453 } 2454 }); 2455 2456 } 2457 2458 }); 2459 2460 }else { 2461 alert('ERROR(' + error.code + '): ' + error.message); 2462 } 2463 } 2464 2465 navigator.geolocation.getCurrentPosition(success, error); 2466 2467 }); 2468 } 2469})(jQuery); 2470(function ($) { 2471 'use strict'; 2472 2473 var listingSingle = {}; 2474 qode.modules.listingSingle = listingSingle; 2475 2476 listingSingle.qodeOnDocumentReady = qodeOnDocumentReady; 2477 listingSingle.qodeOnWindowLoad = qodeOnWindowLoad; 2478 listingSingle.qodeOnWindowResize = qodeOnWindowResize; 2479 2480 $(document).ready(qodeOnDocumentReady); 2481 $(window).load(qodeOnWindowLoad); 2482 $(window).resize(qodeOnWindowResize); 2483 2484 listingSingle.qodeInitCommentRating = qodeInitCommentRating; 2485 listingSingle.qodeInitCommentSorting = qodeInitCommentSorting; 2486 listingSingle.qodeInitNewCommentShowHide = qodeInitNewCommentShowHide; 2487 listingSingle.qodeShowHideEnquiryForm = qodeShowHideEnquiryForm; 2488 listingSingle.qodeSubmitEnquiryForm = qodeSubmitEnquiryForm; 2489 listingSingle.qodeListingInitFitVids = qodeListingInitFitVids; 2490 2491 /* 2492 All functions to be called on $(document).ready() should be in this function 2493 */ 2494 function qodeOnDocumentReady() { 2495 qodeInitCommentRating(); 2496 qodeInitCommentSorting(); 2497 qodeInitNewCommentShowHide(); 2498 qodeShowHideEnquiryForm(); 2499 qodeSubmitEnquiryForm(); 2500 qodeListingInitFitVids(); 2501 qodeInitSingleListingSlider(); 2502 } 2503 2504 /* 2505 ** All functions to be called on $(window).load() should be in this function 2506 */ 2507 function qodeOnWindowLoad() { 2508 qodeSingleListingSliderHeight(); 2509 } 2510 2511 /* 2512 ** All functions to be called on $(window).resize() should be in this function 2513 */ 2514 function qodeOnWindowResize() { 2515 2516 } 2517 2518 function qodeInitCommentRating() { 2519 2520 var article = $('.qode-listing-single-holder .qode-ls-single-item'), 2521 ratingInput = article.find('#qode-rating'), 2522 ratingValue = ratingInput.val(), 2523 stars = article.find('.qode-star-rating'); 2524 2525 var addActive = function () { 2526 for (var i = 0; i < stars.length; i++) { 2527 var star = stars[i]; 2528 if (i < ratingValue) { 2529 $(star).addClass('active'); 2530 } else { 2531 $(star).removeClass('active'); 2532 } 2533 } 2534 }; 2535 2536 addActive(); 2537 2538 stars.click(function () { 2539 ratingInput.val($(this).data('value')).trigger('change'); 2540 }); 2541 2542 ratingInput.change(function () { 2543 ratingValue = ratingInput.val(); 2544 addActive(); 2545 }); 2546 2547 } 2548 2549 function qodeInitCommentSorting() { 2550 2551 var articles = $('.qode-ls-single-item'); 2552 2553 if (articles.length) { 2554 articles.each(function () { 2555 var article = $(this), 2556 postId = article.attr('id'), 2557 selectButton = article.find('.qode-ls-single-comments .qode-ls-single-sort'), 2558 holder = article.find('.qode-ls-single-comments .qode-comment-list'); 2559 2560 selectButton.on('change', function () { 2561 var value = $(this).val(); 2562 if (qode.modules.listings.qodeIsValidObject(value)) { 2563 holder.fadeOut(300); 2564 var result = value.split('-'), 2565 orderBy = result[0], 2566 order = result[1], 2567 ajaxData = { 2568 action: 'qode_listing_get_post_reviews_ajax', 2569 order: order, 2570 orderBy: orderBy, 2571 postId: postId 2572 }; 2573 2574 $.ajax({ 2575 type: "POST", 2576 url: QodeListingAjaxUrl, 2577 data: ajaxData, 2578 success: function (data) { 2579 if (data === 'error') { 2580 //error handler 2581 } else { 2582 //set new item in global var
2583 var response = $.parseJSON(data); 2584 var responseHtml = response.html; 2585 holder.fadeIn(300, function () { 2586 holder.html(responseHtml); 2587 }); 2588 } 2589 } 2590 }); 2591 } 2592 }); 2593 2594 }); 2595 } 2596 } 2597 2598 function qodeInitNewCommentShowHide() { 2599 var articles = $('.qode-ls-single-item'); 2600 2601 if (articles.length) { 2602 articles.each(function () { 2603 var article = $(this), 2604 panelHolderTrigger = article.find('.qode-rating-form-trigger'), 2605 panelHolder = article.find('.qode-comment-form .comment-respond'); 2606 2607 panelHolderTrigger.on('click', function () { 2608 panelHolder.slideToggle('slow'); 2609 }); 2610 }); 2611 } 2612 } 2613 2614 function qodeShowHideEnquiryForm() { 2615 var article = $('.qode-ls-single-item'), 2616 enquiryHolder = $('.qode-ls-enquiry-holder'), 2617 button = article.find('.qode-ls-single-contact-listing'), 2618 buttonClose = $('.qode-ls-enquiry-close'); 2619 2620 button.on('click', function () { 2621 enquiryHolder.fadeIn(300); 2622 enquiryHolder.addClass('opened'); 2623 }); 2624 2625 enquiryHolder.add(buttonClose).on('click', function () { 2626 if (enquiryHolder.hasClass('opened')) { 2627 enquiryHolder.fadeOut(300); 2628 enquiryHolder.removeClass('opened'); 2629 } 2630 }); 2631 2632 $(".qode-ls-enquiry-inner").click(function (e) { 2633 e.stopPropagation(); 2634 }); 2635 // on esc too 2636 $(window).on('keyup', function (e) { 2637 if (enquiryHolder.hasClass('opened') && e.keyCode == 27) { 2638 enquiryHolder.fadeOut(300); 2639 enquiryHolder.removeClass('opened'); 2640 } 2641 }); 2642 2643 } 2644 2645 function qodeSubmitEnquiryForm() { 2646 var enquiryHolder = $('.qode-ls-enquiry-holder'), 2647 enquiryMessageHolder = $('.qode-listing-enquiry-response'), 2648 enquiryForm = enquiryHolder.find('.qode-ls-enquiry-form'); 2649 2650 2651 enquiryForm.on('submit', function () { 2652 enquiryMessageHolder.empty(); 2653 var enquiryData = { 2654 name: enquiryForm.find('#enquiry-name').val(), 2655 email: enquiryForm.find('#enquiry-email').val(), 2656 message: enquiryForm.find('#enquiry-message').val(), 2657 itemId: enquiryForm.find('#enquiry-item-id').val(), 2658 nonce: enquiryForm.find('#qode_nonce_listing_item_enquiry').val() 2659 }; 2660 2661 var requestData = { 2662 action: 'qode_listing_send_listing_item_enquiry', 2663 data: enquiryData 2664 }; 2665 2666 $.ajax({ 2667 type: "POST", 2668 url: QodeListingAjaxUrl, 2669 data: requestData, 2670 success: function (response) { 2671 if (data === 'error') { 2672 enquiryMessageHolder.html(response.data); 2673 //error handler 2674 } else { 2675 enquiryMessageHolder.html(response.data); 2676 enquiryForm.fadeOut(300); 2677 setTimeout(function () { 2678 enquiryForm.remove(); 2679 }, 300); 2680 } 2681 } 2682 }); 2683 }); 2684 2685 } 2686 2687 function qodeListingInitFitVids() { 2688 2689 $('.qode-ls-content-video-part').fitVids(); 2690 } 2691 2692 /* 2693 ** Init Single Listing Slider 2694 */ 2695 2696 function qodeInitSingleListingSlider() { 2697 var singleListingSlider = $('.qode-listing-single-holder .qode-ls-single-item .qode-ls-single-gallery-holder'); 2698 2699 if (singleListingSlider.length) { 2700 singleListingSlider.each(function () { 2701 var thisSlider = $(this), 2702 numberOfItems = 3, 2703 loop = true, 2704 autoplay = true, 2705 number = 0, 2706 speed = 5000, 2707 animationSpeed = 600, 2708 center = true, 2709 autoWidth = true, 2710 navArrows = false, 2711 navDots = false, 2712 margin = 0; 2713 2714 if (typeof singleListingSlider.data('number') !== 'undefined' && singleListingSlider.data('number') !== false) { 2715 number = parseInt(singleListingSlider.data('number')); 2716 } 2717 2718 if (typeof singleListingSlider.data('number-visible') !== 'undefined' && singleListingSlider.data('number-visible') !== false) { 2719 numberOfItems = parseInt(singleListingSlider.data('number-visible')); 2720 } 2721 2722 if (typeof singleListingSlider.data('speed') !== 'undefined' && singleListingSlider.data('speed') !== false) { 2723 speed = singleListingSlider.data('speed'); 2724 } 2725 2726 if (typeof singleListingSlider.data('animation-speed') !== 'undefined' && singleListingSlider.data('animation-speed') !== false) { 2727 animationSpeed = singleListingSlider.data('animation-speed'); 2728 } 2729 2730 if (typeof singleListingSlider.data('nav-arrows') !== 'undefined' && singleListingSlider.data('nav-arrows') !== false && singleListingSlider.data('nav-arrows') === 'no') { 2731 navArrows = false;
2732 } 2733 2734 if (typeof singleListingSlider.data('nav-dots') !== 'undefined' && singleListingSlider.data('nav-dots') !== false && singleListingSlider.data('nav-dots') === 'no') { 2735 navDots = false; 2736 } 2737 2738 if (number === 1) { 2739 loop = false; 2740 autoplay = false; 2741 navArrows = false; 2742 navDots = false; 2743 } 2744 2745 var responsiveNumberOfItems1 = 1, 2746 responsiveNumberOfItems2 = 2; 2747 2748 if (numberOfItems < 3) { 2749 responsiveNumberOfItems1 = numberOfItems; 2750 responsiveNumberOfItems2 = numberOfItems; 2751 } 2752 2753 singleListingSlider.owlCarousel({ 2754 items: numberOfItems, 2755 loop: loop, 2756 autoplay: autoplay, 2757 autoplayTimeout: speed, 2758 smartSpeed: animationSpeed, 2759 margin: margin, 2760 center: center, 2761 autoWidth: autoWidth, 2762 nav: navArrows, 2763 dots: navDots, 2764 responsive: { 2765 0: { 2766 items: responsiveNumberOfItems1, 2767 margin: 0, 2768 center: true, 2769 autoWidth: true 2770 }, 2771 769: { 2772 items: responsiveNumberOfItems2 2773 }, 2774 1025: { 2775 items: numberOfItems 2776 } 2777 }, 2778 navText: [ 2779 '<span class="qode-prev-icon fa fa-angle-left"></span>', 2780 '<span class="qode-next-icon fa fa-angle-right"></span>' 2781 ] 2782 }); 2783 thisSlider.css({'visibility': 'visible'}); 2784 }); 2785 } 2786 } 2787 2788 /* 2789 ** Set Single Listing Slider Height 2790 */ 2791 2792 function qodeSingleListingSliderHeight() { 2793 var singleListingSlider = $('.qode-listing-single-holder .qode-ls-single-item .qode-ls-single-gallery-holder'); 2794 2795 //Set the responsive height of the slider 2796 2797 if (singleListingSlider.length) { 2798 singleListingSlider.each(function () { 2799 var singleListingSlider = $(this), 2800 sliderItem = singleListingSlider.find('.qode-ls-single-gallery-item img'), 2801 maxHeight = singleListingSlider.outerHeight(); 2802 2803 qodeSingleListingSliderRecalculateHeight(singleListingSlider, maxHeight); 2804 2805 $(window).resize(function () { 2806 qodeSingleListingSliderRecalculateHeight(singleListingSlider, maxHeight); 2807 }); 2808 2809 if (singleListingSlider.data('enable-auto-width') === 'yes') { 2810 2811 sliderItem.each(function () { 2812 var thisItem = $(this), 2813 itemInitialHeight = thisItem[0].clientHeight; 2814 qodeSingleListingSliderRecalculateItemsHeight(thisItem, itemInitialHeight); 2815 2816 $(window).resize(function () { 2817 qodeSingleListingSliderRecalculateItemsHeight(thisItem, itemInitialHeight); 2818 }); 2819 }); 2820 2821 } 2822 2823 if (typeof singleListingSlider.data('owl.carousel') !== 'undefined') { 2824 singleListingSlider.trigger('refresh.owl.carousel'); 2825 } 2826 2827 }); 2828 } 2829 } 2830 2831 function qodeSingleListingSliderRecalculateHeight(holder, height){ 2832 var newHeight = qodeSingleListingSliderUpdateHeightCoefficient() * height; 2833 2834 holder.css('height', newHeight) 2835 } 2836 2837 function qodeSingleListingSliderRecalculateItemsHeight(item, height) { 2838 var newHeight = qodeSingleListingSliderUpdateHeightCoefficient() * height; 2839 2840 item.css('height', newHeight); 2841 } 2842
2843 function qodeSingleListingSliderUpdateHeightCoefficient() { 2844 2845 var heightCoefficient = 1; 2846 2847 if ($window_width < 481) { 2848 heightCoefficient = 0.667; 2849 } else if ($window_width < 600) { 2850 heightCoefficient = 0.87; 2851 } else if ($window_width < 769) { 2852 heightCoefficient = 0.968; 2853 } else if ($window_width < 1025) { 2854 heightCoefficient = 0.804; 2855 } else if ($window_width < 1281) { 2856 heightCoefficient = 0.779; 2857 } else if ($window_width < 1441) { 2858 heightCoefficient = 0.916; 2859 } 2860 2861 return heightCoefficient; 2862 } 2863 2864})(jQuery); 2865(function($) { 2866 'use strict'; 2867 2868 var listingAdvSearch = {}; 2869 qode.modules.listingAdvSearch = listingAdvSearch; 2870 2871 listingAdvSearch.qodeOnDocumentReady = qodeOnDocumentReady; 2872 2873 $(document).ready(qodeOnDocumentReady); 2874 listingAdvSearch.qodeInitAdvSearch = qodeInitAdvSearch; 2875 listingAdvSearch.qodeGetAdvancedSearchResponse = qodeGetAdvancedSearchResponse; 2876 2877 /* 2878 All functions to be called on $(document).ready() should be in this function 2879 */ 2880 function qodeOnDocumentReady() { 2881 qodeInitAdvSearch(); 2882 } 2883 2884 function qodeInitAdvSearch(){ 2885 2886 var container = $('.qode-ls-adv-search-holder'); 2887 2888 if(container.length){ 2889 container.each(function(){ 2890 2891 var thisContainer = $(this), 2892 typeID = thisContainer.data('type'), 2893 nextPage = thisContainer.data('next-page'), 2894 maxNumPages = thisContainer.data('max-num-pages'), 2895 submitButton = thisContainer.find('.qode-adv-search-submit'), 2896 keywordSubmitButton = thisContainer.find('.qode-ls-adv-search-keyword-button'), 2897 keywordField = thisContainer.find('.qode-ls-adv-search-keyword'), 2898 availableListings = qodeListingTitles.titles, 2899 loadMoreButton = thisContainer.find('.qode-ls-adv-search-load-more'); 2900 2901 if(qode.modules.listings.qodeIsValidObject(keywordField)){ 2902 keywordField.autocomplete({ 2903 source: availableListings 2904 }); 2905 } 2906 2907 if(qode.modules.listings.qodeIsValidObject(keywordField)){ 2908 keywordSubmitButton.on('click', function(){ 2909 qodeGetAdvancedSearchResponse(typeID, thisContainer, false); 2910 }); 2911 } 2912 2913 2914 submitButton.on('click', function(){ 2915 qodeGetAdvancedSearchResponse(typeID, thisContainer, false); 2916 }); 2917 2918 2919 2920 if(typeof loadMoreButton !== 'undefined' && loadMoreButton !=='false'){ 2921 qode.modules.listings.qodeShowHideButton(loadMoreButton, nextPage, maxNumPages); 2922 2923 loadMoreButton.on('click', function(){ 2924 qodeGetAdvancedSearchResponse(typeID, thisContainer, true); 2925 }); 2926 } 2927 2928 }); 2929 } 2930 2931 } 2932 2933 function qodeGetAdvancedSearchResponse(typeId, container, loadMoreFlag){ 2934 2935 if(typeof typeId !== 'undefined' && typeId !== false && typeId !== ''){ 2936 2937 2938 var number = container.data('number'), 2939 searchFields = container.find('.qode-ls-adv-search-input'), 2940 itemsHolder = container.find('.qode-ls-adv-search-items-holder-inner'), 2941 googleMap = container.data('enable-map'), 2942 mapFlag = false, 2943 loadMoreData, 2944 loadMoreButton = container.find('.qode-ls-adv-search-load-more'), 2945 keywordField = container.find('.qode-ls-adv-search-keyword'), 2946 keyword = '', 2947 defaultSearchParams = {}, 2948 checkBoxSearchParams = {}, 2949 categoryParams = {}, 2950 nextPage, 2951 data = {}; 2952 2953 if(qode.modules.listings.qodeIsValidObject(googleMap)) { 2954 if(googleMap === 'yes'){ 2955 mapFlag = true; 2956 } 2957 } 2958 2959 2960 if(searchFields.length){ 2961 searchFields.each(function(){ 2962 2963 var thisField = $(this); 2964 var fieldNameAttr = thisField.attr('name'); 2965 var fieldType = thisField.attr('type'); 2966 var fieldID; 2967 var fieldVal; 2968 2969 if(fieldNameAttr === 'job_type_categories'){ 2970 //generate category params 2971 fieldVal = thisField.is(':checked'); 2972 fieldID = thisField.attr('id'); 2973 categoryParams[fieldID] = fieldVal; 2974 }else{ 2975 //generate params for all other fields 2976 switch (fieldType) { 2977 case 'checkbox': 2978 fieldVal = thisField.is(':checked'); 2979 checkBoxSearchParams[fieldNameAttr] = fieldVal; 2980 break; 2981 default : 2982 fieldVal = thisField.val(); 2983 defaultSearchParams[fieldNameAttr] = fieldVal; 2984 break; 2985 } 2986 } 2987 }); 2988 } 2989 2990 if(qode.modules.listings.qodeIsValidObject(keywordField)) { 2991 keyword = keywordField.val(); 2992 } 2993 2994 2995 if(loadMoreFlag){
2996 loadMoreData = qode.modules.common.getLoadMoreData(container); 2997 }else{ 2998 container.data('next-page', '2'); 2999 } 3000 3001 3002 //always get value from holder 3003 nextPage = container.data('next-page'); 3004 3005 data = { 3006 action: 'qode_listing_advanced_search_response', 3007 typeId : typeId, 3008 postPerPage : number, 3009 defaultSearchParams: defaultSearchParams, 3010 checkBoxSearchParams: checkBoxSearchParams, 3011 catParams: categoryParams, 3012 keyword: keyword, 3013 enableLoadMore: loadMoreFlag, 3014 loadMoreData: loadMoreData, 3015 enableMap: mapFlag 3016 }; 3017 3018 $.ajax({ 3019 type: "POST", 3020 url: QodeListingAjaxUrl, 3021 data: data, 3022 success: function (data) { 3023 if (data === 'error') { 3024 3025 }else{ 3026 var response = $.parseJSON(data); 3027 var responseHtml = response.html; 3028 var maxNumPages = response.maxNumPages; 3029 3030 if(typeof maxNumPages !== 'undefined' && maxNumPages !== 'false'){ 3031 container.data('max-num-pages', maxNumPages); 3032 } 3033 3034 if(mapFlag){ 3035 3036 var mapObjs = response.mapAddresses; 3037 var mapAddresses = ''; 3038 3039 3040 if(qode.modules.listings.qodeIsValidObject(mapObjs)){ 3041 mapAddresses = mapObjs['addresses']; 3042 } 3043 3044 if(loadMoreFlag){ 3045 nextPage++; 3046 container.data('next-page', nextPage); 3047 //if new map objects are sent via ajax, update global map objects 3048 3049 qode.modules.listings.qodeReinitMultipleGoogleMaps(mapAddresses, 'append'); 3050 3051 setTimeout(function(){ 3052 itemsHolder.append(responseHtml); 3053 },300); 3054 }else{ 3055 //update multiple map addressess object 3056 3057 qode.modules.listings.qodeReinitMultipleGoogleMaps(mapAddresses, 'replace'); 3058 3059 setTimeout(function(){ 3060 itemsHolder.html(responseHtml); 3061 },300); 3062 } 3063 3064 qode.modules.listings.qodeBindTitles(); 3065 } 3066 else{ 3067 3068 if(loadMoreFlag){ 3069 nextPage++; 3070 container.data('next-page', nextPage); 3071 3072 setTimeout(function(){ 3073 itemsHolder.append(responseHtml); 3074 },300); 3075 } 3076 else{ 3077 setTimeout(function(){ 3078 itemsHolder.html(responseHtml); 3079 },300); 3080 } 3081 3082 } 3083 3084 //show button 3085 qode.modules.listings.qodeShowHideButton(loadMoreButton, nextPage, maxNumPages); 3086 } 3087 3088 } 3089 }); 3090 } 3091 3092 } 3093 3094})(jQuery); 3095(function($) { 3096 'use strict'; 3097 3098 var listingGallery = {}; 3099 qode.modules.listingGallery = listingGallery; 3100 3101 listingGallery.qodeIniListingGallery = qodeIniListingGallery; 3102 3103 listingGallery.qodeOnDocumentReady = qodeOnDocumentReady; 3104 3105 $(document).ready(qodeOnDocumentReady); 3106 3107 /* 3108 All functions to be called on $(document).ready() should be in this function 3109 */ 3110 function qodeOnDocumentReady() { 3111 qodeIniListingGallery(); 3112 } 3113 3114 /** 3115 * Masonry gallery, init masonry and resize pictures in grid 3116 */ 3117 function qodeIniListingGallery(){ 3118 3119 var galleryHolder = $('.qode-ls-category-gallery'), 3120 gallery = galleryHolder.children('.qode-ls-gallery-inner'), 3121 gallerySizer = gallery.children('.qode-ls-gallery-sizer'); 3122 3123 resizeListingGallery(gallerySizer.outerWidth(), gallery); 3124 3125 if(galleryHolder.length){ 3126 galleryHolder.each(function(){ 3127 var holder = $(this), 3128 holderGallery = holder.children('.qode-ls-gallery-inner'); 3129 3130 holderGallery.waitForImages(function(){ 3131 holderGallery.animate({opacity:1}); 3132 3133 holderGallery.isotope({ 3134 layoutMode: 'packery', 3135 itemSelector: '.qode-ls-gallery-item', 3136 percentPosition: true, 3137 packery: { 3138 columnWidth: '.qode-ls-gallery-sizer' 3139 } 3140 }); 3141 }); 3142 }); 3143 3144 $(window).resize(function(){ 3145 resizeListingGallery(gallerySizer.outerWidth(), gallery); 3146 gallery.isotope('reloadItems'); 3147 }); 3148 } 3149 } 3150 3151 function resizeListingGallery(size, holder){ 3152 var rectangle_portrait = holder.find('.qode-ls-gallery-rec-portrait'), 3153 rectangle_landscape = holder.find('.qode-ls-gallery-rec-landscape'), 3154 square_big = holder.find('.qode-ls-gallery-square-big'), 3155 square_small = holder.find('.qode-ls-gallery-square-small'); 3156 3157 3158 rectangle_landscape.css('height', size); 3159 square_small.css('height', 'size'); 3160 3161 3162 rectangle_portrait.css('height', 2*size); 3163 3164 3165 if (window.innerWidth <= 680) { 3166 rectangle_landscape.css('height', size/2); 3167 } else { 3168 rectangle_landscape.css('height', size); 3169 } 3170 3171 square_big.css('height', 2*size); 3172 3173 if (window.innerWidth <= 680) { 3174 square_big.css('height', square_big.width()); 3175 } 3176 3177 square_small.css('height', size); 3178 } 3179 3180})(jQuery); 3181(function($) { 3182 'use strict'; 3183 3184 var listingGallery = {}; 3185 qode.modules.listingGallery = listingGallery; 3186 3187 listingGallery.qodeOnDocumentReady = qodeOnDocumentReady; 3188 3189 $(document).ready(qodeOnDocumentReady); 3190 3191 /* 3192 All functions to be called on $(document).ready() should be in this function 3193 */ 3194 function qodeOnDocumentReady() { 3195 3196 } 3197 3198 3199 3200})(jQuery); 3201(function($) { 3202 'use strict'; 3203 3204 var listingSearch = {}; 3205 qode.modules.listingSearch = listingSearch; 3206 3207 listingSearch.qodeListingSearchPriceSlider = qodeListingSearchPriceSlider; 3208 3209 listingSearch.qodeOnDocumentReady = qodeOnDocumentReady; 3210 3211 $(document).ready(qodeOnDocumentReady); 3212 3213 /* 3214 All functions to be called on $(document).ready() should be in this function 3215 */ 3216 function qodeOnDocumentReady() { 3217 qodeListingSearchPriceSlider(); 3218 } 3219 3220 function qodeListingSearchPriceSlider(){ 3221 var holder = $('.qode-ls-main-search-holder-part.price'), 3222 slider = holder.find('.qode-price-slider'), 3223 maxValue = slider.attr('max'), 3224 response = holder.find('.qode-price-slider-response'), 3225 hiddenValue = holder.find('.qode-price-slider-value'); 3226 3227 // Basic rangeslider initialization 3228 slider.rangeslider({ 3229 polyfill: false, 3230 onInit: function(position, value) { 3231 qodeSetListingSearchPricePosition(maxValue, value); 3232 }, 3233 onSlide: function(position, value) { 3234 qodeSetListingSearchPriceAmount(value); 3235 qodeSetListingSearchPricePosition(maxValue, value); 3236 } 3237 }); 3238 3239 function qodeSetListingSearchPriceAmount(value){ 3240 response.text("$"+value); 3241 hiddenValue.val(value); 3242 } 3243 3244 function qodeSetListingSearchPricePosition(maxValue, currentValue) { 3245 3246 if(qode.modules.listings.qodeIsValidObject(maxValue) && qode.modules.listings.qodeIsValidObject(currentValue) ){ 3247 var percent = (currentValue/maxValue) * 100; 3248 response.css('left', percent+'%'); 3249 } 3250 3251 } 3252 3253 } 3254})(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.