connectUtils-1-4-8.js 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535
  1. // Renamed from ac.js. This is the version used for release 1.4.8-AC onwards
  2. var AC = {};
  3. AC.autosaveTimeout = 10000;
  4. AC.draftExtension = '.tmp';
  5. AC.draftPrefix = '~';
  6. AC.timeout = 25000;
  7. // If save should also exit. To disable this, multiple saveMacro calls
  8. // must be possible (not yet in production on 08-AUG-2017)
  9. AC.autoExit = true;
  10. // Last Checked on 08-AUG-2017: No delete scope needed to delete drafts
  11. // LATER: If delete scope is needed users must upgrade to the latest json
  12. // Disabled. Flag to mute notifications for drafts is needed. 16-AUG-2017
  13. AC.draftEnabled = true; //Enabled with the new save that mute notifications for saving TODO is there notification for deleting a draft?
  14. AC.getUrlParam = function(param, escape, url){
  15. try{
  16. var url = url || window.location.search;
  17. var regex = new RegExp(param + '=([^&]+)'),
  18. data = regex.exec(url)[1];
  19. // decode URI with plus sign fix.
  20. return (escape) ? window.decodeURIComponent(data.replace(/\+/g, '%20')) : data;
  21. } catch (e){
  22. return undefined;
  23. }
  24. };
  25. AC.getSpaceKey = function(url)
  26. {
  27. try{
  28. var url = url || window.location.href;
  29. var regex = new RegExp(/\/(spaces|space)\/([^\/]+)/);
  30. return regex.exec(url)[2];
  31. } catch (e){
  32. return undefined;
  33. }
  34. };
  35. AC.getMetaTag = function(name) {
  36. return document.getElementsByTagName('meta')[name].getAttribute('content');
  37. }
  38. //Code from: https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
  39. AC.b64toBlob = function(b64Data, contentType, sliceSize, isByteCharacters)
  40. {
  41. contentType = contentType || '';
  42. sliceSize = sliceSize || 512;
  43. var byteCharacters = isByteCharacters? b64Data : atob(b64Data);
  44. var byteArrays = [];
  45. for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
  46. var slice = byteCharacters.slice(offset, offset + sliceSize);
  47. var byteNumbers = new Array(slice.length);
  48. for (var i = 0; i < slice.length; i++) {
  49. byteNumbers[i] = slice.charCodeAt(i);
  50. }
  51. var byteArray = new Uint8Array(byteNumbers);
  52. byteArrays.push(byteArray);
  53. }
  54. var blob = new Blob(byteArrays, {type: contentType});
  55. return blob;
  56. }
  57. AC.initAsync = function(baseUrl)
  58. {
  59. var link = document.createElement('a');
  60. link.href = location.href;
  61. link.href = link.href; //to have 'host' populated under IE
  62. var hostUrl = link.protocol + '//' + link.hostname;
  63. var lang = AC.getUrlParam('loc', true);
  64. var site = AC.getUrlParam('xdm_e', true);
  65. var user = AC.getUrlParam('user_id', true);
  66. if (lang != null)
  67. {
  68. var dash = lang.indexOf('-');
  69. if (dash >= 0)
  70. {
  71. lang = lang.substring(0, dash);
  72. }
  73. }
  74. var editor = document.createElement('iframe');
  75. editor.setAttribute('width', '100%');
  76. editor.setAttribute('height', '100%');
  77. editor.style.width = '100%';
  78. editor.style.height = '100%';
  79. editor.setAttribute('id', 'editorFrame');
  80. editor.setAttribute('frameborder', '0');
  81. //editor.setAttribute('src', 'https://9674265b.ngrok.io/?dev=1&drawdev=1&' +
  82. editor.setAttribute('src', hostUrl + '/?' +
  83. 'ui=atlas&p=ac148&embed=1&modified=unsavedChanges' +
  84. ((!AC.autoExit) ? '&saveAndExit=1' : '') +
  85. '&keepmodified=1&spin=1&libraries=1&proto=json' +
  86. ((lang != null) ? '&lang=' + lang : '') + ((site != null) ? '&site=' + encodeURIComponent(site) : '') +
  87. ((user != null) ? '&user=' + encodeURIComponent(user) : ''));
  88. var initReceived = false;
  89. var draftHandled = false;
  90. var waitingForAttachments = false;
  91. var xmlReceived = null;
  92. var draftXml = null;
  93. var draftName = null;
  94. var filename = null;
  95. var theMacroData = null;
  96. var pageId = null;
  97. var draftPage = false;
  98. var theLocation = null;
  99. var attachments = null;
  100. var serverName = document.referrer;
  101. var index1 = serverName.indexOf('//');
  102. if (index1 > 0)
  103. {
  104. var index2 = serverName.indexOf('/', index1 + 2);
  105. if (index2 > index1)
  106. {
  107. serverName = serverName.substring(index1 + 2, index2);
  108. }
  109. }
  110. function startEditor()
  111. {
  112. if (initReceived && xmlReceived != null && draftHandled && !waitingForAttachments)
  113. {
  114. AC.init(baseUrl, theLocation, pageId, editor, filename, xmlReceived, draftName, draftXml, theMacroData, draftPage);
  115. }
  116. };
  117. function loadDraft()
  118. {
  119. if (waitingForAttachments)
  120. {
  121. return;
  122. }
  123. if (AC.draftEnabled && pageId != null && attachments != null &&
  124. (draftName != null || xmlReceived == '') && !draftHandled)
  125. {
  126. // Searches for pending new drafts from this user
  127. var prefix = '~drawio~' + user + '~';
  128. // Check if attachments contains draftName
  129. for (var i = 0; i < attachments.length; i++)
  130. {
  131. var fn = attachments[i].fileName;
  132. if (draftName == null && attachments[i].fileSize > 0 &&
  133. fn.substring(0, prefix.length) === prefix &&
  134. fn.substring(fn.length - AC.draftExtension.length) === AC.draftExtension)
  135. {
  136. filename = fn.substring(prefix.length, fn.length - AC.draftExtension.length);
  137. draftName = fn;
  138. }
  139. if (fn == draftName)
  140. {
  141. AP.require(['messages', 'confluence'], function (messages, confluence)
  142. {
  143. var acceptResponse = true;
  144. var timeoutHandler = function()
  145. {
  146. acceptResponse = false;
  147. document.body.style.backgroundSize = 'auto auto';
  148. document.body.style.backgroundImage = 'url(/images/stop-flat-icon-80.png)';
  149. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner', show: false}), '*');
  150. var message = messages.error('The connection has timed out', 'The server at ' +
  151. serverName + ' is taking too long to respond.');
  152. messages.onClose(message, function()
  153. {
  154. confluence.closeMacroEditor();
  155. });
  156. };
  157. var timeoutThread = window.setTimeout(timeoutHandler, AC.timeout);
  158. AC.loadDiagram(pageId, draftName, null, function(loadResp)
  159. {
  160. //console.trace('DRAFT: Found', draftName, loadResp);
  161. window.clearTimeout(timeoutThread);
  162. if (acceptResponse)
  163. {
  164. if (loadResp != null && loadResp.length > 0)
  165. {
  166. draftXml = loadResp;
  167. }
  168. draftHandled = true;
  169. startEditor();
  170. }
  171. }, function()
  172. {
  173. window.clearTimeout(timeoutThread);
  174. if (acceptResponse)
  175. {
  176. draftHandled = true;
  177. startEditor();
  178. }
  179. });
  180. });
  181. // Terminates function
  182. return;
  183. }
  184. }
  185. }
  186. draftHandled = true;
  187. startEditor();
  188. };
  189. var initHandler = function(evt)
  190. {
  191. if (evt.origin == hostUrl)
  192. {
  193. var msg = JSON.parse(evt.data);
  194. if (msg.event == 'init')
  195. {
  196. window.removeEventListener('message', initHandler);
  197. document.body.style.backgroundImage = 'none';
  198. initReceived = true;
  199. startEditor();
  200. }
  201. }
  202. };
  203. window.addEventListener('message', initHandler);
  204. // Parallel loading for data and iframe
  205. document.body.appendChild(editor);
  206. AP.getLocation(function(location)
  207. {
  208. theLocation = location;
  209. AP.require(['messages', 'navigator', 'confluence', 'request'], function (messages, navigator, confluence, request)
  210. {
  211. navigator.getLocation(function (data)
  212. {
  213. if (data != null && data.target != null && data.context!= null &&
  214. (data.target == 'contentedit' || data.target == 'contentcreate'))
  215. {
  216. draftPage = (data.target == 'contentcreate');
  217. pageId = data.context.contentId;
  218. }
  219. if (pageId == null || isNaN(pageId))
  220. {
  221. document.body.style.backgroundImage = 'url(/images/stop-flat-icon-80.png)';
  222. document.body.style.backgroundSize = 'auto auto';
  223. editor.parentNode.removeChild(editor);
  224. var message;
  225. if (data != null && data.target == 'contentcreate')
  226. {
  227. message = messages.error('Cannot insert draw.io diagram to a new Confluence page',
  228. 'Please save the page and try again.');
  229. }
  230. else
  231. {
  232. message = messages.error('Unable to determine page ID',
  233. 'Please contact your Confluence administrator.');
  234. }
  235. messages.onClose(message, function()
  236. {
  237. confluence.closeMacroEditor();
  238. });
  239. }
  240. else
  241. {
  242. // Not needed if drafts not enabled
  243. if (AC.draftEnabled)
  244. {
  245. waitingForAttachments = true;
  246. var acceptResponse2 = true;
  247. var timeoutHandler2 = function()
  248. {
  249. acceptResponse2 = false;
  250. document.body.style.backgroundSize = 'auto auto';
  251. document.body.style.backgroundImage = 'url(/images/stop-flat-icon-80.png)';
  252. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner', show: false}), '*');
  253. var message = messages.error('The connection has timed out', 'The server at ' +
  254. serverName + ' is taking too long to respond.');
  255. messages.onClose(message, function()
  256. {
  257. confluence.closeMacroEditor();
  258. });
  259. };
  260. var timeoutThread2 = window.setTimeout(timeoutHandler2, AC.timeout);
  261. request({
  262. type: 'POST',
  263. data: JSON.stringify([pageId]),
  264. url: '/rpc/json-rpc/confluenceservice-v2/getAttachments',
  265. contentType: 'application/json;charset=UTF-8',
  266. success: function(res)
  267. {
  268. window.clearTimeout(timeoutThread2);
  269. if (acceptResponse2)
  270. {
  271. waitingForAttachments = false;
  272. attachments = JSON.parse(res);
  273. loadDraft();
  274. }
  275. },
  276. error: function(res)
  277. {
  278. window.clearTimeout(timeoutThread2);
  279. if (acceptResponse2)
  280. {
  281. waitingForAttachments = false;
  282. draftHandled = true;
  283. }
  284. }
  285. });
  286. }
  287. var acceptResponse = true;
  288. var timeoutHandler = function()
  289. {
  290. acceptResponse = false;
  291. document.body.style.backgroundSize = 'auto auto';
  292. document.body.style.backgroundImage = 'url(/images/stop-flat-icon-80.png)';
  293. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner', show: false}), '*');
  294. var message = messages.error('The connection has timed out', 'The server at ' +
  295. serverName + ' is taking too long to respond.');
  296. messages.onClose(message, function()
  297. {
  298. confluence.closeMacroEditor();
  299. });
  300. };
  301. var timeoutThread = window.setTimeout(timeoutHandler, AC.timeout);
  302. confluence.getMacroData(function (macroData)
  303. {
  304. window.clearTimeout(timeoutThread);
  305. if (acceptResponse)
  306. {
  307. var name = (macroData != null) ? (macroData.diagramName || '') : null;
  308. theMacroData = macroData;
  309. if (name != null && name.length > 0)
  310. {
  311. var revision = parseInt(macroData.revision);
  312. var owningPageId = macroData.pageId;
  313. draftName = (name != null) ? AC.draftPrefix + name + AC.draftExtension : null;
  314. loadDraft();
  315. if (isNaN(revision))
  316. {
  317. revision = null;
  318. }
  319. timeoutThread = window.setTimeout(timeoutHandler, AC.timeout);
  320. AC.loadDiagram(pageId, name, revision, function(loadResp)
  321. {
  322. window.clearTimeout(timeoutThread);
  323. if (acceptResponse)
  324. {
  325. xmlReceived = loadResp;
  326. filename = name;
  327. //console.trace('DRAFT: Created', AC.draftPrefix + filename + AC.draftExtension);
  328. startEditor();
  329. }
  330. },
  331. function(resp)
  332. {
  333. window.clearTimeout(timeoutThread);
  334. if (acceptResponse)
  335. {
  336. editor.parentNode.removeChild(editor);
  337. var message = messages.error('Read Error', (resp.status == 404) ?
  338. 'File not found' : 'Error loading file');
  339. messages.onClose(message, function()
  340. {
  341. confluence.closeMacroEditor();
  342. });
  343. }
  344. }, owningPageId, true);
  345. }
  346. else
  347. {
  348. filename = null;
  349. xmlReceived = '';
  350. loadDraft();
  351. }
  352. }
  353. });
  354. }
  355. });
  356. });
  357. });
  358. };
  359. AC.init = function(baseUrl, location, pageId, editor, diagramName, initialXml, draftName, draftXml, macroData, draftPage)
  360. {
  361. // Hides the logo
  362. document.body.style.backgroundImage = 'none';
  363. var user = AC.getUrlParam('user_id', true);
  364. var draftExists = false;
  365. AP.require(['messages', 'confluence', 'request'], function(messages, confluence, request)
  366. {
  367. var newPage = location.indexOf('createpage.action') > -1 ? true : false;
  368. var diagramXml = null;
  369. var link = document.createElement('a');
  370. link.href = location.href;
  371. link.href = link.href; //to have 'host' populated under IE
  372. var hostUrl = link.protocol + '//' + link.hostname;
  373. function removeDraft(fn, err)
  374. {
  375. if (draftExists)
  376. {
  377. AC.removeAttachment(pageId, draftName, fn, err);
  378. }
  379. else
  380. {
  381. fn();
  382. }
  383. };
  384. function saveDraft(xml, fn, err)
  385. {
  386. //console.trace('DRAFT: Save', draftName, xml);
  387. AC.saveDiagram(pageId, draftName,
  388. xml,
  389. function(res)
  390. {
  391. var obj = null;
  392. try
  393. {
  394. obj = JSON.parse(res);
  395. }
  396. catch (e)
  397. {
  398. // ignore
  399. }
  400. //console.trace('DRAFT: Saved', obj);
  401. if (obj != null && obj.error != null)
  402. {
  403. if (err != null)
  404. {
  405. err(obj);
  406. }
  407. }
  408. else
  409. {
  410. draftExists = true;
  411. if (fn != null)
  412. {
  413. fn(obj);
  414. }
  415. }
  416. },
  417. function(res)
  418. {
  419. //console.trace('DRAFT: Save error');
  420. var obj = null;
  421. try
  422. {
  423. obj = JSON.parse(res);
  424. }
  425. catch (e)
  426. {
  427. // ignore
  428. }
  429. if (obj != null && obj.error != null)
  430. {
  431. if (err != null)
  432. {
  433. err(obj);
  434. }
  435. }
  436. }, false, 'text/plain', 'Created by Draw.io', false, draftPage);
  437. };
  438. function showTemplateDialog()
  439. {
  440. if (AC.draftEnabled)
  441. {
  442. editor.contentWindow.postMessage(JSON.stringify({action: 'template', callback: true, enableRecent: true, enableSearch: true}), '*');
  443. }
  444. else
  445. {
  446. editor.contentWindow.postMessage(JSON.stringify({action: 'template', enableRecent: true, enableSearch: true}), '*');
  447. }
  448. };
  449. function promptName(name, err, errKey)
  450. {
  451. editor.contentWindow.postMessage(JSON.stringify({action: 'prompt',
  452. titleKey: 'filename', okKey: 'save', defaultValue: name || '' }), '*');
  453. if (err != null || errKey != null)
  454. {
  455. editor.contentWindow.postMessage(JSON.stringify({action: 'dialog',
  456. titleKey: 'error', message: err, messageKey: errKey,
  457. buttonKey: 'ok'}), '*');
  458. }
  459. };
  460. function checkName(name, fn, err)
  461. {
  462. if (name == null || name.length == 0)
  463. {
  464. err(name, 'Filename too short');
  465. }
  466. else if (/[&\*+=\\;/{}|\":<>\?~]/g.test(name))
  467. {
  468. err(name, 'Invalid characters \\ / | : { } < > & + ? = ; * " ~');
  469. }
  470. else
  471. {
  472. request({
  473. type: 'POST',
  474. data: JSON.stringify([pageId]),
  475. url: '/rpc/json-rpc/confluenceservice-v2/getAttachments',
  476. contentType: 'application/json;charset=UTF-8',
  477. success: function(res)
  478. {
  479. var attachments = JSON.parse(res);
  480. if (attachments.error != null)
  481. {
  482. err(name, attachments.error.message);
  483. }
  484. else
  485. {
  486. var draftPattern = new RegExp('^~drawio~.*~' + name.
  487. replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + '.tmp$', 'i');
  488. var lc = name.toLowerCase();
  489. var dn = AC.draftPrefix + lc + AC.draftExtension
  490. var fileExists = false;
  491. // Checks if any files will be overwritten
  492. for (var i = 0; i < attachments.length && !fileExists; i++)
  493. {
  494. // To avoid name clash with new diagrams of other users,
  495. // we need to check for ~drawio~.*~filename.tmp
  496. var an = attachments[i].fileName.toLowerCase();
  497. if (an == lc || an == lc + '.png' || (AC.draftEnabled &&
  498. (an == dn || draftPattern.test(an))))
  499. {
  500. fileExists = true;
  501. }
  502. }
  503. if (fileExists)
  504. {
  505. err(name, name + ' already exists');
  506. }
  507. else
  508. {
  509. fn(name);
  510. }
  511. }
  512. },
  513. error: function(res)
  514. {
  515. // LATER: What error message to return here?
  516. err(name, res);
  517. }
  518. });
  519. }
  520. };
  521. var autosaveThread = null;
  522. var autosaveCounter = 0;
  523. var currentXml = null;
  524. // Shows template dialog for new diagrams with no draft state
  525. if (initialXml != '')
  526. {
  527. editor.contentWindow.postMessage(JSON.stringify({action: 'load',
  528. autosave: 1, xml: initialXml, title: diagramName,
  529. macroData: macroData}), '*');
  530. }
  531. if (draftXml != null)
  532. {
  533. // Keeps ignore option even for existing files
  534. editor.contentWindow.postMessage(JSON.stringify({action: 'draft', xml: draftXml,
  535. name: diagramName, discardKey: 'discardChanges', ignore: true}), '*');
  536. }
  537. else if (initialXml == '')
  538. {
  539. showTemplateDialog();
  540. }
  541. var messageListener = function(evt)
  542. {
  543. if (typeof window.AC !== 'undefined' && evt.origin == hostUrl)
  544. {
  545. var drawMsg = JSON.parse(evt.data);
  546. if (drawMsg.event == 'draft')
  547. {
  548. if (drawMsg.error != null)
  549. {
  550. //console.log('DRAFT: error', drawMsg);
  551. editor.parentNode.removeChild(editor);
  552. var message = messages.error('Draft Read Error', drawMsg.error);
  553. messages.onClose(message, function()
  554. {
  555. confluence.closeMacroEditor();
  556. });
  557. }
  558. else if (drawMsg.result == 'edit')
  559. {
  560. // Use draft
  561. //console.trace('DRAFT: Using', draftName);
  562. editor.contentWindow.postMessage(JSON.stringify({action: 'load',
  563. autosave: 1, xml: drawMsg.message.xml, title: diagramName}), '*');
  564. editor.contentWindow.postMessage(JSON.stringify({action: 'status',
  565. messageKey: 'unsavedChanges', modified: true}), '*');
  566. draftExists = true;
  567. }
  568. else
  569. {
  570. if (initialXml == '' || drawMsg.result == 'ignore')
  571. {
  572. if (initialXml != '')
  573. {
  574. editor.contentWindow.postMessage(JSON.stringify({action: 'load',
  575. autosave: 1, xml: initialXml, title: diagramName,
  576. macroData: macroData}), '*');
  577. }
  578. else
  579. {
  580. diagramName = null;
  581. showTemplateDialog();
  582. }
  583. }
  584. else
  585. {
  586. //console.trace('DRAFT: Discarding', draftName);
  587. AC.removeAttachment(pageId, draftName);
  588. }
  589. }
  590. }
  591. else if (drawMsg.event == 'searchDocs')
  592. {
  593. //since we don't use a unique file extension for draw.io diagrams, we need to find pages having draw.io macro also
  594. //So, two search requests are needed
  595. AP.require('request', function(request) {
  596. request({
  597. //TODO this query can be enhanced to get part of the name matching but the problem is with the png!
  598. url: '/rest/api/content/search?cql=' + encodeURIComponent('type=attachment and (title ~ "' + drawMsg.searchStr + '" or title ~ "' + drawMsg.searchStr + '.png")') + '&limit=100', //limit is 100 and the pages limit is 50 since each diagram has two attachments (and we assume one diagram per page)
  599. success: function(resp)
  600. {
  601. resp = JSON.parse(resp);
  602. var retList = [];
  603. var list = resp.results;
  604. if (list)
  605. {
  606. var attMap = {};
  607. //convert the list to map so we can search by name effeciently
  608. for (var i = 0; i < list.length; i++)
  609. {
  610. //key is pageId + | + att name
  611. var pageId = list[i]["_links"]["webui"].match(/pages\/(\d+)/);
  612. if (pageId != null)
  613. {
  614. attMap[pageId[1] + '|' + list[i].title] = {att: list[i], pageId: pageId[1]};
  615. }
  616. }
  617. //TODO confirm that the attachments are in a page having draw.io macro
  618. for (var key in attMap)
  619. {
  620. var att = attMap[key];
  621. if (attMap[key+'.png']) //each draw.io attachment should have an associated png preview
  622. {
  623. //We cannot get the latest version info, it can searched when a diagram is selected
  624. retList.push({
  625. title: att.att.title,
  626. url: "/download/attachments/" + att.pageId + "/"
  627. + encodeURIComponent(att.att.title),
  628. info: {
  629. id: att.att.id,
  630. pageId: att.pageId
  631. },
  632. imgUrl: baseUrl + "/download/attachments/" + att.pageId + "/"
  633. + encodeURIComponent(att.att.title)
  634. + ".png?api=v2"
  635. });
  636. }
  637. }
  638. editor.contentWindow.postMessage(JSON.stringify({action: 'searchDocsList',
  639. list: retList}), '*');
  640. }
  641. },
  642. error : function(resp)
  643. {
  644. editor.contentWindow.postMessage(JSON.stringify({action: 'searchDocsList',
  645. list: [], errorMsg: "Network Error!"}), '*');
  646. }
  647. });
  648. });
  649. }
  650. else if (drawMsg.event == 'recentDocs')
  651. {
  652. //since we don't use a unique file extension for draw.io diagrams, we need to find pages having draw.io macro also
  653. //So, two search requests are needed
  654. AP.require('request', function(request) {
  655. request({
  656. url: '/rest/api/content/search?cql=type=attachment%20and%20lastmodified%3E%20startOfDay(%22-7d%22)&limit=100', //cql= type=attachment and lastmodified > startOfDay("-7d") //modified in the last 7 days
  657. //limit is 100 and the pages limit is 50 since each diagram has two attachments (and we assume one diagram per page)
  658. success: function(resp)
  659. {
  660. resp = JSON.parse(resp);
  661. var retList = [];
  662. var list = resp.results;
  663. if (list)
  664. {
  665. var attMap = {};
  666. //convert the list to map so we can search by name effeciently
  667. for (var i = 0; i < list.length; i++)
  668. {
  669. //key is pageId + | + att name
  670. var pageId = list[i]["_links"]["webui"].match(/pages\/(\d+)/);
  671. if (pageId != null)
  672. {
  673. attMap[pageId[1] + '|' + list[i].title] = {att: list[i], pageId: pageId[1]};
  674. }
  675. }
  676. //confirm that the attachments are in a page having draw.io macro
  677. request({
  678. url: '/rest/api/content/search?cql=macro=drawio%20and%20lastmodified%3E%20startOfDay(%22-7d%22)&limit=50', //cql= macro=drawio and lastmodified > startOfDay("-7d") //modified in the last 7 days
  679. success: function(resp)
  680. {
  681. resp = JSON.parse(resp);
  682. var pages = {};
  683. var list = resp.results;
  684. if (list)
  685. {
  686. for (var i = 0; i < list.length; i++)
  687. {
  688. pages[list[i].id] = list[i];
  689. }
  690. }
  691. for (var key in attMap)
  692. {
  693. var att = attMap[key];
  694. if (attMap[key+'.png'] && pages[att.pageId] != null) //each draw.io attachment should have an associated png preview
  695. {
  696. //We cannot get the latest version info, it can searched when a diagram is selected
  697. retList.push({
  698. title: att.att.title,
  699. url: "/download/attachments/" + att.pageId + "/"
  700. + encodeURIComponent(att.att.title),
  701. info: {
  702. id: att.att.id,
  703. pageId: att.pageId
  704. },
  705. imgUrl: baseUrl + "/download/attachments/" + att.pageId + "/"
  706. + encodeURIComponent(att.att.title)
  707. + ".png?api=v2"
  708. });
  709. }
  710. }
  711. editor.contentWindow.postMessage(JSON.stringify({action: 'recentDocsList',
  712. list: retList}), '*');
  713. },
  714. error : function(resp)
  715. {
  716. editor.contentWindow.postMessage(JSON.stringify({action: 'recentDocsList',
  717. list: [], errorMsg: "Network Error!"}), '*');
  718. }
  719. });
  720. }
  721. },
  722. error : function(resp)
  723. {
  724. editor.contentWindow.postMessage(JSON.stringify({action: 'recentDocsList',
  725. list: [], errorMsg: "Network Error!"}), '*');
  726. }
  727. });
  728. });
  729. }
  730. else if (drawMsg.event == 'template')
  731. {
  732. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  733. show: true, messageKey: 'inserting'}), '*');
  734. if (drawMsg.docUrl)
  735. {
  736. checkName(drawMsg.name, function(name)
  737. {
  738. diagramName = name;
  739. AP.require('request', function(request) {
  740. var loadTemplate = function(version)
  741. {
  742. request({
  743. url: drawMsg.docUrl + (version != null? "?version=" + version : ""),
  744. success: function(xml)
  745. {
  746. editor.contentWindow.postMessage(JSON.stringify({action: 'load',
  747. autosave: 1, xml: xml, title: diagramName}), '*');
  748. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  749. show: false}), '*');
  750. },
  751. error : function(resp)
  752. {
  753. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  754. show: false}), '*');
  755. editor.contentWindow.postMessage(JSON.stringify({action: 'dialog',
  756. titleKey: 'error', message: "Diagram cannot be loaded", messageKey: null,
  757. buttonKey: 'ok'}), '*');
  758. }
  759. });
  760. }
  761. request({
  762. url: '/rest/api/content/' + drawMsg.info.id,
  763. success: function(resp)
  764. {
  765. resp = JSON.parse(resp);
  766. try
  767. {
  768. loadTemplate(resp.version.number);
  769. }
  770. catch(e)
  771. {
  772. loadTemplate();
  773. }
  774. },
  775. error : function(resp)
  776. {
  777. loadTemplate();
  778. }
  779. });
  780. });
  781. },
  782. function(name, err, errKey)
  783. {
  784. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  785. show: false}), '*');
  786. editor.contentWindow.postMessage(JSON.stringify({action: 'dialog',
  787. titleKey: 'error', message: err, messageKey: errKey,
  788. buttonKey: 'ok'}), '*');
  789. });
  790. }
  791. else
  792. {
  793. checkName(drawMsg.name, function(name)
  794. {
  795. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  796. show: false}), '*');
  797. diagramName = name;
  798. if (AC.draftEnabled)
  799. {
  800. draftName = '~drawio~' + user + '~' + diagramName + AC.draftExtension;
  801. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  802. show: true, messageKey: 'inserting'}), '*');
  803. saveDraft(drawMsg.xml, function()
  804. {
  805. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner', show: false}), '*');
  806. editor.contentWindow.postMessage(JSON.stringify({action: 'load',
  807. autosave: 1, xml: drawMsg.xml, title: diagramName}), '*');
  808. },
  809. function()
  810. {
  811. editor.parentNode.removeChild(editor);
  812. var message = messages.error('Draft Write Error', 'Draft could not be created');
  813. messages.onClose(message, function()
  814. {
  815. confluence.closeMacroEditor();
  816. });
  817. });
  818. }
  819. else
  820. {
  821. editor.contentWindow.postMessage(JSON.stringify({action: 'load',
  822. autosave: 1, xml: drawMsg.xml, title: diagramName}), '*');
  823. }
  824. },
  825. function(name, err, errKey)
  826. {
  827. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  828. show: false}), '*');
  829. editor.contentWindow.postMessage(JSON.stringify({action: 'dialog',
  830. titleKey: 'error', message: err, messageKey: errKey,
  831. buttonKey: 'ok'}), '*');
  832. });
  833. }
  834. }
  835. else if (drawMsg.event == 'autosave')
  836. {
  837. // Saves all changes to draft attachment
  838. currentXml = drawMsg.xml;
  839. if (autosaveThread == null && AC.draftEnabled)
  840. {
  841. //console.trace('DRAFT: Starting timer');
  842. autosaveThread = window.setTimeout(function()
  843. {
  844. //console.log('DRAFT: Saving', currentXml);
  845. autosaveThread = null
  846. saveDraft(currentXml);
  847. autosaveCounter++;
  848. }, (autosaveCounter == 0) ? 0 : AC.autosaveTimeout);
  849. }
  850. }
  851. else if (drawMsg.event == 'exit')
  852. {
  853. removeDraft(function()
  854. {
  855. confluence.closeMacroEditor();
  856. });
  857. }
  858. else if (drawMsg.event == 'save')
  859. {
  860. diagramXml = drawMsg.xml;
  861. if (diagramName == null)
  862. {
  863. promptName('');
  864. }
  865. else
  866. {
  867. editor.contentWindow.postMessage(JSON.stringify({action: 'export',
  868. format: 'png', spinKey: 'saving', message: drawMsg}), '*');
  869. }
  870. }
  871. else if (drawMsg.event == 'prompt')
  872. {
  873. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  874. show: true, messageKey: 'inserting'}), '*');
  875. checkName(drawMsg.value, function(name)
  876. {
  877. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  878. show: false}), '*');
  879. diagramName = name;
  880. editor.contentWindow.postMessage(JSON.stringify({action: 'export',
  881. format: 'png', spinKey: 'saving'}), '*');
  882. },
  883. function(name, err, errKey)
  884. {
  885. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  886. show: false}), '*');
  887. promptName(name, err, errKey);
  888. });
  889. }
  890. else if (drawMsg.event == 'export')
  891. {
  892. // Proceeds from sending the export message by saving the exported files
  893. var imageData = drawMsg.data.substring(drawMsg.data.indexOf(',') + 1);
  894. var diaWidth = drawMsg.bounds.width / drawMsg.scale;
  895. var diaHeight = drawMsg.bounds.height / drawMsg.scale;
  896. function showError(key, message)
  897. {
  898. var msg = {action: 'dialog', titleKey: 'error', modified: true, buttonKey: 'close'};
  899. if (message != null)
  900. {
  901. msg.message = message;
  902. }
  903. else
  904. {
  905. msg.messageKey = key || 'errorSavingFile';
  906. }
  907. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner', show: false}), '*');
  908. editor.contentWindow.postMessage(JSON.stringify(msg), '*');
  909. };
  910. function saveError(err)
  911. {
  912. var key = null;
  913. var message = null;
  914. if (err.status == 409)
  915. {
  916. diagramName = null;
  917. key = 'fileExists';
  918. }
  919. else if (err.status == 401)
  920. {
  921. // Session expired
  922. message = 'Looks like your session expired. Log in again to keep working. ' +
  923. '<a href="' + baseUrl + '/pages/dashboard.action" target="_blank">Login</a>';
  924. }
  925. showError(key, message);
  926. };
  927. function successXml(responseText)
  928. {
  929. var resp = null;
  930. var revision = '1';
  931. var contentId = null;
  932. var contentVer = null;
  933. //TODO Why this code (Is it expected to have incorrect responseText?)
  934. try
  935. {
  936. resp = JSON.parse(responseText);
  937. }
  938. catch (e)
  939. {
  940. // Ignores and use default value for revision
  941. }
  942. // LATER: Get revision from metadata of attachment and check
  943. // what condition makes the response not contain an URL
  944. //TODO Is prev comment still needed with REST API?
  945. if (resp != null && resp.results != null && resp.results[0])
  946. {
  947. var attObj = resp.results[0];
  948. revision = attObj.version.number;
  949. //Save/update the custom content
  950. var spaceKey = AC.getSpaceKey(attObj._expandable.space);
  951. var pageType = attObj.container.type;
  952. AC.saveCustomContent(spaceKey, pageId, pageType, diagramName, revision,
  953. (drawMsg.macroData != null) ? drawMsg.macroData.contentId : null,
  954. (drawMsg.macroData != null) ? drawMsg.macroData.contentVer : null,
  955. function(responseText)
  956. {
  957. var content = JSON.parse(responseText);
  958. contentId = content.id;
  959. contentVer = content.version.number;
  960. AC.saveDiagram(pageId, diagramName + '.png', AC.b64toBlob(imageData, 'image/png'),
  961. successPng, saveError, false, 'image/png', 'draw.io preview', false, draftPage);
  962. }, saveError);
  963. }
  964. else
  965. {
  966. // Logs special case where save response has no URL
  967. try
  968. {
  969. var img = new Image();
  970. var message = 'Invalid Confluence Cloud response';
  971. img.src = '/images/2x2.png?msg=' + encodeURIComponent(message) +
  972. ((responseText != null) ? '&resp=' + encodeURIComponent(responseText) : '&resp=[null]');
  973. '&url=' + encodeURIComponent(window.location.href) +
  974. '&v=' + encodeURIComponent(EditorUi.VERSION);
  975. }
  976. catch (err)
  977. {
  978. // do nothing
  979. }
  980. //TODO Save png here in case responseText is incorrect (But why it can be incorrect?)
  981. AC.saveDiagram(pageId, diagramName + '.png', AC.b64toBlob(imageData, 'image/png'),
  982. successPng, saveError, false, 'image/png', 'draw.io preview', false, draftPage);
  983. }
  984. function successPng(pngResponseText)
  985. {
  986. try
  987. {
  988. confluence.saveMacro(
  989. {
  990. diagramName: diagramName,
  991. revision: revision,
  992. pageId: newPage ? null : pageId,
  993. contentId: contentId,
  994. contentVer: contentVer,
  995. baseUrl: baseUrl,
  996. width: diaWidth,
  997. height: diaHeight,
  998. tbstyle: (drawMsg.macroData != null) ? drawMsg.macroData.tbstyle : '',
  999. links: (drawMsg.macroData != null) ? drawMsg.macroData.links : '',
  1000. lbox: (drawMsg.macroData != null && drawMsg.macroData.lbox != null) ? drawMsg.macroData.lbox : '1',
  1001. zoom: (drawMsg.macroData != null && drawMsg.macroData.zoom != null) ? drawMsg.macroData.zoom : '1'
  1002. });
  1003. if (AC.autoExit || drawMsg.message == null || drawMsg.message.message == null || drawMsg.message.message.exit)
  1004. {
  1005. removeDraft(function()
  1006. {
  1007. confluence.closeMacroEditor();
  1008. });
  1009. }
  1010. else
  1011. {
  1012. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner', show: false}), '*');
  1013. editor.contentWindow.postMessage(JSON.stringify({action: 'status', message: '', modified: false}), '*');
  1014. }
  1015. }
  1016. catch (e)
  1017. {
  1018. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner', show: false}), '*');
  1019. editor.contentWindow.postMessage(JSON.stringify({action: 'dialog',
  1020. titleKey: 'errorSavingFile', message: e.message, buttonKey: 'ok'}), '*');
  1021. }
  1022. };
  1023. };
  1024. if (diagramName != null)
  1025. {
  1026. editor.contentWindow.postMessage(JSON.stringify({action: 'spinner',
  1027. show: true, messageKey: 'saving'}), '*');
  1028. AC.saveDiagram(pageId, diagramName, diagramXml,
  1029. successXml, saveError, false, 'text/plain', 'draw.io diagram', false, draftPage);
  1030. }
  1031. }
  1032. }
  1033. };
  1034. window.addEventListener('message', messageListener);
  1035. });
  1036. };
  1037. AC.loadDiagram = function (pageId, diagramName, revision, success, error, owningPageId, tryRev1, dontCheckVer) {
  1038. // TODO: Get binary
  1039. AP.require(['request', 'confluence'], function(request, confluence) {
  1040. //Confirm that the macro is in sync with the diagram
  1041. //Sometimes the diagram is saved but the macro is not updated
  1042. var attInfo = null;
  1043. var pageInfo = null;
  1044. function confirmDiagramInSync()
  1045. {
  1046. if (attInfo == null || pageInfo == null)
  1047. return;
  1048. //TODO is this condition enough or we need to check timestamps also?
  1049. if (attInfo.version.number > revision
  1050. && (pageInfo.version.message == null || pageInfo.version.message.indexOf("Reverted") < 0))
  1051. {
  1052. AC.loadDiagram(pageId, diagramName, attInfo.version.number, success, error, owningPageId, tryRev1, true);
  1053. //Update the macro
  1054. //Custom Content version will be fixed on next save, this will not affect correctness
  1055. confluence.getMacroData(function (macroData)
  1056. {
  1057. if (macroData != null)
  1058. {
  1059. confluence.saveMacro(
  1060. {
  1061. diagramName: macroData.diagramName,
  1062. revision: attInfo.version.number,
  1063. pageId: macroData.pageId,
  1064. contentId: macroData.contentId,
  1065. contentVer: macroData.contentVer,
  1066. baseUrl: macroData.baseUrl,
  1067. width: macroData.width,
  1068. height: macroData.height,
  1069. tbstyle: macroData.tbstyle,
  1070. links: macroData.links,
  1071. lbox: macroData.lbox != null ? macroData.lbox : '1',
  1072. zoom: macroData.zoom != null ? macroData.zoom : '1'
  1073. });
  1074. }
  1075. });
  1076. }
  1077. }
  1078. //To avoid race we do the version check after loading the diagram in the macro
  1079. var localSuccess = function()
  1080. {
  1081. success.apply(this, arguments);
  1082. if (!dontCheckVer && revision != null)
  1083. {
  1084. request({
  1085. type: 'GET',
  1086. url: '/rest/api/content/' + pageId + '?expand=version',
  1087. contentType: 'application/json;charset=UTF-8',
  1088. success: function (resp)
  1089. {
  1090. pageInfo = JSON.parse(resp);
  1091. confirmDiagramInSync();
  1092. },
  1093. error: function (resp)
  1094. {
  1095. //Ignore
  1096. }
  1097. });
  1098. request({
  1099. type: 'GET',
  1100. url: '/rest/api/content/' + pageId + '/child/attachment?filename=' +
  1101. encodeURIComponent(diagramName) + '&expand=version',
  1102. contentType: 'application/json;charset=UTF-8',
  1103. success: function (resp)
  1104. {
  1105. var tmp = JSON.parse(resp);
  1106. if (tmp.results && tmp.results.length == 1)
  1107. {
  1108. attInfo = tmp.results[0];
  1109. }
  1110. confirmDiagramInSync();
  1111. },
  1112. error: function (resp)
  1113. {
  1114. //Ignore
  1115. }
  1116. });
  1117. }
  1118. }
  1119. request({
  1120. //TODO find out the ID of the page that actually holds the attachments because historical revisions do not have attachments
  1121. url: '/download/attachments/' + pageId + '/' + encodeURIComponent(diagramName) +
  1122. ((revision != null) ? '?version=' + revision : ''),
  1123. success: localSuccess,
  1124. error : function(resp)
  1125. {
  1126. //When a page is copied, attachments are reset to version 1 while the revision parameter remains the same
  1127. if (tryRev1 && revision > 1 && resp.status == 404)
  1128. {
  1129. request({
  1130. url: '/download/attachments/' + pageId + '/' + encodeURIComponent(diagramName),
  1131. success: localSuccess,
  1132. error : function(resp) { //If revesion 1 failed, then try the owningPageId
  1133. if (owningPageId && resp.status == 404)
  1134. {
  1135. request({
  1136. url: '/download/attachments/' + owningPageId + '/' + encodeURIComponent(diagramName)
  1137. +'?version=' + revision, //this version should exists in the original owning page
  1138. success: localSuccess,
  1139. error : error
  1140. });
  1141. }
  1142. }
  1143. });
  1144. }
  1145. else if (owningPageId && resp.status == 404) //We are at revesion 1, so try the owningPageId directly
  1146. {
  1147. request({
  1148. url: '/download/attachments/' + owningPageId + '/' + encodeURIComponent(diagramName),
  1149. success: localSuccess,
  1150. error : error
  1151. });
  1152. }
  1153. else
  1154. {
  1155. error(resp);
  1156. }
  1157. }
  1158. });
  1159. });
  1160. };
  1161. AC.saveCustomContent = function(spaceKey, pageId, pageType, diagramName, revision, contentId, contentVer, success, error)
  1162. {
  1163. var customObj = {
  1164. "type": "ac:com.mxgraph.confluence.plugins.diagramly:drawio-diagram",
  1165. "space": {
  1166. "key": spaceKey
  1167. },
  1168. "container": {
  1169. "type": pageType,
  1170. "id": pageId
  1171. },
  1172. "title": diagramName,
  1173. "body": {
  1174. "storage": {
  1175. "value": encodeURIComponent(JSON.stringify({
  1176. "pageId": pageId,
  1177. "diagramName": diagramName,
  1178. "version": revision
  1179. })),
  1180. "representation": "storage"
  1181. }
  1182. },
  1183. "status": "current"
  1184. };
  1185. if (contentId)
  1186. {
  1187. customObj.version = {
  1188. "number": ++contentVer
  1189. };
  1190. }
  1191. AP.require(['request'], function(request)
  1192. {
  1193. request({
  1194. type: contentId? 'PUT' : 'POST',
  1195. data: JSON.stringify(customObj),
  1196. url: "/rest/api/content/" + (contentId? contentId : ""),
  1197. contentType: "application/json",
  1198. success: success,
  1199. error: function(resp) {
  1200. //User can delete a custom content externally and we will get error 403 and message will contain the given id
  1201. //Then save a new one
  1202. var err = JSON.parse(resp.responseText);
  1203. if (contentId && err.statusCode == 403 && err.message.indexOf(contentId) > 0)
  1204. {
  1205. AC.saveCustomContent(spaceKey, pageId, pageType, diagramName, revision, null, null, success, error);
  1206. }
  1207. //Sometimes the macro is not updated such that the version is not correct. The same happens when a page version is restored
  1208. else if (err.statusCode == 409 && err.message.indexOf("Current version is:") > 0)
  1209. {
  1210. //We will use the error message to detect the correct version instead of doing another request.
  1211. //It should be safe as long as error messages are not translated or changed
  1212. var curContentVer = err.message.match(/\d+/);
  1213. if (curContentVer != null)
  1214. {
  1215. AC.saveCustomContent(spaceKey, pageId, pageType, diagramName, revision, contentId, curContentVer[0], success, error);
  1216. }
  1217. }
  1218. else
  1219. {
  1220. error(resp);
  1221. }
  1222. }
  1223. });
  1224. });
  1225. };
  1226. //TODO We can upload both the diagram and its png in one call if needed?
  1227. AC.saveDiagram = function(pageId, diagramName, xml, success, error, newSave, mime, comment, sendNotif, draftPage)
  1228. {
  1229. loadSucess = function(resp)
  1230. {
  1231. error({status: 409, message: 'File already exists'});
  1232. };
  1233. loadError = function(resp)
  1234. {
  1235. if (resp.status == 404) // file under given name does not exist means we can proceed with saving
  1236. {
  1237. doSave();
  1238. }
  1239. else
  1240. {
  1241. error({status: resp.status, message : resp.statusText });
  1242. }
  1243. };
  1244. var sessionCheck = function(responseText)
  1245. {
  1246. if (responseText != null)
  1247. {
  1248. var obj = JSON.parse(responseText);
  1249. if (obj != null && obj.code == -32600) //TODO is the codes the same with new REST APIs
  1250. {
  1251. error({status: 401});
  1252. return;
  1253. }
  1254. }
  1255. success(responseText);
  1256. }
  1257. doSave = function()
  1258. {
  1259. AP.require(['request'], function(request)
  1260. {
  1261. var attFile = (xml instanceof Blob)? xml : new Blob([xml], {type: mime});
  1262. attFile.name = diagramName;
  1263. var reqData = {file: attFile, minorEdit: sendNotif? false : true};
  1264. var draft = draftPage ? "?status=draft" : "";
  1265. if (comment != null)
  1266. {
  1267. reqData.comment = comment;
  1268. }
  1269. request({
  1270. type: 'PUT',
  1271. data: reqData,
  1272. url: "/rest/api/content/"+ pageId +"/child/attachment" + draft,
  1273. contentType: "multipart/form-data",
  1274. success: sessionCheck,
  1275. error: error
  1276. });
  1277. });
  1278. };
  1279. if(newSave && mime == 'text/plain')
  1280. {
  1281. this.loadDiagram(pageId, diagramName, 0, loadSucess, loadError);
  1282. }
  1283. else
  1284. {
  1285. doSave();
  1286. }
  1287. };
  1288. AC.removeAttachment = function(pageId, filename, fn, err)
  1289. {
  1290. if (pageId != null && filename != null)
  1291. {
  1292. AP.require('request', function(request) {
  1293. request({
  1294. type: 'POST',
  1295. data: JSON.stringify([pageId, filename]),
  1296. url: '/rpc/json-rpc/confluenceservice-v2/removeAttachment',
  1297. contentType: 'application/json;charset=UTF-8',
  1298. success: function()
  1299. {
  1300. if (fn != null)
  1301. {
  1302. fn();
  1303. }
  1304. },
  1305. error: function()
  1306. {
  1307. if (err != null)
  1308. {
  1309. err();
  1310. }
  1311. if (fn != null)
  1312. {
  1313. fn();
  1314. }
  1315. }
  1316. });
  1317. });
  1318. }
  1319. else
  1320. {
  1321. fn();
  1322. }
  1323. };
  1324. AC.getMacroData = function(fn) {
  1325. AP.require('confluence', function(confluence) {
  1326. confluence.getMacroData(fn);
  1327. });
  1328. }
  1329. //From mxUtils
  1330. AC.htmlEntities = function(s, newline)
  1331. {
  1332. s = String(s || '');
  1333. s = s.replace(/&/g,'&amp;'); // 38 26
  1334. s = s.replace(/"/g,'&quot;'); // 34 22
  1335. s = s.replace(/\'/g,'&#39;'); // 39 27
  1336. s = s.replace(/</g,'&lt;'); // 60 3C
  1337. s = s.replace(/>/g,'&gt;'); // 62 3E
  1338. if (newline == null || newline)
  1339. {
  1340. s = s.replace(/\n/g, '&#xa;');
  1341. }
  1342. return s;
  1343. };
  1344. AC.fromHtmlEntities = function(s, newline)
  1345. {
  1346. s = String(s || '');
  1347. s = s.replace(/&amp;/g,'&'); // 38 26
  1348. s = s.replace(/&quot;/g,'"'); // 34 22
  1349. s = s.replace(/&#39;/g,'\\'); // 39 27
  1350. s = s.replace(/&lt;/g,'<'); // 60 3C
  1351. s = s.replace(/&gt;/g,'>'); // 62 3E
  1352. if (newline == null || newline)
  1353. {
  1354. s = s.replace(/&#xa;/g, '\n');
  1355. }
  1356. return s;
  1357. };