我想知道是否可以在RichTextArea字段的iframe上添加样式表或样式规则?
我需要对默认样式进行一些CSS调整,但我无法通过我的应用程序样式表定位RichTextArea,因为它是在iframe中加载的。
答案 0 :(得分:1)
Vaadin RichTextArea 组件的“问题”不仅在于编辑器字段位于iframe
元素内,而且与所有元素一样在其他 Vaadin 组件中,您还必须记住,DOM ready
回调时(例如$(document).ready(function() {})
如果使用jQuery或回调绑定,您的组件将不可用将执行DOMContentLoaded
事件。
这是因为,正如您所知,当Vaadin应用程序启动时,您实际上还没有在DOM内部组件,但 vaadin bootstrap 进程将请求并处理渲染您的用户界面。这实际上是GWT也适用的原则(参见How does GWT provide the correct Javascript code to every browser e.g. to carry out i18n and browser compatibility?)(毕竟Vaadin基于GWT)。
所以,例如如果您使用jQuery,并且在 vaadinBootstrap.js 脚本加载并执行后立即加载了这样的脚本:
$(function() {
// this code will execute, but no components are available yet.
var rTa = $(".v-richtextarea"); // this won't select your Rich text area
var len = rTa.length // len will be 0 here, as no element matches the previous selector because as stated before, there is not an element with such a class in the DOM yet.
});
执行此代码后,创建UI组件和布局的“重”过程开始,您的widgetset和/或默认的加载,然后您就可以设置漂亮的UI并准备好与之交互用户。
为了定制现有的组件,例如RichTextArea,例如将一个样式元素添加到其iframe元素的主体中,您当然可以冒险进入GWT的深度并像在答案中一样使用JSNI,但在我看来,还有另一种方法可以实现它,更紧凑,更简单,不需要使用JSNI。
您需要做的就是在客户端为您的组件实现一个带有连接器的JavaScriptExtension
(您可以只扩展Vaadin的RichTextArea),看看这个简单的代码示例:
#!java
package com.package.example;
@JavaScript({"vaadin://js/src/rich_text_area_connector.js"})
public class RichTextAreaExtension extends AbstractJavaScriptExtension {
@Override
public void extend(AbstractClientConnector connector) {
super.extend(connector);
}
}
这是扩展,然后你需要创建客户端连接器,它基本上是一个JavaScript文件,其函数名称基于扩展名的包名,当然还有扩展名的类名:< / p>
#!javascript
com_package_example_RichTextAreaExtension = function() {
var connectorParentId = this.getParentId();
var element = this.getElement(parentId); // this is the rich text area element, which at this point is
// If you are using jQuery, then you can just select your element like so:
var jQueryElement = $(element);
// and do whatever you would normally do with the element like
// when you are inside $(document).ready(function() {});
// or you can add a style element to the head element inside the iframe, doing something like the following:
$(element).find("iframe").contents().find('head')
.append('<link rel="stylesheet" href="./VAADIN/themes/your_theme/style_for_richtextarea_body.css" type="text/css" />');
}
你完成了。另一个好处是,您可以看到,您不必为不同的浏览器(Mozilla,Chrome,IE)编写不同的代码,您只需使用jQuery,库就可以为您处理兼容性。最后一部分是扩展组件本身。正如我之前所说,你可以扩展Vaadin的RichTextArea:
public class RichTextAreaWithStyleOnBody extends RichTextArea {
public RichTextAreaWithStyleOnBody(String caption, Property<?> dataSource) {
super(caption);
if (dataSource != null)
setPropertyDataSource(dataSource);
new RichTextAreaExtension().extend(this);
}
public RichTextAreaWithStyleOnBody(String caption, Property<?> dataSource) {
this(caption, dataSource);
}
public RichTextAreaWithStyleOnBody(String caption) {
this(caption, null);
}
public RichTextAreaWithStyleOnBody(Property<?> dataSource) {
this(null, dataSource);
}
public RichTextAreaWithStyleOnBody() {
this(null, null);
}
}
请注意主构造函数中JavaScript扩展的用法。最后,您可以在布局中使用它,就像使用任何其他组件一样:
// Inside your UI's class
@Override
protected void init(VaadinRequest request) {
VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
layout.setSpacing(true);
setContent(layout);
RichTextArea rTa = new RichTextAreaWithStyleOnBody("A rich text area with a styled body");
rTa.setStyleName("myRichTextArea"); // you can do whatever you'll like on the server side just because your rich text area extends a Vaadin server side component.
rTa.setSizeFull();
layout.addComponent(rTa);
}
答案 1 :(得分:0)
据我所知,这是不可能的。我遇到了同样的问题,并根据RichTextArea的vaadin代码副本编写了一个小插件。我添加了一些其他方法来设置font-family和font-size。不幸的是,我最近没有足够的时间来清理我的代码,发布新版本的附加组件。
附加组件的主要功能是将工具栏与区域分离。 您可以在 v7 分支中找到代码:https://gitorious.org/richtexttoolbar-vaadin-addon/richtexttoolbar-vaadin-addon
答案 2 :(得分:0)
继续搜索后,我发现了这个讨论,这让我得到了一个解决方案: https://groups.google.com/forum/#!msg/Google-Web-Toolkit/9kwAJNhnamY/1MVfFFRq8tUJ
我最终包装RichTextImpl *类,从父类克隆initElement()方法,并插入这些行......
...对于Mozilla / Safari:
_this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document.designMode = 'On';
var doc = _this.@com.google.gwt.user.client.ui.impl.RichTextAreaImpl::elem.contentWindow.document;
head=doc.getElementsByTagName('head')[0];
link=document.createElement('link');
link.setAttribute('rel',"stylesheet");
link.setAttribute('href',"/path/to/richtext.css" );
link.setAttribute('type',"text/css");
head.appendChild(link);
...对于IE:
var ct = "<html><head><style>@import url('/path/to/richtext.css');</style></head><body CONTENTEDITABLE='true'></body></html>" ;
doc.write( ct );
...在我的RichTextArea字段中加载样式表。
答案 3 :(得分:0)
我有一个为我的richtextarea创建的令牌函数,并且对于在数据库中保存的令牌,只需使用我已经在我的&#34; styles.css&#34;中保存的样式类来保存它。声明。
一步一步是这样的,我正在使用样式表并查找我的令牌类,然后我在iframes标头中添加样式,以便在iframe中设置我的标记类。
function styleRichtextareaIframe(id, themeClass, tokenClass, tokenSelectedClass) {
setTimeout(function() {
// iframe by id selected
var $iframe = $("#" + id).find(".gwt-RichTextArea");
var $head = $iframe.contents().find("head");
var $body = $iframe.contents().find("body");
var classNameToken = "." + themeClass + " " + "." + tokenClass;
var classNameToken_selected = "." + themeClass + " " + "." + tokenSelectedClass;
var fontClass = "." + themeClass + ".v-app, " + "." + themeClass + " " + ".v-window";
var styleSheets = window.document.styleSheets;
var styleSheetsLength = styleSheets.length;
var style = document.createElement('style');
style.type = 'text/css';
for (var i = 0; i < styleSheetsLength; i++) {
var classes = styleSheets[i].rules || styleSheets[i].cssRules;
for (var x = 0; x < classes.length; x++) {
if (classes[x].selectorText == classNameToken) {
style.appendChild(document.createTextNode(getClassFor(classes[x])));
}
if (classes[x].selectorText == classNameToken_selected) {
style.appendChild(document.createTextNode(getClassFor(classes[x])));
}
if (classes[x].selectorText == fontClass) {
style.appendChild(document.createTextNode(getClassFor(classes[x])));
}
}
}
function getClassFor(classObj) {
if (classObj.cssText) {
return classObj.cssText;
} else {
return classObj.style.cssText;
}
}
//Adding the classes also to the body
//of dourse you can change the output string to just give you the style class that you need.
$body.addClass("v-app " + themeClass);
$head.append(style);
}, 200);
}
&#13;
由于&#34;问题&#34;我不得不插入超时功能。使用Vaadin RichTextArea组件不仅是因为编辑器字段位于iframe元素内,而且与所有其他Vaadin组件一样,您还必须记住,当DOM准备好时,您的组件将不可用, (组件不在DOM中)。
希望这对某人有所帮助,抱歉我的英语不好。
干杯。
答案 4 :(得分:0)
我想出的最简单的方法是扩展RichTextArea组件并使用JavaScript设置自定义样式:
public class MyRichTextArea extends RichTextArea {
public MyRichTextArea(String className) {
setStyleName(className);
String js = "var iframeContainer = document.getElementsByClassName('" + className + "')[0];" +
"var iframe = iframeContainer.getElementsByTagName('iframe')[0];" +
"var iframeBody = iframe.contentDocument.getElementsByTagName('body')[0];" +
"iframeBody.style.fontFamily='Arial';";
JavaScript.getCurrent().execute(js);
}
}
用法:
MyRichTextArea field = new MyRichTextArea("fieldClassName");
请注意,所有主流浏览器都应支持 iframe.contentDocument ,但为了更好的支持,应添加其他调整 - 请参阅Getting the document object of an iframe