Thursday, December 27, 2012

Solving erratic mouse behavior in Ubuntu 12.10 inside VirtualBox

My Ubuntu installation within a VirtualBox VM has been nearly unusable due to random, erratic behavior of the mouse cursor. Problems have included:
  •  a click near the middle of the screen activates a button in the launcher on the left side
  •  occasional hits on the exit button of a window, though the cursor was far from it
  •  inability to drag to select text; the selection would jump upward while I was trying to drag down
  •  other dragging operations would create unpredictable and unwanted results

I did research and found these two references:
http://askubuntu.com/questions/202789/cursor-jumps-when-moving-and-some-other-times
https://forums.virtualbox.org/viewtopic.php?f=3&t=51727&start=45

Based on these, I typed the following into the terminal.
sudo apt-add-repository ppa:a7x/bug1041063
sudo apt-get update
sudo apt-get install xserver-xorg-core

My initial tests show this to be a successful fix for the problems listed above.

Monday, November 5, 2012

Dell Optiplex 780 noise after upgrading to Windows 7

I just finished upgrading my Dell Optiplex 780 to Windows 7 64-bit.  The tower was producing a very irritating high-pitched noise after this upgrade.  After a bit of searching, I found this discussion that seemed to match my problem:
http://en.community.dell.com/support-forums/desktop/f/3514/p/19292677/19546282.aspx

I tested the BIOS setting change for C State Control suggested by carl.hobbs and petewitt.  It solved the problem instantly.


Thursday, October 11, 2012

Drupal REST process update

I posted earlier about the problems I have had integrating Drupal 7 REST with an external site.  Since my last post on the topic,  it has been working flawlessly.

Today, though, I upgraded the Drupal site to use Services 7.x-3.2, and configured the site to require TLS for all traffic.

The REST connection died with no explanation.

After an hour of stressful debugging, I found two separate causes:

1. The upgrade of the Services module reset the REST resources settings. I had to re-enable parsing of application/x-www-form-urlencoded  and the node resource. http://stackoverflow.com/questions/8535820/drupal-login-via-rest-server

2. Requiring all traffic to route through https (TLS) killed the PHP cURL methods.  For a debugging quick fix, adding curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); solved the problem. For a better solution, see http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/

Thursday, August 23, 2012

Google Maps API 3 inside jQuery Accordion

I am working on a web page that utilizes multiple JS libraries including jQuery and Google Maps. My map is inside a jQuery Accordion pane, and has been presenting a problem with partial rendering as described on a StackOverflow topic. In my case, the code was configured to initialize the map at the time of the first click on the accordion panel that contained the map. It worked fine, unless the user switched to a different pane then tried to return to the map. Then, it would only draw approximately 1/4 of the map canvas, with the remainder being gray.

In my research, calling google.maps.event.trigger(map, "resize"); was a consistent suggestion, but the first few locations I tried calling it did not work. I finally solved the problem by binding the trigger to the click event of the jQuery Accordion pane, based on an example at essentialwebconcepts.com.

My code:
function triggerMapResize()
    {
    google.maps.event.trigger(map, "resize");
    }

jQuery(document).ready(function() {
    jQuery("#the-accordion").bind('accordionchange', function(event, ui) {
        if (ui.newContent.attr('id') == 'the-pane-id')
            {
            triggerMapResize();
            }
        });
    });
The only remaining problem is that the center of the map changes when the user returns to the map pane after looking at a different pane.  I started a topic on SO for this issue.

Update August 24:
Several changes were required to get this to work on all browsers including IE. IE failed upon page load when I was trying to initialize the map. Originally I was using window.onload = function () { initialize_map(); } but that resulted in a vague IE error.

I added code to capture the map's center LatLng when the user moves the mouse outside the map canvas, and more code to move the center to that point upon returning to the map.

          var map=null;
    var currMapCenter = null;

    jQuery(document).ready(function() {
    jQuery("#accordion").bind('accordionchange', function(event, ui) {
    if (ui.newContent.attr('id') == 'region-list')
    {
    if(map==null) {
    //first load; call map initialization
    initialize_map();
    }
    triggerMapResize();
    }
    });

    function initialize_map() {
   
    //do initialization here...
   
    google.maps.event.addListener(map, 'mouseout', function() {
    currMapCenter=map.getCenter();
    });
    }

    function triggerMapResize() {
    google.maps.event.trigger(map, "resize");
    map.setCenter(currMapCenter);
    }

A side note about another problem I ran across in IE8 that has limited documentation online: When creating LatLng arrays, double-check syntax to be sure there is no comma after the final element. While the map looked perfect in standards-compliant browsers, in IE8 each polygon had a segment extending up to near the North Pole.

var polygonPoints= [
        new google.maps.LatLng(24.3250983277945,-79.4028109345145),
        new google.maps.LatLng(48.9377507851552,-142.984008088915),
        new google.maps.LatLng(37.9247004907078,-131.891417410329),
        new google.maps.LatLng(29.8055038628199,-122.143142289543),
        new google.maps.LatLng(21.6909424687438,-114.135809333967),
        new google.maps.LatLng(24.3250983277945,-79.4028109345145),
        ];

This mistake cost me an hour of confusion. Finally I found a discussion mentioning trailing commas with Google Maps in Internet Explorer and discovered the improper extra comma at the end of each array.   It was caused by creating the LatLng object using concatenation in Excel without manually trimming the last value.

Saturday, August 18, 2012

The power of introverts



I just finished reading Quiet, by Susan Cain. It is by far the best book I have read in a very long time. I can relate completely to her description of extroversion being prized by society, and quietness being condemned.  I have lived with such condemnation my entire life. I have even sought medical treatment to be "cured" of the affliction. This book made me aware that I am not alone in this. It has also given me a new perspective on my place and value in society.
 
This is worth sharing:
In a culture where being social and outgoing are prized above all else, it can be difficult, even shameful, to be an introvert. But, as Susan Cain argues in this passionate talk, introverts bring extraordinary talents and abilities to the world, and should be encouraged and celebrated.


I am very thankful to have finally found employment in an organization that has other people like me, and values my contribution and strengths rather than coercing me to be something I am not.  If only other groups of people in my life could be as understanding.

Wednesday, August 8, 2012

Capturing Facebook Atom feed via PHP cURL

I have been working on how to retrieve the RSS feed of our company Facebook page for inclusion in our website. Thanks to the answer by Francois Deschenes on a Stack Overflow topic, I have the beginnings of a functional solution:

$curl_handle=curl_init();
curl_setopt($curl_handle, CURLOPT_URL,"https://www.facebook.com/feeds/page.php?format=atom10&id=111111111111111"); curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT,5);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER,1);
curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl_handle, CURLOPT_USERAGENT, array('User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Safari/534.45'));
curl_setopt($curl_handle, CURLOPT_VERBOSE, true);
$buffer = curl_exec($curl_handle);
curl_close($curl_handle);

if (empty($buffer))
    {
    print "Sorry, request failed.";
    }
else
    {

    (do stuff with the feed)
           }

I will update this posting as this project progresses.


Wednesday, July 25, 2012

Google Maps API multiple markers and infowindows

I was having trouble with binding InfoWindows to markers. No matter which marker was clicked, the InfoWindow for the last marker to be created was displayed.  I found the answer to the problem here:
http://stackoverflow.com/questions/2357323/trying-to-bind-multiple-infowindows-to-multiple-markers-on-a-lgoogle-map-and-fail

Simply creating a separate function to add the event listener solved the problem.

Wednesday, July 18, 2012

January Drupal frustration solved.

I posted on January 16 about problems integrating Drupal 7 with an external website. I had to set it aside and work on other things until this week. I finally located the cause of the problem today. As are most time-consuming problems, this had a simple solution. I just had to step away from it long enough to reset, then look through the code with a fresh outlook.

The culprit in this case was running the Drupal login function targeted at http://www.mydomain.com, but then trying to retrieve the Drupal node from http://mydomain.com. Since the domain didn't match, my session auth failed.

Sunday, May 27, 2012

Quotes from James Dyson

I recently read an interview with Sir James Dyson. There were two quotes from him in it that really struck a chord with me.

"I don't care how long things take. Failure is to be celebrated - that is how we learn ... We invest in and rejoice in failure, and we stick at it. I learned from each of my mistakes. That's how I came up with a solution."

Many people think I am a perfectionist, but I don't see myself that way. Things must be as good as possible - but that doesn't require perfection at stage one. This quote states my thoughts about software development and programming very well:

"'Perfect' is in fact the completely wrong word to use. You start with a goal and you make the best possible version you can make at that moment. You give the customer the best available at that moment, and then you set another goal and start working on it again." 

He may invent and engineer vacuums and other mechanical devices, but his words make good sense for software architecture as well.




Wednesday, May 16, 2012

JavaScript references

I just found Chris Shiflett's April 26 posting with a great list of references for JavaScript. The first one I have started reading is "JavaScript for PHP Developers" by Stoyan Stefanov. It is one of the most clear and concise descriptions I have found to date as I try to apply my knowledge of other programming languages to JavaScript.

Thursday, April 19, 2012

Avian neighbors

I was able to telecommute today. The weather was perfect and the birds were active. I kept the window open and enjoyed the fresh air and bird songs drifting in.

I kept my camera by my computer and got a few photos of my avian neighbors on the feeder outside my window and in the tree.





Saturday, April 7, 2012

Opinions

Thought for the day: "Opinions have caused more ills than the plague or earthquakes on this little globe of ours." - Fran̤ois-Marie Arouet de Voltaire, 1694 Р1778.

How true.  One of the things I enjoy about writing software is that it involves solely logic and math, in a highly creative manner.

The effectiveness of a UI is certainly subject to opinion, and the methodology used in coding could be debated as well. However, the inner workings of a program are immune to such problems. It either works, or it doesn't.

My work, in a way, is an escape from the pressures of society, in which ignorant prejudices frequently trump reality.

Wednesday, April 4, 2012

The waste of free time

I am currently reading Flow by Mihaly Csikszentmihalyi. It is very interesting - many things I have never thought of, along with many things that make me say "of course!"

Page 162 contains the most concise and clear conveyance of my views that I have ever seen. In part: "The tremendous leisure industry that has arisen in the last few generations has been designed to help fill free time with enjoyable experiences... instead of using our physical and mental resources to experience flow, most of us spend many hours each week watching celebrated athletes playing in enormous stadiums. Instead of making music, we listen to platinum records cut by millionaire musicians...This vicarious participation is able to mask, at least temporarily, the underlying emptiness of wasted time. But it is a very pale substitute for attention invested in real challenges...The energy that could be used to focus on complex goals, to provide for enjoyable growth, is squandered on patterns of stimulation that only mimic reality...Mass leisure, mass culture... are parasites of the mind. ... Their purpose is to make money for someone else. If we allow them to, they can suck out the marrow of our lives, leaving only feeble husks... 'The future,' wrote C.K. Brightbill, 'will belong not only to the educated man, but to the man who is educated to use his leisure wisely'."

Thank you, Dr. Csikszentmihalyi.

As I reach the years of my upper thirties, I am increasingly needing to find ways to understand myself better. It is very helpful to find expressions of others who have already been in the place I find myself now.

Back to something more challenging than typing a blog post...

Thursday, March 15, 2012

JS OOP and kestrel nest box research

Today's goal is to implement JavaScript objects.  I am familiar with OOP in Flex(ActionScript), PHP and other languages from years ago. However, JavaScript's lack of classes will require some re-routing of my neural circuitry.

I am starting my research with these two articles by Douglas Crockford:

The first object I have to create is to represent a kestrel nest box. (Want to build one? - A real box, not a JS object to represent one- Instructions here)  The box has parameters including height, width, depth, height off ground, entrance diameter, direction the entrance faces, what the box is mounted on, and more.

My current project will allow researchers across North America (and maybe South America too) to track data from their kestrel boxes. Using OOP and MVC methods will be essential to keep the software flexible enough to satisfy the preferences of such a diverse audience and allow future expansion of the project.

Update 10:35

More valuable references:
https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects
https://developer.mozilla.org/en/JavaScript/Guide/Details_of_the_Object_Model
https://developer.mozilla.org/en/JavaScript/Guide/Inheritance_Revisited

Update 17:40

I successfully met my goal. In some ways it was easier than expected, but at the same time, a bit confusing. My object is created simply by retrieving the parameters from the database, via jQuery's Ajax functionality, as JSON.

var request = $.ajax({
    url: "getBoxParams.php",
    type: "POST",
    data: {id : nestBoxClicked, user: userToken},
    dataType: "JSON"
    });

request.done(function(boxData) {
     var kbox=new nestBox(boxData);                    
     populateBoxForm(kbox);
     });


Then, I manipulate the object properties in the populateBoxForm() function.

I still prefer working with strongly typed languages and classes, but it appears JavaScript can do what I need for a fully-functional web app, without losing speed or user-friendliness.

Douglas Crockford's article about JavaScript code conventions is another good resource I found today. 

Wednesday, March 14, 2012

Miscellaneous notes and thoughts

While working on integrating an instance of SlickGrid into a project file today, I discovered that all the rows had white backgrounds. In all the examples, the rows alternate colors for easier reading.  It took a while, but I traced the problem down to a conflict in the CSS for .ui-widget-content .  After adding the following to a .css file that loads at the end of the queue, my SlickGrid now has alternating gray and white rows as needed:

.ui-widget-content.slick-row.odd
    {
    background-color:white;   
    }
.ui-widget-content.slick-row.even
    {
    background-color:rgb(250,250,250);   
    }

The current problem I am working on is the inconsistent alignment and width of SlickGrid headers and their associated data cells. It is similar to the problem shown here: http://stackoverflow.com/questions/8559487/slick-grid-header-row-cell-alignment

Update 12:20

What appears to be happening is that the column width is set, for example, to 50. However, the elements added for the sortable and resizable properties add width to the header (about 10 pixels), but not to the cell.



Strangely, it very always becomes properly aligned if I hold down the shift key and refresh the page, even though no changes are made to code or CSS between page loads.

If I set the resizable and sortable properties to false, then everything consistently aligns properly on every page load/refresh.
Update 16:05 

I have spent much of today researching this error, with little advancement.  I tried to rebuild and reproduce the problem in jsfiddle.net, but it aligned properly there.  I tend to think that the cause is related to browser rendering and CSS caching or interpretation. It has been tested on Mac and Windows in Firefox, Chrome and IE. The misalignment is not consistent or predictable.  In Firefox, if I first use Chris Pederick's Web Developer toolbar to clear the cache, the SlickGrid always loads with proper alignment.

So far I am impressed by the capabilities of SlickGrid. My current project has so many jQuery plugins, other modules and CSS files there are bound to be conflicts.

Update 18:50

I haven't been able to consistently reproduce the problem discussed above, so I have moved on. I am now working on retrieving data from the database via jQuery ajax. In the past I have always written my own ajax functions, but have decided to go with jQuery for this project since its requirements may eventually grow beyond the simple tools I have previously built.

So far, the method has been very simple. I need the ajax to be called when a user clicks on a row in the SlickGrid.  In the grid's setup JS, I added:

grid.onClick.subscribe(function(e, args) {
        var cell = grid.getCellFromEvent(e);
        var rowClicked=cell.row;
        var clickedItem = gridData[rowClicked].id;

        var request = $.ajax({
              url: "myScript.php",
              type: "POST",
              data: {id : clickedItem},
              dataType: "html"
            });

            request.done(function(msg) {
              alert(msg);
              });

            request.fail(function(jqXHR, textStatus) {
              alert( "Request failed: " + textStatus );
            });
        });

Now I need to write PHP code to retrieve the specified record from the database, convert the data into JSON and send it back in order to populate the form for editing.

Wednesday, March 7, 2012

Thought for the day: Craftsmanship

It has always been important to me to try to get my projects' source code to be as organized and perfectly laid out as the visible user interface. Why? Partly because it makes future maintenance and upgrades easier, but there's also something to be said for pride of craftsmanship. Even though virtually no one is going to view the source of the websites and apps I design, there is value to me in knowing every part of the project is done as clean and artful as possible.

This concept was highlighted by a quote I read by Steve Jobs' biographer Walter Isaacson:
"One of the most important things he taught Steve was [that] it's important to be a great craftsman, even for the parts unseen. When they were building a fence, he said, 'You have to make the back of the fence that people won't see look just as beautiful as the front, just like a great carpenter would make the back of a chest of drawers ... Even though others won't see it, you will know it's there, and that will make you more proud of your design.'"
( source )

Now that I am using the Eclipse IDE for my work, I expect that making beautiful source code will be easier than ever.

The day's work awaits... Today I will return to working on a GIS UI in JavaScript and PHP, with jQuery and the Google Maps API.

Friday, March 2, 2012

Migrating to Eclipse

My current work project, true to the nature of projects, has become more intensive than expected.  I have made it through several ASP and PHP projects with minimalist development environments, but my current mix of PHP with Javascript, including jQuery and multiple plugins for it, is too much to handle efficiently in a plain text editor.

I realized yesterday afternoon that every time I have built a major application, I have had some sort of IDE to work in. Early on, it was Visual Basic 6. I did a lot of PHP work in Dreamweaver, which is adequate for that.  Later I dove into Flex, and Adobe's IDE was good to work with.

I had explored Eclipse at some point but never had reason to follow through on it until now. I started downloading and configuring it yesterday and have spent many hours since then trying to get the pieces working.  Here are a few items I have found, in hopes it can assist others on the same voyage:

Major components I am using:
  1. SQL Explorer
  2. PHP Development Tools
  3. Target Management (RSE)
  4. Javascript IDE
  5. EGit
My first goal is to install Git, since apparently Eclipse requires a version control system. That is another thing that is new, and something I have been trying to get established for a few years. So far, it is going well, and I am looking forward to the enhanced efficiency it will bring, even though I don't currently work in an Agile team. Here are some Git references that have helped me to make progress:

This morning I had an urgent request from a colleague to update some content in a database. I tried to use Eclipse SQL Explorer to accomplish that and ran into a series of problems. The setup has been frustrating at best. There are a lot of partial instructions in the documentation, like 'download and install ____" but no clarification on where or how to do that.

My first hurdle was to locate the MySQL driver it required. Finally I located a blog post somewhere that pointed me to http://dev.mysql.com/downloads/connector/j/  and I successfully downloaded the .jar file. I was expecting Eclipse to incorporate it somewhere, but evidently it just points to it, so download it to a location where it can reside permanently.

The next confusion was how to connect to the database.  I have used several front end clients for databases over the years, and all had specific fields for server IP/domain, port, and other parameters. It took a couple of hours to figure out what Eclipse requires. I filled in the fields as well as I could guess, but kept getting the error to "check your url."  I copied what I thought was the URL directly from my other database client, so I knew it was correct.  What I didn't know was that Eclipse, rather than providing fields for all the parameters,  uses a single string with embedded parameters and calls it the URL.  I finally located http://www.sqlexplorer.org/connections.php and ccopied the example there, creating a string like jdbc:mysql://mydomain.com:3306/myDBname.  It let me in. I still have not figured out what the "Example URL" is for in the MySQL driver setup window. The page at http://www.sqlexplorer.org/drivers.php shows it filled in with pseudocode, but doesn't explain it in the text.  I guess users are supposed to understand that the "example URL" is supposed to show us how to create the real URL in the connection parameters?  Unfortunately, when I loaded the driver, that field remained blank so I had no clue what to do.

Now that I'm in, it's time to get to work on the Javascript and see what Eclipse can do...


Update 15:00

One more quirk regarding MySQL in SQL Explorer: I wasn't able to view table contents in a grid like I am familiar with. I located a post in a forum that indicated the documentation showed an obsolete  method. I found that the three icons in the upper left of the SQL editor produce different results. I had been using the blue one, which returned the data in long strings. The first one in the row returns data into a grid. Now, to see if there is a way to edit that data.

Monday, February 27, 2012

Working notes February 27

8:30 a.m.
I am working on the Google Maps API 3 again today. One of my goals is to allow users to use their preference of geographic coordinates to locate a spot on the map.

References I have found:

Friday, February 24, 2012

Working notes February 24, 2012: Google Maps API

Today's focus is on creating a user interface for the Google Maps API.  Using basic HTML5, Javascript and the Google Maps API 3, I set out to create a reference of three methods for creating markers on a map, each with different properties.

Here is the source code of the result:
<!DOCTYPE HTML>

<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var geocoder = new google.maps.Geocoder();
var theMap;

function geocodePosition(pos) {
  geocoder.geocode({
    latLng: pos
  }, function(responses) {
    if (responses && responses.length > 0) {
      updateMarkerAddress(responses[0].formatted_address);
    } else {
      updateMarkerAddress('Cannot determine address at this location.');
    }
  });
}

function updateMarkerStatus(str) {
  document.getElementById('markerStatus').innerHTML = str;
}

function updateMarkerPosition(latLng) {
  document.getElementById('info').innerHTML = [
    latLng.lat(),
    latLng.lng()
  ].join(', ');
}

function updateMarkerAddress(str) {
  document.getElementById('address').innerHTML = str;
}

function initialize() {
      //initialize map with pin at Capitol & Front in Boise.
      var latLng = new google.maps.LatLng(43.61351466, -116.203798);
      theMap = new google.maps.Map(document.getElementById('mapCanvas'), {
        zoom: 13,
        center: latLng,
        mapTypeId: google.maps.MapTypeId.HYBRID
      });
     
      var marker = new google.maps.Marker({
        position: latLng,
        title: 'Initialization marker',
        map: theMap,
        draggable: true
      });
     
      // Update current position info.
      updateMarkerPosition(latLng);
      geocodePosition(latLng);
     
      // Add dragging event listeners.
      google.maps.event.addListener(marker, 'dragstart', function() {
      updateMarkerAddress('Dragging...');
      });
     
      google.maps.event.addListener(marker, 'drag', function() {
      updateMarkerStatus('Dragging...');
      updateMarkerPosition(marker.getPosition());
      });
     
      google.maps.event.addListener(marker, 'dragend', function() {
      updateMarkerStatus('Drag ended');
      geocodePosition(marker.getPosition());
      });
     
      //add click listener for new marker http://stackoverflow.com/questions/7083264/google-maps-api-v3-set-marker-and-get-point
      google.maps.event.addListener(theMap, 'click', function(e) {
      placeMarkerByMapClick(e.latLng, theMap);
      });
}

function addMarkerByExternalButton()
    {
        //alert("addMarker");
        var latLng = new google.maps.LatLng(43.60283295462482, -116.19584164278416);
        //var theMap = google.maps.Map(document.getElementById('mapCanvas'));
        var blueMapMarker = "http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png";
               
        // Set up our GMarkerOptions object
        markerOptions = {  };
        
        http://stackoverflow.com/questions/4236522/google-maps-api-v3-info-window-displaying-same-information-for-all-the-markers
        var contentString_1 =  "<b>BSU Broncos Stadium</b><br /> Boise, Idaho, USA<br><b><a href='http://broncosports.com'>BSU Athletics site</a></b><br /><img src='http://image.cdnllnwnl.xosnetwork.com/fls/9900/images/facilities/new_turf.jpg' />";
        var infowindow_1 = new google.maps.InfoWindow({content: contentString_1});
        
        
        var newMarkerFromExtButton = new google.maps.Marker({
            position: latLng,
            title: 'Marker added by external button',
            map: theMap,
            icon: blueMapMarker,
            animation: google.maps.Animation.DROP,
            draggable: false
            });

        newMarkerFromExtButton.setMap(theMap);
        
        // Update current position info.
        updateMarkerPosition(latLng);
        geocodePosition(latLng);
          
        // Add dragging event listeners.
        google.maps.event.addListener(newMarkerFromExtButton, 'dragstart', function() {
        updateMarkerAddress('Dragging...');
        });
          
        google.maps.event.addListener(newMarkerFromExtButton, 'drag', function() {
        updateMarkerStatus('Dragging...');
        updateMarkerPosition(newMarkerFromExtButton.getPosition());
        });
          
        google.maps.event.addListener(newMarkerFromExtButton, 'dragend', function() {
        updateMarkerStatus('Drag ended');
        geocodePosition(newMarkerFromExtButton.getPosition());
        });
        
        //add other listeners
        google.maps.event.addListener(newMarkerFromExtButton, 'click', function() {
        infowindow_1.open(theMap,newMarkerFromExtButton);
        });
        
    }


//reference http://stackoverflow.com/questions/7083264/google-maps-api-v3-set-marker-and-get-point
function placeMarkerByMapClick(position, map) {
    //alert("placeMarker");
    var yellowMapMarker = "http://www.google.com/intl/en_us/mapfiles/ms/micons/yellow-dot.png";
     
    var newMarkerFromMapClick = new google.maps.Marker({
        position: position,
        map: map,
        title: "marker added by map click",
        icon: yellowMapMarker,
        animation: google.maps.Animation.DROP,
        draggable: true
        });
   
    // Update current position info.
    updateMarkerPosition(position);
    geocodePosition(position);
   
     
    // Add dragging event listeners.
    google.maps.event.addListener(newMarkerFromMapClick, 'dragstart', function() {
    updateMarkerAddress('Dragging...');
    });
     
    google.maps.event.addListener(newMarkerFromMapClick, 'drag', function() {
    updateMarkerStatus('Dragging...');
    updateMarkerPosition(newMarkerFromMapClick.getPosition());
    });
     
    google.maps.event.addListener(newMarkerFromMapClick, 'dragend', function() {
    updateMarkerStatus('Drag ended');
    geocodePosition(newMarkerFromMapClick.getPosition());
    });
     
    //next line centers the map on the newly created marker. Disabled since the movement is a bit annoying.
    //map.panTo(position);
    }
     

function addMarkerByTypedCoords()
{
    //alert("addMarker");
    var lat=document.getElementById("lat").value;
    var lon=document.getElementById("lon").value;
   
    var latLng = new google.maps.LatLng(lat, lon);
    //var theMap = google.maps.Map(document.getElementById('mapCanvas'));
    var greenMapMarker = "http://www.google.com/intl/en_us/mapfiles/ms/micons/green-dot.png";
    // Set up our GMarkerOptions object
    markerOptions = { };

    var markerContent =  document.getElementById("markertitle").value;
    var infowindow_1 = new google.maps.InfoWindow({content: markerContent});

    var newMarkerFromTypedCoords = new google.maps.Marker({
        position: latLng,
        title: 'Marker added by typed coordinates',
        map: theMap,
        icon: greenMapMarker,
        animation: google.maps.Animation.DROP,
        draggable: true
        });
   
    newMarkerFromTypedCoords.setMap(theMap);
   
    // Update current position info.
    updateMarkerPosition(latLng);
    geocodePosition(latLng);
   
    // Add dragging event listeners.
    google.maps.event.addListener(newMarkerFromTypedCoords, 'dragstart', function() {
    updateMarkerAddress('Dragging...');
    });
   
    google.maps.event.addListener(newMarkerFromTypedCoords, 'drag', function() {
    updateMarkerStatus('Dragging...');
    updateMarkerPosition(newMarkerFromTypedCoords.getPosition());
    });
   
    google.maps.event.addListener(newMarkerFromTypedCoords, 'dragend', function() {
    updateMarkerStatus('Drag ended');
    geocodePosition(newMarkerFromTypedCoords.getPosition());
    });
   
    //add other listeners
    google.maps.event.addListener(newMarkerFromTypedCoords, 'click', function() {
    infowindow_1.open(theMap,newMarkerFromTypedCoords);
    });
   
    theMap.panTo(latLng);
    }

    
// Onload handler to fire off the app.
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
  <style>
  #mapCanvas {
    width: 800px;
    height: 800px;
    float: left;
  }
  #infoPanel {
    float: left;
    margin-left: 10px;
  }
  #infoPanel div {
    margin-bottom: 5px;
  }
  </style>
 
  <div id="mapCanvas"></div>
 
  <div id="infoPanel">
      <p>NOTE: Marker generated at map initialization is red.</p>
      <hr />
      <h3>Current marker information</h3>
      <b>Marker status:</b>
      <div id="markerStatus"><i>Click and drag the marker.</i></div>
      <b>Current position:</b>
      <div id="info"></div>
      <b>Closest matching address:</b>
      <div id="address"></div>
      <hr />
     
      <h3>Method 1: Add a predefined location marker</h3>
      <p>Marker will be blue. Click the blue marker to get an info window with photo.</p>
      <button onclick="addMarkerByExternalButton()"> Add marker at BSU Stadium</button>
     
      <hr />
      <h3>Method 2: Add new marker from manually entered coordinates</h3>
      <p>Marker will be green</p>
      <form id="typedcoords">
          <fieldset>
          <legend>Type coordinates to add a new marker</legend>
          <label for="lat">Title your new marker:</label>
          <input type="text" name="markertitle" id="markertitle" /><br />
          <label for="lat">Latitude (decimal degrees)</label>
          <input type="text" name="lat" id="lat" /><br />
          <label for="lon">Longitude (decimal degrees)</label>
          <input type="text" name="lon" id="lon" />
          <br />
          <button id="addMarker" title="Add Marker" type="button" onclick="addMarkerByTypedCoords()">Add Marker</button>
          </fieldset>
      </form>
      <hr />
     
      <h3>Method 3: Click map to create new marker</h3>
      <p>Marker will be yellow</p>
      <p>Just click anywhere on the map to create a simple new marker</p>
 
  </div>
</body>
</html>
This example has been tested successfully in Firefox 10 and Safari 5.1 on Mac, and IE and Firefox on Windows XP

References utilized to create this example:

http://code.google.com/apis/maps/documentation/javascript/reference.html

http://code.google.com/apis/maps/documentation/javascript/overlays.html#Markers

http://stackoverflow.com/questions/4236522/google-maps-api-v3-info-window-displaying-same-information-for-all-the-markers

http://code.google.com/apis/maps/documentation/javascript/overlays.html#SimpleIcons

http://groups.google.com/group/google-maps-js-api-v3/browse_thread/thread/5865e223d316b238/e221a5a33c7775d3?pli=1

I'll be working with the GM API for several days, and will likely add more examples as I progress through this project.

Tuesday, February 14, 2012

Working notes for February 14, 2012

Today I am working on integrating SlickGrid into a project. So far, so good.

One task this has required is the insertion of a new CSS file into the page. My project structure displays all content inside of a single PHP file based on URL parameters. Therefore, when individual pages require special CSS, I need to make that happen within the page, not in the wrapper, to avoid unnecessary bandwidth usage.

Here is some Javascript that will load a CSS file into the page's header when called in the body:

<script type="text/javascript">
var fileref=document.createElement("link");
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", "thedir/thefile.css");
document.getElementsByTagName("head")[0].appendChild(fileref);
</script>

Friday, February 3, 2012

Working notes Feb. 3, 2012

I am so thankful to be able to work from my home office on occasion. I can create the ideal atmosphere for maximum productivity. That's where I am today, and things are coming together nicely so far.

Today, I am working on integrating an Elgg social network installation with a custom-built PHP/JS/jQuery/MySQL site for a continent-wide, and potentially worldwide, research project.

Step 1 is to get the main site to check the user's login status in the Elgg site. Being logged into Elgg will open access to multiple tools not available to the public.

Based on example code provided by Steve Clay, I have been able to access the Elgg session data for a user and return a string to tell the user they are logged in.

<?php
/*require a PHP PDO database instance here */

$elggstatus=$_COOKIE["Elgg"]; //capture the session ID

if($elggstatus)
    {
    $user_id = 0;
    $sql = ("SELECT `data` FROM `elgg_users_sessions` WHERE `session` = :sessVal");
    $params=array("sessVal"=>$elggstatus);
   
    $elggUser=$thePDO->thePDOselectfunction($sql,$params);
   
    $userData=$elggUser[(dissect your PDO data structure here)];

        $userData=explode('attributes";', $userData); //split the user object after the attributes segment

        $userData=unserialize($userData[1]); //use PHP's unserialize() function to convert the data back to a PHP value
                      
        $userDisplayName=$userData["name"]; //capture the user's "display name"
    print "You are logged in as $displayName";//provide the feedback to the user.
    }
?>
Update 12:00
I sure enjoy these rare occasions when everything falls into place.  Since my original posting I have been able to create a PHP class to communicate with Elgg and return user status and data.  By using this method I'll be able to extend the communication between Elgg and the main site as needed in the future.

It took a little while to get past some bumps in establishing a new PHP PDO MySQL class separate from the primary instance used for the other database, but once that was fixed it works fine.  The next step is to make sure this works regardless of which URL option the user chooses to access the site. (There is a subdomain that goes directly to it, or they can use a long URL including the primary domain + directory tree)

Update 14:25
No real surprise, what I thought was working earlier failed upon testing by a user.  Evidently Elgg returned the user object in a different order for different users, so the code I had posted earlier did not work.  I revisited Steve's example, found where I had taken a wrong turn, and revised my code. Now it accurately converts the stored value into a standard PHP array for easy and consistent parsing.  The code above has been edited to show my corrections.

Next goal: make Elgg write its session cookies so that it can be read from other subdomains.

Update 15:35
Since the last update, I have been working on trying to make the session cookie visible regardless of subdomain. No success.

I tried creating a new php.ini file in the Elgg root directory with this line:
session.cookie_domain=.mydomain.org
and logged in. My browser's cookie library showed that Elgg did properly set the cookie to be owned by .mydomain.com instead of mydomain.com as previously.

However, login now fails totally. When I try to log in, Elgg shows a red bar in the upper right corner saying 'you have to be logged in to see this file.' I had to disable my php.ini file to get my site back.

Back to researching...

Update 17:30
The joys of software architecture... nothing to show for the past 3 hours of work. I detailed my work to get a solution for cookie visibility across subdomains in a post on the Elgg community. With an immovable deadline looming and having lost 3 hours to fruitless research on the problem, I am considering changing the entire installation configuration to minimize the chance of problems. I had hoped to build Elgg into a multisite-capable system, since we have at least 5 different projects that could utilize its social networking functionality. Given that development of the multisite plugin appears to be inactive, I'll probably have to reconfigure my system to reside completely within a single subdomain to avoid these cookie issues. Maybe in the future a multi-site version of Elgg will be viable and I will reconfigure at that point in time.