blob: d7ddcbb30e4b49b62301b00611e8ba39bf301573 [file] [log] [blame]
var multipleClustersSupported = false;
/* Super-handy augmentation to Function that allows 'this' to be bound
* statically.
*
* Primarily used when creating objects whose methods will be used as
* callbacks in unknown contexts.
*
* Look at txnUtils.js for sample usage.
*/
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
}
}
/* Belongs with createInformationalPanel() */
var customizedYuiPanelCss = false;
/* XXX Ugly, ugly hack to emulate a singleton - users are NEVER supposed
* to use this, and should only access the createInformationalPanel() and
* destroyInformationalPanel() methods below.
*/
var globalSingletonInformationalPanel;
function createInformationalPanel( containerNodeId, headerContentString ) {
/* XXX This should check that globalSingletonInformationalPanel is within
* containerNodeId, and only then perform this cleanup, but this whole
* panel-related section needs to be rewritten anyway - for now, we only
* support the one globalSingletonInformationalPanel, and passing in
* anything other than #informationalPanelContainerDivId as containerNodeId
* is not guaranteed to work.
*/
if( globalSingletonInformationalPanel ) {
destroyInformationalPanel( globalSingletonInformationalPanel );
}
globalYui.one( containerNodeId ).append('<div id="informationalPanelInnerContainerDivId"></div>');
var newPanel = new globalYui.Panel({
srcNode: '#informationalPanelInnerContainerDivId',
headerContent: headerContentString,
width: 800,
height: 400,
render: true,
modal: true,
zIndex: 100,
centered: true,
visible: false
});
if( !customizedYuiPanelCss ) {
/* Needs to be called one time only.
*
* We do this here instead of creating a static entry in a CSS file
* because the first invocation of globalYui.Panel (above) pulls in all
* the necessary additional styling information that is applied to the
* panel - since this new styling information comes in at runtime, it
* overrides any static CSS we might have had, so adding our overrides
* at runtime (*after* globalYui.Panel) is the only way out.
*/
/*
globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-hd', {
background: 'rgb(50,185,50)',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '150%'
});
globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel .yui3-widget-hd .yui3-button-close', {
border: 'medium solid gray',
backgroundColor: 'white',
height: '17px',
width: '20px',
});
*/
// Temporary fix to a yui bug
globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel .yui3-widget-hd .yui3-button-close:before', {
content: 'url(../yui-3.5.1/build/assets/skins/sam/sprite_icons.png)',
backgroundImage: 'url(../yui-3.5.1/build/assets/skins/sam/sprite_icons.png)',
});
/*
globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-ft', {
background: 'rgb(50,185,50)',
});
globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-ft .yui3-button', {
fontWeight: 'bold',
fontSize: '135%',
color: 'white',
margin: '0pt 6px',
padding: '4px 8px',
textDecoration: 'underline',
background: 'none',
border: '0px'
});
*/
customizedYuiPanelCss = true;
}
globalSingletonInformationalPanel = newPanel;
return newPanel;
}
function destroyInformationalPanel( theInformationalPanelInstance ) {
if( theInformationalPanelInstance ) {
theInformationalPanelInstance.hide();
theInformationalPanelInstance.destroy();
if( theInformationalPanelInstance === globalSingletonInformationalPanel ) {
globalSingletonInformationalPanel = null;
}
}
}
function showLoadingImg() {
globalYui.one("#loadingDivId").setStyle('display','block');
//globalYui.one("#blackScreenDivId").setStyle('display','block');
//globalYui.one("#loadingImgId").setStyle('display','block');
}
function hideLoadingImg() {
globalYui.one("#loadingDivId").setStyle('display','none');
//globalYui.one("#loadingImgId").setStyle('display','none');
//globalYui.one("#blackScreenDivId").setStyle('display','none');
}
function swapStageVisibilities( currentStageDivSelector, newStageDivSelector ) {
globalYui.log("In swapStageVisibilities: " + currentStageDivSelector + "->" + newStageDivSelector);
/* Hide the current stage. */
globalYui.one(currentStageDivSelector).setStyle('display','none');
/* Show the new stage. */
globalYui.one(newStageDivSelector).setStyle('display','block');
}
/* TODO XXX Consider bundling the last 3 parameters into their own NewStage object.
* TODO XXX Do the same for the first 2 parameters and a CurrentStage object.
*/
function transitionToNextStage( currentStageDivSelector, currentStageData, newStageDivSelector, newStageData, newStageRenderFunction ) {
clearFormStatus();
globalYui.one(currentStageDivSelector).setStyle('display','none');
/* Render the next stage. */
newStageRenderFunction(newStageData);
globalYui.log("In transitionToNextStage: " + currentStageDivSelector + "->" + newStageDivSelector);
//// tshooter: No longer doing this given dynamic rendering on stages. Only hide current stage.
/* And make it visibly replace the currently showing one. */
///// tshooter: commented: swapStageVisibilities(currentStageDivSelector, newStageDivSelector);
/* And now, handle the updates to addNodesWizardStages... */
/* There can be only one 'current' stage at a time. */
var currentStage = globalYui.one('.installationWizardCurrentStage');
if ( currentStage ) {
var nextStage = null;
/* Check to make sure we haven't reached the last stage. */
if( nextStage = currentStage.next('.installationWizardUnvisitedStage') ) {
/* Mark this up-until-now 'current' stage as 'visited'. */
currentStage.replaceClass( 'installationWizardCurrentStage', 'installationWizardVisitedStage' );
/* Mark the stage after that as the new 'current' stage. */
nextStage.replaceClass( 'installationWizardUnvisitedStage', 'installationWizardCurrentStage' );
}
}
}
function clearFormStatus() {
var formStatusDiv = globalYui.all("#formStatusDivId");
// formStatusDiv.setContent("");
formStatusDiv.setStyle("visibility", "hidden");
formStatusDiv.setStyle("display", "none");
formStatusDiv.set('className','');
formStatusDiv.addClass("formStatusBar");
}
function setFormStatus(statusString, isError, noFade) {
var formStatusDivCssClass;
if (isError) {
formStatusDivCssClass = 'statusError';
} else {
formStatusDivCssClass = 'statusOk';
}
var formStatusDiv = globalYui.all("#formStatusDivId");
formStatusDiv.setStyle("visibility", "visible");
formStatusDiv.setStyle("display", "block");
formStatusDiv.set('className','');
formStatusDiv.addClass("formStatusBar");
formStatusDiv.addClass(formStatusDivCssClass);
formStatusDiv.setContent(statusString);
if (!isError && !noFade) {
//setTimeout(fadeFormStatus, 1000);
}
}
function fadeFormStatus() {
var formStatusDiv = globalYui.one("#formStatusDivId");
formStatusDiv.addClass("formStatusBarZeroOpacity");
}
function convertDisplayType (displayType) {
switch (displayType) {
case "NODISPLAY":
return "NODISPLAY";
case "TEXT":
return "text";
case "SECRET":
return "password";
case "ONOFF":
return "checkbox";
default:
return "text";
}
}
function executeStage(inputUrl, renderStageFunction) {
globalYui.io(inputUrl, {
method: 'GET',
timeout : 10000,
on: {
success: function (x,o) {
globalYui.log("RAW JSON DATA: " + o.responseText);
// Process the JSON data returned from the server
try {
responseJson = globalYui.JSON.parse(o.responseText);
}
catch (e) {
hideLoadingImg();
alert("JSON Parse failed!");
return;
}
globalYui.log("PARSED DATA: " + globalYui.Lang.dump(responseJson));
if (responseJson.result != 0) {
hideLoadingImg();
// Error!
alert("Got error during getting data: " + responseJson.error);
return;
}
responseJson = responseJson.response;
renderStageFunction(responseJson);
hideLoadingImg();
return;
},
failure: function (x,o) {
alert("Async call failed!");
return;
}
}
});
}
function submitDataAndProgressToNextScreen(url, requestData, submitButton, thisScreenId, nextScreenId, nextScreenRenderFunction, errorHandlerFunction) {
showLoadingImg();
globalYui.io(url, {
method: 'POST',
data: globalYui.JSON.stringify(requestData),
timeout : 10000,
on: {
start: function(x, o) {
submitButton.set('disabled', true);
globalYui.log("In start function");
// showLoadingImg();
},
complete: function(x, o) {
submitButton.set('disabled', false);
globalYui.log("In stop function");
// hideLoadingImg();
},
success: function (x,o) {
submitButton.set('disabled', false);
globalYui.log("RAW JSON DATA: " + o.responseText);
// Process the JSON data returned from the server
try {
responseJson = globalYui.JSON.parse(o.responseText);
}
catch (e) {
submitButton.set('disabled', false);
hideLoadingImg();
alert("JSON Parse failed!");
return;
}
globalYui.log("PARSED DATA: " + globalYui.Lang.dump(responseJson));
if (responseJson.result != 0) {
submitButton.set('disabled', false);
// Error!
globalYui.log("Got error during submit data!" + responseJson.error);
if ( errorHandlerFunction ) {
globalYui.log("Invoking error handler function");
errorHandlerFunction(responseJson);
} else {
alert("Got error during submit data!" + responseJson.error);
}
hideLoadingImg();
return;
}
responseJson = responseJson.response;
/* Done with this stage, transition to the next. */
transitionToNextStage( thisScreenId, requestData, nextScreenId, responseJson, nextScreenRenderFunction );
},
failure: function (x,o) {
submitButton.set('disabled', false);
alert("Async call failed!");
}
}
});
}
function PeriodicDataPoller( dataSourceContext, responseHandler ) {
this.dataSourceContext = dataSourceContext;
/* Smoothe out the optional bits of this.dataSourceContext. */
if( !this.dataSourceContext.pollInterval ) {
/* How often we poll. */
this.dataSourceContext.pollInterval = 5000;
}
if( !this.dataSourceContext.maxFailedAttempts ) {
/* How many failed attempts before we stop polling. */
this.dataSourceContext.maxFailedAttempts = 25;
}
this.responseHandler = responseHandler;
/* Of course, we're not paused when we start off. */
this.paused = false;
this.dataSource = new globalYui.DataSource.IO ({
source: this.dataSourceContext.source
});
this.dataSource.plug(globalYui.Plugin.DataSourceJSONSchema, {
schema: this.dataSourceContext.schema
});
this.dataSourcePollFailureCount = 0;
/* Set when start() is invoked. */
this.dataSourcePollHandle = null;
this.dataSourcePollRequestContext = {
request: this.dataSourceContext.request,
callback: {
success: function (e) {
/* Avoid race conditions in JS by not processing incoming responses
* from the backend if the PDP is paused (which is our signal that
* a previous response is still in the middle of being processed).
*/
if( !(this.isPaused()) ) {
/* Reset our failure count every time we succeed. */
this.dataSourcePollFailureCount = 0;
/* Invoke user-pluggable code. */
if( this.responseHandler.success ) {
this.responseHandler.success( e, this );
}
}
}.bind(this),
failure: function (e) {
if( !(this.isPaused()) ) {
++this.dataSourcePollFailureCount;
if( this.dataSourcePollFailureCount > this.dataSourceContext.maxFailedAttempts ) {
/* Invoke user-pluggable code. */
if( this.responseHandler.failure ) {
this.responseHandler.failure( e, this );
}
/* No point making any more attempts. */
this.stop();
}
}
}.bind(this)
}
};
}
/* Start polling. */
PeriodicDataPoller.prototype.start = function() {
this.dataSourcePollHandle = this.dataSource.setInterval
( this.dataSourceContext.pollInterval, this.dataSourcePollRequestContext );
}
/* Stop polling. */
PeriodicDataPoller.prototype.stop = function() {
/* Always unPause() during stop(), so the next start() won't be neutered. */
this.unPause();
this.dataSource.clearInterval( this.dataSourcePollHandle );
}
/* When the PDP is paused, the polling continues on its regular fixed
* interval, but this.responseHandler is not invoked, thus avoiding
* a race condition (at least) in JS.
*
* TODO XXX Improve upon this to not even make calls to the backend
* while not losing our periodicity.
*/
PeriodicDataPoller.prototype.pause = function() {
this.paused = true;
}
PeriodicDataPoller.prototype.unPause = function() {
this.paused = false;
}
PeriodicDataPoller.prototype.isPaused = function() {
return this.paused;
}
/* Perform a one-time poll.
*
* Meant to be used when the polling is not at a set frequency (as with the
* start()/stop() pair), and is instead meant to be under explicit
* control of the application.
*/
PeriodicDataPoller.prototype.pollOnce = function() {
globalYui.io(this.dataSourceContext.source + this.dataSourcePollRequestContext.request, {
on: this.dataSourcePollRequestContext.callback
});
}
function titleCase(word){
return word.substr(0,1).toUpperCase() + word.substr(1).toLowerCase();
}
function generateHMCUrl( uriPath ) {
var url = '';
/* By default, go to the HMC home page. */
uriPath = ( typeof uriPath == "undefined" ) ? '/hmc/html/index.php' : uriPath;
var currentUrl = window.location.href;
globalYui.log('Current URL: ' + currentUrl);
var currentPathPos = currentUrl.indexOf(window.location.pathname);
globalYui.log('Current Path Pos: ' + currentPathPos);
if( -1 != currentPathPos ) {
url = currentUrl.substr(0, currentPathPos) + uriPath;
}
return url;
}