add support for tags
This commit is contained in:
parent
8f585ebc88
commit
de46310d93
36
TODO.org
36
TODO.org
|
@ -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?
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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}`;
|
|
||||||
}
|
|
|
@ -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}`;
|
||||||
|
}
|
|
@ -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 () {
|
// $FlowFixMe
|
||||||
const comment = getComment();
|
function ctrlEnterSubmit(e) {
|
||||||
comment.focus();
|
|
||||||
// $FlowFixMe
|
|
||||||
comment.addEventListener('keydown', 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
Loading…
Reference in a new issue