(function() {
//shortcuts:
var Y = YAHOO,
YU = Y.util,
YUIL = YU.YUILoader,
YL = Y.lang,
D = YU.Dom,
E = YU.Event,
CE = YU.CustomEvent,
API = YAHOO.namespace("api");
/**
* The TermExtractor module facilitates the use of YUI in conjunction with
* the Yahoo Search Term Extraction API. This module REQUIRES a server-
* side proxy to proxy POST requests to the API; see the docs for a sample
* proxy file written in PHP. Use of the API also requires a valid appid,
* which is freely available via the Yahoo Developer Network. See the
* documentation for this module (http://developer.yahoo.com/yui/termextractor )
* and the documentation for the API itself
* (http://developer.yahoo.com/search/content/V1/termExtraction.html ) for
* more details.
* @module termextractor
* @requires yahoo, dom, event, yuiloader
*
*/
/**
* A utility to retrieve related terms via the Yahoo Term Extractor API.
* @namespace YAHOO.api
* @class TermExtractor
* @constructor
* @param {o} object
* An object containing the configuration attributes for
* term extraction. Members of this configuration object include:
* <ul><li><strong>el | str ID contextEl:</strong> The element from whose value
* or innerText property terms will be extracted.</li>
* <li><strong>str proxy:</strong> Path to the server-side post proxy
* that will relay the request and post arguments to the webservice</li>
* <li><strong>str appid:</strong> The <a href="https://developer.yahoo.com/wsregapp/">Yahoo
* Developer App ID</a> to use in making the request. (Optional:
* if this is not provided, the appid must be supplied in your server-
* side proxy as an additional post variable.</li></ul>
*/
API.TermExtractor = function(o) {
//Validate context element:
if (!YL.isUndefined(o) && !YL.isUndefined(o.contextEl) && D.get(o.contextEl) ) {
/**
* The element from whose content terms will be extracted. If an input
* or textarea, content will be extracted from the element's value; if
* other, the element's innerText/textContent will be used.
* @property contextEl
* @type HTMLElement | string ID
* @public
*/
this.contextEl = D.get(o.contextEl);
} else {
YAHOO.log("ERROR: Unable to locate contextElement.", "error", "TermExtractor");
return false;
}
//Validate proxy string presence:
if (!YL.isUndefined(o.proxy) && YL.isString(o.proxy)) {
/**
* The path to the server-side proxy that will proxy the post request
* to the API. Path should be relative to the current HTML page and
* must obey the strict same origin policy enforced by XMLHttpRequest.
* @property proxy
* @type string
* @public
*/
this.proxy = o.proxy;
} else {
YAHOO.log("ERROR: Proxy was not provided to TermExtractor constructor.", "error", "TermExtractor");
}
//Validate appid:
if (!YL.isUndefined(o.appid) && YL.isString(o.appid)) {
/**
* The appid issued by the Yahoo Developer Network for your use. You may choose
* to omit this property in your JavaScript so as to avoid exposing your
* appid to prying eyes; in that case, append the appid as a post variable
* in your server-side proxy.
* @property appid
* @type string
* @public
*/
this.appid = o.appid;
} else {
YAHOO.log("WARNING: Appid was not provided to TermExtractor constructor; be sure to append the appid as an additional post variable in your server-side proxy.", "warn", "TermExtractor");
this.appid = false;
}
/**
* Fired when a term extraction request is complete, whether
* successful or not. This event uses a FLAT Custom Event signature,
* meaning that the subscriber gets a single argument -- an object --
* which contains all relevant information, including the following
* members:
*
* <ul><li><strong>array terms:</strong> An array with all terms returned
* by the API.</li>
* <li><strong>string message:</strong> Any message coming back from TermExtractor
* indicating the disposition of the request -- if it failed,
* the message may give you some indication as to what went
* wrong.</li></ul>
*
* @event onComplete
*/
this.onComplete = new CE("onComplete", this, false, CE.FLAT);
return this;
};
var proto = API.TermExtractor.prototype;
/**
* Provides a readable name for the TermExtractor instance.
* @method toString
* @return String
* @private
*/
proto.toString = function() {
return "TermExtractor " + (this.contextEl.id || this.contextEl.nodeName);
};
/**
* Kicks off a term extraction request. Invoke this method when your
* context element is populated with the content from which you want to
* extract key terms -- for example, on the blur event of a text area.
* There is no return value for this method, as the process is
* asynchronous; subscribe to your TermExtractor instance's onComplete
* event to process the results of your extraction request.
* @method extract
* @return void
* @public
*/
proto.extract = function() {
YAHOO.log("Term extraction initiated.", "info", "TermExtractor");
if (!YL.isUndefined(YU.Connect) && !YL.isUndefined(YL.JSON)) {
YAHOO.log("All YUI dependencies in place.", "info", "TermExtractor");
this._onDependenciesLoaded();
} else {
YAHOO.log("Handing off to YUI Loader to bring in additional dependencies.", "info", "TermExtractor");
//Load additional dependencies:
this._loadDependencies();
}
};
/**
* Once TermExtractor has verified that all YUI dependencies are present,
* or has loaded missing dependencies via YUI Loader, this function
* creates the Ajax request to the API.
* @method _onDependenciesLoaded
* @return void
* @private
*/
proto._onDependenciesLoaded = function() {
var s,
o,
postBody;
YAHOO.log("YUI dependencies loaded.", "info", "TermExtractor");
s = this._getContextContent();
if (!YL.isUndefined(s) && !YL.isUndefined(s.length) && s.length > 0) {
YAHOO.log("Context content:" + s, "info", "TermExtractor");
//postBody for form post to proxy handler:
postBody = [
"context=" + encodeURIComponent(s),
"output=json"
].join("&");
if (this.appid) {
postBody += "&appid=" + encodeURIComponent(this.appid);
}
//set up connection object:
o = {
success: this._onResponseSuccess,
scope: this,
failure: this._onResponseError,
timeout: 30000
};
this._lastConnection = YU.Connect.asyncRequest(
"post",
this.proxy,
o,
postBody);
YAHOO.log("Request made to Term Extraction API.", "info", "TermExtractor");
} else {
YAHOO.log("Context content is undefined or empty.", "info", "TermExtractor");
this.onComplete.fire({
terms: [],
message: "Context element had no content."
});
}
};
/**
* Handles the error case if there is a transport error in contacting
* the API via Ajax.
* @method _onResponseError
* @return void
* @private
*/
proto._onResponseError = function(o) {
YAHOO.log("ERROR: Ajax request failed.", "error", "TermExtractor");
};
/**
* Handles Ajax succcess (does not assume that that the request
* was successful, merely that it id not have a transport error).
* Most errors will result in an XML response from the API, which
* will throw an error in parseJSON. In that case, the error is
* caught and the XML text is logged.
* @method _onResponseSuccess
* @return void
* @private
*/
proto._onResponseSuccess = function(o) {
var json,
result;
YAHOO.log("Ajax request succeeded.", "info","TermExtractor");
try {
json = YL.JSON.parse(o.responseText);
if(!YL.isUndefined(json) && !YL.isUndefined(json.ResultSet) && !YL.isUndefined(json.ResultSet.Result)) {
result = json.ResultSet.Result;
YAHOO.log("Term extraction succeeded; terms: " + result, "info", "TermExtractor");
} else {
result = [];
YAHOO.log("TermExtractor did not locate any terms.", "warn", "TermExtractor");
}
this.onComplete.fire({
terms: result,
message: "Response retrieved from Yahoo Search Term Extractor API."
});
} catch (e) {
YAHOO.log("TermExtractor received an error message from the API service. XML message: " + o.responseText, "error", "TermExtractor");
}
};
/**
* Handles Ajax succcess (does not assume that that the request
* was successful, merely that it id not have a transport error).
* Most errors will result in an XML response from the API, which
* will throw an error in parseJSON. In that case, the error is
* caught and the XML text is logged.
* @method _getContextContent
* @return void
* @private
*/
proto._getContextContent = function() {
YAHOO.log("Getting context content.", "info", "TermExtractor");
var el = this.contextEl;
if((el.nodeName.toLowerCase() === "input") || (el.nodeName.toLowerCase() === "textarea")) {
YAHOO.log("elvalue");
return el.value;
} else {
return (YL.isUndefined(el.innerText)) ? el.textContent : el.innerText;
}
return false;
};
/**
* Loads dependencies for YAHOO.api.TermExtractor using
* YUILoader.
* @method _loadDependencies
* @private
* @return void
*/
proto._loadDependencies = function() {
var loader = new YAHOO.util.YUILoader({
require: ["connection","dom","event","json"],
combine: true,
allowRollup: false,
onSuccess: this._onDependenciesLoaded,
scope: this
});
loader.insert();
};
})();