var GPSapp = { strings : { path_sym : '/images/geo/symbols.png', path_sym_approx : '/images/geo/geocode_approx.png', img_edit : 'Edit', img_image : 'Image' }, sprite_offsets : {"Information":1324,"Flag, Blue":1084,"Flag, Green":1104,"Flag, Red":1124,"Pin, Blue":1624,"Pin, Green":1644,"Pin, Red":1664,"Block, Blue":464,"Block, Green":484,"Block, Red":504,"Restaurant":1784,"Fast Food":1004,"Pizza":1684,"Bar":384,"Convenience Store":844,"Department Store":924,"Shopping Center":1944,"Bank":364,"Pharmacy":1584,"Fitness Center":1064,"Movie Theater":1464,"Live Theater":1364,"Museum":1484,"Park":1544,"Stadium":2064,"Amusement Park":24,"Zoo":2284,"Lodging":1384,"Residence":1764,"School":1904,"Church":724,"Cemetery":704,"Medical Facility":1424,"Police Station":1704,"Post Office":1724,"Scenic Area":1884,"Telephone":2144,"Drinking Water":984,"Restroom":1824,"Airport":4,"Car":644,"Car Rental":664,"Car Repair":684,"Gas Station":1164,"Parking Area":1564,"Toll Booth":2164,"Crossing":864,"Tunnel":2224,"Bridge":564,"RV Park":1844,"Truck Stop":2204,"Scales":1864,"Wrecker":2264,"Geocache":1184,"Geocache Found":1204,"Forest":1144,"Summit":2084,"Picnic Area":1604,"Campground":624,"Shower":1984,"Swimming Area":2104,"Beach":404,"Fishing Area":1024,"Fishing Hot Spot Facility":1044,"Hunting Area":1284,"Ball Park":344,"Bowling":544,"Golf Course":1244,"Bike Trail":444,"Ice Skating":1304,"Trail Head":2184,"Ski Resort":2004,"Skiing Area":2024,"Anchor":44,"Buoy":604,"Light":1344,"Boat Ramp":524,"Dam":884,"Diver Down (Striped Flag)":944,"Diver Down (Code Flag A)":964,"Man Overboard":1404,"Shipwreck":1924,"Navaid, Amber":64,"Navaid, Black":84,"Navaid, Blue":104,"Navaid, Green":124,"Navaid, Green\/Red":144,"Navaid, Green\/White":164,"Navaid, Orange":184,"Navaid, Red":204,"Navaid, Red\/Green":224,"Navaid, Red\/White":244,"Navaid, Violet":264,"Navaid, White":284,"Navaid, White\/Green":304,"Navaid, White\/Red":324,"Civil":804,"City (Large)":744,"City (Medium)":764,"City (Small)":784,"Building":584,"Short Tower":1964,"Tall Tower":2124,"Radio Beacon":1744,"Bell":424,"Horn":1264,"Mine":1444,"Oil Field":1504,"Controlled Area":824,"Danger Area":904,"Restricted Area":1804,"Skull":2044,"Parachute Area":1524,"Glider Area":1224,"Ultralight Area":2244}, map : {}, clickTimer : null, sampleTimer : null, polylines : [] }; /** * */ GPSapp.sizePanels = function() { console.debug('sizePanels'); var hLocMin = 100, hLoc = 0, //hHeader = $('.navbar').outerHeight(), //hTot = $(window).height() - hHeader; hTot = $(window).height() - 60; // console.log('hTot',hTot); if ( $('#locations').length ) { hLoc = $('#map_canvas') ? Math.floor(hTot*0.4) : hTot; if ( hLoc < hLocMin ) hLoc = hLocMin; // console.debug('hLoc', hLoc); $('#locations_wrapper .dataTables_scrollBody').css({'height':hLoc+'px'}); $('#locations').dataTable().fnAdjustColumnSizing(); } if ( $('#map_canvas').length ) { GPSapp.resize_gmap(); } $('.side').css({'height':hTot+'px'}); }; /** * */ GPSapp.resize_gmap = function() { //console.debug('resize_gmap'); //hHeader = $('header').outerHeight(), //hTot = $(window).height() - hHeader, var hTot = $(window).height() - 60, hGMapCur = $('#map_canvas').outerHeight(), hGMapNew = hTot - $('#locations_wrapper').outerHeight(), center; if (hGMapNew != hGMapCur) { $('#map_canvas').css({ height : hGMapNew+'px' }); if (GPSapp.map.gmap) { center = GPSapp.map.gmap ? GPSapp.map.gmap.getCenter() : null; console.log('center', center); google.maps.event.trigger(GPSapp.map.gmap, 'resize'); GPSapp.map.gmap.setCenter(center); } } return; }; /** * Opens the edit form */ GPSapp.editLoc = function(id) { console.log('editLoc',id); var //$node_tr = $('#loc_id_'+id), //link_count = $node_tr.find('.links a').length, width = 820, maxHeight = $(window).outerHeight(), maxWidth = $(window).outerWidth(); if (typeof id == 'string') { id = id.match(/(\d+)$/)[1]; } if (width > maxWidth) { width = maxWidth; } $.colorbox({ /* href: getSelfURL({ 'action' : 'edit', 'id' : id }), */ href : '/geo/' + id + '/edit', title : 'Edit Location', close : '×', width : width, height : maxHeight, iframe : true }); }; /** * @param int id row id */ GPSapp.getMarkerVals = function(id) { //console.log('getMarkerVals', id); var col_names = 'skip_edit skip_meta skip_nameLinks desc address city state zip phone'.split(' '), $node_tr = $('#loc_id_'+id), $nodes_td = $node_tr.children(), vals = { //'id' : parseInt(node_tr.identify().match(/(\d+)$/)[1]), 'id' : id, 'approx': $node_tr.hasClass('approx'), 'sym' : $node_tr.find('.symbol').text(), 'lat' : parseFloat($node_tr.find('.lat').text()), 'lon' : parseFloat($node_tr.find('.lon').text()), 'name' : $node_tr.find('.name').text(), 'links' : $node_tr.find('.links').html() }, cityStateZip = '', addressFull = ''; $.each(col_names, function(i,col_name) { if ( col_name.indexOf('skip') === 0 ) return; vals[col_name] = $nodes_td.eq(i).text(); }); // now build addressFull cityStateZip = ( vals.city ? vals.city+', ' : '' )+vals.state+' '+vals.zip; cityStateZip = cityStateZip.replace(/[, ]*$/,''); addressFull = vals.address +'
' + cityStateZip; addressFull = addressFull.replace(/^(
)(.*?)(
)$/,'$2'); // toss any
at beginning or end vals.addressFull = addressFull; return vals; }; /** * */ GPSapp.show_samples = function() { var $node = $(this); val = $node.val(); //console.debug('node',node); //debug('val',val); $('#samples').childElements().invoke('hide'); if ( GPSapp.sample_timer ) clearTimeout(GPSapp.sample_timer); if ( !val.empty() ) { $('samples').down().show(); $('samples_'+val).show(); GPSapp.sample_timer = setTimeout(function(){ console.debug('hiding'); $('samples').down().hide(); $('samples_'+val).hide(); },3000); } }; $(function () { console.debug('dom loaded'); console.log('GPSapp',GPSapp); var haveLocationsTable = $('#locations').length, $nodes_tr = $('#locations tbody tr'), $node_tr = $(), $node_sym = $(), index = 0; /* $('.selectpicker').selectpicker({ style: "btn-secondary btn-sm" }); */ function iformat(opt) { var $origOpt = $(opt.element); return $(' ' + opt.text + ''); } $(".select2").select2({ allowHtml: true, templateResult: iformat, templateSelection: iformat, theme: "bootstrap4" }); $(".phonenumber .input-group-addon").removeClass("input-group-addon").addClass("input-group-btn"); // $(".phonenumber .input-group-btn .btn").addClass("btn-sm"); GPSapp.feedback = new feedbackClass('#status'); GPSapp.feedback.working('Loading...', {id: 'status_loading'}); if ($('#form-geo').length) { console.warn('have form-geo'); // geo form if ($('#google_url_q').length) { $('#google_url_a').insertBefore('#geo_url_container .controls'); $('#google_url_q').on('click', function(evt) { console.warn('showhide!'); showHide($('#google_url_a')); }); } fieldTrigger([ [ 'input[name=parse_desc]', 'on', '#geo_rem_addr_container' ], [ 'input[name=format]', 'csv', '#geo_opt_line_breaks_container' ] ]); if ($('#samples').length) { $('#geo select').each(function(node) { $(node).on('mouseover', GPSapp.show_samples); $(node).on('keyup', GPSapp.show_samples); }); $('#geo option').each( function(node) { $(node).on('mouseover', GPSapp.show_samples); }); } } if (haveLocationsTable) { console.debug('have locations'); // $('table.scroll').dataTable({ 'bInfo' : false, 'bFilter' : false, 'bPaginate' : false, 'sScrollY' : '200px', 'aoColumns' : [ {'bSortable' : false, 'sWidth' : '36px'}, {'sWidth' : '3em'}, null, null, null, null, null, null, null ] }); // for (index = 0, len = $nodes_tr.length; index < len; ++index) { // self-invoking function creates closure /* (function() { $node_tr.find('.edit').on('click', function(evt) { debug('index',index); GPSapp.editLoc(node_tr.identify()); }); if ( node_vcard ) { node_vcard.on('click', function(evt) { debug('index',index); var vcard_url = getSelfURL({ 'action' : 'vcard', 'id' : node_tr.identify().match(/(\d+)$/)[1] }); console.debug('vcard_url',vcard_url); document.location = vcard_url; }); } })(); */ $node_tr = $($nodes_tr[index]); $node_sym = $node_tr.find('.symbol'); //$node_vcard = $node_tr.find('.vcard'); if ( $node_tr.hasClass('noGeoCode') ) { $node_sym.prop('title','This location is unknown'); } else if ( $node_tr.hasClass('approx') ) { $node_sym.prop('title','This location is approximate'); } else { $node_sym.prop('title',$node_sym.text()); } } $('#locations').on('click', '.edit', function() { //console.log('edit',this); var $node_tr = $(this).closest('tr'), id = $node_tr.prop('id').match(/(\d+)$/)[1]; GPSapp.editLoc(id); return false; }); $('#locations').on('click', '.vcard', function() { //console.log('vcard',this); var $tr = $(this).closest('tr'), //id = $node_tr.prop('id').match(/(\d+)$/)[1], /* vcardUrl = getSelfURL({ 'action' : 'vcard', 'id' : $node_tr.prop('id').match(/(\d+)$/)[1] }); */ vcardUrl = '/geo/' + $tr.prop('id').match(/(\d+)$/)[1] + '/vcard'; console.debug('vcardUrl', vcardUrl); document.location = vcardUrl; return false; }); $('#locations').on('mouseup', 'tr', function() { var $node_tr = $(this).closest('tr'), id = $node_tr.prop('id').match(/(\d+)$/)[1], marker = GPSapp.map.markers[id]; if (GPSapp.clickTimer) { console.log('dblclick'); clearTimeout(GPSapp.clickTimer); GPSapp.clickTimer = null; if ( GPSapp.map.clusterer && !marker.getMap() ) { console.debug('marker is in cluster'); marker.setMap(GPSapp.map.gmap); setTimeout(function() { marker.setMap(null); },11000); } GPSapp.map.infoWindowOpen(id); if (window.getSelection) { window.getSelection().removeAllRanges(); } else if (document.selection) { document.selection.empty(); } } else { GPSapp.clickTimer = setTimeout(function(e) { console.log('single click'); var gm = google.maps, gmap = GPSapp.map.gmap, lat = marker.position.lat(), lon = marker.position.lng(), bounds = new gm.LatLngBounds( new gm.LatLng(lat-0.0005,lon-0.0001), //sw new gm.LatLng(lat+0.0005,lon+0.0001) //ne ); GPSapp.clickTimer = null; if (!gmap.getBounds().contains(marker.position)) { console.log('need to pan'); gmap.panToBounds(bounds); } if (GPSapp.map.clusterer && !marker.getMap()) { console.log('marker is in cluster'); marker.setMap(gmap); setTimeout(function() { marker.setMap(null); },11000); } marker.setAnimation(gm.Animation.BOUNCE); setTimeout(function() { marker.setAnimation(null); }, 1500); }, 275); } }); // end mouseup } else { console.debug('no location table'); } if (haveLocationsTable || $('#map_canvas').length) { if (navigator.appVersion.indexOf("MSIE 6.") != -1) { alert('Google Maps no longer supports IE 6.'+"\n"+ 'IE 6 was released in Nov 2001.' + "\n" + 'It\'s time to upgrade'); $('#map_canvas').remove(); } GPSapp.sizePanels(); $(window).resize(function() { //clearTimeout(window.resizeTimer); if (window.resizeTimer) { return; } window.resizeTimer = setTimeout(function() { console.debug('resizing'); GPSapp.sizePanels(); window.resizeTimer = null; }, 330); }); } if ($('#map_canvas').length) { GPSapp.map.init(); } if ($('#form-geoEdit').length) { GPSapp.edit.init(); } if ($('#garminDisplay').length) { GPSapp.garmin.init(); } }); /** * http://www.phpied.com/3-ways-to-define-a-javascript-class/ * http://javascript.crockford.com/private.html * * GPSapp.map * minmax * add() * fitMapTo() * geoCodeQueue * markerCreate(vals) * * geoCodeQueueClass * add */ /* GPSapp.sub = (function() { var priv = 'Im private'; function privMeth() { console.log('privMeth'); } console.log('sub thing'); return { pub : 'blah', pubMeth : function() { console.log('pubMeth'); } } }()); */ /** * */ GPSapp.map = (function(module,GPSapp) { module.initializing = true; module.gmap = null; module.geocoder = {}; module.clusterer = null; module.markers = {}; module.markerImages = {}; module.infoWindowCur = null; module.init = function() { console.groupCollapsed('GPSapp.map.init()'); var $nodesTr = $('#locations tbody tr'), $nodeTr = $(), markerVals = [], index = 0, len = 0, id = null, vals = {}, lat = null, lon = null, latlng = {}, gmaps = google.maps; this.geocoder = new gmaps.Geocoder(); for ( index = 0, len = $nodesTr.length; index < len; index++ ) { //console.debug('index',index); $nodeTr = $( $nodesTr[index] ); id = parseInt($nodeTr.prop('id').match(/(\d+)$/)[1], 10); vals = GPSapp.getMarkerVals(id); lat = vals.lat; lon = vals.lon; if ( !isNaN(lat) && !isNaN(lon) ) { /* we have lat/lon ... may be approx */ latlng = new gmaps.LatLng(lat, lon); vals.latlng = latlng; this.minmax.add(latlng); if ( vals.approx ) { vals.sym = 'approx'; } markerVals.push(vals); } if ( $nodeTr.hasClass('noGeoCode') || vals.approx ) { /* lat/lon are approx or none @ all... if have address... attempt to geocode */ this.geoCodeQueue.add(id); } } //console.log('markerVals', markerVals); if ( GPSapp.polylines !== undefined && GPSapp.polylines.length > 0 ) { console.log('have polylines'); $.each(GPSapp.polylines, function() { var polyline = gmaps.geometry.encoding.decodePath(this); // iterate over each LatLng in polyline $.each(polyline, function() { GPSapp.map.minmax.add(this); }); }); } //console.log('this.minmax', this.minmax); console.log('this',this); if ( this.minmax.lat_min !== undefined && !this.gmap ) { console.log('create the map and fit to minmax bounds'); this.createMap({ center : this.minmax.getCenter() }); this.minmax.fitMapTo(); } console.log('loop thru markerVals'); for ( index = 0, len = markerVals.length; index < len; index++ ) { this.markerCreate( markerVals[index] ); } $.each(GPSapp.polylines, function() { gmaps.Polyline({ 'map' : this.gmap, 'path' : this, 'clickable' : false, 'strokeColor' : '#6633ff', 'strokeOpacity' : 0.7, 'strokeWeight' : 3 }); }); markerVals = []; if ( typeof MarkerClusterer == 'function' ) { console.log('using MarkerClusterer'); markerVals = $.map(this.markers, function(v){return v;}); this.clusterer = new MarkerClusterer(this.gmap, markerVals, { maxZoom : 12, minimumClusterSize : 10 }); } /* if ( this.geoCodeQueue.queue.length == 0 ) { GPSapp.feedback.workingRemove(null,'status_loading'); this.initializing = false; } */ console.groupEnd(); }; // module.createMap = function(opts) { console.warn('createMap'); var listener = {}, gmaps = google.maps; if ( this.gmap ) { console.log('already have map'); return; } console.log('creating map'); opts = $.extend({ zoom : 5, //center mapTypeId : gmaps.MapTypeId.ROADMAP },opts); this.gmap = new gmaps.Map($('#map_canvas')[0], opts); if ( this.geoCodeQueue.queue.length === 0 ) { listener = gmaps.event.addListener(this.gmap, 'idle', function() { console.info('map has loaded'); gmaps.event.removeListener(listener); GPSapp.feedback.workingRemove(null,'status_loading'); this.initializing = false; }); } this.gmap.addListener('zoom_changed', function() { var zoom = GPSapp.map.gmap.getZoom(); console.warn('zoomChanged', zoom); if (zoom > 18) { GPSapp.map.gmap.setZoom(18); } }); }; // module.resetMarkerPos = function(id) { console.log('resetMarkerPos'); var $nodeTr = $('#loc_id_'+id), lat = parseFloat($nodeTr.find('.lat').text() ,10), lon = parseFloat($nodeTr.find('.lon').text(), 10), marker = this.markers[id]; marker.setPosition( new google.maps.LatLng(lat,lon) ); return; }; // return module; }(GPSapp.map || {}, GPSapp)); GPSapp.map = (function (module) { /** * markerCreate: * adds marker to map (pending use of MarkerClusterer) * adds marker to markers hash * observes marker events * observes TR events */ module.markerCreate = function(vals, addToMap) { console.groupCollapsed('markerCreate'); //console.log('vals',vals); var id = vals.id, marker = null, //$nodeTr = $('#loc_id_'+id), gmaps = google.maps; if ( module.markers[id] ) { //console.debug('marker already created... updating pos'); module.markers[id].setPosition(vals.latlng); return; } if ( addToMap === true && !this.gmap ) { this.createMap({ center : vals.latlng }); } marker = new gmaps.Marker({ position : vals.latlng, draggable : true, map : typeof MarkerClusterer == 'function' ? null : module.gmap, title : vals.name, icon : this.getMarkerImage(vals.sym), flat : true }); //console.log('marker',marker); module.markers[id] = marker; if ( addToMap === true && module.clusterer ) { module.clusterer.addMarkers([ marker ]); } gmaps.event.addListener(marker, 'click', function() { console.log('marker_clicked'); module.infoWindowOpen(id); }); gmaps.event.addListener(marker, 'dragend', function(evt) { console.debug('marker dragged',evt); var response = confirm('Are you sure you want to move this location?'), valsCur = GPSapp.getMarkerVals(id), $nodeTr = $('#loc_id_'+id); console.debug('response',response); if ( response ) { console.log('valsCur',valsCur); console.log('this',this); if ( valsCur.approx ) { $nodeTr.removeClass('approx'); } GPSapp.edit.updateLocAjax(id, { lat : evt.latLng.lat(), lon : evt.latLng.lng(), sym : valsCur.sym, zoom : this.gmap.getZoom() }); } else { console.log('not updating... reverting'); console.log('this',this); this.resetMarkerPos(id); } }); console.groupEnd(); return; }; return module; }(GPSapp.map || {})); GPSapp.map = (function (module,GPSapp) { /** * function getMarkerImage */ module.getMarkerImage = function (sym) { console.log('GPSapp.map.getMarkerImage', sym); var icon = module.markerImages[sym], gmaps = google.maps; if ( !icon ) { //console.debug('icon not yet created',sym); if ( sym == 'approx' ) { icon = new gmaps.MarkerImage( GPSapp.strings.path_sym_approx, new gmaps.Size(16, 16), // size new gmaps.Point(0,0), // origin new gmaps.Point(8, 12) // anchor ); } else { icon = new gmaps.MarkerImage( GPSapp.strings.path_sym, new gmaps.Size(16, 16), // size new gmaps.Point(4,GPSapp.sprite_offsets[sym]),// origin new gmaps.Point(8, 12) // anchor ); } module.markerImages[sym] = icon; } return icon; }; return module; }(GPSapp.map || {}, GPSapp)); /** * */ GPSapp.map.minmax = { add : function(latlng) { var lat = latlng.lat(), lon = latlng.lng(); if ( this.lat_min === undefined ) { this.lat_min = lat; this.lat_max = lat; this.lon_min = lon; this.lon_max = lon; this.lon_min_pos = 180; // used to determine if bounds more compactly cross 180 meridian this.lon_max_neg = -180; } if ( lat < this.lat_min ) { this.lat_min = lat; } else if ( lat > this.lat_max ) { this.lat_max = lat; } if ( lon < this.lon_min ) { this.lon_min = lon; } else if ( lon > this.lon_max ) { this.lon_max = lon; } if ( lon >= 0 && lon < this.lon_min_pos ) { this.lon_min_pos = lon; } else if ( lon < 0 && lon > this.lon_max_neg ) { this.lon_max_neg = lon; } return; }, crossesMeridian : function() { return ( this.lon_max - this.lon_min > 180 ) && ( this.lon_max_neg - this.lon_min_pos < -180 ); }, getCenter : function() { var avgLat = (this.lat_min + this.lat_max)/2, avgLon = (this.lon_min + this.lon_max)/2; if ( this.crossesMeridian() ) { avgLon = avgLon > 0 ? avgLon - 180 : avgLon + 180; } return google.maps.LatLng(avgLat, avgLon); }, fitMapTo : function() { console.group('minmax.fitMapTo()'); var gmaps = google.maps, bounds; if ( this.crossesMeridian() ) { console.log('smaller bounds by crossing 180 meridian'); bounds = new gmaps.LatLngBounds( new gmaps.LatLng(this.lat_min, this.lon_min_pos), //sw new gmaps.LatLng(this.lat_max, this.lon_max_neg) //ne ); } else { bounds = new gmaps.LatLngBounds( new gmaps.LatLng(this.lat_min, this.lon_min), //sw new gmaps.LatLng(this.lat_max, this.lon_max) //ne ); } GPSapp.map.gmap.fitBounds(bounds); console.groupEnd(); return; } }; /** * */ GPSapp.map.geoCodeQueue = { //var self = this; // local namespce for setTimeout closure //this.geoCoder = new google.maps.Geocoder(); //geoCoder = geoCoder; queue : [], processing : [], // waiting for response valsCache : {}, processTimes : [], // so can keep track of requests/sec (not yet implemented) completed : [], maxConcurrent : 5, delay : 250, // in millisecs timer : null, /** * @param int id row id * @param string pos (optional) can be 'front' or 'end' */ add : function(id,pos) { console.log('geoCodeQueue.add',id); var vals = GPSapp.getMarkerVals(id); if ( vals.address ) { console.debug('have address enqueing in geocoder',id); if ( this.queue.length === 0 ) { GPSapp.feedback.working('Geocoding...',{id:'status_loading'}); } vals.addressFull = vals.addressFull.replace(/
/,', '); this.valsCache[id] = vals; if ( typeof pos == 'string' && pos == 'front' ) { this.queue.unshift(id); } else { this.queue.push(id); } if ( this.timer === null ) { this.process(); } } return this; }, process : function() { console.log('process',this); if ( this.queue.length < 1 || this.processing.length >= this.maxConcurrent ) { console.debug('process: queue is empty OR maxConcurrent'); this.timer = null; return; } var id = this.queue.shift(), // get next id in queue vals = this.valsCache[id], tsNow = new Date().getTime()/1000, self = this, gmaps = google.maps; console.log('process', id, tsNow, vals); // add TS to processTimes for calculation of process rate this.processTimes.push(tsNow); this.processing.push(id); if ( this.processTimes.length >= 10 ) { this.delay = 500; } // GPSapp.map.geocoder.geocode( { 'address' : vals.addressFull, 'location' : vals.lat ? new gmaps.LatLng(vals.lat, vals.lon) : null }, function(results, status) { console.groupCollapsed('geoCode response'); console.log(id, status); console.log('this',this); //console.log('geoCode response', vals); var requeue = false, $nodeTr = $('#loc_id_'+id); if ( status == gmaps.GeocoderStatus.OK ) { console.log('results', results); GPSapp.feedback.working('Geocoding... '+self.queue.length+' remain',{id:'status_loading'}); results = results[0]; $nodeTr.removeClass('noGeoCode'); $nodeTr.removeClass('approx'); GPSapp.map.minmax.add(results.geometry.location); vals.latlng = results.geometry.location; vals.lat = results.geometry.location.lat(); vals.lon = results.geometry.location.lng(); GPSapp.map.markerCreate(vals, true); // will update position if already exists GPSapp.edit.updateLoc(vals); } else { console.debug(' vals',vals); if ( status == gmaps.GeocoderStatus.OVER_QUERY_LIMIT ) { console.log(' processing',self.processing.join(',')); requeue = true; //self.delay = 1000; } } self.postProcess(id,requeue); console.groupEnd(); } ); this.timer = setTimeout(function() { self.process(); },this.delay); }, postProcess : function(id, retry) { var idsVals = {}; retry = typeof retry != 'unknown' && retry; console.group('postProcess',id,retry); //console.log('this.processing',this.processing.join(',')); this.processing.splice(this.processing.indexOf(id), 1); //console.log('this.processing',this.processing.join(',')); if ( retry ) { this.add(id, 'front'); } else { this.completed.push(id); this.valsCache[id] = null; } if ( !this.processing.length && !this.queue.length ) { console.log('no more pending geocodes', this); GPSapp.feedback.workingRemove(null, 'status_loading'); if ( GPSapp.map.initializing ) { GPSapp.map.minmax.fitMapTo(); // should only be doing this when initializing the map GPSapp.map.initializing = false; } $.each(this.completed, function() { var $nodeTr = $('#loc_id_'+this); idsVals[id] = { lat : parseFloat($nodeTr.find('.lat').text(), 10), lon : parseFloat($nodeTr.find('.lon').text(), 10) }; }); this.completed = []; $.ajax(getSelfURL(),{ type : 'POST', data : { action : 'edit', locs : JSON.stringify(idsVals) }, success : function() { GPSapp.feedback.push('Geocoded coordinates saved'); } }); } console.groupEnd(); if ( this.timer === null && this.queue.length ) { console.log('postProcess: timer is null && items in queue'); this.process(); } } }; GPSapp.map.infoWindowOpen = function(id) { console.log('infoWindowOpen',id); var marker = this.markers[id], vals = GPSapp.getMarkerVals(id), $nodeLinks = $('
').html(vals.links), //$img_a = $nodeLinks.find('a[class=lightwindow]'); imgUrl = null, content = ''; $nodeLinks.find('a').each( function() { //console.debug('nodeA',nodeA); var $nodeA = $(this), title = $nodeA.find('img').prop('title'); if ( title ) { $nodeA.find('img').attr('title',null); $nodeA.append(' '+title); } }); vals.links = $nodeLinks.html(); content = '

'+ ( vals.desc ? vals.desc.replace(/[\r\n]+/,'
') : '' ) + ( vals.addressFull ? vals.addressFull+'
' : '' ) + ( vals.phone ? vals.phone+'
' : '' ) + '

' + ( vals.links ? '

'+vals.links+'

' : '' ) + ''+GPSapp.strings.img_edit+' Edit'; if ( imgUrl ) { content = '' + '' + '' + '' + '' + '
'+content+'
'; } content = '

'+vals.name+'

' + content; console.debug('content',content); if ( this.infoWindowCur ) { this.infoWindowCur.close(); } this.infoWindowCur = new google.maps.InfoWindow({ content : content, id : id }); // google.maps.event.addListener(this.infoWindowCur, 'domready', function() { console.debug('infoWindowCur domready'); //console.debug('edits',$('map_canvas').select('.edit')); /** * @todo replace below with delegated event listeners */ /* var $lightwindows = $('#map_canvas').find('.lightwindow'); $lightwindows.each( function() { $(this).on('click', function(evt) { console.log('lightwindow link clicked'); evt.preventDefault(); }); }); $('#map_canvas').find('.edit').on('click',function(evt) { GPSapp.editLoc(id); }); */ $('#map_canvas').on('click', '.edit', function(evt) { console.log('edit clicked', id); GPSapp.editLoc(id); return false; }); }); google.maps.event.addListener(this.infoWindowCur, 'closeclick', function() { //console.debug('stopObserving'); /* $('#map_canvas').find('.edit').off('click'); if ( this.infoWindowCur ) this.infoWindowCur.close(); */ this.infoWindowCur = null; }); this.infoWindowCur.open(this.gmap,marker); return; }; /** * */ GPSapp.edit = (function(module,GPSapp) { console.info('GPSapp.edit'); module.init = function() { console.warn('edit init'); this.phoneObserve(); this.linkObserve(); this.phoneUpdate(); // adds empty field $('#geoEdit_action_2').click( function(evt) { //Event.stop(evt); evt.preventDefault(); var response = confirm('Are you sure you want to remove this location?'); if (response) { // $('#geoEdit_action').val('Edit'); // $('#geoEdit_remove').val('true'); $(this).closest('form').submit(); } return false; }); }; // end init return module; }(GPSapp.edit || {}, GPSapp)); /** * */ GPSapp.edit.linkObserve = function() { console.group('linkObserve'); $('body').on('change', 'input[type=url]', GPSapp.edit.linkUpdate); $('body').on('click', '.link a.remove', function() { var $nodeContainer = $(this).closest('.link'); showHide($nodeContainer, 'hide', null, function() { console.log('hidden',this); $(this).remove(); GPSapp.edit.linkUpdate(); }); return false; }); $('#link_add').click(function(evt){ console.log('add link'); evt.preventDefault(); var $nodeLast = $('#links .link').last(), key = $nodeLast.find('input').prop('id').match(/(\d+)$/)[0], keyNew = parseInt(key, 10) + 1, re = new RegExp('_'+key+'([_"])','g'), html = $nodeLast.clone().wrap('
').parent().html().replace(re,'_'+keyNew+'$1'), $nodeNew = $(html).css({'style':'display:none;'}); $nodeNew.find('input').each( function() { var $node = $(this); $node.val(null); //wf2_addValidation(node); //input_node_observe(node); }); $nodeLast.after($nodeNew); showHide($nodeNew, 'show'); GPSapp.edit.linkUpdate(); return false; }); console.groupEnd(); return; }; /** * */ GPSapp.edit.linkUpdate = function() { console.group('linkUpdate'); var keys = [], keysEmpty = [], removeSelector = '.link a.remove'; /* var $node = $(this), if ( $node.hasClass('img') ) { $node.find('input[type=url]').before(GPSapp.strings.img_image).css({'marginLeft':'4px'}); $node.find('.field_container img').css({float:'left'}); // ,'marginLeft':'1em' } */ $('.link input[type=url]').each( function() { var key = $(this).prop('id').match(/(\d+)$/)[0]; if ( $(this).val() && $(this).val() != $(this).prop('placeholder') ) { keys.push(key); } else { keysEmpty.push(key); } }); console.log('keys',keys); console.log('keysEmpty',keysEmpty); $('#geoEdit_link_keys').val(keys.join(',')); // if ( keysEmpty.length ) { showHide('#link_add', 'hide'); } else { showHide('#link_add', 'show'); } if ( keys.length + keysEmpty.length == 1 ) { console.log('just one... don\'t show remove'); $(removeSelector).hide(); } else { $(removeSelector).show(); } console.groupEnd(); return; }; /** * set up event listeners for phone numbers */ GPSapp.edit.phoneObserve = function() { $('body').on('change', 'input[type=tel]', GPSapp.edit.phoneUpdate); $('body').on('click', '.phonenumber a.remove', function() { console.log('removing phone', this); var $nodeContainer = $(this).closest('.phonenumber'); showHide($nodeContainer, 'hide', null, function(){ console.log('removed',this); $(this).remove(); GPSapp.edit.phoneUpdate(); }); return false; }); return; }; /** * */ GPSapp.edit.phoneUpdate = function() { console.group('phoneUpdate', this); var keys = [], keysEmpty = [], removeSelector = '.phonenumber a.remove', $nodeLast = $('.phonenumber').last(), key = $nodeLast.find('input').prop('id').match(/(\d+)$/)[0], keyNew = parseInt(key, 10) + 1, re = new RegExp('_'+key+'([_"])','g'), html, $node, $nodeNew; // gather empty and non-empty keys $('.phonenumber input[type=tel]').each( function() { var key2 = $(this).prop('id').match(/(\d+)$/)[0]; if ( $(this).val() && $(this).val() != $(this).prop('placeholder') ) { keys.push(key2); } else { keysEmpty.push(key2); } }); console.log('keys',keys); console.log('keysEmpty',keysEmpty); $('#geoEdit_phonenumber_keys').val(keys.join(',')); if ( keysEmpty.length === 0 ) { $(removeSelector).show(); console.log('need to add an empty'); html = $nodeLast.clone().wrap('
').parent().html().replace(re,'_'+keyNew+'$1'); $nodeNew = $(html).css({'style':'display:none;'}); $nodeNew.find('input, select').each( function() { $(this).val(null); //wf2_addValidation(node); //input_node_observe(node); }); $nodeNew.find('.remove').hide(); $nodeNew.find('.bootstrap-select').remove(); /* $nodeNew.find('.select2').select2({ // style: 'btn-secondary btn-sm' }); */ // $nodeNew.find(".input-group-btn .btn").addClass("btn-sm"); $nodeLast.after($nodeNew); showHide($nodeNew, 'show'); } else if ( keysEmpty.length > 1 ) { console.log('more than one empty!... remove the first'); $node = $('#geoEdit_phonenumber_'+keysEmpty[0]).closest('.phonenumber'); $node.find('a.remove').click(); } else if ( keys.length + keysEmpty.length == 1 ) { console.log('just one... don\'t show remove'); $(removeSelector).hide(); } else { console.log('show em all.. except for empty'); $.each(keys, function(key) { $node = $('geoEdit_phonenumber_'+key).closest('.phonenumber'); $node.find('.remove').show(); }); } console.groupEnd(); return; }; /** * */ GPSapp.edit.updateLocAjax = function(id,vals) { console.log('updateLocAjax'); vals = $.extend({ action : 'edit', id : id },vals); Ajax.Request(getSelfURL(), { method : 'post', parameters : vals, onSuccess : function(t) { var response = t.responseJSON, success = response.get('success'); console.log('success',success); if ( success ) { GPSapp.edit.updateLoc(vals); GPSapp.feedback.push('Marker updated'); } else { GPSapp.map.resetMarkerPos(id); } }, onFailure : function(t) { GPSapp.map.resetMarkerPos(id); } }); return; }; /* Updates TR with new values if infoWindow is open, will update infoWindow if location changes, will update marker pos */ GPSapp.edit.updateLoc = function(vals,closeModal) { console.group('updateLoc'); //vals = $H(vals); var id = vals.id, cols = ['edit','sym','name & links','desc','address','city','state','postalcode','phonenumber'], $node_tr = $('#loc_id_'+id), $node_tds = $node_tr.children(), $node_sym = $node_tr.find('.symbol'), str_class = '', a = [], marker = GPSapp.map.markers[id], pos_cur, pos_new, openInfoWindow = false feedbackMsg = vals.remove !== undefined && vals.remove ? 'Marker removed' : 'Marker updated'; console.log('vals',vals); console.log('node_tds',$node_tds); if ( closeModal ) { parent.jQuery.colorbox.close() parent.GPSapp.feedback.push(feedbackMsg); } $.each(vals, function(k,v) { var i = cols.indexOf(k), classname = null, $node_td, $node; console.groupCollapsed(k); console.log('v', v); if ( k == 'sym' ) { classname = 'symbol'; $node = $node_td.find('.'+classname); // find & remove existing icon-geo-* class a = $node.prop('class').split(/\s+/); $.each(a, function(i,className) { if ( className.indexOf('icon-geo-') === 0 ) { $node.removeClass(className); } }); str_class = 'icon-geo-'+v.replace(/\W+/g,''); $node.addClass('symbol '+str_class); if ( $('#map_canvas').length ) { console.log('update marker icon (if mapped)',v); if ( marker ) { marker.setIcon(GPSapp.map.getMarkerImage(v)); } } } else if ( i >= 0 ) { $node_td = $node_tds.eq(i); $node_td.html(v); } else if ( $node_tr.find('.'+k) ) { classname = k; } //console.log('classname', classname); if ( classname ) { $node = $node_tr.find('.'+classname); $node.html(v); } console.groupEnd(); }); if ( $node_tr.hasClass('noGeoCode') ) { $node_sym.prop('title','This location is unknown'); GPSapp.map.geoCodeQueue.add(id); } else if ( $node_tr.hasClass('approx') ) { $node_sym.prop('title','This location is approximate'); GPSapp.map.geoCodeQueue.add(id); } else { $node_sym.prop('title',$node_sym.text()); } if ( vals.remove ) { $node_tr.remove(); } if ( $('#map_canvas') ) { if ( vals.remove ) { if ( GPSapp.map.clusterer && !marker.getMap() ) { console.log('marker is in cluster'); GPSapp.map.clusterer.removeMarker(marker); } else { marker.setMap(null); } delete GPSapp.map.markers[id]; } else { pos_cur = marker.getPosition(); if ( vals.lat && vals.lon && vals.lat != pos_cur.lat() && vals.lon != pos_cur.lng() ) { console.log('updating position'); pos_new = new google.maps.LatLng(vals.lat, vals.lon); marker.setPosition(pos_new); } if ( $node_tr.hasClass('noGeoCode') ) { GPSapp.map.geoCodeQueue.add(id); } } if ( GPSapp.map.infoWindowCur && GPSapp.map.infoWindowCur.id == id ) { console.log('close infoWindow'); GPSapp.map.infoWindowCur.close(); openInfoWindow = !vals.remove; } if ( openInfoWindow ) { GPSapp.map.infoWindowOpen(id); } } console.groupEnd(); return; }; /** * Garmin */ /** * */ GPSapp.sendTo = (function(module,GPSapp) { return module; }(GPSapp.sendTo || {}, GPSapp)); /** * 3 Methods * push : displays a message which will display for duration * working : display a message which will remain until workingRemove is called * workingRemove : remove a working message * * @param string container selector or node * @param object opts options */ feedbackClass = function(container,opts) { thisself = this; this.$container = $(container); this.opts = $.extend({ duration : 3000, animate_working : true, animation_id : 'status_ani_wrap' },opts); this.push = function(msg) { var $nodeNew = this.createAndShow(msg); //console.log('feedback.push',msg); setTimeout(function() { $nodeNew.slideUp({ complete : function() { $nodeNew.remove(); if ( thisself.$container.children().length == 1 ) // just animation node thisself.$container.hide(); } }); }, this.opts['duration']); }; this.working = function(msg,opts) { console.log('feedback.working',msg,opts); var $nodeNew = $(); opts = $.extend({ id : null },opts); $found = this.workingFind(msg, opts['id']); if ( $found.length ) { $found.html('
'+msg+'
'); return $found; } if ( this.opts['animate_working'] ) { $( '#' + this.opts['animation_id'] ).show(); } $nodeNew = this.createAndShow(msg) .addClass('working'); if ( opts['id'] ) $nodeNew.prop('id',opts['id']); $nodeNew.queue(function() { var props = { opacity:0 }; $(this).pulse(props,{ pulses : -1, // pulse indefinitely duration : 1000 }); $(this).dequeue(); }); return $nodeNew; }; this.workingRemove = function(msg,id) { console.log('feedback.workingRemove',msg, id); var $found = this.workingFind(msg, id); $found.slideUp({ complete : function() { $found.pulse('destroy') .remove(); if ( thisself.opts['animate_working'] && !thisself.$container.find('.working').length ) $( '#' + thisself.opts['animation_id'] ).hide(); if ( thisself.$container.children().length == 1 ) // just animation node thisself.$container.hide(); } }); }; // private functions this.workingFind = function(msg,id) { //console.log('workingFind',msg,id); var $found = $(), stripped = ''; if ( id ) { $found = $('#'+id); } else { stripped = $('
').html(msg).text(); this.$container.find('.working').each( function() { var $node = $(this); if ( stripped == $node.text() ) { $found = $node; return false; // break; } }); } return $found; }; this.createAndShow = function(msg) { //console.log('createAndShow',msg); var $nodeNew = $('
').html(msg).css({display:'none'}); if ( !this.$container.is(':visible') ) this.$container.show(); this.$container.append($nodeNew); $nodeNew.queue(function(){ $(this).fadeIn(200).dequeue(); }) return $nodeNew; }; }; /** * http://jsoverson.github.io/jquery.pulse.js/ */ (function(t,n){"use strict";var e={pulses:1,interval:0,returnDelay:0,duration:500};t.fn.pulse=function(u,r,a){var i="destroy"===u;return"function"==typeof r&&(a=r,r={}),r=t.extend({},e,r),r.interval>=0||(r.interval=0),r.returnDelay>=0||(r.returnDelay=0),r.duration>=0||(r.duration=500),r.pulses>=-1||(r.pulses=1),"function"!=typeof a&&(a=function(){}),this.each(function(){function e(){return s.data("pulse").stop?void 0:r.pulses>-1&&++c>r.pulses?a.apply(s):(s.animate(u,{duration:r.duration/2,complete:function(){n.setTimeout(function(){s.animate(l,{duration:r.duration/2,complete:function(){n.setTimeout(e,r.interval)}})},r.returnDelay)}}),void 0)}var o,s=t(this),l={},p=s.data("pulse")||{};p.stop=i,s.data("pulse",p);for(o in u)u.hasOwnProperty(o)&&(l[o]=s.css(o));var c=0;e()})}})(jQuery,window,document);function fieldTrigger(c){$(document).ready(function(){$.each(c,function(e,d){d=b(d);$(d.selector).change(function(f){a(d,f)});a(d)})});function a(f,e){var i=(typeof e=="undefined"),h=[],d=[],g=[];$(f.selector).each(function(j,k){var l=null;if($(k).is(":checkbox, :radio")){if($(k).is(":checked")){h.push($(k).val())}}else{if($(k).is("select")&&$(k).prop("multiple")){l=$(k).val();if(l===null){l=[]}h=$.unique($.merge(h,l))}else{h.push($(k).val())}}});if(f.always){d.push(f.always)}$(f.conditions).each(function(k,j){if($.inArray(j["if"],h)>-1){d.push(j.then);g.push(j["else"])}else{d.push(j["else"]);g.push(j.then)}});$(d).each(function(k,j){if(typeof j=="function"){if(i){if(f.execOnInit){j.call($(f.selector))}else{return}}else{j.call($(f.selector),e)}}else{showHide(j,"show",i?"none":"slide")}});$(g).each(function(k,j){if(typeof j=="function"){if(i){if(f.execOnInit){j.call($(f.selector))}else{return}}else{j.call($(f.selector),e)}}else{showHide(j,"hide",i?"none":"slide")}})}function b(d){var e={selector:null,conditions:[],"else":null,always:null,execOnInit:false};if($.isArray(d)){d=$.extend(e,{selector:d[0],conditions:[{"if":d[1],then:d[2],"else":d[3]}]})}else{if(typeof d.conditions!="undefined"&&!$.isArray(d.conditions)){d.conditions=[d.conditions]}d=$.extend(e,d)}return d}};