and binds events associated
3 | * with text selection to a benign function. Finally, remove 'disabled' attributes from all text inputs and
4 | * ensures that keydown and keyup events are allowed (to defeat blocks that prevent cut,copy, paste using shortcuts
5 | * There is one concern though: binding to so many events will undoubtedly break functionality on some pages. For
6 | * instance, text inputs very often have custom events bound to keypresses (eg to run a search and show results as
7 | * the user types). As a result, this script is probably not fit to run indiscriminately on all pages; it should
8 | * rather be used only when the user needs to defeat text-selection blocks on specific pages.
9 | *
10 | * Crunch at https://alanhogan.github.io/bookmarkleter/
11 | */
12 |
13 | function allowTextSelection() {
14 | window.console && console.log("allowTextSelection");
15 |
16 | //add styles that enable text selection
17 | var style = document.createElement("style");
18 | style.type = "text/css";
19 | style.innerHTML = `*, p, div {
20 | user-select: text !important;
21 | -moz-user-select: text !important;
22 | -webkit-user-select:text !important;}
23 | `;
24 |
25 | document.head.appendChild(style);
26 |
27 | //Put all of children in a collection
28 | //Use getElementsByTagName because it has better compatibility (it's older) than querySelectorAll('*')
29 | var elArray = document.body.getElementsByTagName("*");
30 |
31 | //allow mouse events typically involved in selection
32 | for (var i = 0; i < elArray.length; i++) {
33 | var el = elArray[i];
34 | el.onselectstart = el.ondragstart = el.ondrag = el.oncontextmenu = el.onmousedown = el.onmouseup = function() {
35 | return true;
36 | };
37 |
38 | //special processing for text-style elements
39 | if (
40 | el instanceof HTMLInputElement &&
41 | ["text", "password", "email", "number", "tel", "url"].indexOf(
42 | el.type.toLowerCase()
43 | ) > -1
44 | ) {
45 | //enable text inputs (to defeat an easy way to block selection by setting input's 'disabled' attribute)
46 | el.removeAttribute("disabled");
47 |
48 | //counteract any listener that would block copy&paste keyboard shortcuts. (I can't figure out yet why
49 | // although this works on the first text input in text-selection-demo.html, it doesn't work on the 2nd
50 | el.onkeydown = el.onkeyup = function() {
51 | return true;
52 | };
53 | }
54 | }
55 | }
56 |
57 | allowTextSelection();
58 |
--------------------------------------------------------------------------------
/font-stack-guess.js:
--------------------------------------------------------------------------------
1 | // Detector from
2 | // Other code by Alan Hogan
3 | // http://www.apache.org/licenses/LICENSE-2.0
4 | // Compile this to a bookmarklet at
5 | // (originally this bookmarklet used )
6 | // Some code has been previously converted by the Babel REPL to survive
7 | // running in IE11. Avoid ES6 or transpile before committing updates.
8 |
9 | var versionStr = '2.1';
10 |
11 | var Detector = function Detector() {
12 | var baseFonts = ['monospace', 'sans-serif', 'serif'];
13 |
14 | var testString = "mmmmmmmmmmlli";
15 |
16 | var testSize = '72px';
17 |
18 | var h = document.getElementsByTagName("body")[0];
19 |
20 | var s = document.createElement("span");
21 | s.style.fontSize = testSize;
22 | s.innerHTML = testString;
23 | var defaultWidth = {};
24 | var defaultHeight = {};
25 | for (var index in baseFonts) {
26 | s.style.fontFamily = baseFonts[index];
27 | h.appendChild(s);
28 | defaultWidth[baseFonts[index]] = s.offsetWidth;
29 | defaultHeight[baseFonts[index]] = s.offsetHeight;
30 | h.removeChild(s);
31 | }
32 |
33 | function quotedFontIfNecessary(fontName) {
34 | if(/\s/.test(fontName)) { return '\'' + fontName + '\''; }
35 | else return fontName;
36 | }
37 |
38 | function detect(font) {
39 | var detected = false;
40 | for (var index in baseFonts) {
41 | s.style.fontFamily = quotedFontIfNecessary(font) + ', ' + baseFonts[index];
42 | h.appendChild(s);
43 | var matched = s.offsetWidth != defaultWidth[baseFonts[index]] || s.offsetHeight != defaultHeight[baseFonts[index]];
44 | h.removeChild(s);
45 | detected = detected || matched;
46 | }
47 | return detected;
48 | }
49 |
50 | this.detect = detect;
51 | };
52 |
53 | var d = new Detector();
54 |
55 | function guessUsedFont(fullReport) {
56 | var body = document.getElementsByTagName('body')[0];
57 | var stack = body ? window.getComputedStyle(body).fontFamily : '';
58 | var selectionExamined = false;
59 |
60 | try {
61 | var selection = window.getSelection();
62 | if (selection.toString().length > 0) {
63 | var selectedEl = selection.anchorNode.parentElement;
64 | stack = window.getComputedStyle(selectedEl).fontFamily;
65 | selectionExamined = !! stack;
66 | }
67 | } catch (err) { }
68 |
69 |
70 | var fonts = stack.split(/\s*,\s*/).map(function (font) {
71 | return font.replace(/^['"]\s*(.+\S)\s*['"]$/, '$1');
72 | });
73 |
74 | var probableFont = false;
75 | var availableFonts = [], unavailableFonts = [];
76 | fonts.forEach(function (font) {
77 | if (d.detect(font)) {
78 | probableFont = probableFont || font;
79 | availableFonts.push(font);
80 | } else {
81 | unavailableFonts.push(font);
82 | }
83 | });
84 |
85 | if (probableFont) {
86 | var reportStr = (selectionExamined ? 'The selected text' : 'The BODY element') + " is probably using the font family or keyword: \n" + probableFont;
87 | if (fullReport) {
88 | reportStr = reportStr + "\n\n" + "All matching font names or keywords in the stack: \n" + availableFonts.join("\n") + "\n\n" + "Unavailable fonts: \n" + (unavailableFonts.length > 0 ? unavailableFonts.join("\n") : '(None)') + "\n\n" + "Font stack as reported by getComputedStyle: \n" + stack;
89 | reportStr = reportStr + "\n\nOnly Latin characters are tested, so detection will fail for Asian fonts, emojis, and system fonts. ";
90 | } else {
91 | reportStr = reportStr + "\n\n"
92 | }
93 |
94 | reportStr = reportStr + "More info and potentially a newer version of this bookmarklet are available at "
95 | + "https://alanhogan.com/bookmarklets"
96 | + (fullReport ? '#font-stack-full' : '#font-stack-guess');
97 |
98 | reportStr = reportStr + "\n\This is version " + versionStr;
99 |
100 | alert(reportStr);
101 | } else {
102 | alert('Did not detect any fonts');
103 | }
104 | }
105 |
106 | function fullFontStackReport() {
107 | guessUsedFont(true);
108 | }
109 |
110 | // Uncomment ONE of these to generate the simple vs full version of the bookmarklet.
111 | // guessUsedFont();
112 | fullFontStackReport();
113 |
--------------------------------------------------------------------------------
/text-selection-demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Prevent text selection with CSS/JS
9 |
22 |
23 |
24 |
Demo measures to prevent text selections
25 |
26 |
Using CSS
27 |
28 | Text selection in this section has been disabled using CSS only. We simply set the
29 | user-select property and as well as its prefixed alternatives to 'none'. This
30 | method can be effective because it requires no JavaScript; Because CSS style sheets
31 | are typically loaded in the <HEAD> of the document, they take effect immediately.
32 |
33 |
35 |
36 |
37 |
Using JS events bound by html attributes
38 |
41 |
42 | Text selection in this section has been disabled by setting the HTML attributes
43 | that bind to event handlers. The attributes 'onmousedown', 'onmouseup', 'oncontextmenu',
44 | and 'onselect' were all set to a JavaScript function that blocks typical browser behavior
45 | by calling event.preventDefault(). To the textbox below we also added an onkeydown handler
46 | that prevents the typical copy, cut and paste shortcuts.
47 |
48 |
54 |
55 |
56 |
Using purely Javascript
57 |
58 | Text selection in this section has been disabled by setting 'onmousedown', 'onmouseup'... properties
59 | to the same function as in the previous section. The only difference is that in the HTML attributes
60 | that bind to event handlers were set not in HTML as was done above, but in JavaScript. Selection
61 | within the textbox was disabled in JavaScript as well (not in HTML). In addition, the 'disabled'
62 | attribute was set. This is one of the easiest and most effective ways to prevent
63 | selection because the browser blocks all interactions with the disabled textbox.
64 |