Viewing File: /usr/local/cpanel/base/sharedjs/api_shell.js
/* global LOCALE */
(function(window) {
"use strict";
var YAHOO = window.YAHOO;
var CPANEL = window.CPANEL;
var EVENT = YAHOO.util.Event,
DOM = YAHOO.util.Dom,
METADATA_SHOWN = false,
variableRowTemplate = CPANEL.Y.one("#variableRowTemplate").text.trim(),
sortRowTemplate = CPANEL.Y.one("#sortRowTemplate").text.trim(),
filterRowTemplate = CPANEL.Y.one("#filterRowTemplate").text.trim(),
columnRowTemplate = CPANEL.Y.one("#columnRowTemplate").text.trim(),
inputsOnPageLoad = 3,
api_comboboxes = {},
DATATABLE_WIDTH = "700px";
var views = new YAHOO.widget.TabView("views_container");
/**
* Initializer method which sets up event listeners, templates, and creates the tab view.
* Fired onDomReady.
*
* @method init
*/
function init() {
EVENT.on("api_form", "mouseup", update_api_call);
EVENT.on("api_form", "keyup", update_api_call);
EVENT.on("api_form", "submit", run_api_call);
EVENT.on("metadataToggle", "click", toggle_metadata);
EVENT.on("addVariableButton", "click", add_variable);
EVENT.on("addSortButton", "click", add_sort);
EVENT.on("addFilterButton", "click", add_filter);
EVENT.on("addColumnButton", "click", add_column);
EVENT.on(CPANEL.Y.all(".delete-link"), "click", deleteInput);
var api_form = DOM.get("api_form");
EVENT.on( CPANEL.Y(api_form).all("select"), "change", update_api_call );
initialize_comboboxes();
refresh_page_data();
}
function refresh_comboboxes() {
var form_data = CPANEL.dom.get_data_from_form( "api_form" );
var api_version = form_data.api_version;
for (var key in api_comboboxes) {
var cur_api_combobox = api_comboboxes[key];
if ( key === api_version ) {
cur_api_combobox.enable();
} else {
cur_api_combobox.disable();
}
}
}
function refresh_page_data() {
refresh_comboboxes();
update_api_call();
}
function initialize_comboboxes() {
var wrappers = CPANEL.Y.all("div.cjt-combobox-wrapper");
wrappers.forEach( function(wrapper) {
var api_version = wrapper.id.match(/(\d+)$/)[0];
var api_calls = window.PAGE.api_calls[api_version];
var input = CPANEL.Y(wrapper).one("input");
var expander = CPANEL.Y(wrapper).one(".cjt-combobox-expander");
var radio = CPANEL.Y.one("#api_radio_" + api_version);
var combobox = new CPANEL.widgets.Combobox(
input,
null,
api_calls,
{
queryMatchContains: true,
// Prevent YUI 2 AutoComplete from creating zillions of
// unused <li> elements.
maxResultsDisplayed: api_calls.length,
expander: expander
}
);
// Prevent API calls from being displayed as RTL text.
combobox.getListEl().dir = "ltr";
// NOTE: In YUI 3, this would make a nice "smart disable" plugin.
// If we need more of this behavior in YUI 2, though, it probably
// should just move to the Combobox prototype.
combobox.disableEvent.subscribe( function(e) {
var overlay = combobox._disable_overlay;
if ( !overlay ) {
overlay = new CPANEL.dom.Smart_Disable_Overlay(wrapper);
overlay.render(wrapper);
combobox._disable_overlay = overlay;
EVENT.on(overlay.element, "mousedown", function(e) {
overlay.hide();
radio.checked = true;
refresh_page_data();
input.focus();
// Apparently, a browser's default action from mousedown
// on a non-focusable element (e.g., overlay.element)
// is to focus document.body.
EVENT.preventDefault(e);
} );
}
overlay.align();
overlay.show();
} );
combobox.enableEvent.subscribe( function(e) {
if (combobox._disable_overlay) {
combobox._disable_overlay.hide();
}
} );
api_comboboxes[api_version] = combobox;
EVENT.on( radio, "click", refresh_page_data );
} );
}
// So we don’t render the same raw data twice.
var tId_rendered = {};
function display_raw_response(o) {
if (!tId_rendered[o.response.tId]) {
CPANEL.util.set_text_content("raw_status", o.response.status + " " + o.response.statusText);
DOM.get("raw_response").value = o.response.responseText;
DOM.get("raw_headers").value = o.response.getAllResponseHeaders.trim();
var http_cont_len = o.response.getResponseHeader["Content-Length"];
if (http_cont_len) {
http_cont_len = parseInt(http_cont_len, 10);
}
var comp, uncomp;
var is_gzipped = (o.response.getResponseHeader["Content-Encoding"] === "gzip");
if ( is_gzipped ) {
comp = http_cont_len;
} else {
uncomp = http_cont_len;
}
if (uncomp === undefined) {
uncomp = CPANEL.util.byte_length(o.response.responseText);
}
if ( comp !== undefined ) {
DOM.get("resp_length").innerHTML = LOCALE.maketext("[format_bytes,_1] compressed, [format_bytes,_2] uncompressed", comp, uncomp);
} else if ( is_gzipped ) {
DOM.get("resp_length").innerHTML = LOCALE.maketext("compressed size unknown, [format_bytes,_1] uncompressed", uncomp);
} else {
DOM.get("resp_length").innerHTML = LOCALE.format_bytes(uncomp);
}
}
}
/**
* Function which takes the API call object and executes it. It also subscribes
* events to handle failure / success and draw the content in the tab view.
*
* @method run_api_call
*/
function run_api_call(e) {
var LOCALE = window.LOCALE || new CPANEL.Locale();
var api_call = make_api_call_from_form();
if (!CPANEL.api.construct_url_path(api_call)) {
EVENT.stopEvent(e);
}
var datasource = new CPANEL.datasource.CPANEL_XHRDataSource( {
api_version: api_call.version,
module: api_call.module,
func: api_call.func
} );
var overlay = new CPANEL.ajax.Page_Progress_Overlay( null, {
covers: "api_form",
status_html: LOCALE.maketext("Retrieving API call results …")
} );
overlay.show();
var overlay_is_hidden = false;
datasource.subscribe( "dataErrorEvent", function(oArgs) {
if (!overlay_is_hidden) {
overlay.hide();
overlay_is_hidden = true;
}
display_raw_response(oArgs);
views.selectTab(2); // select the raw view
var message = oArgs.message;
if (oArgs.message === YAHOO.util.DataSourceBase.ERROR_DATANULL) {
message = LOCALE.maketext("Table View is unavailable for this function’s data.");
}
CPANEL.util.set_text_content("table_container", message);
DOM.get("table_record_count").innerHTML = "";
} );
datasource.subscribe( "responseParseEvent", function(oArgs) {
var records = oArgs.response.results,
columns;
if ( records ) {
if (records.length && (typeof records[0] === "object")) {
var keys = Object.keys(records[0]).sort();
var has_object_values = false;
columns = keys.map( function(k) {
if (typeof records[0][k] === "object") {
has_object_values = true;
}
return {
key: k,
resizeable: true,
formatter: "text",
sortable: true
};
} );
if (has_object_values) {
CPANEL.util.set_text_content("table_container", LOCALE.maketext("Table View is unavailable for this function’s data."));
DOM.get("table_record_count").innerHTML = "";
columns = [];
return;
}
DOM.get("table_record_count").innerHTML = LOCALE.maketext("[quant,_1,record,records], [quant,_2,field,fields] per record", records.length, keys.length);
} else {
CPANEL.util.set_text_content("table_container", LOCALE.maketext("Table View is unavailable for this function’s data."));
DOM.get("table_record_count").innerHTML = "";
columns = [];
return;
}
var recordsDatasource = new YAHOO.util.LocalDataSource(records);
var datatable = new YAHOO.widget.ScrollingDataTable("table_container", columns, recordsDatasource, {
initialLoad: false,
draggableColumns: true,
width: DATATABLE_WIDTH
} );
// This prevents a "jerk" of the page from re-rendering the table on sort.
var table_container_height;
datatable.subscribe( "beforeRenderEvent", function() {
table_container_height = CPANEL.dom.get_content_height("table_container");
DOM.setStyle("table_container", "height", table_container_height + "px");
} );
datatable.subscribe( "postRenderEvent", function() {
if (table_container_height) {
table_container_height = null;
DOM.setStyle("table_container", "height", "");
}
} );
datatable.load();
} else {
CPANEL.util.set_text_content("table_container", LOCALE.maketext("Table View is unavailable for this function’s data."));
}
} );
datasource.subscribe( "responseEvent", function(o) {
if (!overlay_is_hidden) {
overlay.hide();
overlay_is_hidden = true;
}
display_raw_response(o);
var response_obj;
try {
response_obj = YAHOO.lang.JSON.parse(o.response.responseText);
} catch (e) {}
if ( response_obj ) {
var treeview_data = make_treeview_data_from_object(response_obj);
var treeview = new YAHOO.widget.TreeView( "response_treeview", treeview_data );
treeview.render();
} else {
CPANEL.util.set_text_content("response_treeview", LOCALE.maketext("Invalid JSON."));
}
} );
datasource.makeConnection( api_call );
}
/**
* Function which generates a treeview by recursively traversing the object.
*
* @method make_treeview_data_from_object
* @param {Object} obj The data object to generate the treeview from.
*/
function make_treeview_data_from_object(obj) {
var items = [];
var obj_keys = Object.keys(obj);
if ( !(obj instanceof Array) ) {
obj_keys.sort();
}
for (var k = 0; k < obj_keys.length; k++) {
var key = obj_keys[k];
var new_item = { type: "Text" };
if ( YAHOO.lang.isObject(obj[key]) ) {
var obj_symbol;
if (YAHOO.lang.isArray(obj[key])) {
obj_symbol = "[ " + obj[key].length + " ]";
} else {
obj_symbol = "{ " + Object.keys(obj[key]).length + " }";
}
new_item.label = key + ": " + obj_symbol;
new_item.children = make_treeview_data_from_object( obj[key], new_item );
new_item.expanded = true;
} else {
new_item.label = key + ": " + YAHOO.lang.JSON.stringify(obj[key]);
}
items.push(new_item);
}
return items;
}
/**
* Function which parses the form for data to generate an object used in making the API
* call.
*
* @method make_api_call_from_form
* @return {Object} Returns an api_call object which stores all the values for the call
*/
function make_api_call_from_form() {
// This changes when we move to updated API system
var form_data = CPANEL.dom.get_data_from_form( "api_form" ),
selectedAPI = form_data["api_version"],
api_call = {};
var column = "",
num = "";
var full_func = form_data.functionSelect;
if (/:/.test(full_func)) {
api_call.module = ( full_func.match(/^[^:]+/) || [] )[0];
api_call.func = ( full_func.match(/[^:]+$/) || [] )[0];
} else {
api_call.func = full_func;
}
if ( selectedAPI ) {
api_call.version = selectedAPI;
}
for (var key in form_data) {
if ( !form_data[key] ) {
continue;
}
if ( /^variable_/.test(key) ) {
var variableMatch = key.match(/^variable_key_(.*)/);
if ( variableMatch ) {
if ( !("data" in api_call) ) {
api_call.data = {};
}
api_call.data[form_data[key]] = form_data["variable_value_" + variableMatch[1]];
}
} else if ( /^sort_/.test(key) ) {
var sortMatch = key.match(/^sort_column_(.*)/);
if ( sortMatch ) {
var sort_index = sortMatch[1],
sort_type = form_data["sort_type_" + sort_index],
is_reverse = form_data["sort_reverse_" + sort_index];
column = form_data[key];
if ( is_reverse ) {
column = "!" + column;
}
if ( !("api_data" in api_call) ) {
api_call.api_data = {};
}
if ( !("sort" in api_call.api_data) ) {
api_call.api_data.sort = [];
}
api_call.api_data.sort.push( [ column, sort_type ] );
}
} else if ( /^filter_/.test(key) ) {
var filterMatch = key.match(/^filter_type_(.*)/);
if ( filterMatch ) {
var filter_index = filterMatch[1],
filter_type = form_data[key],
filter_term = form_data["filter_term_" + filter_index];
column = form_data["filter_column_" + filter_index];
if (column === undefined) {
column = "*";
}
if (filter_term && filter_type && column) {
if ( !("api_data" in api_call) ) {
api_call.api_data = {};
}
if ( !("filter" in api_call.api_data) ) {
api_call.api_data.filter = [];
}
api_call.api_data.filter.push( [ column, filter_type, filter_term ] );
}
}
} else if ( /^columns_/.test(key) ) {
if ( !("api_data" in api_call) ) {
api_call.api_data = {};
}
if ( !("columns" in api_call.api_data) ) {
api_call.api_data.columns = [];
}
api_call.api_data.columns.push(form_data[key]);
}
}
if (form_data["page_start"]) {
num = Number(form_data["page_start"]);
if (num) {
if ( !("api_data" in api_call) ) {
api_call.api_data = {};
}
if ( !api_call.api_data.paginate ) {
api_call.api_data.paginate = {};
}
api_call.api_data.paginate.start = num;
}
}
if (form_data["page_size"]) {
num = Number(form_data["page_size"]);
if (num) {
if ( !("api_data" in api_call) ) {
api_call.api_data = {};
}
if ( !api_call.api_data.paginate ) {
api_call.api_data.paginate = {};
}
api_call.api_data.paginate.size = num;
}
}
return api_call;
}
/**
* Function which updates the API call. This includes regenerating the API call object and redrawing
* elements on the page such as the API tree view.
*
* @method update_api_call
*/
function update_api_call() {
var api_call = make_api_call_from_form(),
api_call_treeview_data = make_treeview_data_from_object(api_call),
api_call_treeview = new YAHOO.widget.TreeView( "api_treeview", api_call_treeview_data );
var query_url = CPANEL.api.construct_url_path(api_call) || "";
if ( query_url ) {
var query = CPANEL.api.construct_query(api_call);
if (query) {
query_url += "?" + query;
}
api_call_treeview.render();
}
DOM.get("submit_button").disabled = !query_url;
DOM[ !!query_url ? "removeClass" : "addClass" ]( "api_treeview", "invalid-data" );
CPANEL.util.set_text_content("url", query_url.replace( new RegExp("^" + CPANEL.security_token), "" ) );
}
/**
* Function which takes in a template node and inserts it into the caller's associated
* .inputContainer. Once these nodes are inserted an onClick event is tied to the .delete-link
* so that the user can easily remove it.
*
* @method addInputWithTemplate
* @param {String} template A Template to be cloned and appended to the caller
* @param {Object} caller The scope in which to find the parent.
*/
function addInputWithTemplate(template, caller) {
var inputContainer = DOM.getAncestorByClassName(caller, "inputContainer"),
inputFields = CPANEL.Y(inputContainer).one(".inputFields"),
inputFieldCount = CPANEL.Y(inputContainer).all(".inputField").length,
docFragment = document.createDocumentFragment(),
div = document.createElement("div");
div.innerHTML = YAHOO.lang.substitute( template, { index: DOM.generateId() } );
docFragment.appendChild(div);
var cloneNode = docFragment.firstChild.firstChild;
if ( !inputFieldCount ) {
CPANEL.animate.slide_up(CPANEL.Y(inputFields).one(".noneField"));
inputFields.appendChild(cloneNode);
} else {
inputFields.appendChild(cloneNode);
}
CPANEL.animate.slide_down(cloneNode);
EVENT.on(CPANEL.Y(cloneNode).one(".delete-link"), "click", deleteInput);
EVENT.on(CPANEL.Y(cloneNode).one("input[name^='sort_reverse']"), "change", update_api_call);
EVENT.on(CPANEL.Y(cloneNode).one("input[type='text']"), "paste", update_api_call);
EVENT.on(CPANEL.Y(cloneNode).one("input[type='text']"), "input", update_api_call);
}
/**
* Function which removes associated input field.
* Bound to ".delete-link" onClick events.
*
* @method deleteInput
*/
function deleteInput() {
EVENT.purgeElement(this);// We remove the event listener to prevent double clicking
var inputToDelete = DOM.getAncestorByClassName(this, "inputField"),
parentContainer = DOM.getAncestorByClassName(this, "inputContainer"),
slideAnimation = CPANEL.animate.slide_toggle(inputToDelete);
slideAnimation.onComplete.subscribe( function() {
inputToDelete.parentNode.removeChild(inputToDelete);
update_api_call();
var inputField = CPANEL.Y(parentContainer).all(".inputField");
if ( !inputField.length ) {
CPANEL.animate.slide_toggle(CPANEL.Y(parentContainer).one(".noneField"));
}
});
}
/**
* Event handle function which adds variable input fields to parent div.
* Bound to ".addVariableButton" onClick events.
*
* @method add_variable
*/
function add_variable() {
addInputWithTemplate(variableRowTemplate, this);
}
/**
* Event handle function which adds sort input fields to parent div.
* Bound to ".addSortButton" onClick events.
*
* @method add_sort
*/
function add_sort() {
addInputWithTemplate(sortRowTemplate, this);
}
/**
* Event handle function which adds filter input fields to parent div.
* Bound to ".addFilterButton" onClick events.
*
* @method add_filter
*/
function add_filter() {
addInputWithTemplate(filterRowTemplate, this);
}
/**
* Event handle function which adds filter input fields to parent div.
* Bound to ".addFilterButton" onClick events.
*
* @method add_column
*/
function add_column() {
addInputWithTemplate(columnRowTemplate, this);
}
/**
* Function which shows and hides the metadata div.
*
* @method toggle_metadata
*/
function toggle_metadata() {
var metadataButton = CPANEL.Y.one("#metadataToggle");
if ( METADATA_SHOWN ) {
CPANEL.animate.slide_toggle("metadata");
metadataButton.innerHTML = LOCALE.maketext("Show Sort/Filter/Paginate Options");
} else {
CPANEL.animate.slide_toggle("metadata");
metadataButton.innerHTML = LOCALE.maketext("Hide Sort/Filter/Paginate Options");
}
METADATA_SHOWN = !METADATA_SHOWN;
}
for (var x = 0; x < inputsOnPageLoad; x++) {
addInputWithTemplate(variableRowTemplate, CPANEL.Y.one("#addVariableButton"));
}
views.addTab( new YAHOO.widget.Tab( {
label: LOCALE.maketext("Tree view"),
contentEl: DOM.get("tree_view_container"),
active: true
} ) );
views.addTab( new YAHOO.widget.Tab( {
label: LOCALE.maketext("Table view"),
contentEl: DOM.get("table_view_container")
} ) );
views.addTab( new YAHOO.widget.Tab( {
label: LOCALE.maketext("Raw view"),
contentEl: DOM.get("raw_view_container")
} ) );
EVENT.onDOMReady(init);
})(window);
Back to Directory
File Manager