/**
*
* Flashのpolyfillプラグインから返されたXMLHttpRequestオブジェクトのメソッドとプロパティをシミュレーションします。JavaScriptによるブラウザのバイナリデータ送信がサポートされていない場合にこれを使用します。注意:デフォルトでは、extディレクトリのFlashオブジェクトを検索します。アプリケーションのパッケージ化と実装を行う際、<tt>ext/plugins</tt>ディレクトリとそのコンテンツを実装先のルートディレクトリにコピーします。<tt>FlashPlugin.swf</tt>ファイルのみをコピーする(たとえば<tt>/resources/FlashPlugin.swf</tt>へ)カスタム実装の場合、バイナリデータの初回ポスト(たとえばアプリケーションの<tt>launch</tt>メソッドが実行する)に先立って、プラグインの保存場所のフレームワークに必ず通知してください。<pre><code>
Ext.flashPluginPath="/resources/FlashPlugin.swf";
</code></pre>
*
* @private
*/
Ext.define('Ext.data.flash.BinaryXhr', {
statics: {
/**
* Flashプラグインのインストールが完了して使用できるようになると、Flashプラグインによって呼び出されます。
* @private
*/
flashPluginActivated: function() {
Ext.data.flash.BinaryXhr.flashPluginActive = true;
Ext.data.flash.BinaryXhr.flashPlugin = document.getElementById("ext-flash-polyfill");
Ext.GlobalEvents.fireEvent("flashready"); // let all pending connections know
},
/**
* プラグインが登録されてアクティブになると<tt>true</tt>が設定されます。
* @private
*/
flashPluginActive: false,
/**
* プラグインの重複インストールを防止するフラグです。
* @private
*/
flashPluginInjected: false,
/**
* 新しい接続のIDを数えます。
* @private
*/
connectionIndex: 1,
/**
* アクティブな接続のプレースホルダーです。
* @private
*/
liveConnections: {},
/**
* アクティブになった実際のプラグインへの参照です。
* @private
*/
flashPlugin: null,
/**
* アクティブな接続のいずれかの状態が変わったときにFlashプラグインによって呼び出されます。
* @param {Number/number} javascriptId 接続のIDです。
* @param {number} state 接続の状態です。XHRのreadyState numbersに相当するものです。
* @param {Object} data 返されたデータ、エラー、状態のコードを保持するオプションのオブジェクトです。
* @private
*/
onFlashStateChange: function(javascriptId, state, data) {
var connection;
// Identify the request this is for
connection = this.liveConnections[Number(javascriptId)]; // Make sure its a native number
if (connection) {
connection.onFlashStateChange(state, data);
}
//<debug>
else {
Ext.warn.log("onFlashStateChange for unknown connection ID: " + javascriptId);
}
//</debug>
},
/**
* BinaryXhrオブジェクトを追跡する接続のリストに追加し、IDを割り当てます。
* @param {Ext.data.flash.BinaryXhr} conn 登録する接続
* @return {Number} id
* @private
*/
registerConnection: function(conn) {
var i = this.connectionIndex;
this.conectionIndex = this.connectionIndex + 1;
this.liveConnections[i] = conn;
return i;
},
/**
* Flash polyfillプラグインを導入してバイナリデータの送信を実現します。これは、次の2つの手順を踏んで実行します。まずFlashオブジェクト用にjavascriptローダーをロードし、次にこれを呼び出してFlashオブジェクトを導入します。
* @private
*/
injectFlashPlugin: function() {
var me = this,
flashLoaderPath, flashObjectPath;
// Generate the following HTML set of tags:
// + '<div id="ext-flash-polyfill">'
// + '<p>To view this page ensure that Adobe Flash Player version 11.1.0 or greater is installed, and that the FlashPlugin.swf file was correctly placed in the /resources directory.</p>'
//+ '<a href="http://www.adobe.com/go/getflashplayer"><img src="' + window.location.protocol + '//www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a>'
//+ '</div>'
me.flashPolyfillEl = Ext.getBody().appendChild({
id: 'ext-flash-polyfill',
cn: [
{
tag: 'p',
html: 'To view this page ensure that Adobe Flash Player version 11.1.0 or greater is installed.'
},
{
tag: 'a',
href: 'http://www.adobe.com/go/getflashplayer',
cn: [
{
tag: 'img',
src: window.location.protocol + '//www.adobe.com/images/shared/download_buttons/get_flash_player.gif',
alt: 'Get Adobe Flash player'
}
]
}
]
});
// Now load the flash-loading script
flashLoaderPath = [Ext.Loader.getPath('Ext.data.Connection'), '../../../plugins/flash/swfobject.js'].join('/');
flashObjectPath = "/plugins/flash/FlashPlugin.swf";
//<debug>
flashObjectPath = [Ext.Loader.getPath('Ext.data.Connection'), '../../plugins/flash/FlashPlugin.swf'].join('/');
//</debug>
if (Ext.flashPluginPath) {
flashObjectPath = Ext.flashPluginPath;
}
//console.log('LOADING Flash plugin from: ' + flashObjectPath);
Ext.Loader.loadScript({
url:flashLoaderPath,
onLoad: function() {
// For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection.
var swfVersionStr = "11.4.0";
// To use express install, set to playerProductInstall.swf, otherwise the empty string.
var xiSwfUrlStr = "playerProductInstall.swf";
var flashvars = {};
var params = {};
params.quality = "high";
params.bgcolor = "#ffffff";
params.allowscriptaccess = "sameDomain";
params.allowfullscreen = "true";
var attributes = {};
attributes.id = "ext-flash-polyfill";
attributes.name = "polyfill";
attributes.align = "middle";
swfobject.embedSWF(
flashObjectPath, "ext-flash-polyfill",
"0", "0", // no size so it's not visible.
swfVersionStr, xiSwfUrlStr,
flashvars, params, attributes);
},
onError: function() {
//<debug>
Ext.Error.raise("Could not load flash-loader file swfobject.js from " + flashLoader);
//</debug>
},
scope: me
});
Ext.data.flash.BinaryXhr.flashPluginInjected = true;
}
},
/**
* @property {number} readyState シミュレーション済みの接続のreadyStateです。サポートされている値は0、1、4のみであることに注意してください。2や3という状態が報告されることはありません。
*/
readyState: 0,
/**
* @property {number} status Flashまたはサーバーから返された接続状態コードです。
*/
status: 0,
/**
* Flashまたはサーバーから返された接続状態テキスト(ある場合のみ)です。
*/
statusText: "",
/**
* @property {Array} responseBytes 返されたバイナリバイトです。
*/
responseBytes: null,
/**
* このFlashとの接続を表すIDです。
* @private
*/
javascriptId: null,
/**
* BinaryXhrの新しいインスタンスを作成します。
*/
constructor: function (config) {
// first, make sure flash is loading if needed
if (!Ext.data.flash.BinaryXhr.flashPluginInjected) {
Ext.data.flash.BinaryXhr.injectFlashPlugin();
}
var me = this;
Ext.apply(me, config);
me.requestHeaders = {};
},
/**
* この接続を中断します。readyStateに4を設定します。
*/
abort: function () {
var me = this;
// if complete, nothing to abort
if (me.readyState == 4) {
//<debug>
Ext.warn.log("Aborting a connection that's completed its transfer: " + this.url);
//</debug>
return;
}
// Mark as aborted
me.aborted = true;
// Remove ourselves from the listeners if flash isn't active yet
if (!Ext.data.flash.BinaryXhr.flashPluginActive) {
Ext.GlobalEvents.removeListener("flashready", me.onFlashReady, me);
return;
}
// Flash is already live, so we should have a javascriptID and should have called flash to get the request going. Cancel:
Ext.data.flash.BinaryXhr.flashPlugin.abortRequest(me.javascriptId);
// remove from list
delete Ext.data.flash.BinaryXhr.liveConnections[me.javascriptId];
},
* XMLHttpRequestと同様です。
*/
getAllResponseHeaders: function () {
var headers = [];
Ext.Object.each(this.responseHeaders, function (name, value) {
headers.push(name + ': ' + value);
});
return headers.join('\x0d\x0a');
},
* XMLHttpRequestと同様です。
*/
getResponseHeader: function (header) {
var headers = this.responseHeaders;
return (headers && headers[header]) || null;
},
/**
* XMLHttpRequestと同様です。
*/
open: function (method, url, async, user, password) {
var me = this;
me.method = method;
me.url = url;
me.async = async !== false;
me.user = user;
me.password = password;
//<debug>
if (!me.async) {
Ext.Error.raise("Binary posts are only supported in async mode: " + url);
}
if (me.method != "POST") {
Ext.log.warn("Binary data can only be sent as a POST request: " + url);
}
//</debug>
},
/**
* XMLHttpRequestと同様です。
*/
overrideMimeType: function (mimeType) {
this.mimeType = mimeType;
},
/**
* リクエストを開始します。
* @param {Array} body 送信するバイト値の配列です。
*/
send: function (body) {
var me = this;
me.body = body;
if (!Ext.data.flash.BinaryXhr.flashPluginActive) {
Ext.GlobalEvents.addListener("flashready", me.onFlashReady, me);
} else {
this.onFlashReady();
}
},
/**
* sendにより、またはFlashロード後に呼び出され、バイト送信を実行します。
* @private
*/
onFlashReady: function() {
var me = this, req, status;
me.javascriptId = Ext.data.flash.BinaryXhr.registerConnection(me);
// Create the request object we're sending to flash
req = {
method: me.method, // ignored since we always POST binary data
url: me.url,
user: me.user,
password: me.password,
mimeType: me.mimeType,
requestHeaders: me.requestHeaders,
body: me.body,
javascriptId: me.javascriptId
};
status = Ext.data.flash.BinaryXhr.flashPlugin.postBinary(req);
},
/**
* readyStateを更新してリスナに通知します。
* @private
*/
setReadyState: function (state) {
var me = this;
if (me.readyState != state) {
me.readyState = state;
me.onreadystatechange();
}
},
* XMLHttpRequestと同様です。
*/
setRequestHeader: function (header, value) {
this.requestHeaders[header] = value;
},
/**
* XMLHttpRequestと同様です。
*/
onreadystatechange: Ext.emptyFn,
/**
* 接続が確立したら、Flashから返されたデータをパースします。
* @param {Object} data Flashから送信されるデータオブジェクトです。
* @private
*/
parseData: function (data) {
var me = this;
// parse data and set up variables so that listeners can use this XHR
this.status = data.status || 0;
// we get back no response headers, so fake what we know:
me.responseHeaders = {};
if (me.mimeType) {
me.responseHeaders["content-type"] = me.mimeType;
}
if (data.reason == "complete") {
// Transfer complete and data received
this.responseBytes = data.data;
me.responseHeaders["content-length"] = data.data.length;
} else if (data.reason == "error" || data.reason == "securityError") {
this.statusText = data.text;
me.responseHeaders["content-length"] = 0; // we don't get the error response data
}
//<debug>
else {
Ext.Error.raise("Unkown reason code in data: " + data.reason);
}
//</debug>
},
/**
* 接続に関する更新情報をFlashがコールバックすると呼び出されます。
* @param {Number} state 接続のreadyStateです。
* @param {Object} data オプションのデータオブジェクトです。
* @private
*/
onFlashStateChange: function(state, data) {
var me = this;
if (state == 4) {
// parse data and prepare for handing back to initiator
me.parseData(data);
// remove from list
delete Ext.data.flash.BinaryXhr.liveConnections[me.javascriptId];
}
me.setReadyState(state); // notify all listeners
}
});