【问题标题】:Dart Removing disallowed attribute after editor upgraded编辑器升级后 Dart 删除不允许的属性
【发布时间】:2013-09-22 22:04:24
【问题描述】:

我在 SDK 0.7.3.1_r27487 中升级我的飞镖编辑器后遇到错误“删除不允许的属性”。

我有一个自定义标签,其模板包含 boostarp 属性“data-target”和“data-toggle”。以前版本可以用,升级后报错。

控制台

Removing disallowed attribute <A data-toggle="dropdown">
Removing disallowed attribute <BUTTON data-target=".navbar-collapse">
Removing disallowed attribute <BUTTON data-toggle="collapse">

.html 代码

<element extends="div" name="x-navbar" constructor="Navbar">
<template>    
  ..
  <a name="top" href="#" class="dropdown-toggle" data-toggle="dropdown">Shop <b class="caret"></b></a>
  ..
  <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"></button>
</template>
<script type="application/dart" src="custom_ui.dart"></script> 
</element>

【问题讨论】:

  • Roger,代码是否仍按预期执行?我偶尔也会看到这样的消息(甚至在最新的编辑器版本之前就有),但我的 Polymer 应用程序仍然可以正常工作。

标签: dart dart-html


【解决方案1】:

您可能正在使用Element.innerHtml。你应该改用Element.setInnerHtml

正如您在这个新方法的参数中看到的那样,HTML 代码现在已经过验证和过滤。要恢复旧行为,您必须提供允许所有属性的验证器或树清理器。

明确允许锚点和按钮上的“数据”:

// Call NodeValidatorBuilder.allowX() methods to customize the validator.

final NodeValidatorBuilder _htmlValidator=new NodeValidatorBuilder.common()
  ..allowElement('a', attributes: ['data-target', 'data-toggle'])
  ..allowElement('button', attributes: ['data-target', 'data-toggle']);

query('#anElement').setInnerHtml('a content', validator: _htmlValidator);

ElementCustomElement 类在多个地方使用 HTML 清理(Element.html 工厂、innerHtml 属性、createFragment 方法...)。

即使您不直接在自己的代码中使用这些方法,它们也会被底层的 Dart 库调用(CustomElement 类是为 Polymer 库创建的,但也被最新版本的 Web UI 使用图书馆)。

目前,无法全局禁用或自定义默认清理规则。所以我想你将不得不处理setInnerHtml 调用...或等待另一个 SDK 版本来解决这个问题(“data-”属性是有效的 HTML5 代码,但默认的清理过滤器也不允许它们)作为内联样式:为什么这些属性被认为是不安全的?)。

注意:您应该将switching from Web UI to Polymer 视为Web UI is now deprecated

【讨论】:

  • CedX,感谢您的回复,但我没有使用 Element.innerHtml。我将所有代码放在 .html 中的
【解决方案2】:

对于那些使用 angular dart 的人,您必须使用自定义验证重新实现 NgDirective,如下所示:

library ng_bind_html_unsafe;

import 'dart:html' as dom;
import 'package:angular/angular.dart';

@NgDirective(
    selector: '[ng-bind-html-unsafe]',
    map: const {'ng-bind-html-unsafe': '=>value'}    )
class NgBindHtmlUnsafeDirective{
  final dom.Element element;

  NgBindHtmlUnsafeDirective(this.element);

  set value(value) => element.setInnerHtml(value == null ? '' : value.toString(),
                                             validator: new dom.NodeValidatorBuilder()
                                             ..allowHtml5()
                                             ..allowElement('a', attributes: ['href'])
                                             ..allowElement('img', attributes: ['src']));
}

在该特定示例中,我允许链接和图片不经过任何清理,您可以随意扩展它。

【讨论】:

  • 找不到NgDirective 类。它位于哪里?
【解决方案3】:

在 Angular 0.9.9 ng-bind-html 中支持自定义 NodeValidators。

只需注册一个返回自定义NodeValidator 的工厂,如其他答案所示

factory(NodeValidator, (Injector inj) => getNodeValidator());

ng-bind-html 将使用这个 NodeValidator。

我发现以这种方式包含的 HTML 没有被 Angular 处理(任何指令/组件/表达式都会被忽略)。

当我需要这个时,我会使用自定义的 bind-html 指令,如 @mabounassif 所示,在 value 设置器中 element.setInnerHtml 之后添加此附加代码

if(value != null) {
  _compiler(_element.childNodes, _directiveMap)(_injector, _element.childNodes);
}

另见https://github.com/angular/angular.dart/issues/742

【讨论】:

    【解决方案4】:

    @mabounassifanswer 为目标,我还做了以下操作以允许链接到其他网站:

    import 'dart:html' as dom;
    import 'package:angular/angular.dart';
    
    @Directive(selector: '[html-inseguro]')
    class HtmlInseguro {
      final dom.Element element;
    
      final dom.NodeValidatorBuilder _validador;
    
      HtmlInseguro(this.element)
          : _validador = dom.NodeValidatorBuilder()
              ..allowHtml5()
              ..allowElement('a', attributes: ['href'], uriPolicy: _TodoUriPolicy())
              ..allowElement('img',
                  attributes: ['src'], uriPolicy: _TodoUriPolicy());
    
      @Input('html-inseguro')
      set htmlInseguro(String value) {
        element.setInnerHtml(value?.toString() ?? '', validator: _validador);
      }
    }
    
    class _TodoUriPolicy implements dom.UriPolicy {
      @override
      bool allowsUri(String uri) {
        return true;
      }
    }
    

    那么在组件中你应该有这样的东西:

    @Component(
      template: '''
    <div class="vista-previa-mensaje" [html-inseguro]="mensajeAEnviar | dataReplacer: reemplazos | md2html"></div>
    ''',
      directives: [
        HtmlInseguro,
      ],
      pipes: [Md2Html, DataReplacer])
    class YourComponent{
      //...
    

    【讨论】:

      【解决方案5】:

      我想将img 元素与innerHtml 一起使用,发现上面的答案不完整。它缺少默认为同一来源的uriPolicy。定义自定义 UriPolicy 为我解决了这个问题。

      class DefaultUriPolicy implements UriPolicy {
        DefaultUriPolicy();
      
        bool allowsUri(String uri) {
          // Return true/false based on uri comparison
          return true;
        }
      }
      

      如下定义验证器:

      allowElement('img',
                    attributes: ['src'], uriPolicy: new DefaultUriPolicy()))
      

      【讨论】:

        【解决方案6】:

        对于任何想要使用setInnerHtml 并希望允许所有标签和属性的人,您可以使用这个验证器:

        class AllowAll implements NodeValidator {
            @override
            bool allowsAttribute(Element element, String attributeName, String value) {
               return true;
            }
        
            @override
            bool allowsElement(Element element) {
              return true;
            }
        }
        

        用法:

        element.setInnerHtml(
            value,
            validator: AllowAll()
        );
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-26
          • 1970-01-01
          • 2020-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多