Пытаюсь разобраться с обработкой событий в индизайне

Статус
Закрыто для дальнейших ответов.

andrew.folio

Участник
Топикстартер
Сообщения
28
Реакции
40
Поставил себе такую простую задачу: при клике на пустом TextFrame в нем должен появиться текст Hello World!

Судя из обектной модели индизайна (CS5) обрабатывать события могут следующие объекты:
Application
Document
MenuAction
ScriptMenuAction
Menu
Submenu

Все они имеют соответствующие свойства и методы для обработки событий.

Некоторые примеры, где обрабатываются события меню, я нашел. Например в теме "Скрипт в одну строку", автор Eugenyus, приводит следующий код:
Код:
#targetengine "breakPars"; //Это обязательно первая строка. В кавычках записать любое сочетание символов, но чтобы точно избежать совпадений с другими скриптами
var menuName = "Разбить абзацы на фреймы"; //Так будет назван пункт в меню
var myMenuItem  = app.scriptMenuActions.add(menuName);
myMenuItem.addEventListener('onInvoke', function(){main();});
var mnu = app.menus.item("$ID/Main").submenus.item("$ID/Type"); //Пункт меню будет создан в меню Type
mnu.menuItems.add(myMenuItem);

function main(){ //"оборачиваем" скрипт в эту функцию. Если она в скрипте уже есть, оставляем как есть.

//основной код

}//"закрываем" функцию

Погуглив еще, удалось узнать, что для MenuAction существуют следующие стандартные типы событий (eventType): beforeDisplay, beforeInvoke, onInvoke, afterInvoke.

К сожалению в объектной модели индизайна я не нашел перечня типов событий, которые могут обрабатывать объекты индизайна.
По аналогии с MenuAction, методом перебора, удалось определить, что Document обрабатывает такие стандартные события как beforeOpen, afterOpen, beforeClose, afterClose, beforePlace, afterPlace.

Следующая заготовка скрипта, если ее положить в папку startup scripts и перегрузить индизайн, позволяет сразу после заливки материала неявно применить к нему GREP запрос.
Код:
#targetengine 'myPlace'
 
var myEventHandler = function(ev)
    {
    app.loadFindChangeQuery ("Dash to En-dash", SearchModes.GREP_SEARCH); //Тире на коротке тире
    alert("Сделано " + app.activeDocument.selection[0].parentStory.changeGrep ().length + " замен");
    };
 
app.activeDocument.
    addEventListener('afterPlace', myEventHandler);

Теперь возвращаясь к поставленной задаче.

Как получить событие соответствующее выделению объекта в индизайне?
Как создать собственное (нестандартное событие), если это возможно?
Как перехватывать события мышки или клавиатуры?
Как эмулировать события клавиатуры?
 

Nano

Участник
Сообщения
47
Реакции
100
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

при клике на пустом TextFrame в нем должен появиться текст Hello World

Увы, нет ничего подходящего.

Возможна только такая схема: выделить текстовый фрейм и вызвать соответстующий скрипт через меню или палитру.
 

Eugenyus

12 лет на форуме
Сообщения
1 960
Реакции
3 589
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

Ну например французы с полгода назад заявили, что задача решаема в принципе, но на практике неподъёмна (интересно почему?):
InDesign CS5 introduced a number of new events at every DOM object level. Especially, it is now possible to listen to AFTER_SELECTION_CHANGED and AFTER_SELECTION_ATTRIBUTE_CHANGED from the app object. Therefore, it would be theoretically possible to spy on selection changes and attribute changes by extending the ActionManager, and to playback the corresponding operations on relevant targets. In practice, however, it sounds like a mammoth task!
 

andrew.folio

Участник
Топикстартер
Сообщения
28
Реакции
40
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

Спасибо Eugenyus за подсказку. Нашлось-таки событие afterSelectionChanged. Теперь решение задачи выглядит так:

Код:
#targetengine 'myWorld'
 
var myEventHandler = function(ev)
    {
        with (app.activeDocument) {
            if (selection[0] instanceof TextFrame) {
                app.activeDocument.selection[0].parentStory.contents = "Hello World!"
            } else alert ("Select TextFrame")
        }
    }
 
app.activeDocument.
    addEventListener('afterSelectionChanged', myEventHandler)

Кроме того удалось найти еще несколько событий обектов Application и Document.
xxxOpen, xxxClose, xxxPlace, xxxPrint, xxxRevert, xxxImport, xxxExport, xxxDelete, xxxQuit, xxxActivate, xxxSelectionChanged, xxxSelectionAttributeChanged (xxx - after или before).
За полноту этого списка не отвечаю
 

Eugenyus

12 лет на форуме
Сообщения
1 960
Реакции
3 589
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

Да, нормально получилось. Только alert раздражает, выскакивает при каждом изменении выделенной области - и когда снимаешь выделение, и когда выделяешь не фрейм... Без него, мне думается, можно спокойно обойтись.

PS. Я бы еще предложил каждому такому фрейму давать метку, вот зачем. Я рисую фрейм, перехожу на черную стрелку - получаю во фрейме текст. Захожу во фрейм, удаляю текст, перехожу опять на стрелку - и снова текст во фрейме. Так вот, если я его оттуда удаляю, я не хочу, чтобы он там снова появлялся, и метки могут в этом помочь:
Код:
#targetengine 'myPlace'
 
var myEventHandler = function(ev)
    {
        with (app.activeDocument) {
            if ((selection[0] instanceof TextFrame)[B]&&(selection[0].name!="Hello World!")[/B]) {
                app.activeDocument.selection[0].parentStory.contents = "Hello World!";
                [B]app.activeDocument.selection[0].name = "Hello World!";[/B]
            }
        }
    }
 
app.activeDocument.//everyItem().
    addEventListener('afterSelectionChanged', myEventHandler)
 

andrew.folio

Участник
Топикстартер
Сообщения
28
Реакции
40
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

Назойливого алерта я заметил, но не стал с ним заморачиваться. Цель была получить принципиальный ответ можно ли по событию обрабатывать объекты. По-хорошему надо еще сделать обработчик и на событие beforeSelectionChanged, чтобы можно было определить направление выделения (снимаем выделение или устанавливаем его). А также позаботиться об активации и деактивации таких скриптов. Иначе делать что-либо другое будет невозможно. Но это уже дело техники.

Однако у меня все еще остался один принципиальный вопрос: Как эмулировать события клавиатуры?
Дело в том, что у меня есть плагин, который выполняет некоторое действие с выделенным объектом. Достучаться из скрипта к этому действию плагина я способа не нашел, но на него можно повесить shortcut. Теперь задача состоит в том, чтобы перебирая скриптом необходимые объекты эмулировать shortcut.
 

andrew.folio

Участник
Топикстартер
Сообщения
28
Реакции
40
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

Спасибо Eugenyus еще раз за ссылку на полное описание DOM модели индизайна, где можно найти все события возникающие в объектах индизайна
 

Nano

Участник
Сообщения
47
Реакции
100
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

Отличная работа. Добавлю, что в файле InDesignCS5_ScriptingGuide_JS.pdf нашелся пример Sample Selection Event Listeners с обработкой события afterSelectionChanged
 

Eugenyus

12 лет на форуме
Сообщения
1 960
Реакции
3 589
Ответ: Пытаюсь разобраться с обработкой событий в индизайне

А также позаботиться об активации и деактивации таких скриптов.
Возникла необходимость, и решение нашлось, причем довольно быстро.
Активация/деактивация такого скрипта делается одной кнопкой, находящейся в плавающем окне. Код выглядит так:
Код:
#targetengine "doSomethingWithMultiselect"

var myEventHandler = function(ev){

try{
//Здесь выполняется нужное действие, у меня, например, назначается символьный стиль множеству последовательно выделяемых символов:
app.activeDocument.selection[0].appliedCharacterStyle = "Нужный символьный стиль"; 
w.text = "It's working!";
}
catch(e){w.text = "It doesn't work!";}

}//function

var w = new Window("palette");
var butStart = w.add("button",undefined,"Start"); //Этой кнопкой будем включать/выключать отслеживание события
var started = false; //С помощью этой переменной мы определяем, включено отслеживание события, или нет

butStart.onClick = function(){
    if (!started){
        //Если отслеживание события не включено - включаем
        app.activeDocument.addEventListener('afterSelectionChanged', myEventHandler);
        butStart.text = "Stop"; //Меняем текст на кнопке
        }
    else{
        //Если отслеживание события включено - выключаем
        app.activeDocument.removeEventListener('afterSelectionChanged', myEventHandler);
        butStart.text = "Start"; //Меняем текст на кнопке
        }
    started = !started; //При нажатии на кнопку переключаем переменную
    }

w.show();
 
  • Спасибо
Реакции: gasyoun
Статус
Закрыто для дальнейших ответов.