From 8f33fa233a5c84006b92911aceff3e469b95a93a Mon Sep 17 00:00:00 2001 From: Chad Norwood Date: Thu, 29 Mar 2012 12:16:28 -0500 Subject: [PATCH 01/50] got forked code from Igor, changing back to chad's google API key, fix regex and default to chicago --- TODO | 42 ++++++ examples/gcm/FAQ.html | 20 +++ examples/gcm/config.php | 25 ---- examples/gcm/index.html | 227 +++++++++++++++++++++++++++++++ examples/gcm/index.php | 227 ------------------------------- examples/gcm/js/cnMapFilter.js | 2 +- examples/gcm/js/cnMapFilterUI.js | 10 +- test/HISTORY | 3 + 8 files changed, 298 insertions(+), 258 deletions(-) create mode 100644 TODO create mode 100644 examples/gcm/FAQ.html delete mode 100644 examples/gcm/config.php create mode 100644 examples/gcm/index.html delete mode 100644 examples/gcm/index.php create mode 100644 test/HISTORY diff --git a/TODO b/TODO new file mode 100644 index 0000000..9cea62b --- /dev/null +++ b/TODO @@ -0,0 +1,42 @@ +What is the 'src' directory (ask Chad)? + +Remove external calls + $.getJSON("http://chadnorwood.com/saveJson/?callback=?", {sj: cnMF.reportData}); + + +[DONE] Write a feature list. See http://chadnorwood.com/projects/gcm/#KeyFeatures + +[DONE] What happens when the list of events is too long? See vert slider in + http://chadnorwood.com/gcm/?u=http://www.google.com/calendar/feeds/jo0ubvoi1gutr95kdtl1245u3g@group.calendar.google.com/public/basic + +[DONE] remove PHP code. See index.html + +[DONE] Create test calendar. + https://www.google.com/calendar/feeds/0ei0284so407vu24o7o0q5ares%40group.calendar.google.com/public/basic + +[DONE] non-ascii characters break the geo-locating code. Removed encode(), use instead http://www.w3schools.com/jsref/jsref_encodeuri.asp + +[TRIVIAL] Change dates has a debug popup that should be removed + +[TRIVIAL] Add link to FAQ in information message: "The Following Events Had Addresses (Where) That Could Not Be Found. See FAQ" + See FAQ.html for a start. + +[EASY] Remove the "_ errors" in the top right box. It's redundant with the warning link that appears. + +[EASY] When events are on the whole day, do not display time (second part of 2011-12-10 Sat 00:00) + +[EASY] Jump to an address, city, or zip - the zoom level should match the granularity: "Indiana" is a state-wide request. + +[MEDIUM] Inform the user of inconsistencies (in the calendar entries). Use a javascript alert? + +[MEDIUM] plot icon on the map should bear information. For example, number of events at location. + +[MEDIUM] Display several calendars at once: differentiate by color + +[MEDIUM] Inform the user for time-consuming operations (load calendar) + +[BUG] horizontal time slider filters OK the calendar table, but not the map (look for first chronolgical entry) + +[TEDIOUS] Translate application (add flags under the top right GCM logo; auto-detect language by IP) + +[???] Write an integration process: checkSyntax, minify, push to Web server diff --git a/examples/gcm/FAQ.html b/examples/gcm/FAQ.html new file mode 100644 index 0000000..9498d8f --- /dev/null +++ b/examples/gcm/FAQ.html @@ -0,0 +1,20 @@ + + +GCM FAQ + + + +

GCM FAQ

+
+
The Following Events Had Addresses (Where) That Could Not Be Found
+
GCM relies on the “where” field found in the google calendar which has been specified. +The value of this “where” field is converted into a latitude and longitude using Google's geolocation API; +the conversion sometimes may fail for various reasons, but most usually it is because the where data is incomplete. +To make sure the data is sufficient, copy and paste the “where” field into +google maps. If a single location is returned, then the data is correct. +
+ +
+ + + diff --git a/examples/gcm/config.php b/examples/gcm/config.php deleted file mode 100644 index 2e89815..0000000 --- a/examples/gcm/config.php +++ /dev/null @@ -1,25 +0,0 @@ - \ No newline at end of file diff --git a/examples/gcm/index.html b/examples/gcm/index.html new file mode 100644 index 0000000..717dbc8 --- /dev/null +++ b/examples/gcm/index.html @@ -0,0 +1,227 @@ + + + + + Google Calendar Map + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + diff --git a/examples/gcm/index.php b/examples/gcm/index.php deleted file mode 100644 index 7610ca6..0000000 --- a/examples/gcm/index.php +++ /dev/null @@ -1,227 +0,0 @@ - $max) return $max; - return $var; -} - -foreach (array('r','c','z','m','sz','lat','lng','sd','ed') as $val) { - if (@$_GET[$val]) { - if (1 || preg_match('/^[\d\-\.]+$/',$_GET[$val])) { - $valid[$val] = $_GET[$val]; - } - } -} -foreach ($valid as $key => $val) { - if ($key == 'r') $rating = validateRange($val,0,5, $rating); - if ($key == 'c') $catg = validateRange($val,0,100, $catg); - if ($key == 'z') $gZoomLevel = validateRange($val,1,20, $gZoomLevel); - if ($key == 'm') $maptype = validateRange($val,0,4, $maptype); - if ($key == 'lng') $ll = validateRange($val,-180,180, $ll); - if ($key == 'lat') $lt = validateRange($val,-180,180, $lt); - if ($key == 'sd') $sday = validateRange($val,-10,366, $sday); - if ($key == 'ed') $eday = validateRange($val,-10,366, $eday); - if ($key == 'sd') $sday = $val; // support 2010-9-23 - if ($key == 'ed') $eday = $val; - if ($key == 'sz') { - list($mh,$mw) = split('x',$key); - $maph = validateRange($mh,200,2000, $maph); - $mapw = validateRange($mw,200,2000, $mapw); - } -} -$xmlurl = isset($_GET['u']) ? $_GET['u'] : 'u'; -$foo = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum commodo mollis tortor. Ut dapibus turpis consequat quam. Nulla lacinia. Donec nunc. Donec sollicitudin. Vivamus orci. Pellentesque tempus velit vitae odio. Maecenas enim arcu, volutpat ac, viverra id, bibendum eu, felis. Vestibulum imperdiet arcu. Ut nisi. Cras vel lectus consectetuer mauris luctus ultrices. Duis fringilla pellentesque sapien.'; - - - -?> - - - - - Google Calendar Map - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - */ ?> - - - - - - - - - - - - - - - - - - - - -
-
- - - - - - diff --git a/examples/gcm/js/cnMapFilter.js b/examples/gcm/js/cnMapFilter.js index b6f25d3..17be4d6 100644 --- a/examples/gcm/js/cnMapFilter.js +++ b/examples/gcm/js/cnMapFilter.js @@ -732,7 +732,7 @@ // http://groups.google.com/group/google-maps-api/browse_thread/thread/e347b370e8586767/ddf95bdb0fc6a9f7?lnk=raot geoUrl = 'http://maps.google.com/maps/geo?' + '&key='+ googleApiKey - + '&q='+ escape(addr) + + '&q='+ encodeURI(addr) + '&sensor=false&output=json' + '&callback=?'; //geoUrl = 'http://maps.google.com/maps/geo?callback=?'; diff --git a/examples/gcm/js/cnMapFilterUI.js b/examples/gcm/js/cnMapFilterUI.js index 8cd2577..119efd8 100644 --- a/examples/gcm/js/cnMapFilterUI.js +++ b/examples/gcm/js/cnMapFilterUI.js @@ -948,11 +948,11 @@ cnMF.reportData.submitTime = cnMF.reportData.submitTime.replace(/(\d{3})$/,".$1"); // add period so its secs.msec debug.info("cbGeoDecodeComplete() post cnMF.reportData:", cnMF.reportData); - _gaq.push(['_trackEvent', 'Loading', 'calenders', 'uniqAddrDecoded', cnMF.reportData.uniqAddrDecoded]); - _gaq.push(['_trackEvent', 'Loading', 'calenders', 'uniqAddrTotal', cnMF.reportData.uniqAddrTotal]); - _gaq.push(['_trackEvent', 'Loading', 'calenders', 'uniqAddrErrors', cnMF.reportData.uniqAddrErrors]); - _gaq.push(['_trackEvent', 'Loading', 'calenders', 'totalGeoDecodes', 1]); - _gaq.push(['_trackEvent', 'Loading', 'calenders', 'totalGeoDecodeMsecs', parseInt(cnMF.reportData.submitTime.replace(/\./,'')) - parseInt(cnMF.reportData.loadTime.replace(/\./,''))]); + _gaq.push(['_trackEvent', 'Loading', 'calenders', 'uniqAddrDecoded', cnMF.reportData.uniqAddrDecoded]); + _gaq.push(['_trackEvent', 'Loading', 'calenders', 'uniqAddrTotal', cnMF.reportData.uniqAddrTotal]); + _gaq.push(['_trackEvent', 'Loading', 'calenders', 'uniqAddrErrors', cnMF.reportData.uniqAddrErrors]); + _gaq.push(['_trackEvent', 'Loading', 'calenders', 'totalGeoDecodes', 1]); + _gaq.push(['_trackEvent', 'Loading', 'calenders', 'totalGeoDecodeMsecs', parseInt(cnMF.reportData.submitTime.replace(/\./,'')) - parseInt(cnMF.reportData.loadTime.replace(/\./,''))]); // only script tag can bypass same-origin-policy, so use jsonp hack by adding callback=? // note that URL limit is 1024 (?) chars, so can't send too much data //$.post("http://chadnorwood.com/saveJson/", {sj: cnMF.reportData}); diff --git a/test/HISTORY b/test/HISTORY new file mode 100644 index 0000000..71f7e31 --- /dev/null +++ b/test/HISTORY @@ -0,0 +1,3 @@ + wget "http://localhost/gmap/igor_work/examples/gcm/index.html?ed=180&u=https://www.google.com/calendar/feeds/edbd7jqqu7s83ndvv276mueeig%40group.calendar.google.com/public/basic" -O igor + wget "http://chadnorwood.com/gcm/?ed=180&u=https://www.google.com/calendar/feeds/edbd7jqqu7s83ndvv276mueeig%40group.calendar.google.com/public/basic" -O chad + meld chad igor From 9ed5defd9ffd6b8de34fc3bebd11be8b79b1267c Mon Sep 17 00:00:00 2001 From: Chad Norwood Date: Sun, 8 Apr 2012 14:49:37 -0500 Subject: [PATCH 02/50] Multiple Calendars works --- examples/gcm/index.html | 414 ++++++++++++++++------------ examples/gcm/js/cnMapFilter.js | 446 +++++++++++++++++++------------ examples/gcm/js/cnMapFilterUI.js | 186 +++++++++---- 3 files changed, 646 insertions(+), 400 deletions(-) diff --git a/examples/gcm/index.html b/examples/gcm/index.html index 717dbc8..35ca275 100644 --- a/examples/gcm/index.html +++ b/examples/gcm/index.html @@ -1,184 +1,246 @@ - - - Google Calendar Map - - - - - - - - - - - - - - - - - - - - - - - - + + + Google Calendar Map + + + + + + + + + + + + + + + + + + + + + + + + - + //$("#xmlHelpButton").click(function() { $("#xmlHelpInfo").toggle(); }); + // var myURL = parseURL('http://abc.com:8080/dir/index.html?id=255&m=hello#top'); + var myURL = parseURL(window.location.href); + + // modified to support multiple params with same key, from http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ + function parseURL(url) { + var a = document.createElement('a'); + a.href = url; + + return { + source: url, + protocol: a.protocol.replace(':',''), + host: a.hostname, + port: a.port, + query: a.search, + params: (function(){ + var ret = {}, + seg = a.search.replace(/^\?/,'').split('&'), + len = seg.length, + i = 0, s; + for (;iMap Link"; + $("#MapStatus").append(msg); + } + }); + }); // end document ready + + //]]> + + NOTE: comment out above firebug-lite in production + --> - - - - + diff --git a/examples/gcm/js/cnMapFilter.js b/examples/gcm/js/cnMapFilter.js index 17be4d6..3db1d83 100644 --- a/examples/gcm/js/cnMapFilter.js +++ b/examples/gcm/js/cnMapFilter.js @@ -26,7 +26,7 @@ debug && debug.setLevel(parseInt(lvl[1],10)); //console.log("setLevel=",lvl[1]); } else { - debug && debug.setLevel(0); // turns off all logging + debug && debug.setLevel(9); // turns off all logging } debug.includeMsecs(true); @@ -208,6 +208,11 @@ cnMF.tz.name = coreOptions.tzName ? coreOptions.tzName : 'unknown'; // Olson database timezone key (ex: Europe/Berlin) cnMF.tz.dst = coreOptions.tzDst ? coreOptions.tzDst : 'unknown'; // bool for whether the tz uses daylight saving time cnMF.tz.computedFromBrowser = (cnMF.tz.name != 'unknown'); + + cnMF.myGeo = cnMF.geocodeManager({ + googleApiKey: cnMF.googleApiKey, + }); + } cnMF.countTotal = function () { @@ -244,6 +249,26 @@ return e; } + cnMF.addCal = function(gCalUrl, calData){ + console.log("cnMF.addCal", gCalUrl, calData); + + if (!cnMF.calData) { + cnMF.calData = {}; + } + cnMF.calData[gCalUrl] = calData; + + //$.extend(cnMF, calData); // TODO2 this overwrites, figure out better way to display multiple calendar names + /* + calendarInfo.gCalUrl = gCalUrl; + calendarInfo.totalEntries = ii; + calendarInfo.totalEvents = cdata.feed.openSearch$totalResults.$t || ii; + calendarInfo.gcTitle = cdata.feed.title ? cdata.feed.title['$t'] : 'title unknown'; + calendarInfo.gcLink = cdata.feed.link ? cdata.feed.link[0]['href'] : ''; + calendarInfo.desc = cdata.feed.subtitle ? cdata.feed.subtitle['$t'] : 'subtitle unknown'; + */ + } + + // // mapAllEvents() adjusts zoom and coords in order to fit all events on map // @@ -419,33 +444,29 @@ debug.info("Displaying calendar times using this timezone: "+ gCalObj.ctz); } $.getJSON(gCalUrl + "?alt=json-in-script&callback=?", gCalObj, function(cdata) { - parseGCalData(cdata, startDate, endDate, callbacks); + parseGCalData(gCalUrl, cdata, startDate, endDate, callbacks); }); } - function parseGCalData (cdata, startDate, endDate, callbacks ) { + function parseGCalData (gCalUrl, cdata, startDate, endDate, callbacks ) { + var calendarInfo = {}, + uniqAddr = {}; debug.info("parseGCalData() calendar data: ",cdata); - cnMF.gcTitle = cdata.feed.title ? cdata.feed.title['$t'] : 'title unknown'; - cnMF.gcLink = cdata.feed.link ? cdata.feed.link[0]['href'] : ''; - cnMF.desc = cdata.feed.subtitle ? cdata.feed.subtitle['$t'] : 'subtitle unknown'; - cnMF.reportData['fn'] = cnMF.gcTitle.replace(/\W/,"_"); - cnMF.gcTitle = cdata.feed.title ? cdata.feed.title['$t'] : 'title unknown'; + calendarInfo.gCalUrl = gCalUrl; + calendarInfo.gcTitle = cdata.feed.title ? cdata.feed.title['$t'] : 'title unknown'; + calendarInfo.gcTitle.replace(/"/,'"'); + calendarInfo.gcLink = cdata.feed.link ? cdata.feed.link[0]['href'] : ''; + calendarInfo.desc = cdata.feed.subtitle ? cdata.feed.subtitle['$t'] : 'subtitle unknown'; + + // TODO2 move this to a method if (!cnMF.tz.computedFromBrowser) { cnMF.tz.name = cdata.feed.gCal$timezone.value; debug.info("Displaying calendar times using calendar timezone: "+ cnMF.tz.name); + // TODO2 count in analytics how many people use timezones in browser vs calendar } - var uniqAddr={}; - /* do we need this at all anymore? - eType = cnMF.addEventType({ - tableHeadHtml: "onetwo", - tableCols: [3,5], - title: cnMF.gcTitle, - titleLink: cnMF.gcLink - }); - */ for (var ii=0; cdata.feed.entry && cdata.feed.entry[ii]; ii++) { var curEntry = cdata.feed.entry[ii]; if (!(curEntry['gd$when'] && curEntry['gd$when'][0]['startTime'])) { @@ -463,6 +484,7 @@ } kk = cnMF.addEvent({ //type: eType.id, + calTitle: calendarInfo.gcTitle, name: curEntry['title']['$t'], desc: curEntry['content']['$t'], addrOrig: curEntry['gd$where'][0]['valueString'] || '', // addrOrig is the location field of the event @@ -481,30 +503,32 @@ } debug.log("parsed curEntry "+ii+": ", kk.name, curEntry, kk); } - cnMF.totalEntries = ii; - cnMF.totalEvents = cdata.feed.openSearch$totalResults.$t || cnMF.totalEntries; + calendarInfo.totalEntries = ii; + calendarInfo.totalEvents = cdata.feed.openSearch$totalResults.$t || ii; + cnMF.addCal(gCalUrl, calendarInfo); + cnMF.reportData['fn'] = calendarInfo.gcTitle.replace(/\W/,"_"); debug.log("calling mapfilter.geocode(): ", uniqAddr ); cnMF.myGeoDecodeComplete = false; - cnMF.myGeo = cnMF.geocodeManager({ - addresses: uniqAddr, - googleApiKey: cnMF.googleApiKey, - geocodedAddrCallback: function (gObj) { + cnMF.myGeo.addr2coords( uniqAddr, + function (gObj) { cnMF.processGeocode(gObj); // TODO: this can be private if ('function' === typeof callbacks.onGeoDecodeAddr) callbacks.onGeoDecodeAddr(); }, - geocodeCompleteCallback: function() { + function() { //onGeoDecodeComplete(); cnMF.myGeoDecodeComplete = true; if ('function' === typeof callbacks.onGeoDecodeComplete) callbacks.onGeoDecodeComplete(); } - }); - if ('function' === typeof callbacks.onCalendarLoad) callbacks.onCalendarLoad(); + ); + if ('function' === typeof callbacks.onCalendarLoad) { + callbacks.onCalendarLoad(calendarInfo); + } } // geocodeManager handles the geocoding of addresses - // + // // TODO: use more than just google maps api // // http://tinygeocoder.com/blog/how-to-use/ @@ -518,16 +542,58 @@ /// cnMF.geocodeManager = function( gOpts ) { - // count addreses and unique addreses. - // don't want duplicates - wasting calls to google - var uniqAddresses = {}; - var numAddresses = numUniqAddresses = numUniqAddrDecoded = numUniqAddrErrors = 0; - var geoCache = {}; - var numReqs = 0; - var startTime = new Date().getTime(); + // goal: + // public function + // GeocodeManager.stats() - returns stats object - (num unique addresses, num resolved, etc) - // won't stop till all address objects are resolved (resolved==true) + // private functions + + + // count addreses and unique addreses. + // don't want duplicates - wasting calls to google + + var GeocodeManager = {}, // return obj + addrObjects = [], // stores all address objects + resolveRequests = [], // array of requestObjects, each obj has add, cb1, cb2 + + //uniqAddresses = {}, // stores addr objects + numAddresses = 0, + //numUniqAddresses = 0, + //numUniqAddrDecoded = 0, + //numUniqAddrErrors = 0, + geoCache = {}, + googleApiKey, + numReqs = 0, + startTime = new Date().getTime(), + + // Google specific geocoding variables + desiredRate = 100, // long-term average should be one query every 'desiredRate' ms + maxBurstReq = 4, // if timeout gets delayed, say 500ms, we can send 'maxBurstReq' at a time till we catch up + maxRetry = 4; + + GeocodeManager.init = function() { + googleApiKey = gOpts.googleApiKey; + } + + + GeocodeManager.count = function() { + var c = { + uniqAddrDecoded: 0, + uniqAddrErrors: 0, + uniqAddrTotal: 0 + } + for (var addr in geoCache) { + ao = geoCache[addr]; + c.uniqAddrTotal++; + if (ao.resolved && ao.validCoords) c.uniqAddrDecoded++; + if (ao.resolved && !ao.validCoords) c.uniqAddrErrors++; + } + return c; + } + + + // GeocodeManager won't stop till all address objects are resolved (resolved==true) // when resolved is true, then if (validCoords) it was successful // otherwise look to error // @@ -542,79 +608,108 @@ this.lt = ''; this.lg = ''; } - - function geoMgrInit(){ - for (var ii in gOpts.addresses) { + function deDup(addresses) { + var uniqAddresses = {}, // stores addr objects + ret = []; + for (var ii in addresses) { if (!(ii.length > 0)) { debug.warn("geocodeManager-geoMgrInit() skipping blank address"); continue; } numAddresses++; if (!isNaN(ii)) { - uniqAddresses[gOpts.addresses[ii]] = 1; // array + uniqAddresses[addresses[ii]] = 1; // array + console.log("CHAD TODO2 xx1", ii); } else { + console.log("CHAD TODO2 xx2", ii); uniqAddresses[ii] = 1; // object or string } } - for (var addr in uniqAddresses) { - if (geoCache[addr]) { - gOpts.geocodedAddrCallback(geoCache[addr]); - continue; - } - geoCache[addr] = new addrObject(addr); - numUniqAddresses++; + for (var ii in addresses) { + ret.push(ii); } - gGeocodeQueue(); + return ret; } - function allResolved() { - for (var addr in geoCache) { - if (!geoCache[addr].resolved) return false; + // GeocodeManager.addr2coords(addresses, cb1, cbAll) - resolve a list of addresses + // addresses - object - key is address string, where each address string will map to a address object. + // cb1 - callback function - called when an address is resolved + // cbAll - callback function - called when all addresses are resolved. cb1 is not called after this. + + GeocodeManager.addr2coords = function(addresses, cb1, cbAll) { + var uniqAddresses = deDup(addresses); + // store request + resolveRequests.push({ + state: 'new', + addressesNew: uniqAddresses, + addressesResolved: [], + cb1 : cb1, + cbAll : cbAll + }); + + for (var ii = 0; ii < uniqAddresses.length; ii++) { + if (!geoCache[uniqAddresses[ii]]) { + geoCache[uniqAddresses[ii]] = new addrObject(uniqAddresses[ii]); + } } - return true; + checkRequests(); + googleGeocodeQueue(); } - function getUnresolved() { - for (var addr in geoCache) { - ao = geoCache[addr]; - if (!ao.resolved && !ao.inProgress) return ao; - } - return false; - } - function checkInProgress(ems) { - for (var addr in geoCache) { - ao = geoCache[addr]; - if (ao.inProgress && (ems - ao.sentLast > 2000)) { - if (ao.sentTimes > 3) { - ao.resolved = true; - numUniqAddrErrors++; - debug.log('checkInProgress() forgetting request '+ao.reqNum, ao); - gOpts.geocodedAddrCallback(ao); + // compares resolveRequests against geoCache and does callbacks if addresses are resolved + // returns true if all request addresses are resolved, false if still need resolution. + function checkRequests() { + var curReq, + allResolved = true, + addrNotResolved, + addr; + + for (var ii = 0; ii < resolveRequests.length; ii++) { + curReq = resolveRequests[ii], + addrNotResolved = []; + + if (curReq.state === 'allResolved') { + continue; + } + allResolved = false; + for (var jj = 0; jj < curReq.addressesNew.length; jj++) { + addr = curReq.addressesNew[jj]; + + if (geoCache[addr].resolved) { + curReq.addressesResolved.push(addr); + if (typeof curReq.cb1 === 'function') { + curReq.cb1(geoCache[addr]); + } } else { - ao.inProgress = false; - debug.log('checkInProgress() resetting request '+ao.reqNum+' after '+(ems-ao.sentLast)+'ms', ao); + addrNotResolved.push(addr); + } + } + curReq.addressesNew = addrNotResolved; + if (curReq.addressesNew.length === 0) { + debug.log("checkRequests() resolveRequests done"); + curReq.state = 'allResolved'; + if (typeof curReq.cbAll === 'function') { + curReq.cbAll(); } } } - return false; + return allResolved; } - // gGeocodeQueue() + + // googleGeocodeQueue() // // Note: Google allows 15k lookups per day per IP. However, too many requests // at the same time triggers a 620 code from google. Therefore we want about 100ms - // delay between each request using gGeocodeQueue. Likewise, when we get a 620 code, + // delay between each request using googleGeocodeQueue. Likewise, when we get a 620 code, // we wait a bit and resubmit. // http://code.google.com/apis/maps/faq.html#geocoder_limit // // NOTE: yahoo allows 5k lookups per day per IP // http://developer.yahoo.com/maps/rest/V1/geocode.html // - var desiredRate = 100; // long-term average should be one query every 'desiredRate' ms - var maxBurstReq = 4; // if timeout gets delayed, say 500ms, we can send 'maxBurstReq' at a time till we catch up - var maxRetry = 4; - function gGeocodeQueue () { + function googleGeocodeQueue () { ems = new Date().getTime() - startTime; bursts = maxBurstReq; while (bursts-- && (ems > numReqs*desiredRate ) && (ao = getUnresolved())) { @@ -622,20 +717,45 @@ ao.inProgress = true; ao.sentLast = ems; ao.sentTimes++; - debug.log(" gGeocodeQueue() sending req "+numReqs+" at "+ems+"ms, addr: ", ao.addr1); - cnMF.gGeocode( ao.addr1, gOpts.googleApiKey, function (gObj) { + debug.log(" googleGeocodeQueue() sending req "+numReqs+" at "+ems+"ms, addr: ", ao.addr1); + googleGeocode( ao.addr1, function (gObj) { parseGObj(gObj); }); ems = new Date().getTime() - startTime; } checkInProgress(ems); - if (allResolved()) { - debug.log("gGeocodeQueue() all queries complete, geocoder done"); - gOpts.geocodeCompleteCallback(); - return; + if (checkRequests()) { + debug.log("googleGeocodeQueue() all queries complete, geocoder done"); + //gOpts.geocodeCompleteCallback(); + } else { + setTimeout(function() { googleGeocodeQueue() }, desiredRate); + } + } + function getUnresolved() { + for (var addr in geoCache) { + ao = geoCache[addr]; + if (!ao.resolved && !ao.inProgress) return ao; + } + return false; + } + + function checkInProgress(ems) { + for (var addr in geoCache) { + ao = geoCache[addr]; + if (ao.inProgress && (ems - ao.sentLast > 2000)) { + if (ao.sentTimes > 3) { + ao.resolved = true; + //numUniqAddrErrors++; + debug.log('checkInProgress() forgetting request '+ao.reqNum, ao); + //gOpts.geocodedAddrCallback(ao); + } else { + ao.inProgress = false; + debug.log('checkInProgress() resetting request '+ao.reqNum+' after '+(ems-ao.sentLast)+'ms', ao); + } + } } - setTimeout(function() { gGeocodeQueue() }, desiredRate); + return false; } function parseGObj(gObj) { @@ -661,8 +781,8 @@ geoCache[gObj.addr1].validCoords = false; geoCache[gObj.addr1].inProgress = false; geoCache[gObj.addr1].error = gObj.error; - numUniqAddrErrors++; - gOpts.geocodedAddrCallback(geoCache[gObj.addr1]); + //numUniqAddrErrors++; + //gOpts.geocodedAddrCallback(geoCache[gObj.addr1]); } else if (gObj.lt) { if (!gObj.addr1 || !geoCache[gObj.addr1]) { @@ -677,103 +797,89 @@ geoCache[gObj.addr1].inProgress = false; debug.log("parseGObj() got coords ", gObj.addr1, gObj, geoCache[gObj.addr1]); - numUniqAddrDecoded++; - gOpts.geocodedAddrCallback(geoCache[gObj.addr1]); + //numUniqAddrDecoded++; + //gOpts.geocodedAddrCallback(geoCache[gObj.addr1]); } else { debug.warn("parseGObj() should not be here ", gObj); } } - geoMgrInit(); + // description of gObj + // geocodeObj: { + // lg: null, // number, -180 +180 + // lt: null, // number, -90 +90 + // addr2: null, // string, google's rewording of addr1 + // addr1: null, // string, address passed to geocoder + // errorCode: null, // number + // tmpError: false, // boolean + // error: null // string error msg + // }, + // - return { - numAddresses: numAddresses, - numUniqAddresses: numUniqAddresses, - count: function() { - var c = { - uniqAddrDecoded: 0, - uniqAddrErrors: 0, - uniqAddrTotal: 0 - } - for (var addr in geoCache) { - ao = geoCache[addr]; - c.uniqAddrTotal++; - if (ao.resolved && ao.validCoords) c.uniqAddrDecoded++; - if (ao.resolved && !ao.validCoords) c.uniqAddrErrors++; - } - return c; - } + // googleGeocode() translates addresses into array of lat/lng coords using Google, also see googleGeocodeQueue() + // + function googleGeocode( addr, callback ) { + + //debug.log("gGeocode() submitting addr to google: " + addr); + //$("#"+ cnMFUI.opts.listId ).append('.'); + + // switched from getJson to ajax to handle errors. However, looks like error function is not called + // when google responds with http 400 and text/html (versus http 200 with text/javascript) + // + // http://groups.google.com/group/google-maps-api/browse_thread/thread/e347b370e8586767/ddf95bdb0fc6a9f7?lnk=raot + geoUrl = 'http://maps.google.com/maps/geo?' + + '&key='+ googleApiKey + + '&q='+ encodeURI(addr) + + '&sensor=false&output=json' + + '&callback=?'; + //geoUrl = 'http://maps.google.com/maps/geo?callback=?'; + $.ajax({ + type: "GET", + url: geoUrl, + dataType: "json", + //global: false, + error: function (XMLHttpRequest, textStatus, errorThrown) { + debug.log("gGeocode() error for "+ geoUrl); + }, + // complete is only called after success, not on error, therefore useless + //complete: function (XMLHttpRequest, textStatus) { + // debug.log("gGeocode() complete ", textStatus, XMLHttpRequest); + //}, + success: function(data, textStatus) { + //debug.log("gGeocode() success() status,data: ", textStatus, data); + //$("#"+ cnMFUI.opts.listId ).append('.'); + if (data.Placemark) { + callback( { + lg: data.Placemark[0].Point.coordinates[0], + lt: data.Placemark[0].Point.coordinates[1], + addr2: data.Placemark[0].address, + addr1: data.name + }); + } else { + callback( { + // http://code.google.com/apis/maps/documentation/geocoding/index.html#StatusCodes + addr1: data.name, + data: data, + errorCode: data.Status.code, + tmpError: (data.Status.code == 620) || (data.Status.code == 500) || (data.Status.code == 610), + error: (data.Status.code) ? + ((602==data.Status.code) ? "602: Unknown Address" : + ((620==data.Status.code) ? "620: Too Many Lookups" : "Google code: "+data.Status.code)) : + "Google geocode api changed" + }); + } + } + }); //close $.ajax } - } - // description of gObj - // geocodeObj: { - // lg: null, // number, -180 +180 - // lt: null, // number, -90 +90 - // addr2: null, // string, google's rewording of addr1 - // addr1: null, // string, address passed to geocoder - // errorCode: null, // number - // tmpError: false, // boolean - // error: null // string error msg - // }, - // + GeocodeManager.init(); - // gGeocode() translates addresses into array of lat/lng coords using Google, also see gGeocodeQueue() - // - cnMF.gGeocode = function( addr, googleApiKey, callback ) { + return GeocodeManager; - //debug.log("gGeocode() submitting addr to google: " + addr); - //$("#"+ cnMFUI.opts.listId ).append('.'); - - // switched from getJson to ajax to handle errors. However, looks like error function is not called - // when google responds with http 400 and text/html (versus http 200 with text/javascript) - // - // http://groups.google.com/group/google-maps-api/browse_thread/thread/e347b370e8586767/ddf95bdb0fc6a9f7?lnk=raot - geoUrl = 'http://maps.google.com/maps/geo?' - + '&key='+ googleApiKey - + '&q='+ encodeURI(addr) - + '&sensor=false&output=json' - + '&callback=?'; - //geoUrl = 'http://maps.google.com/maps/geo?callback=?'; - $.ajax({ - type: "GET", - url: geoUrl, - dataType: "json", - //global: false, - error: function (XMLHttpRequest, textStatus, errorThrown) { - debug.log("gGeocode() error for "+ geoUrl); - }, - // complete is only called after success, not on error, therefore useless - //complete: function (XMLHttpRequest, textStatus) { - // debug.log("gGeocode() complete ", textStatus, XMLHttpRequest); - //}, - success: function(data, textStatus) { - //debug.log("gGeocode() success() status,data: ", textStatus, data); - //$("#"+ cnMFUI.opts.listId ).append('.'); - if (data.Placemark) { - callback( { - lg: data.Placemark[0].Point.coordinates[0], - lt: data.Placemark[0].Point.coordinates[1], - addr2: data.Placemark[0].address, - addr1: data.name - }); - } else { - callback( { - // http://code.google.com/apis/maps/documentation/geocoding/index.html#StatusCodes - addr1: data.name, - data: data, - errorCode: data.Status.code, - tmpError: (data.Status.code == 620) || (data.Status.code == 500) || (data.Status.code == 610), - error: (data.Status.code) ? - ((602==data.Status.code) ? "602: Unknown Address" : - ((620==data.Status.code) ? "620: Too Many Lookups" : "Google code: "+data.Status.code)) : - "Google geocode api changed" - }); - } - } - }); //close $.ajax } + + // END GEOCODE diff --git a/examples/gcm/js/cnMapFilterUI.js b/examples/gcm/js/cnMapFilterUI.js index 119efd8..c5e3c0f 100644 --- a/examples/gcm/js/cnMapFilterUI.js +++ b/examples/gcm/js/cnMapFilterUI.js @@ -52,6 +52,7 @@ var mapClickListener = false, mapDragstartListener = false, lastUpdate4MapLoad = false, + moreThanOneCal = false, emptyTableHtml = "nopeno matchuh-uhnowhere"; /* @@ -61,17 +62,16 @@ urlIconDefault = "http://www.google.com/mapfiles/marker.png", urlIconOrange = "http://gmaps-samples.googlecode.com/svn/trunk/markers/orange/blank.png", urlIconBlue = "http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/blank.png", - mapVersion = "Map Version 2011-3-12"; - - // end variables + mapVersion = "Map Version 2012-4-8"; cnMF.reportData.loadTime = (startMs2 +'').replace(/(\d{3})$/,".$1") // add period so its secs.msec cnMF.reportData.userInteracted = false; - function init() { + function init() { - debug.log('mapfilter().init(), cnMF:',cnMF); var timezone = jstz.determine_timezone(); // https://bitbucket.org/pellepim/jstimezonedetect/wiki/Home + var calendarURLs = getCalendarURLs(); + debug.log('mapfilter().init(), cnMF:',cnMF); initDivs(); myGmap = initGMap(); //updateSizes(); @@ -99,23 +99,27 @@ // check for data sources and add them // - if (cnMFUI.opts.gCalUrl && cnMFUI.opts.gCalUrl != 'u') { + if (calendarURLs.length) { $('#calendarTitleContent').html("

Loading Calendar..

"); - updateStatus('Map Loaded, Loading Calendar ..'); + updateStatus('Map Loaded, Loading '+ calendarURLs.length +' Calendar(s) ..'); //$('#calendarDiv').html(''); initResults(); - // TODO: create a cnMF.showDates(start,end) which gets from google calendar if required - if (cnMFUI.opts.gCalUrl == 'test1') { - fakeGCalData(); - } else if (cnMFUI.opts.gCalUrl == 'test2') { - getXmlData(); - } else { - _gaq.push(['_trackEvent', 'Loading', 'calender-u', cnMFUI.opts.gCalUrl]); - cnMF.getGCalData(cnMFUI.opts.gCalUrl, cnMF.origStartDay, cnMF.origEndDay, { - onCalendarLoad: cbCalendarLoad, - onGeoDecodeAddr: cbGeoDecodeAddr, - onGeoDecodeComplete: cbGeoDecodeComplete - }); + for (var ii = 0; ii < calendarURLs.length; ii++) { + var gCalURL = calendarURLs[ii]; + // TODO: create a cnMF.showDates(start,end) which gets from google calendar if required + if (gCalURL == 'test1') { + fakeGCalData(); + } else if (gCalURL == 'test2') { + getXmlData(); + } else { + _gaq.push(['_trackEvent', 'Loading', 'calender-u', gCalURL]); + cnMF.getGCalData(gCalURL, cnMF.origStartDay, cnMF.origEndDay, { + onCalendarLoad: cbCalendarLoad, + onGeoDecodeAddr: cbGeoDecodeAddr, + onGeoDecodeComplete: cbGeoDecodeComplete + }); + } + } } else { updateStatus('Map Loaded.'); @@ -134,8 +138,37 @@ debug.log("mapFilter().init() Completed."); } - - function initDivs() { + function getCalendarURLs() { + var calendarURLs = []; + + if (cnMFUI.opts.gCalURLs) { + if (Object.prototype.toString.call(cnMFUI.opts.gCalURLs) != '[object Array]') { + console.error("gCalURLs must be an array, not "+ typeof cnMFUI.opts.gCalURLs, cnMFUI.opts.gCalURLs); + return []; + } + for (var ii = 0; ii < cnMFUI.opts.gCalURLs.length; ii++) { + calendarURLs.push(cnMFUI.opts.gCalURLs[ii]); + } + } + if (cnMFUI.opts.gCalGroups) { // gcg=xxx,yyy + $.each(cnMFUI.opts.gCalGroups.split(','), function(index, value) { + calendarURLs.push("https://www.google.com/calendar/feeds/"+ value + "%40group.calendar.google.com/public/basic"); + }); + } + if (cnMFUI.opts.gCalImports) { // gci=xxx,yyy + $.each(cnMFUI.opts.gCalImports.split(','), function(index, value) { + calendarURLs.push("https://www.google.com/calendar/feeds/"+ value + "%40import.calendar.google.com/public/basic"); + }); + } + if (cnMFUI.opts.gCalEmails) { // gc=xxx@groups.calendar.google.com,yyy@my.domain.com + $.each(cnMFUI.opts.gCalEmails.split(','), function(index, value) { + calendarURLs.push("https://www.google.com/calendar/feeds/"+ value + "/public/basic"); + }); + } + moreThanOneCal = calendarURLs.length > 1; + return calendarURLs; + } + function initDivs() { // this html does not belong in javascript, but keeping here to aid in prototype development $('#'+cnMFUI.opts.containerId).html( @@ -716,6 +749,7 @@ //infoHTML = "

"+ kk['n'] +"<\/h1>
"+ desc +"
"+footer+"

"; kk.infoHtml = "

"+ kk.name +"<\/h1>"; + kk.infoHtml += moreThanOneCal ? '

Calendar: '+kk.calTitle+'

' : ''; kk.infoHtml += "
"+ cnMFUI.maxStr( addLinks(kk.desc), 900, 26, kk.url) +"
"; kk.infoHtml += '
'; kk.infoHtml += cnMF.formatDate(kk.dateStart, 'F D, l gx') +"-"+ cnMF.formatDate(kk.dateEnd, 'gx') +"
"; @@ -857,49 +891,91 @@ }); } - function cbCalendarLoad() { + /* + calendarInfo.gCalUrl = gCalUrl; + calendarInfo.totalEntries = ii; + calendarInfo.totalEvents = cdata.feed.openSearch$totalResults.$t || ii; + calendarInfo.gcTitle = cdata.feed.title ? cdata.feed.title['$t'] : 'title unknown'; + calendarInfo.gcLink = cdata.feed.link ? cdata.feed.link[0]['href'] : ''; + calendarInfo.desc = cdata.feed.subtitle ? cdata.feed.subtitle['$t'] : 'subtitle unknown'; + */ - document.title = document.title +" - "+ cnMF.gcTitle; + function cbCalendarLoad(calendarInfo) { + var html, + titles = [], + totalEvents = 0; + + cnMF.calData = cnMF.calData || {}; + cnMF.calData[calendarInfo.gCalUrl] = calendarInfo; - updateStatus("" - + cnMF.gcTitle +"
Mapping Events ... "); - $('#calendarTitleContent').html("

"+ cnMF.gcTitle +"

"); - - html = 'Calendar has '+ cnMF.totalEvents + (cnMF.totalEvents==cnMF.totalEntries ? '' - :' ('+cnMF.totalEntries+')') - +' events from '+ cnMF.formatDate(startDate, 'Y-n-D') +'' - +' to '+ cnMF.formatDate(endDate, 'Y-n-D') +'' - +'   Change dates' - + '
'; - $('#calendarTitleContent').append(html); - _gaq.push(['_trackEvent', 'Loading', 'calenders', 'cnMF.totalEvents', cnMF.totalEvents]); - _gaq.push(['_trackEvent', 'Loading', 'calender-cnMF.gcLink', cnMF.gcLink]); - - $('#changeDates').click(function(){ - _gaq.push(['_trackEvent', 'Interaction', 'changeDates']); - setupChangeDates(); + $.each(cnMF.calData, function(gCalUrl, calendarInfo) { + totalEvents += calendarInfo.totalEvents; + titles.push(calendarInfo.gcTitle); }); + + // check to see if we are processing more than one calendar or not. + if (cnMF.validCalendars) { + cnMF.validCalendars++; + document.title = "GCM "+ cnMF.validCalendars + " valid calendars"; + + updateStatus("" + + calendarInfo.gcTitle +"
Mapping Events ... "); + + $('#calendarTitleContent').html('

Showing '+ cnMF.validCalendars +' Valid Calendars

' + +' '+ cnMF.validCalendars +' Calendars have '+ totalEvents + +' events from '+ cnMF.formatDate(startDate, 'Y-n-D') +'' + +' to '+ cnMF.formatDate(endDate, 'Y-n-D') +'' + +'   Change dates' + + '
'); + } else { + cnMF.validCalendars = 1; + document.title = "GCM - "+ calendarInfo.gcTitle; + + updateStatus("" + + calendarInfo.gcTitle +"
Mapping Events ... "); + + $('#calendarTitleContent').html("

"+ calendarInfo.gcTitle +"

" + + 'Calendar has '+ calendarInfo.totalEvents + (calendarInfo.totalEvents==calendarInfo.totalEntries ? '' + :' ('+calendarInfo.totalEntries+')') + +' events from '+ cnMF.formatDate(startDate, 'Y-n-D') +'' + +' to '+ cnMF.formatDate(endDate, 'Y-n-D') +'' + +'   Change dates' + + '
'); + + $('#changeDates').click(function(){ + _gaq.push(['_trackEvent', 'Interaction', 'changeDates']); + setupChangeDates(); + }); - $('#cancelChangeDates').click(function(){ - _gaq.push(['_trackEvent', 'Interaction', 'cancelChangeDates']); - $("#newDates").css('display','none'); - }); - $('#thDate').attr('title','Click to Sort by Event Date, Timezone '+cnMF.tz.name); + $('#cancelChangeDates').click(function(){ + _gaq.push(['_trackEvent', 'Interaction', 'cancelChangeDates']); + $("#newDates").css('display','none'); + }); + $('#thDate').attr('title','Click to Sort by Event Date, Timezone '+cnMF.tz.name); - //updateStatus2('Found '+ cnMF.totalEvents +' ('+cnMF.totalEntries+') events, '+ uniqAddrCount +' unique addresses, decoding .. '); - updateStatus2('Found '+ cnMF.myGeo.numAddresses +' events, '+ cnMF.myGeo.numUniqAddresses +' unique addresses, decoding .. '); + } + + _gaq.push(['_trackEvent', 'Loading', 'calenders', 'calendarInfo.totalEvents', calendarInfo.totalEvents]); + _gaq.push(['_trackEvent', 'Loading', 'calender-calendarInfo.gcLink', calendarInfo.gcLink]); + + //updateStatus2('Found '+ calendarInfo.totalEvents +' ('+calendarInfo.totalEntries+') events, '+ uniqAddrCount +' unique addresses, decoding .. '); + cnt = cnMF.myGeo.count(); + + updateStatus2('Found '+ cnMF.myGeo.numAddresses +' events, '+ cnt.uniqAddrTotal +' unique addresses, decoding .. '); } - // cbGeoDecodeComplete() called everytime we get a response from the internet + // cbGeoDecodeAddr() called everytime we get a response from the internet function cbGeoDecodeAddr () { cnt = cnMF.myGeo.count(); updateStatus2(cnt.uniqAddrDecoded +' of '+ cnt.uniqAddrTotal +' decoded
' + cnt.uniqAddrErrors +' errors' ); - cnMF.reportData['uniqAddrDecoded'] = cnt.uniqAddrDecoded; - cnMF.reportData['uniqAddrTotal'] = cnt.uniqAddrTotal; - cnMF.reportData['uniqAddrErrors'] = cnt.uniqAddrErrors; + cnMF.reportData.uniqAddrDecoded = cnt.uniqAddrDecoded; + cnMF.reportData.uniqAddrTotal = cnt.uniqAddrTotal; + cnMF.reportData.uniqAddrErrors = cnt.uniqAddrErrors; // if user has NOT interacted with map, // AND its been over 3000 ms since last updated map with results from @@ -939,7 +1015,7 @@ mapRedraw(); } } - // cbGeoDecodeComplete() called once all addresses are decoded + // cbGeoDecodeComplete() called once all addresses are decoded for a given calendar function cbGeoDecodeComplete() { debug.log("cbGeoDecodeComplete() begins"); //if (cnMFUI.opts.mapCenterLt == cnMFUI.defaults.mapCenterLt) From 4d43c1af018f2e233711ac755b5dbbf23934bdc4 Mon Sep 17 00:00:00 2001 From: Chad Norwood Date: Sun, 8 Apr 2012 19:41:43 -0500 Subject: [PATCH 03/50] added +/- rightTab --- examples/gcm/css/mapFilter.css | 28 ++++++++++++++++++++++++++-- examples/gcm/index.html | 4 ++-- examples/gcm/js/cnMapFilter.js | 2 +- examples/gcm/js/cnMapFilterUI.js | 29 ++++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/examples/gcm/css/mapFilter.css b/examples/gcm/css/mapFilter.css index 458751c..ac107b5 100644 --- a/examples/gcm/css/mapFilter.css +++ b/examples/gcm/css/mapFilter.css @@ -110,8 +110,17 @@ body {text-align:left;} .ui-state-active { background: white; } .containerWrap {position:absolute; width: 99%; height: 98%; background: #99B3CC; } #gcmDiv { position:relative; width: 100%; height: 100%; background: white; } - #MapID { width:67%; height:99%; float:left; background:blue;} - #rtSide { width:32%; height:99%; float:right; } + #MapID { + width:67%; + height:99%; + float:left; + background:blue; + } + #rtSide { + width:32%; + height:99%; + float:right; + } #tab-header { margin: 5px; font-size:200%; } #MapStats { font-size:70%; } #tab-container { margin: 1px; } @@ -397,6 +406,21 @@ div.scrollContent { * orange-brown buidling: #DED2AC */ + +#rightTab { + position:absolute; + top:70px; + right:0; + display:block; + height:30px; + width:30px; + cursor:pointer; + z-index:10; + background-color: #FFF; + font-size:24px; + font-weight:bold; + padding-left:6px; +} /* end of file */ diff --git a/examples/gcm/index.html b/examples/gcm/index.html index 35ca275..7df25a4 100644 --- a/examples/gcm/index.html +++ b/examples/gcm/index.html @@ -257,9 +257,9 @@

Example Calendars:

  1. Chad's Chicago: Summer Festivals and More
  2. A New York Track Club
  3. -
  4. 2011 Trail Races
  5. -
  6. Collections (Bikes For The World)
  7. Sunset District Events Calendar (San Francisco)
  8. +
  9. Collections (Bikes For The World)
  10. +
  11. Trail Races
  12. All 5 calendars above at once! <--- NEW !!!
  13. Aikido
  14. Test
  15. diff --git a/examples/gcm/js/cnMapFilter.js b/examples/gcm/js/cnMapFilter.js index 3db1d83..93e33fa 100644 --- a/examples/gcm/js/cnMapFilter.js +++ b/examples/gcm/js/cnMapFilter.js @@ -5,7 +5,7 @@ // only showing items that have coordinates/address on map's currently displayed canvas. // // -// Copyright (c) 2011 Chad Norwood +// Copyright (c) 2009-2012 Chad Norwood // Dual licensed under the MIT and GPL licenses: // http://www.opensource.org/licenses/mit-license.php // http://www.gnu.org/licenses/gpl.html diff --git a/examples/gcm/js/cnMapFilterUI.js b/examples/gcm/js/cnMapFilterUI.js index c5e3c0f..36dbf4d 100644 --- a/examples/gcm/js/cnMapFilterUI.js +++ b/examples/gcm/js/cnMapFilterUI.js @@ -13,7 +13,7 @@ * for experimenting with coding methods. I apologize. * It will be cleaned up in stages. * - * Copyright (c) 2011 Chad Norwood + * Copyright (c) 2009-2012 Chad Norwood * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html @@ -247,6 +247,7 @@ }); mapLogo(myGmap); mapJumpBox(myGmap); + mapRightTab(cnMFUI.opts.mapId); iconDefault = new GIcon(G_DEFAULT_ICON, urlIconDefault); return myGmap; } @@ -720,8 +721,30 @@ oMap.getContainer().appendChild(info); } - - function mapLogo(oMap) { + + function mapRightTab(mapId) { + $('#'+mapId).append("
    -
    "); + $('#rightTab').click(function(){ + console.log("mapRightTab() rtSide').width: ",$('#rtSide').width()); + if ($('#rtSide').width() < 1) { + $('#rightTab').html('-'); + $('#MapID').css('width','67%'); + $('#rtSide').animate({ + width : '32%' + }, 400 , 'linear'); + } else { + $('#rightTab').html('+'); + $('#rtSide').animate({ + width : 0 + }, 400, 'linear', function(){ + $('#MapID').css('width','100%'); + }); + + } + }); + } + + function mapLogo(oMap) { /* Insert Logo on Map */ var info=document.createElement('div'); info.id='LogoInfo'; From 244fd447e6dfbb7041445f34b0cf0efce1c49204 Mon Sep 17 00:00:00 2001 From: Chad Norwood Date: Wed, 18 Apr 2012 07:41:12 -0500 Subject: [PATCH 04/50] fixed date parsing, allowing YYYY-MM-DD --- examples/gcm/index.html | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/examples/gcm/index.html b/examples/gcm/index.html index 7df25a4..659b6e8 100644 --- a/examples/gcm/index.html +++ b/examples/gcm/index.html @@ -108,7 +108,7 @@ return results[1]; } - function validateDate(httpParamName, def) { + function validateDate_DELME(httpParamName, def) { var offset = httpGetParam(httpParamName); offset = parseInt(offset); if (isNaN(offset)) { @@ -173,12 +173,6 @@ var lt = validateFloat('lat',-180,180, 41.885405); - // find events initially in this range - var sday = validateDate('sd',0); // start today (0 days from now) - var eday = validateDate('ed',42); // end in 6 weeks - - console.log ("sday=" + sday + " eday=" + eday); - var map_size=validateSize('size',200,2000,200,2000, [800,600]); //var xmlurl = validateURL('u'); var xmlurl = httpGetParam('u'); @@ -220,8 +214,8 @@ gCalGroups: myURL.params.gcg, gCalImports: myURL.params.gci, gCalEmails: myURL.params.gc, - startDay: sday, - endDay: eday, + startDay: httpGetParam('sd') || 0, + endDay: httpGetParam('ed') || 42, googleApiKey: "ABQIAAAAQ8l06ldZX6JSGI8gETtVhhTrRIj9DJoJiLGtM4J1SrTlGmVDcxQDT5BVw88R8j75IQxYlwFcEw6w9w", mapChangeCallback: function (curData) { From 2d17cac065cf1d10a0caa4ffd6a166fac9fe82a3 Mon Sep 17 00:00:00 2001 From: Chad Norwood Date: Wed, 18 Apr 2012 07:41:45 -0500 Subject: [PATCH 05/50] Upgrade to jquery 1.7, google maps api V3 for geocoder --- examples/gcm/index.html | 7 +- examples/gcm/js/cnMapFilter.js | 131 +++++++++++++------------------ examples/gcm/js/cnMapFilterUI.js | 15 ++-- 3 files changed, 70 insertions(+), 83 deletions(-) diff --git a/examples/gcm/index.html b/examples/gcm/index.html index 659b6e8..713ef61 100644 --- a/examples/gcm/index.html +++ b/examples/gcm/index.html @@ -11,9 +11,12 @@ + + - + @@ -24,9 +27,9 @@ + - - - - - - - - - - - - - - - - - + Google Calendar Map + + + + + + + + + + + + + + + + - + + + + + + + + + + + + - // default to Chicago - var ll = validateFloat('lng',-180,180, -87.626072); - var lt = validateFloat('lat',-180,180, 41.885405); + +
    - - var map_size=validateSize('size',200,2000,200,2000, [800,600]); - //var xmlurl = validateURL('u'); - var xmlurl = httpGetParam('u'); - - - - function genLink(curData) { - clink = window.location.pathname +'?z='+ curData.mapZoom; - clink += '&lat='+ curData.mapCenterLt; - clink += '&lng='+ curData.mapCenterLg; - clink += '&m='+ curData.mapType; - clink += '&sd='+ curData.startDay; - clink += '&ed='+ curData.endDay; - $.each(['u','gc','gcg','gci'], function(index, param) { - clink += '&' + param + '=' + myURL.params[param]; - }); - //clink += "&u=" + xmlurl; - // clink += "&u" + (typeof myURL.params.u == 'string' ? [myURL.params.u] : myURL.params.u) - return clink; - } - - - // - // init mapFilter via UI wrapper - // - cnMFUI.init({ - // For more info on options, see 'defaults' - containerId: "containerId", - mapId: "MapID", - listId: "tableTab", - statusId: "MapStatus", - mapCenterLt: lt, - mapCenterLg: ll, - mapZoom: gZoomLevel, - mapType: maptype, - mapAllOnInit: mapAllOnInit, - - gCalURLs: typeof myURL.params.u == 'string' ? [myURL.params.u] : myURL.params.u, - gCalGroups: myURL.params.gcg, - gCalImports: myURL.params.gci, - gCalEmails: myURL.params.gc, - startDay: httpGetParam('sd') || 0, - endDay: httpGetParam('ed') || 42, - googleApiKey: "ABQIAAAAQ8l06ldZX6JSGI8gETtVhhTrRIj9DJoJiLGtM4J1SrTlGmVDcxQDT5BVw88R8j75IQxYlwFcEw6w9w", - - mapChangeCallback: function (curData) { - msg = "Map Link"; - $("#MapStatus").append(msg); - } - }); - }); // end document ready - - //]]> - - - - - -
    -
    - -