Get Selected Discourse Code Block on Web Page & Open in Editor


  • This is a continuation of the discussion in Need Macro/JavaScript to Extract Contents of Code Block.
  • At one point we had a solution, but then it failed in Safari after later updates of Safari and/or macOS.
  • This is a solution using a different method that works in both Safari and Google Chrome.
  • I have tested it in Safari 11.0.1 (11604. and Google Chrome 62.0.3202.94 (3202.94) on macOS 10.11.6.
  • As always, please feel free to post if you have issues or suggestions to improve.

###MACRO:   Get Selected Discourse Code Block on Web Page & Open in Editor
(Note: the KM Forum uses the Discourse software).

~~~ VER: 1.0    2017-11-25 ~~~

<a class="attachment" href="/uploads/default/original/3X/e/8/e88d6ed22ab16124bfbbd1207f3384487e09c389.kmmacros">Get Selected Discourse Code Block on Web Page & Open in Editor.kmmacros</a> (62 KB)
**Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.**





* **Extract the Code in the User Selected Code Block in a Discourse Forum (like the KM forum)**
* Then open that code in the user's default script editor.


0. Set the default script editor you want to use in the first Action.
  * Set it to empty to choose when the macro is run.
1. Click in the code block of a Discourse forum post.
2. Trigger this macro.

Rarely the JavaScript might not find the Code Block.  If that happens, just repeat the above steps.


1. **KM 8.0.4+**
  * But it can be written in KM 7.3.1+
  * It is KM8 specific just because some of the Actions have changed to make things simpler, but equivalent Actions are available in KM 7.3.1.
2. **macOS 10.11.6+ (El Capitan)**
  * KM 8 Requires Yosemite or later, so this macro will probably run on Yosemite, but I make no guarantees.  :wink: 


* **Carefully review the Release Notes and the Macro Actions**
  * Make sure you understand what the Macro will do.  
  * You are responsible for running the Macro, not me.  πŸ˜‰
* Assign a Trigger to this maro.  I prefer βŒƒβŒ₯C
* Move this macro to a Macro Group that is only Active when you need this Macro.
* ENABLE this Macro.
TAGS:  @JavaScript @Web @CodeBlock @Post @Extract


* Any Action in _magenta color_ is designed to be changed by end-user


* To facilitate the reading, customizing, and maintenance of this macro,
      key Actions are colored as follows:
* GREEN   -- Key Comments designed to highlight main sections of macro
* MAGENTA -- Actions designed to be customized by user
* YELLOW  -- Primary Actions (usually the main purpose of the macro)
* ORANGE  -- Actions that permanently destroy Variables or Clipboards,
OR IF/THEN and PAUSE Actions


* While I have given this limited testing, and to the best of my knowledge will do no harm, I cannot guarantee it.
* If you have any doubts or questions:
  * **Ask first**
  * Turn on the KM Debugger from the KM Status Menu, and step through the macro, making sure you understand what it is doing with each Action.


<img src="/uploads/default/original/3X/f/3/f3791ead04526373877412c18e0fc7ebba7ddfe5.png" width="690" height="897">


### JavaScript to Extract Code Block

'use strict';  // See

(function extractCodeBlock() {    // ~~~ automatically executed when this script is executed ~~~
var ptyScriptName   = "Extract Text from Discourse Code Block"
var ptyScriptVer     = "2.0"
var ptyScriptDate   = "2017-11-25"
var ptyScriptLang    = "JS Web"
var ptyScriptAuthor = "JMichaelTX"

PURPOSE: Extract all text in the user selected Code Block in a post in a Discourse Forum

RETURNS: One of these, as text:
β€’ Actual Results of script if all goes well
β€’ Extracted text

β€’ "[USER_CANCELED]" at start of results if the user canceled something
β€’ "[ERROR]" at start of results if a script error occurred.

1. Mac OS X Yosemite 10.11.6+
2. Mac Applications
β€’ Google Chrome OR Safari

β€’ User clicks in the Code Block to be extracted
β€’ Call this function

β€’ Get the DOM Range where the user clicked using the Selection getRangeAt() function
β€’ Get Parent element of range
β€’ Look for Code Block with specified tagName
β€’ Get textContents of this tag.

Ver# Date Description
------ ---------- ---------------------------------------------------------
2.0 2017/11/25 Extract text using .textContents

~~~~~~~~~~~~~~~~~~~ END HEADER COMMENTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

var scriptResults = β€œTBD”

try { //~~~~~~~~~~~ START TRY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

var codeBlockTag = β€œCODE”; // tagName of Discourse Code Block element

//β€” Get Range of where User has Clicked Mouse β€”
// and then its parent element

var rngSel = window.getSelection().getRangeAt(0);
var parElem = rngSel.startContainer.parentNode;
var parTag = parElem.tagName;

//β€” IF selected tag is NOT codeBlockTag, Search UP the DOM tree Until it if found β€”

while (parTag !== codeBlockTag) {
parElem = parElem.parentElement;
parTag = parElem.tagName;

if (parTag === "BODY") {
  scriptResults = "[ERROR] Could NOT find Code Block with tagName of " + codeBlockTag;
  return scriptResults;


scriptResults = parElem.textContent;
} //~~~~ END TRY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

catch (oError) {

if (oError.errorNumber === -128) { // User Canceled

scriptResults =  "[USER_CANCELED]\n\n"
  + "SCRIPT: " + ptyScriptName + "   Ver: " + ptyScriptVer


else {
var errNum = oError.errorNumber || β€œCustom Error”;
scriptResults = β€œ[ERROR]\n\n”
+ "SCRIPT: " + ptyScriptName + " Ver: " + ptyScriptVer + β€œ\n”
+ "Error Number: " + errNum + β€œ\n”
+ oError.message

} // END if/else on ERROR Number
} //~~~~ END TRY/CATCH BLOCK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//β€” RETURN β€”
return scriptResults

//=============== END OF MAIN SCRIPT =======================================

})(); // ~~~ function selectCodeBlock() is automatically executed when this script is executed ~~~

1 Like

If you prefer, you can use this Action to get your default script editor:


/usr/bin/perl -MMac::InternetConfig -le 'print (GetICHelper "applescript")' \
| sed -E 's!^.{4}!!'

My thanks to Chris (@ccstone) for providing this solution.