diff --git a/TODO.org b/TODO.org index a1d5a78..016fb13 100644 --- a/TODO.org +++ b/TODO.org @@ -1,39 +1,29 @@ -* TODO some sort of append logic? e.g. don't dump immediately and add as subitems? -* ??? -npm install --save-dev @babel/core @babel/preset-env -npm install babel-preset-stage-0 -npm install babel-preset-env -- wtf is that shit?? - -npm run build - -npm run flow - -* DONE [#A] move server to a separate folder, systemd install script - CLOSED: [2019-01-05 Sat 14:38] +* TODO [#B] release somewhere? not sure if necessary +* TODO [#B] docs on using -* START [#A] entering additional information and tags +* TODO [#B] doesn't look like hotkey working unless you manually rebind.. wtf? -* TODO the benefit is that you can also add anything as a backend, e.g. you might be more of markdown fan or todo.txt - -* TODO shortcut for org mode to create timestsamped note +* TODO [#C] motivation +** TODO the benefit is that you can also add anything as a backend, e.g. you might be more of markdown fan or todo.txt + +* TODO [#C] how to test it? try on different pages? +* TODO [#C] some sort of append logic? e.g. don't dump immediately and add as subitems? +* TODO [#D] do not minfy for dev * TODO not sure, maybe extension press should be default? control it via option? * TODO or, add menu to extension? -* TODO [#B] release somewhere? not sure if necessary * TODO unsafe-eval in content security policy?? * TODO make manifest templated so we don't have to hardcode actions -* TODO [#B] docs on using +* DONE [#A] move server to a separate folder, systemd install script + CLOSED: [2019-01-05 Sat 14:38] +* DONE [#A] entering additional information and tags + CLOSED: [2019-01-06 Sun 20:41] + * DONE [#B] circleci? CLOSED: [2019-01-06 Sun 13:50] * DONE [#D] nicer manifest? CLOSED: [2019-01-06 Sun 13:43] -* TODO [#D] do not minfy for dev -* TODO [#C] motivation -* TODO [#B] doesn't look like hotkey working unless you manually rebind.. wtf? - - -* TODO [#C] how to test it? try on different pages? diff --git a/package.json b/package.json index e6f4dbb..6c5d439 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grasp-extension", - "version": "0.2.0", + "version": "0.3.0", "description": "A reliable way of capturing web pages and content", "scripts": { "build": "webpack --progress --profile --colors", diff --git a/server/server.py b/server/server.py index 9232572..29113e0 100644 --- a/server/server.py +++ b/server/server.py @@ -1,5 +1,6 @@ """First API, local access only""" import json +import re import hug # type: ignore import hug.types as T # type: ignore @@ -23,11 +24,16 @@ def capture( title: T.Nullable(T.text), selection: T.Nullable(T.text), comment: T.Nullable(T.text), + tag_str: T.Nullable(T.text), ): log("capturing", url, title, selection, comment) heading = url parts = [] + tags = [] + if not empty(tag_str): + tags = re.split('[\s,]', tag_str) + tags = [t for t in tags if not empty(t)] # just in case if not empty(title): heading = title @@ -55,7 +61,7 @@ def capture( CAPTURE_PATH, heading=heading, body=body, - tags=['grasp'], + tags=tags, todo=False, ) response.update({ diff --git a/src/js/background.js b/src/js/background.js index 6094432..d32884f 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -2,14 +2,14 @@ // TODO do I really need to annotate all files with @flow?? import {COMMAND_CAPTURE_SIMPLE, METHOD_CAPTURE_WITH_EXTRAS, showNotification} from './common'; -import {capture_url} from './config'; - +import {defaultTagStr, capture_url} from './options'; type Params = { url: string, title: ?string, selection: ?string, comment: ?string, + tag_str: ?string, } @@ -19,7 +19,6 @@ function makeCaptureRequest( const data = JSON.stringify(params); console.log(`[background] capturing ${data}`); - var request = new XMLHttpRequest(); request.open('POST', capture_url(), true); request.onreadystatechange = () => { @@ -51,13 +50,17 @@ function makeCaptureRequest( request.send(data); } -function capture(comment: ?string = null) { +function capture(comment: ?string = null, tag_str: ?string = null) { chrome.tabs.query({currentWindow: true, active: true }, tabs => { const tab = tabs[0]; if (tab.url == null) { showNotification('ERROR: trying to capture null'); return; } + if (tag_str === null) { + tag_str = defaultTagStr(); + } + const url: string = tab.url; const title: ?string = tab.title; @@ -72,6 +75,7 @@ function capture(comment: ?string = null) { title: title, selection: selection, comment: comment, + tag_str: tag_str, }); }); }); @@ -80,14 +84,15 @@ function capture(comment: ?string = null) { chrome.commands.onCommand.addListener(command => { if (command === COMMAND_CAPTURE_SIMPLE) { - capture(null); + capture(null, null); } }); chrome.runtime.onMessage.addListener((message: any, sender: chrome$MessageSender, sendResponse) => { if (message.method === METHOD_CAPTURE_WITH_EXTRAS) { const comment = message.comment; - capture(comment); + const tag_str = message.tag_str; + capture(comment, tag_str); } }); diff --git a/src/js/config.js b/src/js/config.js deleted file mode 100644 index f6da0bb..0000000 --- a/src/js/config.js +++ /dev/null @@ -1,9 +0,0 @@ -/* @flow */ - -// TODO configure port in options? -const capture_endpoint = 'capture'; -const port = 8090; - -export function capture_url (): string { - return `http://localhost:${port}/${capture_endpoint}`; -} diff --git a/src/js/options.js b/src/js/options.js index e69de29..ab6c369 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -0,0 +1,16 @@ +/* @flow */ + +const capture_endpoint = 'capture'; + +function port(): string { + return "8090"; +} + +// none means do not use tags +export function defaultTagStr (): ?string { + return 'grasp'; +} + +export function capture_url (): string { + return `http://localhost:${port()}/${capture_endpoint}`; +} diff --git a/src/js/popup.js b/src/js/popup.js index 17acab8..d15361f 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -5,12 +5,18 @@ import {METHOD_CAPTURE_WITH_EXTRAS} from './common'; // TODO template it in html too? const BUTTON_ID = 'button_id'; const COMMENT_ID = 'comment_id'; +const TAGS_ID = 'tags_id'; function getComment(): HTMLInputElement { const comment = ((document.getElementById(COMMENT_ID) : any): HTMLInputElement); return comment; } +function getTags(): HTMLInputElement { + const tags = ((document.getElementById(TAGS_ID) : any): HTMLInputElement); + return tags; +} + function getButton(): HTMLElement { const button = ((document.getElementById(BUTTON_ID): any): HTMLElement); return button; @@ -18,25 +24,48 @@ function getButton(): HTMLElement { function submitComment () { const comment_text = getComment().value; + const tag_str = getTags().value; // TODO focus chrome.runtime.sendMessage({ 'method': METHOD_CAPTURE_WITH_EXTRAS, 'comment': comment_text, + 'tag_str': tag_str, }, resp => { console.log("[popup] captured!"); }); window.close(); } +// $FlowFixMe +function ctrlEnterSubmit(e) { + if (e.ctrlKey && e.key === 'Enter') { + submitComment(); + } +} + + +// https://stackoverflow.com/a/6003829/706389 +function moveCaretToEnd(el) { + if (typeof el.selectionStart == "number") { + el.selectionStart = el.selectionEnd = el.value.length; + } else if (typeof el.createTextRange != "undefined") { + el.focus(); + var range = el.createTextRange(); + range.collapse(false); + range.select(); + } +} + + function setupPage () { const comment = getComment(); comment.focus(); - // $FlowFixMe - comment.addEventListener('keydown', e => { - if (e.ctrlKey && e.key === 'Enter') { - submitComment(); - } - }); + comment.addEventListener('keydown', ctrlEnterSubmit); + + const tags = getTags(); + tags.addEventListener('keydown', ctrlEnterSubmit); + tags.addEventListener('focus', () => moveCaretToEnd(tags)); // to put cursor to the end of tags when tabbed + getButton().addEventListener('click', submitComment); } diff --git a/src/popup.html b/src/popup.html index 0133f81..411af8a 100644 --- a/src/popup.html +++ b/src/popup.html @@ -4,7 +4,10 @@
+ + - + +