tag:blogger.com,1999:blog-47275701262874111682024-03-13T13:48:54.127-04:00Bare-nuckle DOMProgramming techniques for dealing with browsers and various API.theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-4727570126287411168.post-41393249619555291832012-01-31T11:46:00.000-05:002012-01-31T11:46:05.648-05:00A simple Echo Machine to demonstrate basic $.ajax on Jquery Mobile pageThis example uses the Jquery and Jquery Mobile application with HTML5 to send an asynchronous request to php on the server. <br />
<br />
<blockquote class="tr_bq"><blockquote class="tr_bq"><!DOCTYPE HTML><br />
<html><br />
<head><br />
<title>Echo Machine</title><br />
<meta name="viewport" content="width=device-width, initial-scale=1"> <br />
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" /><br />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script><br />
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script><br />
</head><br />
<br />
<body><br />
<br />
<div data-role="page" id="easyloader" data-theme="e" data-add-back-btn="true"><br />
<div data-role="header"><br />
<h1>Ajax Echo Machine</h1><br />
</div><br />
<br />
<div data-role="content"> <br />
<p> Test Jquery $.get function. Send an asynchronous request to the server and show results. </p><br />
<label for="echo_term"> Enter a phrase (and then press tab or click outside of box): </label><br />
<input type="text" name="echo_term" id="echo_term" onchange="makeEcho()"/><br />
</div><br />
<br />
<div id="echo_results" style="margin-left:50px" > Echo here. </div><br />
<br />
</div><br />
<br />
<script type="text/javascript"><br />
<br />
function makeEcho() {<br />
var echo_val=$("#echo_term").val(); <br />
$.get("scripts.php", {echo_term : echo_val}, function(data){<br />
if (data.length>0){ <br />
$("#echo_results").html("<p> " + data + " </p>"); <br />
<br />
} else $("#echo_results").html('<p>no data returned! </p>'); <br />
});<br />
} <br />
</script><br />
</body><br />
<blockquote class="tr_bq"></html></blockquote></blockquote></blockquote> uses the php file called scripts.php<br />
<blockquote class="tr_bq"><br />
<?php<br />
//a simple echo machine the returns what you sent it.<br />
$term = strip_tags(substr($_GET['echo_term'],0, 100));<br />
$term = mysql_escape_string($term); <br />
$term = "Response from php: " . $term;<br />
echo $term;<br />
?></blockquote>theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0tag:blogger.com,1999:blog-4727570126287411168.post-59224938671567109922011-08-03T14:35:00.000-04:002011-08-03T14:35:43.720-04:00Update web pages using the Asynchronous HTTP Request with jQuery in CodeIgniter1. Create a web page that has in input box for the guest to enter their email address. <br />
<br />
2. The page should load the javascript file, ready.js (which initializes jQuery.<br />
When the onchange event is fired, it will send the contents of the input box to the ajaxCheck function.<br />
<br />
3. This function will use the ajax $.post function provided through jQuery to send the str value to the server using asynchronious http calls. (note: you can write this yourself or use jQuery). Notice how the controller registration is called and routed to the checkID function. The checkID function queries the database and then returns a value that indicates what was found. These values are:<br />
Current (the email is registered), Invalid (the email is not valid email account), True (user is not registered but in our contact list), False (user is not registered).<br />
<br />
4. Finally it puts these values into a json array structure and sends it back to the javascript function that called it.<br />
<br />
echo json_encode(array("returnValue"=>$value,"idValue"=>$id));<br />
<br />
5. The callback function will have access to these two variables: data.returnValue and data.idValue; <br />
<br />
With this information it can update the web page as appropriate. Use jQuery functions to rewrite elements and the page will not need to do a complete refresh.<br />
<br />
The view file:<br />
<br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"><html></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"><head></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"><script src="<?=base_url()?>/_lib/js/ready.js" type="text/javascript"></script></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"></head></span><br style="background-color: #fff2cc;" /><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"><script ></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;">function ajaxCheck(str) {</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //called by email input box </span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> </span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $.post(</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> "registration/checkID",</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> { sendValue: str },</span><br style="background-color: #fff2cc;" /><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> function(data) {</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //this is the callback function that will receive the results from the php function on the server</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //alert(data.returnValue);</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $success = data.returnValue;</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $newid = data.idValue;</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> switch ($success ) {</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> case 'current':</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //user is registered for the year</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#displayMsg').text('You are already registered for 2011. Sign in to edit');</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> var href = jQuery(location).attr('href');</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#signinbox').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> </span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('input[name="email"]').val(str);</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //var tmpString = '<p><a href="'+href +'/unregister/'+$newid +'"> Unregister </a> for the workshop.</p>';</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //$('#unregisterbox').html(tmpString);</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //$('#unregisterbox').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> break;</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> case 'true':</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //user is not registered yet, but they are in the rolls</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#displayMsg').text('');</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#oldUser').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#regForm2').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#regForm3').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> break;</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> case 'false':</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> //user is not registered and is new</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#displayMsg').text(' Registration requires your name, zip code and organization');</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#regForm2').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#regForm3').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> break;</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> case 'invalid':</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#displayMsg').text(' oops...not a valid form of email');</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> break;</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> default:</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#displayMsg').text(' please register');</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#regForm2').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> $('#regForm3').show();</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> }</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> },</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> "json"</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> );</span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;">}</span><br style="background-color: #fff2cc;" /><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"></script></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"><body></span><br style="background-color: #fff2cc;" /><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> </span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> <label for="in_email" style="display:inline">Email </label></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> <input type="text" id="in_email" name="in_email" onchange="ajaxCheck(this.value)" size=40 value="" /></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> </span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> </span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"> </span><br style="background-color: #fff2cc;" /><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"></body></span><br style="background-color: #fff2cc;" /><span style="background-color: #fff2cc;"></html></span><br />
<br />
<br />
<br />
<br />
<br />
And finally, some php for the controller and the server:<br />
<br />
<span style="background-color: #f3f3f3;">function checkID() {</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //this is called by the browser using ajax techniques via jQuery</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //IF USER IS REGISTERED FOR 2011, DROP OUT.</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //FIND USER IN DATABASE</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> // returns true if it finds the email</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //returns false if it doesn't find the email</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //returns invalid if the email is bad</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //returns current if the email is registered for 2011</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $id = '';</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $email = strtolower($_POST['sendValue']);</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $this->load->helper('email');</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $this->load->database();</span><br style="background-color: #f3f3f3;" /><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> if ($email != '' && valid_email($email) ) { </span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //CHECK if email is in use</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $this->db->where('active', '1');</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $this->db->where('email', $email);</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $attendees = $this->db->get('attendees');</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $attendee = $attendees->result();</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $count = count($attendee);</span><br style="background-color: #f3f3f3;" /><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> if ( $count >= 1 ) {</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $value = 'true';</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //it is in use, see if //check if registered</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $id = $attendee[0]->id;</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $this->db->where('attendeeId', $id);</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $regged = $this->db->get('registrations');</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $reg = $regged->result();</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> if ( count($reg ) >=1 ) {</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //it is registered, see what year</span><br style="background-color: #f3f3f3;" /><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $year = $reg[0]->workshopYear;</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> if ( $year == '2011') {</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> //crash and burn. don't let them reregister. without signing in first</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> $value = 'current';</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> } </span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> } </span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> } else { $value = 'false'; }</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> } else { $value = 'invalid'; }</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> echo json_encode(array("returnValue"=>$value,"idValue"=>$id));</span><br style="background-color: #f3f3f3;" /><span style="background-color: #f3f3f3;"> }</span>theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0tag:blogger.com,1999:blog-4727570126287411168.post-16431050860885083572009-10-14T13:43:00.005-04:002009-10-14T14:01:32.616-04:00Encoded Polylines for Static Google Maps<p><br />The Google Static Map has a size limitation of 2400 characters which is because of IE's url size limit. Since the static map is created by sending the polyline endpoints through the URL, it becomes easy to reach that limit with a curvey path on the map...for example...gpx paths for hiking paths. Using the ecoded polyline feature, which calculates the path segments by their relative changes, and converting to a more efficient binary representation, the data set can be greatly compressed in the URL.<br /></p><p><br />The <a href="http://wiki.urban.cens.ucla.edu/index.php/How-to_use_Google_Maps_polyline_encoding_to_compact_data_size">Urban Sensing Wiki</a> at UCLA about "How-to use Google Maps polyline encoding to compact data size" and gives the following Python functions to use.<br /><br /></p><p><br /><br /></p><pre><br /># Encode a signed number into the google maps polyline encode format.<br /># from: http://wiki.urban.cens.ucla.edu<br />def encodeSignedNumber(num):<br />sgn_num = num << sgn_num =" ~(sgn_num)" encodestring = "">= 0x20:<br /> encodeString += chr((0x20 | (num & 0x1f)) + 63)<br /> num >>= 5<br />encodeString += chr(num + 63)<br />return encodeString<br /><br /># Create the encoded polyline and level strings.<br /># @points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]<br /># This function takes a list of dictionaries (each dictionary contains a<br /># single 'lat','lng' pair) and returns a dictionary:<br /># {'encoded_points': string, 'encoded_levels': string}.<br /># from: http://wiki.urban.cens.ucla.edu<br />def encodePolyPts(points):<br />i = 0<br />plat = 0<br />plng = 0<br />encoded_points = ""<br />encoded_levels = ""<br />for i in range(0, len(points)):<br /> point = points[i]<br /> lat = point['lat']<br /> lng = point['lng']<br /> level = 3 - i%4 <br /> late5 = int(math.floor(lat * 1e5))<br /> lnge5 = int(math.floor(lng * 1e5))<br /> dlat = late5 - plat<br /> dlng = lnge5 - plng <br /> plat = late5<br /> plng = lnge5 <br /><br /> encoded_points += encodeSignedNumber(dlat) + encodeSignedNumber(dlng)<br /> encoded_levels += encodeNumber(level)<br /><br />return {'encoded_points': encoded_points, 'encoded_levels': encoded_levels}<br /></pre><br /><p></p><p><br />To use this encoding capability to draw a static Google map, the (points) list needs to be built. The variable is<br />expected to be a list of dictionaries. The documentation shows us it is expecting the format to be as follows:<br /></p><p><br />@points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]<br /></p><p><br />The following function retrieves the datastore item and parses the lat and lng values<br />to create a single dictionary which is then appended to the list.<br /></p><p><br />Note: in this example the "newStr" variable is a JSON string from the datastore which is loaded into a python object using the<br />simplejson utility. It can then be iterated to find all the stored lat and lng points.<br /></p><br /><pre><br />def mapShow(request, route_key):<br />"""creates a static google map of the entire route """<br />"""written by Thea Ganoe, October 2009"""<br />#http://maps.google.com/maps/api/staticmap?size=400x400&path=weight:3|color:orange|enc:polyline_data<br />user = users.get_current_user()<br />route = models.Route.get(route_key)<br />pathList = []<br />newStr = route.way<br />#'{"description":"'+ route.routeName +'", "img":"'+route.img+'", "getPic": "' + route.img +'", "zoom":"'+ zoomstring +'" , "longitude":"'+ route.longitude +'", "latitude":"'+ route.latitude +'", "position": "0", "heading": "" }'<br />ways_obj = simplejson.loads(newStr)<br />sizeofWay = len(ways_obj['way'])<br />for way in ways_obj['way']:<br /> pathDic = { 'lat': float(way['latitude']), 'lng': float( way['longitude']) }<br /> pathList.append(pathDic)<br /> # points: [{'lat':100, 'lng':50}, {'lat':102, 'lng':49.8}]<br />polyPts = encodePolyPts(pathList)<br />return respond(request, user, 'staticMap', {'enc':polyPts } )<br /></pre><br /><p><br />Since the Django template system is used by this Google App Engine application, the return value will merge the staticMap.html template with the server response. To use the enc value, it is necessary to specify which list is needed, enc.encoded_points or enc.encoded_levels. This template looks like this:<br /><br /></p><pre><p><br /><image src="http://maps.google.com/maps/api/staticmap?size=512x512&path=weight:2|color:red|enc:{{ enc.encoded_points }}&sensor=false&key=myveryownbiglongkeyfromGoogle"/></p></pre><br /><br /><p>To create a static map, the levels data is not needed. If a live Google Map was being displayed, the levels values would be used by it, because the enc list contains dictionaries of . The above function, Showmap() will return the data needed for either type of map. This is because the return value enc actually contains list of points and a list of levels.<br /></p> <pre>'encoded_points': encoded_points, 'encoded_levels': encoded_levels<br /></pre>theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0tag:blogger.com,1999:blog-4727570126287411168.post-10645053045790015102009-05-26T14:55:00.006-04:002009-05-26T15:39:03.755-04:00Dynamic HTML SELECT forms for AppEngineAppEngine<br />dynamically created HTML select forms for Django python templates<br /><br />I didn't see this particular solution anywhere so I'll post it here, since it something that may come up for anyone trying to do a XMLHttpRequest() in Google AppEngine. Normally I use the Django forms in App Engine but I wanted to quickly add some query filters without having to create a model for them.<br />This could happen when the web app needs to interface with the user. In this example, I simply wanted to filter the dataset by the location. So I have one select box with all the states listed. I do have a Django model but it is used for creating new records, not filtering lists.<br /><br />First step, put the forms in the html template (this uses built-in Django template tags ):<br /><br /><blockquote><br /><form method="post" id="frmSearchBox"><br /><br /><table><br /><tr><td><br /> <SELECT name="states" id="states" onChange="selectState(this)"><br /> {% for stt in states %}<br /> <option name="op" value="{{ stt }}" ><br /><br /> {% endfor %} <br /> </SELECT><br /></td><br /><table><br /><input type="button" name="btnSearch" value="Submit" onclick="javascript:searchStates();"><br /><form> <br /></blockquote><br /><br />Notice this form is a post. Because I want to add AJAX to only update a portion of the page.<br /><blockquote><br />function searchRoutes() {<br /> //the submit button on the searchbox form triggers this function<br /> //this will do an ajax post to the server and filter the routes according to the user selection<br /><br /> var states = document.getElementById('states')[document.getElementById('states').selectedIndex].innerHTML;<br /><br /> var body ="states=" + states ;<br /> var req = createXMLHttpRequest();<br /> req.open('POST', '/rpcRouteSearch/', true);<br /> req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");<br /> req.setRequestHeader("Content-length", body.length);<br /> req.setRequestHeader("Connection", "close");<br /> req.onreadystatechange = onAddSuccess;<br /> req.send(body);<br /><br /> function onAddSuccess(response) {<br /> //alert("in searchRoutes callback: " + req.readyState);<br /> //replaces the #_nodes with the slideshow<br /> if (req.readyState != 4) {return; }<br /> var serverResponse = req.responseText;<br /> var mg = document.getElementById("leftImages");<br /> mg.innerHTML = serverResponse;<br /><br /> }<br />}<br /><br /></blockquote><br /><br />================<br />Now a peek at the python in views.py, our callback is waiting for the line that starts with request.method == 'POST':<br /><br /><blockquote><br />def intro(request):<br /> user = users.get_current_user()<br /> statelist = ['All']<br /> if request.method == 'GET':<br /> routes = db.GqlQuery("SELECT * FROM Route" )<br /> numroutes = routes.count()<br /> """Next sections prepare data for the search box forms """<br /> for route in routes:<br /> statelist.append(route.state)<br /> """this next trick removes duplicate values! """<br /> statelist = list(set(statelist))<br /> return respond(request, user, 'intro', {'routes' : routes, 'numroutes' : numroutes, 'states' : statelist })<br /> if request.method == 'POST':<br /> """AJAX call, use post when filtering with the search box form """<br /> post= request.POST.copy()<br /> statefilter = post['states']<br /> statefilter = statefilter.strip()<br /> # The Query interface prepares a query using instance methods.<br /> q = db.Query(models.Route)<br /> """q = models.Route.all()"""<br /> q.filter('state = ',statefilter)<br /> # The query is not executed until results are accessed.<br /> routes = q.fetch(25)<br /> numroutes = q.count()<br /> statelist = ['All']<br /> return respond(request, user, 'introRoutes', {'routes' : routes, 'numroutes' : numroutes, 'states' : statelist})<br /><br /></blockquote><br />====<br /><br />The lines that were nonstandard, are these<br /><br /> statefilter = post['states']<br /> statefilter = statefilter.strip()<br /><br />It was necessary to use the string function strip to get the results to work properly in the filter function. All it does is remove whitespace from the ends of the string (not inside) and now the variable is ready to be used by the filter.<br /><br />======<br /><br />The python code is going to use a template called "introRoutes.html" to build it's serverResponse that gets sent to the waiting Callback function in the javascript.<br /><br />Since we are working with an HTML form select box, it would be nice to set the SELECTED value, to make sure the form is reset for the user, moreso important when there are many of these select options...otherwise the user has to reset them all manually. We want to set the form back to 'All' after every use, the 'All' setting is added at the beginning of the Python function,<br /><br />statelist = ['All']<br /><br />and then the other states available are added to it. To make sure ALL is always SELECTED, the attribute must be written to the form, in this case we are in an asychronous call to the server, but it works the same way.<br /><br />Here is an extra $2 trick..use Django’s built-in template tags and filters! Anything in the {% isPython %} commands and the bracket tags {{ areVariables }}. These are more fully described at http://docs.djangoproject.com/en/dev/ref/templates/builtins/#ref-templates-builtins<br /><br />Example of dynamically created HTML select forms for Django python templates. <br /><br /><br /><em><br /><select name="states" id="states" style="width: 6em;"> <option name="op" value="{{ stt }}" ifequal="" stt="" all="" selected="selected" endifequal="">{{ stt }} {% endfor %} </option></select><br /></table></form></em>theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0tag:blogger.com,1999:blog-4727570126287411168.post-14341204423778401202009-02-15T13:44:00.005-05:002009-02-15T13:55:37.286-05:00Configuring Ubuntu, Eclipse w/phpEclipse plugin, and LAMPP running on a web serverDeveloping with Eclipse. I've always been a notepad IDE person (obviously hence the blog name but....real work has required me to use Eclipse and CVS). <br /><br />This covers Ubuntu/8.04 (hardy), Eclipse Ganymede with phpEclipse plugin, and LAMPP. LAMPP is a quick way to get an Apache2 web server up and running for development purposes, with mySQL and PHP automatically set up. But the ultimate solution and purpose of this post, getting Eclipse to output files that run on a web server, will work on any web server. In addition configure phpEclipse and Eclipse workspace folders which requires a few additional steps which are detailed here.<br /><br />If you don't have LAMPP, you can get xampp-linux-1.7.tar.gz from:<br /> Linux http://www.apachefriends.org/en/xampp-linux.html<br /><br />Note: If apache2 is installed somewhere else on the system, LAMPP can coexist, but the other Apache daemons will have to be stopped before LAMPP will start (system will check and warn).<br /><br />Eclipse Ganymede was downloaded and installed from the Eclipse.org site since an older Eclipse was available from the Syntaptic Package Manager and I wanted Ganymede, but really you can use whichever you want, it will not affect these instructions.<br /><br />Once LAMPP is running and localhost is showing the XAMPP page and Eclipse is configured and loaded with phpEclipse and all the web tools, the Eclipse workspace will normally be placed in your home folder. However, if you're writing PHP files with Eclipse (you installed phpEclipse, afterall) obviously both the web server and Eclipse needs to know where to find the folders. The secret is to put those Eclipse php folders on the webserver. Then put symlinks in the Eclipse workspace that point to the those folders.<br /><br />Demonstration:<br /><br />1. make a folder called 'projectX', or whatever you want to call it, in htdocs (the default server document root which can be found at /opt/lampp ) and give it permissions so it is owned by the user:<br /><br /> chown $user /opt/lampp/htdocs/projectX<br /><br />(in all these examples, $user should be replaced by your Ubuntu username in the commands)<br /><br />2. make a symbolic link to this to file, and put it (the symlink) in the workspace to be used by Eclipse to hold projects. When Eclipse saves to the folder, the files will actually be written to the folder that was created in the web server's document root (in htdocs).<br /><br />The rule for creating a symbolic link: <br /><br /> ln -s /path/to/real/file /path/to/non-existant/file<br /><br />modified for this demo:<br /><br /> ln -s /opt/lampp/htdocs/projectX /home/$user/workspace<br /><br />Which will result in a folder with an arrow on it in the users eclipse workspace!! It will have zero items in it until files are download from Eclipse CVS or the phpEclipse IDE is used to create or edit files. Most importantly, the files can be browsed and read by the development web server.theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0tag:blogger.com,1999:blog-4727570126287411168.post-5725398081326135712009-01-16T00:35:00.002-05:002009-01-16T00:41:02.765-05:00Python PreviewIn order to do much with Google App Engine, Python server programming awaits with its strange mix of being an old programmer's program and being of the future with a direction that will carry us away from everything as we've known it. Python is different from programs like PHP or Perl or ASP because it isn't a scripting language. It's a real meat and potatoes programming language that can go toe to toe (maybe, almost) with the likes of C++. To work with Python, server side developers will spend the most time figuring out how to put data in a list or a dictionary or some combination of the two. The Python book is 5 inches thick but I spend most of my time around page 20, preview about lists and dictionaries because to get my data processed, this was the only way. (My data being strings of json-like recordsets)<br /><br />And there is a good reason for that. It is not necessary to name fields or columns or components. Python doesn't care. Just stuff the data into a lists, put the list in a dictionary and follow a few rules to iterate through it. It's not even necessary to declare the data types. Python does that invisibly at run time based on what it finds in the containers.<br /><br />It works beautifully with Google's Big Table. Formal database records with their keys and nomalized relations are out the window. Goodbye to recordsets and table joins. Who needs a table schema? The process of defining the list and dictionary in Python creates dynamic objects. Which are all any reasonable server needs to manipulate the data before sending it off to any of its possible destinations.theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0tag:blogger.com,1999:blog-4727570126287411168.post-59086604456167795942008-12-21T18:12:00.001-05:002008-12-21T18:15:25.643-05:00Reading Visual Basic Binary encoding for screen coordinatesReading Visual Basic Binary encoding for screen positions, X and y.<br /><br /><br /><br />This is a slight departure from Ajax-related topics, but since I've been heavily involved with transforming older binary files to modern XML, there was one challenge that took some unexpected calculating that I want to document here.<br /><br /><br /><br />The older binary files were created by Visual Basic 6, apparently it writes the screen coordinate positions in big endian formats.<br /><br /><br /><br />In my binary files, I knew these eight bytes contain the screen position and size of a block. Another way to describe this would be a the top left corner and lower right corner, the coordinates (x1, y1) and (x2, y2).<br /><br /><br /><br />Here are some bytes that describe 4 boxes in a row, with varying widths, but all with the same height,effectively making a table.<br /><br /><br /><br />4 rows of 8 bytes in hex code format:<br /><br /><br /><br />00 8C 00 08 01 31 00 69<br /><br />00 8C 00 69 01 31 00 C5<br /><br />00 8C 01 C4 01 31 02 7F<br /><br />00 8C 02 7F 01 31 03 16<br /><br /><br /><br /><br /><br /><br /><br />In each row, the first two bytes are x1. Next two are y1. Then x2, and last is y2. Little endian doesn't work, the numbers get too big. Using big endian:<br /><br /><br /><br />ypos1, xpos1, ypos2, xpos2<br /><br /><br /><br />140, 8, 305, 105<br /><br />140, 105, 305, 453<br /><br />140, 452, 305, 639<br /><br />140, 639, 305, 790<br /><br /><br /><br /><br /><br />Since we know the y values are the same, column 1 would be y1 and column 3 would be y2.<br /><br />This would leave column 2 as x1 and column 4 as x2. This works since each row starts where the previous row left off. Note that to find the width, just subtract xpos1 from xpos2 and to find the height, subtract ypos1 from ypos2.<br /><br /><br /><br />The only reason this was any problem, is that the Intel machines are little endian, the built-in readUint16() gave results that were way too high to be screen positions. Therefore, an extra processing function was needed to make the calculation.<br /><br /><br /><br />Here is an example from the internet (devx.com) showing a conversion between little endian and big endian.<br /><br /><br /><code><br /><br /><br />int SHORT_little_endian_TO_big_endian(int i)<br /><br />{<br /><br /> return ((i>>8)&0xff)+((i << 8)&0xff00);<br /><br />}<br /><br /><br /><br /><br /></code><br /><br />Here was my own coded solution that reads one byte at a time while parsing through the binary file:<br /><br /><code><br /><br /> highb = inf.ReadByte()<br /><br /> lowb = inf.ReadByte()<br /><br /> highb = (highb * &H100&)<br /><br /> ypos1 = highb + lowb<br /><br /></code>theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0tag:blogger.com,1999:blog-4727570126287411168.post-63566233463676347692008-10-09T16:56:00.006-04:002008-10-09T18:41:43.325-04:00sharing JSON between web page and serverI've created an App Engine application that uses a field in it's model to store a JSON. This application uses Django and simpleJSON. I wrote my own Javascript framework for App Engine, which I'll try to publish so people can use it. I looked at Prototype and some others but wanted more control since I don't think the browser DOM's are all that hard for simple ajax effects and requests. However, if I must use drag and drop, I will probably enlist the help of a framework. So far I have avoided drag and drop.<br /><br />The place I want to start out is with JSON. My application is like a project that plays the movie and the movie is the JSON, it is the data.<br /><br />I started with the example from <a href="http://oreilly.com/catalog/9780596101619/toc.html"> "Google Maps Hacks" By Rich Gibson, Schuyler Erle </a><br /><br />Which was a good placeto start dealing with the Google Maps API and building HTML files that run it. The book is several years old already, so I had to update to the Version 2 maps.<br /><br />An example of an active Javascript Object on a page with a google map can be seen at <a href="http://igargoyle.com/slideshow.html"> igargoyle.com </a> and then view the source for the myObj object.<br /><br /><code><br />var myObj = {"photos": [<br /> {"img": "http://igargoyle.com/theman.jpg",<br /> "longitude": "-119.236402821", "latitude": "40.754786911",<br /> "title": "Black Rock City: 2005",<br /> "description": "A Playa Slideshow using Google Maps. Just email this to your friends, and when it loads, it will start playing automatically."},...]}<br /><br /></code><br /><br />This is an example of a JSON object being used in HTML script. Notice that it is an object named myObj which contains and array named photos. To retrieve the longitude of the ith element in the array (only the first element is shown above) use<br /><br /><code><br />longitude = myObj.photos[i].longitude;<br /></code><br /><br />If you have a script to run in the browser or any kind of a states to chose between, if the data is in an array index data structure, each item can be accessed directly by it's index. Arrays are very fast for these sorts of finds, where the number is known. Arrays are not so good if searching for a key needs to be done. If your data fits an array, it will work good as a Javscript object. Think of this object as something that is loaded into the client browser memory when the html page loads. It is then ready to be used to update the page display on user requests and/or timing events. This memory object really only needs the subset of information that the given page may require. No need to put everything from your database on the server in the page. Manipulation can be done in the server side code to send only the data needed by the page. This keeps it small, fast and efficient.<br /><br />Now that there is a Javascript object in memory on the web page, the web page could have some editing features, to update/change the object. It then needs to be POSTed back to the App Engine server and saved in the datastore. To get the object out of memory, just write it to a hidden (or not hidden) form!<br /><br />here is a javaScript function that does just that:<br /><br /><code><br />function myObj2string() {<br /> var newString =JSON.stringify(myObj);<br /> document.getElementById('JSONbox').value = newString;<br />}<br /></code><br /><br />the JSONbox element should be in the body:<br /><blockquote><code><br /><textarea id="JSONbox" name="JSONbox" value="" rows="5" cols="60" style="visibility: visible;"> </textarea></code><br /></blockquote><br />Now that we have captured a Javascript object in a form box, it can be POSTED to the server and stored in Big Table.<br />This is in the python code<br /><code><br /><br /><br /> modelEntity.way = request.POST['JSONbox']<br /> db.put(modelEntity)<br /><br /><br /></code><br /><br />When the model was built (model.py) for modelEntity, a field for the JSON was included as a TextProperty() which has so far worked well for me.<br /><code><br />way = db.TextProperty()<br /></code><br /><br />Now that JSONs can be created and stored, to retrieve it and use it, follow these steps.<br /><br />in django views (python server code):<br /><code><br />def play(request, modelEntity_key):<br />...<br />newStr = modelEntity.way<br />...<br />return respond(request, user, 'viewer', {'ways':newStr})<br /><br /></code><br /><br />notice the resonse will call the viewer.html template and pass a context containing newStr which will be called ways. Django passes data to the templates by giving it a context. A context is simply a set of variables and their associated values. A template uses this to populate its variable tags and evaluate its block tags.<br /><br />putting JSON back into an html page via a Django template:<br /><br /><code><br />var myObj = {{ ways }} ;<br /><br /></code><br /><br />If the model instance has been passed to the template (eg a context like this: {'modelName':modelEntity} ) the JSON can be pulled directly out of it's model and rendered in the HTML (again this is the Django template):<br /><br /><code><br /><br />var myObj = {{ modelName.way }} ;<br /><br /></code><br /><br />That should illustrate how easy it is to use JSON. It can be stringified and handled like a string on the server for storage purposes and then used by Django's template and context system where it is rendered in html and then loaded as an object into client memory!theaellenhttp://www.blogger.com/profile/10793736904919374465noreply@blogger.com0