ext-foreignobject.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*globals svgEditor, svgedit, svgCanvas, $*/
  2. /*jslint vars: true, eqeq: true, todo: true*/
  3. /*
  4. * ext-foreignobject.js
  5. *
  6. * Licensed under the Apache License, Version 2
  7. *
  8. * Copyright(c) 2010 Jacques Distler
  9. * Copyright(c) 2010 Alexis Deveria
  10. *
  11. */
  12. svgEditor.addExtension("foreignObject", function(S) {
  13. var NS = svgedit.NS,
  14. Utils = svgedit.utilities,
  15. svgcontent = S.svgcontent,
  16. addElem = S.addSvgElementFromJson,
  17. selElems,
  18. editingforeign = false,
  19. svgdoc = S.svgroot.parentNode.ownerDocument,
  20. started,
  21. newFO;
  22. var properlySourceSizeTextArea = function () {
  23. // TODO: remove magic numbers here and get values from CSS
  24. var height = $('#svg_source_container').height() - 80;
  25. $('#svg_source_textarea').css('height', height);
  26. };
  27. function showPanel(on) {
  28. var fc_rules = $('#fc_rules');
  29. if(!fc_rules.length) {
  30. fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
  31. }
  32. fc_rules.text(!on?"":" #tool_topath { display: none !important; }");
  33. $('#foreignObject_panel').toggle(on);
  34. }
  35. function toggleSourceButtons(on) {
  36. $('#tool_source_save, #tool_source_cancel').toggle(!on);
  37. $('#foreign_save, #foreign_cancel').toggle(on);
  38. }
  39. // Function: setForeignString(xmlString, elt)
  40. // This function sets the content of element elt to the input XML.
  41. //
  42. // Parameters:
  43. // xmlString - The XML text.
  44. // elt - the parent element to append to
  45. //
  46. // Returns:
  47. // This function returns false if the set was unsuccessful, true otherwise.
  48. function setForeignString(xmlString) {
  49. var elt = selElems[0];
  50. try {
  51. // convert string into XML document
  52. var newDoc = Utils.text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');
  53. // run it through our sanitizer to remove anything we do not support
  54. S.sanitizeSvg(newDoc.documentElement);
  55. elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
  56. S.call("changed", [elt]);
  57. svgCanvas.clearSelection();
  58. } catch(e) {
  59. console.log(e);
  60. return false;
  61. }
  62. return true;
  63. }
  64. function showForeignEditor() {
  65. var elt = selElems[0];
  66. if (!elt || editingforeign) {return;}
  67. editingforeign = true;
  68. toggleSourceButtons(true);
  69. elt.removeAttribute('fill');
  70. var str = S.svgToString(elt, 0);
  71. $('#svg_source_textarea').val(str);
  72. $('#svg_source_editor').fadeIn();
  73. properlySourceSizeTextArea();
  74. $('#svg_source_textarea').focus();
  75. }
  76. function setAttr(attr, val) {
  77. svgCanvas.changeSelectedAttribute(attr, val);
  78. S.call("changed", selElems);
  79. }
  80. return {
  81. name: "foreignObject",
  82. svgicons: svgEditor.curConfig.extPath + "foreignobject-icons.xml",
  83. buttons: [{
  84. id: "tool_foreign",
  85. type: "mode",
  86. title: "Foreign Object Tool",
  87. events: {
  88. 'click': function() {
  89. svgCanvas.setMode('foreign');
  90. }
  91. }
  92. },{
  93. id: "edit_foreign",
  94. type: "context",
  95. panel: "foreignObject_panel",
  96. title: "Edit ForeignObject Content",
  97. events: {
  98. 'click': function() {
  99. showForeignEditor();
  100. }
  101. }
  102. }],
  103. context_tools: [{
  104. type: "input",
  105. panel: "foreignObject_panel",
  106. title: "Change foreignObject's width",
  107. id: "foreign_width",
  108. label: "w",
  109. size: 3,
  110. events: {
  111. change: function() {
  112. setAttr('width', this.value);
  113. }
  114. }
  115. },{
  116. type: "input",
  117. panel: "foreignObject_panel",
  118. title: "Change foreignObject's height",
  119. id: "foreign_height",
  120. label: "h",
  121. events: {
  122. change: function() {
  123. setAttr('height', this.value);
  124. }
  125. }
  126. }, {
  127. type: "input",
  128. panel: "foreignObject_panel",
  129. title: "Change foreignObject's font size",
  130. id: "foreign_font_size",
  131. label: "font-size",
  132. size: 2,
  133. defval: 16,
  134. events: {
  135. change: function() {
  136. setAttr('font-size', this.value);
  137. }
  138. }
  139. }
  140. ],
  141. callback: function() {
  142. $('#foreignObject_panel').hide();
  143. var endChanges = function() {
  144. $('#svg_source_editor').hide();
  145. editingforeign = false;
  146. $('#svg_source_textarea').blur();
  147. toggleSourceButtons(false);
  148. };
  149. // TODO: Needs to be done after orig icon loads
  150. setTimeout(function() {
  151. // Create source save/cancel buttons
  152. var save = $('#tool_source_save').clone()
  153. .hide().attr('id', 'foreign_save').unbind()
  154. .appendTo("#tool_source_back").click(function() {
  155. if (!editingforeign) {return;}
  156. if (!setForeignString($('#svg_source_textarea').val())) {
  157. $.confirm("Errors found. Revert to original?", function(ok) {
  158. if(!ok) {return false;}
  159. endChanges();
  160. });
  161. } else {
  162. endChanges();
  163. }
  164. // setSelectMode();
  165. });
  166. var cancel = $('#tool_source_cancel').clone()
  167. .hide().attr('id', 'foreign_cancel').unbind()
  168. .appendTo("#tool_source_back").click(function() {
  169. endChanges();
  170. });
  171. }, 3000);
  172. },
  173. mouseDown: function(opts) {
  174. var e = opts.event;
  175. if(svgCanvas.getMode() == "foreign") {
  176. started = true;
  177. newFO = S.addSvgElementFromJson({
  178. "element": "foreignObject",
  179. "attr": {
  180. "x": opts.start_x,
  181. "y": opts.start_y,
  182. "id": S.getNextId(),
  183. "font-size": 16, //cur_text.font_size,
  184. "width": "48",
  185. "height": "20",
  186. "style": "pointer-events:inherit"
  187. }
  188. });
  189. var m = svgdoc.createElementNS(NS.MATH, 'math');
  190. m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH);
  191. m.setAttribute('display', 'inline');
  192. var mi = svgdoc.createElementNS(NS.MATH, 'mi');
  193. mi.setAttribute('mathvariant', 'normal');
  194. mi.textContent = "\u03A6";
  195. var mo = svgdoc.createElementNS(NS.MATH, 'mo');
  196. mo.textContent = "\u222A";
  197. var mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
  198. mi2.textContent = "\u2133";
  199. m.appendChild(mi);
  200. m.appendChild(mo);
  201. m.appendChild(mi2);
  202. newFO.appendChild(m);
  203. return {
  204. started: true
  205. };
  206. }
  207. },
  208. mouseUp: function(opts) {
  209. var e = opts.event;
  210. if(svgCanvas.getMode() == "foreign" && started) {
  211. var attrs = $(newFO).attr(["width", "height"]);
  212. var keep = (attrs.width != 0 || attrs.height != 0);
  213. svgCanvas.addToSelection([newFO], true);
  214. return {
  215. keep: keep,
  216. element: newFO
  217. };
  218. }
  219. },
  220. selectedChanged: function(opts) {
  221. // Use this to update the current selected elements
  222. selElems = opts.elems;
  223. var i = selElems.length;
  224. while(i--) {
  225. var elem = selElems[i];
  226. if(elem && elem.tagName === 'foreignObject') {
  227. if(opts.selectedElement && !opts.multiselected) {
  228. $('#foreign_font_size').val(elem.getAttribute("font-size"));
  229. $('#foreign_width').val(elem.getAttribute("width"));
  230. $('#foreign_height').val(elem.getAttribute("height"));
  231. showPanel(true);
  232. } else {
  233. showPanel(false);
  234. }
  235. } else {
  236. showPanel(false);
  237. }
  238. }
  239. },
  240. elementChanged: function(opts) {
  241. var elem = opts.elems[0];
  242. }
  243. };
  244. });