ext-foreignobject.js 7.1 KB

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