Вручную вызвать вырезать / копировать / вставить в Android WebView - PullRequest
2 голосов
/ 26 апреля 2019

Я создаю небольшое приложение для браузера с использованием веб-браузера Android и использую window.getSelection() в javascript, чтобы получить характер любого текста, выбранного пользователем, и показать настраиваемое контекстное меню, основанное на типе выбора, т.е. будь то диапазон, карат, является ли это в contenteditable и т.д.

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

В идеале мне нужен способ получить лучшую информацию о том, что было выбрано из веб-просмотра, или, если это невозможно, мне нужен способ узнать, произошел ли выбор в iframe, чтобы я мог отключить свою логику пользовательского контекстного меню и вернуться к контекстное меню Android по умолчанию.

ОБНОВЛЕНИЕ / ДАЛЬНЕЙШАЯ РАЗЪЯСНЕНИЕ 07/05/2019:

Кажется, я не был достаточно ясен в своем первоначальном описании ...

Моя цель - создать визуально и функционально пользовательское меню при выборе контента в веб-просмотре, который можно вырезать / копировать / вставить, как стандартное контекстное меню в любой части страницы / фреймах и т. Д., Например

example custom menu

Я осознал, что мой оригинальный подход с использованием javascript для определения типа выделения и выполнения вырезания / копирования / вставки был неправильным, поскольку он будет заблокирован из-за перекрестной безопасности источников в фреймах.

Мне нужен нативный подход на основе Android / WebView. Я обнаружил, что могу определить тип выделения в веб-просмотре, просматривая элементы в mode.getMenu() в onActionModeStarted. Это позволит мне отображать правильные кнопки в моем пользовательском интерфейсе меню, но я не смог вручную вызвать ту же логику, которая вызывается при нажатии кнопки вырезать / копировать / вставить. Мне показалось, что я нашел решение с помощью webView.performAccessibilityAction(AccessibilityNodeInfo.ACTION_CUT, null);, но по какой-то причине это не сработало, поэтому я думаю, что мой вопрос действительно заключается в том, как вручную вызвать вырезание / копирование / вставку выделенного текста из веб-просмотра без использования JavaScript? или любой другой подход, который позволит мне иметь пользовательское меню выбора с большим количеством опций, основанных на том, что было выбрано, не нарушая ограничения безопасности браузера?

Ответы [ 4 ]

2 голосов
/ 09 мая 2019

Хорошо, я понял, как примерно это сделать.

Шаг 1) В своей деятельности переопределите onActionModeStarted и проверьте пункты меню, доступные в контекстном меню по умолчанию. Это дает вам представление о том, какой тип выделения и какие кнопки вам нужно будет отображать в вашем пользовательском меню. Также он дает вам ссылку на идентификатор предмета, который вы можете использовать позже для запуска действия, например,

systemSelectionMenu = mode.getMenu(); // keep a reference to the menu
MenuItem copyItem = systemSelectionMenu.getItem(0); // fetch any menu items you want
copyActionId = copyItem.getItemId(); // store reference to each item you want to manually trigger

Шаг 2) Вместо очистки меню, используйте setVisible(), чтобы скрыть каждый пункт меню, для которого вы хотите пользовательскую кнопку, например,

copyItem.setVisible(false); 

Шаг 3) В пользовательском событии onclick кнопки вы можете запустить действие копирования, используя:

myActivity.systemSelectionMenu.performIdentifierAction(myActivity.copyActionId, 0)
1 голос
/ 03 мая 2019

Вы можете получить выбор iframe, только если он имеет то же происхождение. В противном случае у вас нет шансов отследить какие-либо события iframe (щелчки, касания, нажатия клавиш и т. Д.).

const getSelectedText = (win, doc) => {    
  const isWindowSelectionAvailable = win && typeof win.getSelection != "undefined";
  if (isWindowSelectionAvailable) {
    return win.getSelection().toString();
  }

  const hasDocumentSelection = doc && typeof doc.selection != "undefined" && doc.selection.type == "Text";
  if (hasDocumentSelection) {
    return doc.selection.createRange().text;
  }

  return '';
}

const doIfTextSelected = (win, doc, cb) => () => {
  const selectedText = getSelectedText(win, doc);
  if (selectedText) {
      cb(selectedText);
  }
}

const setupSelectionListener = (win, doc, cb) => {
  doc.onmouseup = doIfTextSelected(win, doc, cb);
  doc.onkeyup = doIfTextSelected(win, doc, cb);
}

const getIframeWinAndDoc = (iframe) => {
  try {
    const doc = iframe.contentDocument || iframe.contentWindow.document;
    const win = iframe.contentWindow || iframe.contentDocument.defaultView;

    return { win, doc };
  } catch (e) {
    console.error(`${e}`);
    
    return {};
  }
}

const callback = console.log;

setupSelectionListener(window, document, callback);

document.querySelectorAll('iframe').forEach(iframe => {
  const { win, doc } = getIframeWinAndDoc(iframe, console.log);
  
  // Only for same origin iframes due to https://en.wikipedia.org/wiki/Same-origin_policy
  if (win && doc) {
    setupSelectionListener(win, doc, callback);
  }
})
<h3>Select me</h3>

<div class="container">
  <iframe src="https://teimurjan.github.io"></iframe>
</div>
0 голосов
/ 04 мая 2019

Основная проблема в том, что window.getSelection() вернет выбор только для основного контекста / окна.Поскольку iframe - это другое окно и другой контекст, вы должны вызвать getSelection() из iframe, который является "текущим".

0 голосов
/ 03 мая 2019

Эта проблема варьируется от браузера к другому, если она работает с Internet Explorer, поэтому она может упасть с Chrome Попробуйте это

App.util.getSelectedText = function(frameId) {
var frame = Ext.getDom(frameId);
var frameWindow = frame.contentWindow;
var frameDocument = frameWindow.document;

if (frameDocument.getSelection) {
    return frameDocument.getSelection();
}
else if (frameDocument.selection) {
    return frameDocument.selection.createRange().text;
}
};

Надеюсь, что все в порядке

...