我如何有意义地对changeAttributes做出反应:从WebView传递委托?

时间:2010-12-10 16:56:52

标签: cocoa fonts webkit

WebView通过WebEditingDelegate支持委托机制为WebView(或私有WebHTMLView)收到的各种操作实现自定义行为的机制。当一个动作,如:

-(void)changeAttributes:(id)sender

WebHTMLView中收到,它将传递给委托方法:

-(BOOL)webView:(WebView *)webView doCommandBySelector:(SEL)command

不幸的是,该机制不提供原始行动方法中“sender”的传达。

对于绝大多数操作,发件人并不重要,但是对于changeAttributes和changeFont,例如,合同要求收件人调用“sender”以便例如convertAttributes:convertFont:

对于changeFont案例,事实证明,调用[[NSFontManager sharedFontManager] convertFont:]就足够了,因为巧合的是这就是发件人。

changeAttributes案例中,特别是当删除线被更改时,发件人可能是私人类“NSFontEffectsBox”,可能对应于负责更改删除线/的字体面板的子部分等设置。

不幸的是,调用[[NSFontManager sharedFontManager] convertAttributes:]无法获得预期的属性更改。这使得有兴趣有意义地实现这种方法的代表有点困惑:

  1. WebKit不传达发件人,因此代表无法进行合同[sender convertAttributes:]来电。

  2. changeAttributes:调用被发送到私有WebKit类WebHTMLView,该类不能被子类化,例如,自定义changeAttributes:的行为。

    < / LI>
  3. changeAttributes:来电的发件人NSFontEffectsBox是私人类,无法访问,例如为[NSFontEffectsBox sharedFontEffectsBox]

  4. 简而言之:开发人员似乎没有办法有意义地覆盖changeAttributes:的{​​{1}}行为。

    有什么想法吗?

2 个答案:

答案 0 :(得分:4)

这是一个邪恶的。适当的邪恶行为(他们都不特别干净或理想)将是:

  1. 做一些内联汇编程序来查看堆栈以从调用者的堆栈(或调用者的调用者,视情况应该)读取sender参数。当然,这假定发件人被放置在堆栈上,而不是在%eax调用WebHTMLView时。这将始终适用于PowerPC代码,因此它很可能是非启动器。

  2. 使用名为WebHTMLView的方法在__my_evil_hacky_nasty_ugly_changeAttributes_thing:上放置一个类别,并在运行时使用ObjC运行时的method_exchangeImplementations()来交换类别的实现。您的方法变为changeAttributes:,他们的方法变为__my_evil_hacky_nasty_ugly_changeAttributes_thing:,您可以调用它来传递原始呼叫。

  3. 正如我所说,两者都不是特别理想,但第二个具有完全运行时支持的优势(即运行时明确设计为允许您这样做),并且因为您在运行时查找类和方法,它是容忍失败的。在这种情况下失败会让你回到原点。

    确实需要针对WebKit记录一个错误,让它们传递给发件人以使其有意义。您重写的版本可能会查找方法-(BOOL)webView:(WebView*)webView doCommandBySelector:(SEL)selector sender:(id)sender,如果找到则调用该方法,否则只需调用原始方法。这就是Apple的代码应该做的事情,TBH。

答案 1 :(得分:3)

你看过源代码了吗?

WebHTMLView.mm

我没有看到-changeAttributes:如何调用-webView:doCommandBySelector:,因为在此类中,它仅在其自己的-doCommandBySelector:方法中调用。

- (void)changeAttributes:(id)sender
{
    [self _applyStyleToSelection:[self _styleForAttributeChange:sender] withUndoAction:EditActionChangeAttributes];
}


- (void)doCommandBySelector:(SEL)aSelector
{
…
    if (![[webView _editingDelegateForwarder] webView:webView doCommandBySelector:aSelector] && coreFrame) {
…
}

另外,为什么不能将WebHTMLView子类化?是因为Mac App Store对API的限制吗? WebKit是否算作私有?我以为是开源。

-Wil