Как я могу осмысленно реагировать на изменение ChangeAttributes: делегирование от WebView?

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 случай, в частности, когда зачеркивание изменено, отправитель может быть закрытым классомNSFontEffectsBoxmsgstr "что, по-видимому, соответствует подразделу панели шрифтов, отвечающему за изменение настроек перечеркивания и т. д.

К сожалению звоню [[NSFontManager sharedFontManager] convertAttributes:] НЕ получает ожидаемые изменения атрибута. Это оставляет делегата, который заинтересован в осмысленной реализации этого метода, немного загадкой:

  1. WebKit не передает отправителю, поэтому делегат не может заключить договор [sender convertAttributes:] вызов.

  2. changeAttributes: вызов отправляется в закрытый класс WebKit, WebHTMLView, которые не могут быть разделены на подклассы, например, чтобы настроить поведение changeAttributes:,

  3. Отправитель для changeAttributes: вызов, NSFontEffectsBox, является частным классом и недоступен, например, как [NSFontEffectsBox sharedFontEffectsBox],

Короче говоря, у разработчика, похоже, нет возможности существенно изменить поведение changeAttributes: для WebView,

Есть идеи?

2 ответа

Это злой Подходящей злой парой действий (ни одно из которых не является особенно чистым или идеальным) будет:

  1. Сделайте какой-нибудь встроенный ассемблер, чтобы посмотреть обратно в стек, чтобы прочитать аргумент отправителя из стека вызывающего (или вызывающего, в зависимости от обстоятельств). Это, конечно, предполагает, что отправитель помещается в стек, а не в %eax когда звонок WebHTMLView сделан. Это всегда будет относиться к коду PowerPC, так что, скорее всего, это не стартер.

  2. Поместите категорию на WebHTMLView с методом с именем что-то вроде __my_evil_hacky_nasty_ugly_changeAttributes_thing: и во время выполнения используйте method_exchangeImplementations() из среды выполнения ObjC, чтобы поменять реализацию вашей категории на свою. Ваш метод становится changeAttributes: и их становится __my_evil_hacky_nasty_ugly_changeAttributes_thing:, который вы можете позвонить, чтобы передать исходный вызов.

Как я уже сказал, ни один из них не является особенно идеальным, но второй обладает преимуществом полной поддержки времени выполнения (т. Е. Среда выполнения явно предназначена для того, чтобы позволить вам это сделать), и, поскольку вы просматриваете класс и методы во время выполнения, это сбой. терпимый. Однако неудача в этом случае возвращает вас на круги своя.

На самом деле ему нужна ошибка, зарегистрированная в WebKit, чтобы они передавали отправителю, чтобы сделать его вообще значимым. Ваша переопределенная версия может потенциально искать метод -(BOOL)webView:(WebView*)webView doCommandBySelector:(SEL)selector sender:(id)sender и вызовите его, если он найден, в противном случае просто вызовите исходный метод. Это то, что должен делать код Apple, TBH.

Вы смотрели на исходный код?

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

Другие вопросы по тегам