Creating nodes with images using phonegap and services
A lot of different people has started experimenting with Phonegap and Drupal. You have Jeff Linwood and his Drupal plugin for Phonegap for iOS, and I just discovered Drupalgap as I was planning this post the last weeks, which does more or less (actually it does more, but not all) some of the same things I will try to do in this post.
If you want to get up and running real quick, Drupalgap seems great. If you want to learn the code behind it, and extend it yourself (this was my motivation), keep reading.
This post is dedicated to writing phonegap apps to post images to your nodes, right from your javascript. You just make an HTML file, include some javascript magic, and hey, we just posted images to our site using the camera on the phone.
As I have written a couple of posts now about posting content to your Drupal site from an app with the services module, I thought I should probably do a little more tutorial like post. I have started moving a lot of functions into a javascript file I call drupal.js that have several different methods of communicating with your Drupal services endpoint. Today I want to just scratch the surface, and provide a working example app.
To get this working on your site, follow these steps:
- Use Drupal 7 and services module v3.
- Enable the modules Services and REST server.
- Add a new services endpoint (under structure->services)
- Enter a path to the endpoint and select REST server. Also use session authentication if you want to log in.
- Add json as response formatter
- Enable the node, file and user resources.
- Be sure to have a content type enabled, and preferably with a body field and image field (for this example)
- Download the app and test it out!
The app can be found here (android, webOS, blackberry and symbian only. iOS will not be released, as this is just an example app that I don’t want to get into the app store).
Since this is a hobby-project at the moment, I don’t have very much time to do development on the js every day, but I will post back with more info on that in a later post. The thought is that you can run these functions from your html app, so you don’t have to write all the ajax calls yourself.
For example for nodes, you can do something like this:
var date = new Date();var timestamp = Math.round(date.getTime() / 1000);var node_object = { "type": prompt("Enter content type"), "title": prompt("Enter node title"), "body": { "und": [ {"value": prompt("Enter body text"); } ] }, "created": timestamp, "status": 1};url = "http://example.com/services/endpoint";drupalServicesPostNode(node_object, url, function() { alert('Node posted!');});
The last parameter is the success function (optional). There is also a standard success function in drupal.js, but it is just an alert to tell you that that it was a success.
Currently it supports logging in, logging out, posting nodes (also with posting files/pictures).
So let's go into a more detailed tutorial. To post pictures, you have to have a base64 encoded image. This is actually what you get back from Phonegap when accessing the camera, but just to watch the basics of posting nodes with images, try typing this into a click function for something (remember to be able to post cross domain javascipt and include drupal.js. And also, if you just include this code (and not logging in), remember to also be able to post as anonymous. Oh, and obviously, include jQuery)
$("#someid").click(function() { var data = "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"; url = "http://example.com/endpoint"; // Your services endpoint var data = { "file": data, "filename": "fancy.gif" }; drupalServicesPostFile(data, url, postwith);});function postwith(data) { var date = new Date(); var timestamp = Math.round(date.getTime() / 1000); var node_object = { "type": "page", // your content type "title": "My title", "body": { "und": { 0 : { "value": "Some body text" } } }, "field_image": { "und": { 0 : { //be sure to change this to your image field name "fid": data.fid, //this is the fid we got back from services "alt": "Some alt text", "title": "Some title text" } } }, "created": timestamp, "status": 1 }; url = "http://example.com/endpoint"; // Your services endpoint drupalServicesPostNode(node_object, url);}
What this does, is make a file called "fancy.gif", execute the success function postwith, which posts a node with the file id recieved from posting the image. Or more specifically: This would make a node with that pretty burning bird I have on my site. The crazy, long string there, is the base64 version of it. So let's take a look at how to do the same with a custom picture. I'll do something like this:
$("#someid").click(function() { navigator.camera.getPicture(picsuccess, onfail, { quality: 50 });});function picsuccess (data) { url = "http://example.com/endpoint"; // Your services endpoint var data = { "file": data, "filename": "test.jpg" }; drupalServicesPostFile(data, url, postwith);}
This shoots the file all the way to your Drupal site with the function drupalServicesPostFile (declared in drupal.js). Then it executes a success function called postwith, which is the same as above. drupalServicesPostNode does the rest. And then we go to our site and look at our fancy new picture node, created right from our phone's camera.
To check out my small javascript called drupal.js, you can go here
Hope this helps someone researching the same questions I did, and not finding the answers.
And to celebreate another exciting evening of javascipt, here is an exciting animation: