Path: blob/trunk/third_party/closure/goog/datasource/jsxmlhttpdatasource.js
2868 views
// Copyright 2006 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview16* DataSource implementation that uses XMLHttpRequest as transport, with17* response as valid JSON.18*19* Response can have unexecutable starting/ending text to prevent inclusion20* using <script src="...">21*22*/232425goog.provide('goog.ds.JsXmlHttpDataSource');2627goog.require('goog.Uri');28goog.require('goog.ds.DataManager');29goog.require('goog.ds.FastDataNode');30goog.require('goog.ds.LoadState');31goog.require('goog.ds.logger');32goog.require('goog.events');33goog.require('goog.json');34goog.require('goog.log');35goog.require('goog.net.EventType');36goog.require('goog.net.XhrIo');37383940/**41* Similar to JsonDataSource, with using XMLHttpRequest for transport42* Currently requires the result be a valid JSON.43*44* @param {(string|goog.Uri)} uri URI for the request.45* @param {string} name Name of the datasource.46* @param {string=} opt_startText Text to expect/strip before JS response.47* @param {string=} opt_endText Text to expect/strip after JS response.48* @param {boolean=} opt_usePost If true, use POST. Defaults to false (GET).49*50* @extends {goog.ds.FastDataNode}51* @constructor52* @final53*/54goog.ds.JsXmlHttpDataSource = function(55uri, name, opt_startText, opt_endText, opt_usePost) {56goog.ds.FastDataNode.call(this, {}, name, null);57if (uri) {58this.uri_ = new goog.Uri(uri);59this.xhr_ = new goog.net.XhrIo();60this.usePost_ = !!opt_usePost;6162goog.events.listen(63this.xhr_, goog.net.EventType.COMPLETE, this.completed_, false, this);64} else {65this.uri_ = null;66}67this.startText_ = opt_startText;68this.endText_ = opt_endText;69};70goog.inherits(goog.ds.JsXmlHttpDataSource, goog.ds.FastDataNode);717273/**74* Delimiter for start of JSON data in response.75* null = starts at first character of response76* @type {string|undefined}77* @private78*/79goog.ds.JsXmlHttpDataSource.prototype.startText_;808182/**83* Delimiter for end of JSON data in response.84* null = ends at last character of response85* @type {string|undefined}86* @private87*/88goog.ds.JsXmlHttpDataSource.prototype.endText_;899091/**92* Gets the state of the backing data for this node93* @return {goog.ds.LoadState} The state.94* @override95*/96goog.ds.JsXmlHttpDataSource.prototype.getLoadState = function() {97return this.loadState_;98};99100101/**102* Sets the request data. This can be used if it is required to103* send a specific body rather than build the body from the query104* parameters. Only used in POST requests.105* @param {string} data The data to send in the request body.106*/107goog.ds.JsXmlHttpDataSource.prototype.setQueryData = function(data) {108this.queryData_ = data;109};110111112/**113* Load or reload the backing data for this node.114* Fires the JsonDataSource115* @override116*/117goog.ds.JsXmlHttpDataSource.prototype.load = function() {118goog.log.info(119goog.ds.logger, 'Sending JS request for DataSource ' +120this.getDataName() + ' to ' + this.uri_);121122if (this.uri_) {123if (this.usePost_) {124var queryData;125if (!this.queryData_) {126queryData = this.uri_.getQueryData().toString();127} else {128queryData = this.queryData_;129}130131var uriNoQuery = this.uri_.clone();132uriNoQuery.setQueryData(null);133this.xhr_.send(String(uriNoQuery), 'POST', queryData);134} else {135this.xhr_.send(String(this.uri_));136}137} else {138this.loadState_ = goog.ds.LoadState.NOT_LOADED;139}140};141142143/**144* Called on successful request.145* @private146*/147goog.ds.JsXmlHttpDataSource.prototype.success_ = function() {148goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());149};150151152/**153* Completed callback. Loads data if successful, otherwise sets154* state to FAILED155* @param {goog.events.Event} e Event object, Xhr is target.156* @private157*/158goog.ds.JsXmlHttpDataSource.prototype.completed_ = function(e) {159if (this.xhr_.isSuccess()) {160goog.log.info(161goog.ds.logger, 'Got data for DataSource ' + this.getDataName());162var text = this.xhr_.getResponseText();163164// Look for start and end token and trim text165if (this.startText_) {166var startpos = text.indexOf(this.startText_);167text = text.substring(startpos + this.startText_.length);168}169if (this.endText_) {170var endpos = text.lastIndexOf(this.endText_);171text = text.substring(0, endpos);172}173174// Parse result.175176try {177var jsonObj = goog.json.parse(text);178this.extendWith(jsonObj);179this.loadState_ = goog.ds.LoadState.LOADED;180} catch (ex) {181// Invalid JSON.182this.loadState_ = goog.ds.LoadState.FAILED;183goog.log.error(goog.ds.logger, 'Failed to parse data: ' + ex.message);184}185186// Call on a timer to avoid threading issues on IE.187goog.global.setTimeout(goog.bind(this.success_, this), 0);188} else {189goog.log.info(190goog.ds.logger,191'Data retrieve failed for DataSource ' + this.getDataName());192this.loadState_ = goog.ds.LoadState.FAILED;193}194};195196197