4 |
5 |
6 | captured!
7 |
8 |
9 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "Org Capture",
4 | "version": "0.2.1",
5 | "description": "A helper for capturing things via org-protocol in emacs: First, set up: http://orgmode.org/worg/org-contrib/org-protocol.html",
6 | "homepage_url": "https://github.com/sprig/org-capture-extension",
7 |
8 | "background": {
9 | "persistent": false,
10 | "scripts": ["background.js"]
11 | },
12 |
13 | "permissions": ["activeTab", "storage"],
14 |
15 | "options_ui": {
16 | "page": "options.html"
17 | },
18 |
19 | "browser_action": {
20 | "default_icon": "org-mode-unicorn.png"
21 | },
22 |
23 | "commands": {
24 | "_execute_browser_action": {
25 | "description": "Capture current page with org-capture",
26 | "suggested_key": {
27 | "default": "Ctrl+Shift+L",
28 | "mac": "Command+Shift+L"
29 | }
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2017 Konstantin Kliakhandler
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Org Capture Settings
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Get notified after captures?
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Selected Template
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | Unselected Template
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Use New-Style links? (Recommended for Org-Mode 9.0+)
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | Debug (will produce logging messages to console)
48 |
49 |
50 |
51 |
52 |
Note: You will have to enable "Preserve Log" in the console in order to see the logged messages.
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/background.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////////
2 | // Copyright (c) 2015-2017 Konstantin Kliakhandler //
3 | // //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy //
5 | // of this software and associated documentation files (the "Software"), to deal //
6 | // in the Software without restriction, including without limitation the rights //
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
8 | // copies of the Software, and to permit persons to whom the Software is //
9 | // furnished to do so, subject to the following conditions: //
10 | // //
11 | // The above copyright notice and this permission notice shall be included in //
12 | // all copies or substantial portions of the Software. //
13 | // //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //
20 | // THE SOFTWARE. //
21 | ///////////////////////////////////////////////////////////////////////////////////
22 |
23 |
24 | chrome.runtime.onInstalled.addListener(function (details) {
25 | if (details.reason == "install")
26 | chrome.storage.sync.set(
27 | {
28 | selectedTemplate: 'p',
29 | unselectedTemplate: 'L',
30 | useNewStyleLinks: true,
31 | debug: false,
32 | overlay: true
33 | });
34 | else if ((details.reason == "update" && details.previousVersion.startsWith("0.1")))
35 | chrome.storage.sync.set(
36 | {
37 | selectedTemplate: 'p',
38 | unselectedTemplate: 'L',
39 | useNewStyleLinks: false,
40 | debug: false,
41 | overlay: true
42 | });
43 | });
44 |
45 | chrome.browserAction.onClicked.addListener(function (tab) {
46 | chrome.tabs.executeScript({file: "capture.js"});
47 | });
48 |
--------------------------------------------------------------------------------
/options.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////////
2 | // Copyright (c) 2015-2017 Konstantin Kliakhandler //
3 | // //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy //
5 | // of this software and associated documentation files (the "Software"), to deal //
6 | // in the Software without restriction, including without limitation the rights //
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
8 | // copies of the Software, and to permit persons to whom the Software is //
9 | // furnished to do so, subject to the following conditions: //
10 | // //
11 | // The above copyright notice and this permission notice shall be included in //
12 | // all copies or substantial portions of the Software. //
13 | // //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //
20 | // THE SOFTWARE. //
21 | ///////////////////////////////////////////////////////////////////////////////////
22 |
23 |
24 | // Saves options to chrome.storage.sync.
25 | function save_options() {
26 | var selTemp = document.getElementById('selTemplate').value;
27 | var unselTemp = document.getElementById('unselTemplate').value;
28 | var NewStyleP = document.getElementById('useNewStyle').checked;
29 | var debugP = document.getElementById('debug').checked;
30 | var overlayP = document.getElementById('overlay').checked;
31 |
32 | chrome.storage.sync.set({
33 | selectedTemplate: selTemp,
34 | unselectedTemplate: unselTemp,
35 | useNewStyleLinks: NewStyleP,
36 | debug: debugP,
37 | overlay: overlayP
38 | }, function() {
39 | // Update status to let user know options were saved.
40 | var status = document.getElementById('status');
41 | status.textContent = 'Options saved.';
42 | setTimeout(function() {
43 | status.textContent = '';
44 | }, 750);
45 | });
46 | }
47 |
48 | // Restores select box and checkbox state using the preferences
49 | // stored in chrome.storage.
50 | function restore_options() {
51 | // Use default value color = 'red' and likesColor = true.
52 | chrome.storage.sync.get({
53 | selectedTemplate: 'p',
54 | unselectedTemplate: 'L',
55 | useNewStyleLinks: true,
56 | debug: false,
57 | overlay: true
58 | }, function(options) {
59 | document.getElementById('unselTemplate').value = options.unselectedTemplate;
60 | document.getElementById('selTemplate').value = options.selectedTemplate;
61 | document.getElementById('useNewStyle').checked = options.useNewStyleLinks;
62 | document.getElementById('debug').checked = options.debug;
63 | document.getElementById('overlay').checked = options.overlay;
64 | });
65 | }
66 | document.addEventListener('DOMContentLoaded', restore_options);
67 | document.getElementById('save').addEventListener('click',
68 | save_options);
69 |
--------------------------------------------------------------------------------
/capture.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////////
2 | // Copyright (c) 2015-2017 Konstantin Kliakhandler //
3 | // //
4 | // Permission is hereby granted, free of charge, to any person obtaining a copy //
5 | // of this software and associated documentation files (the "Software"), to deal //
6 | // in the Software without restriction, including without limitation the rights //
7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
8 | // copies of the Software, and to permit persons to whom the Software is //
9 | // furnished to do so, subject to the following conditions: //
10 | // //
11 | // The above copyright notice and this permission notice shall be included in //
12 | // all copies or substantial portions of the Software. //
13 | // //
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //
20 | // THE SOFTWARE. //
21 | ///////////////////////////////////////////////////////////////////////////////////
22 |
23 |
24 | (function () {
25 |
26 |
27 | class Capture {
28 |
29 | createCaptureURI() {
30 | var protocol = "capture";
31 | var template = (this.selection_text != "" ? this.selectedTemplate : this.unselectedTemplate);
32 | if (this.useNewStyleLinks)
33 | return "org-protocol://"+protocol+"?template="+template+'&url='+this.encoded_url+'&title='+this.escaped_title+'&body='+this.selection_text;
34 | else
35 | return "org-protocol://"+protocol+":/"+template+'/'+this.encoded_url+'/'+this.escaped_title+'/'+this.selection_text;
36 | }
37 |
38 | constructor() {
39 | this.window = window;
40 | this.document = document;
41 | this.location = location;
42 |
43 | this.selection_text = escapeIt(window.getSelection().toString());
44 | this.encoded_url = encodeURIComponent(location.href);
45 | this.escaped_title = escapeIt(document.title);
46 |
47 | }
48 |
49 | capture() {
50 | var uri = this.createCaptureURI();
51 |
52 | if (this.debug) {
53 | logURI(uri);
54 | }
55 |
56 | location.href = uri;
57 |
58 | if (this.overlay) {
59 | toggleOverlay();
60 | }
61 | }
62 |
63 | captureIt(options) {
64 | if (chrome.runtime.lastError) {
65 | alert("Could not capture url. Error loading options: " + chrome.runtime.lastError.message);
66 | return;
67 | }
68 |
69 | if (this.selection_text) {
70 | this.template = this.selectedTemplate;
71 | this.protocol = this.selectedProtocol;
72 | } else {
73 | this.template = this.unselectedTemplate;
74 | this.protocol = this.unselectedProtocol;
75 | }
76 |
77 | for(var k in options) this[k] = options[k];
78 | this.capture();
79 | }
80 | }
81 |
82 |
83 | function replace_all(str, find, replace) {
84 | return str.replace(new RegExp(find, 'g'), replace);
85 | }
86 |
87 | function escapeIt(text) {
88 | return replace_all(replace_all(replace_all(encodeURIComponent(text), "[(]", escape("(")),
89 | "[)]", escape(")")),
90 | "[']" ,escape("'"));
91 | }
92 |
93 | function logURI(uri) {
94 | window.console.log("Capturing the following URI with new org-protocol: ", uri);
95 | return uri;
96 | }
97 |
98 | function toggleOverlay() {
99 | var outer_id = "org-capture-extension-overlay";
100 | var inner_id = "org-capture-extension-text";
101 | if (! document.getElementById(outer_id)) {
102 | var outer_div = document.createElement("div");
103 | outer_div.id = outer_id;
104 |
105 | var inner_div = document.createElement("div");
106 | inner_div.id = inner_id;
107 | inner_div.innerHTML = "Captured";
108 |
109 | outer_div.appendChild(inner_div);
110 | document.body.appendChild(outer_div);
111 |
112 | var css = document.createElement("style");
113 | css.type = "text/css";
114 | // noinspection JSAnnotator
115 | css.innerHTML = `#org-capture-extension-overlay {
116 | position: fixed; /* Sit on top of the page content */
117 | display: none; /* Hidden by default */
118 | width: 100%; /* Full width (cover the whole page) */
119 | height: 100%; /* Full height (cover the whole page) */
120 | top: 0;
121 | left: 0;
122 | right: 0;
123 | bottom: 0;
124 | background-color: rgba(0,0,0,0.2); /* Black background with opacity */
125 | z-index: 1; /* Specify a stack order in case you're using a different order for other elements */
126 | cursor: pointer; /* Add a pointer on hover */
127 | }
128 |
129 | #org-capture-extension-text{
130 | position: absolute;
131 | top: 50%;
132 | left: 50%;
133 | font-size: 50px;
134 | color: white;
135 | transform: translate(-50%,-50%);
136 | -ms-transform: translate(-50%,-50%);
137 | }`;
138 | document.body.appendChild(css);
139 | }
140 |
141 | function on() {
142 | document.getElementById(outer_id).style.display = "block";
143 | }
144 |
145 | function off() {
146 | document.getElementById(outer_id).style.display = "none";
147 | }
148 |
149 | on();
150 | setTimeout(off, 200);
151 |
152 | }
153 |
154 |
155 | var capture = new Capture();
156 | var f = function (options) {capture.captureIt(options)};
157 | chrome.storage.sync.get(null, f);
158 | })();
159 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Org Capture Extension
2 |
3 | This is an extension for Google Chrome (tm) and Firefox (tm) which adds a "Capture" button, sending the site address, title, and selected text (if any) to emacs via org-protocol, see the [Org-Mode site] for instructions for setting that up org-protocol. The extentsion itself is available at the [Chrome App Store].
4 |
5 | # Improvements
6 |
7 | - Adding options for selecting the exact structure of the links that are constructed (e.g. for the benefit of people with '///' problems).
8 | - There is always room to improve. Open a ticket with your ideas.
9 |
10 | # Example Usage
11 | [](https://www.youtube.com/watch?v=zKDHto-4wsU)
12 | 
13 |
14 | # Problems? Please [click here](#troubleshooting) or scroll to the bottom.
15 |
16 | # Detailed setup instructions
17 |
18 | ## Install the extension
19 |
20 | Either via the [Chrome App Store] or by dragging the extension folder to the "Extensions" tab in Chrome. If the latter is the chosen procedure then one needs to enable developer mode first, if I'm not mistaken. Note that if you choose to have a local-install, then you need to choose some icon and name it org-mode-unicorn.png, placing it in the extension's folder. Or, you can name it anything you want, but then you need to update manifest.json.
21 |
22 | _Note_: The first time you use the extension, Chrome will ask you allow it to run ```open ....``` (on OSX) or ```xdg-open ...``` (on Linux), or ??? (On Windows). Those are the standard system mechanisms for dispatching a file/URL to the appropriate handler, so you should accept the request.
23 |
24 | ## Set up org-protocol
25 |
26 | Detailed instructions available at [Org-Mode site].
27 |
28 | The gist of it is to make your system recognize emacsclient as the handler of ```org-protocol://``` links. In addition, one needs to set up emacs to load org-protocol and to set up capture templates.
29 |
30 | ### Register emacsclient as the ```org-protocol``` handler
31 |
32 | #### Under Linux
33 |
34 | ``` bash
35 | cat > "${HOME}/.local/share/applications/org-protocol.desktop" << EOF
36 | [Desktop Entry]
37 | Name=org-protocol
38 | Exec=emacsclient %u
39 | Type=Application
40 | Terminal=false
41 | Categories=System;
42 | MimeType=x-scheme-handler/org-protocol;
43 | EOF
44 | ```
45 |
46 | And then, for GTK-based DE:
47 | ``` bash
48 | update-desktop-database ~/.local/share/applications/
49 | ```
50 |
51 | For KDE5:
52 | ``` bash
53 | kbuildsycoca5
54 | xdg-mime default org-protocol.desktop x-scheme-handler/org-protocol
55 | ```
56 | ##### For KDE4
57 | ###### Note: This is a workaround to issue #16 - See comment [here](https://github.com/sprig/org-capture-extension/issues/16#issuecomment-305050310)
58 |
59 | Create the file
60 | */usr/local/bin/emacs-capture*
61 | ```sh
62 | #!/bin/bash
63 |
64 | # HACK: workaround for a kde-open bug (feature?) that might have
65 | # eaten a colon from our argument, om nom nom
66 | argv=()
67 | for arg in "$@"; do
68 | re='s_^org-protocol:/+capture:?/+_org-protocol://capture://_'
69 | argv+=("$(echo -n "$arg" | sed -Ez "$re")")
70 | done
71 |
72 | # Note: feel free to add any other arguments you want,
73 | # e.g. emacsclient --alternate-editor= -c "${argv[@]}"
74 | emacsclient "${argv[@]}"
75 | ```
76 | And the file
77 |
78 | *$HOME/.local/share/applications/emacs-capture.desktop*
79 | ```desktop
80 | #!/usr/bin/env xdg-open
81 | [Desktop Entry]
82 | Name=Emacs Client
83 | Exec=emacs-capture "%u"
84 | Icon=emacs-icon
85 | Type=Application
86 | Terminal=false
87 | MimeType=x-scheme-handler/org-protocol;
88 | ```
89 |
90 | Finally, run
91 |
92 | ``` bash
93 | kbuildsycoca4
94 | sudo update-desktop-database
95 | ```
96 |
97 | #### Under OSX
98 |
99 | Start Applescript Editor. Paste the following snippet:
100 |
101 | ``` applescript
102 | on emacsclient(input)
103 | do shell script "/Applications/Emacs.app/Contents/MacOS/bin-x86_64-10_9/emacsclient -n -c -a \"/Applications/Emacs.app/Contents/MacOS/Emacs\" '" & input & "'"
104 | end emacsclient
105 |
106 | on open location input
107 | emacsclient(input)
108 | end open location
109 |
110 | on open inputs
111 | repeat with raw_input in inputs
112 | set input to POSIX path of raw_input
113 | emacsclient(input)
114 | end repeat
115 | end open
116 |
117 | on run
118 | do shell script emacsclient("")
119 | end run
120 | ```
121 |
122 | Adjust the paths and save it (with 'type' as Application) under ```/Applications/EmacsClient.app``` (or whatever else you choose).
123 | Edit (with Xcode) the file ```/Applications/Emacsclient.app/Contents/Info.plist```
124 |
125 | And add there the following:
126 | ``` plist
127 | CFBundleURLTypes
128 |
129 |
130 | CFBundleURLName
131 | org-protocol
132 | CFBundleURLSchemes
133 |
134 | org-protocol
135 |
136 |
137 |
138 | ```
139 |
140 | and
141 | ``` plist
142 | CFBundleDocumentTypes
143 |
144 |
145 | CFBundleTypeExtensions
146 |
147 | *
148 |
149 | CFBundleTypeName
150 | All
151 | CFBundleTypeOSTypes
152 |
153 | ****
154 |
155 | CFBundleTypeRole
156 | Viewer
157 |
158 |
159 | ```
160 |
161 | and restart the desktop. You can also download [EmacsClient.app.zip], which I prepared in advance, if you are lazy.
162 |
163 | ##### Install EmacsClient.app with homebrew cask
164 |
165 | If you have Homebrew and [Homebrew-Cask](https://caskroom.github.io/) installed, you can also install [EmacsClient.app.zip] with `brew cask install emacsclient`
166 |
167 | ##### Frame Visibility
168 |
169 | Under some setups the emacs frame does not appear on top. @dangom [proposes a workaround using hammerspoon](https://github.com/sprig/org-capture-extension/issues/46#issuecomment-379498419):
170 |
171 | Add the following to your init.lua:
172 |
173 | ```lua
174 | function emacsclientWatcher(appName, eventType, appObject)
175 | if (eventType == hs.application.watcher.activated) then
176 | if (appName == "Emacsclient") then
177 | -- Bring Emacs to Front
178 | hs.osascript.applescript('tell application "Emacs" to activate')
179 | end
180 | end
181 | end
182 | appWatcher = hs.application.watcher.new(emacsclientWatcher)
183 | appWatcher:start()
184 | ```
185 |
186 | #### Under Windows
187 |
188 | Open the Registry Editor (Win-R, then type `regedit`). Within `HKEY_CLASSES_ROOT`, add a key called `org-protocol`. Within `org-protocol`, set the data for the string value with the name `(Default)` to be `URL:org-protocol`, add another string value with name `URL Protocol` and no data, and add a key called `shell`.
189 |
190 | Within `shell`, create a key called `open`.
191 |
192 | Within `open`, create a key called `command`.
193 |
194 | Within `command`, set the data for the string value with the name `(Default)` to `"C:\the\path\to\your\emacsclientw.exe" "%1"`, updating the path to point to your Emacs installation.
195 |
196 | If you get stuck, see [this guide to registering a protocol handler](https://msdn.microsoft.com/en-us/library/aa767914\(v=vs.85\).aspx) and look at how registries are set up for other protocol handlers (`skype`, `ftp`, etc.). Most of your pre-existing protocol handlers have more config than you need.
197 |
198 | ### Set up handlers in emacs
199 |
200 | If some text is selected before the button is clicked, then the following is sent to emacs:
201 | ```
202 | org-protocol://capture:/p///selection>
203 | ```
204 |
205 | If nothing is selected, then instead the following is sent:
206 | ```
207 | org-protocol://capture:/L//
208 | ```
209 |
210 | This means that you need to have appropriate capture templates for "L" and for "p". Example templates below:
211 |
212 | ```lisp
213 | (setq org-capture-templates `(
214 | ("p" "Protocol" entry (file+headline ,(concat org-directory "notes.org") "Inbox")
215 | "* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?")
216 | ("L" "Protocol Link" entry (file+headline ,(concat org-directory "notes.org") "Inbox")
217 | "* %? [[%:link][%:description]] \nCaptured On: %U")
218 | ))
219 | ```
220 |
221 |
222 | _Hint:_ You can put code in capture handlers via %() blocks. I use this mechanism to automatically close the newly crated frame in the L template. If anyone cares to know, I'll add the details. Another example use is below.
223 |
224 | [*Note*](https://github.com/sprig/org-capture-extension/issues/37): The `L` template above would break for links to pages having `[` and `]` characters in their page titles - notably ArXiv. To mitigae this, you can use the improved template, contributed by [Vincent Picaud](https://www.github.com/vincent-picaud):
225 |
226 | ```lisp
227 | (defun transform-square-brackets-to-round-ones(string-to-transform)
228 | "Transforms [ into ( and ] into ), other chars left unchanged."
229 | (concat
230 | (mapcar #'(lambda (c) (if (equal c ?[) ?\( (if (equal c ?]) ?\) c))) string-to-transform))
231 | )
232 |
233 | (setq org-capture-templates `(
234 | ("p" "Protocol" entry (file+headline ,(concat org-directory "notes.org") "Inbox")
235 | "* %^{Title}\nSource: %u, %c\n #+BEGIN_QUOTE\n%i\n#+END_QUOTE\n\n\n%?")
236 | ("L" "Protocol Link" entry (file+headline ,(concat org-directory "notes.org") "Inbox")
237 | "* %? [[%:link][%(transform-square-brackets-to-round-ones \"%:description\")]]\n")
238 | ))
239 | ```
240 |
241 | #### Example: closins the frame after a capture
242 |
243 | If you wish to automatically close the emacs frame after a capture, add the following template:
244 |
245 | ```lisp
246 | ("L" "Protocol Link" entry (file+headline ,(concat org-directory "notes.org") "Inbox")
247 | "* %? [[%:link][%:description]] %(progn (setq kk/delete-frame-after-capture 2) \"\")\nCaptured On: %U"
248 | :empty-lines 1)
249 | ```
250 |
251 | and in the initialization of org-mode put:
252 |
253 | ```lisp
254 | ;; Kill the frame if one was created for the capture
255 | (defvar kk/delete-frame-after-capture 0 "Whether to delete the last frame after the current capture")
256 |
257 | (defun kk/delete-frame-if-neccessary (&rest r)
258 | (cond
259 | ((= kk/delete-frame-after-capture 0) nil)
260 | ((> kk/delete-frame-after-capture 1)
261 | (setq kk/delete-frame-after-capture (- kk/delete-frame-after-capture 1)))
262 | (t
263 | (setq kk/delete-frame-after-capture 0)
264 | (delete-frame))))
265 |
266 | (advice-add 'org-capture-finalize :after 'kk/delete-frame-if-neccessary)
267 | (advice-add 'org-capture-kill :after 'kk/delete-frame-if-neccessary)
268 | (advice-add 'org-capture-refile :after 'kk/delete-frame-if-neccessary)
269 | ```
270 |
271 | # Troubleshooting
272 |
273 | Is the extension not working as you expect? i.e., is it "broken"? You need to do some investigative
274 | legwork. And if you open a ticket, provide enough information to help solve the problem!
275 |
276 | Please describe your setup. Linux? Version. OSX? Version. Emacs? Version. org-mode? Version. Chrome? Version. How did
277 | you get your system to send org-protocol links to emacs? Please provide the relevant capture templates.
278 |
279 | Please find the simplest URL for which it fails (does it work on a simple address that contain only
280 | alphanumeric characters and periods? and backslashes? and query parameters? and escaped characters?
281 | etc.). Then open the developer console and look for the debug message that the extension gives and
282 | add it to the ticket.
283 |
284 | Open a terminal and run $open "COPIED-URL" (do not skip the quotes, unless what you are pasting
285 | already has quotes around it). $open is simply open if you are on OSX and xdg-open if on
286 | linux. COPIED-URL is obviously the url you pasted here in step 1. Does it work? Congrats, you found
287 | where the problem is not (i.e. inside chrome). No? Does $open org-"protocol://capture:/p/a/b" work?
288 | No? Again you found where the problem lies not. Otherwise proceed to step 3.
289 |
290 | Call up the line you ran in the terminal with the non-working url. it will be of the form open
291 | "org-protocol://capture://PIECE1/PIECE2/ with PIECE2 usually being longer and more complex
292 | if you selected any text, and PIECE1 otherwise. Please edit the url until it is as short as possible
293 | while still breaking (Note, % should always be proceeded by two digits/letters in the ranges 0-9 and
294 | A-F so do not leave a percent sign with a single symbol following). You can probably trim one of the
295 | pieces to be just one character. Add to the ticket the smallest breaking URL.
296 |
297 | Try sending said URL directly to emacsclient, for good measure. Does it work? Again, congrats. If
298 | you are using OSX, make sure that the emacsclient which you call is the correct one!
299 |
300 | ### P.S.
301 | It is of course fine to ask for help with problems in your config as well.
302 |
303 | # License
304 | This repository is licensed as MIT license, see the LICENSE file for details.
305 |
306 | [Org-Mode site]: http://orgmode.org/worg/org-contrib/org-protocol.html
307 | [Chrome App Store]: https://chrome.google.com/webstore/detail/org-capture/kkkjlfejijcjgjllecmnejhogpbcigdc
308 | [EmacsClient.app.zip]: https://github.com/sprig/org-capture-extension/raw/master/EmacsClient.app.zip
309 |
--------------------------------------------------------------------------------