I am trying to use the google calender api inside a greasemonkey script. This is my code inspired from the google calender api tutorial:
// ==UserScript==
// #name Google Calender
// #namespace xyz
// #include *
// #version 1
// ==/UserScript==
var $ = unsafeWindow.jQuery;
API_js_callback = "https://apis.google.com/js/api.js";
var script = document.createElement('script');
script.src = API_js_callback;
var head = document.getElementsByTagName("head")[0];
(head || document.body).appendChild(script);
//this is not working
var gapi = unsafeWindow.gapi;
$(document).ready(function()
{
// Client ID and API key from the Developer Console
var CLIENT_ID = 'XXX';
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = "https://www.googleapis.com/auth/calendar.readonly";
handleClientLoad();
/**
* On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
function initClient() {
.........
}
});
Inside the handleClientLoad method, I got the following exception:
Cannot read property 'load' of undefined
Any idea?
The gapi library is injected after the document loads, therefore it hasn't loaded yet when the document is ready. The gapi-related code need to be run on script load, for example:
GAPI_js_src = "https://apis.google.com/js/api.js";
var script = document.createElement('script');
script.src = GAPI_js_src;
var head = document.getElementsByTagName("head")[0];
(head || document.body).appendChild(script);
script.onload = (function() {
var gapi = unsafeWindow.gapi;
// Client ID and API key from the Developer Console
var CLIENT_ID = 'XXX';
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = "https://www.googleapis.com/auth/calendar.readonly";
handleClientLoad();
/**
* On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
function initClient() {
.........
}
});
I need to Purge all my Images in my Website which is using AKAMAI CDN.
I have written the code for purging one file.
PFB the code for single file purging.
But my requirement is to purge all files in the website.
Can anyone suggest how to achieve this.
Thanks
//
// © 2016 WorldVentures. All rights reserved.
//
using Akamai.EdgeGrid.Auth;
using Akamai.Utils;
using CMS;
using CMS.DataEngine;
using CMS.DocumentEngine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(AkamaiPurge))]
public class AkamaiPurge : Module
{
// Module class constructor, the system registers the module under the name "CustomInit"
public AkamaiPurge()
: base("CustomInit")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
// Assigns custom handlers to events
DocumentEvents.Insert.After += Document_Insert_After;
DocumentEvents.Update.After += Document_Update_After;
DocumentEvents.Delete.After += Document_Delete_After;
}
/// <summary>
/// Will be triggered when any document is added
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Document_Insert_After(object sender, DocumentEventArgs e)
{
// PurgeCache();
PurgeCacheAkamai();
}
/// <summary>
/// Will be triggered when any document is Updated
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Document_Update_After(object sender, DocumentEventArgs e)
{
//PurgeCache();
PurgeCacheAkamai();
}
/// <summary>
/// Will be triggered when any document is Deleted
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Document_Delete_After(object sender, DocumentEventArgs e)
{
//PurgeCache();
PurgeCacheAkamai();
}
/// <summary>
/// Following function will invalidate cache from Akamai server
/// </summary>
public void PurgeCache()
{
string secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string clientToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string accessToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string apiurl = "https://akab-7t5mh54r7lq3a7d7-js5q6mdtx42qimcn.purge.akamaiapis.net/ccu/v3/invalidate/url/production";
List<string> headers = new List<string>();
string httpMethod = "POST";
string data = "{\"hostname\": \"www.qa.worldventures.com\",\"objects\": [\"www.qa.worldventures.com/getmedia/9931b92a-c7f3-4a71-ab27-37e2b13572c0/should-be-here.jpg?width=2541&height=1811&ext=.jpg\"]}";
Stream uploadStream = null;
uploadStream = new MemoryStream(data.ToByteArray());
var uri = new Uri(apiurl);
var request = WebRequest.Create(uri);
request.Method = httpMethod;
var signer = new EdgeGridV1Signer();
var credential = new ClientCredential(clientToken, accessToken, secret);
signer.Sign(request, credential);
using (var result = signer.Execute(request, credential))
{
using (result)
{
using (var reader = new StreamReader(result))
{
string value = reader.ReadToEnd();
}
}
}
}
/// <summary>
/// Following function will invalidate cache from Akamai server
/// </summary>
public void PurgeCacheAkamai()
{
string secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string clientToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string accessToken = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
string apiurl = "https://akab-7t5mh54r7lq3a7d7-js5q6mdtx42qimcn.purge.akamaiapis.net/ccu/v3/invalidate/url/production";
List<string> headers = new List<string>();
string httpMethod = "POST";
string outputfile = null;
string data = "{\"hostname\": \"www.qa.worldventures.com\",\"objects\": [\"www.qa.worldventures.com/getmedia/9931b92a-c7f3-4a71-ab27-37e2b13572c0/should-be-here.jpg?width=2541&height=1811&ext=.jpg\"]}";
int maxBodySize = 2048;
EdgeGridV1Signer signer = new EdgeGridV1Signer(null, maxBodySize);
ClientCredential credential = new ClientCredential(clientToken, accessToken, secret);
Stream uploadStream = null;
uploadStream = new MemoryStream(data.ToByteArray());
var uri = new Uri(apiurl);
var request = WebRequest.Create(uri);
foreach (string header in headers) request.Headers.Add(header);
request.Method = httpMethod;
Stream output = Console.OpenStandardOutput();
if (outputfile != null)
output = new FileInfo(outputfile).OpenWrite();
signer.Sign(request, credential, uploadStream);
using (var result = signer.Execute(request, credential, uploadStream))
{
using (output)
{
using (result)
{
using (var reader = new StreamReader(result))
{
string value = reader.ReadToEnd();
}
}
}
}
//using (var result = signer.Execute(request, credential))
//{
// using (result)
// {
// using (var reader = new StreamReader(result))
// {
// string value = reader.ReadToEnd();
// }
// }
//}
}
public void PurgeCacheAkamai2()
{
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create("https://akab-7t5mh54r7lq3a7d7-js5q6mdtx42qimcn.purge.akamaiapis.net/ccu/v3/invalidate/url/production");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string postData = "This is a test that posts this string to a Web server.";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
}
}
It depends on how you want to do it.
For example if you are still using CCU or Fast purge feature of akamai.
If you are using CCU or fast purge then best thing to do is, tag all your images to a dedicated CP Code.
Once done you can purge the CP Code which will intern purge all the images.
Few useful documents that you can refer for CCU:
https://developer.akamai.com/api/purge/ccu-v2/overview.html
For Fast Purge:
https://control.akamai.com/dl/customers/FIMA/Fast-Purge-QuickRef.pdf
https://github.com/akamai-open/api-kickstart/tree/master/examples
Thank,
Vinod
I'm using python script to dynamically change the content of my web-page. The link of the web page is: [HERE]
The web page contains table which has two columns:
1) Values between 1 to 5.
2) And the time when it is uploaded on the page.
It is displayed dynamically by the JavaScript on the page. See the source of the page opening the link above.
Now I'm creating a android application which displays the values in the text view by fetching that page and parsing the HTML. But the page source only contains JavaScript code. So whenever I fetch the HTML, it only displays the JavaScript even if it contains more than one rows with values.
My question is how to fetch those values dynamically?
I'm using AsyncTask and scheduling it every 10 seconds. My code is:
public class MainActivity extends AppCompatActivity {
TextView et ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (TextView) findViewById(R.id.editText);
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[]{"https://rasppiclient.herokuapp.com/"});
callAsynchronousTask();
}
public void callAsynchronousTask() {
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
DownloadWebPageTask performBackgroundTask = new DownloadWebPageTask();
// PerformBackgroundTask this class is the class that extends AsynchTask
performBackgroundTask.execute(new String[]{"https://rasppiclient.herokuapp.com/"});
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 10000); //execute in every 50000 ms
}
public class DownloadWebPageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
}
}
return response;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Toast.makeText(MainActivity.this,s,Toast.LENGTH_LONG).show();
}
}}
This does not work with DefaultHttpClient. What you could to is the evaluate the javascript and then get the content with AndroidJSCore.
JSContext context = new JSContext();
context.evaluateScript(yourJsString);
context.property("getWhatYouWantHere");
An example from the github looks like this
JSContext context = new JSContext();
context.evaluateScript("a = 10");
JSValue newAValue = context.property("a");
System.out.println(df.format(newAValue.toNumber())); // 10.0
String script =
"function factorial(x) { var f = 1; for(; x > 1; x--) f *= x; return f; }\n" +
"var fact_a = factorial(a);\n";
context.evaluateScript(script);
JSValue fact_a = context.property("fact_a");
System.out.println(df.format(fact_a.toNumber())); // 3628800.0
We are working on a greasemonkeyscript to pull data from an express server cross-domain.
(We found code which is working for a normal html site here:
)
Can you get this to work for greasemonkey?
(maybe with unsafeWindow ?)
app.js:
var express = require("express");
var app = express();
var fs=require('fs');
var stringforfirefox = 'hi buddy!'
// in the express app for crossDomainServer.com
app.get('/getJSONPResponse', function(req, res) {
res.writeHead(200, {'Content-Type': 'application/javascript'});
res.end("__parseJSONPResponse(" + JSON.stringify( stringforfirefox) + ");");
});
app.listen(8001)
greasemonkeyscript:
// ==UserScript==
// #name greasemonkeytestscript
// #namespace http://www.example.com/
// #description jQuery test script
// #include *
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js
// ==/UserScript==
function __parseJSONPResponse(data) { alert(data); } // ??????????
document.onkeypress = function keypressed(e){
if (e.keyCode == 112) {
var script = document.createElement('script');
script.src = 'http://localhost:8001/getJSONPResponse';
document.body.appendChild(script); // triggers a GET request
alert(script);
}
}
I've never used Express before, but that app looks to be returning code like:
__parseJSONPResponse("\"hi buddy!\"");
which is placed into a <script> node in the target-page scope.
This means that the Greasemonkey script must also place the __parseJSONPResponse function in the target-page scope.
One way to do that is:
unsafeWindow.__parseJSONPResponse = function (data) {
alert (data);
}
However, it looks like you control the Express app. If that's true, then don't use JSONP for this kind of thing. Use GM_xmlhttpRequest().
app.js might become:
var express = require ("express");
var app = express ();
var fs = require ('fs');
var stringforfirefox = 'hi buddy!'
app.get ('/getJSONPResponse', function (req, res) {
res.send (JSON.stringify (stringforfirefox) );
} );
app.listen (8001)
And the GM script would be something like:
// ==UserScript==
// #name greasemonkeytestscript
// #namespace http://www.example.com/
// #description jQuery test script
// #include *
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// #grant GM_xmlhttpRequest
// ==/UserScript==
document.onkeypress = function keypressed (e){
if (e.keyCode == 112) {
GM_xmlhttpRequest ( {
method: 'GET',
url: 'http://localhost:8001/getJSONPResponse',
onload: function (respDetails) {
alert (respDetails.responseText);
}
} );
}
}
Is there a way to make Phonegap's File API work just like same API works in browser?
I need same behavior as in browser: Tap on "Open file" button -> "Select File" dialog ->... -> Opening the file with FileReader Object.
Thank you!!!
UPDATE: I've found some solution. It opens File Dialog and it returns the name of the JS File Object. But when i pass that JS File Object to FileReader from PhoneGap - it doesn't open (onload listener never fires). What i do wrong?
Here's my Java:
package org.apache.cordova.example;
import android.os.Bundle;
import org.apache.cordova.api.CordovaInterface;
import android.content.Intent;
import android.net.Uri;
import android.webkit.ValueCallback;
import org.apache.cordova.CordovaChromeClient;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.DroidGap;
public class cordovaExample extends DroidGap
{
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
this.appView.setWebChromeClient(new FileAttachmentChromeClient(this, this.appView));
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage) return;
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
// openFileChooser is an overridable method in WebChromeClient which isn't
// included in the SDK's Android stub code
public class FileAttachmentChromeClient extends CordovaChromeClient {
public FileAttachmentChromeClient(CordovaInterface ctx, CordovaWebView app) {
super(ctx, app);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
cordovaExample.this.startActivityForResult(Intent.createChooser(i, "Choose type of attachment"), FILECHOOSER_RESULTCODE);
}
}
}
And what i do with JavaScript:
var SelectedFile;
var FReader;
document.getElementById('fileBox').addEventListener('change', fileChosen);
function fileChosen(evnt) {
SelectedFile = evnt.target.files[0];
FReader = new FileReader();
FReader.readAsDataURL(SelectedFile);
FReader.onload = function(loadevnt){ .... } //never happens
}
Well the problem is most mobile browsers do not support the file dialog. IIRC iOS 6 is the first mobile browser to support this functionality. I did write some code in my Corinthian project, not under active development, that does monkey patch this functionality.
First you'd need to write an Android plugin to start an intent to provide the file dialog. I'm using OI File Manager.
package org.apache.cordova;
import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.LOG;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
/**
* This class exposes methods in DroidGap that can be called from JavaScript.
*/
public class App extends CordovaPlugin {
/**
* Executes the request and returns PluginResult.
*
* #param action The action to execute.
* #param args JSONArry of arguments for the plugin.
* #param callbackContext The callback context from which we were invoked.
* #return A PluginResult object with a status and message.
*/
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
PluginResult.Status status = PluginResult.Status.OK;
String result = "";
try {
if (action.equals("clearCache")) {
this.clearCache();
}
else if (action.equals("show")) {
// This gets called from JavaScript onCordovaReady to show the webview.
// I recommend we change the name of the Message as spinner/stop is not
// indicative of what this actually does (shows the webview).
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
webView.postMessage("spinner", "stop");
}
});
}
else if (action.equals("loadUrl")) {
this.loadUrl(args.getString(0), args.optJSONObject(1));
}
else if (action.equals("cancelLoadUrl")) {
this.cancelLoadUrl();
}
else if (action.equals("clearHistory")) {
this.clearHistory();
}
else if (action.equals("backHistory")) {
this.backHistory();
}
else if (action.equals("overrideButton")) {
this.overrideButton(args.getString(0), args.getBoolean(1));
}
else if (action.equals("overrideBackbutton")) {
this.overrideBackbutton(args.getBoolean(0));
}
else if (action.equals("exitApp")) {
this.exitApp();
}
callbackContext.sendPluginResult(new PluginResult(status, result));
return true;
} catch (JSONException e) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
return false;
}
}
//--------------------------------------------------------------------------
// LOCAL METHODS
//--------------------------------------------------------------------------
/**
* Clear the resource cache.
*/
public void clearCache() {
this.webView.clearCache(true);
}
/**
* Load the url into the webview.
*
* #param url
* #param props Properties that can be passed in to the DroidGap activity (i.e. loadingDialog, wait, ...)
* #throws JSONException
*/
public void loadUrl(String url, JSONObject props) throws JSONException {
LOG.d("App", "App.loadUrl("+url+","+props+")");
int wait = 0;
boolean openExternal = false;
boolean clearHistory = false;
// If there are properties, then set them on the Activity
HashMap<String, Object> params = new HashMap<String, Object>();
if (props != null) {
JSONArray keys = props.names();
for (int i = 0; i < keys.length(); i++) {
String key = keys.getString(i);
if (key.equals("wait")) {
wait = props.getInt(key);
}
else if (key.equalsIgnoreCase("openexternal")) {
openExternal = props.getBoolean(key);
}
else if (key.equalsIgnoreCase("clearhistory")) {
clearHistory = props.getBoolean(key);
}
else {
Object value = props.get(key);
if (value == null) {
}
else if (value.getClass().equals(String.class)) {
params.put(key, (String)value);
}
else if (value.getClass().equals(Boolean.class)) {
params.put(key, (Boolean)value);
}
else if (value.getClass().equals(Integer.class)) {
params.put(key, (Integer)value);
}
}
}
}
// If wait property, then delay loading
if (wait > 0) {
try {
synchronized(this) {
this.wait(wait);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.webView.showWebPage(url, openExternal, clearHistory, params);
}
/**
* Cancel loadUrl before it has been loaded (Only works on a CordovaInterface class)
*/
#Deprecated
public void cancelLoadUrl() {
this.cordova.cancelLoadUrl();
}
/**
* Clear page history for the app.
*/
public void clearHistory() {
this.webView.clearHistory();
}
/**
* Go to previous page displayed.
* This is the same as pressing the backbutton on Android device.
*/
public void backHistory() {
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
webView.backHistory();
}
});
}
/**
* Override the default behavior of the Android back button.
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
*
* #param override T=override, F=cancel override
*/
public void overrideBackbutton(boolean override) {
LOG.i("App", "WARNING: Back Button Default Behaviour will be overridden. The backbutton event will be fired!");
webView.bindButton(override);
}
/**
* Override the default behavior of the Android volume buttons.
* If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
*
* #param button volumeup, volumedown
* #param override T=override, F=cancel override
*/
public void overrideButton(String button, boolean override) {
LOG.i("DroidGap", "WARNING: Volume Button Default Behaviour will be overridden. The volume event will be fired!");
webView.bindButton(button, override);
}
/**
* Return whether the Android back button is overridden by the user.
*
* #return boolean
*/
public boolean isBackbuttonOverridden() {
return webView.isBackButtonBound();
}
/**
* Exit the Android application.
*/
public void exitApp() {
this.webView.postMessage("exit", null);
}
}
package com.simonmacdonald.corinthian;
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
import org.json.JSONArray;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
public class FileDialog extends Plugin {
private static final int PICK_FILE_RESULT_CODE = 8974;
private static final int PICK_DIRECTORY_RESULT_CODE = 8975;
private static final String LOG_TAG = "FileDialog";
public String callbackId;
/**
* Executes the request and returns PluginResult.
*
* #param action The action to execute.
* #param args JSONArry of arguments for the plugin.
* #param callbackId The callback id used when calling back into JavaScript.
* #return A PluginResult object with a status and message.
*/
#Override
public PluginResult execute(String action, JSONArray args, String callbackId) {
this.callbackId = callbackId;
JSONObject options = args.optJSONObject(0);
if (action.equals("pickFile")) {
showDialog(options, PICK_FILE_RESULT_CODE);
} else if (action.equals("pickFolder")) {
showDialog(options, PICK_DIRECTORY_RESULT_CODE);
}
else {
return new PluginResult(PluginResult.Status.INVALID_ACTION);
}
PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
r.setKeepCallback(true);
return r;
}
private void showDialog(JSONObject options, int type) {
Intent intent;
if (type == PICK_FILE_RESULT_CODE) {
intent = new Intent("org.openintents.action.PICK_FILE");
} else {
intent = new Intent("org.openintents.action.PICK_DIRECTORY");
}
if (options != null) {
String title = options.optString("title");
if (title != null) {
intent.putExtra("org.openintents.extra.TITLE", title);
}
String button = options.optString("button");
if (button != null) {
intent.putExtra("org.openintents.extra.BUTTON_TEXT", button);
}
}
//intent.setData(Uri.fromFile(new File("/")));
try {
this.cordova.startActivityForResult((Plugin)this,intent,PICK_FILE_RESULT_CODE);
} catch (ActivityNotFoundException e) {
showDownloadDialog();
}
}
private void showDownloadDialog() {
final Context context = this.cordova.getContext();
Runnable runnable = new Runnable() {
public void run() {
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle("Install File Manager?");
dialog.setMessage("This requires the free OI File Manager app. Would you like to install it now?");
dialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int i) {
dlg.dismiss();
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("market://search?q=pname:org.openintents.filemanager")
);
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
// We don't have the market app installed, so download it directly.
Intent in = new Intent(Intent.ACTION_VIEW);
in.setData(Uri.parse("http://openintents.googlecode.com/files/FileManager-1.2.apk"));
context.startActivity(in);
}
}
});
dialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int i) {
dlg.dismiss();
}
});
dialog.create();
dialog.show();
}
};
this.cordova.getActivity().runOnUiThread(runnable);
}
#Override
public void onActivityResult(int reqCode, int resultCode, Intent data) {
//super.onActivityResult(reqCode, resultCode, data);
//Log.d(LOG_TAG, "Data is " + data.getData().toString());
Log.d(LOG_TAG, "we are in on activity result");
switch (reqCode) {
case PICK_FILE_RESULT_CODE:
case PICK_DIRECTORY_RESULT_CODE: {
if (resultCode==Activity.RESULT_OK && data!=null && data.getData()!=null) {
String filePath = "file://" + data.getData().getPath();
Log.d(LOG_TAG, "The data is = " + filePath);
Log.d(LOG_TAG, "Calling succes with callback id = " + this.callbackId);
this.success(new PluginResult(PluginResult.Status.OK, filePath), this.callbackId);
}
break;
}
}
}
}
Then you'd need to write your JavaScript interface:
FileDialog: {
pickFile: function(successCallback, errorCallback, options) {
var win = typeof successCallback !== 'function' ? null : function(f) {
window.resolveLocalFileSystemURI(f, function(fileEntry) {
successCallback(fileEntry);
}, fail);
};
cordova.exec(win, errorCallback, "FileDialog", "pickFile", [options]);
},
pickFolder: function(successCallback, errorCallback, options) {
var win = typeof successCallback !== 'function' ? null : function(d) {
window.resolveLocalFileSystemURI(d, function(dirEntry) {
successCallback(dirEntry);
}, fail);
};
cordova.exec(win, errorCallback, "FileDialog", "pickFolder", [options]);
},
patch: function() {
var inputs = document.getElementsByTagName("input");
for (var i=0; i < inputs.length; i++) {
if (inputs[i].getAttribute('type') == 'file'){
var me = inputs[i];
inputs[i].addEventListener("click", function() {
corinthian.FileDialog.pickFile(function(fileEntry) {
me.value = fileEntry.fullPath;
});
});
}
}
}
}
and finally monkey patch by calling FileDialog.patch(); once you have received the deviceready event in PhoneGap.
Hope this helps...