Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

support SVG templates #6778

Closed
sussh opened this issue Mar 20, 2014 · 14 comments
Closed

support SVG templates #6778

sussh opened this issue Mar 20, 2014 · 14 comments

Comments

@sussh
Copy link

sussh commented Mar 20, 2014

bower.json

{
  "name": "angular",
  "version": "1.2.14",
  "main": "./angular.js",
  "dependencies": {
  }
}
# HG changeset patch
# User Zugr <[email protected]>
# Date 1395340922 -7200
#      Thu Mar 20 20:42:02 2014 +0200
#
# Node ID 5ecaba4e38c688524d0a348ff678c240c05d2d73
# Parent  cb5f47358b3d1f33c7edf8ce744eeb2c55f9aa4a
корректировка angular.js с целью исправления обработки svg элементов в шаблонах

diff --git a/www/js/components/angular/angular.js b/www/js/components/angular/angular.js
--- a/www/js/components/angular/angular.js
+++ b/www/js/components/angular/angular.js
@@ -6022,8 +6022,11 @@

           if (directive.replace) {
             replaceDirective = directive;
-            $template = directiveTemplateContents(directiveValue);
-            compileNode = $template[0];
+            $template = ('ownerSVGElement' in $compileNode[0] ?
+               makeSvgElement(trim(directiveValue), $compileNode[0].ownerDocument) :
+               directiveTemplateContents(directiveValue));
+
+          compileNode = $template[0];

             if ($template.length != 1 || compileNode.nodeType !== 1) {
               throw $compileMinErr('tplrt',
@@ -6467,7 +6470,9 @@
           content = denormalizeTemplate(content);

           if (origAsyncDirective.replace) {
-            $template = directiveTemplateContents(content);
+            $template = ('ownerSVGElement' in $compileNode[0] ?
+                makeSvgElement(trim(content), $compileNode[0].ownerDocument) :
+                directiveTemplateContents(content));
             compileNode = $template[0];

             if ($template.length != 1 || compileNode.nodeType !== 1) {
@@ -21050,4 +21055,26 @@

 })(window, document);

-!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style>');
\ No newline at end of file
+!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style>');
+
+function makeSvgElement(xhtml, ownerDocument)
+   { return angular.element('<svg>' + xhtml + '</svg>').contents(); }
+
+// Inspiration for this derived from a shim known as "innerSVG" which adds "innerHTML" attribute to SVGElement:
+// http://stackoverflow.com/questions/9723422/is-there-some-innerhtml-replacement-in-svg-xml
+Object.defineProperty(SVGElement.prototype, 'innerHTML', {
+   get: function ()
+       {}, // TBD!
+   set: function (markup)
+       {
+       // 1. Remove all children
+       while (this.firstChild)
+           { this.firstChild.parentNode.removeChild(this.firstChild); }
+       // 2. Make the SVG Node
+       var contents = makeSvgElement(markup, this.ownerDocument)[0].childNodes;
+       // 3. Append the childNodes to this node
+       while (contents.length)
+           { this.appendChild(contents[0]); }
+       },
+   enumerable: false,
+   configurable: true});
@caitp
Copy link
Contributor

caitp commented Mar 20, 2014

you created this patch with mercurial? scratches head.

Anyways, if I'm understanding this correctly, you're wanting to support SVG templates. What is the reason for the SVGElement wrapper? I'm not sure that's something that is needed.

In any case, if a template contains SVG markup, but no parent <svg> element, then the elements are just created as HTML elements, and won't contain ownerSVGElement anyways. So detecting them is actually very hard.

In any case, you should clone the actual angular repository and author these changes using git, and submit a pull request. This way, if it's easier to review, and you'll actually end up in the change history of the repository.

@sussh
Copy link
Author

sussh commented Mar 20, 2014

Object.defineProperty (SVGElement.prototype, 'innerHTML', {
    set: function (markup) ...
recursively peresozdayt HTML elements replacing them with SVG nodes

'ownerSVGElement' in $ compileNode [0] is very fast

I use svg templates in my project. This is analogous  MS Visio.

@sussh
Copy link
Author

sussh commented Mar 20, 2014

yes mercurial

@sussh
Copy link
Author

sussh commented Mar 20, 2014

function directiveTemplateContents () to do the same with the table context

@caitp
Copy link
Contributor

caitp commented Mar 20, 2014

It's not the performance that's the issue, the issue is, if I have a template like this:

<g>
  <text>Hello, world</text>
</g>

Those nodes will not automatically become SVGGElement and SVGTextElement, they won't adhere to the SVGElement interface, and will never have ownerSVGElement. This is because they are not instantiated with document.createElementNS and the SVG namespace, just document.createElement.

If the template does actually contain a parent <svg> node, then all child nodes will have the correct namespace, and not need to be wrapped, in which case there's nothing to worry about.

We could extend the directive API to add an optional namespace property or something, but it seems a bit late in the game for this, so I'm not sure this is the right thing to do.

@caitp
Copy link
Contributor

caitp commented Mar 20, 2014

And yes, I wrote the function to support table elements, but the thing with table elements is that they can be detected by regular expressions, because their names are not shared in MathML or SVG or other XML dialects fused into HTML5. But with SVG, you have a lot more element names to deal with, and some of them overlap with regular HTML, creating ambiguities (like <a>)

Believe me, I would love to support arbitrary SVG templates, but HTML5 has made this a sort of difficult thing to do.

@sussh
Copy link
Author

sussh commented Mar 20, 2014

for example
templates/editArea.html

<svg>
            <g class="element-pane no-user-select gluck-hide">
                <rect class="origin-selection-rect" x="0" y="0" height="100%" width="100%" style="fill:white;fill-opacity: 0;" ng-mousedown="onMouseDown($event)"></rect>
                <g ng-repeat="element in elements">
                    <block element="element"/>
                </g>
                <rect class="drag-selection-rect" x="0" y="0" height="0" width="0"></rect>
                <g ng-repeat="gluck in glucks | orderBy:'range'" gluck="gluck"></g>
            </g>
</svg>

templates/block.html

<g id="{{obj.id}}">
    <path class="source" d="{{obj.sourcePath.toString()}}"/>
    <defs ng-if="obj.textPath">
        <path id="textPath_{{obj.id}}" d="obj.textPath"/>
    </defs>
    <text>
        <textPath xlink:href="#textPath">Text on a Path</textPath>
    </text>
    <g ng-transclude></g>
    <!--<path ng-repeat="(key, resizer) in obj.dragResizers" class="drag-points" d="{{resizer.path.toString()}}"/>-->
    <path ng-if="obj.drawResizersPath" class="draw-resizers" d="{{obj.drawResizersPath.toString()}}" style="marker:url(#connector)"/>
    <path ng-if="obj.dragPointsPath" class="drag-points" d="{{obj.dragPointsPath.toString()}}" style="marker:url(#connector)"/>
</g>

@sussh
Copy link
Author

sussh commented Mar 20, 2014

basiс angular.js block replaced HTML nodes. After this patch block replaced SVG nodes. In both embodiments innerHTML equal

@caitp
Copy link
Contributor

caitp commented Mar 20, 2014

I don't think so, but I'll see what people think about it.

@caitp
Copy link
Contributor

caitp commented Mar 20, 2014

Yeah, you're right, looking at it again you're checking the parent node, so if it's inserted into an SVG, it should be svg-ified. That works.

I still don't think we want the innerHTML shim, though. This can be implemented better. In Mozilla's implementation (at least, as documented on mdn), SVGElements already have a perfectly valid innerHTML, but no innerSVG --- This has been shown to be true in a fiddle, and this also works in Chrome. However, it does not work in Safari 7, and possibly has problems in IE.

@petebacondarwin
Copy link
Contributor

@sussh - I would suggest that this idea needs to be presented as a GitHub Pull Request with associated tests so that we can confirm how well it works across the browsers that we support

@caitp
Copy link
Contributor

caitp commented Mar 20, 2014

Yep, pete is right on the money there. If you want help I can pair with you to fix this up and test it

@btford btford added this to the Backlog milestone Mar 25, 2014
@btford btford changed the title svg & angualr.js support SVG templates Mar 25, 2014
@btford btford removed the gh: issue label Aug 20, 2014
@caitp
Copy link
Contributor

caitp commented Sep 18, 2014

I believe this is more or less fixed, is it not?

@caitp
Copy link
Contributor

caitp commented Sep 18, 2014

Please re-open if there are still issues relating to this with 1.3

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants