arcocene

org-protocol

How I make a quick post from from Chrome via org-protocol.

Set up org-protocol

Follow the org-protocol install instructions. In addition to the Emacs and Gnome setup sections, I followed these instructions to get xdg-open working. I had to hack xdg-open because of this bug. I copied the existing one to ~/bin/ and added a couple lines based on this hack

diff -u /usr/bin/xdg-open ~/bin/xdg-open
--- /usr/bin/xdg-open   2011-10-03 21:49:38.000000000 -0700
+++ /home/foo/bin/xdg-open      2013-03-04 15:26:38.399395783 -0800
@@ -358,10 +358,16 @@

 open_gnome()
 {
-    if gvfs-open --help 2>/dev/null 1>&2; then
-        gvfs-open "$1"
-    else
-        gnome-open "$1"
+    # Handle org-protocol
+    if (echo "$1" | grep -q '^org-protocol://'); then
+        echo "emacsclient $1"
+        emacsclient "$1"
+    else        
+        if gvfs-open --help 2>/dev/null 1>&2; then
+            gvfs-open "$1"
+        else
+            gnome-open "$1"
+        fi
     fi

     if [ $? -eq 0 ]; then
@@ -411,5 +417,11 @@

 open_generic()
 {
+    # Handle org-protocol
+    if (echo "$1" | grep -q '^org-protocol://'); then
+        emacsclient "$1"
+        exit_success
+    fi
+        
     # Paths or file:// URLs
     if (echo "$1" | grep -q '^file://' ||
         ! echo "$1" | egrep -q '^[a-zA-Z+\.\-]+:'); then

Set up chrome.

I tested with the store-link sub-protocol that everyone seems to use. Once that's known to work, we can add our own version that creates a new post.

Add a custom sub-protocol to create a new post.

(defun mumblr-create-post-from-link ()
  "Create a new post from a link passed in via org-protocol.")

(defun org-protocol-remember2 (info)
  (if (and (boundp 'org-stored-links)
           (fboundp 'org-remember))
      (let* ((parts (org-protocol-split-data info t))
             (template (or (and (= 1 (length (car parts))) (pop parts))
                           org-protocol-default-template-key))
             (url (org-protocol-sanitize-uri (car parts)))
             (type (if (string-match "^\\([a-z]+\\):" url)
                       (match-string 1 url)))
                (title (or (cadr parts) ""))
                (region (or (caddr parts) "sfsfsf"))
                (orglink (org-make-link-string
                          url (if (string-match "[^[:space:]]" title) title url)))
                remember-annotation-functions)
              (setq org-stored-links
                    (cons (list url title) org-stored-links))
               (kill-new orglink)
              (org-store-link-props :type type
                                    :link url
                                    :description title
                                    :region region)
              ;;(raise-frame)
              (select-frame-set-input-focus (selected-frame))
              (org-remember nil (string-to-char template))
              (lower-frame)
              ;;(delete-frame) ; uncomment this if you use -c in the call to emacsclient
              )
             (message "Org-mode not loaded."))
  nil)


(defun org-protocol-outlook (info)
  (if (and (boundp 'org-stored-links)
           (or (fboundp org-outlook-capture))
           (org-protocol-do-outlook-capture info org-outlook-capture))
      (message "Org-mode not loaded."))
  nil)
(setq org-stored-links '())

(defun org-protocol-do-outlook-capture (info capture-func)
  "Support `org-capture' and `org-remember' alike.
CAPTURE-FUNC is either the symbol `org-remember' or `org-capture'."
  (let* ((parts (org-protocol-split-data info t))
         (template (or (and (= 1 (length (car parts))) (pop parts))
                       org-outlook-protocol-default-template-key))
         (url (concat "outlook:" (org-protocol-sanitize-uri (car parts))))
         (type (if (string-match "^\\([a-z]+\\):" url)
                   (match-string 1 url)))
         (title (or (cadr parts) ""))
         (sender (or (caddr parts) ""))
         (sender-email (or (cadddr parts) ""))
         (region "")
         (orglink (org-make-link-string
                   url (if (string-match "[^[:space:]]" (format "%s (%s)" title sender)) (format "%s (%s)" title sender) url)))
         (org-capture-link-is-already-stored t) ;; avoid call to org-store-link
         remember-annotation-functions)
    ;(with-temp-buffer
    ;  (clipboard-yank)
    ;  (setq region (buffer-substring (point-min) (point-max))))
    (setq org-stored-links
          (cons (list url title) org-stored-links))
    (kill-new orglink)
    (org-store-link-props :type type
                          :link url
                          :sender sender
                          :sender-email sender-email
                          :description title
                          :title title
                          :annotation orglink
                                        ;:initial region
                          )
    (raise-frame)
    (funcall capture-func nil template)))

(add-to-list 'org-protocol-protocol-alist
             '(("mumblr-post"
                :protocol "mumblr"
                :function mumblr-create-post-from-link)))

Add a bookmarklet for the new sub-protocol

I simplified this JS for getting the selection HTML to something small but Chrome-only.

(All on one line)

javascript:location.href='org-protocol://image-post://'+
  encodeURIComponent(location.href)+'/'+
  encodeURIComponent(document.title)+'/'+
  encodeURIComponent(window.getSelection())

javascript:(function() {
    var html = '';
    var sel = window.getSelection();
    if (sel.rangeCount > 0) {
        var range = sel.getRangeAt(0);
        var clone = range.cloneContents();
        var div = document.createElement('div');
        div.appendChild(clone);
        html = div.innerHTML;
    }
    location.href='org-protocol://image-post://'+
        encodeURIComponent(location.href)+'/'+
        encodeURIComponent(document.title)+'/'+
        encodeURIComponent(html);
}())

javascript:(function(){function%20R(w){try{var%20d=w.document,j,i,t,T,N,b,r=1,C;for(j=0;t=["object","embed","applet","iframe"][j];++j){T=d.getElementsByTagName(t);for(i=T.length-1;(i+1)&&(N=T[i]);--i)if(j!=3||!R((C=N.contentWindow)?C:N.contentDocument.defaultView)){b=d.createElement("div");b.style.width=N.width;%20b.style.height=N.height;b.innerHTML="%3Cdel%3E"+(j==3?"third-party%20"+t:t)+"%3C/del%3E";N.parentNode.replaceChild(b,N);}}}catch(E){r=0}return%20r}R(self);var%20i,x;for(i=0;x=frames[i];++i)R(x)})()
2013-01-29 Tue 09:59