Created
August 20, 2014 03:06
-
-
Save vko-online/7e2dc1320c524906f2bb to your computer and use it in GitHub Desktop.
XHRHelper File for cordova
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Phone.Controls; | |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.IO; | |
using System.IO.IsolatedStorage; | |
using System.Linq; | |
using System.Text; | |
using System.Windows; | |
namespace WPCordovaClassLib.CordovaLib | |
{ | |
public class XHRHelper : IBrowserDecorator | |
{ | |
public WebBrowser Browser { get; set; } | |
public PhoneApplicationPage Page { get; set; } | |
public void InjectScript() | |
{ | |
string script = @"(function(win, doc) { | |
var docDomain = null; | |
try { | |
docDomain = doc.domain; | |
} catch (err) {} | |
if (!docDomain || docDomain.length === 0) { | |
var aliasXHR = win.XMLHttpRequest; | |
var XHRShim = function() {}; | |
win.XMLHttpRequest = XHRShim; | |
XHRShim.noConflict = aliasXHR; | |
XHRShim.UNSENT = 0; | |
XHRShim.OPENED = 1; | |
XHRShim.HEADERS_RECEIVED = 2; | |
XHRShim.LOADING = 3; | |
XHRShim.DONE = 4; | |
XHRShim.prototype = { | |
isAsync: false, | |
onreadystatechange: null, | |
readyState: 0, | |
_url: '', | |
timeout: 0, | |
withCredentials: false, | |
_requestHeaders: null, | |
open: function (reqType, uri, isAsync, user, password) { | |
if (uri && uri.indexOf('http') === 0) { | |
if (!this.wrappedXHR) { | |
this.wrappedXHR = new aliasXHR(); | |
var self = this; | |
if (this.timeout > 0) { | |
this.wrappedXHR.timeout = this.timeout; | |
} | |
Object.defineProperty(this, 'timeout', { | |
set: function(val) { | |
this.wrappedXHR.timeout = val; | |
}, | |
get: function() { | |
return this.wrappedXHR.timeout; | |
} | |
}); | |
if (this.withCredentials) { | |
this.wrappedXHR.withCredentials = this.withCredentials; | |
} | |
Object.defineProperty(this, 'withCredentials', { | |
set: function(val) { | |
this.wrappedXHR.withCredentials = val; | |
}, | |
get: function() { | |
return this.wrappedXHR.withCredentials; | |
} | |
}); | |
Object.defineProperty(this, 'status', { | |
get: function() { | |
return this.wrappedXHR.status; | |
} | |
}); | |
Object.defineProperty(this, 'responseText', { | |
get: function() { | |
return this.wrappedXHR.responseText; | |
} | |
}); | |
Object.defineProperty(this, 'statusText', { | |
get: function() { | |
return this.wrappedXHR.statusText; | |
} | |
}); | |
Object.defineProperty(this, 'responseXML', { | |
get: function() { | |
return this.wrappedXHR.responseXML; | |
} | |
}); | |
Object.defineProperty(this, 'response', { | |
get: function() { | |
return this.wrappedXHR.response; | |
} | |
}); | |
Object.defineProperty(this, 'responseType', { | |
set: function(val) { | |
return this.wrappedXHR.responseType = val; | |
} | |
}); | |
this.getResponseHeader = function(header) { | |
return this.wrappedXHR.getResponseHeader(header); | |
}; | |
this.getAllResponseHeaders = function() { | |
return this.wrappedXHR.getAllResponseHeaders(); | |
}; | |
this.wrappedXHR.onreadystatechange = function() { | |
self.changeReadyState(self.wrappedXHR.readyState); | |
}; | |
} | |
return this.wrappedXHR.open(reqType, uri, isAsync, user, password); | |
} | |
else | |
{ | |
this.isAsync = isAsync; | |
this.reqType = reqType; | |
this._url = uri; | |
} | |
}, | |
statusText: '', | |
changeReadyState: function(newState) { | |
this.readyState = newState; | |
if (this.onreadystatechange) { | |
// mimic simple 'readystatechange' event which should be passed as per spec | |
var evt = {type: 'readystatechange', target: this, timeStamp: new Date().getTime()}; | |
this.onreadystatechange(evt); | |
} | |
if (this.readyState == XHRShim.DONE){ | |
this.onload && this.onload(); | |
} | |
}, | |
addEventListener: function (type, listener, useCapture){ | |
if (this.wrappedXHR) { | |
this.wrappedXHR.addEventListener(type, listener, useCapture); | |
} else { | |
this['on' + type] = listener; | |
} | |
}, | |
removeEventListener: function (type, listener, useCapture){ | |
if (this.wrappedXHR) { | |
this.wrappedXHR.removeEventListener(type, listener, useCapture); | |
} else { | |
if (this['on' + type] == listener) { // if listener is currently used | |
delete this['on' + type]; | |
} | |
} | |
}, | |
setRequestHeader: function(header, value) { | |
if (this.wrappedXHR) { | |
this.wrappedXHR.setRequestHeader(header, value); | |
} | |
}, | |
getResponseHeader: function(header) { | |
return this.wrappedXHR ? this.wrappedXHR.getResponseHeader(header) : ''; | |
}, | |
getAllResponseHeaders: function() { | |
return this.wrappedXHR ? this.wrappedXHR.getAllResponseHeaders() : ''; | |
}, | |
overrideMimeType: function(mimetype) { | |
return this.wrappedXHR ? this.wrappedXHR.overrideMimeType(mimetype) : ''; | |
}, | |
responseText: '', | |
responseXML: '', | |
onResult: function(res) { | |
this.status = 200; | |
if (typeof res == 'object') { | |
res = JSON.stringify(res); | |
} | |
this.responseText = res; | |
this.responseXML = res; | |
this.changeReadyState(XHRShim.DONE); | |
}, | |
onError: function(err) { | |
this.status = 404; | |
this.changeReadyState(XHRShim.DONE); | |
}, | |
abort: function() { | |
if (this.wrappedXHR) { | |
return this.wrappedXHR.abort(); | |
} | |
}, | |
send: function(data) { | |
if (this.wrappedXHR) { | |
return this.wrappedXHR.send(data); | |
} | |
else { | |
this.changeReadyState(XHRShim.OPENED); | |
var alias = this; | |
var root = window.location.href.split('#')[0]; // remove hash | |
var basePath = root.substr(0,root.lastIndexOf('/')) + '/'; | |
//console.log( 'Stripping protocol if present and removing leading / characters' ); | |
var resolvedUrl = | |
// remove protocol from the beginning of the url if present | |
( this._url.indexOf( window.location.protocol ) === 0 ? | |
this._url.substring( window.location.protocol.length ) : | |
this._url ) | |
// get rid of all the starting slashes | |
.replace(/^[/]*/, '') | |
.split('#')[0]; // remove hash | |
var wwwFolderPath = navigator.userAgent.indexOf('MSIE 9.0') > -1 ? 'app/www/' : 'www/'; | |
// handle special case where url is of form app/www but we are loaded just from /www | |
if( resolvedUrl.indexOf('app/www') == 0 ) { | |
resolvedUrl = window.location.protocol + wwwFolderPath + resolvedUrl.substr(7); | |
} | |
else if( resolvedUrl.indexOf('www') == 0) { | |
resolvedUrl = window.location.protocol + wwwFolderPath + resolvedUrl.substr(4); | |
} | |
if(resolvedUrl.indexOf(':') < 0) { | |
resolvedUrl = basePath + resolvedUrl; // consider it relative | |
} | |
var funk = function () { | |
if (!window.__onXHRLocalCallback) { | |
window.__onXHRLocalCallback = {}; | |
} | |
window.__onXHRLocalCallback[resolvedUrl] = function (responseCode, responseText) { | |
alias.status = responseCode; | |
if (responseCode == '200') { | |
alias.responseText = responseText; | |
Object.defineProperty(alias, 'responseXML', { | |
get: function () { | |
return new DOMParser().parseFromString(this.responseText, 'text/xml'); | |
} | |
}); | |
} | |
else { | |
alias.onerror && alias.onerror(responseCode); | |
} | |
alias.changeReadyState(XHRShim.DONE); | |
delete window.__onXHRLocalCallback[resolvedUrl]; | |
} | |
alias.changeReadyState(XHRShim.LOADING); | |
window.external.Notify('XHRLOCAL/' + resolvedUrl); | |
} | |
if (this.isAsync) { | |
setTimeout(funk, 0); | |
} | |
else { | |
funk(); | |
} | |
} | |
}, | |
status: 404 | |
}; | |
} | |
window.__onXHRLocalCallbackProxy = function (url, code, text){ | |
if(window.__onXHRLocalCallback[url]) { | |
window.__onXHRLocalCallback[url](code, text); | |
} | |
} | |
})(window, document); "; | |
Browser.InvokeScript("eval", new string[] { script }); | |
} | |
//Fix from https://issues.apache.org/jira/browse/CB-4873 | |
/// <summary> | |
/// Invoke a XHR callback | |
/// </summary> | |
/// <param name="url">The URL of the request</param> | |
/// <param name="code">The response code</param> | |
/// <param name="text">The response text</param> | |
private void InvokeCallback(string url, int code, string text) | |
{ | |
Browser.InvokeScript("__onXHRLocalCallbackProxy", | |
new string[] | |
{ | |
url, | |
code.ToString(), | |
text ?? "" // else InvokeScript crashes if text happens to be null | |
}); | |
} | |
public bool HandleCommand(string commandStr) | |
{ | |
if (commandStr.IndexOf("XHRLOCAL") == 0) | |
{ | |
string url = commandStr.Replace("XHRLOCAL/", ""); | |
Uri uri = new Uri(url, UriKind.RelativeOrAbsolute); | |
using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) | |
{ | |
if (isoFile.FileExists(uri.AbsolutePath)) | |
{ | |
using (TextReader reader = new StreamReader(isoFile.OpenFile(uri.AbsolutePath, FileMode.Open, FileAccess.Read))) | |
{ | |
string text = reader.ReadToEnd(); | |
InvokeCallback(url, 200, text); | |
return true; | |
} | |
} | |
} | |
Uri relUri = new Uri(uri.AbsolutePath, UriKind.Relative); | |
var resource = Application.GetResourceStream(relUri); | |
if (resource == null) | |
{ | |
// 404 ? | |
InvokeCallback(url, 404, null); | |
return true; | |
} | |
else | |
{ | |
using (StreamReader streamReader = new StreamReader(resource.Stream)) | |
{ | |
string text = streamReader.ReadToEnd(); | |
InvokeCallback(url, 200, text); | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thnx, man! This is real help!!!