Как я могу осмысленно реагировать на изменение 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
случай, в частности, когда зачеркивание изменено, отправитель может быть закрытым классомNSFontEffectsBox
msgstr "что, по-видимому, соответствует подразделу панели шрифтов, отвечающему за изменение настроек перечеркивания и т. д.
К сожалению звоню [[NSFontManager sharedFontManager] convertAttributes:]
НЕ получает ожидаемые изменения атрибута. Это оставляет делегата, который заинтересован в осмысленной реализации этого метода, немного загадкой:
WebKit не передает отправителю, поэтому делегат не может заключить договор
[sender convertAttributes:]
вызов.changeAttributes:
вызов отправляется в закрытый класс WebKit,WebHTMLView
, которые не могут быть разделены на подклассы, например, чтобы настроить поведениеchangeAttributes:
,Отправитель для
changeAttributes:
вызов,NSFontEffectsBox
, является частным классом и недоступен, например, как[NSFontEffectsBox sharedFontEffectsBox]
,
Короче говоря, у разработчика, похоже, нет возможности существенно изменить поведение changeAttributes:
для WebView
,
Есть идеи?
2 ответа
Это злой Подходящей злой парой действий (ни одно из которых не является особенно чистым или идеальным) будет:
Сделайте какой-нибудь встроенный ассемблер, чтобы посмотреть обратно в стек, чтобы прочитать аргумент отправителя из стека вызывающего (или вызывающего, в зависимости от обстоятельств). Это, конечно, предполагает, что отправитель помещается в стек, а не в
%eax
когда звонокWebHTMLView
сделан. Это всегда будет относиться к коду PowerPC, так что, скорее всего, это не стартер.Поместите категорию на
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.
Вы смотрели на исходный код?
Я не вижу как -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