utils.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. var multipleClustersSupported = false;
  2. /* Super-handy augmentation to Function that allows 'this' to be bound
  3. * statically.
  4. *
  5. * Primarily used when creating objects whose methods will be used as
  6. * callbacks in unknown contexts.
  7. *
  8. * Look at txnUtils.js for sample usage.
  9. */
  10. Function.prototype.bind = function(scope) {
  11. var _function = this;
  12. return function() {
  13. return _function.apply(scope, arguments);
  14. }
  15. }
  16. /* Belongs with createInformationalPanel() */
  17. var customizedYuiPanelCss = false;
  18. /* XXX Ugly, ugly hack to emulate a singleton - users are NEVER supposed
  19. * to use this, and should only access the createInformationalPanel() and
  20. * destroyInformationalPanel() methods below.
  21. */
  22. var globalSingletonInformationalPanel;
  23. function createInformationalPanel( containerNodeId, headerContentString ) {
  24. /* XXX This should check that globalSingletonInformationalPanel is within
  25. * containerNodeId, and only then perform this cleanup, but this whole
  26. * panel-related section needs to be rewritten anyway - for now, we only
  27. * support the one globalSingletonInformationalPanel, and passing in
  28. * anything other than #informationalPanelContainerDivId as containerNodeId
  29. * is not guaranteed to work.
  30. */
  31. if( globalSingletonInformationalPanel ) {
  32. destroyInformationalPanel( globalSingletonInformationalPanel );
  33. }
  34. globalYui.one( containerNodeId ).append('<div id="informationalPanelInnerContainerDivId"></div>');
  35. var newPanel = new globalYui.Panel({
  36. srcNode: '#informationalPanelInnerContainerDivId',
  37. headerContent: headerContentString,
  38. width: 800,
  39. height: 400,
  40. render: true,
  41. modal: true,
  42. zIndex: 100,
  43. centered: true,
  44. visible: false
  45. });
  46. if( !customizedYuiPanelCss ) {
  47. /* Needs to be called one time only.
  48. *
  49. * We do this here instead of creating a static entry in a CSS file
  50. * because the first invocation of globalYui.Panel (above) pulls in all
  51. * the necessary additional styling information that is applied to the
  52. * panel - since this new styling information comes in at runtime, it
  53. * overrides any static CSS we might have had, so adding our overrides
  54. * at runtime (*after* globalYui.Panel) is the only way out.
  55. */
  56. /*
  57. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-hd', {
  58. background: 'rgb(50,185,50)',
  59. textAlign: 'center',
  60. fontWeight: 'bold',
  61. fontSize: '150%'
  62. });
  63. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel .yui3-widget-hd .yui3-button-close', {
  64. border: 'medium solid gray',
  65. backgroundColor: 'white',
  66. height: '17px',
  67. width: '20px',
  68. });
  69. */
  70. // Temporary fix to a yui bug
  71. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel .yui3-widget-hd .yui3-button-close:before', {
  72. content: 'url(../yui-3.5.1/build/assets/skins/sam/sprite_icons.png)',
  73. backgroundImage: 'url(../yui-3.5.1/build/assets/skins/sam/sprite_icons.png)',
  74. });
  75. /*
  76. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-ft', {
  77. background: 'rgb(50,185,50)',
  78. });
  79. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-ft .yui3-button', {
  80. fontWeight: 'bold',
  81. fontSize: '135%',
  82. color: 'white',
  83. margin: '0pt 6px',
  84. padding: '4px 8px',
  85. textDecoration: 'underline',
  86. background: 'none',
  87. border: '0px'
  88. });
  89. */
  90. customizedYuiPanelCss = true;
  91. }
  92. globalSingletonInformationalPanel = newPanel;
  93. return newPanel;
  94. }
  95. function destroyInformationalPanel( theInformationalPanelInstance ) {
  96. if( theInformationalPanelInstance ) {
  97. theInformationalPanelInstance.hide();
  98. theInformationalPanelInstance.destroy();
  99. if( theInformationalPanelInstance === globalSingletonInformationalPanel ) {
  100. globalSingletonInformationalPanel = null;
  101. }
  102. }
  103. }
  104. function showLoadingImg() {
  105. globalYui.one("#loadingDivId").setStyle('display','block');
  106. //globalYui.one("#blackScreenDivId").setStyle('display','block');
  107. //globalYui.one("#loadingImgId").setStyle('display','block');
  108. }
  109. function hideLoadingImg() {
  110. globalYui.one("#loadingDivId").setStyle('display','none');
  111. //globalYui.one("#loadingImgId").setStyle('display','none');
  112. //globalYui.one("#blackScreenDivId").setStyle('display','none');
  113. }
  114. function swapStageVisibilities( currentStageDivSelector, newStageDivSelector ) {
  115. globalYui.log("In swapStageVisibilities: " + currentStageDivSelector + "->" + newStageDivSelector);
  116. /* Hide the current stage. */
  117. globalYui.one(currentStageDivSelector).setStyle('display','none');
  118. /* Show the new stage. */
  119. globalYui.one(newStageDivSelector).setStyle('display','block');
  120. }
  121. /* TODO XXX Consider bundling the last 3 parameters into their own NewStage object.
  122. * TODO XXX Do the same for the first 2 parameters and a CurrentStage object.
  123. */
  124. function transitionToNextStage( currentStageDivSelector, currentStageData, newStageDivSelector, newStageData, newStageRenderFunction ) {
  125. clearFormStatus();
  126. globalYui.one(currentStageDivSelector).setStyle('display','none');
  127. /* Render the next stage. */
  128. newStageRenderFunction(newStageData);
  129. globalYui.log("In transitionToNextStage: " + currentStageDivSelector + "->" + newStageDivSelector);
  130. //// tshooter: No longer doing this given dynamic rendering on stages. Only hide current stage.
  131. /* And make it visibly replace the currently showing one. */
  132. ///// tshooter: commented: swapStageVisibilities(currentStageDivSelector, newStageDivSelector);
  133. /* And now, handle the updates to addNodesWizardStages... */
  134. /* There can be only one 'current' stage at a time. */
  135. var currentStage = globalYui.one('.installationWizardCurrentStage');
  136. if ( currentStage ) {
  137. var nextStage = null;
  138. /* Check to make sure we haven't reached the last stage. */
  139. if( nextStage = currentStage.next('.installationWizardUnvisitedStage') ) {
  140. /* Mark this up-until-now 'current' stage as 'visited'. */
  141. currentStage.replaceClass( 'installationWizardCurrentStage', 'installationWizardVisitedStage' );
  142. /* Mark the stage after that as the new 'current' stage. */
  143. nextStage.replaceClass( 'installationWizardUnvisitedStage', 'installationWizardCurrentStage' );
  144. }
  145. }
  146. }
  147. function clearFormStatus() {
  148. var formStatusDiv = globalYui.all("#formStatusDivId");
  149. // formStatusDiv.setContent("");
  150. formStatusDiv.setStyle("visibility", "hidden");
  151. formStatusDiv.setStyle("display", "none");
  152. formStatusDiv.set('className','');
  153. formStatusDiv.addClass("formStatusBar");
  154. }
  155. function setFormStatus(statusString, isError, noFade) {
  156. var formStatusDivCssClass;
  157. if (isError) {
  158. formStatusDivCssClass = 'statusError';
  159. } else {
  160. formStatusDivCssClass = 'statusOk';
  161. }
  162. var formStatusDiv = globalYui.all("#formStatusDivId");
  163. formStatusDiv.setStyle("visibility", "visible");
  164. formStatusDiv.setStyle("display", "block");
  165. formStatusDiv.set('className','');
  166. formStatusDiv.addClass("formStatusBar");
  167. formStatusDiv.addClass(formStatusDivCssClass);
  168. formStatusDiv.setContent(statusString);
  169. if (!isError && !noFade) {
  170. //setTimeout(fadeFormStatus, 1000);
  171. }
  172. }
  173. function fadeFormStatus() {
  174. var formStatusDiv = globalYui.one("#formStatusDivId");
  175. formStatusDiv.addClass("formStatusBarZeroOpacity");
  176. }
  177. function convertDisplayType (displayType) {
  178. switch (displayType) {
  179. case "NODISPLAY":
  180. return "NODISPLAY";
  181. case "TEXT":
  182. return "text";
  183. case "SECRET":
  184. return "password";
  185. case "ONOFF":
  186. return "checkbox";
  187. default:
  188. return "text";
  189. }
  190. }
  191. function executeStage(inputUrl, renderStageFunction) {
  192. globalYui.io(inputUrl, {
  193. method: 'GET',
  194. timeout : 10000,
  195. on: {
  196. success: function (x,o) {
  197. globalYui.log("RAW JSON DATA: " + o.responseText);
  198. // Process the JSON data returned from the server
  199. try {
  200. responseJson = globalYui.JSON.parse(o.responseText);
  201. }
  202. catch (e) {
  203. hideLoadingImg();
  204. alert("JSON Parse failed!");
  205. return;
  206. }
  207. globalYui.log("PARSED DATA: " + globalYui.Lang.dump(responseJson));
  208. if (responseJson.result != 0) {
  209. hideLoadingImg();
  210. // Error!
  211. alert("Got error during getting data: " + responseJson.error);
  212. return;
  213. }
  214. responseJson = responseJson.response;
  215. renderStageFunction(responseJson);
  216. hideLoadingImg();
  217. return;
  218. },
  219. failure: function (x,o) {
  220. alert("Async call failed!");
  221. return;
  222. }
  223. }
  224. });
  225. }
  226. function submitDataAndProgressToNextScreen(url, requestData, submitButton, thisScreenId, nextScreenId, nextScreenRenderFunction, errorHandlerFunction) {
  227. showLoadingImg();
  228. globalYui.io(url, {
  229. method: 'POST',
  230. data: globalYui.JSON.stringify(requestData),
  231. timeout : 10000,
  232. on: {
  233. start: function(x, o) {
  234. submitButton.set('disabled', true);
  235. globalYui.log("In start function");
  236. // showLoadingImg();
  237. },
  238. complete: function(x, o) {
  239. submitButton.set('disabled', false);
  240. globalYui.log("In stop function");
  241. // hideLoadingImg();
  242. },
  243. success: function (x,o) {
  244. submitButton.set('disabled', false);
  245. globalYui.log("RAW JSON DATA: " + o.responseText);
  246. // Process the JSON data returned from the server
  247. try {
  248. responseJson = globalYui.JSON.parse(o.responseText);
  249. }
  250. catch (e) {
  251. submitButton.set('disabled', false);
  252. hideLoadingImg();
  253. alert("JSON Parse failed!");
  254. return;
  255. }
  256. globalYui.log("PARSED DATA: " + globalYui.Lang.dump(responseJson));
  257. if (responseJson.result != 0) {
  258. submitButton.set('disabled', false);
  259. // Error!
  260. globalYui.log("Got error during submit data!" + responseJson.error);
  261. if ( errorHandlerFunction ) {
  262. globalYui.log("Invoking error handler function");
  263. errorHandlerFunction(responseJson);
  264. } else {
  265. alert("Got error during submit data!" + responseJson.error);
  266. }
  267. hideLoadingImg();
  268. return;
  269. }
  270. responseJson = responseJson.response;
  271. /* Done with this stage, transition to the next. */
  272. transitionToNextStage( thisScreenId, requestData, nextScreenId, responseJson, nextScreenRenderFunction );
  273. },
  274. failure: function (x,o) {
  275. submitButton.set('disabled', false);
  276. alert("Async call failed!");
  277. }
  278. }
  279. });
  280. }
  281. function PeriodicDataPoller( dataSourceContext, responseHandler ) {
  282. this.dataSourceContext = dataSourceContext;
  283. /* Smoothe out the optional bits of this.dataSourceContext. */
  284. if( !this.dataSourceContext.pollInterval ) {
  285. /* How often we poll. */
  286. this.dataSourceContext.pollInterval = 5000;
  287. }
  288. if( !this.dataSourceContext.maxFailedAttempts ) {
  289. /* How many failed attempts before we stop polling. */
  290. this.dataSourceContext.maxFailedAttempts = 25;
  291. }
  292. this.responseHandler = responseHandler;
  293. /* Of course, we're not paused when we start off. */
  294. this.paused = false;
  295. this.dataSource = new globalYui.DataSource.IO ({
  296. source: this.dataSourceContext.source
  297. });
  298. this.dataSource.plug(globalYui.Plugin.DataSourceJSONSchema, {
  299. schema: this.dataSourceContext.schema
  300. });
  301. this.dataSourcePollFailureCount = 0;
  302. /* Set when start() is invoked. */
  303. this.dataSourcePollHandle = null;
  304. this.dataSourcePollRequestContext = {
  305. request: this.dataSourceContext.request,
  306. callback: {
  307. success: function (e) {
  308. /* Avoid race conditions in JS by not processing incoming responses
  309. * from the backend if the PDP is paused (which is our signal that
  310. * a previous response is still in the middle of being processed).
  311. */
  312. if( !(this.isPaused()) ) {
  313. /* Reset our failure count every time we succeed. */
  314. this.dataSourcePollFailureCount = 0;
  315. /* Invoke user-pluggable code. */
  316. if( this.responseHandler.success ) {
  317. this.responseHandler.success( e, this );
  318. }
  319. }
  320. }.bind(this),
  321. failure: function (e) {
  322. if( !(this.isPaused()) ) {
  323. ++this.dataSourcePollFailureCount;
  324. if( this.dataSourcePollFailureCount > this.dataSourceContext.maxFailedAttempts ) {
  325. /* Invoke user-pluggable code. */
  326. if( this.responseHandler.failure ) {
  327. this.responseHandler.failure( e, this );
  328. }
  329. /* No point making any more attempts. */
  330. this.stop();
  331. }
  332. }
  333. }.bind(this)
  334. }
  335. };
  336. }
  337. /* Start polling. */
  338. PeriodicDataPoller.prototype.start = function() {
  339. this.dataSourcePollHandle = this.dataSource.setInterval
  340. ( this.dataSourceContext.pollInterval, this.dataSourcePollRequestContext );
  341. }
  342. /* Stop polling. */
  343. PeriodicDataPoller.prototype.stop = function() {
  344. /* Always unPause() during stop(), so the next start() won't be neutered. */
  345. this.unPause();
  346. this.dataSource.clearInterval( this.dataSourcePollHandle );
  347. }
  348. /* When the PDP is paused, the polling continues on its regular fixed
  349. * interval, but this.responseHandler is not invoked, thus avoiding
  350. * a race condition (at least) in JS.
  351. *
  352. * TODO XXX Improve upon this to not even make calls to the backend
  353. * while not losing our periodicity.
  354. */
  355. PeriodicDataPoller.prototype.pause = function() {
  356. this.paused = true;
  357. }
  358. PeriodicDataPoller.prototype.unPause = function() {
  359. this.paused = false;
  360. }
  361. PeriodicDataPoller.prototype.isPaused = function() {
  362. return this.paused;
  363. }
  364. /* Perform a one-time poll.
  365. *
  366. * Meant to be used when the polling is not at a set frequency (as with the
  367. * start()/stop() pair), and is instead meant to be under explicit
  368. * control of the application.
  369. */
  370. PeriodicDataPoller.prototype.pollOnce = function() {
  371. globalYui.io(this.dataSourceContext.source + this.dataSourcePollRequestContext.request, {
  372. on: this.dataSourcePollRequestContext.callback
  373. });
  374. }
  375. function titleCase(word){
  376. return word.substr(0,1).toUpperCase() + word.substr(1).toLowerCase();
  377. }
  378. function generateHMCUrl( uriPath ) {
  379. var url = '';
  380. /* By default, go to the HMC home page. */
  381. uriPath = ( typeof uriPath == "undefined" ) ? '/hmc/html/index.php' : uriPath;
  382. var currentUrl = window.location.href;
  383. globalYui.log('Current URL: ' + currentUrl);
  384. var currentPathPos = currentUrl.indexOf(window.location.pathname);
  385. globalYui.log('Current Path Pos: ' + currentPathPos);
  386. if( -1 != currentPathPos ) {
  387. url = currentUrl.substr(0, currentPathPos) + uriPath;
  388. }
  389. return url;
  390. }