Check what text has been highlighted by user

Hi community!

Is there an easy way to check which text / if a specific piece of text has been highlighted by user?

Example use case:

A div or prepopulated text field provides a certain text. User is asked to highlight a specific part of this text. In the moment the user has finished highlighting, the highlighted text is passed to a variable for further processing.

Thank you!

1 Like

You can achieve the result you want using a couple of experimental JavaScript technologies.
a. A Selection object, accessable via the window.getSelection() function.
b. the same type of object, accessed via the document.getSelection() function.
c. The selection property of the document object.

The following example demonstrates one way to use the above experimental technologies.

<<set $selection to ''>>\
<div id="the-text">Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo culpa suscipit blanditiis nam odit itaque.</div>

<<timed 0s>>
	<<script>>
		$('#the-text').on('mouseup', function () {
			var selectedText = '';

			if (window.getSelection) { 
				selectedText = window.getSelection().toString();
			} 
			else if (document.getSelection) { 
				selectedText = document.getSelection().toString();
			} 
			else if (document.selection) { 
				selectedText = document.selection.createRange().text;
			}
			else {
				console.log('selection not supported');
				return;
			}

			console.log('selectedText: ' + selectedText);

			if (selectedText) {
				/* Update the $selected Story Variable. */
				State.variables.selected = selectedText;
			}
		});
	<</script>>
<</timed>>

see:
SugarCube: the <<timed>> macro, the <<script>> macro, and the State.variables collection object
jQuery .on() function.

2 Likes

Thank you very much! Code works perfectly (tested in FF and Edge). But can I bug you again? I tried turning your code into a widget for processing logic in the same passage, like checking if highlighted selection is correct, etc. As I do not know how to do this in JavaScript, I tried to use your code within ChapelR’s event macro.

> <<widget "checkHighlighted">>
> 	<<set _sentence to $args [0]>>
> 	<<set _correctHighlight to $args [1]>>
> 	<<set $selection to ''>>\
> 	<<print '<div id="highlightHere">' + _sentence + '</div>'>>
> 
> 	<<event 'mouseup' '#highlightHere'>> 
> 		<<script>>
> 				var selectedText = '';
> 
> 				if (window.getSelection) { 
> 					selectedText = window.getSelection().toString();
> 				} 
> 				else if (document.getSelection) { 
> 					selectedText = document.getSelection().toString();
> 				} 
> 				else if (document.selection) { 
> 					selectedText = document.selection.createRange().text;
> 				}
> 				else {
> 					console.log('selection not supported');
> 					return;
> 				}
> 
> 				console.log('selectedText: ' + selectedText);
> 	
> 				if (selectedText) {
> 					/* Update the $selected Story Variable. */
> 					State.variables.selection = selectedText;
> 				}
> 			});
            <</script>>
> 	    <<run UI.alert($selection)>>
> 	<</event>>
> <</widget>>

Upon highlighting, I get an alert window, but it is empty. Also, if I highlight a word by double-clicking on it, alert is opened and closed immediately. Is there a way to prevent this?

Thank you!

You have a few errors in your edited JavaScript:

  1. You may only return from a function, so when you attempted to change it from a function you introduced an error there.
  2. You didn’t remove the closing curly brace, parenthesis, and semi-colon of the jQuery event handler call.

Additionally. You have some general issues with your widget:

  1. You should probably have everything except the <div> within a <<silently>>.
  2. You do not need to <<print>> the <div>.
  3. You’re adding an event handler each time you call the widget, but not scheduling its removal. You either need to remove it upon navigation—what I’ve done in the following example—or remove the handler from the widget and use a global delegated handler instead.

Try something like the following:

<<widget "checkHighlighted">>
	\<<silently>>
		<<set _sentence to $args[0]>>
		<<set _correctHighlight to $args[1]>>
		<<set _highlightId to 'highlightHere'>>
		<<set $selection to ''>>

		<<event 'mouseup.checkHighlighted' `'#' + _highlightId`>> 
			<<script>>
			var selectedText = '';

			if (window.getSelection) { 
				selectedText = window.getSelection().toString();
			} 
			else if (document.getSelection) { 
				selectedText = document.getSelection().toString();
			} 
			else if (document.selection) { 
				selectedText = document.selection.createRange().text;
			}
			else {
				console.log('selection not supported');
			}

			if (selectedText) {
				/* Update the story variable: $selection. */
				State.variables.selection = selectedText;
			}
			<</script>>
			<<if $selection is _correctHighlight>>
				<<run UI.alert('Correct: ' + $selection)>>
			<<else>>
				<<run UI.alert('Wrong: ' + $selection)>>
			<</if>>
		<</event>>
		<<event ':passageinit'>>
			/* Remove our `mouseup` event handler on navigation. */
			<<run $(document).off('mouseup.checkHighlighted')>>
		<</event>>
	<</silently>>
	\<div @id="_highlightId">_sentence</div>
\<</widget>>

NOTES:

  • I added an example test against _correctHighlight after the <<script>>.
  • In your final code, you may wish to trim the selected text, so that leading/trailing whitespace is not included—since it’s fairly easy to accidentally select some.

 

Only by not making the mouseup event handler not handle the selection test itself or by not triggering on that event.

As to why. Double-clicking fires several mouse events beyond the dblclick event—specifically, two pairs of mousedown/mouseup events and two click events.

 
EDIT (Ă—1): Updated the widget.