2019-05-28 12:09:54 +02:00
|
|
|
<!doctype html>
|
|
|
|
<html>
|
|
|
|
<head>
|
2020-02-08 12:02:45 -05:00
|
|
|
<!--
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
+-------------------------------------------------------------+
|
2019-05-28 12:42:04 +02:00
|
|
|
| |
|
|
|
|
| Nullboard, a minimalist kanban board |
|
|
|
|
| https://nullboard.io |
|
|
|
|
| |
|
2020-02-08 12:02:45 -05:00
|
|
|
+-------------------------------------------------------------+
|
2019-05-28 12:09:54 +02:00
|
|
|
|
|
|
|
LICENSE
|
|
|
|
|
|
|
|
The 2-clause BSD license with the Commons Clause condition.
|
|
|
|
|
|
|
|
IN SHORT
|
|
|
|
|
|
|
|
You can use, change and distribute the software free of charge
|
|
|
|
provided that you do not sell it or make money off it in
|
|
|
|
certain less direct ways as specified below. When distributed,
|
|
|
|
the software must include a complete copy of this license.
|
|
|
|
|
|
|
|
IN FULL
|
|
|
|
|
|
|
|
The Software is provided to you by the Licensor under the
|
|
|
|
License, as defined below, subject to the following condition.
|
|
|
|
|
|
|
|
Without limiting other conditions in the License, the grant of
|
|
|
|
rights under the License will not include, and the License does
|
|
|
|
not grant to you, the right to Sell the Software.
|
|
|
|
|
|
|
|
For purposes of the foregoing, "Sell" means practicing any or
|
|
|
|
all of the rights granted to you under the License to provide
|
|
|
|
to third parties, for a fee or other consideration (including
|
|
|
|
without limitation fees for hosting or consulting/ support
|
|
|
|
services related to the Software), a product or service whose
|
|
|
|
value derives, entirely or substantially, from the functionality
|
|
|
|
of the Software. Any license notice or attribution required
|
|
|
|
by the License must also include this Commons Clause License
|
|
|
|
Condition notice.
|
|
|
|
|
|
|
|
Software: Nullboard
|
|
|
|
License: The 2-clause BSD License
|
|
|
|
Licensor: Alexander Pankratov / swapped.ch
|
|
|
|
|
|
|
|
-->
|
2020-02-08 12:02:45 -05:00
|
|
|
<meta charset="utf-8">
|
|
|
|
<title>Nullboard</title>
|
|
|
|
<style>
|
|
|
|
|
|
|
|
/***/
|
|
|
|
@font-face {
|
2021-04-05 11:50:02 +02:00
|
|
|
font-family: 'f-barlow';
|
2020-02-08 12:02:45 -05:00
|
|
|
font-weight: 400;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/Barlow-Regular.woff') format('woff');
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
@font-face {
|
2021-04-05 11:50:02 +02:00
|
|
|
font-family: 'f-barlow';
|
2020-02-08 12:02:45 -05:00
|
|
|
font-weight: 500;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/Barlow-Medium.woff') format('woff');
|
|
|
|
}
|
2019-06-10 13:19:05 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
/***/
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-ibm-plex';
|
|
|
|
font-weight: 400;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/IBMPlexSans-Regular.woff') format('woff');
|
|
|
|
}
|
|
|
|
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-ibm-plex';
|
|
|
|
font-weight: 500;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/IBMPlexSans-Medium.woff') format('woff');
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-open-sans';
|
|
|
|
font-weight: 400;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/OpenSans-Regular.woff') format('woff');
|
|
|
|
}
|
|
|
|
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-open-sans';
|
|
|
|
font-weight: 500;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/OpenSans-600.woff') format('woff');
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-segoe-ui';
|
|
|
|
font-weight: 400;
|
|
|
|
font-style: normal;
|
|
|
|
src: local('Segoe UI');
|
|
|
|
}
|
|
|
|
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-segoe-ui';
|
|
|
|
font-weight: 500;
|
|
|
|
font-style: normal;
|
|
|
|
src: local('Segoe UI Semibold');
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-maven-pro';
|
|
|
|
font-weight: 400;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/MavenPro-Regular.woff') format('woff');
|
|
|
|
}
|
|
|
|
|
|
|
|
@font-face {
|
|
|
|
font-family: 'f-maven-pro';
|
|
|
|
font-weight: 500;
|
|
|
|
font-style: normal;
|
|
|
|
src: url('extras/MavenPro-500.woff') format('woff');
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
html {
|
|
|
|
--ff: f-barlow, sans-serif;
|
|
|
|
|
2021-04-07 13:56:10 +02:00
|
|
|
--fs: 11; /* font-size */
|
|
|
|
--lh: calc( var(--fs) * 1.25 ); /* line-height */
|
2021-04-05 11:50:02 +02:00
|
|
|
--fs-head: 13.6; /* font-size of board heading */
|
|
|
|
--fs-nops: 9; /* font-size of the note ops */
|
|
|
|
--lw: calc(20 * var(--fs) + 30); /* .list width */
|
|
|
|
}
|
|
|
|
|
|
|
|
html, body, input, textarea {
|
|
|
|
font-family: var(--ff);
|
|
|
|
font-size: calc( var(--fs) * 1px );
|
|
|
|
line-height: calc( var(--lh) * 1px );
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
html.f-ibm-plex {
|
|
|
|
--ff: f-ibm-plex, sans-serif;
|
|
|
|
--fs: 11;
|
|
|
|
--fs-head: 12.5;
|
|
|
|
--lw: calc(20 * var(--fs) + 40); /* .list width */
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
html.f-open-sans {
|
|
|
|
--ff: f-open-sans, sans-serif;
|
|
|
|
--fs: 11;
|
|
|
|
--fs-head: 12.5;
|
|
|
|
--lw: calc(20 * var(--fs) + 50); /* .list width */
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
html.f-segoe-ui {
|
|
|
|
--ff: f-segoe-ui, sans-serif;
|
|
|
|
--fs: 11;
|
|
|
|
--fs-head: 13;
|
|
|
|
--fs-nops: 8;
|
2021-04-06 13:21:48 +02:00
|
|
|
--lw: calc(22 * var(--fs) + 40); /* .list width */
|
2021-04-05 11:50:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-07 13:56:10 +02:00
|
|
|
/***/
|
|
|
|
html.f-maven-pro {
|
|
|
|
--ff: f-maven-pro, sans-serif;
|
|
|
|
--fs: 12;
|
|
|
|
--fs-head: 13;
|
|
|
|
--lw: calc(20 * var(--fs) + 47); /* .list width */
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
/***/
|
|
|
|
html, body, h1, textarea, input {
|
|
|
|
padding: 0;
|
|
|
|
margin: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
body {
|
|
|
|
background: #fff;
|
|
|
|
background: #f8f9fb;
|
|
|
|
}
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
/***/
|
2021-03-31 18:27:33 +02:00
|
|
|
@keyframes shake {
|
|
|
|
33% { margin-left: -5px; }
|
|
|
|
66% { margin-left: 5px; }
|
|
|
|
100% { margin-left: 0px; }
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
a {
|
|
|
|
text-decoration: none;
|
2020-02-19 03:50:03 +01:00
|
|
|
transition: color 200ms;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
a, a:active, a:focus, textarea, input {
|
|
|
|
outline: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
tt {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
/***/
|
2021-04-06 19:32:46 +02:00
|
|
|
.ding {
|
|
|
|
animation-name: shake;
|
|
|
|
animation-duration: 200ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
.no-user-select {
|
|
|
|
-webkit-touch-callout: none;
|
|
|
|
-webkit-user-select: none;
|
|
|
|
-khtml-user-select: none;
|
|
|
|
-moz-user-select: none;
|
|
|
|
-ms-user-select: none;
|
|
|
|
user-select: none;
|
|
|
|
}
|
|
|
|
}
|
2020-02-08 12:02:45 -05:00
|
|
|
/***/
|
|
|
|
.clearfix:after,
|
|
|
|
.board:after,
|
|
|
|
.lists:after,
|
|
|
|
.notes:after,
|
|
|
|
.head:after,
|
|
|
|
.menu:after {
|
|
|
|
content: "";
|
|
|
|
display: table;
|
|
|
|
clear: both;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.board {
|
2021-04-06 19:54:47 +02:00
|
|
|
min-width: calc( var(--lw) * 1px );
|
2020-02-08 12:02:45 -05:00
|
|
|
|
|
|
|
width: -moz-max-content; /* firefox */
|
|
|
|
width: -webkit-max-content; /* chrome */
|
|
|
|
width: intrinsic; /* safari */
|
|
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
padding: 20px;
|
2020-04-30 18:39:43 +02:00
|
|
|
|
|
|
|
user-select: none;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
body.crowded .board {
|
|
|
|
margin-top: 28px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board u {
|
|
|
|
text-decoration: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board u:before {
|
|
|
|
content: '\00D7';
|
|
|
|
position: relative;
|
|
|
|
top: 2px;
|
2021-04-05 11:50:02 +02:00
|
|
|
font-size: calc(16rem / 11);
|
|
|
|
line-height: calc(10 / 17);
|
2020-02-08 12:02:45 -05:00
|
|
|
font-weight: 400;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.board .head {
|
|
|
|
padding: 5px 0;
|
2021-04-06 23:54:46 +02:00
|
|
|
margin: 1px 5px 0;
|
2020-02-08 12:02:45 -05:00
|
|
|
position: relative;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head .text,
|
|
|
|
.board .head .edit {
|
|
|
|
font-weight: 500;
|
2021-04-05 11:50:02 +02:00
|
|
|
font-size: calc( var(--fs-head) / 11 * 1rem );
|
|
|
|
line-height: calc( 20 / var(--fs-head) );
|
2020-02-08 12:02:45 -05:00
|
|
|
padding: 0 5px 2px;
|
|
|
|
border: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head .text {
|
|
|
|
min-height: 20px;
|
|
|
|
white-space: pre;
|
|
|
|
overflow: hidden;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head .edit {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head .edit::placeholder {
|
|
|
|
font-weight: 400;
|
2021-04-05 11:50:02 +02:00
|
|
|
font-size: calc(10rem / 11);
|
|
|
|
line-height: calc(22 / 10);
|
2020-02-08 12:02:45 -05:00
|
|
|
text-transform: uppercase;
|
|
|
|
color: #1489db;
|
2020-02-19 14:25:11 +01:00
|
|
|
opacity: 0.8;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
.board .head.editing .text {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head.editing .edit {
|
|
|
|
display: block;
|
|
|
|
outline: 1px solid #8eaedd;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .menu {
|
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
|
|
|
right: 0;
|
|
|
|
height: 20px;
|
|
|
|
padding: 5px 6px 7px 30px;
|
|
|
|
background: linear-gradient(to right, #EAEDF000, #EAEDF0 10px);
|
2021-04-05 11:50:02 +02:00
|
|
|
line-height: calc(20 / 11);
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
.board .menu a,
|
|
|
|
.board .ops a {
|
|
|
|
color: #000000A0;
|
|
|
|
transition: color 200ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .menu a {
|
|
|
|
padding-left: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .menu a:hover,
|
|
|
|
.board .ops a:hover {
|
|
|
|
color: #000;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .menu a.warn:hover,
|
|
|
|
.board .ops a.warn:hover {
|
|
|
|
color: #c40;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .menu .undo-board,
|
|
|
|
.board .menu .redo-board {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head.editing .menu {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board > .head {
|
|
|
|
background: #EAEDF0;
|
|
|
|
padding: 5px;
|
|
|
|
margin: 0 0 10px;
|
|
|
|
border-radius: 2px;
|
|
|
|
position: relative;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board > .head .menu {
|
|
|
|
margin-right: 5px;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.board .lists-scroller {
|
|
|
|
height: auto;
|
|
|
|
margin: -1px 0 10px;
|
|
|
|
overflow-x: auto;
|
|
|
|
overflow-y: hidden;
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.lists-scroller div {
|
|
|
|
height: 1px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .lists {
|
|
|
|
white-space: nowrap;
|
|
|
|
overflow: auto;
|
|
|
|
scrollbar-width: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list {
|
|
|
|
display: inline-block;
|
|
|
|
vertical-align: top;
|
2021-04-05 11:50:02 +02:00
|
|
|
width: calc( var(--lw) * 1px );
|
2020-02-08 12:02:45 -05:00
|
|
|
margin: 0 5px 10px;
|
|
|
|
background: linear-gradient(#EAEDF0 30px, #DDE1E5 90px);
|
|
|
|
border-radius: 2px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list::-webkit-scrollbar {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list:first-child {
|
|
|
|
margin-left: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list:last-child {
|
|
|
|
margin-right: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list .notes {
|
|
|
|
padding: 0 5px;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.board .head .menu .teaser {
|
|
|
|
position: absolute;
|
|
|
|
right: 3px;
|
|
|
|
top: 5px;
|
|
|
|
padding: 0 3px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head .menu .bulk {
|
|
|
|
display: none;
|
|
|
|
opacity: 0;
|
|
|
|
z-index: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head .menu:hover .bulk {
|
|
|
|
display: block;
|
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .head .menu:hover .teaser {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.board .list .menu .mov-list-r.half {
|
|
|
|
padding-left: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list .menu .full {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list:first-child .menu .half,
|
|
|
|
.board .list:last-child .menu .half {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list:first-child .menu .mov-list-r.full,
|
|
|
|
.board .list:last-child .menu .mov-list-l.full {
|
|
|
|
display: inline-block;
|
|
|
|
}
|
|
|
|
|
|
|
|
.board .list:first-child:last-child .menu .half,
|
|
|
|
.board .list:first-child:last-child .menu .full {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note {
|
2020-02-08 12:02:45 -05:00
|
|
|
background: #fff;
|
|
|
|
margin-top: 5px;
|
|
|
|
box-shadow: 0 1px 2px #bbb, 0 0 1px #ddd;
|
|
|
|
position: relative;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.dragging,
|
|
|
|
.board .note.dragging.raw {
|
2020-02-08 12:02:45 -05:00
|
|
|
background: #CED4DA;
|
2021-04-05 11:50:02 +02:00
|
|
|
box-shadow: 0 +1px 0 #0001 inset,
|
|
|
|
0 -1px 0 #0001 inset,
|
|
|
|
+1px 0 0 #0001 inset,
|
|
|
|
-1px 0 0 #0001 inset;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.dragging * {
|
2020-02-08 12:02:45 -05:00
|
|
|
opacity: 0 !important;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note:last-child {
|
2020-02-08 12:02:45 -05:00
|
|
|
margin-bottom: 5px;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.board .note {
|
|
|
|
padding-bottom: 6px;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .text,
|
|
|
|
.board .note .edit {
|
2021-04-05 11:50:02 +02:00
|
|
|
padding: 5px 10px 0;
|
2020-02-08 12:02:45 -05:00
|
|
|
margin-right: 15px;
|
2021-04-05 11:50:02 +02:00
|
|
|
min-height: 100%;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .text {
|
2020-02-08 12:02:45 -05:00
|
|
|
white-space: pre-wrap;
|
2020-02-20 17:32:37 +01:00
|
|
|
overflow-wrap: anywhere;
|
2021-04-05 11:50:02 +02:00
|
|
|
min-height: calc( var(--lh) * 1px );
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2020-02-20 01:13:00 +01:00
|
|
|
/***/
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .head .text a,
|
|
|
|
.board .note .text a {
|
2020-02-20 01:13:00 +01:00
|
|
|
color: inherit;
|
|
|
|
cursor: default;
|
|
|
|
transition: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
@keyframes whoomp {
|
|
|
|
0% { color: inherit; }
|
|
|
|
30% { color: #888; }
|
|
|
|
100% { color: inherit; }
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .head .text a:hover,
|
|
|
|
.board .note .text a:hover {
|
2020-02-20 01:13:00 +01:00
|
|
|
animation-name: whoomp;
|
|
|
|
animation-duration: 700ms;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.reveal .board .head .text a,
|
|
|
|
.reveal .board .note .text a {
|
2020-02-20 01:13:00 +01:00
|
|
|
color: #1489db;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.reveal .board .head .text a:hover,
|
|
|
|
.reveal .board .note .text a:hover {
|
2020-02-20 01:13:00 +01:00
|
|
|
animation-name: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .edit {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: none;
|
|
|
|
border: none;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.editing {
|
2020-02-08 12:02:45 -05:00
|
|
|
box-shadow: none;
|
|
|
|
outline: 1px solid #8eaedd;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.editing .text {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.editing .edit {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: block;
|
|
|
|
resize: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .ops {
|
2020-02-08 12:02:45 -05:00
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
|
|
|
right: 0;
|
|
|
|
opacity: 0;
|
|
|
|
transition: opacity 400ms;
|
|
|
|
cursor: default;
|
2021-04-05 11:50:02 +02:00
|
|
|
font-size: calc(9rem / 11);
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.editing .ops {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note:hover .ops {
|
2020-02-08 12:02:45 -05:00
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .ops .teaser {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: block;
|
|
|
|
margin-top: 2px;
|
|
|
|
margin-right: 1px;
|
|
|
|
padding-right: 3px;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .ops .teaser:before {
|
2020-02-08 12:02:45 -05:00
|
|
|
content: '\2261';
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .ops .bulk {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: none;
|
|
|
|
background: #fff;
|
|
|
|
border-left: none;
|
2021-04-05 11:50:02 +02:00
|
|
|
padding: 1px 0 2px 5px;
|
|
|
|
font-size: calc( var(--fs-nops) * 1px );
|
2020-02-08 12:02:45 -05:00
|
|
|
font-weight: 500;
|
|
|
|
border-left: 1px solid #ddd;
|
|
|
|
border-bottom: 1px solid #ddd;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .ops .bulk a {
|
2020-02-08 12:02:45 -05:00
|
|
|
padding-right: 4px;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .ops:hover .bulk {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: block;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note .ops:hover .teaser {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.raw {
|
2020-02-08 12:02:45 -05:00
|
|
|
background: transparent;
|
|
|
|
box-shadow: none;
|
|
|
|
font-weight: 500;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.raw.editing {
|
2020-02-08 12:02:45 -05:00
|
|
|
background: #fff;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.raw .text {
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
/***/
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.collapsed {
|
2021-04-05 11:50:02 +02:00
|
|
|
padding-bottom: 6px;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.board .note.collapsed .text,
|
|
|
|
.note-dragster.collapsed .text {
|
|
|
|
max-height: calc( var(--lh) * 1px );
|
2020-02-08 12:02:45 -05:00
|
|
|
overflow: hidden;
|
2021-04-05 11:50:02 +02:00
|
|
|
padding-bottom: 0;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.collapsed .ops {
|
2020-02-08 12:02:45 -05:00
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.collapsed .ops .teaser {
|
2020-02-08 12:02:45 -05:00
|
|
|
padding: 1px 3px 0 1px;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.collapsed .ops .teaser:before {
|
2020-02-08 12:02:45 -05:00
|
|
|
content: '_';
|
|
|
|
top: 1px;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.collapsed:hover .ops .teaser:before {
|
2020-02-08 12:02:45 -05:00
|
|
|
content: '\2261';
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2021-04-02 01:59:34 +02:00
|
|
|
.note-dragster {
|
2020-02-08 12:02:45 -05:00
|
|
|
z-index: 2;
|
|
|
|
position: absolute;
|
|
|
|
opacity: 0;
|
|
|
|
background: #fff;
|
|
|
|
white-space: pre-wrap;
|
|
|
|
cursor: move;
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
padding: 5px 25px 6px 10px;
|
2020-02-08 12:02:45 -05:00
|
|
|
|
|
|
|
box-shadow: 0 +1px 0 #ACB4BC inset,
|
|
|
|
0 -1px 0 #ACB4BC inset,
|
|
|
|
+1px 0 0 #ACB4BC inset,
|
|
|
|
-1px 0 0 #ACB4BC inset,
|
|
|
|
0px 1px 3px #00000030;
|
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
.note-dragster a {
|
2020-02-20 01:13:00 +01:00
|
|
|
color: #000;
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
/***/
|
|
|
|
.logo {
|
|
|
|
position: absolute;
|
|
|
|
top: 9px;
|
|
|
|
left: 9px;
|
2021-04-05 11:50:02 +02:00
|
|
|
line-height: calc(19 / 11);
|
2020-02-08 12:02:45 -05:00
|
|
|
padding: 6px 12px;
|
|
|
|
opacity: 0.6;
|
|
|
|
z-index: 3;
|
|
|
|
background: #f8f9fb;
|
|
|
|
}
|
|
|
|
|
|
|
|
body.crowded .logo:hover {
|
|
|
|
background: #fff;
|
|
|
|
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo:hover {
|
|
|
|
opacity: 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo .bulk {
|
|
|
|
overflow: hidden;
|
|
|
|
height: 0;
|
|
|
|
opacity: 0;
|
|
|
|
transition: opacity 400ms;
|
2021-04-05 11:50:02 +02:00
|
|
|
padding-top: 1px;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
.logo:hover .bulk {
|
|
|
|
height: auto;
|
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo a {
|
|
|
|
color: #000;
|
|
|
|
display: block;
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo a:hover {
|
|
|
|
color: #1489db;
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo .bulk a:before {
|
|
|
|
display: inline-block;
|
|
|
|
content: '-';
|
|
|
|
width: 11px;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.config {
|
|
|
|
position: absolute;
|
|
|
|
top: 10px;
|
|
|
|
right: 21px;
|
2021-04-06 23:54:46 +02:00
|
|
|
line-height: calc(19 / 11);
|
2020-02-08 12:02:45 -05:00
|
|
|
z-index: 3;
|
|
|
|
background: #f8f9fb;
|
|
|
|
}
|
|
|
|
|
2021-04-08 13:24:35 +02:00
|
|
|
.crowded .config:hover,
|
|
|
|
.crowded.adjusting .config {
|
2020-02-08 12:02:45 -05:00
|
|
|
background: #fff;
|
|
|
|
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
|
|
|
}
|
|
|
|
|
|
|
|
.config a {
|
|
|
|
display: block;
|
|
|
|
color: #000;
|
|
|
|
transition: color 200ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
.config a:hover {
|
|
|
|
color: #1489db;
|
|
|
|
}
|
|
|
|
|
|
|
|
.config .teaser {
|
|
|
|
padding: 5px;
|
|
|
|
color: #999;
|
|
|
|
}
|
|
|
|
|
|
|
|
.config .bulk {
|
|
|
|
margin-right: 20px;
|
2021-04-05 11:50:02 +02:00
|
|
|
padding: 5px 0 0 22px;
|
2020-02-08 12:02:45 -05:00
|
|
|
transition: opacity 400ms;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.config .bulk .boards {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: none;
|
|
|
|
padding: 6px 2px;
|
|
|
|
margin: 6px -2px;
|
|
|
|
border-top: 1px solid #00000028;
|
|
|
|
border-bottom: 1px solid #00000028;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.config .bulk .boards a.load-board {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: block;
|
2021-04-06 23:54:46 +02:00
|
|
|
padding-left: 5px;
|
|
|
|
margin-left: -5px;
|
|
|
|
transition: none;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.config .bulk .boards a.load-board.active {
|
2020-02-08 12:02:45 -05:00
|
|
|
color: #1489db;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.config .bulk .boards a.load-board.active:before {
|
2020-02-08 12:02:45 -05:00
|
|
|
content: '\2022 ';
|
|
|
|
display: inline-block;
|
|
|
|
width: 13px;
|
|
|
|
margin-left: -13px;
|
|
|
|
}
|
2020-01-30 11:19:37 -05:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.config .bulk .boards a.load-board.active:hover {
|
2021-04-02 01:59:34 +02:00
|
|
|
color: #000;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.config .bulk .boards a.load-board.dragging {
|
2021-04-02 01:59:34 +02:00
|
|
|
background: #DDE1E5;
|
|
|
|
border-radius: 2px;
|
|
|
|
color: transparent;
|
2021-04-06 23:54:46 +02:00
|
|
|
transition: none;
|
2021-04-05 11:50:02 +02:00
|
|
|
box-shadow: 0 0 1px #0002 inset;
|
2021-04-02 01:59:34 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
.config .bulk .boards a.load-board.dragging.active:before {
|
|
|
|
content: '';
|
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
.load-dragster {
|
|
|
|
z-index: 10;
|
|
|
|
position: absolute;
|
|
|
|
opacity: 0;
|
2021-04-05 11:50:02 +02:00
|
|
|
line-height: calc(19 / 11);
|
2021-04-02 01:59:34 +02:00
|
|
|
padding-left: 5px;
|
|
|
|
background: #fff;
|
2020-02-08 12:02:45 -05:00
|
|
|
color: #000;
|
2021-04-02 01:59:34 +02:00
|
|
|
border-radius: 2px;
|
|
|
|
cursor: move;
|
2021-04-06 23:54:46 +02:00
|
|
|
outline: 1px solid #ACB4BC;
|
|
|
|
box-shadow: 0px 1px 3px #00000030;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
2020-02-19 14:25:11 +01:00
|
|
|
.config .bulk a i,
|
|
|
|
.config .bulk a b {
|
|
|
|
font-style: normal;
|
|
|
|
font-weight: inherit;
|
|
|
|
}
|
|
|
|
|
|
|
|
.config .bulk a i {
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
.config .bulk input.imp-board-select {
|
|
|
|
position: absolute;
|
|
|
|
width: 1px;
|
|
|
|
height: 1px;
|
|
|
|
visibility: hidden;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.config .bulk .break {
|
2021-04-05 18:20:23 +02:00
|
|
|
padding: 6px 2px 0;
|
|
|
|
margin: 6px -2px 0;
|
2020-02-19 14:25:11 +01:00
|
|
|
border-top: 1px solid #00000028;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
/***/
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .section .title {
|
2021-04-05 11:50:02 +02:00
|
|
|
text-align: center;
|
|
|
|
width: 0;
|
|
|
|
display: inline-block;
|
|
|
|
white-space: pre;
|
2021-04-06 16:51:20 +02:00
|
|
|
transition: width 250ms, padding 250ms;
|
2021-04-05 11:50:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 20:21:08 +02:00
|
|
|
.config .bulk .section .title u {
|
|
|
|
text-decoration: none;
|
2021-04-06 16:51:20 +02:00
|
|
|
transition: opacity 100ms;
|
2021-04-05 11:50:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .section .details {
|
|
|
|
height: 0;
|
2021-04-05 11:50:02 +02:00
|
|
|
opacity: 0;
|
|
|
|
transition: opacity 250ms;
|
2021-04-05 18:20:23 +02:00
|
|
|
padding-right: 8px;
|
|
|
|
margin-right: -8px;
|
|
|
|
}
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
/***/
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .section.open {
|
|
|
|
padding-bottom: 8px;
|
|
|
|
border-bottom: 1px solid #00000028;
|
|
|
|
}
|
|
|
|
|
2021-04-06 19:54:47 +02:00
|
|
|
.crowded .config .bulk .section.open {
|
|
|
|
border-bottom: none;
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .section.open .title {
|
2021-04-06 13:21:48 +02:00
|
|
|
width: 100%;
|
|
|
|
font-weight: 500;
|
2021-04-06 16:51:20 +02:00
|
|
|
padding-left: 5px;
|
|
|
|
transition: width 250ms, padding 250ms;
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 20:21:08 +02:00
|
|
|
.config .bulk .section.open .title u {
|
2021-04-06 16:51:20 +02:00
|
|
|
opacity: 0;
|
|
|
|
transition: opacity 100ms;
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .section.open .details {
|
|
|
|
height: 100%;
|
2021-04-06 13:21:48 +02:00
|
|
|
opacity: 1;
|
|
|
|
transition: opacity 250ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .f-prefs table {
|
2021-04-05 18:20:23 +02:00
|
|
|
padding: 0;
|
|
|
|
margin: 0;
|
|
|
|
border-collapse: collapse;
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .f-prefs td {
|
2021-04-05 18:20:23 +02:00
|
|
|
margin: 0;
|
|
|
|
padding: 0 0 0 5px;
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .f-prefs td.name {
|
2021-04-05 18:20:23 +02:00
|
|
|
width: 100%;
|
|
|
|
white-space: pre;
|
|
|
|
padding-left: 0;
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .f-prefs tr td.val {
|
2021-04-05 18:20:23 +02:00
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
2021-04-06 18:37:26 +02:00
|
|
|
.fs-set .config .bulk .ui-prefs .f-prefs tr.ui-fs td.val,
|
2021-04-06 19:32:46 +02:00
|
|
|
.lh-set .config .bulk .ui-prefs .f-prefs tr.ui-lh td.val,
|
|
|
|
.lw-set .config .bulk .ui-prefs .f-prefs tr.ui-lw td.val {
|
2021-04-06 13:21:48 +02:00
|
|
|
color: #1489db;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .f-prefs a {
|
2021-04-05 18:20:23 +02:00
|
|
|
display: inline-block;
|
|
|
|
padding: 0 2px;
|
|
|
|
transition: padding 250ms;
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .f-prefs a.less:hover {
|
2021-04-05 18:20:23 +02:00
|
|
|
padding: 0 4px 0 0;
|
|
|
|
transition: padding 250ms;
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .f-prefs a.more:hover {
|
|
|
|
padding: 0 0 0 4px;
|
|
|
|
transition: padding 250ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
.config .bulk .ui-prefs .f-prefs a.more:hover {
|
2021-04-05 18:20:23 +02:00
|
|
|
padding: 0 0 0 4px;
|
|
|
|
transition: padding 250ms;
|
2021-04-05 11:50:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
2021-04-06 16:51:20 +02:00
|
|
|
.config .bulk .ui-prefs .switch-font.active:before {
|
2021-04-05 11:50:02 +02:00
|
|
|
content: '\2022 ';
|
|
|
|
display: inline-block;
|
|
|
|
width: 13px;
|
|
|
|
margin-left: -13px;
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
/***/
|
|
|
|
.config .bulk {
|
|
|
|
display: none;
|
|
|
|
opacity: 0;
|
|
|
|
}
|
|
|
|
|
2021-04-08 13:24:35 +02:00
|
|
|
.config:hover .teaser,
|
|
|
|
.adjusting .config .teaser {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2021-04-08 13:24:35 +02:00
|
|
|
.config:hover .bulk,
|
|
|
|
.adjusting .config .bulk {
|
2020-02-08 12:02:45 -05:00
|
|
|
display: block;
|
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
/***/
|
|
|
|
.adjusting * {
|
|
|
|
cursor: row-resize !important;
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
/***/
|
|
|
|
.overlay {
|
|
|
|
position: fixed;
|
|
|
|
z-index: 10;
|
|
|
|
top: 0;
|
|
|
|
left: 0;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
background: rgba(0,0,0,0.9);
|
|
|
|
display: none;
|
2020-02-19 12:46:15 +01:00
|
|
|
color: #000;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.overlay .license {
|
2021-04-05 11:50:02 +02:00
|
|
|
font-size: calc(12rem / 11);
|
|
|
|
line-height: calc(16 / 12);
|
2020-02-08 12:02:45 -05:00
|
|
|
white-space: pre-wrap;
|
|
|
|
width: 384px;
|
|
|
|
height: auto;
|
|
|
|
max-height: 600px;
|
|
|
|
padding: 20px 25px 22px;
|
|
|
|
overflow-y: auto;
|
|
|
|
background: #fff;
|
|
|
|
position: absolute;
|
|
|
|
top: 100px;
|
|
|
|
left: 50%;
|
|
|
|
margin-left: -192px;
|
2021-04-05 11:50:02 +02:00
|
|
|
|
|
|
|
width: calc( (var(--fs) * 36 + 6) * 1px ); /* 402px, 476px */
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
.overlay .license a {
|
|
|
|
color: #1489db;
|
|
|
|
}
|
|
|
|
|
|
|
|
.overlay .license span {
|
|
|
|
display: inline-block;
|
|
|
|
padding-right: 8px;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
.overlay .about {
|
2021-04-05 11:50:02 +02:00
|
|
|
font-size: calc(12rem / 11);
|
|
|
|
line-height: calc(16 / 12);
|
2020-02-08 12:02:45 -05:00
|
|
|
text-align: center;
|
|
|
|
height: auto;
|
|
|
|
padding: 50px 25px;
|
|
|
|
background: #fff;
|
|
|
|
position: absolute;
|
|
|
|
top: 100px;
|
|
|
|
left: 50%;
|
|
|
|
margin-left: -145px;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.overlay .about,
|
|
|
|
.overlay .about div {
|
|
|
|
width: calc( (var(--fs) * 18 + 39) * 1px ); /* 240px, 277px */
|
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
.overlay .about h1 {
|
2021-04-05 11:50:02 +02:00
|
|
|
font-size: calc(15rem / 11);
|
2020-02-08 12:02:45 -05:00
|
|
|
font-weight: 500;
|
|
|
|
margin-bottom: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.overlay .about a {
|
|
|
|
display: block;
|
|
|
|
color: #1489db;
|
|
|
|
}
|
|
|
|
|
|
|
|
.overlay .about div {
|
|
|
|
position: absolute;
|
|
|
|
bottom: -30px;
|
2021-03-31 20:49:29 +02:00
|
|
|
color: #eee;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
.overlay .about div span {
|
|
|
|
display: inline-block;
|
|
|
|
text-align: left;
|
|
|
|
padding-right: 10px;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***/
|
|
|
|
|
|
|
|
@media print {
|
|
|
|
.logo, .config,
|
|
|
|
.board .head .teaser,
|
|
|
|
.list .head .teaser {
|
|
|
|
visibility: hidden;
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note {
|
2020-02-08 12:02:45 -05:00
|
|
|
box-shadow: none;
|
|
|
|
outline: 1px solid #ccc;
|
|
|
|
}
|
|
|
|
|
2020-02-20 23:37:13 +01:00
|
|
|
.board .note.raw {
|
2020-02-08 12:02:45 -05:00
|
|
|
outline: none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 09:08:28 -05:00
|
|
|
/*
|
2020-02-19 03:50:03 +01:00
|
|
|
* Dark mode
|
|
|
|
*/
|
2021-04-06 23:54:46 +02:00
|
|
|
.theme-dark body {
|
|
|
|
background: #09090A;
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #d6d6d6;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .head {
|
2021-04-06 23:54:46 +02:00
|
|
|
background: #17171a;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2020-02-19 03:50:03 +01:00
|
|
|
/***/
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .menu {
|
2021-04-06 23:54:46 +02:00
|
|
|
background: linear-gradient(to right, #17171a00, #17171a 10px);
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .menu a {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #aaa;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .menu a:hover {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #fc4;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .menu a.warn:hover,
|
|
|
|
.theme-dark .board .ops a.warn:hover {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #fc5555 !important;
|
2021-04-05 11:50:02 +02:00
|
|
|
text-shadow: 0 0 1px #fc555544;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .head {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #eee;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .head .edit::placeholder {
|
2020-02-19 12:42:00 +01:00
|
|
|
color: #bf9d21;
|
|
|
|
}
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
.theme-dark .board > .head {
|
|
|
|
box-shadow: 0 0 2px #fff1 inset;
|
|
|
|
}
|
|
|
|
|
2020-02-19 03:50:03 +01:00
|
|
|
/***/
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .list {
|
2021-04-06 23:54:46 +02:00
|
|
|
background: #17171a;
|
|
|
|
box-shadow: 0 0 2px #fff1 inset;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note {
|
2021-04-06 23:54:46 +02:00
|
|
|
background: linear-gradient(#242426, #202022);
|
|
|
|
box-shadow: 0 1px 3px #000a;
|
2020-02-19 03:50:03 +01:00
|
|
|
text-shadow: 0 0 4px #0008;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
.theme-dark .reveal .board .head .text a,
|
|
|
|
.theme-dark .reveal .board .note .text a {
|
2020-02-20 01:13:00 +01:00
|
|
|
color: #fc0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@keyframes whoomp-dark {
|
|
|
|
0% { color: inherit; }
|
|
|
|
30% { color: #fff; }
|
|
|
|
100% { color: inherit; }
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .head .text a:hover,
|
|
|
|
.theme-dark .board .note .text a:hover {
|
2020-02-20 01:13:00 +01:00
|
|
|
animation-name: whoomp-dark;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note.raw {
|
2020-02-19 03:50:03 +01:00
|
|
|
background: transparent;
|
2020-02-14 08:19:49 -05:00
|
|
|
box-shadow: none;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note.raw .text {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #eee;
|
|
|
|
text-shadow: 0 0 4px #0008;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note .ops .teaser {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #ccc;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note .ops .bulk {
|
2021-04-06 23:54:46 +02:00
|
|
|
background: #202022;
|
2020-02-19 03:50:03 +01:00
|
|
|
border-left: 1px solid #111;
|
|
|
|
border-bottom: 1px solid #111;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note.raw .ops .bulk {
|
2020-02-19 03:50:03 +01:00
|
|
|
border: none;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note .ops .bulk a {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #ccc;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note .ops .bulk a:hover {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #fc2;
|
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
/***/
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note.dragging,
|
|
|
|
.theme-dark .board .note.dragging.raw {
|
2021-04-06 23:54:46 +02:00
|
|
|
background: #09090A;
|
|
|
|
outline: 1px solid #fff2;
|
2020-02-19 03:50:03 +01:00
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
.theme-dark .note-dragster {
|
2021-04-06 23:54:46 +02:00
|
|
|
box-shadow: 0px 1px 4px #000;
|
|
|
|
background: linear-gradient(#242426, #202022);
|
|
|
|
outline: 1px solid #fc28;
|
2020-02-19 03:50:03 +01:00
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
.theme-dark .note-dragster a {
|
2020-02-20 01:13:00 +01:00
|
|
|
color: #d6d6d6;
|
|
|
|
}
|
|
|
|
|
2020-02-19 03:50:03 +01:00
|
|
|
/***/
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark textarea,
|
|
|
|
.theme-dark input {
|
2020-02-19 03:50:03 +01:00
|
|
|
background: #111315;
|
|
|
|
color: #eee;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .head.editing .edit {
|
2020-02-19 03:50:03 +01:00
|
|
|
outline: 1px solid #bc9908;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .board .note.editing {
|
2020-02-19 03:50:03 +01:00
|
|
|
background: #111315;
|
|
|
|
outline: 1px solid #bc9908;
|
|
|
|
}
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
/***/
|
|
|
|
.theme-dark .logo a {
|
|
|
|
color: #ccc;
|
|
|
|
}
|
|
|
|
|
|
|
|
.theme-dark .logo,
|
|
|
|
.theme-dark.crowded .logo:hover {
|
|
|
|
background: #09090A;
|
|
|
|
}
|
|
|
|
|
|
|
|
.theme-dark .logo a:hover {
|
|
|
|
color: #fc2;
|
|
|
|
}
|
|
|
|
|
|
|
|
.theme-dark .logo > a:hover {
|
|
|
|
color: #fff;
|
|
|
|
}
|
|
|
|
|
2020-02-19 03:50:03 +01:00
|
|
|
/***/
|
2021-04-05 11:50:02 +02:00
|
|
|
.theme-dark .config,
|
|
|
|
.theme-dark.crowded .config:hover {
|
2021-04-06 23:54:46 +02:00
|
|
|
background: #09090A !important;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .config a {
|
2020-02-12 09:08:28 -05:00
|
|
|
color: #ddd;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .config a:hover {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #fc2;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.theme-dark .config .bulk .boards {
|
2020-02-19 14:25:11 +01:00
|
|
|
border-top: 1px solid #fff2;
|
|
|
|
border-bottom: 1px solid #fff2;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.theme-dark .config .bulk .boards a.load-board.active {
|
2020-02-19 03:50:03 +01:00
|
|
|
color: #fc2;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.theme-dark .config .bulk .boards a.load-board.active:hover {
|
2021-04-02 01:59:34 +02:00
|
|
|
color: #ddd;
|
|
|
|
}
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
.theme-dark .config .bulk .break {
|
2020-02-19 14:25:11 +01:00
|
|
|
border-top: 1px solid #fff2;
|
|
|
|
}
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
.theme-dark.fs-set .config .bulk .ui-prefs .f-prefs tr.ui-fs td.val,
|
|
|
|
.theme-dark.lh-set .config .bulk .ui-prefs .f-prefs tr.ui-lh td.val,
|
|
|
|
.theme-dark.lw-set .config .bulk .ui-prefs .f-prefs tr.ui-lw td.val {
|
2021-04-06 16:51:20 +02:00
|
|
|
color: #fc2;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .config a.switch-theme i {
|
2020-02-19 14:25:11 +01:00
|
|
|
display: inline;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
.theme-dark .config a.switch-theme b {
|
2020-02-19 14:25:11 +01:00
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
/***/
|
2021-04-06 23:54:46 +02:00
|
|
|
.theme-dark .config .bulk .boards .load-board.dragging,
|
|
|
|
.theme-dark .config .bulk .boards .load-board.active.dragging {
|
|
|
|
background: #fff2;
|
|
|
|
color: transparent;
|
2021-04-02 01:59:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.theme-dark .load-dragster {
|
2021-04-07 18:51:52 +02:00
|
|
|
background: #09090A;
|
2021-04-02 01:59:34 +02:00
|
|
|
box-shadow: 0px 2px 4px #000;
|
2021-04-06 23:54:46 +02:00
|
|
|
outline: 1px solid #fc2a;
|
|
|
|
color: #ddd;
|
2020-02-12 09:08:28 -05:00
|
|
|
}
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
</style>
|
|
|
|
|
|
|
|
</head>
|
2019-05-28 12:09:54 +02:00
|
|
|
<body>
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=logo>
|
|
|
|
<a href=https://nullboard.io>Nullboard</a>
|
|
|
|
<div class=bulk>
|
|
|
|
<a href=# class=view-about>About</a>
|
|
|
|
<a href=# class=view-license>License</a>
|
|
|
|
<a href=https://nullboard.io/github target=_blank>Github</a>
|
|
|
|
<a href=https://nullboard.io/twitter target=_blank>Twitter</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
<div class='config no-user-select'>
|
2020-02-08 12:02:45 -05:00
|
|
|
<a href=# class=teaser>≡</a>
|
|
|
|
<div class=bulk>
|
|
|
|
<a href=# class=add-board>Add new board...</a>
|
2021-04-05 11:50:02 +02:00
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
<div class=boards draggable=false>
|
2019-05-28 12:09:54 +02:00
|
|
|
<!-- here'll be boards -->
|
|
|
|
</div>
|
2021-04-05 11:50:02 +02:00
|
|
|
|
2021-03-31 20:20:49 +02:00
|
|
|
<a href=# class=exp-board>Export current board...</a>
|
2021-03-31 20:49:29 +02:00
|
|
|
<a href=# class=imp-board>Import boards...</a>
|
2020-02-08 12:02:45 -05:00
|
|
|
<input class=imp-board-select type="file" accept=".nbx">
|
2021-04-05 11:50:02 +02:00
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
<div class="section ui-prefs break">
|
2021-04-06 20:21:08 +02:00
|
|
|
<a href=# class=title>UI preferences<u>...</u></a>
|
2021-04-06 16:51:20 +02:00
|
|
|
<div class=details>
|
2021-04-05 11:50:02 +02:00
|
|
|
<a href="#" class="switch-font active break" font="barlow">Use Barlow</a>
|
2021-04-06 13:21:48 +02:00
|
|
|
<a href="#" class="switch-font" font="ibm-plex">Use IBM Plex Sans</a>
|
|
|
|
<a href="#" class="switch-font" font="open-sans">Use Open Sans</a>
|
|
|
|
<a href="#" class="switch-font" font="segoe-ui">Use Segoe UI</a>
|
|
|
|
<a href="#" class="switch-font" font="maven-pro">Use Maven Pro</a>
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
<div class='f-prefs break'>
|
2021-04-06 13:21:48 +02:00
|
|
|
<table>
|
2021-04-06 19:32:46 +02:00
|
|
|
<tr class='ui-fs'><td class=name>Font size:</td> <td><a href=# class=less><</a></td><td class=val></td><td><a href=# class=more>></a></td></tr>
|
|
|
|
<tr class='ui-lh'><td class=name>Line height:</td><td><a href=# class=less><</a></td><td class=val></td><td><a href=# class=more>></a></td></tr>
|
|
|
|
<tr class='ui-lw'><td class=name>List width:</td> <td><a href=# class=less><</a></td><td class=val></td><td><a href=# class=more>></a></td></tr>
|
2021-04-05 18:20:23 +02:00
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
<a href="#" class="switch-theme break">Use <i>light</i><b>dark</b> theme</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
2020-02-08 12:02:45 -05:00
|
|
|
</div>
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=wrap>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=overlay>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<tt>
|
|
|
|
<!-- templates -->
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=board>
|
|
|
|
<div class=head>
|
|
|
|
<div class=text></div>
|
|
|
|
<input class=edit spellcheck=false placeholder='Name of the board'>
|
|
|
|
<div class=menu>
|
|
|
|
<a href=# class=teaser>≡</a>
|
|
|
|
<div class=bulk>
|
|
|
|
<a href=# class='del-board warn'><u></u> Board</a>
|
|
|
|
<a href=# class='undo-board'>Undo</a>
|
|
|
|
<a href=# class='redo-board'>Redo</a>
|
|
|
|
<a href=# class='add-list'>+ List</a>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=lists-scroller><div></div></div>
|
|
|
|
<div class=lists>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=list>
|
|
|
|
<div class=head>
|
|
|
|
<div class=text></div>
|
|
|
|
<input class=edit spellcheck=false placeholder='Name of the list'>
|
|
|
|
<div class=menu>
|
|
|
|
<a href=# class=teaser>≡</a>
|
|
|
|
<div class=bulk>
|
|
|
|
<a href=# class='del-list warn'><u></u> List</a>
|
|
|
|
<a href=# class='mov-list-l full'>< Move</a>
|
|
|
|
<a href=# class='mov-list-l half'>< Mo</a><a href=# class='mov-list-r half'>ve ></a>
|
|
|
|
<a href=# class='mov-list-r full'>Move ></a>
|
|
|
|
<a href=# class='add-note'>+ Note</a>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=notes>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=note>
|
|
|
|
<div class=ops>
|
|
|
|
<a href=# class=teaser></a>
|
|
|
|
<div class=bulk>
|
2021-04-05 11:50:02 +02:00
|
|
|
<a href=# class='del-note warn'>X</a>
|
2020-02-08 12:02:45 -05:00
|
|
|
<a href=# class='raw-note'>R</a>
|
|
|
|
<a href=# class='collapse'>_</a>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
2021-04-05 11:50:02 +02:00
|
|
|
<div class=text> </div>
|
2020-02-08 12:02:45 -05:00
|
|
|
<textarea class=edit spellcheck=false></textarea>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
<a href=# class=load-board></a>
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
<textarea class=encoder></textarea>
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=about>
|
2019-05-28 12:09:54 +02:00
|
|
|
<h1>Nullboard</h1>
|
|
|
|
Minimalist locally-stored kanban board
|
2020-02-08 12:02:45 -05:00
|
|
|
<a href=https://nullboard.io target=_blank>https://nullboard.io</a>
|
2019-05-28 12:09:54 +02:00
|
|
|
<div></div>
|
|
|
|
</div>
|
|
|
|
|
2020-02-08 12:02:45 -05:00
|
|
|
<div class=license>
|
2019-05-28 12:09:54 +02:00
|
|
|
</div>
|
|
|
|
</tt>
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
2021-03-29 10:09:46 +02:00
|
|
|
<script src="extras/jquery-3.3.1.min.js"></script>
|
|
|
|
<script>window.jQuery || document.write('<script src="https://code.jquery.com/jquery-3.3.1.min.js">\x3C/script>')</script>
|
2021-03-31 18:27:33 +02:00
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
<script type="text/javascript">
|
|
|
|
|
|
|
|
Number.prototype.clamp = function(min, max)
|
|
|
|
{
|
|
|
|
return Math.min(Math.max(this, min), max);
|
|
|
|
};
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
2019-05-28 12:09:54 +02:00
|
|
|
<script type="text/javascript">
|
2020-02-08 12:02:45 -05:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function AppConfig()
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
this.format = NB.confVersion;
|
|
|
|
this.maxUndo = 50; // board revisions to keep
|
|
|
|
this.fontName = null; // font-family
|
|
|
|
this.fontSize = null; // font-size
|
|
|
|
this.lineHeight = null; // line-height
|
2021-04-06 19:32:46 +02:00
|
|
|
this.listWidth = null; // list-width
|
2021-04-06 19:09:14 +02:00
|
|
|
this.theme = null; // default or 'dark'
|
|
|
|
this.board = null; // active board
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function BoardMeta()
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
this.title = '';
|
2021-03-31 19:32:01 +02:00
|
|
|
this.current = 1; // revision
|
2021-04-02 01:59:34 +02:00
|
|
|
this.ui_spot = 0; // 0 = not set
|
2021-03-31 19:32:01 +02:00
|
|
|
this.history = [ ]; // revision IDs
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
class Storage
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 22:12:53 +02:00
|
|
|
constructor()
|
|
|
|
{
|
|
|
|
this.type = '?';
|
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
this.conf = new AppConfig();
|
2021-03-31 22:12:53 +02:00
|
|
|
this.boardIndex = new Map();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
open()
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
return this.openInner();
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
wipe()
|
|
|
|
{
|
|
|
|
return this.wipeInner();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
getConfig()
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
return this.conf;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setActiveBoard(board_id)
|
|
|
|
{
|
|
|
|
var meta = board_id ? this.boardIndex.get(board_id) : true;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta)
|
|
|
|
throw `Invalid board_id in setActiveBoard(... ${board_id})`;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.conf.board = board_id;
|
|
|
|
return this.setJson('config', this.conf);
|
|
|
|
}
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setTheme(theme)
|
|
|
|
{
|
|
|
|
this.conf.theme = theme;
|
|
|
|
return this.setJson('config', this.conf);
|
|
|
|
}
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-04-06 15:29:12 +02:00
|
|
|
setFontName(fname)
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
this.conf.fontName = fname;
|
2021-03-31 18:27:33 +02:00
|
|
|
return this.setJson('config', this.conf);
|
|
|
|
}
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-04-06 15:29:12 +02:00
|
|
|
setFontSize(fs)
|
2021-04-05 11:50:02 +02:00
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
this.conf.fontSize = fs;
|
2021-04-05 11:50:02 +02:00
|
|
|
return this.setJson('config', this.conf);
|
|
|
|
}
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
setLineHeight(lh)
|
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
this.conf.lineHeight = lh;
|
2021-04-06 16:51:20 +02:00
|
|
|
return this.setJson('config', this.conf);
|
|
|
|
}
|
|
|
|
|
2021-04-06 19:32:46 +02:00
|
|
|
setListWidth(lw)
|
|
|
|
{
|
|
|
|
this.conf.listWidth = lw;
|
|
|
|
return this.setJson('config', this.conf);
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
getBoardIndex()
|
|
|
|
{
|
|
|
|
return this.boardIndex;
|
|
|
|
}
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
saveBoard(board)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 1. assign new revision (next unused)
|
|
|
|
* 2. trim all in-between revisions bypassed by undos if any
|
|
|
|
* 3. cap history as per config
|
|
|
|
*/
|
|
|
|
var meta = this.boardIndex.get(board.id);
|
|
|
|
var ok_data, ok_meta;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
delete board.history; // remove temporarily
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta)
|
|
|
|
{
|
2021-03-31 19:32:01 +02:00
|
|
|
board.revision = 1;
|
|
|
|
|
|
|
|
ok_data = this.setJson('board.' + board.id + '.' + board.revision, board);
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
meta = new BoardMeta();
|
2021-03-31 19:32:01 +02:00
|
|
|
meta.title = board.title || '(Untitled board)';
|
|
|
|
meta.current = board.revision;
|
|
|
|
meta.history = [ board.revision ];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.boardIndex.set(board.id, meta);
|
|
|
|
}
|
2021-03-31 19:32:01 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
var rev_old = board.revision;
|
|
|
|
var rev_new = meta.history[0] + 1;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
board.revision = rev_new;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
ok_data = this.setJson('board.' + board.id + '.' + board.revision, board);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
meta.title = board.title || '(Untitled board)';
|
|
|
|
meta.current = board.revision;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
// trim revisions skipped over with undo and cap the revision count
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
var rebuild = [ board.revision ];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
for (var rev of meta.history)
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
if ( (rev_old < rev && rev < rev_new) || (rebuild.length >= this.conf.maxUndo) )
|
2021-03-31 19:32:01 +02:00
|
|
|
{
|
|
|
|
this.delItem('board.' + board.id + '.' + rev);
|
|
|
|
console.log( `Deleted revision ${rev} of ${board.id} (${board.title})` );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rebuild.push(rev);
|
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
meta.history = rebuild;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-02 12:37:26 +02:00
|
|
|
ok_meta = this.setJson('board.' + board.id + '.meta', meta) &&
|
2021-04-05 11:50:02 +02:00
|
|
|
this.setJson('board.' + board.id, meta.current); // for older versions
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
board.history = meta.history; // restore
|
|
|
|
|
|
|
|
console.log( `Saved revision ${board.revision} of ${board.id} (${board.title}), ok = ${ok_data} | ${ok_meta}` );
|
|
|
|
return ok_data && ok_meta;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
loadBoard(board_id, revision)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
var meta = this.boardIndex.get(board_id);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta)
|
|
|
|
throw `Invalid board_id in loadBoard(${board_id}, ${revision})`;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (revision == null)
|
|
|
|
revision = meta.current;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta.history.includes(revision))
|
|
|
|
throw `Invalid revision in loadBoard(${board_id}, ${revision})`;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var board = this.getJson('board.' + board_id + '.' + revision);
|
|
|
|
if (! board)
|
|
|
|
return false;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
if (board.format != NB.blobVersion)
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
|
|
|
console.log('Board ' + board_id + '/' + revision + ' format is unsupported');
|
2021-03-31 19:32:01 +02:00
|
|
|
console.log('Have [' + board.format + '], need [' + NB.blobVersion);
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (board.revision != revision)
|
|
|
|
{
|
|
|
|
console.log('Board ' + board_id + '/' + revision + ' revision is wrong');
|
|
|
|
console.log('Have [' + board.revision + ']');
|
|
|
|
return false;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
board.history = meta.history;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
console.log( `Loaded revision ${board.revision} of ${board.id} (${board.title})` );
|
|
|
|
|
|
|
|
return Object.assign(new Board(), board);
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
nukeBoard(board_id)
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
|
|
|
var meta = this.boardIndex.get(board_id);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta)
|
|
|
|
throw `Invalid board_id in nukeBoard(${board.id})`;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var title = meta.title + '';
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
for (var rev of meta.history)
|
|
|
|
this.delItem('board.' + board_id + '.' + rev);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
this.delItem('board.' + board_id + '.meta');
|
|
|
|
this.boardIndex.delete(board_id);
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
console.log( `Deleted board ${board_id} (${title})` );
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
getBoardHistory(board_id)
|
|
|
|
{
|
|
|
|
var meta = this.boardIndex.get(board_id);
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta)
|
|
|
|
throw `Invalid board_id in getBoardHistory(${board_id})`;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
return meta.history;
|
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setBoardRevision(board_id, revision)
|
|
|
|
{
|
|
|
|
var meta = this.boardIndex.get(board_id);
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta)
|
|
|
|
throw `Invalid board_id in setBoardRevision(${board_id}, ${revision})`;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta.history.includes(revision))
|
|
|
|
throw `Invalid revision in setBoardRevision(${board_id}, ${revision})`;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (meta.current == revision) // wth
|
|
|
|
return true;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
meta.current = revision;
|
|
|
|
|
2021-04-02 12:37:26 +02:00
|
|
|
return this.setJson('board.' + board_id + '.meta', meta) &&
|
|
|
|
this.setJson('board.' + board_id, revision); // for older versions
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
setBoardUiSpot(board_id, ui_spot)
|
|
|
|
{
|
|
|
|
var meta = this.boardIndex.get(board_id);
|
|
|
|
|
|
|
|
if (! meta)
|
|
|
|
throw `Invalid board_id in setBoardRevision(${board_id}, ${revision})`;
|
|
|
|
|
|
|
|
meta.ui_spot = ui_spot;
|
|
|
|
|
|
|
|
return this.setJson('board.' + board_id + '.meta', meta);
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
|
|
|
* private
|
|
|
|
*/
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
getItem(name) { throw 'implement-me'; }
|
|
|
|
setItem(name) { throw 'implement-me'; }
|
|
|
|
delItem(name) { throw 'implement-me'; }
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
openInner() { throw 'implement-me'; }
|
|
|
|
wipeInner() { throw 'implement-me'; }
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
getJson(name)
|
|
|
|
{
|
|
|
|
var foo = this.getItem(name);
|
|
|
|
if (! foo) return false;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
try { foo = JSON.parse(foo); } catch (x) { return false; }
|
|
|
|
return foo;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setJson(name, val)
|
|
|
|
{
|
|
|
|
if (! this.setItem(name, JSON.stringify(val)))
|
|
|
|
{
|
|
|
|
console.log("setJson(" + name + ") failed");
|
|
|
|
return false;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
class Storage_Local extends Storage
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 22:12:53 +02:00
|
|
|
constructor()
|
|
|
|
{
|
|
|
|
super();
|
|
|
|
this.type = 'LocalStorage';
|
|
|
|
}
|
2021-03-31 19:32:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
getItem(name)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
return localStorage.getItem('nullboard.' + name);
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
|
|
|
|
setItem(name, val)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
localStorage.setItem('nullboard.' + name, val);
|
|
|
|
return true;
|
2020-02-08 12:02:45 -05:00
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
|
|
|
|
delItem(name)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
localStorage.removeItem('nullboard.' + name);
|
|
|
|
return true;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
openInner()
|
|
|
|
{
|
|
|
|
var conf = this.getJson('config');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
if (conf && (conf.format != NB.confVersion))
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-03-31 19:32:01 +02:00
|
|
|
if (! confirm('Preferences are stored in an unsupported format. Reset them?'))
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 19:32:01 +02:00
|
|
|
conf = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conf)
|
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
this.conf = conf;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.conf.theme = this.getItem('theme');
|
|
|
|
this.conf.board = this.getItem('last_board');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-06 15:29:12 +02:00
|
|
|
if (this.getItem('fsize') == 'z1')
|
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
this.conf.fontSize = 13;
|
|
|
|
this.conf.lineHeight = 17;
|
2021-04-06 15:29:12 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! this.setJson('config', this.conf))
|
|
|
|
{
|
|
|
|
this.conf = null;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2019-06-10 22:57:14 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.boardIndex = new Map();
|
2019-06-10 22:57:14 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
// new format
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
for (var i=0; i<localStorage.length; i++)
|
|
|
|
{
|
|
|
|
var k = localStorage.key(i);
|
|
|
|
var m = k.match(/^nullboard\.board\.(\d+).meta$/);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
if (! m)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var board_id = parseInt(m[1]);
|
|
|
|
var meta = this.getJson('board.' + board_id + '.meta');
|
|
|
|
|
|
|
|
if (! meta.hasOwnProperty('history'))
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-05 11:50:02 +02:00
|
|
|
console.log( `Invalid meta for board ${board_id}` );
|
|
|
|
continue;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
for (var rev of meta.history)
|
|
|
|
if (! this.getJson('board.' + board_id + '.' + rev))
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-05 11:50:02 +02:00
|
|
|
console.log( `Invalid revision ${rev} in history of ${board_id}` );
|
|
|
|
meta = this.rebuildMeta(board_id);
|
|
|
|
break;
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta)
|
|
|
|
continue;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
meta = Object.assign(new BoardMeta(), meta);
|
2021-04-05 11:50:02 +02:00
|
|
|
this.boardIndex.set(board_id, meta);
|
|
|
|
}
|
|
|
|
|
|
|
|
// old format
|
|
|
|
|
|
|
|
for (var i=0; i<localStorage.length; i++)
|
|
|
|
{
|
|
|
|
var k = localStorage.key(i);
|
|
|
|
var m = k.match(/^nullboard\.board\.(\d+)$/);
|
|
|
|
|
|
|
|
if (! m)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var board_id = parseInt(m[1]);
|
|
|
|
if (this.boardIndex.has(board_id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
var meta = this.rebuildMeta(board_id);
|
|
|
|
if (! meta)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
meta = Object.assign(new BoardMeta(), meta);
|
|
|
|
this.boardIndex.set(board_id, meta);
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2019-06-10 22:57:14 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (this.conf.board && ! this.boardIndex.has(this.conf.board))
|
|
|
|
this.conf.board = null;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.type = 'LocalStorage';
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
return true;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
wipeInner()
|
|
|
|
{
|
|
|
|
for (var i=0; i<localStorage.length; )
|
|
|
|
{
|
|
|
|
var k = localStorage.key(i);
|
|
|
|
var m = k.match(/^nullboard\./);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (m) localStorage.removeItem(k);
|
|
|
|
else i++;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.conf = new AppConfig();
|
|
|
|
this.boardIndex = new Map();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
|
|
|
* private
|
|
|
|
*/
|
|
|
|
rebuildMeta(board_id)
|
|
|
|
{
|
|
|
|
var meta = new BoardMeta();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
console.log( `Rebuilding meta for ${board_id} ...` );
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// get current revision
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
meta.current = this.getItem('board.' + board_id); // may be null
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// load history
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var re = new RegExp('^nullboard\.board\.' + board_id + '\.(\\d+)$');
|
|
|
|
var revs = new Array();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
for (var i=0; i<localStorage.length; i++)
|
|
|
|
{
|
|
|
|
var m = localStorage.key(i).match(re);
|
|
|
|
if (m) revs.push( parseInt(m[1]) );
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! revs.length)
|
2021-04-05 11:50:02 +02:00
|
|
|
{
|
|
|
|
console.log('* No revisions found');
|
|
|
|
this.delItem('board.' + board_id);
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
2021-04-05 11:50:02 +02:00
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
revs.sort(function(a,b){ return b-a; });
|
|
|
|
meta.history = revs;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// validate current revision
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! meta.history.includes(meta.current))
|
|
|
|
meta.current = meta.history[meta.history.length-1];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// get board title
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var board = this.getJson('board.' + board_id + '.' + meta.current)
|
|
|
|
meta.title = (board.title || '(untitled board)');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.setJson('board.' + board_id + '.meta', meta);
|
|
|
|
|
|
|
|
return meta;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
</script>
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
<script type="text/javascript">
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function Note(text)
|
|
|
|
{
|
|
|
|
this.text = text;
|
|
|
|
this.raw = false;
|
|
|
|
this.min = false;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function List(title)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
this.title = title;
|
|
|
|
this.notes = [ ];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.addNote = function(text)
|
|
|
|
{
|
|
|
|
var x = new Note(text);
|
|
|
|
this.notes.push(x);
|
|
|
|
return x;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function Board(title)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 19:32:01 +02:00
|
|
|
this.format = NB.blobVersion;
|
2021-03-31 18:27:33 +02:00
|
|
|
this.id = +new Date();
|
|
|
|
this.revision = 0;
|
|
|
|
this.title = title || '';
|
|
|
|
this.lists = [ ];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.addList = function(title)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
var x = new List(title);
|
|
|
|
this.lists.push(x);
|
|
|
|
return x;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
</script>
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
<script type="text/javascript">
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
function Drag2()
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
// config
|
|
|
|
this.listSel = null;
|
|
|
|
this.itemSel = null;
|
2021-04-02 01:59:34 +02:00
|
|
|
this.dragster = null;
|
2021-04-01 19:12:43 +02:00
|
|
|
this.onDragging = function(started) { }
|
|
|
|
this.swapAnimMs = 200;
|
|
|
|
|
|
|
|
// state
|
|
|
|
this.item = null;
|
2021-03-31 18:27:33 +02:00
|
|
|
this.priming = null;
|
2021-04-01 19:12:43 +02:00
|
|
|
this.primeXY = { x: 0, y: 0 };
|
2021-03-31 18:27:33 +02:00
|
|
|
this.$drag = null;
|
2021-04-01 19:12:43 +02:00
|
|
|
this.mouseEv = null;
|
2021-03-31 18:27:33 +02:00
|
|
|
this.delta = { x: 0, y: 0 };
|
2021-04-01 19:12:43 +02:00
|
|
|
this.inSwap = 0;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
// api
|
2021-03-31 18:27:33 +02:00
|
|
|
this.prime = function(item, ev)
|
|
|
|
{
|
|
|
|
var self = this;
|
2021-04-01 19:12:43 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.item = item;
|
|
|
|
this.priming = setTimeout(function(){ self.onPrimed.call(self); }, ev.altKey ? 1 : 500);
|
2021-04-01 19:12:43 +02:00
|
|
|
this.primeXY = { x: ev.clientX, y: ev.clientY };
|
|
|
|
this.mouseEv = ev;
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.cancelPriming = function()
|
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
if (! this.item || ! this.priming)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clearTimeout(this.priming);
|
|
|
|
this.priming = null;
|
|
|
|
this.item = null;
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.end = function()
|
2021-03-30 10:18:01 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
this.cancelPriming();
|
|
|
|
this.stopDragging();
|
2021-03-30 10:18:01 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.isActive = function()
|
|
|
|
{
|
|
|
|
return this.item && (this.priming == null);
|
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.onPrimed = function()
|
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
console.log('onPrimed');
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
clearTimeout(this.priming);
|
|
|
|
this.priming = null;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
removeTextSelection();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
var $item = $(this.item);
|
|
|
|
$item.addClass('dragging');
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
$('body').append('<div class=' + this.dragster + '></div>');
|
|
|
|
var $drag = $('body .' + this.dragster).last();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
$drag.outerWidth ( $item.outerWidth() );
|
|
|
|
$drag.outerHeight( $item.outerHeight() );
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.$drag = $drag;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (this.onDragging)
|
|
|
|
this.onDragging.call(this, true); // started
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $win = $(window);
|
|
|
|
var scroll_x = $win.scrollLeft();
|
|
|
|
var scroll_y = $win.scrollTop();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
var pos = $item.offset();
|
|
|
|
this.delta.x = pos.left - this.mouseEv.clientX - scroll_x;
|
|
|
|
this.delta.y = pos.top - this.mouseEv.clientY - scroll_y;
|
2021-04-02 01:59:34 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.adjustDrag();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$drag.css({ opacity: 1 });
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('body').addClass('dragging');
|
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.adjustDrag = function()
|
2021-03-30 10:18:01 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! this.$drag)
|
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
var drag = this;
|
|
|
|
var $drag = this.$drag;
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $win = $(window);
|
|
|
|
var scroll_x = $win.scrollLeft();
|
|
|
|
var scroll_y = $win.scrollTop();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
var drag_x = drag.mouseEv.clientX + drag.delta.x + scroll_x;
|
|
|
|
var drag_y = drag.mouseEv.clientY + drag.delta.y + scroll_y;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
$drag.offset({ left: drag_x, top: drag_y });
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (drag.inSwap)
|
2021-03-31 18:27:33 +02:00
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
|
|
|
* see if a swap is in order
|
|
|
|
*/
|
2021-04-01 19:12:43 +02:00
|
|
|
var pos = $drag.offset();
|
|
|
|
var x = pos.left + $drag.width()/2 - $win.scrollLeft();
|
|
|
|
var y = pos.top + $drag.height()/2 - $win.scrollTop();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var target = null; // if over some item
|
|
|
|
var before = false; // if should go before that item
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
$(this.listSel).each(function(){
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var list = this;
|
2021-04-01 19:12:43 +02:00
|
|
|
var rcList = list.getBoundingClientRect();
|
|
|
|
var yTop, itemTop = null;
|
|
|
|
var yBottom, itemBottom = null;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (x <= rcList.left || rcList.right <= x)
|
2021-03-31 18:27:33 +02:00
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
$(list).find(drag.itemSel).each(function(){
|
|
|
|
var rcItem = this.getBoundingClientRect();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (! itemTop || rcItem.top < yTop)
|
|
|
|
{
|
|
|
|
itemTop = this;
|
|
|
|
yTop = rcItem.top;
|
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (! itemBottom || yBottom < rcItem.bottom)
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
itemBottom = this;
|
|
|
|
yBottom = rcItem.bottom;
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (y <= rcItem.top || rcItem.bottom <= y)
|
2021-03-31 18:27:33 +02:00
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (this == drag.item)
|
2021-03-31 18:27:33 +02:00
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
target = this;
|
|
|
|
before = (y < (rcItem.top + rcItem.bottom)/2);
|
2021-03-31 18:27:33 +02:00
|
|
|
});
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (y < rcList.top)
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
target = itemTop;
|
|
|
|
before = true;
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2021-04-01 19:12:43 +02:00
|
|
|
else
|
|
|
|
if (y >= rcList.bottom)
|
|
|
|
{
|
|
|
|
target = itemBottom;
|
|
|
|
before = false;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
});
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (! target)
|
2021-03-31 18:27:33 +02:00
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (target == drag.item)
|
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (! before && $(target).next()[0] == drag.item ||
|
|
|
|
before && $(target).prev()[0] == drag.item)
|
|
|
|
return;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
|
|
|
* swap 'em
|
|
|
|
*/
|
2021-04-01 19:12:43 +02:00
|
|
|
var $target = $(target);
|
|
|
|
|
|
|
|
var have = drag.item;
|
|
|
|
var $have = $(have);
|
2021-03-31 18:27:33 +02:00
|
|
|
var $want = $have.clone();
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$want.css({ display: 'none' });
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (before)
|
|
|
|
{
|
|
|
|
$want.insertBefore($target);
|
|
|
|
$want = $target.prev();
|
|
|
|
}
|
|
|
|
else
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
$want.insertAfter($target);
|
|
|
|
$want = $target.next();
|
|
|
|
}
|
|
|
|
|
|
|
|
drag.item = $want[0];
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (! drag.swapAnimMs)
|
|
|
|
{
|
|
|
|
$have.remove();
|
|
|
|
$want.show();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* see if it's a same-list move
|
|
|
|
*/
|
|
|
|
if (target.parentNode == have.parentNode)
|
|
|
|
{
|
|
|
|
var delta = $have.offset().top - $target.offset().top;
|
|
|
|
|
|
|
|
var d_bulk = 0;
|
|
|
|
var d_have = 0;
|
|
|
|
var $bulk = $();
|
|
|
|
|
|
|
|
if (delta < 0) // item is moving down
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
for (var $i = $have.next(); $i.length && $i[0] != $want[0]; $i = $i.next())
|
|
|
|
$bulk = $bulk.add($i);
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
for (var $i = $want.next(); $i.length && $i[0] != $have[0]; $i = $i.next())
|
|
|
|
$bulk = $bulk.add($i);
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
d_bulk = $have.outerHeight(true);
|
|
|
|
d_have = $bulk.last().offset().top + $bulk.last().outerHeight(true) - $bulk.first().offset().top;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (delta < 0) d_bulk = -d_bulk;
|
|
|
|
else d_have = -d_have;
|
2021-03-31 18:27:33 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
$have.parent().css({ position: 'relative' });
|
|
|
|
$have.css({ position: 'relative', 'z-index': 0 });
|
|
|
|
$bulk.css({ position: 'relative', 'z-index': 1 });
|
2021-03-31 18:27:33 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
drag.inSwap = 1 + $bulk.length;
|
2021-03-31 18:27:33 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
$have.animate({ top: d_have }, drag.swapAnimMs, function(){ if (! --drag.inSwap) swapCleanUp(); });
|
|
|
|
$bulk.animate({ top: d_bulk }, drag.swapAnimMs, function(){ if (! --drag.inSwap) swapCleanUp(); });
|
2021-03-31 18:27:33 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
function swapCleanUp()
|
|
|
|
{
|
|
|
|
$have.parent().css({ position: '' });
|
2021-03-31 20:45:26 +02:00
|
|
|
|
|
|
|
$have.remove();
|
2021-04-01 19:12:43 +02:00
|
|
|
$want.show();
|
|
|
|
$bulk.css({ position: '', 'z-index': '', top: '' });
|
|
|
|
|
2021-03-31 20:45:26 +02:00
|
|
|
drag.adjustDrag();
|
|
|
|
}
|
2021-04-01 19:12:43 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drag.inSwap = 1;
|
|
|
|
|
|
|
|
$want.slideDown(drag.swapAnimMs);
|
|
|
|
|
|
|
|
$have.slideUp(drag.swapAnimMs, function() {
|
|
|
|
$have.remove();
|
|
|
|
drag.inSwap = 0;
|
|
|
|
drag.adjustDrag();
|
|
|
|
});
|
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
this.onMouseMove = function(ev)
|
2021-03-30 10:18:01 +02:00
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
this.mouseEv = ev;
|
2021-03-31 18:27:33 +02:00
|
|
|
|
|
|
|
if (! this.item)
|
2021-03-30 10:18:01 +02:00
|
|
|
return;
|
2021-03-31 18:27:33 +02:00
|
|
|
|
|
|
|
if (this.priming)
|
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
var x = ev.clientX - this.primeXY.x;
|
|
|
|
var y = ev.clientY - this.primeXY.y;
|
2021-03-31 18:27:33 +02:00
|
|
|
if (x*x + y*y > 5*5)
|
|
|
|
this.onPrimed();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.adjustDrag();
|
2021-03-30 10:18:01 +02:00
|
|
|
}
|
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
|
|
|
|
this.stopDragging = function()
|
2021-03-30 10:18:01 +02:00
|
|
|
{
|
2021-04-01 19:12:43 +02:00
|
|
|
var $item = $(this.item);
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
$item.removeClass('dragging');
|
2021-03-31 18:27:33 +02:00
|
|
|
$('body').removeClass('dragging');
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (this.$drag)
|
|
|
|
{
|
|
|
|
this.$drag.remove();
|
|
|
|
this.$drag = null;
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
removeTextSelection();
|
2021-03-31 18:27:33 +02:00
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
if (this.onDragging)
|
|
|
|
this.onDragging.call(this, false); // stopped
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this.item = null;
|
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
</script>
|
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
<script type="text/javascript">
|
|
|
|
|
|
|
|
function VarAdjust()
|
|
|
|
{
|
|
|
|
// state
|
|
|
|
this.onChange = null;
|
|
|
|
this.startY = 0;
|
|
|
|
this.used = false;
|
|
|
|
|
|
|
|
// api
|
|
|
|
this.start = function(ev, onChange)
|
|
|
|
{
|
|
|
|
if (! onChange)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.onChange = onChange;
|
|
|
|
this.startY = ev.clientY;
|
|
|
|
this.used = false;
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
setTimeout(function(){
|
2021-04-08 13:24:35 +02:00
|
|
|
if (! self.onChange)
|
|
|
|
return;
|
|
|
|
$('body').addClass('adjusting');
|
|
|
|
self.used = true;
|
|
|
|
}, 250);
|
2021-04-07 18:51:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this.onMouseMove = function(ev)
|
|
|
|
{
|
|
|
|
if (! this.onChange)
|
|
|
|
return;
|
|
|
|
|
|
|
|
$('body').addClass('adjusting');
|
|
|
|
self.used = true;
|
|
|
|
this.onChange(ev.clientY - this.startY);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.end = function()
|
|
|
|
{
|
|
|
|
if (! this.onChange)
|
|
|
|
return;
|
|
|
|
|
|
|
|
$('body').removeClass('adjusting');
|
|
|
|
this.onChange = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
<script type="text/javascript">
|
|
|
|
|
|
|
|
/*
|
|
|
|
* poor man's error handling -- $fixme
|
|
|
|
*/
|
2021-03-31 19:32:01 +02:00
|
|
|
var easyMartina = false;
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
window.onerror = function(message, file, line, col, e){
|
|
|
|
var cb1;
|
2021-03-31 19:32:01 +02:00
|
|
|
if (! easyMartina) alert("Error occurred: " + e.message);
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener("error", function(e) {
|
|
|
|
var cb2;
|
2021-03-31 19:32:01 +02:00
|
|
|
if (! easyMartina) alert("Error occurred: " + e.error.message);
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
2021-03-31 20:35:46 +02:00
|
|
|
* notes / lists / boards
|
2019-05-28 12:09:54 +02:00
|
|
|
*/
|
2021-03-31 18:27:33 +02:00
|
|
|
function addNote($list, $after, $before)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
var $note = $('tt .note').clone();
|
|
|
|
var $notes = $list.find('.notes');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$note.find('.text').html('');
|
|
|
|
$note.addClass('brand-new');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if ($before)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
$before.before($note);
|
|
|
|
$note = $before.prev();
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
else
|
|
|
|
if ($after)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
$after.after($note);
|
|
|
|
$note = $after.next();
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
else
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
$notes.append($note);
|
|
|
|
$note = $notes.find('.note').last();
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$note.find('.text').click();
|
|
|
|
}
|
2021-03-30 10:31:28 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function deleteNote($note)
|
|
|
|
{
|
|
|
|
$note
|
|
|
|
.animate({ opacity: 0 }, 'fast')
|
|
|
|
.slideUp('fast')
|
|
|
|
.queue(function(){
|
|
|
|
$note.remove();
|
|
|
|
saveBoard();
|
|
|
|
});
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
function noteLocation($item)
|
|
|
|
{
|
|
|
|
var loc = 0;
|
|
|
|
for (var $p = $item.closest('.note'); $p.length; $p = $p.prev(), loc += 1);
|
|
|
|
for (var $p = $item.closest('.list'); $p.length; $p = $p.prev(), loc += 10000);
|
|
|
|
return loc;
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
function addList()
|
|
|
|
{
|
|
|
|
var $board = $('.wrap .board');
|
|
|
|
var $lists = $board.find('.lists');
|
|
|
|
var $list = $('tt .list').clone();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$list.find('.text').html('');
|
|
|
|
$list.find('.head').addClass('brand-new');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$lists.append($list);
|
|
|
|
$board.find('.lists .list .head .text').last().click();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var lists = $lists[0];
|
|
|
|
lists.scrollLeft = Math.max(0, lists.scrollWidth - lists.clientWidth);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setupListScrolling();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function deleteList($list)
|
|
|
|
{
|
|
|
|
var empty = true;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$list.find('.note .text').each(function(){
|
|
|
|
empty &= ($(this).html().length == 0);
|
|
|
|
});
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! empty && ! confirm("Delete this list and all its notes?"))
|
|
|
|
return;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$list
|
|
|
|
.animate({ opacity: 0 })
|
|
|
|
.queue(function(){
|
|
|
|
$list.remove();
|
|
|
|
saveBoard();
|
|
|
|
});
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setupListScrolling();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function moveList($list, left)
|
|
|
|
{
|
|
|
|
var $a = $list;
|
|
|
|
var $b = left ? $a.prev() : $a.next();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $menu_a = $a.find('> .head .menu .bulk');
|
|
|
|
var $menu_b = $b.find('> .head .menu .bulk');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var pos_a = $a.offset().left;
|
|
|
|
var pos_b = $b.offset().left;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$a.css({ position: 'relative' });
|
|
|
|
$b.css({ position: 'relative' });
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$menu_a.hide();
|
|
|
|
$menu_b.hide();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$a.animate({ left: (pos_b - pos_a) + 'px' }, 'fast');
|
|
|
|
$b.animate({ left: (pos_a - pos_b) + 'px' }, 'fast', function(){
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (left) $list.prev().before($list);
|
|
|
|
else $list.before($list.next());
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$a.css({ position: '', left: '' });
|
|
|
|
$b.css({ position: '', left: '' });
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$menu_a.css({ display: '' });
|
|
|
|
$menu_b.css({ display: '' });
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
saveBoard();
|
|
|
|
});
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
function openBoard(board_id)
|
|
|
|
{
|
|
|
|
closeBoard(true);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
NB.board = NB.storage.loadBoard(board_id, null);
|
|
|
|
NB.storage.setActiveBoard(board_id);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
showBoard(true);
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function reopenBoard(revision)
|
|
|
|
{
|
|
|
|
var board_id = NB.board.id;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var via_menu = $('.wrap .board > .head .menu .bulk').is(':visible');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
NB.storage.setBoardRevision(board_id, revision);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
openBoard(board_id);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (via_menu)
|
|
|
|
{
|
|
|
|
var $menu = $('.wrap .board > .head .menu');
|
|
|
|
var $teaser = $menu.find('.teaser');
|
|
|
|
var $bulk = $menu.find('.bulk');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$teaser.hide().delay(100).queue(function(){ $(this).css('display', '').dequeue(); });
|
|
|
|
$bulk.show().delay(100).queue(function(){ $(this).css('display', '').dequeue(); });
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function closeBoard(quick)
|
|
|
|
{
|
|
|
|
var $board = $('.wrap .board');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (quick)
|
|
|
|
$board.remove();
|
|
|
|
else
|
|
|
|
$board
|
|
|
|
.animate({ opacity: 0 }, 'fast')
|
|
|
|
.queue(function(){ $board.remove(); });
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
NB.board = null;
|
|
|
|
NB.storage.setActiveBoard(null);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
updateUndoRedo();
|
|
|
|
updateBoardIndex();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
function addBoard()
|
|
|
|
{
|
|
|
|
closeBoard(true);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
NB.board = new Board();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
showBoard(true);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap .board .head').addClass('brand-new');
|
|
|
|
$('.wrap .board .head .text').click();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
function saveBoard()
|
|
|
|
{
|
|
|
|
var $board = $('.wrap .board');
|
|
|
|
var board = Object.assign({}, NB.board); // id, revision & title
|
|
|
|
|
|
|
|
board.lists = [];
|
|
|
|
|
|
|
|
$board.find('.list').each(function(){
|
|
|
|
var $list = $(this);
|
|
|
|
var l = board.addList( getText($list.find('.head .text')) );
|
|
|
|
|
|
|
|
$list.find('.note').each(function(){
|
|
|
|
var $note = $(this)
|
|
|
|
var n = l.addNote( getText($note.find('.text')) );
|
|
|
|
n.raw = $note.hasClass('raw');
|
|
|
|
n.min = $note.hasClass('collapsed');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
NB.storage.saveBoard(board);
|
|
|
|
NB.board = board;
|
|
|
|
|
|
|
|
updateUndoRedo();
|
|
|
|
updateBoardIndex();
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function deleteBoard()
|
|
|
|
{
|
|
|
|
var $list = $('.wrap .board .list');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if ($list.length && ! confirm("PERMANENTLY delete this board, all its lists and their notes?"))
|
|
|
|
return;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
NB.storage.nukeBoard(NB.board.id);
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
closeBoard();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
function undoBoard()
|
|
|
|
{
|
|
|
|
if (! NB.board)
|
|
|
|
return false;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var hist = NB.storage.getBoardHistory(NB.board.id);
|
|
|
|
var have = NB.board.revision;
|
|
|
|
var want = 0;
|
|
|
|
|
|
|
|
for (var i=0; i<hist.length-1 && ! want; i++)
|
|
|
|
if (have == hist[i])
|
|
|
|
want = hist[i+1];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! want)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
console.log('Undo - failed');
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-30 10:31:28 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
console.log('Undo -> ' + want);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
reopenBoard(want);
|
|
|
|
return true;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function redoBoard()
|
|
|
|
{
|
|
|
|
if (! NB.board)
|
|
|
|
return false;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var hist = NB.storage.getBoardHistory(NB.board.id);
|
|
|
|
var have = NB.board.revision;
|
|
|
|
var want = 0;
|
2021-03-30 10:31:28 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
for (var i=1; i<hist.length && ! want; i++)
|
|
|
|
if (have == hist[i])
|
|
|
|
want = hist[i-1];
|
|
|
|
|
|
|
|
if (! want)
|
|
|
|
{
|
|
|
|
console.log('Redo - failed');
|
|
|
|
return false;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
2021-03-31 18:27:33 +02:00
|
|
|
|
|
|
|
console.log('Redo -> ' + want);
|
|
|
|
|
|
|
|
reopenBoard(want);
|
|
|
|
return true;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
function showBoard(quick)
|
|
|
|
{
|
|
|
|
var board = NB.board;
|
2021-03-30 10:37:15 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $wrap = $('.wrap');
|
|
|
|
var $bdiv = $('tt .board');
|
|
|
|
var $ldiv = $('tt .list');
|
|
|
|
var $ndiv = $('tt .note');
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $b = $bdiv.clone();
|
|
|
|
var $b_lists = $b.find('.lists');
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$b[0].board_id = board.id;
|
|
|
|
setText( $b.find('.head .text'), board.title );
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
board.lists.forEach(function(list){
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $l = $ldiv.clone();
|
|
|
|
var $l_notes = $l.find('.notes');
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setText( $l.find('.head .text'), list.title );
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
list.notes.forEach(function(n){
|
|
|
|
var $n = $ndiv.clone();
|
|
|
|
setText( $n.find('.text'), n.text );
|
|
|
|
if (n.raw) $n.addClass('raw');
|
|
|
|
if (n.min) $n.addClass('collapsed');
|
|
|
|
$l_notes.append($n);
|
|
|
|
});
|
|
|
|
|
|
|
|
$b_lists.append($l);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (quick)
|
|
|
|
$wrap.html('').append($b);
|
2020-02-08 12:02:45 -05:00
|
|
|
else
|
2021-03-31 18:27:33 +02:00
|
|
|
$wrap.html('')
|
|
|
|
.css({ opacity: 0 })
|
|
|
|
.append($b)
|
|
|
|
.animate({ opacity: 1 });
|
|
|
|
|
|
|
|
updatePageTitle();
|
|
|
|
updateUndoRedo();
|
|
|
|
updateBoardIndex();
|
|
|
|
setupListScrolling();
|
|
|
|
}
|
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
/*
|
|
|
|
* demo board
|
|
|
|
*/
|
|
|
|
function createDemoBoard()
|
|
|
|
{
|
|
|
|
var blob =
|
|
|
|
'{"format":20190412,"id":1555071015420,"revision":581,"title":"Welcome to Nullboard","lists":[{"title":"The Use' +
|
|
|
|
'r Manual","notes":[{"text":"This is a note.\\nA column of notes is a list.\\nA set of lists is a board.","raw"' +
|
|
|
|
':false,"min":false},{"text":"All data is saved locally.\\nThe whole thing works completely offline.","raw":fal' +
|
|
|
|
'se,"min":false},{"text":"Last 50 board revisions are retained.","raw":false,"min":false},{"text":"Ctrl-Z is Un' +
|
|
|
|
'do - goes one revision back.\\nCtrl-Y is Redo - goes one revision forward.","raw":false,"min":false},{"tex' +
|
|
|
|
't":"Caveats","raw":true,"min":false},{"text":"Desktop-oriented.\\nMobile support is basically untested.","raw"' +
|
|
|
|
':false,"min":false},{"text":"Works in Firefox, Chrome is supported.\\nShould work in Safari, may work in Edge.' +
|
|
|
|
'","raw":false,"min":false},{"text":"Still very much in beta. Caveat emptor.","raw":false,"min":false},{"text":' +
|
|
|
|
'"Issues and suggestions","raw":true,"min":false},{"text":"Post them on Github.\\nSee \\"Nullboard\\" at the to' +
|
|
|
|
'p left for the link.","raw":false,"min":false}]},{"title":"Things to try","notes":[{"text":"\u2022 Click on ' +
|
|
|
|
'a note to edit.","raw":false,"min":false},{"text":"\u2022 Click outside of it when done editing.\\n\u2022 ' +
|
|
|
|
'Alternatively, use Shift-Enter.","raw":false,"min":false},{"text":"\u2022 To discard changes press Escape.",' +
|
|
|
|
'"raw":false,"min":false},{"text":"\u2022 Try Ctrl-Enter, see what it does.\\n\u2022 Try Ctrl-Shift-Enter t' +
|
|
|
|
'oo.","raw":false,"min":false},{"text":"\u2022 Hover over a note to show its \u2261 menu.\\n\u2022 Hover ' +
|
|
|
|
'over \u2261 to reveal the options.","raw":false,"min":false},{"text":"\u2022 X deletes the note.\\n\u2022' +
|
|
|
|
' R changes how a note looks.\\n\u2022 _ collapses the note.","raw":false,"min":false},{"text":"This is a ' +
|
|
|
|
'raw note.","raw":true,"min":false},{"text":"This is a collapsed note. Only its first line is visible. Useful f' +
|
|
|
|
'or keeping lists compact.","raw":false,"min":true}, {"text":"Links","raw":true,"min":false}, {"text":"Links pu' +
|
|
|
|
'lse on hover and can be opened via the right-click menu - https://nullboard.io","raw":false,"min":false}, {"tex' +
|
|
|
|
't":"Pressing CapsLock highlights all links and makes them left-clickable.","raw":false,"min":false}]},{"title"' +
|
|
|
|
':"More things to try","notes":[{"text":"\u2022 Drag notes around to rearrange.\\n\u2022 Works between the ' +
|
|
|
|
'lists too.","raw":false,"min":false},{"text":"\u2022 Click on a list name to edit.\\n\u2022 Enter to save,' +
|
|
|
|
' Esc to cancel.","raw":false,"min":false},{"text":"\u2022 Try adding a new list.\\n\u2022 Try deleting one' +
|
|
|
|
'. This _can_ be undone.","raw":false,"min":false},{"text":"\u2022 Same for the board name.","raw":false,"m' +
|
|
|
|
'in":false},{"text":"Boards","raw":true,"min":false},{"text":"\u2022 Check out \u2261 at the top right.",' +
|
|
|
|
'"raw":false,"min":false},{"text":"\u2022 Try adding a new board.\\n\u2022 Try switching between the boards' +
|
|
|
|
'.","raw":false,"min":false},{"text":"\u2022 Try deleting a board. Unlike deleting a\\n list this _canno' +
|
|
|
|
't_ be undone.","raw":false,"min":false},{"text":"\u2022 Export the board (save to a file, as json)\\n' +
|
|
|
|
'\u2022 Import the board (load from a save)","raw":false,"min":false}]}]}';
|
|
|
|
|
|
|
|
var demo = JSON.parse(blob);
|
|
|
|
|
|
|
|
if (! demo)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
demo.id = +new Date();
|
|
|
|
demo.revision = 0;
|
|
|
|
|
|
|
|
NB.storage.saveBoard(demo);
|
|
|
|
NB.storage.setActiveBoard(demo.id);
|
|
|
|
|
|
|
|
return Object.assign(new Board(), demo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* board export / import
|
|
|
|
*/
|
|
|
|
function exportBoard()
|
|
|
|
{
|
|
|
|
var blob, file;
|
|
|
|
|
|
|
|
if (! NB.board)
|
|
|
|
{
|
|
|
|
var index = NB.storage.getBoardIndex();
|
|
|
|
var all = [];
|
|
|
|
|
|
|
|
boards.forEach(function(meta, board_id){
|
|
|
|
all.push( NB.storage.loadBoard(board_id, null) );
|
|
|
|
})
|
|
|
|
|
|
|
|
blob = JSON.stringify(all);
|
|
|
|
file = `Nullboard.nbx`;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var board = NB.board;
|
|
|
|
blob = JSON.stringify(board);
|
|
|
|
file = `Nullboard-${board.id}-${board.title}.nbx`;
|
|
|
|
}
|
|
|
|
|
|
|
|
blob = encodeURIComponent(blob);
|
|
|
|
blob = "data:application/octet-stream," + blob;
|
|
|
|
|
|
|
|
return { blob: blob, file: file };
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkImport(foo)
|
|
|
|
{
|
|
|
|
var props = [ 'format', 'id', 'revision', 'title', 'lists' ];
|
|
|
|
|
|
|
|
for (var i=0; i<props.length; i++)
|
|
|
|
if (! foo.hasOwnProperty(props[i]))
|
|
|
|
return "Required board properties are missing.";
|
|
|
|
|
|
|
|
if (! foo.id || ! foo.revision || ! Array.isArray(foo.lists))
|
|
|
|
return "Required board properties are empty.";
|
|
|
|
|
|
|
|
if (foo.format != NB.blobVersion)
|
|
|
|
return `Unsupported blob format "${board.format}", expecting "${NB.blobVersion}".`;
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function importBoard(blob)
|
|
|
|
{
|
|
|
|
var data;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
data = JSON.parse(blob);
|
|
|
|
}
|
|
|
|
catch (x)
|
|
|
|
{
|
|
|
|
alert('File is not in a valid JSON format.');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! Array.isArray(data))
|
|
|
|
data = [ data ];
|
|
|
|
|
|
|
|
var index = NB.storage.getBoardIndex();
|
|
|
|
var msg, one, all = '';
|
|
|
|
|
|
|
|
for (var i=0; i<data.length; i++)
|
|
|
|
{
|
|
|
|
var board = data[i];
|
|
|
|
|
|
|
|
var whoops = checkImport(board);
|
|
|
|
if (whoops)
|
|
|
|
{
|
|
|
|
alert(whoops);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var title = board.title || '(untitled board)';
|
|
|
|
one = `"${title}", ID ${board.id}, revision ${board.revision}`;
|
|
|
|
all += ` ID ${board.id}, revision ${board.revision} - "${title}" \n`;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data.length == 1) msg = `Import a board called ${one} ?`;
|
|
|
|
else msg = `About to import the following boards:\n\n${all}\nProceed?`;
|
|
|
|
|
|
|
|
if (! confirm(msg))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (var i=0; i<data.length; i++)
|
|
|
|
{
|
|
|
|
var board = data[i];
|
|
|
|
|
|
|
|
if (index.has(board.id))
|
|
|
|
{
|
|
|
|
console.log(`Import: board ${board.id} (${board.title}) will be assigned new ID`);
|
|
|
|
board.id = +new Date();
|
|
|
|
}
|
|
|
|
|
|
|
|
board.revision--; // save will ++ it back
|
|
|
|
|
|
|
|
if (! NB.storage.saveBoard(board)) // this updates 'index'
|
|
|
|
{
|
|
|
|
alert(`Failed to save board ${board.id}. Import failed.`);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
openBoard(data[0].id);
|
|
|
|
}
|
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
function saveBoardOrder()
|
|
|
|
{
|
|
|
|
var $index = $('.config .load-board');
|
|
|
|
var spot = 1;
|
|
|
|
|
|
|
|
$index.each(function(){
|
|
|
|
var id = parseInt( $(this).attr('board_id') );
|
|
|
|
NB.storage.setBoardUiSpot(id, spot++);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
function updatePageTitle()
|
|
|
|
{
|
|
|
|
var title = 'Nullboard';
|
|
|
|
|
|
|
|
if (NB.board)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
title = NB.board.title;
|
2021-03-31 19:32:01 +02:00
|
|
|
title = 'NB - ' + (title || '(untitled board)');
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
document.title = title;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function updateUndoRedo()
|
|
|
|
{
|
|
|
|
var $undo = $('.board .menu .undo-board');
|
|
|
|
var $redo = $('.board .menu .redo-board');
|
|
|
|
|
|
|
|
var undo = false;
|
|
|
|
var redo = false;
|
|
|
|
|
|
|
|
if (NB.board && NB.board.revision)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
var history = NB.storage.getBoardHistory(NB.board.id);
|
|
|
|
var rev = NB.board.revision;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
undo = (rev != history[history.length-1]);
|
|
|
|
redo = (rev != history[0]);
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (undo) $undo.show(); else $undo.hide();
|
|
|
|
if (redo) $redo.show(); else $redo.hide();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function updateBoardIndex()
|
|
|
|
{
|
|
|
|
var $index = $('.config .boards');
|
|
|
|
var $export = $('.config .exp-board');
|
|
|
|
var $entry = $('tt .load-board');
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $board = $('.wrap .board');
|
|
|
|
var id_now = NB.board && NB.board.id;
|
|
|
|
var empty = true;
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$index.html('');
|
|
|
|
$index.hide();
|
2020-02-20 01:13:00 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var boards = NB.storage.getBoardIndex();
|
2021-04-02 01:59:34 +02:00
|
|
|
var index = [];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
boards.forEach(function(meta, id){ index.push({ id: id, meta: meta }); });
|
|
|
|
|
|
|
|
index.sort(function(a, b){ return b.meta.ui_spot && a.meta.ui_spot > b.meta.ui_spot; });
|
|
|
|
|
|
|
|
index.forEach(function(entry){
|
2021-03-26 10:40:42 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $e = $entry.clone();
|
2021-04-02 01:59:34 +02:00
|
|
|
$e.attr('board_id', entry.id);
|
|
|
|
$e.html(entry.meta.title);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
if (entry.id == id_now)
|
2021-03-31 18:27:33 +02:00
|
|
|
$e.addClass('active');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$index.append($e);
|
|
|
|
empty = false;
|
|
|
|
});
|
2021-03-26 10:40:42 +01:00
|
|
|
|
2021-03-31 20:20:49 +02:00
|
|
|
if (! empty)
|
|
|
|
{
|
|
|
|
if (id_now) $export.html('Export this board...').show();
|
|
|
|
else $export.html('Export all boards...').show();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$export.hide();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! empty) $index.show();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
2021-03-31 20:35:46 +02:00
|
|
|
* generic utils
|
|
|
|
*/
|
|
|
|
function htmlEncode(raw)
|
|
|
|
{
|
|
|
|
return $('tt .encoder').text(raw).html();
|
|
|
|
}
|
|
|
|
|
|
|
|
function setText($note, text)
|
|
|
|
{
|
|
|
|
$note.attr('_text', text);
|
|
|
|
|
|
|
|
text = htmlEncode(text);
|
2021-04-05 11:50:02 +02:00
|
|
|
var hmmm = /\b(https?:\/\/[^\s]+)/mg;
|
2021-03-31 20:35:46 +02:00
|
|
|
|
|
|
|
text = text.replace(hmmm, function(url){
|
|
|
|
return '<a href="' + url + '" target=_blank>' + url + '</a>';
|
|
|
|
});
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
$note.html(text); // ? text : ' ');
|
2021-03-31 20:35:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function getText($note)
|
|
|
|
{
|
|
|
|
return $note.attr('_text');
|
|
|
|
}
|
|
|
|
|
2021-04-01 19:12:43 +02:00
|
|
|
function removeTextSelection()
|
|
|
|
{
|
|
|
|
if (window.getSelection) { window.getSelection().removeAllRanges(); }
|
|
|
|
else if (document.selection) { document.selection.empty(); }
|
|
|
|
}
|
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
/*
|
|
|
|
* inline editing
|
2021-03-31 18:27:33 +02:00
|
|
|
*/
|
|
|
|
function startEditing($text, ev)
|
|
|
|
{
|
|
|
|
var $note = $text.parent();
|
|
|
|
var $edit = $note.find('.edit');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$note[0]._collapsed = $note.hasClass('collapsed');
|
|
|
|
$note.removeClass('collapsed');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$edit.val( getText($text) );
|
|
|
|
$edit.width( $text.width() );
|
2021-04-05 11:50:02 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$edit.height( $text.height() );
|
|
|
|
$note.addClass('editing');
|
2021-03-26 10:29:33 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$edit.focus();
|
|
|
|
}
|
2021-03-26 10:29:33 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function stopEditing($edit, via_escape, via_xclick)
|
|
|
|
{
|
|
|
|
var $item = $edit.parent();
|
|
|
|
if (! $item.hasClass('editing'))
|
|
|
|
return;
|
2021-03-26 10:29:33 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$item.removeClass('editing');
|
|
|
|
if ($item[0]._collapsed)
|
|
|
|
$item.addClass('collapsed')
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
var $text = $item.find('.text');
|
|
|
|
var text_now = $edit.val().trimRight();
|
|
|
|
var text_was = getText( $text );
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
var brand_new = $item.hasClass('brand-new');
|
|
|
|
$item.removeClass('brand-new');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
if (via_escape)
|
2020-02-08 12:02:45 -05:00
|
|
|
{
|
2021-04-05 11:50:02 +02:00
|
|
|
if (brand_new)
|
|
|
|
$item.closest('.note, .list, .board').remove();
|
2021-03-31 18:27:33 +02:00
|
|
|
return;
|
2019-05-28 12:09:54 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (via_xclick && brand_new && !text_now.length)
|
|
|
|
{
|
|
|
|
$item.closest('.note, .list, .board').remove();
|
|
|
|
return;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (text_now != text_was || brand_new)
|
|
|
|
{
|
|
|
|
setText( $text, text_now );
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if ($item.parent().hasClass('board'))
|
|
|
|
NB.board.title = text_now;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
updatePageTitle();
|
|
|
|
saveBoard();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
if (brand_new && $item.hasClass('list'))
|
|
|
|
addNote($item);
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
function handleTab(ev)
|
|
|
|
{
|
|
|
|
var $this = $(this);
|
|
|
|
var $note = $this.closest('.note');
|
|
|
|
var $sibl = ev.shiftKey ? $note.prev() : $note.next();
|
|
|
|
|
|
|
|
if ($sibl.length)
|
|
|
|
{
|
|
|
|
stopEditing($this, false, false);
|
|
|
|
$sibl.find('.text').click();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
function setRevealState(ev)
|
|
|
|
{
|
|
|
|
var raw = ev.originalEvent;
|
|
|
|
var caps = raw.getModifierState && raw.getModifierState( 'CapsLock' );
|
|
|
|
|
|
|
|
if (caps) $('body').addClass('reveal');
|
|
|
|
else $('body').removeClass('reveal');
|
|
|
|
}
|
|
|
|
|
2019-05-28 12:09:54 +02:00
|
|
|
//
|
2021-03-31 18:27:33 +02:00
|
|
|
function showDing()
|
|
|
|
{
|
|
|
|
$('body')
|
|
|
|
.addClass('ding')
|
|
|
|
.delay(250)
|
|
|
|
.queue(function(){ $(this).removeClass('ding').dequeue(); });
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
/*
|
|
|
|
* overlay
|
|
|
|
*/
|
2021-03-31 18:27:33 +02:00
|
|
|
function showOverlay($div)
|
|
|
|
{
|
|
|
|
$('.overlay')
|
|
|
|
.html('')
|
|
|
|
.append($div)
|
|
|
|
.css({ opacity: 0, display: 'block' })
|
|
|
|
.animate({ opacity: 1 });
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function hideOverlay()
|
|
|
|
{
|
|
|
|
$('.overlay').animate({ opacity: 0 }, function(){
|
|
|
|
$(this).hide();
|
|
|
|
});
|
|
|
|
}
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function haveOverlay()
|
|
|
|
{
|
|
|
|
return $('.overlay').css('display') != 'none';
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
/*
|
|
|
|
* license popup
|
|
|
|
*/
|
2021-03-31 18:27:33 +02:00
|
|
|
function formatLicense()
|
|
|
|
{
|
|
|
|
var text = document.head.childNodes[1].nodeValue;
|
|
|
|
var pos = text.search('LICENSE');
|
|
|
|
var qos = text.search('Software:');
|
|
|
|
var bulk;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
bulk = text.substr(pos, qos-pos);
|
|
|
|
bulk = bulk.replace(/([^\n])\n\t/g, '$1 ');
|
|
|
|
bulk = bulk.replace(/\n\n\t/g, '\n\n');
|
|
|
|
bulk = bulk.replace(/([A-Z ]{7,})/g, '<u>$1</u>');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
var c1 = [];
|
|
|
|
var c2 = [];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
text.substr(qos).trim().split('\n').forEach(function(line){
|
|
|
|
line = line.split(':');
|
|
|
|
c1.push( line[0].trim() + ':' );
|
|
|
|
c2.push( line[1].trim() );
|
|
|
|
});
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
bulk += '<span>' + c1.join('<br>') + '</span>';
|
|
|
|
bulk += '<span>' + c2.join('<br>') + '</span>';
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
var links =
|
|
|
|
[
|
|
|
|
{ text: '2-clause BSD license', href: 'https://opensource.org/licenses/BSD-2-Clause/' },
|
|
|
|
{ text: 'Commons Clause', href: 'https://commonsclause.com/' }
|
|
|
|
];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
links.forEach(function(l){
|
|
|
|
bulk = bulk.replace(l.text, '<a href="' + l.href + '" target=_blank>' + l.text + '</a>');
|
|
|
|
});
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
return bulk.trim();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
/*
|
|
|
|
* adjust this and that
|
|
|
|
*/
|
2021-03-31 18:27:33 +02:00
|
|
|
function adjustLayout()
|
|
|
|
{
|
|
|
|
var $body = $('body');
|
|
|
|
var $board = $('.board');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! $board.length)
|
|
|
|
return;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-06 19:54:47 +02:00
|
|
|
var list_w = getListWidth();
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var lists = $board.find('.list').length;
|
2021-04-06 19:54:47 +02:00
|
|
|
var lists_w = (lists < 2) ? list_w : (list_w + 10) * lists - 10;
|
2021-03-31 18:27:33 +02:00
|
|
|
var body_w = $body.width();
|
|
|
|
|
|
|
|
if (lists_w + 190 <= body_w)
|
|
|
|
{
|
|
|
|
$board.css('max-width', '');
|
|
|
|
$body.removeClass('crowded');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-06 19:54:47 +02:00
|
|
|
var max = Math.floor( (body_w - 40) / (list_w + 10) );
|
|
|
|
max = (max < 2) ? list_w : (list_w + 10) * max - 10;
|
2021-03-31 18:27:33 +02:00
|
|
|
$board.css('max-width', max + 'px');
|
|
|
|
$body.addClass('crowded');
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
|
|
|
//
|
2021-03-31 18:27:33 +02:00
|
|
|
function adjustListScroller()
|
|
|
|
{
|
|
|
|
var $board = $('.board');
|
|
|
|
if (! $board.length)
|
|
|
|
return;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $lists = $('.board .lists');
|
|
|
|
var $scroller = $('.board .lists-scroller');
|
|
|
|
var $inner = $scroller.find('div');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var max = $board.width();
|
|
|
|
var want = $lists[0].scrollWidth;
|
2021-04-07 18:51:52 +02:00
|
|
|
var have = $inner.outerWidth();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-08 13:24:35 +02:00
|
|
|
if (want <= max+5)
|
2021-03-31 18:27:33 +02:00
|
|
|
{
|
|
|
|
$scroller.hide();
|
|
|
|
return;
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$scroller.show();
|
|
|
|
if (want == have)
|
|
|
|
return;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$inner.width(want);
|
|
|
|
cloneScrollPos($lists, $scroller);
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function cloneScrollPos($src, $dst)
|
|
|
|
{
|
|
|
|
var src = $src[0];
|
|
|
|
var dst = $dst[0];
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (src._busyScrolling)
|
|
|
|
{
|
|
|
|
src._busyScrolling--;
|
|
|
|
return;
|
|
|
|
}
|
2020-02-19 03:50:03 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
dst._busyScrolling++;
|
|
|
|
dst.scrollLeft = src.scrollLeft;
|
|
|
|
}
|
2020-02-19 14:25:11 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
function setupListScrolling()
|
|
|
|
{
|
|
|
|
var $lists = $('.board .lists');
|
|
|
|
var $scroller = $('.board .lists-scroller');
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
adjustListScroller();
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$lists[0]._busyScrolling = 0;
|
|
|
|
$scroller[0]._busyScrolling = 0;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$scroller.on('scroll', function(){ cloneScrollPos($scroller, $lists); });
|
|
|
|
$lists .on('scroll', function(){ cloneScrollPos($lists, $scroller); });
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
adjustLayout();
|
|
|
|
}
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
/*
|
2021-04-06 13:21:48 +02:00
|
|
|
* dragsters
|
2021-04-05 11:50:02 +02:00
|
|
|
*/
|
2021-04-06 13:21:48 +02:00
|
|
|
function initDragAndDrop()
|
|
|
|
{
|
|
|
|
NB.noteDrag = new Drag2();
|
|
|
|
NB.noteDrag.listSel = '.board .list';
|
|
|
|
NB.noteDrag.itemSel = '.note';
|
|
|
|
NB.noteDrag.dragster = 'note-dragster';
|
|
|
|
NB.noteDrag.onDragging = function(started)
|
|
|
|
{
|
|
|
|
var drag = this;
|
|
|
|
var $note = $(drag.item);
|
|
|
|
|
|
|
|
if (started)
|
|
|
|
{
|
|
|
|
var $drag = drag.$drag;
|
|
|
|
|
|
|
|
if ($note.hasClass('collapsed'))
|
|
|
|
$drag.addClass('collapsed');
|
|
|
|
|
|
|
|
$drag.html('<div class=text></div>');
|
|
|
|
$drag.find('.text').html( $note.find('.text').html() );
|
|
|
|
|
|
|
|
drag.org_loc = noteLocation($note);
|
|
|
|
if ($note.hasClass('collapsed'))
|
|
|
|
drag.$drag.addClass('collapsed');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (drag.org_log != noteLocation($note))
|
|
|
|
saveBoard();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NB.loadDrag = new Drag2();
|
|
|
|
NB.loadDrag.listSel = '.config .boards';
|
|
|
|
NB.loadDrag.itemSel = 'a.load-board';
|
|
|
|
NB.loadDrag.dragster = 'load-dragster';
|
|
|
|
NB.loadDrag.onDragging = function(started)
|
|
|
|
{
|
|
|
|
var drag = this;
|
|
|
|
|
|
|
|
if (started)
|
|
|
|
{
|
|
|
|
var $drag = drag.$drag;
|
|
|
|
|
|
|
|
$('.config .teaser').css({ display: 'none' });
|
|
|
|
$('.config .bulk').css({ display: 'block', opacity: 1 });
|
|
|
|
$drag.html( $(this.item).html() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$('.config .teaser').css({ display: '' });
|
|
|
|
$('.config .bulk')
|
|
|
|
.show()
|
|
|
|
.delay(250)
|
|
|
|
.queue(function(){ $(this).css({ display: '', opacity: '' }).dequeue(); });
|
|
|
|
saveBoardOrder();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fonts
|
|
|
|
*/
|
|
|
|
function initFonts()
|
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
var toGo = 0;
|
|
|
|
var loaded = [];
|
|
|
|
var failed = [];
|
2021-04-06 13:21:48 +02:00
|
|
|
|
|
|
|
NB.font = null; // current font
|
|
|
|
|
|
|
|
//
|
2021-04-06 19:09:14 +02:00
|
|
|
function isUsable(f)
|
|
|
|
{
|
|
|
|
return ! failed.includes(f) && loaded.includes(f);
|
|
|
|
}
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
function onFontsLoaded()
|
|
|
|
{
|
|
|
|
var conf = NB.storage.getConfig();
|
|
|
|
|
2021-04-06 19:09:14 +02:00
|
|
|
$('.config .switch-font').each(function(){
|
|
|
|
if (! isUsable($(this).attr('font')))
|
|
|
|
$(this).remove();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (conf.fontName && ! isUsable(conf.fontName))
|
2021-04-06 13:21:48 +02:00
|
|
|
{
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setFontName(null);
|
2021-04-06 13:21:48 +02:00
|
|
|
selectFont(null);
|
|
|
|
}
|
|
|
|
|
2021-04-06 19:09:14 +02:00
|
|
|
selectFont(conf.fontName || 'barlow');
|
2021-04-06 13:21:48 +02:00
|
|
|
|
2021-04-06 19:09:14 +02:00
|
|
|
if (conf.fontSize)
|
|
|
|
setFontSize(conf.fontSize);
|
2021-04-06 15:29:12 +02:00
|
|
|
|
2021-04-06 19:09:14 +02:00
|
|
|
if (conf.lineHeight)
|
|
|
|
setLineHeight(conf.lineHeight);
|
2021-04-06 15:29:12 +02:00
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
updateVarsAndLayout();
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function onFontLoaded(f, ok)
|
|
|
|
{
|
|
|
|
var f_name = f.family.substr(3,f.family.length-4);
|
|
|
|
|
|
|
|
if (! ok)
|
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
console.log( `! Failed to load ${f.family} ${f.weight}` );
|
|
|
|
failed.push(f_name);
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-04-06 19:09:14 +02:00
|
|
|
loaded.push(f_name);
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:09:14 +02:00
|
|
|
if (! --toGo)
|
2021-04-06 13:21:48 +02:00
|
|
|
onFontsLoaded();
|
|
|
|
}
|
|
|
|
|
|
|
|
document.fonts.forEach(function(f){
|
2021-04-06 19:09:14 +02:00
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
if (f.status == 'loaded')
|
|
|
|
return;
|
|
|
|
|
|
|
|
console.log( `Loading ${f.family} ${f.weight} ...` );
|
2021-04-06 19:09:14 +02:00
|
|
|
toGo++;
|
|
|
|
f.load()
|
|
|
|
.then(function(){ onFontLoaded(f, true); })
|
|
|
|
.catch(function(){ onFontLoaded(f, false); });
|
2021-04-06 13:21:48 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function selectFont(font)
|
2021-04-05 11:50:02 +02:00
|
|
|
{
|
2021-04-06 18:37:26 +02:00
|
|
|
var $html = $('html');
|
|
|
|
$html.removeClass('f-' + NB.font).addClass('f-' + font);
|
2021-04-06 13:21:48 +02:00
|
|
|
NB.font = font;
|
2021-04-05 11:50:02 +02:00
|
|
|
|
|
|
|
var $list = $('.config .switch-font');
|
|
|
|
$list.removeClass('active');
|
|
|
|
$list.filter('[font="' + font + '"]').addClass('active');
|
2021-04-06 13:21:48 +02:00
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
updateVarsAndLayout();
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2021-04-07 13:56:10 +02:00
|
|
|
function getVar(name)
|
|
|
|
{
|
|
|
|
var v = $('html').css(name);
|
|
|
|
var m = v.match(/^\s*calc\((.*)\)$/);
|
|
|
|
if (m) v = eval(m[1]);
|
|
|
|
return parseFloat( v );
|
|
|
|
}
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
function getFontSize()
|
|
|
|
{
|
2021-04-07 13:56:10 +02:00
|
|
|
return getVar('--fs');
|
2021-04-05 11:50:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
function getLineHeight()
|
|
|
|
{
|
2021-04-07 13:56:10 +02:00
|
|
|
return getVar('--lh');;
|
2021-04-05 11:50:02 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:32:46 +02:00
|
|
|
function getListWidth()
|
|
|
|
{
|
2021-04-07 13:56:10 +02:00
|
|
|
return parseInt( getVar('--lw') );
|
2021-04-06 19:32:46 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
//
|
|
|
|
function updateFontSize()
|
|
|
|
{
|
|
|
|
var val = getFontSize();
|
2021-04-06 18:37:26 +02:00
|
|
|
$('.config .f-prefs .ui-fs .val').html( val.toFixed(1) );
|
2021-04-06 15:29:12 +02:00
|
|
|
return val;
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
2021-04-01 19:12:43 +02:00
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
function updateLineHeight()
|
2021-04-01 19:12:43 +02:00
|
|
|
{
|
2021-04-06 13:21:48 +02:00
|
|
|
var val = getLineHeight();
|
2021-04-06 18:37:26 +02:00
|
|
|
$('.config .f-prefs .ui-lh .val').html( val.toFixed(1) );
|
2021-04-06 15:29:12 +02:00
|
|
|
return val;
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
2021-04-01 19:12:43 +02:00
|
|
|
|
2021-04-06 19:32:46 +02:00
|
|
|
function updateListWidth()
|
|
|
|
{
|
|
|
|
var val = getListWidth();
|
|
|
|
$('.config .f-prefs .ui-lw .val').html( val.toFixed(0) );
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
function updateVarsAndLayout()
|
2021-04-07 13:56:10 +02:00
|
|
|
{
|
|
|
|
updateFontSize();
|
|
|
|
updateLineHeight();
|
|
|
|
updateListWidth();
|
2021-04-07 18:51:52 +02:00
|
|
|
adjustLayout();
|
2021-04-07 13:56:10 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
//
|
|
|
|
function setFontSize(fs)
|
|
|
|
{
|
2021-04-07 18:51:52 +02:00
|
|
|
fs = fs.clamp(9, 24);
|
|
|
|
|
|
|
|
$('html').css('--fs', fs + '').addClass('fs-set');
|
|
|
|
updateVarsAndLayout();
|
|
|
|
|
|
|
|
if (getLineHeight() < fs)
|
|
|
|
setLineHeight(fs);
|
2021-04-06 13:21:48 +02:00
|
|
|
|
2021-04-06 15:29:12 +02:00
|
|
|
return getFontSize();
|
2021-04-01 19:12:43 +02:00
|
|
|
}
|
2020-02-19 03:50:03 +01:00
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
function setLineHeight(lh)
|
2021-04-02 01:59:34 +02:00
|
|
|
{
|
2021-04-07 18:51:52 +02:00
|
|
|
var fs = getFontSize();
|
|
|
|
|
2021-04-07 13:56:10 +02:00
|
|
|
lh = parseInt(10*lh) / 10.; // trim to a single decimal digit
|
2021-04-07 18:51:52 +02:00
|
|
|
lh = lh.clamp(fs, 3*fs);
|
|
|
|
|
|
|
|
$('html').css('--lh', lh + '').addClass('lh-set');
|
|
|
|
updateVarsAndLayout();
|
2021-04-07 13:56:10 +02:00
|
|
|
|
2021-04-06 15:29:12 +02:00
|
|
|
return getLineHeight();
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:32:46 +02:00
|
|
|
function setListWidth(lw)
|
|
|
|
{
|
2021-04-07 18:51:52 +02:00
|
|
|
lw = lw.clamp(200, 400);
|
|
|
|
|
|
|
|
$('html').css('--lw', lw + '').addClass('lw-set');
|
|
|
|
updateVarsAndLayout();
|
2021-04-06 19:32:46 +02:00
|
|
|
return getListWidth();
|
|
|
|
}
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
//
|
|
|
|
function resetFontSize()
|
|
|
|
{
|
2021-04-06 18:37:26 +02:00
|
|
|
$('html').css('--fs', '').removeClass('fs-set');
|
2021-04-07 18:51:52 +02:00
|
|
|
updateVarsAndLayout();
|
2021-04-06 15:29:12 +02:00
|
|
|
return updateFontSize();
|
2021-04-06 13:21:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function resetLineHeight()
|
|
|
|
{
|
2021-04-06 18:37:26 +02:00
|
|
|
$('html').css('--lh', '').removeClass('lh-set');
|
2021-04-07 18:51:52 +02:00
|
|
|
updateVarsAndLayout();
|
2021-04-06 15:29:12 +02:00
|
|
|
return updateLineHeight();
|
2021-04-02 01:59:34 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 19:32:46 +02:00
|
|
|
function resetListWidth()
|
|
|
|
{
|
|
|
|
$('html').css('--lw', '').removeClass('lw-set');
|
2021-04-07 18:51:52 +02:00
|
|
|
updateVarsAndLayout();
|
2021-04-06 19:32:46 +02:00
|
|
|
return updateListWidth();
|
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
2021-03-31 20:35:46 +02:00
|
|
|
* event handlers
|
2021-03-31 18:27:33 +02:00
|
|
|
*/
|
|
|
|
$(window).on('blur', function(){
|
|
|
|
$('body').removeClass('reveal');
|
|
|
|
});
|
2020-02-19 14:25:11 +01:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$(document).on('keydown', function(ev){
|
|
|
|
setRevealState(ev);
|
|
|
|
});
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$(document).on('keyup', function(ev){
|
2021-03-30 10:18:01 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var raw = ev.originalEvent;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
setRevealState(ev);
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (ev.target.nodeName == 'TEXTAREA' ||
|
|
|
|
ev.target.nodeName == 'INPUT')
|
|
|
|
return;
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (ev.ctrlKey && (raw.code == 'KeyZ'))
|
|
|
|
{
|
|
|
|
var ok = ev.shiftKey ? redoBoard() : undoBoard();
|
|
|
|
if (! ok)
|
|
|
|
showDing();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (ev.ctrlKey && (raw.code == 'KeyY'))
|
|
|
|
{
|
|
|
|
if (! redoBoard())
|
|
|
|
showDing();
|
|
|
|
}
|
|
|
|
});
|
2021-03-30 10:37:15 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .text', function(ev){
|
2019-05-28 12:09:54 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (this.was_dragged)
|
|
|
|
{
|
|
|
|
this.was_dragged = false;
|
|
|
|
return false;
|
|
|
|
}
|
2020-02-08 12:02:45 -05:00
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
NB.noteDrag.cancelPriming();
|
2020-02-08 12:02:45 -05:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
startEditing($(this), ev);
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .note .text a', function(ev){
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! $('body').hasClass('reveal'))
|
|
|
|
return true;
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
ev.stopPropagation();
|
|
|
|
return true;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.wrap').on('keydown', '.board .edit', function(ev){
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var isNote = (this.tagName == 'TEXTAREA');
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// esc
|
|
|
|
if (ev.keyCode == 27)
|
2021-03-31 12:35:41 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
stopEditing($(this), true, false);
|
|
|
|
return false;
|
2021-03-31 12:35:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// tab
|
|
|
|
if (ev.keyCode == 9)
|
2021-03-31 12:35:41 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
handleTab.call(this, ev);
|
|
|
|
return false;
|
2021-03-31 12:35:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// done
|
|
|
|
if (ev.keyCode == 13 && ! isNote ||
|
|
|
|
ev.keyCode == 13 && ev.altKey ||
|
|
|
|
ev.keyCode == 13 && ev.shiftKey && ! ev.ctrlKey)
|
2021-03-31 12:35:41 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
stopEditing($(this), false, false);
|
|
|
|
return false;
|
2021-03-31 12:35:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// done + (add after / add before)
|
|
|
|
if (ev.keyCode == 13 && ev.ctrlKey)
|
2021-03-31 12:35:41 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
var $this = $(this);
|
|
|
|
var $note = $this.closest('.note');
|
|
|
|
var $list = $note.closest('.list');
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
stopEditing($this, false, false);
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if ($note && ev.shiftKey) // ctrl-shift-enter
|
|
|
|
addNote($list, null, $note);
|
|
|
|
else
|
|
|
|
if ($note && !ev.shiftKey) // ctrl-enter
|
|
|
|
addNote($list, $note);
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
|
|
|
}
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// done + collapse
|
|
|
|
if (isNote && ev.altKey && ev.key == 'ArrowUp')
|
|
|
|
{
|
|
|
|
var $item = $(this).parent();
|
|
|
|
$item[0]._collapsed = true;
|
|
|
|
stopEditing($(this), false, false);
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// done + expand
|
|
|
|
if (isNote && ev.altKey && ev.key == 'ArrowDown')
|
|
|
|
{
|
|
|
|
var $item = $(this).parent();
|
|
|
|
$item[0]._collapsed = false;
|
|
|
|
stopEditing($(this), false, false);
|
|
|
|
return false;
|
2021-03-31 12:35:41 +02:00
|
|
|
}
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// done + toggle 'raw'
|
|
|
|
if (isNote && ev.altKey && ev.keyCode == 82)
|
2021-03-31 12:35:41 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
$(this).parent().toggleClass('raw');
|
|
|
|
stopEditing($(this), false, false);
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// ctrl-shift-8
|
|
|
|
if (isNote && ev.key == '*' && ev.ctrlKey)
|
|
|
|
{
|
|
|
|
var have = this.value;
|
|
|
|
var pos = this.selectionStart;
|
|
|
|
var want = have.substr(0, pos) + '\u2022 ' + have.substr(this.selectionEnd);
|
|
|
|
$(this).val(want);
|
|
|
|
this.selectionStart = this.selectionEnd = pos + 2;
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
return true;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('keypress', '.board .edit', function(ev){
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
// tab
|
|
|
|
if (ev.keyCode == 9)
|
2021-03-31 12:35:41 +02:00
|
|
|
{
|
2021-03-31 18:27:33 +02:00
|
|
|
handleTab.call(this, ev);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.wrap').on('blur', '.board .edit', function(ev){
|
|
|
|
if (document.activeElement != this)
|
|
|
|
stopEditing($(this), false, true);
|
|
|
|
else
|
|
|
|
; // switch away from the browser window
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.wrap').on('input propertychange', '.board .note .edit', function(){
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var delta = $(this).outerHeight() - $(this).height();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$(this).height(10);
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (this.scrollHeight > this.clientHeight)
|
2021-04-05 11:50:02 +02:00
|
|
|
$(this).height(this.scrollHeight - delta);
|
2021-03-31 18:27:33 +02:00
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.config').on('click', '.add-board', function(){
|
|
|
|
addBoard();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.config').on('click', '.load-board', function(){
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-04-02 01:59:34 +02:00
|
|
|
var board_id = parseInt( $(this).attr('board_id') );
|
|
|
|
|
|
|
|
NB.loadDrag.cancelPriming();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (NB.board && (NB.board.id == board_id))
|
|
|
|
closeBoard();
|
|
|
|
else
|
2021-04-02 01:59:34 +02:00
|
|
|
openBoard(board_id);
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .del-board', function(){
|
|
|
|
deleteBoard();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .undo-board', function(){
|
|
|
|
undoBoard();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .redo-board', function(){
|
|
|
|
redoBoard();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.wrap').on('click', '.board .add-list', function(){
|
|
|
|
addList();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .del-list', function(){
|
|
|
|
deleteList( $(this).closest('.list') );
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .mov-list-l', function(){
|
|
|
|
moveList( $(this).closest('.list'), true );
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .mov-list-r', function(){
|
|
|
|
moveList( $(this).closest('.list'), false );
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.wrap').on('click', '.board .add-note', function(){
|
|
|
|
addNote( $(this).closest('.list') );
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .del-note', function(){
|
|
|
|
deleteNote( $(this).closest('.note') );
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .raw-note', function(){
|
|
|
|
$(this).closest('.note').toggleClass('raw');
|
|
|
|
saveBoard();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.wrap').on('click', '.board .collapse', function(){
|
|
|
|
$(this).closest('.note').toggleClass('collapsed');
|
|
|
|
saveBoard();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.wrap').on('mousedown', '.board .note .text', function(ev){
|
2021-04-02 01:59:34 +02:00
|
|
|
NB.noteDrag.prime(this.parentNode, ev);
|
|
|
|
});
|
|
|
|
|
|
|
|
$('.config').on('mousedown', 'a.load-board', function(ev){
|
|
|
|
if ($('.config a.load-board').length > 1)
|
|
|
|
NB.loadDrag.prime(this, ev);
|
2021-03-31 18:27:33 +02:00
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
//
|
|
|
|
$('.config').on('mousedown', '.ui-fs .val', function(ev){
|
|
|
|
var org = getFontSize();
|
|
|
|
NB.varAdjust.start(ev, function(delta){ setFontSize( org + delta/50. ); });
|
|
|
|
});
|
|
|
|
|
|
|
|
$('.config').on('mousedown', '.ui-lh .val', function(ev){
|
|
|
|
var org = getLineHeight();
|
|
|
|
NB.varAdjust.start(ev, function(delta){ setLineHeight( org + delta/50. ); });
|
|
|
|
});
|
|
|
|
|
|
|
|
$('.config').on('mousedown', '.ui-lw .val', function(ev){
|
|
|
|
var org = getListWidth();
|
|
|
|
NB.varAdjust.start(ev, function(delta){ setListWidth( org + delta/5. ); });
|
|
|
|
});
|
|
|
|
|
|
|
|
//
|
2021-03-31 18:27:33 +02:00
|
|
|
$(document).on('mouseup', function(ev){
|
2021-04-02 01:59:34 +02:00
|
|
|
NB.noteDrag.end();
|
|
|
|
NB.loadDrag.end();
|
2021-04-07 18:51:52 +02:00
|
|
|
NB.varAdjust.end();
|
2021-03-31 18:27:33 +02:00
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$(document).on('mousemove', function(ev){
|
|
|
|
setRevealState(ev);
|
2021-04-02 01:59:34 +02:00
|
|
|
NB.noteDrag.onMouseMove(ev);
|
|
|
|
NB.loadDrag.onMouseMove(ev);
|
2021-04-07 18:51:52 +02:00
|
|
|
NB.varAdjust.onMouseMove(ev);
|
2021-03-31 18:27:33 +02:00
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.config').on('click', '.imp-board', function(ev){
|
|
|
|
$('.config .imp-board-select').click();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.config').on('change', '.imp-board-select' , function(){
|
|
|
|
var files = this.files;
|
|
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = function(ev){ importBoard(ev.target.result); };
|
|
|
|
reader.readAsText(files[0]);
|
|
|
|
return true;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.config').on('click', '.exp-board', function(){
|
2021-03-31 20:20:49 +02:00
|
|
|
var pack = exportBoard();
|
|
|
|
$(this).attr('href', pack.blob);
|
|
|
|
$(this).attr('download', pack.file);
|
2021-03-31 18:27:33 +02:00
|
|
|
return true;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
//
|
|
|
|
$('.config .section .title').on('click', function(){
|
|
|
|
$(this).closest('.section').toggleClass('open');
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-04-05 18:20:23 +02:00
|
|
|
$('.config').on('click', '.switch-font', function(){
|
2021-04-05 11:50:02 +02:00
|
|
|
var font = $(this).attr('font');
|
|
|
|
selectFont(font);
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setFontName(font);
|
2021-03-31 18:27:33 +02:00
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
//
|
|
|
|
$('.config .f-prefs .ui-fs .less').on('click', function(){
|
2021-04-07 18:51:52 +02:00
|
|
|
var fs = setFontSize( parseInt(10*getFontSize()) / 10. - 0.5 );
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setFontSize(fs);
|
2021-04-06 13:21:48 +02:00
|
|
|
return false;
|
2021-04-05 18:20:23 +02:00
|
|
|
});
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
$('.config .f-prefs .ui-fs .val').on('click', function(){
|
2021-04-07 18:51:52 +02:00
|
|
|
if (NB.varAdjust.used) return false;
|
2021-04-06 13:21:48 +02:00
|
|
|
var fs = resetFontSize();
|
2021-04-07 18:51:52 +02:00
|
|
|
if (getLineHeight() < fs) setLineHeight(fs);
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setFontSize(null);
|
2021-04-06 13:21:48 +02:00
|
|
|
return false;
|
2021-04-05 18:20:23 +02:00
|
|
|
});
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
$('.config .f-prefs .ui-fs .more').on('click', function(){
|
2021-04-07 18:51:52 +02:00
|
|
|
var fs = setFontSize( parseInt(10*getFontSize()) / 10. + 0.5 );
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setFontSize(fs);
|
2021-04-06 13:21:48 +02:00
|
|
|
return false;
|
2021-04-05 18:20:23 +02:00
|
|
|
});
|
|
|
|
|
2021-04-06 15:29:12 +02:00
|
|
|
//
|
2021-04-06 13:21:48 +02:00
|
|
|
$('.config .f-prefs .ui-lh .less').on('click', function(){
|
2021-04-07 18:51:52 +02:00
|
|
|
var lh = setLineHeight( parseInt(10*getLineHeight()) / 10. - 0.1 );
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setLineHeight(lh);
|
2021-04-06 13:21:48 +02:00
|
|
|
return false;
|
2021-04-05 18:20:23 +02:00
|
|
|
});
|
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
$('.config .f-prefs .ui-lh .val').on('click', function(){
|
2021-04-07 18:51:52 +02:00
|
|
|
if (NB.varAdjust.used) return false;
|
2021-04-06 13:21:48 +02:00
|
|
|
var lh = resetLineHeight();
|
2021-04-07 18:51:52 +02:00
|
|
|
if (lh < getFontSize()) setFontSize(lh);
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setLineHeight(null);
|
2021-04-06 13:21:48 +02:00
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
$('.config .f-prefs .ui-lh .more').on('click', function(){
|
2021-04-07 18:51:52 +02:00
|
|
|
var lh = setLineHeight( parseInt(10*getLineHeight()) / 10. + 0.1 );
|
2021-04-06 15:29:12 +02:00
|
|
|
NB.storage.setLineHeight(lh);
|
2021-04-06 13:21:48 +02:00
|
|
|
return false;
|
|
|
|
});
|
2021-04-05 18:20:23 +02:00
|
|
|
|
2021-04-06 19:32:46 +02:00
|
|
|
//
|
|
|
|
$('.config .f-prefs .ui-lw .less').on('click', function(){
|
|
|
|
var lw = setListWidth( getListWidth() - 5 );
|
|
|
|
NB.storage.setListWidth(lw);
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
$('.config .f-prefs .ui-lw .val').on('click', function(){
|
2021-04-07 18:51:52 +02:00
|
|
|
if (NB.varAdjust.used) return false;
|
2021-04-06 19:32:46 +02:00
|
|
|
resetListWidth();
|
|
|
|
NB.storage.setListWidth(null);
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
$('.config .f-prefs .ui-lw .more').on('click', function(){
|
|
|
|
var lw = setListWidth( getListWidth() + 5 );
|
|
|
|
NB.storage.setListWidth(lw);
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
2021-04-06 16:51:20 +02:00
|
|
|
//
|
|
|
|
$('.config').on('click', '.switch-theme', function() {
|
|
|
|
var $html = $('html');
|
|
|
|
$html.toggleClass('theme-dark');
|
|
|
|
NB.storage.setTheme($html.hasClass('theme-dark') ? 'dark' : '');
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
$('.overlay').click(function(ev){
|
|
|
|
if (ev.originalEvent.target != this)
|
|
|
|
return true;
|
|
|
|
hideOverlay();
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$(window).keydown(function(ev){
|
|
|
|
if (haveOverlay() && ev.keyCode == 27)
|
|
|
|
hideOverlay();
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.view-about').click(function(){
|
|
|
|
var $div = $('tt .about').clone();
|
2021-03-31 20:49:29 +02:00
|
|
|
$div.find('div').html(`Version ${NB.codeVersion}`);
|
2021-03-31 18:27:33 +02:00
|
|
|
showOverlay($div);
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$('.view-license').click(function(){
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var $div = $('tt .license').clone();
|
|
|
|
$div.html(formatLicense());
|
|
|
|
showOverlay($div);
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
$(window).resize(adjustLayout);
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-04-06 23:54:46 +02:00
|
|
|
$('body').on('dragstart', function(){ return false; });
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
/*
|
|
|
|
* the init()
|
|
|
|
*/
|
2021-04-06 13:21:48 +02:00
|
|
|
var NB =
|
|
|
|
{
|
2021-04-07 18:51:52 +02:00
|
|
|
codeVersion: 20210407,
|
|
|
|
blobVersion: 20190412, // board blob format in Storage
|
2021-04-06 13:21:48 +02:00
|
|
|
board: null,
|
|
|
|
};
|
|
|
|
|
|
|
|
NB.storage = new Storage_Local();
|
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! NB.storage.open())
|
|
|
|
{
|
2021-03-31 19:32:01 +02:00
|
|
|
easyMartina = true;
|
|
|
|
throw new Error();
|
2021-03-31 18:27:33 +02:00
|
|
|
}
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
var boards = NB.storage.getBoardIndex();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
boards.forEach( function(meta, board_id) {
|
2021-03-31 18:27:33 +02:00
|
|
|
var hist = meta.history.join(', ');
|
|
|
|
console.log( `Found board ${board_id} - "${meta.title}", revision ${meta.current}, history [${hist}]` );
|
|
|
|
});
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
var conf = NB.storage.getConfig();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
console.log( `Active: [${conf.board}]` );
|
|
|
|
console.log( `Theme: [${conf.theme}]` );
|
2021-04-06 19:09:14 +02:00
|
|
|
console.log( `Font: [${conf.fontName}], size [${conf.fontSize || '-'}], line-height [${conf.lineHeight || '-'}]` );
|
2021-04-05 11:50:02 +02:00
|
|
|
|
2021-04-05 18:20:23 +02:00
|
|
|
//
|
2021-04-06 13:21:48 +02:00
|
|
|
initFonts();
|
2021-04-05 18:20:23 +02:00
|
|
|
|
2021-04-06 13:21:48 +02:00
|
|
|
initDragAndDrop();
|
2021-04-05 18:20:23 +02:00
|
|
|
|
2021-04-07 18:51:52 +02:00
|
|
|
NB.varAdjust = new VarAdjust()
|
|
|
|
|
2021-04-05 11:50:02 +02:00
|
|
|
//
|
2021-03-31 18:27:33 +02:00
|
|
|
if (conf.theme)
|
2021-04-05 11:50:02 +02:00
|
|
|
$('html').addClass('theme-' + conf.theme);
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (conf.board)
|
|
|
|
openBoard(conf.board)
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
adjustLayout();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
updateBoardIndex();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 20:35:46 +02:00
|
|
|
//
|
2021-03-31 18:27:33 +02:00
|
|
|
if (! NB.board && ! $('.config .load-board').length)
|
|
|
|
NB.board = createDemoBoard();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
if (NB.board)
|
|
|
|
showBoard(true);
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2021-03-31 18:27:33 +02:00
|
|
|
//
|
|
|
|
setInterval(adjustListScroller, 100);
|
|
|
|
|
|
|
|
setupListScrolling();
|
2021-03-31 12:35:41 +02:00
|
|
|
|
2019-05-28 12:09:54 +02:00
|
|
|
</script>
|
|
|
|
|
|
|
|
</html>
|