Как я могу осмысленно реагировать на изменение ChangeAttributes: делегирование от WebView? - PullRequest
8 голосов
/ 10 декабря 2010

WebView через WebEditingDelegate поддерживает механизм, позволяющий делегату реализовать пользовательское поведение для различных действий, которые получает WebView (или частное WebHTMLView).Когда в WebHTMLView получено действие, такое как:

-(void)changeAttributes:(id)sender

, оно передается методу делегата:

-(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:]call.

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

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

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

Есть идеи?

Ответы [ 2 ]

4 голосов
/ 10 декабря 2010

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

  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.

3 голосов
/ 10 декабря 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...