diff --git a/main.go b/main.go index d25f72f..a9ac728 100644 --- a/main.go +++ b/main.go @@ -23,9 +23,9 @@ import ( "text/template" ) -const VERSION = "v2" +const VERSION = "v1" const CONTEXT_USER = 1 -const SYNC_PAGINATION = 200 +const SYNC_PAGINATION = 100 var ( FlagGenerate bool @@ -132,7 +132,6 @@ func main() { // {{{ http.HandleFunc("/notes2", pageNotes2) http.HandleFunc("/login", pageLogin) http.HandleFunc("/sync", pageSync) - http.HandleFunc("/offline", pageOffline) http.HandleFunc("/user/authenticate", AuthManager.AuthenticationHandler) @@ -227,15 +226,6 @@ func pageServiceWorker(w http.ResponseWriter, r *http.Request) { // {{{ return } } // }}} -func pageOffline(w http.ResponseWriter, r *http.Request) { // {{{ - page := NewPage("offline") - - err := Webengine.Render(page, w, r) - if err != nil { - w.Write([]byte(err.Error())) - return - } -} // }}} func pageLogin(w http.ResponseWriter, r *http.Request) { // {{{ page := NewPage("login") @@ -279,11 +269,9 @@ func actionSyncFromServer(w http.ResponseWriter, r *http.Request) { // {{{ return } - /* Log.Debug("/sync/from_server", "num_nodes", len(nodes), "maxSeq", maxSeq) foo, _ := json.Marshal(nodes) os.WriteFile(fmt.Sprintf("/tmp/nodes-%d.json", offset), foo, 0644) - */ j, _ := json.Marshal(struct { OK bool @@ -300,6 +288,7 @@ func actionSyncFromServerCount(w http.ResponseWriter, r *http.Request) { // {{{ user := getUser(r) changedFrom, _ := strconv.Atoi(r.PathValue("sequence")) + Log.Debug("FOO", "UUID", user.ClientUUID, "changedFrom", changedFrom) count, err := NodesCount(user.UserID, uint64(changedFrom), user.ClientUUID) if err != nil { Log.Error("/sync/from_server/count", "error", err) @@ -345,14 +334,9 @@ func actionSyncToServer(w http.ResponseWriter, r *http.Request) { // {{{ return } - _, err = db.Exec(`CALL add_nodes($1, $2, $3::jsonb)`, user.UserID, user.ClientUUID, request.NodeData) - if err != nil { - Log.Error("sync", "error", err) - httpError(w, err) - return - } + db.Exec(`CALL add_nodes($1, $2, $3::jsonb)`, user.UserID, user.ClientUUID, request.NodeData) - responseData(w, map[string]any{ + responseData(w, map[string]interface{}{ "OK": true, }) } // }}} diff --git a/sql/00006.sql b/sql/00006.sql index 453b260..6b0ea9b 100644 --- a/sql/00006.sql +++ b/sql/00006.sql @@ -1 +1,16 @@ -DROP INDEX public.node_uuid_idx; +CREATE TABLE public.node_history ( + id serial4 NOT NULL, + user_id int4 NOT NULL, + uuid bpchar(36) NOT NULL, + parents varchar[] NULL, + created timestamptz NOT NULL, + updated timestamptz NOT NULL, + name varchar(256) NOT NULL, + "content" text NOT NULL, + content_encrypted text NOT NULL, + markdown bool DEFAULT false NOT NULL, + client bpchar(36) DEFAULT ''::bpchar NOT NULL, + CONSTRAINT node_history_pk PRIMARY KEY (id), + CONSTRAINT node_history_user_fk FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE RESTRICT ON UPDATE RESTRICT +); +CREATE INDEX node_history_uuid_idx ON public.node USING btree (uuid); diff --git a/sql/00011.sql b/sql/00011.sql deleted file mode 100644 index 5b67839..0000000 --- a/sql/00011.sql +++ /dev/null @@ -1,166 +0,0 @@ -CREATE OR REPLACE PROCEDURE add_nodes(p_user_id int4, p_client_uuid varchar, p_nodes jsonb) -LANGUAGE PLPGSQL AS $$ - -DECLARE - node_data jsonb; - node_updated timestamptz; - db_updated timestamptz; - db_uuid bpchar; - db_client bpchar; - db_client_seq int; - node_uuid bpchar; - parent_uuid bpchar; - -BEGIN - RAISE NOTICE '--------------------------'; - FOR node_data IN SELECT * FROM jsonb_array_elements(p_nodes) - LOOP - node_uuid = (node_data->>'UUID')::bpchar; - node_updated = (node_data->>'Updated')::timestamptz; - - IF node_data->>'ParentUUID' = '00000000-0000-0000-0000-000000000000' THEN - parent_uuid = NULL; - ELSE - parent_uuid = node_data->>'ParentUUID'; - END IF; - - /* Retrieve the current modified timestamp for this node from the database. */ - SELECT - uuid, updated, client, client_sequence - INTO - db_uuid, db_updated, db_client, db_client_seq - FROM public."node" - WHERE - user_id = p_user_id AND - uuid = node_uuid; - - /* Is the node not in database? It needs to be created. */ - IF db_uuid IS NULL THEN - RAISE NOTICE '01 New node %', node_uuid; - INSERT INTO public."node" ( - user_id, "uuid", parent_uuid, created, updated, - "name", "content", markdown, "content_encrypted", - client, client_sequence - ) - VALUES( - p_user_id, - node_uuid, - parent_uuid, - (node_data->>'Created')::timestamptz, - (node_data->>'Updated')::timestamptz, - (node_data->>'Name')::varchar, - (node_data->>'Content')::text, - (node_data->>'Markdown')::bool, - '', /* content_encrypted */ - p_client_uuid, - (node_data->>'ClientSequence')::int - ); - CONTINUE; - END IF; - - - /* The client could send a specific node again if it didn't receive the OK from this procedure before. */ - IF db_updated = node_updated AND db_client = p_client_uuid AND db_client_seq = (node_data->>'ClientSequence')::int THEN - RAISE NOTICE '04, already recorded, %, %', db_client, db_client_seq; - CONTINUE; - END IF; - - /* Determine if the incoming node data is to go into history or replace the current node. */ - IF db_updated > node_updated THEN - RAISE NOTICE '02 DB newer, % > % (%))', db_updated, node_updated, node_uuid; - /* Incoming node is going straight to history since it is older than the current node. */ - INSERT INTO node_history( - user_id, "uuid", parents, created, updated, - "name", "content", markdown, "content_encrypted", - client, client_sequence - ) - VALUES( - p_user_id, - node_uuid, - (jsonb_populate_record(null::json_ancestor_array, node_data))."Ancestors", - (node_data->>'Created')::timestamptz, - (node_data->>'Updated')::timestamptz, - (node_data->>'Name')::varchar, - (node_data->>'Content')::text, - (node_data->>'Markdown')::bool, - '', /* content_encrypted */ - p_client_uuid, - (node_data->>'ClientSequence')::int - ) - ON CONFLICT (client, client_sequence) - DO NOTHING; - ELSE - RAISE NOTICE '03 Client newer, % > % (%, %)', node_updated, db_updated, node_uuid, (node_data->>'ClientSequence'); - /* Incoming node is newer and will replace the current node. - * - * The current node is copied to the node_history table and then modified in place - * with the incoming data. */ - INSERT INTO node_history( - user_id, "uuid", parents, - created, updated, "name", "content", markdown, "content_encrypted", - client, client_sequence - ) - SELECT - user_id, - "uuid", - ( - WITH RECURSIVE nodes AS ( - SELECT - uuid, - COALESCE(parent_uuid, '') AS parent_uuid, - name, - 0 AS depth - FROM node - WHERE - uuid = node_uuid - - UNION - - SELECT - n.uuid, - COALESCE(n.parent_uuid, '') AS parent_uuid, - n.name, - nr.depth+1 AS depth - FROM node n - INNER JOIN nodes nr ON n.uuid = nr.parent_uuid - ) - SELECT ARRAY ( - SELECT name - FROM nodes - ORDER BY depth DESC - OFFSET 1 /* discard itself */ - ) - ), - created, - updated, - name, - content, - markdown, - content_encrypted, - client, - client_sequence - FROM public."node" - WHERE - user_id = p_user_id AND - uuid = node_uuid - ON CONFLICT (client, client_sequence) - DO NOTHING; - - /* Current node in database is updated with incoming data. */ - UPDATE public."node" - SET - updated = (node_data->>'Updated')::timestamptz, - updated_seq = nextval('node_updates'), - name = (node_data->>'Name')::varchar, - content = (node_data->>'Content')::text, - markdown = (node_data->>'Markdown')::bool, - client = p_client_uuid, - client_sequence = (node_data->>'ClientSequence')::int - WHERE - user_id = p_user_id AND - uuid = node_uuid; - END IF; - - END LOOP; -END -$$; diff --git a/sql/00012.sql b/sql/00012.sql deleted file mode 100644 index e62f011..0000000 --- a/sql/00012.sql +++ /dev/null @@ -1,166 +0,0 @@ -CREATE OR REPLACE PROCEDURE add_nodes(p_user_id int4, p_client_uuid varchar, p_nodes jsonb) -LANGUAGE PLPGSQL AS $$ - -DECLARE - node_data jsonb; - node_updated timestamptz; - db_updated timestamptz; - db_uuid bpchar; - db_client bpchar; - db_client_seq int; - node_uuid bpchar; - parent_uuid_nullable bpchar; - -BEGIN - RAISE NOTICE '--------------------------'; - FOR node_data IN SELECT * FROM jsonb_array_elements(p_nodes) - LOOP - node_uuid = (node_data->>'UUID')::bpchar; - node_updated = (node_data->>'Updated')::timestamptz; - - IF node_data->>'ParentUUID' = '00000000-0000-0000-0000-000000000000' THEN - parent_uuid_nullable = NULL; - ELSE - parent_uuid_nullable = node_data->>'ParentUUID'; - END IF; - - /* Retrieve the current modified timestamp for this node from the database. */ - SELECT - uuid, updated, client, client_sequence - INTO - db_uuid, db_updated, db_client, db_client_seq - FROM public."node" - WHERE - user_id = p_user_id AND - uuid = node_uuid; - - /* Is the node not in database? It needs to be created. */ - IF db_uuid IS NULL THEN - RAISE NOTICE '01 New node %', node_uuid; - INSERT INTO public."node" ( - user_id, "uuid", parent_uuid, created, updated, - "name", "content", markdown, "content_encrypted", - client, client_sequence - ) - VALUES( - p_user_id, - node_uuid, - parent_uuid_nullable, - (node_data->>'Created')::timestamptz, - (node_data->>'Updated')::timestamptz, - (node_data->>'Name')::varchar, - (node_data->>'Content')::text, - (node_data->>'Markdown')::bool, - '', /* content_encrypted */ - p_client_uuid, - (node_data->>'ClientSequence')::int - ); - CONTINUE; - END IF; - - - /* The client could send a specific node again if it didn't receive the OK from this procedure before. */ - IF db_updated = node_updated AND db_client = p_client_uuid AND db_client_seq = (node_data->>'ClientSequence')::int THEN - RAISE NOTICE '04, already recorded, %, %', db_client, db_client_seq; - CONTINUE; - END IF; - - /* Determine if the incoming node data is to go into history or replace the current node. */ - IF db_updated > node_updated THEN - RAISE NOTICE '02 DB newer, % > % (%))', db_updated, node_updated, node_uuid; - /* Incoming node is going straight to history since it is older than the current node. */ - INSERT INTO node_history( - user_id, "uuid", parents, created, updated, - "name", "content", markdown, "content_encrypted", - client, client_sequence - ) - VALUES( - p_user_id, - node_uuid, - (jsonb_populate_record(null::json_ancestor_array, node_data))."Ancestors", - (node_data->>'Created')::timestamptz, - (node_data->>'Updated')::timestamptz, - (node_data->>'Name')::varchar, - (node_data->>'Content')::text, - (node_data->>'Markdown')::bool, - '', /* content_encrypted */ - p_client_uuid, - (node_data->>'ClientSequence')::int - ) - ON CONFLICT (client, client_sequence) - DO NOTHING; - ELSE - RAISE NOTICE '03 Client newer, % > % (%, %)', node_updated, db_updated, node_uuid, (node_data->>'ClientSequence'); - /* Incoming node is newer and will replace the current node. - * - * The current node is copied to the node_history table and then modified in place - * with the incoming data. */ - INSERT INTO node_history( - user_id, "uuid", parents, - created, updated, "name", "content", markdown, "content_encrypted", - client, client_sequence - ) - SELECT - user_id, - "uuid", - ( - WITH RECURSIVE nodes AS ( - SELECT - uuid, - COALESCE(parent_uuid, '') AS parent_uuid, - name, - 0 AS depth - FROM node - WHERE - uuid = node_uuid - - UNION - - SELECT - n.uuid, - COALESCE(n.parent_uuid, '') AS parent_uuid, - n.name, - nr.depth+1 AS depth - FROM node n - INNER JOIN nodes nr ON n.uuid = nr.parent_uuid - ) - SELECT ARRAY ( - SELECT name - FROM nodes - ORDER BY depth DESC - OFFSET 1 /* discard itself */ - ) - ), - created, - updated, - name, - content, - markdown, - content_encrypted, - client, - client_sequence - FROM public."node" - WHERE - user_id = p_user_id AND - uuid = node_uuid - ON CONFLICT (client, client_sequence) - DO NOTHING; - - /* Current node in database is updated with incoming data. */ - UPDATE public."node" - SET - updated = (node_data->>'Updated')::timestamptz, - updated_seq = nextval('node_updates'), - name = (node_data->>'Name')::varchar, - content = (node_data->>'Content')::text, - markdown = (node_data->>'Markdown')::bool, - client = p_client_uuid, - client_sequence = (node_data->>'ClientSequence')::int - WHERE - user_id = p_user_id AND - uuid = node_uuid; - END IF; - - END LOOP; -END -$$; diff --git a/static/css/login.css b/static/css/login.css index 7e19cb8..88a9140 100644 --- a/static/css/login.css +++ b/static/css/login.css @@ -1,44 +1,37 @@ -@import "theme.css"; - #app { - display: grid; - justify-items: center; - margin-top: 128px; + display: grid; + justify-items: center; + margin-top: 128px; } - #logo { - margin-bottom: 48px; + margin-bottom: 48px; } - #box { - display: grid; - grid-gap: 16px 0; - justify-items: center; - width: 300px; - padding: 48px 0px; - background-color: #fff; - box-shadow: 0px 20px 52px -33px rgba(0,0,0,0.75); - border-left: 8px solid var(--color3); - - input { - padding: 4px 8px; - font-size: 1em; - width: calc(100% - 64px); - border: 1px solid #aaa; - border-radius: 4px; - } - - button { - padding: 6px 16px; - font-size: 1em; - border-radius: 4px; - border: none; - background-color: var(--color1); - color: #fff; - } - - #error { - color: #c33; - margin-top: 16px; - } + display: grid; + grid-gap: 16px 0; + justify-items: center; + width: 300px; + padding: 48px 0px; + background-color: #fff; + box-shadow: 0px 20px 52px -33px rgba(0, 0, 0, 0.75); + border-left: 8px solid #666; +} +#box input { + padding: 4px 8px; + font-size: 1em; + width: calc(100% - 64px); + border: 1px solid #aaa; + border-radius: 4px; +} +#box button { + padding: 6px 16px; + font-size: 1em; + border-radius: 4px; + border: none; + background-color: #fe5f55; + color: #fff; +} +#box #error { + color: #c33; + margin-top: 16px; } diff --git a/static/css/main.css b/static/css/main.css index a8924d9..75f1925 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -1,29 +1,23 @@ -@import "theme.css"; - html { - box-sizing: border-box; - background: var(--color2); - font-family: "Liberation Mono", monospace; - font-size: 14px; - margin: 0px; - padding: 0px; + box-sizing: border-box; + background: #efede8; + font-family: "Liberation Mono", monospace; + font-size: 14px; + margin: 0px; + padding: 0px; } - body { - margin: 0px; - padding: 0px; + margin: 0px; + padding: 0px; } - *, *:before, *:after { - box-sizing: inherit; + box-sizing: inherit; } - *:focus { - outline: none; + outline: none; } - [onClick] { - cursor: pointer; + cursor: pointer; } diff --git a/static/css/markdown.css b/static/css/markdown.css deleted file mode 100644 index 84eb0b2..0000000 --- a/static/css/markdown.css +++ /dev/null @@ -1,76 +0,0 @@ -.el-node-markdown { - h1 { - border-bottom: 1px solid #ccc; - margin-top: 32px; - margin-bottom: 8px; - - display: inline-block; - font-size: 1.25em; - - border-radius: 8px; - color: #fff; - background-color: var(--color1); - padding: 4px 12px; - - &:first-child { - margin-top: 32px; - } - } - - h2 { - font-size: 1.25em; - margin-top: 32px; - margin-bottom: 0px; - color: var(--color1); - } - - h3:before { - font-size: 1.0em; - content: "> "; - color: var(--color1); - } - - p { - line-height: 150%; - } - - img { - max-width: var(--thumbnail-width); - max-height: var(--thumbnail-height); - } - - table { - border: 1px solid #ccc; - border-collapse: collapse; - - th { - text-align: left; - padding: 8px; - } - - th, - td { - border: 1px solid #ccc; - padding: 8px; - } - } - - code { - background-color: #f8f8f8; - border: 1px solid #ccc; - padding: 2px 4px; - border-radius: 4px; - } - - pre { - background-color: #f8f8f8; - border: 1px solid #ccc; - padding: 8px; - border-radius: 4px; - - code { - border: unset; - padding: unset; - } - } -} diff --git a/static/css/notes2.css b/static/css/notes2.css index 71737dd..b6b0963 100644 --- a/static/css/notes2.css +++ b/static/css/notes2.css @@ -1,390 +1,264 @@ -@import "theme.css"; - -:root { - --content-width: 900px; - --thumbnail-width: 300px; - --thumbnail-height: 100px; -} - html { - background-color: #fff; + background-color: #fff; } - #notes2 { - min-height: 100vh; - - display: grid; - grid-template-areas: - "tree hum crumbs crumbs ding" - "tree hum name name ding" - "tree hum sync functions ding" - "tree hum content content ding" - "tree hum blank blank ding" - ; - grid-template-columns: min-content minmax(16px, 1fr) minmax(min-content, 820px) 80px minmax(16px, 1fr); - grid-template-rows: - min-content min-content 48px 1fr; - - - @media only screen and (max-width: 600px) { - grid-template-areas: - "crumbs" - "sync" - "name" - "content" - "blank" - ; - grid-template-columns: 1fr; - - #tree { - display: none; - } - - n2-syncprogress { - .el-count { - top: 4px; - } - } - } - + min-height: 100vh; + display: grid; + grid-template-areas: "tree crumbs" "tree sync" "tree name" "tree content" "tree blank"; + grid-template-columns: min-content 1fr; + grid-template-rows: 48px 56px 48px min-content 1fr; +} +@media only screen and (max-width: 600px) { + #notes2 { + grid-template-areas: "crumbs" "sync" "name" "content" "blank"; + grid-template-columns: 1fr; + } + #notes2 #tree { + display: none; + } } - #tree { - grid-area: tree; - display: grid; - background-color: #fafafa; - color: #444; - z-index: 100; - - border-right: 1px solid #ddd; - - n2-tree { - /*border: 2px solid #f8f8f8;*/ - padding: 16px 48px 16px 24px; - } - - &:focus-within { - n2-tree { - /* - border: 2px solid #fe5f55; - */ - } - - } - - - #logo { - display: grid; - position: relative; - justify-items: center; - margin-top: 8px; - margin-bottom: 8px; - margin-left: 24px; - margin-right: 24px; - cursor: pointer; - - img { - width: 128px; - left: -20px; - - } - } - - .icons { - display: flex; - justify-content: center; - margin-bottom: 32px; - gap: 8px; - } - - .node { - display: grid; - grid-template-columns: 40px min-content; - grid-template-rows: - min-content 1fr; - margin-top: 12px; - align-items: center; - - .expand-toggle { - user-select: none; - cursor: pointer; - justify-self: center; - - img { - width: auto; - height: 18px; - } - } - - .name { - white-space: nowrap; - cursor: pointer; - user-select: none; - - &:hover { - color: var(--color1); - } - - &.selected { - color: var(--color1); - font-weight: bold; - } - - } - - .children { - padding-left: 24px; - margin-left: 18px; - border-left: 1px solid #ddd; - grid-column: 1 / -1; - - &.collapsed { - display: none; - } - } - } + grid-area: tree; + padding: 16px 32px; + background-color: #333; + color: #ddd; + z-index: 100; + border-left: 2px solid #333; } - -#tree-nodes { - padding: 16px 32px; - /* - border-radius: 8px; -*/ - /* - box-shadow: 5px 5px 10px -5px rgba(0, 0, 0, 0.75); - */ +#tree:focus { + border-left: 2px solid #FE5F55; +} +#tree #logo { + display: grid; + position: relative; + justify-items: center; + margin-bottom: 8px; + margin-left: 24px; + margin-right: 24px; +} +#tree #logo img { + width: 128px; + left: -20px; +} +#tree .icons { + display: flex; + justify-content: center; + margin-bottom: 32px; + gap: 8px; +} +#tree .node { + display: grid; + grid-template-columns: 24px min-content; + grid-template-rows: min-content 1fr; + margin-top: 12px; +} +#tree .node .expand-toggle { + user-select: none; +} +#tree .node .expand-toggle img { + width: 16px; + height: 16px; +} +#tree .node .name { + white-space: nowrap; + cursor: pointer; + user-select: none; +} +#tree .node .name:hover { + color: #fe5f55; +} +#tree .node .name.selected { + color: #fe5f55; + font-weight: bold; +} +#tree .node .children { + padding-left: 24px; + margin-left: 8px; + border-left: 1px solid #444; + grid-column: 1 / -1; +} +#tree .node .children.collapsed { + display: none; } - #crumbs { - grid-area: crumbs; - display: grid; - align-items: start; - justify-items: center; - height: min-content; - margin: 0 16px 16px 16px; - - n2-crumbs { - background: #e4e4e4; - display: flex; - flex-wrap: wrap; - padding: 8px 16px; - background: #e4e4e4; - color: #333; - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; - - &.node-modified { - background-color: var(--color1); - color: var(--color2); - - .crumb:after { - color: var(--color2); - } - } - - n2-crumb { - margin-right: 8px; - cursor: pointer; - user-select: none; - -webkit-tap-highlight-color: transparent; - - a { - text-decoration: none; - color: inherit; - } - } - - n2-crumb:after { - content: ">"; - font-weight: bold; - color: var(--color1) - } - - n2-crumb:last-child { - margin-right: 0; - } - - n2-crumb:last-child:after { - content: ''; - margin-left: 0px; - } - - } - + grid-area: crumbs; + display: grid; + align-items: start; + justify-items: center; + margin: 0px 16px; } - -n2-syncprogress { - --radius: 8px; - - display: grid; - grid-area: sync; - display: grid; - justify-items: center; - align-items: center; - - position: relative; - - opacity: 0; - transition: height 0s 500ms, opacity 500ms linear, visibility 0s 500ms; - - &.show { - opacity: 1; - transition: visibility, height 0s, opacity 500ms linear; - } - - progress { - width: 100%; - height: 24px; - border-radius: 8px; - } - - .count { - position: absolute; - top: 16px; - width: 100%; - white-space: nowrap; - color: #888; - text-align: center; - font-size: 12pt; - font-weight: bold; - } - - progress[value]::-webkit-progress-bar { - background-color: #eee; - box-shadow: 0 2px var(--radius) rgba(0, 0, 0, 0.25) inset; - border-radius: var(--radius); - } - - progress[value]::-moz-progress-bar { - background-color: #eee; - box-shadow: 0 2px var(--radius) rgba(0, 0, 0, 0.25) inset; - border-radius: var(--radius); - } - - progress[value]::-webkit-progress-value { - background: rgb(186, 95, 89); - background: linear-gradient(180deg, rgba(186, 95, 89, 1) 0%, rgba(254, 95, 85, 1) 50%, rgba(186, 95, 89, 1) 100%); - border-radius: var(--radius); - } - - progress[value]::-moz-progress-value { - background: rgb(186, 95, 89); - background: linear-gradient(180deg, rgba(186, 95, 89, 1) 0%, rgba(254, 95, 85, 1) 50%, rgba(186, 95, 89, 1) 100%); - border-radius: var(--radius); - } - +#crumbs .crumbs { + display: flex; + flex-wrap: wrap; + padding: 8px 16px; + background: #e4e4e4; + color: #333; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} +#crumbs .crumbs.node-modified { + background-color: #fe5f55; + color: #efede8; +} +#crumbs .crumbs.node-modified .crumb:after { + color: #efede8; +} +#crumbs .crumbs .crumb { + margin-right: 8px; + cursor: pointer; + user-select: none; + -webkit-tap-highlight-color: transparent; +} +#crumbs .crumbs .crumb:after { + content: "•"; + margin-left: 8px; + color: #fe5f55; +} +#crumbs .crumbs .crumb:last-child { + margin-right: 0; +} +#crumbs .crumbs .crumb:last-child:after { + content: ''; + margin-left: 0px; +} +#sync-progress { + grid-area: sync; + display: grid; + justify-items: center; + width: 100%; + height: 56px; + position: relative; +} +#sync-progress progress { + width: 100%; + padding: 0 7px; + max-width: 900px; + height: 16px; + border-radius: 4px; +} +#sync-progress progress[value]::-webkit-progress-bar { + background-color: #eee; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25) inset; + border-radius: 4px; +} +#sync-progress progress[value]::-moz-progress-bar { + background-color: #eee; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25) inset; + border-radius: 4px; +} +#sync-progress progress[value]::-webkit-progress-value { + background: #ba5f59; + background: linear-gradient(180deg, #ba5f59 0%, #fe5f55 50%, #ba5f59 100%); + border-radius: 4px; +} +#sync-progress progress[value]::-moz-progress-value { + background: #ba5f59; + background: linear-gradient(180deg, #ba5f59 0%, #fe5f55 50%, #ba5f59 100%); + border-radius: 4px; +} +#sync-progress .count { + width: min-content; + white-space: nowrap; + margin-top: 0px; + color: #888; + position: absolute; + top: 22px; +} +#sync-progress.hidden { + visibility: hidden; + opacity: 0; + transition: visibility 0s 500ms, opacity 500ms linear; +} +#name { + color: #333; + font-weight: bold; + text-align: center; + font-size: 1.15em; + margin-top: 0px; + margin-bottom: 16px; +} +/* ============================================================= * + * Textarea replicates the height of an element expanding height * + * ============================================================= */ +.grow-wrap { + /* easy way to plop the elements on top of each other and have them both sized based on the tallest one's height */ + display: grid; + grid-area: content; + font-size: 1em; +} +.grow-wrap::after { + /* Note the weird space! Needed to preventy jumpy behavior */ + content: attr(data-replicated-value) " "; + /* This is how textarea text behaves */ + width: calc(100% - 32px); + max-width: 900px; + white-space: pre-wrap; + word-wrap: break-word; + background: rgba(0, 255, 255, 0.5); + justify-self: center; + /* Hidden from view, clicks, and screen readers */ + visibility: hidden; +} +.grow-wrap > textarea { + /* You could leave this, but after a user resizes, then it ruins the auto sizing */ + resize: none; + /* Firefox shows scrollbar on growth, you can hide like this. */ + overflow: hidden; +} +.grow-wrap > textarea, +.grow-wrap::after { + /* Identical styling required!! */ + padding: 0.5rem; + font: inherit; + /* Place on top of each other */ + grid-area: 1 / 1 / 2 / 2; } - /* ============================================================= */ - -n2-nodeui { - margin-bottom: 32px; - - .el-name { - grid-area: name; - color: #333; - font-weight: bold; - text-align: center; - font-size: 1.15em; - margin-top: 8px; - margin-bottom: 0px; - } - - .el-functions { - grid-area: functions; - } - - .el-node-content { - grid-area: content; - justify-self: center; - word-wrap: break-word; - font-family: monospace; - color: #333; - - width: 100%; - max-width: var(--content-width); - field-sizing: content; - - resize: none; - outline: none; - - padding: 32px 0; - border-left: none; - border-right: none; - border-top: 1px solid #e0e0e0; - border-bottom: 1px solid #e0e0e0; - margin-bottom: 32px; - - &:invalid { - background: #f5f5f5; - padding-top: 16px; - } - } - - .el-node-markdown { - grid-area: content; - display: none; - - border-top: 1px solid #e0e0e0; - border-bottom: 1px solid #e0e0e0; - margin-bottom: 32px; - } - - &.show-markdown { - .el-node-content { - display: none; - } - - .el-node-markdown { - display: block; - } - } +#node-content { + justify-self: center; + word-wrap: break-word; + font-family: monospace; + color: #333; + width: calc(100% - 32px); + max-width: 900px; + resize: none; + border: none; + outline: none; +} +#node-content:invalid { + background: #f5f5f5; + padding-top: 16px; } - #blank { - grid-area: blank; - height: 32px; + grid-area: blank; + height: 32px; } - -dialog.op { - &::backdrop { - background: rgba(0, 0, 0, 0.5); - } - - .header { - font-weight: bold; - margin-top: 16px; - - &:first-child { - margin-top: 0px; - } - } - +dialog.op::backdrop { + background: rgba(0, 0, 0, 0.5); } - -#op-search { - .results { - display: grid; - grid-template-columns: min-content min-content; - grid-gap: 6px 16px; - - div { - white-space: nowrap; - } - - - .ancestors { - display: flex; - - .ancestor::after { - content: ">"; - margin: 0px 8px; - color: #a00; - } - - .ancestor:last-child::after { - content: ""; - } - } - } +dialog.op .header { + font-weight: bold; + margin-top: 16px; +} +dialog.op .header:first-child { + margin-top: 0px; +} +#op-search .results { + display: grid; + grid-template-columns: min-content min-content; + grid-gap: 6px 16px; +} +#op-search .results div { + white-space: nowrap; +} +#op-search .results .ancestors { + display: flex; +} +#op-search .results .ancestors .ancestor::after { + content: ">"; + margin: 0px 8px; + color: #a00; +} +#op-search .results .ancestors .ancestor:last-child::after { + content: ""; } diff --git a/static/css/theme.css b/static/css/theme.css index b9c47ed..e69de29 100644 --- a/static/css/theme.css +++ b/static/css/theme.css @@ -1,5 +0,0 @@ -:root { - --color1: #fe5f55; - --color2: #efede8; - --color3: #666; -} diff --git a/static/images/collapsed.svg b/static/images/collapsed.svg index d93f4ca..8bd376f 100644 --- a/static/images/collapsed.svg +++ b/static/images/collapsed.svg @@ -2,49 +2,73 @@ - - - image/svg+xml - folder-outline - - - + transform="translate(-42.756321,-24.613384)"> diff --git a/static/images/expanded.svg b/static/images/expanded.svg index 017e8a4..e1a6f66 100644 --- a/static/images/expanded.svg +++ b/static/images/expanded.svg @@ -2,43 +2,64 @@ image/svg+xmlfolder-openfolder-open-outline + transform="translate(-42.756321,-24.613384)"> diff --git a/static/images/icon_markdown.svg b/static/images/icon_markdown.svg deleted file mode 100644 index f8d0aae..0000000 --- a/static/images/icon_markdown.svg +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - Markdown icon - - - - - Markdown icon - - - - diff --git a/static/images/icon_markdown_hollow.svg b/static/images/icon_markdown_hollow.svg deleted file mode 100644 index d938c6f..0000000 --- a/static/images/icon_markdown_hollow.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - diff --git a/static/images/icon_refresh.svg b/static/images/icon_refresh.svg index a6aa907..d46322e 100644 --- a/static/images/icon_refresh.svg +++ b/static/images/icon_refresh.svg @@ -7,7 +7,7 @@ viewBox="0 0 4.2333398 5.8208399" version="1.1" id="svg1" - inkscape:version="1.4.2 (ebf0e94, 2025-05-08)" + inkscape:version="1.3.2 (091e20e, 2023-11-25)" sodipodi:docname="icon_refresh.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" @@ -23,16 +23,15 @@ inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" - inkscape:zoom="23.548693" - inkscape:cx="6.9218279" - inkscape:cy="12.5697" + inkscape:zoom="0.83651094" + inkscape:cx="7.7703706" + inkscape:cy="11.356695" inkscape:window-width="1916" inkscape:window-height="1161" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" - inkscape:current-layer="layer1" - showgrid="false" /> + inkscape:current-layer="layer1" /> + style="stroke-width:0.264583;fill:#f9f9f9" /> diff --git a/static/images/icon_save.svg b/static/images/icon_save.svg deleted file mode 100644 index 0846a73..0000000 --- a/static/images/icon_save.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - content-save - - - diff --git a/static/images/icon_save_disabled.svg b/static/images/icon_save_disabled.svg deleted file mode 100644 index 907cee6..0000000 --- a/static/images/icon_save_disabled.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - content-save - - - diff --git a/static/images/icon_search.svg b/static/images/icon_search.svg index 6de83dd..8be3977 100644 --- a/static/images/icon_search.svg +++ b/static/images/icon_search.svg @@ -7,7 +7,7 @@ viewBox="0 0 109.40056 109.39984" version="1.1" id="svg8" - inkscape:version="1.4.2 (ebf0e94, 2025-05-08)" + inkscape:version="1.4 (e7c3feb, 2024-10-09)" sodipodi:docname="icon_search.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" @@ -27,16 +27,16 @@ inkscape:pageshadow="2" inkscape:zoom="0.70710678" inkscape:cx="206.47518" - inkscape:cy="207.88939" + inkscape:cy="207.18229" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" units="px" - inkscape:window-width="1916" - inkscape:window-height="1161" - inkscape:window-x="0" - inkscape:window-y="18" - inkscape:window-maximized="1" + inkscape:window-width="2190" + inkscape:window-height="1404" + inkscape:window-x="1463" + inkscape:window-y="16" + inkscape:window-maximized="0" inkscape:showpageshadow="true" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d6d6d6" @@ -62,6 +62,6 @@ + style="stroke-width:6.25145;fill:#ffffff" /> diff --git a/static/images/leaf.svg b/static/images/leaf.svg index 306a2a0..ed44541 100644 --- a/static/images/leaf.svg +++ b/static/images/leaf.svg @@ -2,51 +2,56 @@ image/svg+xmlfolder-openfolder-open-outlinenotebook-outlinetext-box-outline + transform="translate(-42.756321,-24.613384)"> diff --git a/static/js/app.mjs b/static/js/app.mjs deleted file mode 100644 index 7fa4dda..0000000 --- a/static/js/app.mjs +++ /dev/null @@ -1,331 +0,0 @@ -import { ROOT_NODE } from 'node_store' -import { CustomHTMLElement } from './lib/custom_html_element.mjs' -import { N2Tree } from 'tree' -import { Node } from 'node' - -export class App { - constructor() {// {{{ - this.currentNode = null - this.tree = new N2Tree() - this.crumbs = new N2Crumbs() - this.crumbsElement = document.getElementById('crumbs') - this.nodeUI = document.getElementById('note') - - _mbus.subscribe('TREE_TRUNK_FETCHED', async () => { - document.getElementById('tree').append(this.tree.render()) - document.getElementById('tree-nodes')?.focus() - - const startNode = await this.getStartNode() - this.goToNode(startNode.UUID, false, false) - }) - - _mbus.subscribe('TREE_NODE_SELECTED', event => { - const node = event.detail.data - this.goToNode(node.UUID, false, false) - }) - - _mbus.subscribe('GO_TO_NODE', event => { - const node = event.detail.data - this.goToNode(node.nodeUUID, node.dontPush, node.dontExpand) - }) - - window.addEventListener('keydown', event => this.keyHandler(event)) - window.addEventListener('popstate', event => this.popState(event)) - document.getElementById('notes2').addEventListener('click', event => { - if (event.target.id === 'notes2') - document.getElementById('node-content')?.focus() - }) - - window._sync = new Sync() - - // I think it is uncomfortable having the sync running as soon as the page load. - // I haven't gotten the time to look at the page before stuff jumps around. - // There a slight delay to initiate sync seems reasonable. - setTimeout(() => window._sync.run(), 1000) - }// }}} - - keyHandler(event) {//{{{ - let handled = true - - // All keybindings is Alt+Shift, since the popular browsers at the time (2023) allows to override thees. - // Ctrl+S is the exception to using Alt+Shift, since it is overridable and in such widespread use for saving. - // Thus, the exception is acceptable to consequent use of alt+shift. - if (!(event.shiftKey && event.altKey) && !(event.key.toUpperCase() === 'S' && event.ctrlKey)) - return - - switch (event.key.toUpperCase()) { - case 'T': - if (document.activeElement.id === 'tree-nodes') { - console.log('take focus') - this.nodeUI.takeFocus() - } else { - this.tree.focus() - } - break - - case 'F': - _mbus.dispatch('op-search') - break - /* - case 'C': - this.showPage('node') - break - - case 'E': - this.showPage('keys') - break - */ - - case 'M': - globalThis._mbus.dispatch('MARKDOWN_TOGGLE') - break - - case 'N': - this.createNode() - break - - /* - case 'P': - this.showPage('node-properties') - break - - */ - case 'S': - this.saveNode() - /* - else if (this.page.value === 'node-properties') - this.nodeProperties.current.save() - */ - break - /* - - case 'U': - this.showPage('upload') - break - - case 'F': - this.showPage('search') - break - */ - - default: - handled = false - } - - if (handled) { - event.preventDefault() - event.stopPropagation() - } - }//}}} - popState(event) {// {{{ - _mbus.dispatch("GO_TO_NODE", { nodeUUID: event.state.nodeUUID, dontPush: true, dontExpand: true }) - }// }}} - async getStartNode() {//{{{ - let nodeUUID = ROOT_NODE - - // Is a UUID provided on the URI as an anchor? - const parts = document.URL.split('#') - if (parts[1]?.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) - nodeUUID = parts[1] - - return await nodeStore.get(nodeUUID) - }//}}} - async saveNode() {//{{{ - if (!this.currentNode.isModified()) - return - - /* The node history is a local store for node history. - * This could be provisioned from the server or cleared if - * deemed unnecessary. - * - * The send queue is what will be sent back to the server - * to have a recorded history of the notes. - * - * A setting to be implemented in the future could be to - * not save the history locally at all. */ - const node = this.currentNode - - // The node is still in its old state and will present - // the unmodified content to the node store. - const history = nodeStore.nodesHistory.add(node) - - // Prepares the node object for saving. - // Sets Updated value to current date and time. - await node.save() - - // Updated node is added to the send queue to be stored on server. - const sendQueue = nodeStore.sendQueue.add(node) - - // Updated node is saved to the primary node store. - const nodeStoreAdding = nodeStore.add([node]) - - await Promise.all([history, sendQueue, nodeStoreAdding]) - }//}}} - async createNode() {//{{{ - let name = prompt("Name") - if (!name) - return - - const nn = Node.create(name, this.currentNode.UUID) - nn.save() - - nodeStore.sendQueue.add(nn) - nodeStore.add([nn]) - - }//}}} - async goToNode(nodeUUID, dontPush, dontExpand) {//{{{ - if (nodeUUID === null || nodeUUID === undefined) - return - - // Don't switch notes until saved. - if (this.nodeUI.isModified()) { - if (!confirm("Changes not saved. Do you want to discard changes?")) - return - } - - if (!dontPush) - history.pushState({ nodeUUID }, '', `/notes2#${nodeUUID}`) - - const node = nodeStore.node(nodeUUID) - node.reset() // any modifications are discarded. - - this.currentNode = node - this.tree.setSelected(node, dontExpand) - - const ancestors = await nodeStore.getNodeAncestry(node) - _mbus.dispatch('CRUMBS_SET', ancestors, () => this.crumbsElement.replaceChildren(this.crumbs.render())) - _mbus.dispatch('NODE_UI_OPEN', node) - _mbus.dispatch('NODE_UNMODIFIED') - - // Scrolls node into view. - this.tree.makeVisible(node) - }//}}} -} - -class N2Crumbs extends CustomHTMLElement { - static {// {{{ - this.tmpl = document.createElement('template') - this.tmpl.innerHTML = ` - ` - }// }}} - constructor() {// {{{ - super() - this.classList.add('crumbs') - - this.crumbs = [] - - _mbus.subscribe('CRUMBS_SET', event => { - this.crumbs = event.detail.data - }) - }// }}} - render() {// {{{ - const crumbs = this.crumbs.map(node => - new N2Crumb( - node.get('Name'), - node.UUID, - ) - ) - - const start = new N2Crumb('Start', ROOT_NODE) - crumbs.push(start) - - this.replaceChildren(...crumbs.reverse()) - return this - }// }}} -} -customElements.define('n2-crumbs', N2Crumbs) - -class N2Crumb extends CustomHTMLElement { - static {// {{{ - this.tmpl = document.createElement('template') - this.tmpl.innerHTML = ` - - ` - }// }}} - constructor(label, uuid) {// {{{ - super() - this.classList.add('crumb') - - this.label = label - this.uuid = uuid - - this.elLink.href = `/notes2#${this.uuid}` - this.elLink.innerText = this.label - this.elLink.addEventListener('click', () => _mbus.dispatch("GO_TO_NODE", { nodeUUID: this.uuid, dontPush: false, dontExpand: true })) - }// }}} -} -customElements.define('n2-crumb', N2Crumb) - -function tmpl(html) {// {{{ - const el = document.createElement('template') - el.innerHTML = html - return el.content.children -}// }}} - -class Op { - constructor(id) {// {{{ - this.id = id - _mbus.subscribe(this.id, p => this.render(p)) - }// }}} - render(html) {// {{{ - const op = document.getElementById('op') - const t = document.createElement('template') - t.innerHTML = `${html}` - op.replaceChildren(t.content) - document.getElementById(this.id).showModal() - }// }}} - get(selector) {// {{{ - return document.querySelector(`#${this.id} ${selector}`) - }// }}} - bind(selector, event, fn) {// {{{ - this.get(selector).addEventListener(event, evt => fn(evt)) - }// }}} -} - -class OpSearch extends Op { - constructor() {// {{{ - super('op-search') - }// }}} - render() {// {{{ - super.render(` -
Search
-
- -
-
Results
-
- `) - - this.bind('input[type="text"]', 'keydown', evt => this.search(evt)) - }// }}} - search(event) {// {{{ - if (event.key !== 'Enter') - return - - const searchFor = document.querySelector('#op-search input').value - nodeStore.search(searchFor, ROOT_NODE) - .then(res => this.displayResults(res)) - }// }}} - displayResults(results) {// {{{ - const rs = [] - for (const r of results) { - const ancestors = r.ancestry.reverse().map(a => { - const div = tmpl(`
${a.data.Name}
`) - div[0].addEventListener('click', () => _notes2.current.goToNode(a.UUID)) - return div[0] - }) - - - const div = tmpl(`
${r.name}
`) - div[0].addEventListener('click', () => _notes2.current.goToNode(r.uuid)) - rs.push(...div) - - const ancDev = tmpl('
') - ancDev[0].append(...ancestors) - rs.push(ancDev[0]) - } - this.get('.results').replaceChildren(...rs) - }// }}} -} - -// vim: foldmethod=marker diff --git a/static/js/lib/custom_html_element.mjs b/static/js/lib/custom_html_element.mjs deleted file mode 100644 index dedb5d8..0000000 --- a/static/js/lib/custom_html_element.mjs +++ /dev/null @@ -1,57 +0,0 @@ -export class CustomHTMLElement extends HTMLElement { - constructor() {// {{{ - super() - - this.appendChild(this.constructor.tmpl.content.cloneNode(true)) - - this.querySelectorAll('*').forEach(el => { - const field = el.dataset.field - if (field !== undefined) { - const fieldName = this.toElementName('field', field) - this[fieldName] = el - } - - const name = el.dataset.el - if (name !== undefined) { - const elName = this.toElementName('el', name) - this[elName] = el - el.classList.add('el-' + name) - } - }) - }// }}} - toElementName(prefix, str) {// {{{ - str = prefix + '-' + str - return str.replace(/-(id|[a-z])/g, match => match.toUpperCase().replace('-', '')) - }// }}} -} - -export class StupidPreactCustomHTMLElement extends HTMLElement { - constructor() {// {{{ - super() - - // Stupid stuff because of Preact. - this.clonedNodes = this.constructor.tmpl.content.cloneNode(true) - this.clonedNodes.querySelectorAll('*').forEach(el => { - const field = el.dataset.field - if (field !== undefined) { - const fieldName = this.toElementName('field', field) - this[fieldName] = el - } - - const name = el.dataset.el - if (name !== undefined) { - const elName = this.toElementName('el', name) - this[elName] = el - el.classList.add('el-' + name) - } - }) - }// }}} - toElementName(prefix, str) {// {{{ - str = prefix + '-' + str - return str.replace(/-(id|[a-z])/g, match => match.toUpperCase().replace('-', '')) - }// }}} - connectedCallback() {// {{{ - // Stupid stuff because of Preact. - this.appendChild(this.clonedNodes) - }// }}} -} diff --git a/static/js/lib/node_modules/.package-lock.json b/static/js/lib/node_modules/.package-lock.json index 3d3d164..441fdf4 100644 --- a/static/js/lib/node_modules/.package-lock.json +++ b/static/js/lib/node_modules/.package-lock.json @@ -4,24 +4,14 @@ "requires": true, "packages": { "node_modules/marked": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.3.tgz", - "integrity": "sha512-7VT90JOkDeaRWpfjOReRGPEKn0ecdARBkDGL+tT1wZY0efPPqkUxLUSmzy/C7TIylQYJC9STISEsCHrqb/7VIA==", - "license": "MIT", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.1.1.tgz", + "integrity": "sha512-EgxRjgK9axsQuUa/oKMx5DEY8oXpKJfk61rT5iY3aRlgU6QJtUcxU5OAymdhCvWvhYcd9FKmO5eQoX8m9VGJXg==", "bin": { "marked": "bin/marked.js" }, "engines": { - "node": ">= 20" - } - }, - "node_modules/marked-token-position": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/marked-token-position/-/marked-token-position-2.0.2.tgz", - "integrity": "sha512-IMyr4mR3A5uFReXn7cxLDgDLjefG110ANy0oMGs5+gB7NsdIbv9YoVoJuGxuMSFHWOeIFkAzjdSoFNVKcMPfZw==", - "license": "MIT", - "peerDependencies": { - "marked": ">=16.2.0 <19" + "node": ">= 18" } }, "node_modules/preact": { diff --git a/static/js/lib/node_modules/marked-token-position/LICENSE b/static/js/lib/node_modules/marked-token-position/LICENSE deleted file mode 100644 index 5d36390..0000000 --- a/static/js/lib/node_modules/marked-token-position/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 @UziTech - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/static/js/lib/node_modules/marked-token-position/README.md b/static/js/lib/node_modules/marked-token-position/README.md deleted file mode 100644 index a10f43c..0000000 --- a/static/js/lib/node_modules/marked-token-position/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# marked-token-position - -Add `position` field for each token. - -```ts -interface Position { - /** - * Positions for each line of the token. LinePositions will not include the newline character for the line. - */ - lines: LinePosition[] - /** - * Position at the beginning of token - */ - start: PositionFields; - /** - * Position at the end of token - */ - end: PositionFields; -} - -interface LinePosition { - /** - * Position at the beginning of line - */ - start: PositionFields; - /** - * Position at the end of line. Will not include the newline character. - */ - end: PositionFields; -} - -interface PositionFields { - /** - * Number of characters from the beginning of the markdown string - */ - offset: number; - /** - * Line number of the token. Starts at line 0. - */ - line: number; - /** - * Column number of the token. Starts at column 0. - */ - column: number; -} -``` - -# Usage - -## Extension - -```js -import {Marked} from "marked"; -import markedTokenPosition from "marked-token-position"; - -// or UMD script -// -// -// const Marked = marked.Marked; - -const marked = new Marked(); - -function anotherExtension { - return { - walkTokens(token) { - // token has `position` field - } - hooks: { - processAllTokens(tokens) { - // tokens have `position` field - } - } - }; -} - -marked.use(anotherExtension(), markedTokenPosition()); - -marked.parse("# example markdown"); -``` - -The `position` field will be added to the tokens so any other extension can -use the `position` field in a `walkTokens` function or `processAllTokens` hook. - -> [!CAUTION] -> The `processAllTokens` hook is used by this extension so any other extension -> using `processAllTokens` that requires the `position` field must be added -> before this extension because marked calls the `processAllTokens` hooks in -> reverse order. - -The tokens will look like: - -```json -[ - { - "type": "heading", - "raw": "# example markdown", - "depth": 1, - "text": "example markdown", - "tokens": [ - { - "type": "text", - "raw": "example markdown", - "text": "example markdown", - "escaped": false, - "position": { - "start": { - "offset": 2, - "line": 0, - "column": 2 - }, - "end": { - "offset": 18, - "line": 0, - "column": 18 - } - } - } - ], - "position": { - "start": { - "offset": 0, - "line": 0, - "column": 0 - }, - "end": { - "offset": 18, - "line": 0, - "column": 18 - } - } - } -] -``` - -## addTokenPositions - -Calling `marked.lexer()` will not add the `position` field with the extension -since the extension is only called on `marked.parse()` and `marked.parseInline()`. - -An `addTokenPositions` function is exported to add the `position` field to the -tokens returned by `marked.lexer()`. - -```js -import {Marked} from "marked"; -import {addTokenPositions} from "marked-token-position"; - -// or UMD script -// -// -// const Marked = marked.Marked; -// const addTokenPositions = markedTokenPosition.addTokenPositions; - - -const marked = new Marked(); -const tokens = marked.lexer("# example markdown"); - -addTokenPositions(tokens); - -// tokens now have a `position` field -``` diff --git a/static/js/lib/node_modules/marked-token-position/lib/index.d.ts b/static/js/lib/node_modules/marked-token-position/lib/index.d.ts deleted file mode 100644 index f61cd65..0000000 --- a/static/js/lib/node_modules/marked-token-position/lib/index.d.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Generated by dts-bundle-generator v9.5.1 - -import { MarkedExtension, Token, Tokens } from 'marked'; - -export interface TokenWithPosition extends Tokens.Generic { - position: Position; -} -export interface Position { - /** - * Positions for each line of the token. LinePositions will not include the newline character for the line. - */ - lines: LinePosition[]; - /** - * Position at the beginning of token - */ - start: PositionFields; - /** - * Position at the end of token - */ - end: PositionFields; -} -export interface LinePosition { - /** - * Position at the beginning of line - */ - start: PositionFields; - /** - * Position at the end of line. Will not include the newline character. - */ - end: PositionFields; -} -export interface PositionFields { - /** - * Number of characters from the beginning of the markdown string - */ - offset: number; - /** - * Line number of the token. Starts at line 0. - */ - line: number; - /** - * Column number of the token. Starts at column 0. - */ - column: number; -} -/** - * Add position field to tokens - */ -export declare function addTokenPositions(tokens: Token[]): TokenWithPosition[]; -/** - * Marked extension to add position field to tokens - */ -declare function _default(options?: {}): MarkedExtension; - -export { - _default as default, -}; - -export {}; diff --git a/static/js/lib/node_modules/marked-token-position/lib/index.esm.js b/static/js/lib/node_modules/marked-token-position/lib/index.esm.js deleted file mode 100644 index 41a85f7..0000000 --- a/static/js/lib/node_modules/marked-token-position/lib/index.esm.js +++ /dev/null @@ -1,6 +0,0 @@ -function g(u){let i=u.map(r=>r.raw).join("");return h(u,0,0,0,i).tokens}function b(u={}){return{hooks:{processAllTokens(i){return g(i)}}}}function h(u,i,r,f,l){for(let s of u){let n=s,a=T(i,r,f,l,n.raw);if(n.position=a,n.tokens&&h(n.tokens,i,r,f,l),n.childTokens){let c=i,t=r,e=f,d=l;for(let k of n.childTokens){let o=h(n[k],c,t,e,d);c=o.offset,t=o.line,e=o.column,d=o.markdown}}if(n.type==="list"&&h(n.items,i,r,f,l),n.type==="table"){let c=i,t=r,e=f,d=l;for(let k of n.header){let o=h(k.tokens,c,t,e,d);c=o.offset,t=o.line,e=o.column,d=o.markdown}for(let k of n.rows)for(let o of k){let P=h(o.tokens,c,t,e,d);c=P.offset,t=P.line,e=P.column,d=P.markdown}}let m=a.end.offset-i;i=a.end.offset,r=a.end.line,f=a.end.column,l=l.slice(m)}return{tokens:u,offset:i,line:r,column:f,markdown:l}}function T(u,i,r,f,l){let s=[],n=l.split(` -`),a=f.split(` -`);n:for(let t=0;t<=a.length-n.length;t++){s=[];for(let e=0;e0?` -`:""),x={offset:u+P.length+o,line:i+t+e,column:(t+e===0?r:0)+o},p={offset:x.offset+k.length,line:x.line,column:x.column+k.length};s.push({start:x,end:p})}break}if(s.length===0)throw new Error(`Cannot find ${JSON.stringify(l)} in ${JSON.stringify(f)}`);let m=s[0].start,c=s.at(-1).end;return s.length>1&&s.at(-1).start.offset===c.offset&&(s=s.slice(0,-1)),{lines:s,start:m,end:c}}export{g as addTokenPositions,b as default}; -//# sourceMappingURL=index.esm.js.map diff --git a/static/js/lib/node_modules/marked-token-position/lib/index.esm.js.map b/static/js/lib/node_modules/marked-token-position/lib/index.esm.js.map deleted file mode 100644 index 4eb0539..0000000 --- a/static/js/lib/node_modules/marked-token-position/lib/index.esm.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../src/index.ts"], - "sourcesContent": ["/* node:coverage ignore next */\nimport type { MarkedExtension, Token, Tokens } from 'marked';\n\nexport interface TokenWithPosition extends Tokens.Generic {\n position: Position;\n}\ninterface Position {\n /**\n * Positions for each line of the token. LinePositions will not include the newline character for the line.\n */\n lines: LinePosition[]\n /**\n * Position at the beginning of token\n */\n start: PositionFields;\n /**\n * Position at the end of token\n */\n end: PositionFields;\n}\n\ninterface LinePosition {\n /**\n * Position at the beginning of line\n */\n start: PositionFields;\n /**\n * Position at the end of line. Will not include the newline character.\n */\n end: PositionFields;\n}\n\ninterface PositionFields {\n /**\n * Number of characters from the beginning of the markdown string\n */\n offset: number;\n /**\n * Line number of the token. Starts at line 0.\n */\n line: number;\n /**\n * Column number of the token. Starts at column 0.\n */\n column: number;\n}\n\n/**\n * Add position field to tokens\n */\nexport function addTokenPositions(tokens: Token[]) {\n const markdown = tokens.map(token => token.raw).join('');\n return addPosition(tokens, 0, 0, 0, markdown).tokens;\n}\n\n/**\n * Marked extension to add position field to tokens\n */\nexport default function(options = {}): MarkedExtension {\n return {\n hooks: {\n processAllTokens(tokens) {\n return addTokenPositions(tokens);\n },\n },\n };\n}\n\nfunction addPosition(tokens: Token[], offset: number, line: number, column: number, markdown: string) {\n for (const token of tokens) {\n const genericToken = token as Tokens.Generic;\n const position = getPosition(offset, line, column, markdown, genericToken.raw);\n genericToken.position = position;\n\n if (genericToken.tokens) {\n addPosition(genericToken.tokens, offset, line, column, markdown);\n }\n\n if (genericToken.childTokens) {\n let nextOffset = offset;\n let nextLine = line;\n let nextColumn = column;\n let nextMarkdown = markdown;\n for (const childToken of genericToken.childTokens) {\n const nextPosition = addPosition(genericToken[childToken], nextOffset, nextLine, nextColumn, nextMarkdown);\n nextOffset = nextPosition.offset;\n nextLine = nextPosition.line;\n nextColumn = nextPosition.column;\n nextMarkdown = nextPosition.markdown;\n }\n }\n\n if (genericToken.type === 'list') {\n addPosition(genericToken.items, offset, line, column, markdown);\n }\n\n if (genericToken.type === 'table') {\n let nextOffset = offset;\n let nextLine = line;\n let nextColumn = column;\n let nextMarkdown = markdown;\n for (const headerCell of genericToken.header) {\n const nextPosition = addPosition(headerCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown);\n nextOffset = nextPosition.offset;\n nextLine = nextPosition.line;\n nextColumn = nextPosition.column;\n nextMarkdown = nextPosition.markdown;\n }\n for (const row of genericToken.rows) {\n for (const rowCell of row) {\n const nextPosition = addPosition(rowCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown);\n nextOffset = nextPosition.offset;\n nextLine = nextPosition.line;\n nextColumn = nextPosition.column;\n nextMarkdown = nextPosition.markdown;\n }\n }\n }\n\n const deltaOffset = position.end.offset - offset;\n offset = position.end.offset;\n line = position.end.line;\n column = position.end.column;\n markdown = markdown.slice(deltaOffset);\n }\n\n return {\n tokens: tokens as TokenWithPosition[],\n offset,\n line,\n column,\n markdown,\n };\n}\n\nfunction getPosition(offset: number, line: number, column: number, markdown: string, raw: string): Position {\n let lines: LinePosition[] = [];\n const rawLines = raw.split('\\n');\n const markdownLines = markdown.split('\\n');\n\n // eslint-disable-next-line no-labels\n md: for (let i = 0; i <= markdownLines.length - rawLines.length; i++) {\n lines = [];\n for (let j = 0; j < rawLines.length; j++) {\n const markdownLine = markdownLines[i + j];\n const rawLine = rawLines[j];\n const lineStartOffset = markdownLine.indexOf(rawLine);\n\n if (lineStartOffset === -1) {\n // eslint-disable-next-line no-labels\n continue md;\n }\n\n const beforeMarkdownLines = markdownLines.slice(0, i + j).join('\\n') + (i + j > 0 ? '\\n' : '');\n const start = {\n offset: offset + beforeMarkdownLines.length + lineStartOffset,\n line: line + i + j,\n column: (i + j === 0 ? column : 0) + lineStartOffset,\n };\n const end = {\n offset: start.offset + rawLine.length,\n line: start.line,\n column: start.column + rawLine.length,\n };\n\n lines.push({\n start,\n end,\n });\n }\n break;\n }\n\n /* node:coverage ignore next 4 */\n if (lines.length === 0) {\n // This shouldn't ever happen but if it does it would be nice to have a good error message\n throw new Error(`Cannot find ${JSON.stringify(raw)} in ${JSON.stringify(markdown)}`);\n }\n\n const start = lines[0].start;\n const end = lines.at(-1)!.end;\n\n if (lines.length > 1 && lines.at(-1)!.start.offset === end.offset) {\n lines = lines.slice(0, -1);\n }\n\n return {\n lines,\n start,\n end,\n };\n}\n"], - "mappings": "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", - "names": ["addTokenPositions", "tokens", "markdown", "token", "addPosition", "index_default", "options", "offset", "line", "column", "genericToken", "position", "getPosition", "nextOffset", "nextLine", "nextColumn", "nextMarkdown", "childToken", "nextPosition", "headerCell", "row", "rowCell", "deltaOffset", "raw", "lines", "rawLines", "markdownLines", "md", "i", "j", "markdownLine", "rawLine", "lineStartOffset", "beforeMarkdownLines", "start", "end"] -} diff --git a/static/js/lib/node_modules/marked-token-position/lib/index.umd.js b/static/js/lib/node_modules/marked-token-position/lib/index.umd.js deleted file mode 100644 index 253cb7d..0000000 --- a/static/js/lib/node_modules/marked-token-position/lib/index.umd.js +++ /dev/null @@ -1,9 +0,0 @@ -(function(g,f){if(typeof exports=="object"&&typeof module<"u"){module.exports=f()}else if("function"==typeof define && define.amd){define("markedTokenPosition",f)}else {g["markedTokenPosition"]=f()}}(typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : this,function(){var exports={};var __exports=exports;var module={exports}; -var m=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var F=(e,n)=>()=>(e&&(n=e(e=0)),n);var M=(e,n)=>{for(var o in n)m(e,o,{get:n[o],enumerable:!0})},j=(e,n,o,f)=>{if(n&&typeof n=="object"||typeof n=="function")for(let t of y(n))!C.call(e,t)&&t!==o&&m(e,t,{get:()=>n[t],enumerable:!(f=O(n,t))||f.enumerable});return e};var b=e=>j(m({},"__esModule",{value:!0}),e);var T={};M(T,{addTokenPositions:()=>L,default:()=>E});function L(e){let n=e.map(o=>o.raw).join("");return x(e,0,0,0,n).tokens}function E(e={}){return{hooks:{processAllTokens(n){return L(n)}}}}function x(e,n,o,f,t){for(let c of e){let i=c,a=S(n,o,f,t,i.raw);if(i.position=a,i.tokens&&x(i.tokens,n,o,f,t),i.childTokens){let d=n,r=o,s=f,u=t;for(let k of i.childTokens){let l=x(i[k],d,r,s,u);d=l.offset,r=l.line,s=l.column,u=l.markdown}}if(i.type==="list"&&x(i.items,n,o,f,t),i.type==="table"){let d=n,r=o,s=f,u=t;for(let k of i.header){let l=x(k.tokens,d,r,s,u);d=l.offset,r=l.line,s=l.column,u=l.markdown}for(let k of i.rows)for(let l of k){let P=x(l.tokens,d,r,s,u);d=P.offset,r=P.line,s=P.column,u=P.markdown}}let p=a.end.offset-n;n=a.end.offset,o=a.end.line,f=a.end.column,t=t.slice(p)}return{tokens:e,offset:n,line:o,column:f,markdown:t}}function S(e,n,o,f,t){let c=[],i=t.split(` -`),a=f.split(` -`);n:for(let r=0;r<=a.length-i.length;r++){c=[];for(let s=0;s0?` -`:""),h={offset:e+P.length+l,line:n+r+s,column:(r+s===0?o:0)+l},w={offset:h.offset+k.length,line:h.line,column:h.column+k.length};c.push({start:h,end:w})}break}if(c.length===0)throw new Error(`Cannot find ${JSON.stringify(t)} in ${JSON.stringify(f)}`);let p=c[0].start,d=c.at(-1).end;return c.length>1&&c.at(-1).start.offset===d.offset&&(c=c.slice(0,-1)),{lines:c,start:p,end:d}}var g=F(()=>{"use strict"});module.exports=(g(),b(T)).default;module.exports.addTokenPositions=(g(),b(T)).addTokenPositions; - -if(__exports != exports)module.exports = exports;return module.exports})); -//# sourceMappingURL=index.umd.js.map diff --git a/static/js/lib/node_modules/marked-token-position/lib/index.umd.js.map b/static/js/lib/node_modules/marked-token-position/lib/index.umd.js.map deleted file mode 100644 index 7894776..0000000 --- a/static/js/lib/node_modules/marked-token-position/lib/index.umd.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../src/index.ts", ""], - "sourcesContent": ["/* node:coverage ignore next */\nimport type { MarkedExtension, Token, Tokens } from 'marked';\n\nexport interface TokenWithPosition extends Tokens.Generic {\n position: Position;\n}\ninterface Position {\n /**\n * Positions for each line of the token. LinePositions will not include the newline character for the line.\n */\n lines: LinePosition[]\n /**\n * Position at the beginning of token\n */\n start: PositionFields;\n /**\n * Position at the end of token\n */\n end: PositionFields;\n}\n\ninterface LinePosition {\n /**\n * Position at the beginning of line\n */\n start: PositionFields;\n /**\n * Position at the end of line. Will not include the newline character.\n */\n end: PositionFields;\n}\n\ninterface PositionFields {\n /**\n * Number of characters from the beginning of the markdown string\n */\n offset: number;\n /**\n * Line number of the token. Starts at line 0.\n */\n line: number;\n /**\n * Column number of the token. Starts at column 0.\n */\n column: number;\n}\n\n/**\n * Add position field to tokens\n */\nexport function addTokenPositions(tokens: Token[]) {\n const markdown = tokens.map(token => token.raw).join('');\n return addPosition(tokens, 0, 0, 0, markdown).tokens;\n}\n\n/**\n * Marked extension to add position field to tokens\n */\nexport default function(options = {}): MarkedExtension {\n return {\n hooks: {\n processAllTokens(tokens) {\n return addTokenPositions(tokens);\n },\n },\n };\n}\n\nfunction addPosition(tokens: Token[], offset: number, line: number, column: number, markdown: string) {\n for (const token of tokens) {\n const genericToken = token as Tokens.Generic;\n const position = getPosition(offset, line, column, markdown, genericToken.raw);\n genericToken.position = position;\n\n if (genericToken.tokens) {\n addPosition(genericToken.tokens, offset, line, column, markdown);\n }\n\n if (genericToken.childTokens) {\n let nextOffset = offset;\n let nextLine = line;\n let nextColumn = column;\n let nextMarkdown = markdown;\n for (const childToken of genericToken.childTokens) {\n const nextPosition = addPosition(genericToken[childToken], nextOffset, nextLine, nextColumn, nextMarkdown);\n nextOffset = nextPosition.offset;\n nextLine = nextPosition.line;\n nextColumn = nextPosition.column;\n nextMarkdown = nextPosition.markdown;\n }\n }\n\n if (genericToken.type === 'list') {\n addPosition(genericToken.items, offset, line, column, markdown);\n }\n\n if (genericToken.type === 'table') {\n let nextOffset = offset;\n let nextLine = line;\n let nextColumn = column;\n let nextMarkdown = markdown;\n for (const headerCell of genericToken.header) {\n const nextPosition = addPosition(headerCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown);\n nextOffset = nextPosition.offset;\n nextLine = nextPosition.line;\n nextColumn = nextPosition.column;\n nextMarkdown = nextPosition.markdown;\n }\n for (const row of genericToken.rows) {\n for (const rowCell of row) {\n const nextPosition = addPosition(rowCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown);\n nextOffset = nextPosition.offset;\n nextLine = nextPosition.line;\n nextColumn = nextPosition.column;\n nextMarkdown = nextPosition.markdown;\n }\n }\n }\n\n const deltaOffset = position.end.offset - offset;\n offset = position.end.offset;\n line = position.end.line;\n column = position.end.column;\n markdown = markdown.slice(deltaOffset);\n }\n\n return {\n tokens: tokens as TokenWithPosition[],\n offset,\n line,\n column,\n markdown,\n };\n}\n\nfunction getPosition(offset: number, line: number, column: number, markdown: string, raw: string): Position {\n let lines: LinePosition[] = [];\n const rawLines = raw.split('\\n');\n const markdownLines = markdown.split('\\n');\n\n // eslint-disable-next-line no-labels\n md: for (let i = 0; i <= markdownLines.length - rawLines.length; i++) {\n lines = [];\n for (let j = 0; j < rawLines.length; j++) {\n const markdownLine = markdownLines[i + j];\n const rawLine = rawLines[j];\n const lineStartOffset = markdownLine.indexOf(rawLine);\n\n if (lineStartOffset === -1) {\n // eslint-disable-next-line no-labels\n continue md;\n }\n\n const beforeMarkdownLines = markdownLines.slice(0, i + j).join('\\n') + (i + j > 0 ? '\\n' : '');\n const start = {\n offset: offset + beforeMarkdownLines.length + lineStartOffset,\n line: line + i + j,\n column: (i + j === 0 ? column : 0) + lineStartOffset,\n };\n const end = {\n offset: start.offset + rawLine.length,\n line: start.line,\n column: start.column + rawLine.length,\n };\n\n lines.push({\n start,\n end,\n });\n }\n break;\n }\n\n /* node:coverage ignore next 4 */\n if (lines.length === 0) {\n // This shouldn't ever happen but if it does it would be nice to have a good error message\n throw new Error(`Cannot find ${JSON.stringify(raw)} in ${JSON.stringify(markdown)}`);\n }\n\n const start = lines[0].start;\n const end = lines.at(-1)!.end;\n\n if (lines.length > 1 && lines.at(-1)!.start.offset === end.offset) {\n lines = lines.slice(0, -1);\n }\n\n return {\n lines,\n start,\n end,\n };\n}\n", "\nmodule.exports = require(\"./src/index.ts\").default;\nmodule.exports.addTokenPositions = require(\"./src/index.ts\").addTokenPositions;\n"], - "mappings": "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", - "names": ["src_exports", "__export", "addTokenPositions", "src_default", "tokens", "markdown", "token", "addPosition", "options", "offset", "line", "column", "genericToken", "position", "getPosition", "nextOffset", "nextLine", "nextColumn", "nextMarkdown", "childToken", "nextPosition", "headerCell", "row", "rowCell", "deltaOffset", "raw", "lines", "rawLines", "markdownLines", "md", "i", "j", "markdownLine", "rawLine", "lineStartOffset", "beforeMarkdownLines", "start", "end", "init_src", "__esmMin"] -} diff --git a/static/js/lib/node_modules/marked-token-position/package.json b/static/js/lib/node_modules/marked-token-position/package.json deleted file mode 100644 index 4f359e9..0000000 --- a/static/js/lib/node_modules/marked-token-position/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "marked-token-position", - "version": "2.0.2", - "description": "marked extension template", - "main": "./lib/index.esm.js", - "module": "./lib/index.esm.js", - "browser": "./lib/index.umd.js", - "type": "module", - "keywords": [ - "marked", - "extension" - ], - "files": [ - "lib/", - "src/" - ], - "exports": { - ".": { - "typescript": "./src/index.ts", - "types": "./lib/index.d.ts", - "default": "./lib/index.esm.js" - } - }, - "scripts": { - "build": "npm run build:esbuild && npm run build:types", - "build:esbuild": "node esbuild.config.js", - "build:types": "tsc && dts-bundle-generator --export-referenced-types --project tsconfig.json -o lib/index.d.ts src/index.ts", - "format": "eslint --fix", - "lint": "eslint", - "test": "npm run build:esbuild && node --experimental-transform-types ./spec/test.config.js", - "test:cover": "npm run build:esbuild && node --experimental-transform-types --experimental-test-coverage ./spec/test.config.js -- --cover", - "test:only": "npm run build:esbuild && node --experimental-transform-types ./spec/test.config.js -- --only", - "test:types": "npm run build:types && tsc --project tsconfig-test-types.json && attw -P --entrypoints . --profile esm-only", - "test:update": "npm run build:esbuild && node --experimental-transform-types --test-update-snapshots ./spec/test.config.js" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/UziTech/marked-token-position.git" - }, - "author": "Tony Brix (https://Tony.Brix.ninja)", - "license": "MIT", - "bugs": { - "url": "https://github.com/UziTech/marked-token-position/issues" - }, - "homepage": "https://github.com/UziTech/marked-token-position#readme", - "peerDependencies": { - "marked": ">=16.2.0 <19" - }, - "devDependencies": { - "@arethetypeswrong/cli": "^0.18.2", - "@markedjs/eslint-config": "^1.0.14", - "@semantic-release/changelog": "^6.0.3", - "@semantic-release/commit-analyzer": "^13.0.1", - "@semantic-release/git": "^10.0.1", - "@semantic-release/github": "^12.0.6", - "@semantic-release/npm": "^13.1.5", - "@semantic-release/release-notes-generator": "^14.1.0", - "dts-bundle-generator": "^9.5.1", - "esbuild": "^0.28.0", - "esbuild-plugin-umd-wrapper": "^3.0.0", - "eslint": "^10.2.0", - "marked": "^18.0.0", - "semantic-release": "^25.0.3", - "typescript": "^6.0.2" - } -} diff --git a/static/js/lib/node_modules/marked-token-position/src/index.ts b/static/js/lib/node_modules/marked-token-position/src/index.ts deleted file mode 100644 index d624389..0000000 --- a/static/js/lib/node_modules/marked-token-position/src/index.ts +++ /dev/null @@ -1,192 +0,0 @@ -/* node:coverage ignore next */ -import type { MarkedExtension, Token, Tokens } from 'marked'; - -export interface TokenWithPosition extends Tokens.Generic { - position: Position; -} -interface Position { - /** - * Positions for each line of the token. LinePositions will not include the newline character for the line. - */ - lines: LinePosition[] - /** - * Position at the beginning of token - */ - start: PositionFields; - /** - * Position at the end of token - */ - end: PositionFields; -} - -interface LinePosition { - /** - * Position at the beginning of line - */ - start: PositionFields; - /** - * Position at the end of line. Will not include the newline character. - */ - end: PositionFields; -} - -interface PositionFields { - /** - * Number of characters from the beginning of the markdown string - */ - offset: number; - /** - * Line number of the token. Starts at line 0. - */ - line: number; - /** - * Column number of the token. Starts at column 0. - */ - column: number; -} - -/** - * Add position field to tokens - */ -export function addTokenPositions(tokens: Token[]) { - const markdown = tokens.map(token => token.raw).join(''); - return addPosition(tokens, 0, 0, 0, markdown).tokens; -} - -/** - * Marked extension to add position field to tokens - */ -export default function(options = {}): MarkedExtension { - return { - hooks: { - processAllTokens(tokens) { - return addTokenPositions(tokens); - }, - }, - }; -} - -function addPosition(tokens: Token[], offset: number, line: number, column: number, markdown: string) { - for (const token of tokens) { - const genericToken = token as Tokens.Generic; - const position = getPosition(offset, line, column, markdown, genericToken.raw); - genericToken.position = position; - - if (genericToken.tokens) { - addPosition(genericToken.tokens, offset, line, column, markdown); - } - - if (genericToken.childTokens) { - let nextOffset = offset; - let nextLine = line; - let nextColumn = column; - let nextMarkdown = markdown; - for (const childToken of genericToken.childTokens) { - const nextPosition = addPosition(genericToken[childToken], nextOffset, nextLine, nextColumn, nextMarkdown); - nextOffset = nextPosition.offset; - nextLine = nextPosition.line; - nextColumn = nextPosition.column; - nextMarkdown = nextPosition.markdown; - } - } - - if (genericToken.type === 'list') { - addPosition(genericToken.items, offset, line, column, markdown); - } - - if (genericToken.type === 'table') { - let nextOffset = offset; - let nextLine = line; - let nextColumn = column; - let nextMarkdown = markdown; - for (const headerCell of genericToken.header) { - const nextPosition = addPosition(headerCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown); - nextOffset = nextPosition.offset; - nextLine = nextPosition.line; - nextColumn = nextPosition.column; - nextMarkdown = nextPosition.markdown; - } - for (const row of genericToken.rows) { - for (const rowCell of row) { - const nextPosition = addPosition(rowCell.tokens, nextOffset, nextLine, nextColumn, nextMarkdown); - nextOffset = nextPosition.offset; - nextLine = nextPosition.line; - nextColumn = nextPosition.column; - nextMarkdown = nextPosition.markdown; - } - } - } - - const deltaOffset = position.end.offset - offset; - offset = position.end.offset; - line = position.end.line; - column = position.end.column; - markdown = markdown.slice(deltaOffset); - } - - return { - tokens: tokens as TokenWithPosition[], - offset, - line, - column, - markdown, - }; -} - -function getPosition(offset: number, line: number, column: number, markdown: string, raw: string): Position { - let lines: LinePosition[] = []; - const rawLines = raw.split('\n'); - const markdownLines = markdown.split('\n'); - - // eslint-disable-next-line no-labels - md: for (let i = 0; i <= markdownLines.length - rawLines.length; i++) { - lines = []; - for (let j = 0; j < rawLines.length; j++) { - const markdownLine = markdownLines[i + j]; - const rawLine = rawLines[j]; - const lineStartOffset = markdownLine.indexOf(rawLine); - - if (lineStartOffset === -1) { - // eslint-disable-next-line no-labels - continue md; - } - - const beforeMarkdownLines = markdownLines.slice(0, i + j).join('\n') + (i + j > 0 ? '\n' : ''); - const start = { - offset: offset + beforeMarkdownLines.length + lineStartOffset, - line: line + i + j, - column: (i + j === 0 ? column : 0) + lineStartOffset, - }; - const end = { - offset: start.offset + rawLine.length, - line: start.line, - column: start.column + rawLine.length, - }; - - lines.push({ - start, - end, - }); - } - break; - } - - /* node:coverage ignore next 4 */ - if (lines.length === 0) { - // This shouldn't ever happen but if it does it would be nice to have a good error message - throw new Error(`Cannot find ${JSON.stringify(raw)} in ${JSON.stringify(markdown)}`); - } - - const start = lines[0].start; - const end = lines.at(-1)!.end; - - if (lines.length > 1 && lines.at(-1)!.start.offset === end.offset) { - lines = lines.slice(0, -1); - } - - return { - lines, - start, - end, - }; -} diff --git a/static/js/lib/node_modules/marked/LICENSE b/static/js/lib/node_modules/marked/LICENSE.md similarity index 100% rename from static/js/lib/node_modules/marked/LICENSE rename to static/js/lib/node_modules/marked/LICENSE.md diff --git a/static/js/lib/node_modules/marked/README.md b/static/js/lib/node_modules/marked/README.md index 60f0b28..d4ab251 100644 --- a/static/js/lib/node_modules/marked/README.md +++ b/static/js/lib/node_modules/marked/README.md @@ -5,6 +5,7 @@ # Marked [![npm](https://badgen.net/npm/v/marked)](https://www.npmjs.com/package/marked) +[![gzip size](https://badgen.net/badgesize/gzip/https://cdn.jsdelivr.net/npm/marked/marked.min.js)](https://cdn.jsdelivr.net/npm/marked/marked.min.js) [![install size](https://badgen.net/packagephobia/install/marked)](https://packagephobia.now.sh/result?p=marked) [![downloads](https://badgen.net/npm/dt/marked)](https://www.npmjs.com/package/marked) [![github actions](https://github.com/markedjs/marked/workflows/Tests/badge.svg)](https://github.com/markedjs/marked/actions) @@ -17,7 +18,7 @@ ## Demo -Check out the [demo page](https://marked.js.org/demo/) to see Marked in action ⛹️ +Checkout the [demo page](https://marked.js.org/demo/) to see marked in action ⛹️ ## Docs @@ -32,7 +33,7 @@ Also read about: **Node.js:** Only [current and LTS](https://nodejs.org/en/about/releases/) Node.js versions are supported. End of life Node.js versions may become incompatible with Marked at any point in time. -**Browser:** [Baseline Widely Available](https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility) +**Browser:** Not IE11 :) ## Installation @@ -83,7 +84,7 @@ $ marked --help
- + + + diff --git a/views/pages/notes2.gotmpl b/views/pages/notes2.gotmpl index 77b74a6..f633692 100644 --- a/views/pages/notes2.gotmpl +++ b/views/pages/notes2.gotmpl @@ -1,33 +1,35 @@ {{ define "page" }} -
-
-
- - -
- +
{{ end }} diff --git a/views/pages/offline.gotmpl b/views/pages/offline.gotmpl deleted file mode 100644 index 0c283f9..0000000 --- a/views/pages/offline.gotmpl +++ /dev/null @@ -1,4 +0,0 @@ -{{ define "page" }} -
Site is offline.
-
||ERROR||
-{{ end }}