Хоббит или туда и обратно
Некоторое кол-во времени назад мне срочно потребовалось найти возможные способы получения переменных из js и браузера, чтобы передать их значение в моем приложении на java. К сожалению, на хабре данный вопрос не был раскрыт или возможно сила покинула меня и поиск дается уже не так легко.
Как бы то ни было сегодня я постараюсь в какой то мере пролить свет на данный вопрос. Итак приступим!
Задача
В кратце опишу сложившуюся ситуацию — есть некое приложение со страницей редактора, в качетсве редактора имеем бесплатный NiceEdit. Почему именно внешний редактор — мне было необходимо достаточно быстро встроить редактор + данные пользователя представляются как html и писать велосипед было бы достаточно глупо. Были попытки встроить готовый виджет на swt, но или проект устарел или автор покривил душой — работать виджет отказывался.
Основная проблема — пользователь вводит\редактирует данные в редакторе, нажимает чудо кнопочку и наше приложение должно получить то, что только что было написано.
Решение
Как оказалось существует не один вариант решения подобной задачи:
- Способ номер 1 — JNI
Самое простое и полезное что пришло в голову — это сделать в html странице редактора, которая загружается встроенным в java браузером, свое текстовое поле и натравить на него редактор:
<script type="text/javascript"> var textArea; bkLib.onDomLoaded(function() { new nicEditor({fullPanel : true}).panelInstance('area1'); var el = document.getElementById('EDITOR').getElementsByTagName('div'); textArea = el[el.length-1]; }); </script>
Далее в самом приложении нам нужно написать нативную функцию, которую мы будем вызывать:
static class CustomFunction extends BrowserFunction { //CustomFunctionData data = new CustomFunctionData(null); public CustomFunction(Browser browser, String name) { super(browser, name); } public Object function(Object[] arguments) { templateText = (String) arguments[0]; return null; } }
создание новой customdata выдает ексепнш, хотя этот способ был описан на stackowerflow
Создаем объект:
new CustomFunction(browser, "getTextAreaContent");
Теперь мы можем гордо вызвать необходимую нам функцию из браузера:
browser.execute("var cont = textArea.innerHTML; getTextAreaContent(cont);");
- Способ номер 2 — создание скрипта и вызов через браузер
Никто не мешает нам создать переменную, записать туда нужный кусок скрипта и выполнить ее через браузер. Причем скрипт будет создавать пользовательский евент, изменяя статус браузера:
final String SELECTIONSCRIPT = "function handleSelection() { " + " var selTxt = ''; " + " if (window.getSelection) { " + " selTxt = window.getSelection(); " + " } else if (document.getSelection) { " + " selTxt = document.getSelection(); " + " } else if (document.selection) { " + " selTxt = document.selection.createRange().text; " + " } " + " window.status = '::SELECTION::' + selTxt; " + "} " + "document.attachEvent('onmouseup', handleSelection); "; final Browser browser = new Browser(shell, SWT.NONE); browser.addStatusTextListener(new StatusTextListener() { public void changed(StatusTextEvent arg0) { if (arg0.text.startsWith("::SELECTION::")) { String selection = arg0.text.substring("::SELECTION::".length()); System.out.println(selection); } }}); browser.addProgressListener(new ProgressAdapter() { @Override public void completed(ProgressEvent arg0) { browser.execute(SELECTIONSCRIPT); } });
Правда тут нас ждут некоторые подводные камни, о которых никто не упоминал на разных форумах — не все браузеры позволяют изменять статус окна приложениям без разрешения пользователя. То есть, к примеру, в мозилле нужно поставить флаг dom.disable_window_status_change на false в about:config.
Вот оба способа, которые я знаю и которыми пользовался… Буду рад прочитать новые идеи и замечания к статье. Спасибо за внимание.