writer.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. import * as Models from "../ivprog_elements";
  2. import { LocalizedStrings } from "../../services/localizedStringsService";
  3. import * as VariableValueMenu from "./variable_value_menu";
  4. import * as VariableValueMenuManagement from "./variable_value_menu";
  5. import * as CommandsManagement from "../commands";
  6. import * as GenericExpressionManagement from "./generic_expression";
  7. import * as CodeGenerator from '../code_generator';
  8. export function createFloatingCommand () {
  9. return $(
  10. '<div class="ui writer created_element"> <i class="ui icon small upload"></i> <span> ' +
  11. LocalizedStrings.getUI("text_command_write") +
  12. " var </span></div>"
  13. );
  14. }
  15. export function renderCommand (command, function_obj) {
  16. const ret = `<div class="ui writer command_container">
  17. <i class="ui icon small upload command_drag"></i>
  18. <i class="ui icon times red button_remove_command"></i>
  19. <span class="span_command_spec">${LocalizedStrings.getUI(
  20. "text_command_write"
  21. )}
  22. ( </span><div class="all_elements_write"></div> <span class="textual_expression"></span>
  23. <span class="close_parentheses span_command_spec">)</span>
  24. <img data-state="${command.newline ? "on" : "false"}" src="${
  25. command.newline ? "img/new_line.svg" : "img/no_new_line.svg"
  26. }" class="ivprog_newline_btn"/>
  27. <i class="ui icon i cursor button_write_expression" style="margin-left: 3rem !important; margin-right: -1.1rem !important;"></i>
  28. <i class="ui icon unlock button_alternate_expression"></i>
  29. </div>`;
  30. const el = $(ret);
  31. el.data("command", command);
  32. //renderExpression (command, function_obj, div_to_render, expression_array)
  33. GenericExpressionManagement.renderExpression(
  34. command,
  35. function_obj,
  36. el.find(".all_elements_write"),
  37. command.content
  38. );
  39. addHandlers(command, function_obj, el);
  40. if (command.content && command.lockexpression) {
  41. try {
  42. var text = CodeGenerator.elementExpressionCode(command.content);
  43. if (text) {
  44. $(el.find('.all_elements_write')[0]).toggle();
  45. $(el.find('.textual_expression')[0]).text(text);
  46. $(el.find('.textual_expression')[0]).toggle();
  47. $(el.find('.button_alternate_expression')[0]).toggleClass('unlock').toggleClass('lock');
  48. }
  49. } catch (e) {
  50. command.lockexpression = false;
  51. }
  52. }
  53. el.find('.unlock').popup({
  54. content : LocalizedStrings.getUI("text_lock_expression"),
  55. delay: {
  56. show: 750,
  57. hide: 0
  58. }
  59. });
  60. el.find('.lock').popup({
  61. content : LocalizedStrings.getUI("text_unlock_expression"),
  62. delay: {
  63. show: 750,
  64. hide: 0
  65. }
  66. });
  67. el.find('.button_write_expression').popup({
  68. content : LocalizedStrings.getUI("text_edit_expression"),
  69. delay: {
  70. show: 750,
  71. hide: 0
  72. }
  73. });
  74. return el;
  75. }
  76. function addHandlersManager (
  77. command,
  78. _function_obj,
  79. _writer_dom,
  80. item_div,
  81. content_element
  82. ) {
  83. item_div.find(".times").on("click", function () {
  84. for (let i = 0; i < command.content.length; i++) {
  85. if (command.content[i] == content_element) {
  86. delete command.content[i];
  87. command.content.splice(i, 1);
  88. item_div.children().off();
  89. item_div.off();
  90. item_div.fadeOut();
  91. if (command.content.length > 0) {
  92. item_div.next(".icon_add_item_to_writer").fadeOut();
  93. }
  94. break;
  95. }
  96. }
  97. });
  98. }
  99. function addHandlers (command, function_obj, writer_dom) {
  100. $(writer_dom.find('.textual_expression')[0]).toggle();
  101. writer_dom.find('.button_write_expression').on('click', function() {
  102. window.expressionEdition = true;
  103. window.inputExpression = null;
  104. var afterWhichElement;
  105. var lockButton = $(writer_dom.find('.button_alternate_expression')[0]);
  106. var editButton = $(this);
  107. afterWhichElement = writer_dom.find('.all_elements_write');
  108. if (command.lockexpression) {
  109. afterWhichElement = writer_dom.find('.textual_expression');
  110. }
  111. var text = "";
  112. if (command.content) {
  113. if (command.content.length == 1 && command.content[0].content == null && !command.content[0].function_called) {
  114. text = "";
  115. } else {
  116. try {
  117. text = CodeGenerator.elementExpressionCode(command.content);
  118. } catch(ex) {
  119. text = "";
  120. }
  121. }
  122. }
  123. var ok_button = $('<i class="ui icon check circle expression-edit-confirm"></i>');
  124. var cancel_button = $('<i class="ui icon undo expression-edit-cancel"></i>');
  125. var input = $('<input type="text" spellcheck="false" autocomplete="off" class="input-expression-field" >');
  126. input.val(text);
  127. input.focusout(function(evt) {
  128. ok_button.click();
  129. evt.preventDefault();
  130. return true;
  131. });
  132. input.keyup(function(evt) {
  133. if (evt.keyCode == 27) { // esc
  134. cancel_button.click();
  135. }
  136. if (evt.keyCode == 13) { // enter
  137. ok_button.click();
  138. }
  139. });
  140. ok_button.click(function() {
  141. var parsed = null;
  142. parsed = GenericExpressionManagement.expressionParserToVisual(input.val(), function_obj, input);
  143. if (parsed) {
  144. window.expressionEdition = false;
  145. command.content = parsed;
  146. renderAlgorithm();
  147. }
  148. });
  149. cancel_button.mousedown(function(evt) {
  150. var parsed = GenericExpressionManagement.expressionParserToVisual(text, function_obj, input);
  151. if (parsed) {
  152. window.expressionEdition = false;
  153. command.content = parsed;
  154. renderAlgorithm();
  155. }
  156. });
  157. input.insertAfter(afterWhichElement);
  158. input.focus();
  159. cancel_button.insertAfter(input);
  160. ok_button.insertAfter(input);
  161. var len = text.length;
  162. input[0].setSelectionRange(len, len);
  163. afterWhichElement.css('display', 'none');
  164. lockButton.css('display', 'none');
  165. editButton.css('display', 'none');
  166. ok_button.popup({
  167. content : LocalizedStrings.getUI("text_edit_expression_confirm"),
  168. delay: {
  169. show: 750,
  170. hide: 0
  171. }
  172. });
  173. cancel_button.popup({
  174. content : LocalizedStrings.getUI("text_edit_expression_cancel"),
  175. delay: {
  176. show: 750,
  177. hide: 0
  178. }
  179. });
  180. });
  181. writer_dom.find('.button_alternate_expression').on('click', function() {
  182. if (command.content) {
  183. var text = CodeGenerator.elementExpressionCode(command.content);
  184. if (text) {
  185. $(writer_dom.find('.all_elements_write')[0]).toggle();
  186. $(writer_dom.find('.textual_expression')[0]).text(text);
  187. $(writer_dom.find('.textual_expression')[0]).toggle();
  188. $(this).toggleClass('unlock').toggleClass('lock');
  189. command.lockexpression = !command.lockexpression;
  190. }
  191. if (command.lockexpression) {
  192. writer_dom.find('.lock').popup({
  193. content : LocalizedStrings.getUI("text_unlock_expression"),
  194. delay: {
  195. show: 750,
  196. hide: 0
  197. }
  198. });
  199. } else {
  200. writer_dom.find('.unlock').popup({
  201. content : LocalizedStrings.getUI("text_lock_expression"),
  202. delay: {
  203. show: 750,
  204. hide: 0
  205. }
  206. });
  207. }
  208. }
  209. });
  210. writer_dom.find(".button_remove_command").on("click", function () {
  211. if (CommandsManagement.removeCommand(command, function_obj, writer_dom)) {
  212. writer_dom.fadeOut(400, function () {
  213. writer_dom.remove();
  214. });
  215. }
  216. });
  217. Sortable.create(writer_dom.find(".all_elements_write")[0], {
  218. handle: ".ellipsis",
  219. animation: 100,
  220. ghostClass: "ghost",
  221. group: "writer_" + Math.floor(Math.random() * 10000000),
  222. draggable: ".div_parent_handler",
  223. onEnd: function (evt) {
  224. command.content.splice(
  225. evt.newIndex,
  226. 0,
  227. command.content.splice(evt.oldIndex, 1)[0]
  228. );
  229. writer_dom.empty();
  230. writer_dom.replaceWith(renderCommand(command, function_obj));
  231. },
  232. });
  233. // Attach event handles for the newline button
  234. const newlineBtn = writer_dom.find(".ivprog_newline_btn");
  235. newlineBtn.on("click", function () {
  236. const state = this.dataset.state;
  237. if (state === "on") {
  238. this.dataset.state = "off";
  239. command.newline = false;
  240. this.setAttribute("src", "img/no_new_line.svg");
  241. } else {
  242. this.dataset.state = "on";
  243. command.newline = true;
  244. this.setAttribute("src", "img/new_line.svg");
  245. }
  246. writer_dom.data("command", command);
  247. setPopup(newlineBtn, command.newline);
  248. });
  249. // Attach jquery popup
  250. setPopup(newlineBtn, command.newline);
  251. }
  252. function setPopup (element, state) {
  253. if (element.popup("exists")) {
  254. element.popup("destroy");
  255. }
  256. const content = state
  257. ? LocalizedStrings.getUI("write_command_newline_on")
  258. : LocalizedStrings.getUI("write_command_newline_off");
  259. element.popup({
  260. content: content,
  261. delay: {
  262. show: 750,
  263. hide: 0,
  264. },
  265. });
  266. }
  267. function _addHandlerIconAdd (
  268. dom_object,
  269. command,
  270. function_obj,
  271. insert_after = false,
  272. after_which = null
  273. ) {
  274. const icon_add_item = $(
  275. '<i class="ui icon plus square outline icon_add_item_to_writer"></i> '
  276. );
  277. if (!insert_after) {
  278. dom_object.append(icon_add_item);
  279. } else {
  280. icon_add_item.insertAfter(after_which);
  281. }
  282. icon_add_item.on("click", function (_event) {
  283. const div_parent_with_handler = $(
  284. '<div class="div_parent_handler" style="display:none;"></div>'
  285. );
  286. const new_div_item = $('<div class="var_value_menu_div"></div>');
  287. div_parent_with_handler.append(
  288. $('<i class="ui icon ellipsis vertical inverted handler"></i>')
  289. );
  290. div_parent_with_handler.append(new_div_item);
  291. div_parent_with_handler.append(
  292. $('<i class="white inverted icon times handler"></i>')
  293. );
  294. div_parent_with_handler.insertAfter(icon_add_item);
  295. const new_related_menu = new Models.VariableValueMenu(
  296. VariableValueMenuManagement.VAR_OR_VALUE_TYPES.all,
  297. null,
  298. null,
  299. null,
  300. true
  301. );
  302. VariableValueMenu.renderMenu(
  303. command,
  304. new_related_menu,
  305. new_div_item,
  306. function_obj
  307. );
  308. addHandlerIconAdd(
  309. dom_object,
  310. command,
  311. function_obj,
  312. true,
  313. div_parent_with_handler
  314. );
  315. addHandlersManager(
  316. command,
  317. function_obj,
  318. dom_object,
  319. div_parent_with_handler,
  320. new_related_menu
  321. );
  322. let pos = 1;
  323. dom_object.find(".icon_add_item_to_writer").each(function () {
  324. if ($(this).get(0) === icon_add_item.get(0)) {
  325. command.content.splice(pos, 0, new_related_menu);
  326. } else {
  327. pos++;
  328. }
  329. });
  330. if (command.content.length == 1) {
  331. icon_add_item.remove();
  332. }
  333. div_parent_with_handler.fadeIn();
  334. });
  335. }
  336. export function addContent (
  337. command,
  338. _ref_object,
  339. dom_object,
  340. _menu_var_or_value,
  341. function_obj,
  342. _ref_object_content
  343. ) {
  344. if (dom_object.hasClass("var_value_menu_div")) {
  345. const icon_add_item = $(
  346. '<i class="ui icon plus square outline icon_add_item_to_writer"></i> '
  347. );
  348. icon_add_item.insertAfter(dom_object);
  349. icon_add_item.on("click", function (_event) {
  350. const div_parent_with_handler = $(
  351. '<div class="div_parent_handler"></div>'
  352. );
  353. div_parent_with_handler.append(
  354. $('<i class="ui icon ellipsis vertical inverted handler"></i>')
  355. );
  356. div_parent_with_handler.append(new_div_item);
  357. div_parent_with_handler.append(
  358. $('<i class="white inverted icon times handler"></i>')
  359. );
  360. div_parent_with_handler.insertAfter(icon_add_item);
  361. const new_related_menu = new Models.VariableValueMenu(
  362. VariableValueMenuManagement.VAR_OR_VALUE_TYPES.all,
  363. null,
  364. null,
  365. null,
  366. true
  367. );
  368. VariableValueMenu.renderMenu(
  369. command,
  370. new_related_menu,
  371. new_div_item,
  372. function_obj
  373. );
  374. addHandlersManager(
  375. command,
  376. function_obj,
  377. dom_object,
  378. div_parent_with_handler,
  379. new_related_menu
  380. );
  381. command.content.push(new_related_menu);
  382. if (command.content.length == 1) {
  383. icon_add_item.remove();
  384. }
  385. });
  386. }
  387. }