utils.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. globalYui.one( '#informationalPanelInnerContainerDivId' ).append( '<div class="yui3-widget-hd"></div>' );
  36. globalYui.one( '#informationalPanelInnerContainerDivId' ).append( '<div class="yui3-widget-bd"></div>' );
  37. globalYui.one( '#informationalPanelInnerContainerDivId' ).append( '<div class="yui3-widget-ft"></div>' );
  38. var newPanel = new globalYui.Panel({
  39. srcNode: '#informationalPanelInnerContainerDivId',
  40. headerContent: headerContentString,
  41. width: 800,
  42. height: 400,
  43. render: true,
  44. modal: true,
  45. zIndex: 100,
  46. visible: false
  47. });
  48. if( !customizedYuiPanelCss ) {
  49. /* Needs to be called one time only.
  50. *
  51. * We do this here instead of creating a static entry in a CSS file
  52. * because the first invocation of globalYui.Panel (above) pulls in all
  53. * the necessary additional styling information that is applied to the
  54. * panel - since this new styling information comes in at runtime, it
  55. * overrides any static CSS we might have had, so adding our overrides
  56. * at runtime (*after* globalYui.Panel) is the only way out.
  57. */
  58. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-hd', {
  59. background: 'rgb(50,185,50)',
  60. textAlign: 'center',
  61. fontWeight: 'bold',
  62. fontSize: '150%'
  63. });
  64. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel .yui3-widget-hd .yui3-button-close', {
  65. border: 'medium solid gray',
  66. backgroundColor: 'white',
  67. height: '17px',
  68. width: '20px',
  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. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-ft', {
  76. background: 'rgb(50,185,50)',
  77. });
  78. globalYui.StyleSheet('KewlApp').set( '.yui3-skin-sam .yui3-panel-content .yui3-widget-ft .yui3-button', {
  79. fontWeight: 'bold',
  80. fontSize: '135%',
  81. color: 'white',
  82. margin: '0pt 6px',
  83. padding: '4px 8px',
  84. textDecoration: 'underline',
  85. background: 'none',
  86. border: '0px'
  87. });
  88. customizedYuiPanelCss = true;
  89. }
  90. globalSingletonInformationalPanel = newPanel;
  91. return newPanel;
  92. }
  93. function destroyInformationalPanel( theInformationalPanelInstance ) {
  94. if( theInformationalPanelInstance ) {
  95. theInformationalPanelInstance.hide();
  96. theInformationalPanelInstance.destroy();
  97. if( theInformationalPanelInstance === globalSingletonInformationalPanel ) {
  98. globalSingletonInformationalPanel = null;
  99. }
  100. }
  101. }
  102. function showLoadingImg() {
  103. globalYui.one("#loadingDivId").setStyle('display','block');
  104. //globalYui.one("#blackScreenDivId").setStyle('display','block');
  105. //globalYui.one("#loadingImgId").setStyle('display','block');
  106. }
  107. function hideLoadingImg() {
  108. globalYui.one("#loadingDivId").setStyle('display','none');
  109. //globalYui.one("#loadingImgId").setStyle('display','none');
  110. //globalYui.one("#blackScreenDivId").setStyle('display','none');
  111. }
  112. function swapStageVisibilities( currentStageDivSelector, newStageDivSelector ) {
  113. globalYui.log("In swapStageVisibilities: " + currentStageDivSelector + "->" + newStageDivSelector);
  114. /* Hide the current stage. */
  115. globalYui.one(currentStageDivSelector).setStyle('display','none');
  116. /* Show the new stage. */
  117. globalYui.one(newStageDivSelector).setStyle('display','block');
  118. }
  119. /* TODO XXX Consider bundling the last 3 parameters into their own NewStage object.
  120. * TODO XXX Do the same for the first 2 parameters and a CurrentStage object.
  121. */
  122. function transitionToNextStage( currentStageDivSelector, currentStageData, newStageDivSelector, newStageData, newStageRenderFunction ) {
  123. clearFormStatus();
  124. globalYui.one(currentStageDivSelector).setStyle('display','none');
  125. /* Render the next stage. */
  126. newStageRenderFunction(newStageData);
  127. globalYui.log("In transitionToNextStage: " + currentStageDivSelector + "->" + newStageDivSelector);
  128. //// tshooter: No longer doing this given dynamic rendering on stages. Only hide current stage.
  129. /* And make it visibly replace the currently showing one. */
  130. ///// tshooter: commented: swapStageVisibilities(currentStageDivSelector, newStageDivSelector);
  131. /* And now, handle the updates to addNodesWizardStages... */
  132. /* There can be only one 'current' stage at a time. */
  133. var currentStage = globalYui.one('.installationWizardCurrentStage');
  134. if ( currentStage ) {
  135. var nextStage = null;
  136. /* Check to make sure we haven't reached the last stage. */
  137. if( nextStage = currentStage.next('.installationWizardUnvisitedStage') ) {
  138. /* Mark this up-until-now 'current' stage as 'visited'. */
  139. currentStage.replaceClass( 'installationWizardCurrentStage', 'installationWizardVisitedStage' );
  140. /* Mark the stage after that as the new 'current' stage. */
  141. nextStage.replaceClass( 'installationWizardUnvisitedStage', 'installationWizardCurrentStage' );
  142. }
  143. }
  144. }
  145. function clearFormStatus() {
  146. var formStatusDiv = globalYui.all("#formStatusDivId");
  147. // formStatusDiv.setContent("");
  148. formStatusDiv.setStyle("visibility", "hidden");
  149. formStatusDiv.setStyle("display", "none");
  150. formStatusDiv.set('className','');
  151. formStatusDiv.addClass("formStatusBar");
  152. }
  153. function setFormStatus(statusString, isError, noFade) {
  154. var formStatusDivCssClass;
  155. if (isError) {
  156. formStatusDivCssClass = 'statusError';
  157. } else {
  158. formStatusDivCssClass = 'statusOk';
  159. }
  160. var formStatusDiv = globalYui.all("#formStatusDivId");
  161. formStatusDiv.setStyle("visibility", "visible");
  162. formStatusDiv.setStyle("display", "block");
  163. formStatusDiv.set('className','');
  164. formStatusDiv.addClass("formStatusBar");
  165. formStatusDiv.addClass(formStatusDivCssClass);
  166. formStatusDiv.setContent(statusString);
  167. if (!isError && !noFade) {
  168. //setTimeout(fadeFormStatus, 1000);
  169. }
  170. }
  171. function fadeFormStatus() {
  172. var formStatusDiv = globalYui.one("#formStatusDivId");
  173. formStatusDiv.addClass("formStatusBarZeroOpacity");
  174. }
  175. function convertDisplayType (displayType) {
  176. switch (displayType) {
  177. case "NODISPLAY":
  178. return "NODISPLAY";
  179. case "TEXT":
  180. return "text";
  181. case "SECRET":
  182. return "password";
  183. case "ONOFF":
  184. return "checkbox";
  185. default:
  186. return "text";
  187. }
  188. }
  189. function executeStage(inputUrl, renderStageFunction) {
  190. globalYui.io(inputUrl, {
  191. method: 'GET',
  192. timeout : 10000,
  193. on: {
  194. success: function (x,o) {
  195. globalYui.log("RAW JSON DATA: " + o.responseText);
  196. // Process the JSON data returned from the server
  197. try {
  198. responseJson = globalYui.JSON.parse(o.responseText);
  199. }
  200. catch (e) {
  201. hideLoadingImg();
  202. alert("JSON Parse failed!");
  203. return;
  204. }
  205. globalYui.log("PARSED DATA: " + globalYui.Lang.dump(responseJson));
  206. if (responseJson.result != 0) {
  207. hideLoadingImg();
  208. // Error!
  209. alert("Got error during getting data: " + responseJson.error);
  210. return;
  211. }
  212. responseJson = responseJson.response;
  213. renderStageFunction(responseJson);
  214. hideLoadingImg();
  215. return;
  216. },
  217. failure: function (x,o) {
  218. alert("Async call failed!");
  219. return;
  220. }
  221. }
  222. });
  223. }
  224. function submitDataAndProgressToNextScreen(url, requestData, submitButton, thisScreenId, nextScreenId, nextScreenRenderFunction, errorHandlerFunction) {
  225. showLoadingImg();
  226. globalYui.io(url, {
  227. method: 'POST',
  228. data: globalYui.JSON.stringify(requestData),
  229. timeout : 10000,
  230. on: {
  231. start: function(x, o) {
  232. submitButton.set('disabled', true);
  233. globalYui.log("In start function");
  234. // showLoadingImg();
  235. },
  236. complete: function(x, o) {
  237. submitButton.set('disabled', false);
  238. globalYui.log("In stop function");
  239. // hideLoadingImg();
  240. },
  241. success: function (x,o) {
  242. submitButton.set('disabled', false);
  243. globalYui.log("RAW JSON DATA: " + o.responseText);
  244. // Process the JSON data returned from the server
  245. try {
  246. responseJson = globalYui.JSON.parse(o.responseText);
  247. }
  248. catch (e) {
  249. submitButton.set('disabled', false);
  250. hideLoadingImg();
  251. alert("JSON Parse failed!");
  252. return;
  253. }
  254. globalYui.log("PARSED DATA: " + globalYui.Lang.dump(responseJson));
  255. if (responseJson.result != 0) {
  256. submitButton.set('disabled', false);
  257. hideLoadingImg();
  258. // Error!
  259. globalYui.log("Got error during submit data!" + responseJson.error);
  260. if ( errorHandlerFunction ) {
  261. globalYui.log("Invoking error handler function");
  262. errorHandlerFunction(responseJson);
  263. } else {
  264. alert("Got error during submit data!" + responseJson.error);
  265. }
  266. return;
  267. }
  268. responseJson = responseJson.response;
  269. /* Done with this stage, transition to the next. */
  270. transitionToNextStage( thisScreenId, requestData, nextScreenId, responseJson, nextScreenRenderFunction );
  271. },
  272. failure: function (x,o) {
  273. submitButton.set('disabled', false);
  274. alert("Async call failed!");
  275. }
  276. }
  277. });
  278. }
  279. function PeriodicDataPoller( dataSourceContext, responseHandler ) {
  280. this.dataSourceContext = dataSourceContext;
  281. /* Smoothe out the optional bits of this.dataSourceContext. */
  282. if( !this.dataSourceContext.pollInterval ) {
  283. /* How often we poll. */
  284. this.dataSourceContext.pollInterval = 5000;
  285. }
  286. if( !this.dataSourceContext.maxFailedAttempts ) {
  287. /* How many failed attempts before we stop polling. */
  288. this.dataSourceContext.maxFailedAttempts = 5;
  289. }
  290. this.responseHandler = responseHandler;
  291. this.dataSource = new globalYui.DataSource.IO ({
  292. source: this.dataSourceContext.source
  293. });
  294. this.dataSource.plug(globalYui.Plugin.DataSourceJSONSchema, {
  295. schema: this.dataSourceContext.schema
  296. });
  297. this.dataSourcePollFailureCount = 0;
  298. /* Set when start() is invoked. */
  299. this.dataSourcePollHandle = null;
  300. this.dataSourcePollRequestContext = {
  301. request: this.dataSourceContext.request,
  302. callback: {
  303. success: function (e) {
  304. /* Reset our failure count every time we succeed. */
  305. this.dataSourcePollFailureCount = 0;
  306. /* Invoke user-pluggable code. */
  307. if( this.responseHandler.success ) {
  308. this.responseHandler.success( e, this );
  309. }
  310. }.bind(this),
  311. failure: function (e) {
  312. ++this.dataSourcePollFailureCount;
  313. if( this.dataSourcePollFailureCount > this.dataSourceContext.maxFailedAttempts ) {
  314. /* Invoke user-pluggable code. */
  315. if( this.responseHandler.failure ) {
  316. this.responseHandler.failure( e, this );
  317. }
  318. /* No point making any more attempts. */
  319. this.stop();
  320. }
  321. }.bind(this)
  322. }
  323. };
  324. }
  325. /* Start polling. */
  326. PeriodicDataPoller.prototype.start = function() {
  327. this.dataSourcePollHandle = this.dataSource.setInterval( this.dataSourceContext.pollInterval, this.dataSourcePollRequestContext );
  328. }
  329. /* Stop polling. */
  330. PeriodicDataPoller.prototype.stop = function() {
  331. this.dataSource.clearInterval( this.dataSourcePollHandle );
  332. }
  333. function titleCase(word){
  334. return word.substr(0,1).toUpperCase() + word.substr(1).toLowerCase();
  335. }