Create a gist now

Instantly share code, notes, and snippets.

Perl script to URI-escape JavaScript for bookmarklets
#!/usr/bin/env perl
#
# Written by John Gruber, taken with permission from:
# http://daringfireball.net/2007/03/javascript_bookmarklet_builder
use strict;
use warnings;
use URI::Escape qw(uri_escape_utf8);
use open IO => ":utf8", # UTF8 by default
":std"; # Apply to STDIN/STDOUT/STDERR
my $src = do { local $/; <> };
# Zap the first line if there's already a bookmarklet comment:
$src =~ s{^// ?javascript:.+\n}{};
my $bookmarklet = $src;
$bookmarklet =~ s{^\s*//.+\n}{}gm; # Kill comments.
$bookmarklet =~ s{\t}{ }gm; # Tabs to spaces
$bookmarklet =~ s{ +}{ }gm; # Space runs to one space
$bookmarklet =~ s{^\s+}{}gm; # Kill line-leading whitespace
$bookmarklet =~ s{\s+$}{}gm; # Kill line-ending whitespace
$bookmarklet =~ s{\n}{}gm; # Kill newlines
# Escape single- and double-quotes, spaces, control chars, unicode:
$bookmarklet = "javascript:" .
uri_escape_utf8($bookmarklet);
print "// $bookmarklet\n" . $src;
# Put bookmarklet on clipboard:
`/bin/echo -n '$bookmarklet' | /usr/bin/pbcopy`;
@hober
hober commented Oct 3, 2011

I have an elisp version of this, if you're into that sort of thing.

(defun ted-create-bookmarklet-from-region (start end)
  "Create a bookmarklet of the code from START to END.

Inserts a comment with the bookmarklet, and adds the bookmarklet to the
kill ring.

Based on John Gruber's bookmarklet builder, which you can find at
http://daringfireball.net/2007/03/javascript_bookmarklet_builder
as modified by John Tantalo at https://gist.github.com/1259477"
  (interactive "r")
  (setq start (set-marker (make-marker) start))
  (setq end (set-marker (make-marker) end))
  (set-marker-insertion-type start nil)
  (set-marker-insertion-type end t)

  ;; Zap the first line if there's already a bookmarklet comment
  (goto-char start)
  (when (looking-at "^// javascript:.+\n")
    (replace-match ""))

  (let ((bookmarklet (buffer-substring start end)))
    (with-temp-buffer
      (insert bookmarklet)
      ;; Kill comments.
      (goto-char (point-min))
      (while (re-search-forward "//.+\n" (point-max) t)
        (replace-match "\n"))
      ;; Tabs to spaces
      (goto-char (point-min))
      (while (re-search-forward "[\t]" (point-max) t)
        (replace-match " "))
      ;; Space runs to one space
      (goto-char (point-min))
      (while (re-search-forward "[ ]{2,}" (point-max) t)
        (replace-match " "))
      ;; Kill line-leading whitespace
      (goto-char (point-min))
      (while (re-search-forward "^[ ]+" (point-max) t)
        (replace-match ""))
      ;; Kill line-(point-maxing whitespace
      (goto-char (point-min))
      (while (re-search-forward "[ ]+$" (point-max) t)
        (replace-match ""))
      ;; Kill newlines
      (goto-char (point-min))
      (while (re-search-forward "\n" (point-max) t)
        (replace-match ""))

      (setq bookmarklet
            (format "javascript:%s"
                    ;; Escape single- and double-quotes, spaces, control
                    ;; chars, unicode:
                    (url-hexify-string
                     (buffer-substring (point-min) (point-max))))))

    ;; Put the bookmarklet on the kill ring.
    (kill-new bookmarklet)

    ;; Add a comment with the bookmarklet in it.
    (goto-char start)
    (insert (format "// %s\n" bookmarklet)))

  (set-marker start nil)
  (set-marker end nil))```
@lewang
lewang commented Feb 4, 2012

I made an improved version that tries to not treat "//" in http:// as a comment.

(defun ted-create-bookmarklet-from-region (start end)
  "Create a bookmarklet of the code from START to END.

Inserts a comment with the bookmarklet, and adds the bookmarklet to the
kill ring.

Based on John Gruber's bookmarklet builder, which you can find at
http://daringfireball.net/2007/03/javascript_bookmarklet_builder
as modified by John Tantalo at https://gist.github.com/1259477"
  (interactive "r")
  (setq start (set-marker (make-marker) start))
  (setq end (set-marker (make-marker) end))
  (set-marker-insertion-type start nil)
  (set-marker-insertion-type end t)

  ;; Zap the first line if there's already a bookmarklet comment
  (goto-char start)
  (when (looking-at "^// javascript:.+\n")
    (replace-match ""))

  (let ((bookmarklet (buffer-substring start end))
        (one-space-regex (regexp-opt '("[\t]" "[ ]{2,}")))
        (zip-regex (regexp-opt '("^[ ]+" "[ ]+$" "\n"))))
    (with-temp-buffer
      (insert bookmarklet)
      ;; Kill comments.
      (goto-char (point-min))
      (while (re-search-forward "\\([^:]\\)\\(//.+\\)$" (point-max) t)
        (replace-match "\\1"))
      ;; compace to one space
      (goto-char (point-min))
      (while (re-search-forward one-space-regex (point-max) t)
        (replace-match " "))
      ;; remove other stuff
      (while (re-search-forward zip-regex (point-max) t)
        (replace-match " "))

      (setq bookmarklet
            (format "javascript:%s"
                    ;; Escape single- and double-quotes, spaces, control
                    ;; chars, unicode:
                    (url-hexify-string
                     (buffer-substring-no-properties (point-min) (point-max))))))

    ;; Put the bookmarklet on the kill ring.
    (kill-new bookmarklet)

    ;; Add a comment with the bookmarklet in it.
    (goto-char start)
    (insert (format "// %s\n" bookmarklet)))

  (set-marker start nil)
  (set-marker end nil))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment