add support for tags

This commit is contained in:
Dima Gerasimov 2019-01-06 20:44:00 +00:00
parent 8f585ebc88
commit de46310d93
9 changed files with 89 additions and 49 deletions

View file

@ -1,39 +1,29 @@
* TODO some sort of append logic? e.g. don't dump immediately and add as subitems? * TODO [#B] release somewhere? not sure if necessary
* ??? * TODO [#B] docs on using
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 * TODO [#B] doesn't look like hotkey working unless you manually rebind.. wtf?
npm run flow
* DONE [#A] move server to a separate folder, systemd install script * TODO [#C] motivation
CLOSED: [2019-01-05 Sat 14:38] ** 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
* START [#A] entering additional information and tags
* 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] 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 not sure, maybe extension press should be default? control it via option?
* TODO or, add menu to extension? * TODO or, add menu to extension?
* TODO [#B] release somewhere? not sure if necessary
* TODO unsafe-eval in content security policy?? * TODO unsafe-eval in content security policy??
* TODO make manifest templated so we don't have to hardcode actions * 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? * DONE [#B] circleci?
CLOSED: [2019-01-06 Sun 13:50] CLOSED: [2019-01-06 Sun 13:50]
* DONE [#D] nicer manifest? * DONE [#D] nicer manifest?
CLOSED: [2019-01-06 Sun 13:43] 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?

View file

@ -1,6 +1,6 @@
{ {
"name": "grasp-extension", "name": "grasp-extension",
"version": "0.2.0", "version": "0.3.0",
"description": "A reliable way of capturing web pages and content", "description": "A reliable way of capturing web pages and content",
"scripts": { "scripts": {
"build": "webpack --progress --profile --colors", "build": "webpack --progress --profile --colors",

View file

@ -1,5 +1,6 @@
"""First API, local access only""" """First API, local access only"""
import json import json
import re
import hug # type: ignore import hug # type: ignore
import hug.types as T # type: ignore import hug.types as T # type: ignore
@ -23,11 +24,16 @@ def capture(
title: T.Nullable(T.text), title: T.Nullable(T.text),
selection: T.Nullable(T.text), selection: T.Nullable(T.text),
comment: T.Nullable(T.text), comment: T.Nullable(T.text),
tag_str: T.Nullable(T.text),
): ):
log("capturing", url, title, selection, comment) log("capturing", url, title, selection, comment)
heading = url heading = url
parts = [] 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): if not empty(title):
heading = title heading = title
@ -55,7 +61,7 @@ def capture(
CAPTURE_PATH, CAPTURE_PATH,
heading=heading, heading=heading,
body=body, body=body,
tags=['grasp'], tags=tags,
todo=False, todo=False,
) )
response.update({ response.update({

View file

@ -2,14 +2,14 @@
// TODO do I really need to annotate all files with @flow?? // TODO do I really need to annotate all files with @flow??
import {COMMAND_CAPTURE_SIMPLE, METHOD_CAPTURE_WITH_EXTRAS, showNotification} from './common'; import {COMMAND_CAPTURE_SIMPLE, METHOD_CAPTURE_WITH_EXTRAS, showNotification} from './common';
import {capture_url} from './config'; import {defaultTagStr, capture_url} from './options';
type Params = { type Params = {
url: string, url: string,
title: ?string, title: ?string,
selection: ?string, selection: ?string,
comment: ?string, comment: ?string,
tag_str: ?string,
} }
@ -19,7 +19,6 @@ function makeCaptureRequest(
const data = JSON.stringify(params); const data = JSON.stringify(params);
console.log(`[background] capturing ${data}`); console.log(`[background] capturing ${data}`);
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', capture_url(), true); request.open('POST', capture_url(), true);
request.onreadystatechange = () => { request.onreadystatechange = () => {
@ -51,13 +50,17 @@ function makeCaptureRequest(
request.send(data); 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 => { chrome.tabs.query({currentWindow: true, active: true }, tabs => {
const tab = tabs[0]; const tab = tabs[0];
if (tab.url == null) { if (tab.url == null) {
showNotification('ERROR: trying to capture null'); showNotification('ERROR: trying to capture null');
return; return;
} }
if (tag_str === null) {
tag_str = defaultTagStr();
}
const url: string = tab.url; const url: string = tab.url;
const title: ?string = tab.title; const title: ?string = tab.title;
@ -72,6 +75,7 @@ function capture(comment: ?string = null) {
title: title, title: title,
selection: selection, selection: selection,
comment: comment, comment: comment,
tag_str: tag_str,
}); });
}); });
}); });
@ -80,14 +84,15 @@ function capture(comment: ?string = null) {
chrome.commands.onCommand.addListener(command => { chrome.commands.onCommand.addListener(command => {
if (command === COMMAND_CAPTURE_SIMPLE) { if (command === COMMAND_CAPTURE_SIMPLE) {
capture(null); capture(null, null);
} }
}); });
chrome.runtime.onMessage.addListener((message: any, sender: chrome$MessageSender, sendResponse) => { chrome.runtime.onMessage.addListener((message: any, sender: chrome$MessageSender, sendResponse) => {
if (message.method === METHOD_CAPTURE_WITH_EXTRAS) { if (message.method === METHOD_CAPTURE_WITH_EXTRAS) {
const comment = message.comment; const comment = message.comment;
capture(comment); const tag_str = message.tag_str;
capture(comment, tag_str);
} }
}); });

View file

@ -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}`;
}

View file

@ -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}`;
}

View file

@ -5,12 +5,18 @@ import {METHOD_CAPTURE_WITH_EXTRAS} from './common';
// TODO template it in html too? // TODO template it in html too?
const BUTTON_ID = 'button_id'; const BUTTON_ID = 'button_id';
const COMMENT_ID = 'comment_id'; const COMMENT_ID = 'comment_id';
const TAGS_ID = 'tags_id';
function getComment(): HTMLInputElement { function getComment(): HTMLInputElement {
const comment = ((document.getElementById(COMMENT_ID) : any): HTMLInputElement); const comment = ((document.getElementById(COMMENT_ID) : any): HTMLInputElement);
return comment; return comment;
} }
function getTags(): HTMLInputElement {
const tags = ((document.getElementById(TAGS_ID) : any): HTMLInputElement);
return tags;
}
function getButton(): HTMLElement { function getButton(): HTMLElement {
const button = ((document.getElementById(BUTTON_ID): any): HTMLElement); const button = ((document.getElementById(BUTTON_ID): any): HTMLElement);
return button; return button;
@ -18,25 +24,48 @@ function getButton(): HTMLElement {
function submitComment () { function submitComment () {
const comment_text = getComment().value; const comment_text = getComment().value;
const tag_str = getTags().value;
// TODO focus // TODO focus
chrome.runtime.sendMessage({ chrome.runtime.sendMessage({
'method': METHOD_CAPTURE_WITH_EXTRAS, 'method': METHOD_CAPTURE_WITH_EXTRAS,
'comment': comment_text, 'comment': comment_text,
'tag_str': tag_str,
}, resp => { }, resp => {
console.log("[popup] captured!"); console.log("[popup] captured!");
}); });
window.close(); window.close();
} }
function setupPage () {
const comment = getComment();
comment.focus();
// $FlowFixMe // $FlowFixMe
comment.addEventListener('keydown', e => { function ctrlEnterSubmit(e) {
if (e.ctrlKey && e.key === 'Enter') { if (e.ctrlKey && e.key === 'Enter') {
submitComment(); 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();
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); getButton().addEventListener('click', submitComment);
} }

View file

@ -4,7 +4,10 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
</head> </head>
<body> <body>
<!-- TODO ugh didn't work -->
<!-- <%= htmlWebpackPlugin.options.ids.tags %> -->
<div><textarea id="comment_id" rows="4" cols="50" placeholder="Enter your comments; press Ctrl-Enter to capture"></textarea></div> <div><textarea id="comment_id" rows="4" cols="50" placeholder="Enter your comments; press Ctrl-Enter to capture"></textarea></div>
<div><textarea id="tags_id" rows="1" cols="50">grasp</textarea></div>
<div><button id="button_id" type="button" align="right">capture!</button></div> <div><button id="button_id" type="button" align="right">capture!</button></div>
</body> </body>
</html> </html>

View file

@ -81,7 +81,7 @@ var options = {
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "popup.html"), template: path.join(__dirname, "src", "popup.html"),
filename: "popup.html", filename: "popup.html",
chunks: ["popup"] chunks: ["popup"],
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: path.join(__dirname, "src", "options.html"), template: path.join(__dirname, "src", "options.html"),