script.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. using static FastReport.Web.Constants;
  2. namespace FastReport.Web
  3. {
  4. partial class WebReport
  5. {
  6. string template_script() => $@"
  7. 'use strict';
  8. var {template_FR} = {{
  9. outline: function () {{
  10. var sizes = sessionStorage.getItem('fastreport-outline-split-sizes');
  11. if (sizes) {{
  12. sizes = JSON.parse(sizes);
  13. }} else {{
  14. sizes = [25, 75];
  15. }}
  16. var split = this.Split(['.{template_FR}-outline', '.{template_FR}-report'], {{
  17. sizes: sizes,
  18. minSize: [0, 50],
  19. snapOffset: 20,
  20. onDragEnd: function () {{
  21. sessionStorage.setItem('fastreport-outline-split-sizes', JSON.stringify(split.getSizes()));
  22. }},
  23. elementStyle: function (dimension, size, gutterSize) {{
  24. return {{
  25. 'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)'
  26. }}
  27. }},
  28. gutterStyle: function (dimension, gutterSize) {{
  29. return {{
  30. 'flex-basis': gutterSize + 'px'
  31. }}
  32. }},
  33. gutter: function (index, direction) {{
  34. var gutter = document.createElement('div');
  35. gutter.className = '{template_FR}-gutter {template_FR}-gutter-' + direction;
  36. return gutter;
  37. }}
  38. }});
  39. var tree = sessionStorage.getItem('fastreport-outline-tree');
  40. if (tree) {{
  41. tree = JSON.parse(tree);
  42. var that = this;
  43. var container = this._findContainer();
  44. Object.keys(tree).forEach(function (key) {{
  45. var caret = container.querySelector('[data-fr-outline-node-id=""' + key + '""]');
  46. if (caret) {{
  47. that.outlineOpenNode(caret, true);
  48. }}
  49. }});
  50. }}
  51. }},
  52. outlineOpenNode: function (caret, skipTreeStorage) {{
  53. caret.parentNode.parentNode.getElementsByClassName('{template_FR}-outline-children')[0].style.display = '';
  54. caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-open-node')[0].style.display = 'none';
  55. caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-close-node')[0].style.display = '';
  56. if (skipTreeStorage === true) {{
  57. return;
  58. }}
  59. var tree = sessionStorage.getItem('fastreport-outline-tree');
  60. if (tree) {{
  61. tree = JSON.parse(tree);
  62. }} else {{
  63. tree = {{}};
  64. }}
  65. tree[caret.getAttribute('data-fr-outline-node-id')] = true;
  66. sessionStorage.setItem('fastreport-outline-tree', JSON.stringify(tree));
  67. }},
  68. outlineCloseNode: function (caret) {{
  69. caret.parentNode.parentNode.getElementsByClassName('{template_FR}-outline-children')[0].style.display = 'none';
  70. caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-open-node')[0].style.display = '';
  71. caret.parentNode.parentNode.getElementsByClassName('{template_FR}-js-outline-close-node')[0].style.display = 'none';
  72. var tree = sessionStorage.getItem('fastreport-outline-tree');
  73. if (tree) {{
  74. tree = JSON.parse(tree);
  75. }} else {{
  76. tree = {{}};
  77. }}
  78. delete tree[caret.getAttribute('data-fr-outline-node-id')];
  79. sessionStorage.setItem('fastreport-outline-tree', JSON.stringify(tree));
  80. }},
  81. outlineGoto: function (page, offset) {{
  82. this.goto(page);
  83. }},
  84. load: function () {{
  85. this._reload();
  86. }},
  87. refresh: function () {{
  88. this._reload('&forceRefresh=yes');
  89. }},
  90. zoom: function (value) {{
  91. this._closeDropdowns();
  92. this._reload('&skipPrepare=yes&zoom=' + value);
  93. }},
  94. goto: function (page) {{
  95. this._reload('&skipPrepare=yes&goto=' + page);
  96. }},
  97. click: function (el, kind, value) {{
  98. var that = this;
  99. if (kind == 'text_edit') {{
  100. if (that._win) {{
  101. that._win.close();
  102. }}
  103. that._win = this._popup('{template_ROUTE_BASE_PATH}/preview.textEditForm?reportId={ID}&click=' + value, 'Text edit', 400, 200);
  104. that._win.onmessage = function (e) {{
  105. if (e.data == 'submit') {{
  106. var newText = that._win.document.querySelector('textarea').value;
  107. var form = new FormData();
  108. form.append('text', newText);
  109. that._reload('&skipPrepare=yes&' + kind + '=' + value, form);
  110. that._win.close();
  111. }}
  112. }};
  113. return;
  114. }}
  115. this._reload('&skipPrepare=yes&' + kind + '=' + value);
  116. }},
  117. customMethodInvoke: function(elementId, inputValue){{
  118. var that = this;
  119. var body = this._findBody();
  120. var container = this._findContainer();
  121. this._fetch({{
  122. method: 'POST',
  123. url: '{template_ROUTE_BASE_PATH}/preview.toolbarElementClick?reportId={ID}&elementId=' + elementId + '&inputValue=' + inputValue,
  124. onSend: function () {{
  125. that._activateSpinner();
  126. }},
  127. onSuccess: function (xhr) {{
  128. container.outerHTML = xhr.responseText;
  129. that._execScripts();
  130. }},
  131. onError: function (xhr) {{
  132. that._placeError(xhr, body);
  133. that._deactivateSpinner();
  134. }}
  135. }});
  136. }},
  137. settab: function (tab) {{
  138. this._reload('&skipPrepare=yes&settab=' + tab);
  139. }},
  140. closetab: function (tab) {{
  141. this._reload('&skipPrepare=yes&closetab=' + tab);
  142. }},
  143. _reload: function (params, form) {{
  144. var that = this;
  145. var body = this._findBody();
  146. var container = this._findContainer();
  147. this._fetch({{
  148. method: 'POST',
  149. url: '{template_ROUTE_BASE_PATH}/preview.getReport?reportId={ID}&renderBody=yes' + (params || ''),
  150. form: form,
  151. onSend: function () {{
  152. that._activateSpinner();
  153. //that._lockToolbar();
  154. }},
  155. onSuccess: function (xhr) {{
  156. container.outerHTML = xhr.responseText;
  157. that._execScripts();
  158. }},
  159. onError: function (xhr) {{
  160. that._placeError(xhr, body);
  161. that._deactivateSpinner();
  162. }},
  163. onFinally: function () {{
  164. //that._unlockToolbar();
  165. }}
  166. }});
  167. }},
  168. {SILENT_RELOAD}: function (params, form) {{
  169. var that = this;
  170. var body = this._findBody();
  171. var container = this._findContainer();
  172. this._fetch({{
  173. method: 'POST',
  174. url: '{template_ROUTE_BASE_PATH}/preview.getReport?reportId={ID}&renderBody=yes' + (params || ''),
  175. form: form,
  176. onSuccess: function (xhr) {{
  177. container.outerHTML = xhr.responseText;
  178. that._execScripts();
  179. }},
  180. onError: function (xhr) {{
  181. that._placeError(xhr, body);
  182. }},
  183. }});
  184. }},
  185. {DIALOG}: function (params, form) {{
  186. this._fetch({{
  187. method: 'POST',
  188. url: '{template_ROUTE_BASE_PATH}/dialog?reportId={ID}' + (params || ''),
  189. form: form
  190. }});
  191. }},
  192. showEmailExportModal: function() {{
  193. var modalcontainer = this._findModalContainer();
  194. const emailExportLink = document.getElementById('emailexport');
  195. const buttons = document.querySelectorAll('.fr-webreport-settings-btn');
  196. const Overlay = document.querySelector('.modalcontainer-overlay');
  197. var that = this;
  198. this._fetch({{
  199. method: 'POST',
  200. url: '{template_ROUTE_BASE_PATH}/exportsettings.getSettings?reportId={ID}&format=email',
  201. onSuccess: function (xhr) {{
  202. modalcontainer.innerHTML = xhr.responseText;
  203. that._execModalScripts();
  204. document.querySelector(`[data-target=email]`).classList.add('modalcontainer--visible');
  205. Overlay.classList.add('modalcontainer-overlay--visible');
  206. }},
  207. }})
  208. }},
  209. showPopup: function (message, isSuccess) {{
  210. var popup = document.createElement(""div"");
  211. popup.className = ""fr-notification"";
  212. if (isSuccess) {{
  213. popup.classList.add(""positive"");
  214. }} else {{
  215. popup.classList.add(""negative"");
  216. }}
  217. var content = document.createElement(""div"");
  218. content.className = ""fr-notification-content"";
  219. var image = document.createElement(""img"");
  220. image.src = ""/_fr/resources.getResource?resourceName=notification-bell.svg&contentType=image%2Fsvg%2Bxml"";
  221. var text = document.createElement(""div"");
  222. text.innerText = message;
  223. content.appendChild(image);
  224. content.appendChild(text);
  225. popup.appendChild(content);
  226. document.body.appendChild(popup);
  227. setTimeout(function () {{
  228. popup.style.opacity = ""0"";
  229. setTimeout(function () {{
  230. popup.remove();
  231. }}, 500);
  232. }}, 2000);
  233. }},
  234. getExportSettings: function () {{
  235. this._getExportSettings();
  236. }},
  237. _getExportSettings: function (params, form) {{
  238. var modalcontainer = this._findModalContainer();
  239. const buttons = document.querySelectorAll('.fr-webreport-settings-btn');
  240. const Overlay = document.querySelector('.modalcontainer-overlay');
  241. var fileformat;
  242. var that = this;
  243. buttons.forEach((el) => {{
  244. el.addEventListener('click', (e) => {{
  245. fileformat = e.currentTarget.getAttribute('data-path');
  246. this._fetch({{
  247. method: 'POST',
  248. url: '{template_ROUTE_BASE_PATH}/exportsettings.getSettings?reportId={ID}&format='+ fileformat + (params || ''),
  249. form: form,
  250. onSuccess: function (xhr) {{
  251. modalcontainer.innerHTML = xhr.responseText;
  252. that._execModalScripts();
  253. document.querySelector(`[data-target=${{fileformat}}]`).classList.add('modalcontainer--visible');
  254. Overlay.classList.add('modalcontainer-overlay--visible');
  255. }},
  256. }});
  257. }})
  258. }});
  259. }},
  260. _execScripts: function () {{
  261. var container = this._findContainer();
  262. var scripts = container.getElementsByTagName('script');
  263. for (var i = 0; i < scripts.length; i++) {{
  264. eval(scripts[i].text);
  265. }}
  266. }},
  267. _execModalScripts: function() {{
  268. var includeContainer = this._findModalContainer();
  269. var scripts = includeContainer.getElementsByTagName('script');
  270. for(var i = 0; i<scripts.length; i++) {{
  271. var script = document.createElement('script');
  272. if(scripts[i].text) {{
  273. script.text = scripts[i].text;
  274. }} else {{
  275. for(var j = 0; j<scripts[i].attributes.length; j++) {{
  276. if(scripts[i].attributes[j].name in HTMLScriptElement.prototype) {{
  277. script[scripts[i].attributes[j].name] = scripts[i].attributes[j].value;
  278. }}
  279. }}
  280. }}
  281. scripts[i].parentNode.replaceChild(script, scripts[i]);
  282. }}
  283. }},
  284. _placeError: function (xhr, body) {{
  285. //var iframe = document.createElement('iframe');
  286. //iframe.src = 'data:text/html;charset=utf-8,' + escape(xhr.responseText);
  287. //body.innerHTML = '<div class=""{template_FR}-error-container""><div class=""{template_FR}-error"">Error<br>' + xhr.status + ' - ' + xhr.statusText + '</div>' + iframe.outerHTML + '</div>';
  288. body.innerHTML = '<div class=""{template_FR}-error-container""><div class=""{template_FR}-error-text"">Error<br>' + xhr.status + ' - ' + xhr.statusText + '</div><div class=""{template_FR}-error-response"">' + xhr.responseText + '</div></div>';
  289. }},
  290. _activateSpinner: function () {{
  291. document.getElementsByClassName('{template_FR}-spinner')[0].style.display = '';
  292. }},
  293. _deactivateSpinner: function () {{
  294. document.getElementsByClassName('{template_FR}-spinner')[0].style.display = 'none';
  295. }},
  296. _findContainer: function () {{
  297. return document.getElementsByClassName('{template_FR}-container')[0];
  298. }},
  299. _findModalContainer: function () {{
  300. return document.getElementsByClassName('content-modalcontainer')[0];
  301. }},
  302. /*
  303. _findToolbar: function () {{
  304. return document.getElementsByClassName('{template_FR}-toolbar')[0];
  305. }},
  306. */
  307. _findBody: function () {{
  308. return document.getElementsByClassName('{template_FR}-body')[0];
  309. }},
  310. _closeDropdowns: function () {{
  311. var dropdowns = document.getElementsByClassName('{template_FR}-dropdown-content');
  312. var func = function (dd) {{
  313. setTimeout(function () {{
  314. dd.style['display'] = '';
  315. }}, 100);
  316. }}
  317. for (var i = 0; i < dropdowns.length; i++) {{
  318. var dd = dropdowns[i];
  319. dd.style['display'] = 'none';
  320. func(dd);
  321. }}
  322. }},
  323. /*
  324. _lockToolbar: function () {{
  325. var toolbar = this._findToolbar();
  326. if (toolbar) {{
  327. toolbar.style['pointer-events'] = 'none';
  328. }}
  329. }},
  330. _unlockToolbar: function () {{
  331. var toolbar = this._findToolbar();
  332. if (toolbar) {{
  333. toolbar.style['pointer-events'] = '';
  334. }}
  335. }},
  336. */
  337. _fetchQueue: [],
  338. _fetch: function (options) {{
  339. var method = options.method;
  340. var url = options.url;
  341. var form = options.form;
  342. var onSuccess = options.onSuccess;
  343. var onError = options.onError;
  344. var onSend = options.onSend;
  345. var onFinally = options.onFinally;
  346. var that = this;
  347. var xhr = new XMLHttpRequest();
  348. xhr.__form = form;
  349. xhr.__onSend = onSend;
  350. xhr.open(method, url, true);
  351. xhr.onreadystatechange = function () {{
  352. if (xhr.readyState != 4)
  353. return;
  354. if (xhr.status != 200) {{
  355. if (typeof onError === 'function') {{
  356. onError(xhr);
  357. }}
  358. }} else {{
  359. if (typeof onSuccess === 'function') {{
  360. onSuccess(xhr);
  361. }}
  362. }}
  363. if (typeof onFinally === 'function') {{
  364. onFinally(xhr);
  365. }}
  366. that._nextFetch();
  367. }};
  368. this._fetchQueue.push(xhr);
  369. if (this._fetchQueue.length == 1) {{
  370. var f = this._fetchQueue[0];
  371. if (typeof f.__onSend === 'function') {{
  372. f.__onSend(f);
  373. }}
  374. f.send(f.__form);
  375. }}
  376. }},
  377. _nextFetch: function () {{
  378. this._fetchQueue.shift();
  379. if (this._fetchQueue.length) {{
  380. var f = this._fetchQueue[0];
  381. if (typeof f.__onSend === 'function') {{
  382. f.__onSend(f);
  383. }}
  384. f.send(f.__form);
  385. }}
  386. }},
  387. _popup: function (url, title, w, h) {{
  388. // Fixes dual-screen position Most browsers Firefox
  389. var dualScreenLeft = window.screenLeft != undefined ? window.screenLeft : window.screenX;
  390. var dualScreenTop = window.screenTop != undefined ? window.screenTop : window.screenY;
  391. var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
  392. var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
  393. var left = ((width / 2) - (w / 2)) + dualScreenLeft;
  394. var top = ((height / 2) - (h / 2)) + dualScreenTop;
  395. var params = 'menubar=0, toolbar=0, location=0, status=0, resizable=1, scrollbars=1';
  396. var newWindow = window.open(url, title, params + ', width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
  397. if (newWindow.focus) {{
  398. newWindow.focus();
  399. }}
  400. return newWindow;
  401. }}
  402. }};
  403. ";
  404. }
  405. }