Twitter Email
subspace (/ˈsʌbspɛɪs/)
A Jekyll playground site

A tag to insert a code selector widget

Author: Admin
Title: A tag to insert a code selector widget
Language: en-US
Created: 14:36 on Monday, 11. October 2021
Modified: 15:04 on Monday, 11. October 2021
Keywords: jekyll, ruby, tag, liquid, code
Excerpt:

This is a simple Liquid tag that inserts a code selector widget. When clicking on it, the code in the following highlight block will be selected. This tag must be put immediately before the highlight tag.

Tags: Jekyll
Page layout: nonav
Last modified:
14:36 on Monday, 11. October 2021 | by Admin in Jekyll

This is very simple. The tag inserts a small <div> element that contains some clickable text. When clicked, the contents of the following highlight block will be selected so it can be easily copied. Note that the codeselect tag must stand immediately before the highlight tag (literally, the line before, otherwise it may not work). It also works with the markdown method of code highlighting (three backticks) and is smart enough to NOT select the line numbers in case they are present.

Yes, I’m aware that there are different and maybe easier solutions for this problems, some are CSS and JavaScript - only, but this solution is slightly smarter, because it’s optional.

The plugin code.
Code: (click to select all)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module Jekyll
  class SelTag < Liquid::Tag

    def initialize(tag_name, text, tokens)
      super
      @text = text
    end

    # render the output. Make sure, we have a valid cssclass
    def render(context)
      output = "<div class=\"codeselect\">Code: (click to select all)</div>"
      return output
    end
  end
end
Liquid::Template.register_tag('codeselect', Jekyll::SelTag)

Supporting JavasSript code

This is the necessary JavaScript. It consists of 2 parts. First, a generic jQuery plugin to select the text of a given node. Just put this somewhere into your site’s footer scripts. It must load after jQuery has been fully loaded.

Code: (click to select all)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// jQuery plugin to select text of a node
// should work on all modern browsers
jQuery.fn.selectText = function(){
    this.find('input').each(function() {
        if($(this).prev().length == 0 || !$(this).prev().hasClass('p_copy')) { 
            $('<p class="p_copy" style="position: absolute; z-index: -1;"></p>').insertBefore($(this));
        }
        $(this).prev().html($(this).val());
    });
    var doc = document;
    var element = this[0];

    console.log(this, element);
    if (doc.body.createTextRange) {
        var range = document.body.createTextRange();
        range.moveToElementText(element);
        range.select();
    } else if (window.getSelection) {
        var selection = window.getSelection();
        var range = document.createRange();
        if (typeof(element) == 'object') {
          range.selectNodeContents(element);
        } else {
          console.log(' not an object ' + typeof(element));
        }
        selection.removeAllRanges();
        selection.addRange(range);
    }
};

The following small JavaScript fragment should go to your $(document).ready() function. It handles the clicks and does the actual work.

Code: (click to select all)
1
2
3
4
5
6
7
8
9
10
    $('div.codeselect').on('click', function(event) {
      // this is for a highlight witOUT linenos or the markdown method
      if ( $(this).next().contents().find('code').length ) {
        $(this).next().contents().find('code').selectText();
      }
      // and this is for linenos
      if ( $(this).next().contents().find('td.code').length ) {
        $(this).next().contents().find('td.code').selectText();
      }
    });