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);
}
$("#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);
}
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:
mongolito404•Sunday, Feb 5th 2012 (over 12 years ago)
Hi, last year I made a similar PhoneGap application using Services 3.x on Drupal 6. The code is on github at https://github.com/pbuyle/DrupalGeoPicture.
John•Sunday, Feb 5th 2012 (over 12 years ago)
Checkout Mobile App Generator. Generates the html files from a drupal site.
http://drupal.org/project/mag
/shameless plug
Efrain Lugo•Thursday, Feb 16th 2012 (over 12 years ago)
Dude you are awesome! I've been trying to figure out a way to integrate Drupal and Phonegap and this is perfect! Thank you so much!
eiriksm•Thursday, Feb 16th 2012 (over 12 years ago)
Glad to be of help. And please feel free to add your own experiences if you are using the same drupal.js I do.
Nick•Monday, Apr 30th 2012 (over 12 years ago)
Hey, first off thanks for the tutorial, this stuff is really cool.
I'm having an issue, my post is returning:
POST 401 (Unauthorized)
I don't have User Authentication session on, and this remains true when I toggle the bypass content access permission for unauthed users(though its a terrible idea). Have any ideas?
Nick•Monday, Apr 30th 2012 (over 12 years ago)
Gah just had to enable some permissions under services... Thanks again
Nick•Sunday, May 6th 2012 (over 12 years ago)
When I delete the Article I posted, the content is removed, but the file (fancy.gif) remains inside my file system, any ideas? Thanks,
eiriksm•Sunday, May 6th 2012 (over 12 years ago)
As opposed to creating the files when being on a node form, you are in this example creating the files first, and then creating the node. You can look in the database to see the difference (the file_usage table in D7). When uploading the files via the node form, the file is "used" by a node. But when you create it through services, it is being "used" by services.
Not sure why it's not tracked the way you want it to. Have you tried the issue queue for services?
Alban•Tuesday, Jul 31st 2012 (about 12 years ago)
Hi,
First of all thanks for this useful example.
Do you have any idea if it is possible, and if so, how to attach and post 2 or more images on a same node ?
Thanks.
eiriksm•Tuesday, Jul 31st 2012 (about 12 years ago)
Sure. Just make sure the image field has a cardinality of more than 1. Then add stuff to the node_object array. Like this:
Alban•Tuesday, Jul 31st 2012 (about 12 years ago)
Thank you, it rocks!
Oscar•Wednesday, Dec 19th 2012 (almost 12 years ago)
Hi.
I'm testing this solution that looks good.
I have managed to send an image base64 encoded. This part goes fine for me. Yeahh..
Then I try to the same thing but with phonegap and taking a photo in this moment. You comets this option at the end of the tutorial.
But I have a problem.
A file is upload, yes. But the file uploaded have only about 80 kbs and, of course isn't the image.
How can I resolve this problem?
Do you think that I have to convert the photo to base65 before send it to Drupal?
Thanks for you help and congratulations for your web page!
Oscar•Thursday, Dec 20th 2012 (over 11 years ago)
Sorry.
I solved the problem adding "destinationType: Camera.DestinationType.DATA_URL
Thanks!
handoyo•Tuesday, Nov 19th 2013 (almost 11 years ago)
Hi there,i can't see or download your drupal.js file. :) Thanks
Sebas Lemieux•Wednesday, Jul 16th 2014 (about 10 years ago)
Do you happen to know if the image posted that way will use the parameters of your iamge field ?
I post images to an Image field by using services (from Lightroom), and it doesn't seems to use the folder I set in the field parameters. Same for the max resolution thing...
So I'm trying to figure out if it's a Service thing or linked to my particular case.
Thanks