window_management.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. /*******************************************************************************
  2. AToMPM - A Tool for Multi-Paradigm Modelling
  3. Copyright (c) 2011 Raphael Mannadiar (raphael.mannadiar@mail.mcgill.ca)
  4. Modified by Conner Hansen (chansen@crimson.ua.edu)
  5. This file is part of AToMPM.
  6. AToMPM is free software: you can redistribute it and/or modify it under the
  7. terms of the GNU Lesser General Public License as published by the Free Software
  8. Foundation, either version 3 of the License, or (at your option) any later
  9. version.
  10. AToMPM is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  12. PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with AToMPM. If not, see <http://www.gnu.org/licenses/>.
  15. *******************************************************************************/
  16. ///////////////////////////////////////////////////////////////////////////////
  17. // DEPRECATED FUNCTIONS
  18. ///////////////////////////////////////////////////////////////////////////////
  19. function _openDialog(type, args, callback){
  20. AtomPMClient.alertDeprecatedFunctionCall("_openDialog");
  21. WindowManagement.openDialog(type, args, callback);
  22. }
  23. function _spawnClient(fname,callbackURL){
  24. AtomPMClient.alertDeprecatedFunctionCall("_spawnClient");
  25. WindowManagement.spawnClient(fname, callbackURL);
  26. }
  27. function _spawnHeadlessClient(context,onready,onchlog){
  28. AtomPMClient.alertDeprecatedFunctionCall("_spawnHeadlessClient");
  29. WindowManagement.spawnHeadlessClient(context, onready, onchlog);
  30. }
  31. function __showDialog(){
  32. alert(AtomPMClient);
  33. AtomPMClient.alertDeprecatedFunctionCall("__showDialog");
  34. WindowManagement.showDialog();
  35. }
  36. function __closeDialog(){
  37. AtomPMClient.alertDeprecatedFunctionCall("__closeDialog");
  38. WindowManagement.closeDialog();
  39. }
  40. ///////////////////////////////////////////////////////////////////////////////
  41. //DEPRECATED FUNCTIONS
  42. ///////////////////////////////////////////////////////////////////////////////
  43. WindowManagement = function(){
  44. /**
  45. * Hides the login screen
  46. */
  47. this.hideLoginScreen = function()
  48. {
  49. //$('#div_login').style.display = 'none';
  50. $('#div_login').css('display', 'none');
  51. __setCanvasScrolling(true);
  52. };
  53. /**
  54. * Shows the login screen
  55. */
  56. this.showLoginScreen = function()
  57. {
  58. //$('#div_login').style.display = 'inline';
  59. $('#div_login').css('display', 'inline');
  60. __setCanvasScrolling(false);
  61. };
  62. //Todo: Shred this function into smaller functions, as this should
  63. // really just amount to a switch statement
  64. //TBI: complete comments about each dialog (copy from user's manual)
  65. /**
  66. * Opens a general dialog window
  67. */
  68. this.openDialog = function(type,args,callback)
  69. {
  70. args = args || {};
  71. function error(err,fatal)
  72. {
  73. console.error("Error! " + err);
  74. GUIUtils.setupAndShowDialog(
  75. [GUIUtils.getTextSpan(
  76. err,
  77. 'error')],
  78. undefined,
  79. (fatal ? __NO_BUTTONS : __ONE_BUTTON),
  80. (fatal ? 'FATAL ERROR (restart required)' : 'ERROR'));
  81. //console.error(err,args);
  82. }
  83. // TODO: Fix this, convert to JQuery
  84. if( type == _CLOUD_DATA_MANAGER )
  85. /* args: extensions,readonly,title */
  86. {
  87. HttpUtils.httpReq(
  88. 'GET',
  89. HttpUtils.url('/filelist',__NO_WID),
  90. undefined,
  91. function(statusCode,resp){
  92. var fnames = __localizeFilenames(
  93. __filterFilenamesByExtension(
  94. resp.split('\n'),
  95. args['extensions'] || ['.*'])).sort(),
  96. maxFnameLength =
  97. utils.max(fnames, function(_) {
  98. return _.length;
  99. }),
  100. fileb = GUIUtils.getFileBrowser(fnames,true),
  101. feedbackarea = $('<div>'),
  102. feedback = GUIUtils.getTextSpan(''),
  103. progressbar = $('<div>'),
  104. progressfill = $('<div>'),
  105. download = $('<div>'),
  106. trash = $('<div>'),
  107. div_dldel = $('<div>'),
  108. hldropzone =
  109. /* highlight or unhighlight the dropzone */
  110. function(zone)
  111. {
  112. if( zone == undefined )
  113. {
  114. fileb['filepane']().attr('class', 'fileb_pane');
  115. download.attr('class', 'dropzone');
  116. trash.attr('class', 'dropzone');
  117. }
  118. else if( zone == 'upload' )
  119. {
  120. var filepane = fileb['filepane']();
  121. filepane.attr('class', 'fileb_pane droppable');
  122. filepane.get(0).ondrop = onfilepanedrop;
  123. }
  124. else if( zone == 'dl/del' )
  125. {
  126. download.attr('class', 'dropzone droppable');
  127. trash.attr('class', 'dropzone droppable');
  128. }
  129. },
  130. cancelevt =
  131. /* prevent event bubbling */
  132. function(event)
  133. {
  134. event.stopPropagation();
  135. event.preventDefault();
  136. return false;
  137. },
  138. ondownloaddrop =
  139. function(event)
  140. {
  141. cancelevt(event);
  142. hldropzone();
  143. window.location.assign(event.dataTransfer.getData('uri'));
  144. },
  145. ontrashdrop =
  146. function(event)
  147. {
  148. cancelevt(event);
  149. hldropzone();
  150. var uri = event.dataTransfer.getData('uri');
  151. DataUtils.deleteFromCloud(uri,
  152. function(statusCode,resp)
  153. {
  154. if( ! utils.isHttpSuccessCode(statusCode) )
  155. return error(resp);
  156. feedback.html('deleted '+uri.match(/.*\/(.+)\.file/)[1]);
  157. });
  158. },
  159. onfilepanedrop =
  160. /* react to file drop from desktop
  161. 1. exit with error if non-zip files
  162. 2. move to handleFiles() otherwise */
  163. function(event)
  164. {
  165. cancelevt(event);
  166. hldropzone();
  167. var files = event.dataTransfer.files;
  168. for( var i=0; i<files.length; i++ )
  169. if( files[i].type != 'application/zip' )
  170. return error('uploaded files must zip archives');
  171. handleFiles(event.dataTransfer.files,0);
  172. },
  173. handleFiles =
  174. /* handle each dropped file from desktop
  175. 1. retrieve next file to handle
  176. 2. update feedback message and show progress bar
  177. 3. init file reader event handlers
  178. . onprogress updates progress bar
  179. . onload reacts to upload completion by adjusting
  180. feedback message, hiding progress bar and sending
  181. file to backend
  182. 4. start upload */
  183. function(files,i)
  184. {
  185. if( i >= files.length)
  186. return;
  187. var file = files[i];
  188. feedback.html('uploading '+file.name);
  189. progressbar.css("display", 'inline-block');
  190. var reader = new FileReader();
  191. reader.onprogress =
  192. function(event)
  193. {
  194. if( event.lengthComputable )
  195. progressfill.css("width",
  196. (100*event.loaded/event.total)+'%');
  197. };
  198. reader.onload =
  199. function(event)
  200. {
  201. progressfill.css("width", '100%');
  202. feedback.html('processing '+file.name+' ...');
  203. progressbar.css("display", 'none');
  204. DataUtils.uploadToCloud(
  205. fileb['getcurrfolder'](),
  206. event.target.result,
  207. function(statusCode,resp)
  208. {
  209. if( ! utils.isHttpSuccessCode(statusCode) )
  210. return error(resp);
  211. feedback.html('successfully processed '+file.name);
  212. handleFiles(files,++i);
  213. });
  214. };
  215. reader.readAsBinaryString(file);
  216. },
  217. cloudmgrClosed =
  218. function()
  219. {
  220. return fileb['filebrowser'].parent() == null;
  221. };
  222. document.body.ondragenter =
  223. /* show dropzone when file drag from desktop enters window */
  224. function(event)
  225. {
  226. if(cloudmgrClosed()) return true;
  227. cancelevt(event);
  228. hldropzone(
  229. (event.dataTransfer.effectAllowed == 'copyMove' ? 'dl/del' : 'upload'));
  230. return false;
  231. };
  232. document.body.ondragleave =
  233. /* hide dropzone when file drag from desktop leaves window (which
  234. causes event.pageX == 0) */
  235. function(event)
  236. {
  237. if(cloudmgrClosed()) return true;
  238. cancelevt(event);
  239. if( event.pageX == 0 )
  240. hldropzone();
  241. return false;
  242. };
  243. document.body.ondrop =
  244. function(event)
  245. {
  246. if(cloudmgrClosed()) return true;
  247. cancelevt(event);
  248. hldropzone();
  249. console.warn('non-dropzone drops are ignored');
  250. return false;
  251. };
  252. fileb['filebrowser'].attr('title',
  253. 'drag\'n\'drop files to file pane to upload\n'+
  254. '(close and re-open dialog to observe effects)');
  255. download.attr('title', 'drag\'n\'drop files from file pane to download');
  256. trash.attr('title', 'drag\'n\'drop files from file pane to delete\n'+
  257. '(close and re-open dialog to observe effects)');
  258. progressfill.attr('class', 'progress_fill');
  259. progressfill.html('&nbsp;');
  260. progressbar.attr('class', 'progress_bar');
  261. progressbar.append(progressfill);
  262. progressbar.css("display", 'none');
  263. feedbackarea.append(feedback);
  264. feedbackarea.append(progressbar);
  265. download.css("backgroundImage", 'url(client/media/download.png)');
  266. trash.css("backgroundImage", 'url(client/media/trash.png)');
  267. download.attr('class', 'dropzone');
  268. trash.attr('class', 'dropzone');
  269. download.css("cssFloat", 'left');
  270. trash.css("cssFloat", 'right');
  271. download.get(0).ondragover = cancelevt;
  272. trash.get(0).ondragover = cancelevt;
  273. download.get(0).ondrop = ondownloaddrop;
  274. trash.get(0).ondrop = ontrashdrop;
  275. div_dldel.append(download);
  276. div_dldel.append(trash);
  277. if( args['readonly'] )
  278. trash.css("display", 'none');
  279. GUIUtils.setupAndShowDialog(
  280. [fileb['filebrowser'],div_dldel,feedbackarea],
  281. undefined,
  282. __ONE_BUTTON,
  283. args['title'] ||
  284. 'manage your cloud data\n(note:: you must close and re-open '+
  285. 'dialog to view upload and deletion effects)');
  286. });
  287. }
  288. else if( type == _CUSTOM )
  289. /* args: widgets, title
  290. 'widgets' must be a list where each entry is either
  291. ['id':___,'type':'input','label':___,'default':___], or
  292. ['id':___,'type':'select','choices':___,'multipleChoice':___] */
  293. {
  294. var elements = [],
  295. getinputs = [];
  296. args['widgets'].forEach(
  297. function(w)
  298. {
  299. if( w['type'] == 'select' )
  300. {
  301. var select = GUIUtils.getSelector(w['choices'],w['multipleChoice']);
  302. getinputs.push(function(_)
  303. {
  304. _[w['id']] = HttpUtils.getSelectorSelection(select);
  305. });
  306. elements.push(select);
  307. }
  308. else if( w['type'] == 'input' )
  309. {
  310. var label = GUIUtils.getTextSpan(w['label'] || ''),
  311. input = GUIUtils.getStringInput(w['default'] || '');
  312. getinputs.push(function(_)
  313. {
  314. _[w['id']] = input[0].value;
  315. });
  316. elements.push(label,input);
  317. }
  318. });
  319. GUIUtils.setupAndShowDialog(
  320. elements,
  321. function()
  322. {
  323. var values = {};
  324. getinputs.forEach( function(gi) {gi(values);} );
  325. return values;
  326. },
  327. __TWO_BUTTONS,
  328. args['title'],
  329. callback);
  330. }
  331. else if( type == _ENTITY_EDITOR )
  332. /* args: uri */
  333. {
  334. var uri = (args['uri'] || __selection['items'][0]),
  335. matches = uri.match(/.*\/(.*)Icon\/(.*)\.instance/) ||
  336. uri.match(/.*\/(.*)Link\/(.*)\.instance/),
  337. type = matches[1],
  338. id = matches[2];
  339. HttpUtils.httpReq(
  340. 'GET',
  341. HttpUtils.url(uri),
  342. undefined,
  343. function(statusCode,resp)
  344. {
  345. if( ! utils.isHttpSuccessCode(statusCode) )
  346. return error(resp);
  347. return openDialog(
  348. _DICTIONARY_EDITOR,
  349. {'data': utils.jsonp( utils.jsonp(resp)['data'] ),
  350. 'ignoreKey':
  351. function(attr,val)
  352. {
  353. return attr.charAt(0) == '$' || val == undefined;
  354. },
  355. 'keepEverything':
  356. function()
  357. {
  358. return __changed(uri);
  359. },
  360. 'title':'edit '+type+' #'+id},
  361. callback || function(changes) {DataUtils.update(uri,changes);});
  362. });
  363. }
  364. else if( type == _ERROR )
  365. error(args);
  366. else if( type == __FATAL_ERROR )
  367. error(args,true);
  368. else if( type == _FILE_BROWSER )
  369. /* args: extensions,multipleChoice,manualInput,title,startDir */
  370. {
  371. HttpUtils.httpReq(
  372. 'GET',
  373. HttpUtils.url('/filelist',__NO_WID),
  374. undefined,
  375. function(statusCode,resp)
  376. {
  377. args['extensions'].push('/');
  378. var fnames = __localizeFilenames(
  379. __filterFilenamesByExtension(
  380. resp.split('\n'),
  381. args['extensions'] || ['.*'])
  382. ).sort(),
  383. maxFnameLength =
  384. utils.max(fnames,function(_) {return _.length;}),
  385. a_filebview = $('<a>'),
  386. folder_buttons = $('<div>'),
  387. new_folder_b = $('<button>'),
  388. rename_folder_b = $('<button>'),
  389. delete_folder_b = $('<button>'),
  390. move_folder_b = $('<button>'),
  391. file_buttons = $('<div>'),
  392. rename_file_b = $('<button>'),
  393. delete_file_b = $('<button>'),
  394. move_file_b = $('<button>'),
  395. feedbackarea = $('<div>'),
  396. feedback = GUIUtils.getTextSpan('',"feedback"),
  397. fileb =
  398. GUIUtils.getFileBrowser(fnames,false,args['manualInput'],__getRecentDir(args['startDir']));
  399. a_filebview.html('file browser view')
  400. .attr("href", '#')
  401. .attr("class", 'enabled_link');
  402. new_folder_b.html('new folder')
  403. .click(function(ev) {
  404. var folder_name = prompt("please fill in a name for the folder");
  405. if (folder_name != null) {
  406. folder_name = folder_name.replace(/^\s+|\s+$/g, ''); // trim
  407. if (!folder_name.match(/^[a-zA-Z0-9_\s]+$/i)) {
  408. feedback.html("invalid folder name: " + folder_name);
  409. } else {
  410. console.log("/" + window.localStorage.getItem('user') + fileb['getcurrfolder']() + folder_name + '.folder');
  411. DataUtils.createFolder("/" + window.localStorage.getItem('user') + fileb['getcurrfolder']() + folder_name + '.folder', function(statusCode, resp) {
  412. if( ! utils.isHttpSuccessCode(statusCode) ) {
  413. feedback.html(resp)
  414. } else {
  415. feedback.html('created ' + folder_name);
  416. fnames.push(fileb['getcurrfolder']() + folder_name + "/")
  417. fileb['refresh'](fnames);
  418. }
  419. });
  420. }
  421. }
  422. });
  423. folder_buttons.append(new_folder_b);
  424. rename_folder_b.html('rename folder')
  425. .click(function(ev) {
  426. var value = fileb['getcurrfolder']();
  427. var folder_name = prompt("please fill in a new name for folder " + value);
  428. if (folder_name != null) {
  429. folder_name = folder_name.replace(/^\s+|\s+$/g, ''); // trim
  430. if (!folder_name.match(/^[a-zA-Z0-9_\s]+$/i)) {
  431. feedback.html("invalid folder name: " + folder_name);
  432. } else {
  433. DataUtils.renameInCloud("/" + window.localStorage.getItem('user') + value.slice(0, -1) + ".folder", folder_name, function(statusCode,resp)
  434. {
  435. if( ! utils.isHttpSuccessCode(statusCode) ) {
  436. feedback.html(resp);
  437. } else {
  438. var matches = value.match(/^\/(.*\/)?(.*)\/$/),
  439. newvalue = "/" + (matches[1] || "") + folder_name + "/";
  440. for (var idx in fnames) {
  441. fnames[idx] = fnames[idx].replace(new RegExp("^("+value+")(.*)"), newvalue+"$2");
  442. }
  443. fileb['refresh'](fnames, newvalue);
  444. feedback.html('renamed ' + value + ' to ' + newvalue);
  445. }
  446. });
  447. }
  448. }
  449. });
  450. folder_buttons.append(rename_folder_b);
  451. delete_folder_b.html('delete folder')
  452. .click(function(ev) {
  453. var value = fileb['getcurrfolder']();
  454. if (confirm("are you sure you want to delete " + value + "?")) {
  455. DataUtils.deleteFromCloud("/" + window.localStorage.getItem('user') + value.slice(0, -1) + ".folder", function(statusCode,resp)
  456. {
  457. if( ! utils.isHttpSuccessCode(statusCode) ) {
  458. feedback.html(resp);
  459. } else {
  460. var todelete = [];
  461. for (var idx in fnames) {
  462. if (fnames[idx].match(new RegExp("^("+value+").*"))) {
  463. todelete.push(fnames[idx]);
  464. }
  465. }
  466. for (var idx in todelete) {
  467. fnames.splice(fnames.indexOf(todelete[idx]), 1);
  468. }
  469. fileb['refresh'](fnames);
  470. feedback.html('deleted ' + value);
  471. }
  472. });
  473. }
  474. });
  475. folder_buttons.append(delete_folder_b);
  476. move_folder_b.html('move folder')
  477. .click(function(ev) {
  478. var value = fileb['getcurrfolder']();
  479. var folder_loc = prompt("please fill in a new parent folder for folder " + value);
  480. if (folder_loc != null) {
  481. folder_loc = folder_loc.replace(/^\s+|\s+$/g, ''); // trim
  482. if (!folder_loc.match(/^\/([a-zA-Z0-9_\s]+\/)*$/i)) {
  483. feedback.html("invalid parent location: " + folder_loc);
  484. } else {
  485. DataUtils.moveInCloud("/" + window.localStorage.getItem('user') + value.slice(0, -1) + ".folder", folder_loc, function(statusCode,resp)
  486. {
  487. if( ! utils.isHttpSuccessCode(statusCode) ) {
  488. feedback.html(resp);
  489. } else {
  490. var matches = value.match(/^\/(.*\/)?(.*)\/$/),
  491. newvalue = folder_loc + matches[2] + "/";
  492. for (var idx in fnames) {
  493. fnames[idx] = fnames[idx].replace(new RegExp("^("+value+")(.*)"), newvalue+"$2");
  494. }
  495. fileb['refresh'](fnames, newvalue);
  496. feedback.html('moved ' + value + ' to ' + folder_loc);
  497. }
  498. });
  499. }
  500. }
  501. });
  502. folder_buttons.append(move_folder_b);
  503. rename_file_b.html('rename file')
  504. .click(function(ev) {
  505. var value = fileb['getselection']();
  506. var file_name = prompt("please fill in a new name for file " + value);
  507. if (file_name != null) {
  508. file_name = file_name.replace(/^\s+|\s+$/g, ''); // trim
  509. if (!file_name.match(/^[a-zA-Z0-9_\s\.]+$/i)) {
  510. feedback.html("invalid folder name: " + file_name);
  511. } else {
  512. DataUtils.renameInCloud("/" + window.localStorage.getItem('user') + value.slice(0, -1) + ".file", file_name, function(statusCode,resp)
  513. {
  514. if( ! utils.isHttpSuccessCode(statusCode) ) {
  515. feedback.html(resp);
  516. } else {
  517. var matches = value.match(/^\/(.*\/)?(.*)\/$/),
  518. newvalue = "/" + (matches[1] || "") + file_name;
  519. var idx = fnames.indexOf(value);
  520. if (idx >= 0) {
  521. fnames[idx] = newvalue;
  522. }
  523. fileb['refresh'](fnames);
  524. feedback.html('renamed ' + value + ' to ' + newvalue);
  525. }
  526. });
  527. }
  528. }
  529. });
  530. file_buttons.append(rename_file_b);
  531. delete_file_b.html('delete file')
  532. .click(function(ev) {
  533. var value = fileb['getselection']();
  534. if (confirm("are you sure you want to delete " + value + "?")) {
  535. DataUtils.deleteFromCloud("/" + window.localStorage.getItem('user') + value + ".file", function(statusCode,resp)
  536. {
  537. if( ! utils.isHttpSuccessCode(statusCode) ) {
  538. feedback.html(resp);
  539. } else {
  540. feedback.html('deleted ' + value);
  541. var idx = fnames.indexOf(value);
  542. if (idx >= 0) {
  543. fnames.splice(idx, 1);
  544. }
  545. fileb['refresh'](fnames);
  546. }
  547. });
  548. }
  549. });
  550. file_buttons.append(delete_file_b);
  551. move_file_b.html('move file')
  552. .click(function(ev) {
  553. var value = fileb['getselection']();
  554. var folder_loc = prompt("please fill in a new parent folder for file " + value);
  555. if (folder_loc != null) {
  556. folder_loc = folder_loc.replace(/^\s+|\s+$/g, ''); // trim
  557. if (!folder_loc.match(/^\/([a-zA-Z0-9_\s]+\/)*$/i)) {
  558. feedback.html("invalid parent location: " + folder_loc);
  559. } else {
  560. DataUtils.moveInCloud("/" + window.localStorage.getItem('user') + value + ".file", folder_loc, function(statusCode,resp)
  561. {
  562. if( ! utils.isHttpSuccessCode(statusCode) ) {
  563. feedback.html(resp);
  564. } else {
  565. var matches = value.match(/^\/(.*\/)?(.*)$/),
  566. newvalue = folder_loc + matches[2];
  567. feedback.html('moved ' + value + ' to ' + folder_loc);
  568. var idx = fnames.indexOf(value);
  569. if (idx >= 0) {
  570. fnames[idx] = newvalue;
  571. }
  572. fileb['refresh'](fnames);
  573. }
  574. });
  575. }
  576. }
  577. });
  578. file_buttons.append(move_file_b);
  579. GUIUtils.setupAndShowDialog(
  580. [fileb['filebrowser'],folder_buttons,file_buttons,feedback],
  581. function()
  582. {
  583. var value = [fileb['getselection']()];
  584. if (value.length > 0 && value[0] != "" && args['startDir']) {
  585. __setRecentDir(args['startDir'],value[0].substring(0, value[0].lastIndexOf('/') + 1));
  586. }
  587. return value;
  588. },
  589. __TWO_BUTTONS,
  590. args['title'],
  591. callback);
  592. });
  593. }
  594. else if( type == _LEGAL_CONNECTIONS )
  595. /* args: uri1, uri2, ctype, forceCallback */
  596. {
  597. var legalConnections = __legalConnections(args['uri1'],args['uri2'],args['ctype']);
  598. if( legalConnections.length == 0 )
  599. {
  600. var err = 'no valid connection between selected types';
  601. if( args['forceCallback'] )
  602. callback({'$err':err});
  603. else
  604. error(err);
  605. }
  606. else if( legalConnections.length == 1 )
  607. callback( legalConnections[0]+'Link.type' );
  608. else
  609. {
  610. var select = GUIUtils.getSelector(legalConnections);
  611. GUIUtils.setupAndShowDialog(
  612. [select],
  613. function() {return HttpUtils.getSelectorSelection(select)+'Link.type';},
  614. __TWO_BUTTONS,
  615. 'choose connection type',
  616. callback);
  617. }
  618. }
  619. else if( type == _LOADED_TOOLBARS )
  620. /* args: multipleChoice, type, title */
  621. {
  622. var choosableToolbars = [];
  623. for( var tb in __loadedToolbars )
  624. {
  625. if( (args['type'] == undefined &&
  626. (__isIconMetamodel(tb) || __isButtonModel(tb))) ||
  627. (args['type'] == 'metamodels' &&
  628. __isIconMetamodel(tb)) ||
  629. (args['type'] == 'buttons' &&
  630. __isButtonModel(tb)) )
  631. choosableToolbars.push(tb);
  632. }
  633. var select = GUIUtils.getSelector(choosableToolbars,args['multipleChoice']);
  634. GUIUtils.setupAndShowDialog(
  635. [select],
  636. function() {return HttpUtils.getSelectorSelection(select);},
  637. __TWO_BUTTONS,
  638. args['title'],
  639. callback);
  640. }
  641. else if( type == _DICTIONARY_EDITOR )
  642. /* args: data, ignoreKey, keepEverything, title */
  643. {
  644. var form = $('<form>'),
  645. table = $('<table>'),
  646. attrs2ii = {};
  647. form.onsubmit = function() {return false;};
  648. form.append(table);
  649. for( var attr in args['data'] )
  650. {
  651. if( args['ignoreKey'] != undefined &&
  652. args['ignoreKey'](attr,args['data'][attr]['value']) )
  653. continue;
  654. var tr = $('<tr>');
  655. var ii = GUIUtils.getInputField(
  656. args['data'][attr]['type'],
  657. args['data'][attr]['value']);
  658. // var tr = table.append( $('<tr>') ),
  659. // ii = GUIUtils.getInputField(
  660. // args['data'][attr]['type'],
  661. // args['data'][attr]['value']);
  662. tr.append( $('<td>').append( GUIUtils.getTextSpan(attr)) );
  663. tr.append( $('<td>').append(ii.input) );
  664. attrs2ii[attr] = ii;
  665. table.append( tr );
  666. }
  667. GUIUtils.setupAndShowDialog(
  668. [form],
  669. function()
  670. {
  671. var changes = {},
  672. keepAll = (args['keepEverything'] != undefined &&
  673. args['keepEverything']());
  674. for( var attr in attrs2ii )
  675. {
  676. var am = attrs2ii[attr];
  677. var newVal = am['getinput'](am['input']);
  678. if( keepAll ||
  679. utils.jsons(newVal) != utils.jsons(am['oldVal']) )
  680. changes[attr] = newVal;
  681. }
  682. return changes;
  683. },
  684. __TWO_BUTTONS,
  685. args['title'],
  686. callback);
  687. }
  688. else if( type == __SVG_TEXT_EDITOR )
  689. {
  690. if( args.tagName != 'tspan' )
  691. {
  692. console.warn('SVG text editing only works on "Text" VisualObjects');
  693. return;
  694. }
  695. var vobj = args.parentNode,
  696. vobjuri = vobj.getAttribute('__vobjuri'),
  697. iconuri = __vobj2uri(vobj),
  698. lines = [];
  699. for( var i=0; i < vobj.children.length; i++ )
  700. if( vobj.children[i].tagName == 'tspan' )
  701. lines.push(vobj.children[i].textContent);
  702. var input =
  703. GUIUtils.getTextInput(
  704. lines.join('\n'),
  705. undefined,
  706. Math.min(lines.length,__MAX_TEXTAREA_LINES) );
  707. GUIUtils.setupAndShowDialog(
  708. [input],
  709. function() {return input.value;},
  710. __TWO_BUTTONS,
  711. 'enter new text',
  712. function(newVal)
  713. {
  714. DataUtils.update(
  715. iconuri+'/'+vobjuri+'.vobject',{'textContent':newVal});
  716. });
  717. }
  718. };
  719. /* spawn a new instance of atompm... if a model is specified (as 'fname'), it is
  720. loaded into the new instance... if a callback url is specified, critical
  721. information about the new instance is POSTed to it
  722. NOTE:: window.open returns a reference to the created window... however, this
  723. reference is not always complete (e.g. body.onload has not necessarily
  724. run its course)... for this reason, before proceeding with handling
  725. 'fname' and 'callbackURL', we poll the reference to ensure its
  726. completion */
  727. this.spawnClient = function (fname,callbackURL)
  728. {
  729. var c = window.open(window.location.href, '_blank'),
  730. onspawn =
  731. function()
  732. {
  733. if( (fname || callbackURL) &&
  734. (c.__wid == undefined ||
  735. c.__aswid == undefined ||
  736. c._loadModel == undefined) )
  737. return window.setTimeout(onspawn,250);
  738. c.__user = __user;
  739. if( fname )
  740. c._loadModel(fname);
  741. if( callbackURL )
  742. _httpReq(
  743. 'POST',
  744. callbackURL,
  745. {'aswid':c.__aswid,
  746. 'cswid':c.__wid,
  747. 'fname':fname,
  748. 'host':window.location.host});
  749. };
  750. onspawn();
  751. };
  752. /* initialize a headless client, i.e. a client with a proper backend but whose
  753. socket-message handling code is user-defined
  754. 1. setup new backend csworker and subscribe to it
  755. 2. call 'onready'
  756. 3. from this point on, all incoming socket messages are dispatched to
  757. 'onchlog'
  758. NOTE:: this code and the above comments are simplified versions of what's in
  759. initClient() (TBI:: merge this function with initClient()??)
  760. NOTE:: the context object gets populated with the headless client's wids and
  761. with a pointer to a function that closes it (as 'close') */
  762. this.spawnHeadlessClient = function (context,onready,onchlog)
  763. {
  764. var socket = io.connect(
  765. window.location.hostname,
  766. {'port':8124,'reconnect':false,'force new connection':true});
  767. socket.on('message',
  768. function(msg)
  769. {
  770. console.debug(' >>> '+utils.jsons(msg));
  771. if( msg['statusCode'] != undefined )
  772. {
  773. if( msg['statusCode'] == 201 )
  774. {
  775. HttpUtils.httpReq(
  776. 'PUT',
  777. '/aswSubscription?wid='+context.__wid,
  778. undefined,
  779. function(statusCode,resp)
  780. {
  781. context.__aswid = utils.jsonp(resp)['data'];
  782. onready();
  783. });
  784. context.close = socket.socket.disconnect;
  785. }
  786. else
  787. console.error('headless client failed to connect to back-end');
  788. }
  789. else
  790. onchlog(
  791. msg['data']['changelog'],
  792. msg['data']['sequence#'],
  793. msg['data']['hitchhiker']);
  794. });
  795. socket.on('disconnect',
  796. function()
  797. {
  798. console.debug('headless client lost connection to back-end');
  799. });
  800. socket.on('connect',
  801. function()
  802. {
  803. HttpUtils.httpReq(
  804. 'POST',
  805. '/csworker',
  806. undefined,
  807. function(statusCode,resp)
  808. {
  809. console.debug("Connect!");
  810. console.debug(statusCode);
  811. console.debug(resp);
  812. context.__wid = resp;
  813. socket.emit(
  814. 'message',
  815. {'method':'POST','url':'/changeListener?wid='+context.__wid});
  816. });
  817. });
  818. };
  819. /**
  820. * Sets whether to update the window title or not
  821. * @param changed whether or not the title has changed
  822. */
  823. this.setWindowTitle = function(changed)
  824. {
  825. if( __saveas == undefined )
  826. document.title =
  827. __TITLE +' - '+
  828. (changed ? '+ ' :'')+
  829. '[Unnamed]';
  830. else
  831. document.title =
  832. __TITLE+' - '+
  833. (changed ? '+ ' :'')+
  834. __saveas.match(/(.*\/){0,1}(.*)\.model/)[2]+' - '+
  835. __saveas;
  836. };
  837. /**
  838. * Displays the modal dialog
  839. */
  840. this.showDialog = function()
  841. {
  842. var dialog = $('#div_dialog'),
  843. dim_bg = $('#div_dim_bg');
  844. dim_bg.css("display", 'inline');
  845. dialog.css("display", 'block');
  846. dialog.css("left", document.body.scrollLeft +
  847. window.innerWidth/2 -
  848. dialog.width()/2 + "px");
  849. dialog.css("top", document.body.scrollTop +
  850. window.innerHeight/2 -
  851. dialog.height()/2 + "px");
  852. __setCanvasScrolling(false);
  853. };
  854. /**
  855. * Closes the modal dialog if it is currently opened
  856. */
  857. this.closeDialog = function()
  858. {
  859. var dialog = $('#div_dialog');
  860. dialog.css("display", 'none');
  861. $('#div_dim_bg').css("display", 'none');
  862. HttpUtils.removeChildren(dialog);
  863. __setCanvasScrolling(true);
  864. BehaviorManager.setActiveBehaviourStatechart(__SC_CANVAS);
  865. };
  866. /**
  867. * Closes the modal dialog if it is currently opened (with arg js event)
  868. * Huseyin Ergin
  869. * HUSEYIN-ENTER
  870. */
  871. this.closeDialog = function(ev)
  872. {
  873. if(ev!=null && ev.keyCode==13) {
  874. $('#okbutton').click();
  875. }
  876. var dialog = $('#div_dialog');
  877. dialog.css("display", 'none');
  878. $('#div_dim_bg').css("display", 'none');
  879. HttpUtils.removeChildren(dialog);
  880. __setCanvasScrolling(true);
  881. BehaviorManager.setActiveBehaviourStatechart(__SC_CANVAS);
  882. };
  883. return this;
  884. }();