// config related var LOADMAP = true; var makeLocation = function(x) { return "http://charlestonbb.placeaware.com/"+x; }; var makeAJAXLocation = function(x) { return makeLocation('ajax/'+x); }; var makeImageLocation = function(x) { return makeLocation('images/charlestonbb/'+x); }; var makeMarkerImageLocation = function(x) { return makeImageLocation('markers/'+x); }; var remoteCall = partial(callRemote, makeAJAXLocation('remoteCall.php')); // environment setup var BUTTER = new ButterLib(); Butterlate.setTextDomain("messages", makeLocation("langs")); var B = createDOMFunc("B"); // global variables var MAP = null; var USER_EMAIL = "unknown"; var STARTING_POINT = null; var PLACE_TYPES = new Array(); //var PLACES = new Array(); var PLACE_MARKERS = new Array(); var TRIP_LIST = new TripList(); var MAP_LIST = new MapList(); var MINI_MSG_SHOWING = false; var TRIP_LINE = null; var TRIP_POINTS = new Array(); // objects function PlaceType(id,name) { this.id = id; this.name = name; this.places = new Array(); this.addPlace = function(x) { this.places.push(x); }; this.hasVisibleMarkers = function() { return (PLACE_MARKERS.get(this.id).length > 0); }; this.hideMarkers = function() { var id = this.id; PLACE_MARKERS = PLACE_MARKERS.getWithFunction(function(type_id) { return (type_id!=id); }); redrawMarkers(); }; this.refreshMarkerList = function() { var request = doSimpleXMLHttpRequest(makeAJAXLocation('places.php'), {'type_id': this.id}); request.addCallback(setupPlaceMenu, this.id); request.addCallback(this._showMarkers, this.id); }; this.showMarkers = function() { if(this.places.length==0) this.refreshMarkerList(); else this._showMarkers(this.id, null); }; this._showMarkers = function(id, request) { PLACE_MARKERS.push(id); redrawMarkers(); }; } function Map(name) { this.name = name; this.id = BUTTER.getID(); this.toXml = function() { return ""; }; this.toJSON = function() { return "{'name': \""+JSONEscape(this.name)+"\"}"; }; } function MapList() { this.current = null; this.maps = new Array(); this.setCurrent = function(name) { this.current = name; this._addMap(name); this.refresh(); }; this.addMap = function() { var number = this.maps.length + 1; var name = prompt("Enter a name for your new map:", "Day "+number); if(name) { name = name.maxLength(10); if(this.maps.getWithFunction(function (m) {return m.name==name;}).length > 0) { alert("\""+name+"\" has already been used."); MAP_LIST.addMap(); } else { this._addMap(name); this.current = name; this.refresh(); TRIP_LIST.loadTrip(this.current); } }; }; this._addMap = function(name) { if(this.maps.getWithFunction(function(map) { return map.name==name; }).length == 0) { this.maps.push(new Map(name)); } }; this.changeName = function() { var number = this.maps.length + 1; var name = prompt("Enter a new name for the map \""+unescapeHTML(this.current)+"\":", "Day "+number); if(name) { name = name.maxLength(10); if(this.maps.getWithFunction(function (m) {return m.name==name;}).length > 0) { alert("\""+name+"\" has already been used."); MAP_LIST.changeName(); } else { doSimpleXMLHttpRequest(makeAJAXLocation('trip.php'), {'action': 'delete', 'name': MAP_LIST.current}); var index = this.maps.getIndexWithFunction(function (x) { return x.name==MAP_LIST.current; }); this.maps[index].name = name; this.current = name; MAP_LIST.refresh(); TRIP_LIST.save(); } }; }; this.deleteCurrentMap = function() { if (confirm("All trips in the \""+unescapeHTML(this.current)+"\" itenerary will be deleted. Are you sure?")) { doSimpleXMLHttpRequest(makeAJAXLocation('trip.php'), {'action': 'delete', 'name': this.current}); this.maps = this.maps.getWithFunction(function (x) { return x.name!=MAP_LIST.current }); this.current = this.maps[0].name; this.refresh(); TRIP_LIST.loadTrip(this.current); } }; this.loadList = function() { var handleList = function(request) { if(request.responseText=="") { MAP_LIST.setCurrent("Day 1"); return; } MAP_LIST.maps = new Array(); var makeMap = function (x) { return new Map(unescapeHTML(x.name)); }; var maps = forEachJSONElement(request, makeMap); forEach(maps, function(map) { MAP_LIST.maps.push(map); }); MAP_LIST.current = MAP_LIST.maps[0].name; MAP_LIST.refresh(); TRIP_LIST.loadTrip(MAP_LIST.current); }; var request = doSimpleXMLHttpRequest(makeAJAXLocation('map_list.php')); request.addCallback(handleList); }; this.refresh = function() { if(this.maps.length ==1) addElementClass($("delete_current_map"), "hidden_block"); else removeElementClass($("delete_current_map"), "hidden_block"); var maplist = new Array(); forEach(this.maps, function (map) { var elem_class = (map.name==MAP_LIST.current) ? "selected_map" : "unselected_map"; maplist.push(toHTML(SPAN({'class': elem_class, 'id': map.id}, SPAN({'class': "tab"}, map.name)))); }); $("map_list").innerHTML = "".join(maplist); var tmp_maplist = new Array(); forEach(this.maps, function (map) { onMouseOverClass(map.id, "map_name_hover"); connect(map.id, 'onclick', function() { MAP_LIST.setCurrent(map.name); TRIP_LIST.loadTrip(map.name); }); tmp_maplist.push(map.toJSON()); }); var xml = "(["+','.join(tmp_maplist)+"])"; doSimpleXMLHttpRequest(makeAJAXLocation('map_list.php'), {'map_list': xml}); }; } function TripList() { this.places = new Array(); this.hasPlace = function(id) { var existing = this.places.getWithFunction( function(x) { return x.id==id; }); return (existing.length > 0); }; this.addStartPoint = function(pladdy) { // accepts place or addy if(TRIP_LIST.places.length > 0 && TRIP_LIST.places[0].id==pladdy.id) return; //this.places = this.places.frontPush(pladdy); var narray = new Array(); narray.push(pladdy); this.places.each(function (i) { narray.push(i); }); this.places = narray; }; this.addPlace = function (place) { //if(this.hasPlace(place.id)) { alert(_("Place already exists in trip.")); return; } this.places.push(place); this.refresh(); }; this.addAddy = function(addy) { //if(this.hasPlace(addy.id)) { alert(_("Place already exists in trip.")); return; } this.places.push(addy); this.refresh(); }; this.move_up = function(index) { //var index = this.places.getIndexWithFunction( function(x) {return x.id==place_id;} ); if(index > 0) { this.places.swap(index, index-1); this.refresh(); } }; this.move_down = function(index) { //var index = this.places.getIndexWithFunction( function(x) {return x.id==place_id;} ); if(index < (this.places.length-1)) { this.places.swap(index, index+1); this.refresh(); } }; this.remove = function(index) { var id = this.places[index].id+'.'+index; dropOut('trip_place.'+id, {afterFinish: function () { TRIP_LIST._remove(index); }}); }; this._remove = function(index) { //this.places = this.places.getWithFunction(function(x) {return x.id!=place_id;}); this.places = this.places.getByIndexFunction(function(x) {return x!=index;}); this.refresh(); }; this.hasPoint = function(point) { return this.places.getWithFunction(function (p) { return p.point.equals(point); }).length > 0; }; this.refresh = function() { var d = document.createElement('div'); if(TRIP_LIST.places.length < 1) { var menu = DIV({'class': 'trip_place_menu'},H1({'id': 'empty'},"You have no trips in today's itinerary.")); var html = DIV({'class': 'trip_place_info'}, menu, DIV({'class': 'trip_empty'}, H1({}, "Click on the Places menu on the left to start adding trips."))); d.appendChild(html); } else { var html = this.places.cmap(function(x, index) { return makeTripHTML(x, index, TRIP_LIST.places.length); }); html.each(function(o) { d.appendChild(o); }); } swapDOM($("trip").firstChild, d); var points = new Array(); cforEach(this.places, function(info, index) { var id = info.id+'.'+index; var remove_link = 'trip_remove.'+id; onMouseOverClass(remove_link, "span_link_hover"); connect(remove_link, 'onclick', function() { TRIP_LIST.remove(index); }); // must do this so IE doesn't feck up if(index!=0) { var mup_link = 'trip_mup.'+id; onMouseOverClass(mup_link, "span_link_hover"); connect(mup_link, 'onclick', function() { TRIP_LIST.move_up(index); }); } // must do this so IE doesn't feck up if(index!=(TRIP_LIST.places.length-1)) { var mdown_link = 'trip_mdown.'+id; onMouseOverClass(mdown_link, "span_link_hover"); connect(mdown_link, 'onclick', function() { TRIP_LIST.move_down(index); }); } var notes_link = 'notes_visible.'+id; onMouseOverClass(notes_link, "span_link_hover"); var edit_link = SPAN({'id': 'edit_link_'+id, 'class': 'button'}, "Edit Notes"); var save_link = SPAN({'id': 'save_link_'+id, 'class': 'button'}, "Save Notes"); $(notes_link).appendChild(edit_link); connect(edit_link, 'onclick', function() { swapDOM($(edit_link), $(save_link)); var notes = toggleDivText('notes.'+id, 10, 100); // only save if user finished editing if(notes != info.notes) { info.notes = notes; TRIP_LIST.save(); } }); connect(save_link, 'onclick', function() { swapDOM($(save_link), $(edit_link)); var notes = toggleDivText('notes.'+id, 10, 100); // only save if user finished editing if(notes != info.notes) { info.notes = notes; TRIP_LIST.save(); } }); points.push(new GLatLng(info.point.lat, info.point.lon)); }); this.save(); if(this.places.length > 1) { TRIP_POINTS = new Array(); TRIP_LIST.getDirections(0); // don't need to call redrawMarkers here because it will be called as we get directions } else { TRIP_LINE = null; redrawMarkers(); } }; this.save = function() { trip_json_array = new Array(); forEach(this.places, function(info) { var json = info.toJSON(); trip_json_array.push(json); }); var trip_xml = "({'map_name': \""+escapeHTML(MAP_LIST.current)+"\", 'places': [" + ','.join(trip_json_array) + "]})"; doSimpleXMLHttpRequest(makeAJAXLocation('trip.php'), {'trip': trip_xml, 'name': MAP_LIST.current}); }; this.loadTrip = function(trip_name) { var handleTrip = function(request) { TRIP_LIST.places = new Array(); if(request.responseText != "") { var makePlace = function (x) { if(x.type == "place") { x.point = new BPoint(x.lat, x.lon); x.toXml = function() { return ""; }; x.toJSON = function () { return "{'type': \"place\",'id': \""+this.id+"\",'notes': \""+JSONEscape(this.notes)+"\"}"; }; // resecape the notes in case they aren't changed, they will be posted as escaped HTML // x.notes = escapeHTML(x.notes); } else { notes = x.notes; x = new Addy(x.addy, new BPoint(x.lat, x.lon)); // resecape the notes in case they aren't changed, they will be posted as escaped HTML x.notes = notes; //escapeHTML(notes); } return x; }; //alert(request.responseText); var root = eval(request.responseText); MAP_LIST.setCurrent(unescapeHTML(root.map_name)); var places = map(makePlace, root.places); forEach(places, function(place) { TRIP_LIST.places.push(place); }); if(STARTING_POINT) TRIP_LIST.addStartPoint(STARTING_POINT); } else if(STARTING_POINT) TRIP_LIST.addStartPoint(STARTING_POINT); TRIP_LIST.refresh(); }; // seems weird - but the xml we sent eariler w/ the trip had been escaped this way, so we must escape // when we request by name as well // trip_name = HTMLToXML(escapeHTML(trip_name)); var request = doSimpleXMLHttpRequest(makeAJAXLocation('trip.php'), {'name': trip_name}); request.addCallback(handleTrip); }; this.setDirectionText = function(index, text) { $("directions."+index).innerHTML = text; }; this.getDirections = function(index) { if((index+1) >= this.places.length) return; var fr_place = this.places[index]; var fr_type = fr_place.type; var fr = (fr_type=="addy") ? fr_place.addy : fr_place.id; var fraddy = (fr_type == "addy") ? fr_place.addy : fr_place.address; var to_place = this.places[index+1]; var to_type = to_place.type; var to = (to_type=="addy") ? to_place.addy : to_place.id; var toaddy = (to_type == "addy") ? to_place.addy : to_place.address; var handleSearchResults = function (request) { if(request.responseText == "NOT_FOUND") { var d = new GDirections(FAKEMAP); d.load("from: " + fraddy + " to: " + toaddy, {getSteps: true}); GEvent.addListener(d, "load", function() { if(d.getNumRoutes() == 0) { showBriefMiniMessage("Directions from place "+(index+1)+" could not be found"); TRIP_LIST.setDirectionText(index, "Directions not found."); } else { var xml = ''; var route = d.getRoute(0); for(var i=0; i"; } xml += ""; var poly = d.getPolyline(); for(var i=0; i"; } xml += ""; var params = queryString({'key': fraddy+toaddy, 'value': xml}); var request = doXHR(makeAJAXLocation('storage.php'), {method: 'POST', sendContent: params, headers: {"Content-Type":"application/x-www-form-urlencoded"}}); request.addCallback(TRIP_LIST.getDirections(index)); } TRIP_LIST.getDirections(index+1); }); GEvent.addListener(d, "error", function() { showBriefMiniMessage("Directions from place "+(index+1)+" could not be found"); TRIP_LIST.setDirectionText(index, "Directions not found."); TRIP_LIST.getDirections(index+1); }); } else { var pdata = rootToObject(request); var makeStep = function (x) { return x.inner_text; }; var steps = forEachElement(request, "step", makeStep); var dtext = "Distance: "+pdata.distance+"
"+"
".join(steps); TRIP_LIST.setDirectionText(index, dtext); var points = forEachElement(request, "point", function (x) { return new GLatLng(x.lat, x.lon) }); points.unshiftArray(TRIP_POINTS); TRIP_POINTS = points; TRIP_LINE = new GPolyline(points); //, "#FF0000", 2); var bounds = new GLatLngBounds(); forEach(points, function(x) { bounds.extend(x); }); var newzoom = MAP.getBoundsZoomLevel(bounds); MAP.setCenter(bounds.getCenter(), newzoom); TRIP_LIST.getDirections(index+1); redrawMarkers(); } }; var params = {'key': fraddy+toaddy}; var request = doSimpleXMLHttpRequest(makeAJAXLocation('storage.php'), params); request.addCallback(handleSearchResults); }; } function Place(id, name, type_id, point) { this.type = "place"; this.id = id; this.name = name; this.type_id = type_id; this.point = point; this.toJSON = function () { return "{'type': \"place\",'id': \""+this.id+"\",'notes': \""+JSONEscape(this.notes)+"\"}"; }; this.toXml = function() { return ""; }; this.notes = null; } // smaller than a GPoint function BPoint(lat,lon) { this.lat = lat; this.lon = lon; this.toGLatLng = function() { return new GLatLng(lat, lon); }; this.equals = function(bp) { return (bp.lat == this.lat && bp.lon == this.lon); }; } // address object function Addy(addy, point) { this.type = "addy"; this.id = BUTTER.getID(); this.addy = addy; this.point = point; this.toXml = function() { return ""; }; this.toJSON = function() { return "{'notes': \""+JSONEscape(this.notes)+"\",'type': \"addy\",'addy': \""+this.addy+"\",'lat': \""+this.point.lat+"\",'lon': \""+this.point.lon+"\"}"; }; this.notes = null; } // small GIcon function SmallPin() { var icon = new GIcon(); icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png"; icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png"; icon.iconSize = new GSize(12, 20); icon.shadowSize = new GSize(22, 20); icon.iconAnchor = new GPoint(6, 20); icon.infoWindowAnchor = new GPoint(5, 1); return icon; } // Extending mochikit functions function onMouseOverClass(elementName, className) { connect(elementName, 'onmouseover', function() { addElementClass(elementName, className); }); connect(elementName, 'onmouseout', function() { removeElementClass(elementName, className); }); } function onEnter(id, fnc) { connect(id, 'onkeydown', function(e) {if(e.key().code==13) fnc();}); } function toggleDivText(id, rows, cols) { var src = null; var dest = $(id); var result = ""; if(dest.nodeName.toLowerCase()=="div") { src = document.createElement("textarea"); src.setAttribute('rows', rows); src.setAttribute('cols', cols); result = src.value = unescapeHTML(dest.innerHTML); } else { src = document.createElement("div"); result = src.innerHTML = escapeHTML(dest.value); } src.setAttribute('id', id); swapDOM(dest,src); return result; } function XMLToHTML(s) { if(s==null) return ""; return s.replace("&","&"); } function JSONEscape(s) { if(s==null) return ""; return s.replace("\"","\\\""); } function HTMLToXML(s) { if(s==null) return ""; s = s.replace(">","&gt;"); return s.replace("<","&lt;"); } function escapeHTML(s) { if(s==null) return ""; s = s.replace("&","&"); s = s.replace("<","<"); s = s.replace(">",">"); return s; } function unescapeHTML(s) { s = s.replace("<","<"); s = s.replace(">",">"); s = s.replace("&","&"); return s; } //functions function loadMap() { if(!LOADMAP) return; var isFirstLoad = (MAP==null); if(isFirstLoad) { if (!GBrowserIsCompatible()) { alert(_("Your browser is not compatable with this map.")); return; } FAKEMAP = new GMap2($("fakemap")); MAP = new GMap2($("map")); MAP.setCenter(new GLatLng(32.795355714148336, -79.94338989257812), 13); MAP.addControl(new GLargeMapControl()); MAP.addControl(new GOverviewMapControl()); MAP.addControl(new GMapTypeControl()); GEvent.addListener(MAP, "click", function(overlay, point) { if (point) { //MAP.showMapBlowup(point); } }); //$("search_box").value = "Type addy or place name here."; //connect("search_box", 'onfocus', function() { $("search_box").value = ""; }); // if someone types something and hits enter, run a search onEnter("search_box", function() { doSearch($("search_box").value); }); // login hit enter on password onEnter("password", login); // create account hit enter on password onEnter("create_reenter_password", createAccount); function makeDiv(id) { var d = document.createElement('div'); d.id = id; $("map").appendChild(d); setOpacity(id, 0.9); hideElement(id); } makeDiv("map_message"); makeDiv("mini_map_message"); setOpacity("darken", 0.7); showLoginoutLink(); } getPlaceTypes(); // this will call TRIP_LIST.loadTrip(); when finished MAP_LIST.loadList(); showLoginoutLink(); // roundElement("type_menu_wrapper", null); // add empty message to itinerary var menu = DIV({'class': 'trip_place_menu'},H1({'id': 'empty'},"You have no trips in today's itinerary.")); var html = DIV({'class': 'trip_place_info'}, menu, DIV({'class': 'trip_empty'}, H1({}, "Click on the Places menu on the left to start adding trips."))); appendChildNodes($("trip"), html); // set default start point if we need to if(getQueryParam("default")!=null) { var handleCall = function(request) { var makePlace = function (x) { var place = new Place(x.id, x.name, x.type_id, new BPoint(x.lat, x.lon)); place.address = x.address; place.website = x.website; place.description = x.description; place.phone = x.phone; return place; }; var places = forEachJSONElement(request, makePlace); STARTING_POINT = places[0]; TRIP_LIST.addStartPoint(STARTING_POINT); TRIP_LIST.refresh(); MAP.setCenter(new GLatLng(places[0].point.lat, places[0].point.lon), 13); }; var request = doSimpleXMLHttpRequest(makeAJAXLocation('places.php'), {'default_id': getQueryParam("default")}); request.addCallback(handleCall); } } function showLoginoutLink() { var handleCall = function(request) { if(request.responseText=='0') showLoginLink(); else showLogoutLink(); }; var request = doSimpleXMLHttpRequest(makeAJAXLocation('user.php'), {'action': 'check_login'}); request.addCallback(handleCall); } function clearFormFields() { var f = new Array("create_email", "email", "create_password", "password", "create_reenter_password"); f.each(function (id) { $(id).value=""; }); } function logout() { clearFormFields(); var request = doSimpleXMLHttpRequest(makeAJAXLocation('user.php'), {'action': 'logout'}); request.addCallback(function (request) { showLoginoutLink(); MAP_LIST = new MapList(); TRIP_LIST = new TripList(); TRIP_LIST.refresh(); MAP_LIST.loadList(); showBriefMiniMessage("You've been logged out."); }); } function login() { var email = USER_EMAIL = $("email").value; var password = $("password").value; if(email=="" || password=="") { alert("You must specify both a username and password."); return; } var handleLogin = function(request) { if(request.responseText=='1') { hideLogin(); showLogoutLink(); clearFormFields(); MAP_LIST.loadList(); } else alert("Incorrect username or password."); }; var params = {'action': 'login', 'email': email, 'password': password}; var request = doSimpleXMLHttpRequest(makeAJAXLocation('user.php'), params); request.addCallback(handleLogin); } function createAccount() { var email = $("create_email").value; var password = $("create_password").value; var preenter = $("create_reenter_password").value; if(password=="" || preenter=="" || email=="") { alert("No field can be left blank"); return; } else if (!isValidEmailAddy(email)) { alert("The email address you entered is invalid."); return; } if(password != preenter) { alert("The password you entered the second time doesn't match the first"); return; } var handleCreate = function(request) { if(request.responseText == '1') { hideLogin(); showLogoutLink(); showBriefMiniMessage("User created."); clearFormFields(); //MAP_LIST.refresh(); TRIP_LIST.save(); } else if(request.responseText == '2') { alert("Email address has already been used."); } }; var params = {'action': 'create', 'email': email, 'password': password}; var request = doSimpleXMLHttpRequest(makeAJAXLocation('user.php'), params); request.addCallback(handleCreate); } function showLoginLink() { hideElement("logout"); hideElement("email_itinerary"); showElement("login"); showElement("create_account"); } function doLogin() { if(!confirm("If you log in all of your current settings will be lost. Continue?")) return; showElement("darken"); showElement("login_box"); $("email").focus(); } function doCreate() { showElement("darken"); showElement("create_login_box"); $("create_email").focus(); }; function showLogoutLink() { hideElement("login"); hideElement("create_account"); showElement("logout"); showElement("email_itinerary"); } function hideLogin() { hideElement("darken"); hideElement("login_box"); hideElement("create_login_box"); } function showMapMessage(html) { //var closeButton = function(x) { return INPUT({'id': 'map_msg_close.'+x, 'type': 'button', 'value': 'Close Window'}); }; var closeButton = function(x) { return SPAN({'id': 'map_msg_close.'+x, 'class': 'span_link'}, 'Close Window'); }; var map_message = $('map_message'); map_message.innerHTML = ""; appendChildNodes(map_message, DIV({}, closeButton(1), BR(), html, BR(), closeButton(2))); var closeFunction = function(x) { connect('map_msg_close.'+x, 'onclick', function () { shrink("map_message"); }); onMouseOverClass('map_msg_close.'+x, 'span_link_hover'); }; forEach([1,2], closeFunction); appear(map_message); } function hideMapMessage() { shrink("map_message"); } function showMiniMessage(msg) { $('mini_map_message').innerHTML = msg; if (MINI_MSG_SHOWING) shake('mini_map_message'); else { appear('mini_map_message', {afterFinish: function () { MINI_MSG_SHOWING = true; }}); } } function showBriefMiniMessage(msg) { showMiniMessage(msg); callLater(5, hideMiniMessage); } function hideMiniMessage() { fade('mini_map_message'); MINI_MSG_SHOWING = false; } function doSearch(txt) { //var txt = $("search_box").value; if(txt=="") return; showMiniMessage("Searching..."); //hideMapMessage(); var handleSearchResults = function(request) { var makePlace = function (x) { return x; }; var places = forEachElement(request, "place", makePlace); // if no results if(places.length==0) { showBriefMiniMessage("Sorry, no results were found."); return; } hideMiniMessage(); var items = [{}]; var sr = 0; forEach(places, function(x) { var name = (x.type=="addy") ? x.addy : x.name; items.push(LI({}, SPAN({'class': 'span_link', 'id': 'search_result.'+sr}, name))); sr++; }); sr = 0; showMapMessage(UL.apply(null, items)); forEach(places, function(x) { onMouseOverClass('search_result.'+sr, "span_link_hover"); connect('search_result.'+sr, 'onclick', function() { if(x.type=="addy") { var addy = new Addy(x.addy, new BPoint(x.lat, x.lon)); var marker = makeAddyMarker(addy); openAddyInfoWindow(addy); } else { var place = new Place(x.id, x.name, x.type_id, new BPoint(x.lat, x.lon)); var marker = makeMarker(place); openMarkerInfoWindow(place); } MAP.addOverlay(marker); hideMapMessage(); }); sr++; }); }; var request = doSimpleXMLHttpRequest(makeAJAXLocation('search.php'), {'query': txt}); request.addCallback(handleSearchResults); } function getPlaceTypes() { var request = doSimpleXMLHttpRequest(makeAJAXLocation('placeTypes.php')); request.addCallback(setupTypeMenu); } function redrawMarkers() { MAP.clearOverlays(); forEach(PLACE_MARKERS, function(type_id) { var place_type = getLocalPlaceType(type_id); forEach(place_type.places, function(place) { // If this place is not on the trip list if(!TRIP_LIST.hasPoint(place.point)) { var marker = makeMarker(place); MAP.addOverlay(marker); } }); }); if(TRIP_LINE!=null) MAP.addOverlay(TRIP_LINE); TRIP_LIST.places.ceach(function(place, index) { MAP.addOverlay(makeTripMarker(place, index, TRIP_LIST.places.length)); }); } function makeTripMarker(place, number, max) { var point = place.point.toGLatLng(); var makeIcon = function () { var baseIcon = new GIcon(); baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png"; baseIcon.iconSize = new GSize(20, 34); baseIcon.shadowSize = new GSize(37, 34); baseIcon.iconAnchor = new GPoint(9, 34); baseIcon.infoWindowAnchor = new GPoint(9, 2); baseIcon.infoShadowAnchor = new GPoint(18, 25); return baseIcon; }; var icon = new GIcon(makeIcon()); if(number == 0) icon.image = makeMarkerImageLocation('start.png'); else if(number == (max-1)) icon.image = icon.image = makeMarkerImageLocation('stop.png'); else icon.image = makeMarkerImageLocation('marker'+(number+1)+'.png'); var marker = new GMarker(point, icon); GEvent.addListener(marker, 'click', function() { if(place.type=="place") openMarkerInfoWindow(place); else openAddyInfoWindow(place); }); return marker; } function setupTypeMenu(request) { var makePlaceType = function (x) { return new PlaceType(x.id, x.name); }; PLACE_TYPES = forEachJSONElement(request, makePlaceType); var divs = map(function (place) { var div = toHTML(DIV({'class': 'typeHeading'}, DIV({'id': 'typeHeading.'+place.id},place.name))); return div+toHTML(DIV({'class': 'typeContents', 'id': 'typeContents.'+place.id}, _("loading..."))); }, PLACE_TYPES); $("type_menu").innerHTML = "".join(divs); forEach(PLACE_TYPES, function (place_type) { toggle($('typeContents.'+place_type.id), "blind"); onMouseOverClass('typeHeading.'+place_type.id, "typeHeading_hover"); connect('typeHeading.'+place_type.id, 'onclick', function() { toggle($('typeContents.'+place_type.id), "blind"); // Already being shown - hide it! if(place_type.hasVisibleMarkers()) { place_type.hideMarkers(); } else { place_type.showMarkers(); } }); }); } function setupPlaceMenu(type_id, request) { var makePlace = function (x) { return new Place(x.id, x.name, x.type_id, new BPoint(x.lat, x.lon)); }; var places = forEachJSONElement(request, makePlace); var placeType = getLocalPlaceType(type_id); // add each place to it's proper place type, and make menu var contents = new Array(); forEach(places, function(place) { placeType.addPlace(place); var html = toHTML(LI({'class': 'place_link', 'id': 'place_link.'+place.id}, place.name)); contents.push(html); //var marker = makeMarker(place); //MAP.addOverlay(marker); }); var list = "
    "+"".join(contents)+"
"; $('typeContents.'+type_id).innerHTML = (contents.length!=0) ? list : _("No places for this type."); forEach(places, function(place) { onMouseOverClass('place_link.'+place.id, "place_link_hover"); connect('place_link.'+place.id, 'onclick', function() { openMarkerInfoWindow(place); }); }); } function makeAddyMarker(addy) { var point = new GLatLng(addy.point.lat, addy.point.lon); var marker = new GMarker(point, SmallPin()); GEvent.addListener(marker, 'click', function() { openAddyInfoWindow(addy); }); return marker; } function openAddyInfoWindow(addy) { var point = new GLatLng(addy.point.lat, addy.point.lon); MAP.setCenter(point); MAP.openInfoWindowHtml(point, makeAddyHTML(addy)); connect('addLink.'+addy.id, 'onclick', function() { TRIP_LIST.addAddy(addy); }); connect('makeDefaultStart.'+addy.id, 'onclick', function() { addStartingPoint(addy); }); onMouseOverClass('addLink.'+addy.id, "span_link_hover"); onMouseOverClass('makeDefaultStart.'+addy.id, "span_link_hover"); } function makeAddyHTML(addy) { var addToTrip = SPAN({'id': 'addLink.'+addy.id, 'class': 'span_link'}, _("Add To Trip")); var makeDefaultStart = SPAN({'id': 'makeDefaultStart.'+addy.id, 'class': 'span_link'}, _("Make Default Starting Point")); var html = DIV({'class': 'marker_place_info'}, addToTrip, BR(), makeDefaultStart, BR(), B({}, addy.addy), BR(), BR()); return toHTML(html); } function makeMarker(place) { var point = new GLatLng(place.point.lat, place.point.lon); var marker = new GMarker(point, SmallPin()); GEvent.addListener(marker, 'click', function() { openMarkerInfoWindow(place); }); return marker; } function openMarkerInfoWindow(place) { var openWindow = function(lat, lon, request) { // This next array will have one element that is an object formed from the XML "place" // element that contains extended information about the place, such as description, website, etc. //var place_info_list = forEachElement(request, "place", function(x) { return x; }); var place_info_list = forEachJSONElement(request, function(x) { // we're going to return something that isn't really a "place" type, // but an "extended" place, w/ description, etc, no lat/lon x.type = "place"; x.point = new BPoint(x.lat, x.lon); x.toXml = function() { return ""; }; x.toJSON = function() { return "{'type': \"place\",'id': \""+this.id+"\",'notes': \""+JSONEscape(this.notes)+"\"}"; }; return x; }); var point = new GLatLng(lat, lon); MAP.setCenter(point); MAP.openInfoWindow(point, makeMarkerHTML(place_info_list[0])); connect('addLink.'+place_info_list[0].id, 'onclick', function() { TRIP_LIST.addPlace(place_info_list[0]); }); connect('makeDefaultStart.'+place_info_list[0].id, 'onclick', function() { addStartingPoint(place_info_list[0]); }); onMouseOverClass('addLink.'+place_info_list[0].id, "span_link_hover"); onMouseOverClass('makeDefaultStart.'+place_info_list[0].id, "span_link_hover"); }; var request = doSimpleXMLHttpRequest(makeAJAXLocation('places.php'), {'id': place.id, 'clicked': '1'}); request.addCallback(openWindow, place.point.lat, place.point.lon); } // This function takes an info object that contains extended information // about the place, such as description, website, etc. function makeMarkerHTML(info) { var addToTrip = SPAN({'id': 'addLink.'+info.id, 'class': 'span_link'}, _("Add To Trip")); var makeDefaultStart = SPAN({'id': 'makeDefaultStart.'+info.id, 'class': 'span_link'}, _("Make Default Starting Point")); var link = (info.website) ? makeRedirectLink(info.id, info.website) : _("No website."); var name = H1({}, info.name); // The description must be handled differently in IE because it sucks var description = null; description = DIV({'class': 'description'}, info.description); var phone = info.phone; var address = info.address; var html = DIV({'class': 'marker_place_info'}, addToTrip, BR(), makeDefaultStart, name, description, UL({}, LI({}, _("Phone: "), phone), LI({}, _("Address: "), address), LI({}, _("Website: "), link))); return html; } function makeRedirectLink(place_id, website) { var link = makeLocation("redirect.php?place_id="+place_id+"&to=http://"+website); return A({'href': link, 'target': '_BLANK'}, website); } function makeTripHTML(info, number, trip_size) { var id = info.id+'.'+number; var remove_link = SPAN({'id': 'trip_remove.'+id, 'class': 'span_link'}, IMG({'src': makeImageLocation('list-remove.gif')}), _("Remove from trip")); var move_up = (number==0) ? null : SPAN({'id': 'trip_mup.'+id, 'class': 'span_link'}, IMG({'src': makeImageLocation('go-up.gif')}), _("Move Up")); var move_down = (number==(trip_size-1)) ? null : SPAN({'id': 'trip_mdown.'+id, 'class': 'span_link'}, IMG({'src': makeImageLocation('go-down.gif')}), _("Move Down")); var menu = DIV({'class': 'trip_place_menu'}, remove_link, " ", move_up, " ", move_down); var directions = (number==(trip_size-1)) ? BR() : DIV({'id': 'directions.'+number, 'class': 'directions'}, "Fetching directions"); var notes_text = (info.notes=="No notes."||info.notes==null||info.notes==""||info.notes=="undefined") ? "No notes." : unescapeHTML(info.notes); var notes = DIV({'class': 'note'}, DIV({'id': 'notes.'+id}, notes_text)); var notes_link = SPAN({'id': 'notes_visible.'+id, 'class': 'span_link'}," "); if(info.type=="place") { var link = (info.website) ? makeRedirectLink(info.id, info.website) : _("No website."); var name = H1({}, (number+1)+'. '+info.name); // IE is the suck! var description = null; description = DIV({'class': 'description'}, info.description); var phone = info.phone; var address = info.address; var html = DIV({'class': 'trip_place_info', 'id': 'trip_place.'+id}, menu, DIV({'class': 'trip_details'}, name, description, UL({},LI(_("Phone: "), phone), LI(_("Address: "), address), LI(_("Website: "), link)), directions, notes_link, notes)); } else { // addy var name = H1({}, (number+1)+'. '+info.addy); var html = DIV({'class': 'trip_place_info', 'id': 'trip_place.'+id}, menu, DIV({'class': 'trip_details'}, name, directions, notes_link, notes)); } return html; } function getLocalPlaceType(id) { var place_type = null; forEach(PLACE_TYPES, function(x) { if(x.id==id) { place_type = x; return; } }); return place_type; } function addStartingPoint(addy) { STARTING_POINT = addy; var location = (addy.type == "addy") ? addy.addy : addy.name; if(confirm("Add staring point of \""+location+"\" to front of each trip?")) { TRIP_LIST.addStartPoint(addy); TRIP_LIST.refresh(); } } // email trips to user function email() { if(!confirm("Send an email containing your trip information?")) return; var r = doSimpleXMLHttpRequest(makeAJAXLocation('email.php')); r.addCallback(function() { alert("Email sent. You should receive it shortly."); }); } // check for a valid email addy function isValidEmailAddy(email) { var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; return filter.test(email); } function help() { showElement("darken"); showElement('help_box'); } function hideHelp() { hideElement("darken"); hideElement('help_box'); } function setMyAddress() { var addy = prompt("Specify your starting address:"); if (addy) doSearch(addy); }