Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mimic Ctrl+A with JavaScript

I would like to select all text on a page programmatically with the exact same result as if I would press key combo Ctrl+A.

The problem with using document.getSelection().selectAllChildren(body) is that the selection will also include text nodes that are not selectable by the user, i.e. <script> </script> or nodes for which there is user-select:none defined in CSS:

<div style="-moz-user-select:none">Will be selected</div>

There is the method modify on selection objects that could be used like this: selection.modify("extend", "forward", "documentboundary"); to extend a selection from the beginning of a document to its end which will ignore any script or style element contents and elements with -moz-user-select:none - unfortunately Firefox does not allow documentboundary as 3. argument and word does not help much.

Is there a fast way to accomplish this? Only needs to work in Firefox.

EDIT (not-so-good-solution): Select first text node, then use selection.modify('extend', 'forward', 'line') repeatedly while selection.focusNode is not equal to the last text node - but depending on the length of the document this takes up to several seconds!

EDIT: selection.selectAllChildren will work as intended in Chrome where text elements with user-select:none won't be selected - unfortunately there is a different behavior in FF.

EDIT: This is not a duplicate of this post since I'm neither addressing contenteditable elements nor am I concerned about them;)

like image 436
user1521685 Avatar asked May 17 '17 15:05

user1521685


1 Answers

It seems to me the most efficient way is to move what you want selected into its own selectable div, and selectAllChildren of that. I tried this on a google search, several stack overflow questions, and a few random sites. In every case the results were instantaneous and exactly the same has a ctrl+A.

function selectAll() {
  var sel = window.getSelection();
  var body = document.querySelector("body");
  // Place the children in an array so that we can use the filter method
  var children = Array.prototype.slice.call(body.children);

  // Create the selectable div
  var selectable = document.createElement("div");

  // Style the selectable div so that it doesn't break the flow of a website.

  selectable.style.width = '100%';
  selectable.style.height = '100%';
  selectable.margin = 0;
  selectable.padding = 0;
  selectable.position = 'absolute';

  // Add the selectable element to the body
  body.appendChild(selectable);

  // Filter the children so that we only move what we want to select.
  children = children.filter(function(e) {
    var s = getComputedStyle(e);
    return s.getPropertyValue('user-select') != 'none' && e.tagName != 'SCRIPT'
  });
  // Add each child to the selectable div
  for (var i = 0; i < children.length; i++) {
        selectable.appendChild(children[i]);
  }

  // Select the children of the selectable div
  sel.selectAllChildren(selectable);

}

selectAll();
like image 80
richbai90 Avatar answered Nov 09 '22 03:11

richbai90