Получаем данные из Javascript через функции Java

Хоббит или туда и обратно


Некоторое кол-во времени назад мне срочно потребовалось найти возможные способы получения переменных из 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.

Вот оба способа, которые я знаю и которыми пользовался… Буду рад прочитать новые идеи и замечания к статье. Спасибо за внимание.
Поделиться публикацией
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 20
      0
      Хотя нет, слишком уж навороченно получается если данные еще и на серверную часть передавать. Этот метод подойдет если в проекте уже ипользуется GWT.
        +1
        Господи. GWT-то тут причем? Он тут ничем не поможет.

        Автор, я так понял, решает проблему взаимодействия Standalone Java Application и HTML-страницы, открытой в браузере, встроенном в его приложение.

        Честно говоря, за изложение материала хочется поставить двойку. Даже просто за заголовок. Абсолютно неинформативно.
          0
          Да-да. Извиняюсь, я на автомате ответил, этот GWT мне уже все мозги проел :(
          Жаль, что мессагу удалить нельзя.
      +1
      23.3. Взаимодействие с JavaScriptсценариями из Java

      Любое взаимодействие Java с JavaScriptсценарием осуществляется через экземпляр класса netscape.javascript.JSObject.
      «JavaScript. Подробное руководство, 5-е издание — Флэнаган Д. 2008»

      Насколько я понимаю это оно? В книге есть примеры и полное описание объекта (также рассказано и взаимодействие в обратном направлении).
        0
        Плюсую. Пользуюсь этим и всё отлично работает, в обе стороны.
          0
          LiveConnect это называется. Осталось только в Gecko, и то обещают выпилить в скорейшем времени.
            0
            Ну почему-же только в Gecko. В IE работает, а мне это собственно говоря только в IE и надо.
              0
              Ого, я не знал, что LiveConnect в IE работает. А с какой версии?
                0
                Ну я тестил начиная с IE6. Но вот тут пишут:
                  0
                  Internet Explorer: Java Plug-in provides full support of JSObject in IE 3/4 by accessing the DOM through COM.
        0
        Возможно по ссылкам выше уже описано такое решение: использовать в клиенте встроенный в JRE http-сервер (com.sun.net.httpserver.HttpServer).
        Тогда можно будет очевидным образом взаимодействовать со страницы браузера с приложением.
        Плюсы такого решения: всё достаточно «очевидно» в том смысле что нет черной магии JS с изменением статуса а потом чтением этого статуса и нет BrowserFunction. Если есть ForntEnd разработчик — он может ваять свои интерфейсы и взаимодействие привычным и понятным способом. Это становится особенно важным когда взаимодействие становится сложней чем просто передать содержимое поля.

          0
          Мне кажется для десктопного прилежения на SWt как раз более муторным будет устраивать взаимодействие через httpServer. Спрашивается зачем? KISS никто не отменял :)
            0
            KISS как раз будет со встроенным http-сервером)
            Есть html страница в браузере. Её делают те кто в этом хорошо понимает и взаимодействуют привычным образом.
            Использование стандартных вещей (status/title) нестандартным образом на KISS (который «никто не отменял») никак не тянет :)
            Да что CustomFunction == KISS — тоже ниоткуда не следует
          0
          При двух одновременно запущенных экземплярах программы редакторы одновременно работают?
            0
            Приложения Standalone. Поэтому запустив 2 экземпляра, в получаете 2 отдельных приложения, в каждом из которых запущен свой instance браузера. соответственно данные не являются общими, и callback функции выполняются отдельно в каждом браузере. Если даже одноврменно редактировать один и тот же файл в каждом из двух приложений (ну при условии отсутсвия лока на файл)
              0
              Извиняюсь, что так не скоро отвечаю :)
              Просто у Java был наследный баг со встроенным браузером — на все приложения Java запускался единственный его экземпляр. В приницпе, казалось бы, ничего страшного — фактически один экземполяр, у которого открыты разные вкладки, но на практике вылазило множество побочных эффектов. По крайней мере под Windows было именно так. Потому и интересно насколько хорошо работают два запущенные приложения в данном случае.
                0
                Я тоже красавец с ответом =)

                Ммм… не уверен по поводу баги. У меня в моём приложении 4 виджета браузера. Запустил парочку инстансов, все диалоги с браузерами пооткрывал. Логика моего приложения работает без сбоев.
                Кроме всего прочего, один и тот же диалог с браузером запущен был несколько раз. Всё нормально отработало, нигде ничего не было нарушено. (Это в контексте одной jvm)

                А 2 приложения запускаются в разных jvm ещё помоему, так что инстансы браузера явно не могут перекрываться.
                  0
                  Большое спасибо. А то, я как два года назад на эти грабли напоролся, так с тех пор и боюсь браузеры для пользовательского интерфейса в Java использовать.
                    0
                    Могу развить вам новую параною =)
                    Вот столкнулся недельку назад. Ситуация какая. Есть BrowserFunction. Я ей передаю в аргументы htm из jquery. Так вот, если браузер подтянет не вебкит или дефолтный браузер, а мозиллу, то в java передастся голый текст без html. для Webkit браузера и ИЕ (на винде) всё отлично возвращается HTML. Для 5го фф вернётся хтмл без хтмл =) по сути результат выполнения $.text()... Побороть не смог, буду сажать своих пользователей на хром

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое