├── .htaccess
├── 404.html
├── LICENSE
├── README.md
├── _notes
└── .htaccess
├── config.php
├── css
├── simple.css
├── simple.min.css
├── styles.css
└── styles.min.css
├── favicon.ico
├── image
├── Screenshot_20230725_001749.png
├── Screenshot_20230725_001758.png
├── Screenshot_20230725_001834.png
├── Screenshot_20230725_001901.png
├── Screenshot_20230725_001922.png
├── Screenshot_20230725_002013.png
├── Screenshot_20230725_002105.png
├── Screenshot_20230725_002159.png
├── Screenshot_20230725_002735.png
├── Screenshot_20230725_003659.png
└── Screenshot_20230725_003719.png
├── index.php
├── js
├── notelist.js
├── notelist.min.js
├── script.js
├── script.min.js
├── simple.js
└── simple.min.js
├── modules
├── common.php
├── copy.php
├── create_notes_folder.php
├── css
│ ├── lastsaved.css
│ ├── lastsaved.min.css
│ ├── menu.css
│ ├── menu.min.css
│ ├── modal.css
│ └── modal.min.css
├── header.php
├── js
│ ├── copy.js
│ ├── copy.min.js
│ ├── lastsaved.js
│ ├── lastsaved.min.js
│ ├── menu.js
│ ├── menu.min.js
│ ├── modal.js
│ ├── modal.min.js
│ ├── password.js
│ ├── password.min.js
│ ├── tinyago.js
│ ├── tinyago.min.js
│ ├── view.js
│ └── view.min.js
├── lastsaved.php
├── menu.php
├── password.php
├── protect.php
└── protect_form.php
├── nginx.conf.example
├── notelist.php
├── passwordHelp.html
├── setup.php
├── simple.php
└── view.php
/.htaccess:
--------------------------------------------------------------------------------
1 | RewriteEngine On
2 |
3 | #RewriteCond %{HTTPS} off
4 | #RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
5 |
6 | # if there is a view parameter in the querystring then use view.php
7 | RewriteCond %{QUERY_STRING} ^view [NC]
8 | RewriteRule ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)$ view.php?note=$1 [L,QSA]
9 | # the [L] flag will stop any futher processing
10 |
11 | RewriteCond %{QUERY_STRING} ^simple [NC]
12 | RewriteRule ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)$ simple.php?note=$1 [L,QSA]
13 | # the [L] flag will stop any futher processing
14 |
15 | #allow 0-9 a-z and hyphens/dashes
16 | RewriteRule ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)$ index.php?note=$1 [L,QSA]
17 |
18 |
19 | Header set X-Robots-Tag: "noindex, nofollow"
20 |
21 |
--------------------------------------------------------------------------------
/404.html:
--------------------------------------------------------------------------------
1 |
2 |
404 Not Found
3 |
4 | 404 Not Found
5 |
nginx
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 domOrielton
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # minimal-web-notepad
2 |
3 | 这是一个在 [pereorga/minimalist-web-notepad](https://github.com/pereorga/minimalist-web-notepad) 上添加了额外功能的分支。附加的代码使得体积增加了,所以不再是极简,但是在经过压缩和gzip后仅有10KB。如果你想要真正极简的版本,pereorga 的实现小于 3KB,而且还没有经过压缩!
4 |
5 | 密码功能是通过在文本文件中添加一个头部行来实现的,该行在便签中不显示。请注意,这并不会加密内容,只是限制访问权限。服务器的唯一要求是启用了 mod_rewrite 的 Apache Web 服务器或启用了 ngx_http_rewrite_module 和 PHP 的 nginx Web 服务器。
6 |
7 | 
8 |
9 | 对 pereorga 的原始版本添加了以下功能:
10 | - 可以在便签中显示超链接的查看选项(在移动设备上非常有用)
11 | - 支持密码保护,并提供只读访问选项
12 | - 仅查看链接
13 | - 显示便签的上次保存时间
14 | - 将便签的URL、只读URL和便签文本复制到剪贴板
15 | - 以无衬线字体或等宽字体查看便签
16 | - 可以下载便签
17 | - 显示可用的便签列表
18 | - 可以根据需要打开或关闭功能以减小页面大小
19 |
20 | 可以在 汉化版:https://7t.vc 或原版 http://note.rf.gd/ 或 http://note.rf.gd/some-note-name-here 上查看演示。由于演示没有启用 HTTPS,所以浏览器中会显示密码警告,请仅用于测试,不要用于其他用途。
21 |
22 | 截图:
23 | **便签查看模式**
24 | 
25 |
26 | **适配移动设备的响应式菜单**
27 | 
28 | 
29 |
30 | **等宽字体**
31 | 
32 |
33 | **密码保护**
34 | 
35 |
36 | **受保护便签的密码提示**
37 | 
38 |
39 | “以只读模式查看”链接仅显示便签文本,不显示其他内容
40 |
41 | **复制到剪贴板的链接**
42 | 
43 |
44 | **便签列表**
45 | - 通常仅用于非公开的 URL,尽管页面是受密码保护的
46 | 
47 |
48 | 如果不想显示便签列表,可以在 index.php 文件顶部将 $allow_noteslist 参数设置为 false,或者将 `notelist.php` 重命名为其他名称。便签列表页面的密码位于 `notelist.php` 文件的顶部,可以使用 `Protect\with('modules/protect_form.php','在这里更改密码')` 进行修改。
49 |
50 | **备选编辑视图**
51 | 还有一种备选的编辑视图,可以在便签后添加 `?simple` 来访问,例如 /quick?simple。我个人觉得这个视图非常适合在手机上快速添加便签,它在页面顶部有一个较小的编辑区域,当你输入文本并按下回车键时,它会将文本添加到便签中,并将其移动到占据页面剩余部分的视图中。此视图部分将 URL 显示为可点击的链接。您不能在此视图上设置密码,但它会遵循已有的密码。
52 |
53 | 
54 |
55 | 安装:
56 | 只要启用了 mod_rewrite 并且 Web 服务器被允许写入 `_notes` 数据目录,就不需要进行任何配置。这个数据目录在 `config.php` 文件中设置,所以如果你想要将其更改为原始 pereorga/minimalist-web-notepad 版本使用的文件夹,请在那里进行修改。所有的便签都以文本文件的形式存储,所以运行 Apache(或 Nginx)的服务器应该就足够了,不需要使用数据库。如果便签无法保存,请检查 `_notes` 目录的权限,通常 0755 或 744 就足够了。
57 |
58 | 
59 |
60 | 还有一个 `setup.php` 页面,可以用来检查 `_notes` 目录是否存在并且可以写入。如果无法保存便签,可以尝试删除 `_notes` 目录,然后访问 `setup.php` 页面以创建该文件夹。如果一切正常,可以选择删除 `setup.php` 文件。
61 |
62 | 可能有些情况下需要将 `config.php` 文件中的 $base_url 变量替换为您安装的硬编码 URL 路径。如果是这种情况,请将以 `$base_url=dirname('//')` 开头的行替换为 `$base_url='http://actualURL.com/notes'`,将 actualURL.com/notes 替换为与您的安装相关的内容。
63 |
64 | ### 在 Apache 上
65 | 可能需要启用 mod_rewrite 并在站点配置中设置 `.htaccess` 文件。请参阅 [在 Ubuntu 14.04 上设置 Apache 的 mod_rewrite](https://www.digitalocean.com/community/tutorials/how-to-set-up-mod_rewrite-for-apache-on-ubuntu-14-04)。
66 |
67 | ## 在 Nginx 上
68 | 在 Nginx 上,需要确保 nginx.conf 文件正确配置以确保应用程序按预期工作。请检查 nginx.conf.example 文件或查看[没有密码问题的讨论](https://github.com/domOrielton/minimal-web-notepad/issues/4)。感谢 [eonegh](https://github.com/eonegh) 提供示例文件。
69 |
--------------------------------------------------------------------------------
/_notes/.htaccess:
--------------------------------------------------------------------------------
1 | Deny from all
2 |
--------------------------------------------------------------------------------
/config.php:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/css/simple.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | background: #ebeef1;
4 | }
5 |
6 | .container {
7 | position: absolute;
8 | top: 20px;
9 | right: 20px;
10 | bottom: 20px;
11 | left: 20px;
12 | }
13 |
14 | .contentAdd, .content {
15 | font-size: 100%;
16 | margin: 0;
17 | padding: 20px;
18 | overflow-y: auto;
19 | resize: none;
20 | width: 100%;
21 | height: 10%;
22 | min-height: 10%;
23 | -webkit-box-sizing: border-box;
24 | -moz-box-sizing: border-box;
25 | box-sizing: border-box;
26 | border: 1px #ddd solid;
27 | outline: none;
28 | font-family: sans-serif;
29 | }
30 |
31 | .content {
32 | height: 90%;
33 | min-height: 90%;
34 | }
35 |
36 | .content br {
37 | display: block;
38 | line-height: 1.5em;
39 | }
40 |
41 | @media screen and (max-width: 600px) {
42 | .contentAdd {
43 | padding-top: 5px !important;
44 | }
45 | }
46 |
47 | #printable {
48 | display: none;
49 | }
50 |
51 | @media print {
52 | .container {
53 | display: none;
54 | }
55 |
56 | #printable {
57 | display: block;
58 | white-space: pre-wrap;
59 | word-break: break-word;
60 | }
61 | }
62 |
63 | .wordwrap {
64 | /* used for the view functionality */
65 | white-space: pre-wrap;
66 | /* CSS3 */
67 | white-space: -moz-pre-wrap;
68 | /* Firefox */
69 | white-space: -pre-wrap;
70 | /* Opera <7 */
71 | white-space: -o-pre-wrap;
72 | /* Opera 7 */
73 | word-wrap: break-word;
74 | /* IE */
75 | }
76 |
77 | .footer {
78 | font-size: 100%;
79 | font-family: monospace;
80 | position: absolute;
81 | bottom: 0;
82 | left: 20px;
83 | text-align: left;
84 | }
85 |
86 | @media print {
87 | .footer {
88 | display: none;
89 | }
90 | }
91 |
92 | .navbar {
93 | overflow: hidden;
94 | position: fixed;
95 | bottom: 0;
96 | min-width: 100px;
97 | background-color: #ebeef1;
98 | }
99 |
100 | .navbar a {
101 | float: left;
102 | display: block;
103 | color: black;
104 | text-align: center;
105 | padding: 1px 5px;
106 | text-decoration: underline;
107 | }
108 |
109 | .navbar a:hover {
110 | /*background-color: #ddd;*/
111 | color: black;
112 | }
113 |
114 | .navbar a.active {
115 | color: black;
116 | }
117 |
--------------------------------------------------------------------------------
/css/simple.min.css:
--------------------------------------------------------------------------------
1 | body{margin:0;background:#ebeef1}.container{position:absolute;top:20px;right:20px;bottom:20px;left:20px}.contentAdd,.content{font-size:100%;margin:0;padding:20px;overflow-y:auto;resize:none;width:100%;height:10%;min-height:10%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:1px #ddd solid;outline:0;font-family:sans-serif}.content{height:90%;min-height:90%}.content br{display:block;line-height:1.5em}@media screen and (max-width:600px){.contentAdd{padding-top:5px!important}}#printable{display:none}@media print{.container{display:none}#printable{display:block;white-space:pre-wrap;word-break:break-word}}.wordwrap{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.footer{font-size:100%;font-family:monospace;position:absolute;bottom:0;left:20px;text-align:left}@media print{.footer{display:none}}.navbar{overflow:hidden;position:fixed;bottom:0;min-width:100px;background-color:#ebeef1}.navbar a{float:left;display:block;color:black;text-align:center;padding:1px 5px;text-decoration:underline}.navbar a:hover{color:black}.navbar a.active{color:black}
--------------------------------------------------------------------------------
/css/styles.css:
--------------------------------------------------------------------------------
1 | /*! Minimalist Web Notepad | https://github.com/pereorga/minimalist-web-notepad */
2 | body {
3 | margin: 0;
4 | background: #ebeef1;
5 | }
6 |
7 | .container {
8 | position: absolute;
9 | top: 20px;
10 | right: 20px;
11 | bottom: 20px;
12 | left: 20px;
13 | }
14 |
15 | .content {
16 | font-size: 100%;
17 | margin: 0;
18 | padding: 20px;
19 | overflow-y: auto;
20 | resize: none;
21 | width: 100%;
22 | height: 100%;
23 | min-height: 100%;
24 | -webkit-box-sizing: border-box;
25 | -moz-box-sizing: border-box;
26 | box-sizing: border-box;
27 | border: 1px #ddd solid;
28 | outline: none;
29 | /* comment font- settings out to return to default monospace font */
30 | font-family: sans-serif;
31 | font-size: medium;
32 | }
33 |
34 | #printable {
35 | display: none;
36 | }
37 |
38 | .hidden {visibility: hidden;}
39 |
40 | a {
41 | cursor: pointer;
42 | color: blue;
43 | }
44 |
45 | a:hover, a.hover {
46 | text-decoration: underline;
47 | }
48 |
49 | @media print {
50 | #content {
51 | display: none;
52 | }
53 |
54 | #printable {
55 | display: block;
56 | white-space: pre-wrap;
57 | word-break: break-word;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/css/styles.min.css:
--------------------------------------------------------------------------------
1 | /*! Minimalist Web Notepad | https://github.com/pereorga/minimalist-web-notepad */body{margin:0;background:#ebeef1}.container{position:absolute;top:20px;right:20px;bottom:20px;left:20px}.content{font-size:100%;margin:0;padding:20px;overflow-y:auto;resize:none;width:100%;height:100%;min-height:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:1px #ddd solid;outline:0;font-family:sans-serif;font-size:medium}#printable{display:none}.hidden{visibility:hidden}a{cursor:pointer;color:blue}a:hover,a.hover{text-decoration:underline}@media print{#content{display:none}#printable{display:block;white-space:pre-wrap;word-break:break-word}}
2 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/favicon.ico
--------------------------------------------------------------------------------
/image/Screenshot_20230725_001749.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_001749.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_001758.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_001758.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_001834.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_001834.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_001901.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_001901.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_001922.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_001922.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_002013.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_002013.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_002105.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_002105.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_002159.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_002159.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_002735.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_002735.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_003659.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_003659.png
--------------------------------------------------------------------------------
/image/Screenshot_20230725_003719.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VMCoud/minimal-web-notepad/4f38db2e2d9763ff49fd169e915a58bf51a6b971/image/Screenshot_20230725_003719.png
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
90 |
91 |
92 |
93 | '.PHP_EOL;
100 | echo "".PHP_EOL;
101 | }
102 | if ($include_Header) { checkHeader($path, null, true); } //check if the removePassword be shown ?>
103 |
104 |
105 |
--------------------------------------------------------------------------------
/js/notelist.js:
--------------------------------------------------------------------------------
1 | // from https://www.w3schools.com/howto/howto_js_sort_table.asp
2 | function sortTable(n) {
3 | var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
4 | table = document.getElementById("notelistTable");
5 | switching = true;
6 | //Set the sorting direction to ascending:
7 | dir = "asc";
8 | /*Make a loop that will continue until
9 | no switching has been done:*/
10 | while (switching) {
11 | //start by saying: no switching is done:
12 | switching = false;
13 | rows = table.getElementsByTagName("TR");
14 | /*Loop through all table rows (except the
15 | first, which contains table headers):*/
16 | for (i = 1; i < (rows.length - 1); i++) {
17 | //start by saying there should be no switching:
18 | shouldSwitch = false;
19 | /*Get the two elements you want to compare,
20 | one from current row and one from the next:*/
21 | x = rows[i].getElementsByTagName("TD")[n];
22 | y = rows[i + 1].getElementsByTagName("TD")[n];
23 | /*check if the two rows should switch place,
24 | based on the direction, asc or desc:*/
25 | if (dir == "asc") {
26 | if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
27 | //if so, mark as a switch and break the loop:
28 | shouldSwitch = true;
29 | break;
30 | }
31 | } else if (dir == "desc") {
32 | if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
33 | //if so, mark as a switch and break the loop:
34 | shouldSwitch = true;
35 | break;
36 | }
37 | }
38 | }
39 | if (shouldSwitch) {
40 | /*If a switch has been marked, make the switch
41 | and mark that a switch has been done:*/
42 | rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
43 | switching = true;
44 | //Each time a switch is done, increase this count by 1:
45 | switchcount++;
46 | } else {
47 | /*If no switching has been done AND the direction is "asc",
48 | set the direction to "desc" and run the while loop again.*/
49 | if (switchcount == 0 && dir == "asc") {
50 | dir = "desc";
51 | switching = true;
52 | }
53 | }
54 | }
55 | }
56 | // from https://www.w3schools.com/howto/howto_js_filter_table.asp
57 | function filterTable() {
58 | // Declare variables
59 | var input, filter, table, tr, td, i;
60 | input = document.getElementById("filterNotes");
61 | filter = input.value.toUpperCase();
62 | table = document.getElementById("notelistTable");
63 | tr = table.getElementsByTagName("tr");
64 |
65 | // Loop through all table rows, and hide those who don't match the search query
66 | for (i = 0; i < tr.length; i++) {
67 | td = tr[i].getElementsByTagName("td")[0];
68 | if (td) {
69 | if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
70 | tr[i].style.display = "";
71 | } else {
72 | tr[i].style.display = "none";
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/js/notelist.min.js:
--------------------------------------------------------------------------------
1 | function sortTable(a){var j,k,b,e,h,g,f,c,d=0;j=document.getElementById("notelistTable");b=true;c="asc";while(b){b=false;k=j.getElementsByTagName("TR");for(e=1;e<(k.length-1);e++){f=false;h=k[e].getElementsByTagName("TD")[a];g=k[e+1].getElementsByTagName("TD")[a];if(c=="asc"){if(h.innerHTML.toLowerCase()>g.innerHTML.toLowerCase()){f=true;break}}else{if(c=="desc"){if(h.innerHTML.toLowerCase()-1){e[b].style.display=""}else{e[b].style.display="none"}}}};
--------------------------------------------------------------------------------
/js/script.js:
--------------------------------------------------------------------------------
1 | function uploadContent(force) {
2 |
3 | force = force || false; //force needed to add password even though the text is not changed
4 | // If textarea value changes.
5 | if (content !== textarea.value || force) {
6 | var temp = textarea.value;
7 | var request = new XMLHttpRequest();
8 | var saved = false;
9 | request.open('POST', window.location.href, true);
10 | request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
11 |
12 | request.onreadystatechange = function() {
13 | //if (this.readyState !== 4 || this.status !== 200) {
14 | // saved = "error";
15 | //} // for lastUpdated status
16 | // the password page won't show correctly if the textarea is there and the session has timed out but
17 | // we can still search for text displayed in the form as it is in the responseText
18 | if (this.responseText.search("Invalid password") !== -1) {
19 | location.reload();
20 | }
21 | //if (this.responseText.search("saved") > 0) {
22 | // saved = true;
23 | //}
24 | //} // will give a true here is password is set on blank note as note gets deleted
25 | //if (this.responseText.search("deleted") !== -1) {
26 | // saved = true;
27 | //} // will give a true here is password is set on blank note as note gets deleted
28 | if (typeof lastUpdated === "function" ) {
29 | lastUpdated(this.responseText);
30 | } // check if the lastupdated functions are loaded
31 | };
32 |
33 | request.onload = function() {
34 | if (request.readyState === 4) {
35 |
36 | // Request has ended, check again after 1 second.
37 | content = temp;
38 | setTimeout(uploadContent, 1500); //increased time from 1 to 1.5 seconds to offset header check
39 | }
40 | }
41 |
42 | request.onerror = function() {
43 | //saved = "error"; // for lastUpdated status
44 | // Try again after 1 second
45 | setTimeout(uploadContent, 1000);
46 | }
47 |
48 | // Send the request.
49 | var requestToSend = 'text=' + encodeURIComponent(temp);
50 | if (typeof passwordRequest_Add === "function") {
51 | requestToSend = passwordRequest_Add(requestToSend);
52 | } //check if the password functions are loaded
53 | if (typeof passwordRequest_Remove === "function") {
54 | requestToSend = passwordRequest_Remove(requestToSend);
55 | } //check if the password functions are loaded
56 | request.send(requestToSend);
57 |
58 | // Make the content available to print.
59 | printable.removeChild(printable.firstChild);
60 | printable.appendChild(document.createTextNode(temp));
61 |
62 | if (document.getElementById("contentWithLinks")) {
63 | // used by the simple view
64 | document.getElementById("contentWithLinks").innerHTML = linkify(document.getElementById("printable").innerHTML).replace(/\r\n|\r|\n/g, "
");
65 | var objDiv = document.getElementById("contentWithLinks").scrollHeight; //scroll to bottom as text added there
66 | }
67 |
68 | } else {
69 |
70 | // Content has not changed, check again after 1 second.
71 | setTimeout(uploadContent, 1000);
72 | if (typeof lastSaved === "function") {
73 | lastSaved();
74 | } //check if the lastupdated functions are loaded
75 | }
76 | }
77 |
78 | var textarea = document.getElementById('content');
79 | var printable = document.getElementById('printable');
80 | var content = textarea.value;
81 |
82 | // Make the content available to print.
83 | printable.appendChild(document.createTextNode(content));
84 |
85 | // Enable TABs to indent. Based on https://stackoverflow.com/a/14166052/1391963
86 | textarea.onkeydown = function(e) {
87 | if (e.keyCode === 9 || e.which === 9) {
88 | e.preventDefault();
89 | var s = this.selectionStart;
90 | this.value = this.value.substring(0, this.selectionStart) + '\t' + this.value.substring(this.selectionEnd);
91 | this.selectionEnd = s + 1;
92 | }
93 | }
94 |
95 | textarea.focus();
96 | uploadContent();
97 |
--------------------------------------------------------------------------------
/js/script.min.js:
--------------------------------------------------------------------------------
1 | function uploadContent(f){f=f||false;if(content!==textarea.value||f){var b=textarea.value;var e=new XMLHttpRequest();var d=false;e.open("POST",window.location.href,true);e.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");e.onreadystatechange=function(){if(this.responseText.search("Invalid password")!==-1){location.reload()}if(typeof lastUpdated==="function"){lastUpdated(this.responseText)}};e.onload=function(){if(e.readyState===4){content=b;setTimeout(uploadContent,1500)}};e.onerror=function(){setTimeout(uploadContent,1000)};var c="text="+encodeURIComponent(b);if(typeof passwordRequest_Add==="function"){c=passwordRequest_Add(c)}if(typeof passwordRequest_Remove==="function"){c=passwordRequest_Remove(c)}e.send(c);printable.removeChild(printable.firstChild);printable.appendChild(document.createTextNode(b));if(document.getElementById("contentWithLinks")){document.getElementById("contentWithLinks").innerHTML=linkify(document.getElementById("printable").innerHTML).replace(/\r\n|\r|\n/g,"
");var a=document.getElementById("contentWithLinks").scrollHeight}}else{setTimeout(uploadContent,1000);if(typeof lastSaved==="function"){lastSaved()}}}var textarea=document.getElementById("content");var printable=document.getElementById("printable");var content=textarea.value;printable.appendChild(document.createTextNode(content));textarea.onkeydown=function(b){if(b.keyCode===9||b.which===9){b.preventDefault();var a=this.selectionStart;this.value=this.value.substring(0,this.selectionStart)+"\t"+this.value.substring(this.selectionEnd);this.selectionEnd=a+1}};textarea.focus();uploadContent();
--------------------------------------------------------------------------------
/js/simple.js:
--------------------------------------------------------------------------------
1 | var textareaAdd = document.getElementById('contentAdd'); // used by the simple view
2 |
3 | textareaAdd.onkeydown = function(e) {
4 | if (e.keyCode === 9 || e.which === 9) {
5 | e.preventDefault();
6 | var s = this.selectionStart;
7 | this.value = this.value.substring(0, this.selectionStart) + '\t' + this.value.substring(this.selectionEnd);
8 | this.selectionEnd = s + 1;
9 | }
10 | if (e.keyCode === 13 || e.which === 13) {
11 | e.preventDefault();
12 | document.getElementById("content").value += '\n' + textareaAdd.value;
13 | this.value = '';
14 | }
15 | }
16 |
17 | textareaAdd.focus();
18 |
--------------------------------------------------------------------------------
/js/simple.min.js:
--------------------------------------------------------------------------------
1 | var textareaAdd=document.getElementById("contentAdd");textareaAdd.onkeydown=function(b){if(b.keyCode===9||b.which===9){b.preventDefault();var a=this.selectionStart;this.value=this.value.substring(0,this.selectionStart)+"\t"+this.value.substring(this.selectionEnd);this.selectionEnd=a+1}if(b.keyCode===13||b.which===13){b.preventDefault();document.getElementById("content").value+="\n"+textareaAdd.value;this.value=""}};textareaAdd.focus();
--------------------------------------------------------------------------------
/modules/common.php:
--------------------------------------------------------------------------------
1 | console.log( 'Debug Objects: " . date('H:i:s'). " " . $output . "' );".PHP_EOL;
39 | }
40 |
41 | function writeToLog($txt)
42 | {
43 | file_put_contents('log.txt', date('Y-m-d H:i:s'). "\t" .$txt.PHP_EOL, FILE_APPEND | LOCK_EX);
44 | }
45 |
--------------------------------------------------------------------------------
/modules/copy.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
--------------------------------------------------------------------------------
/modules/create_notes_folder.php:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/modules/css/lastsaved.css:
--------------------------------------------------------------------------------
1 | .savedStatus {
2 | /* bottomRightCorner */
3 | font-size: 100%;
4 | font-family: monospace;
5 | position: absolute;
6 | bottom: 1px;
7 | right: 20px;
8 | }
9 |
10 | @media print {
11 | .savedStatus {
12 | display: none;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/modules/css/lastsaved.min.css:
--------------------------------------------------------------------------------
1 | .savedStatus{font-size:100%;font-family:monospace;position:absolute;bottom:1px;right:20px}@media print{.savedStatus{display:none}}
--------------------------------------------------------------------------------
/modules/css/menu.css:
--------------------------------------------------------------------------------
1 | .wordwrap {
2 | /* used for the view functionality */
3 | white-space: pre-wrap;
4 | /* CSS3 */
5 | white-space: -moz-pre-wrap;
6 | /* Firefox */
7 | white-space: -pre-wrap;
8 | /* Opera <7 */
9 | white-space: -o-pre-wrap;
10 | /* Opera 7 */
11 | word-wrap: break-word;
12 | /* IE */
13 | }
14 |
15 | .footer {
16 | font-size: 100%;
17 | font-family: monospace;
18 | position: absolute;
19 | bottom: 0;
20 | left: 20px;
21 | text-align: left;
22 | }
23 |
24 | @media print {
25 | .footer {
26 | display: none;
27 | }
28 | }
29 |
30 | /* navbar css - https://www.w3schools.com/howto/howto_js_bottom_nav_responsive.asp */
31 | .navbar {
32 | overflow: hidden;
33 | position: fixed;
34 | bottom: 0;
35 | min-width: 100px;
36 | background-color: #ebeef1;
37 | }
38 |
39 | .navbar a {
40 | float: left;
41 | display: block;
42 | color: black;
43 | text-align: center;
44 | padding: 1px 5px;
45 | text-decoration: underline;
46 | }
47 |
48 | .navbar a:hover {
49 | /*background-color: #ddd;*/
50 | color: black;
51 | }
52 |
53 | .navbar a.active {
54 | color: black;
55 | }
56 |
57 | .navbar .icon {
58 | display: none;
59 | }
60 |
61 | @media screen and (max-width: 600px) {
62 | .navbar a:not(:nth-child(2)) {
63 | display: none;
64 | }
65 |
66 | .navbar a {
67 | font-size: 17px;
68 | }
69 |
70 | .navbar a.icon {
71 | position: relative;
72 | left: 0;
73 | bottom: 0;
74 | /*float: left;*/
75 | display: block;
76 | }
77 | }
78 |
79 | @media screen and (max-width: 600px) {
80 | .navbar.responsive .icon {
81 | position: absolute;
82 | left: 0;
83 | bottom: 0;
84 | }
85 |
86 | .navbar.responsive a:not(:first-child) {
87 | float: none;
88 | display: block;
89 | text-align: left;
90 | margin-left: 40px !important;
91 | margin: 20px;
92 | }
93 | }
94 |
95 | /* end of navbar */
96 | /* overlay from https://raventools.com/blog/create-a-modal-dialog-using-css-and-javascript/ */
97 | #overlay {
98 | visibility: hidden;
99 | position: absolute;
100 | left: 0px;
101 | top: 0px;
102 | width: 100%;
103 | height: 100%;
104 | text-align: center;
105 | z-index: 1000;
106 | font-family: sans-serif;
107 | font-size: medium;
108 | }
109 |
110 | #overlay div {
111 | width: 250px;
112 | margin: 100px auto;
113 | background-color: #fff;
114 | border: 1px solid grey;
115 | padding: 15px;
116 | text-align: center;
117 | }
118 |
119 | body {
120 | height: 100%;
121 | margin: 0;
122 | padding: 0;
123 | }
124 |
--------------------------------------------------------------------------------
/modules/css/menu.min.css:
--------------------------------------------------------------------------------
1 | .wordwrap{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.footer{font-size:100%;font-family:monospace;position:absolute;bottom:0;left:20px;text-align:left}@media print{.footer{display:none}}.navbar{overflow:hidden;position:fixed;bottom:0;min-width:100px;background-color:#ebeef1}.navbar a{float:left;display:block;color:black;text-align:center;padding:1px 5px;text-decoration:underline}.navbar a:hover{color:black}.navbar a.active{color:black}.navbar .icon{display:none}@media screen and (max-width:600px){.navbar a:not(:nth-child(2)){display:none}.navbar a{font-size:17px}.navbar a.icon{position:relative;left:0;bottom:0;display:block}}@media screen and (max-width:600px){.navbar.responsive .icon{position:absolute;left:0;bottom:0}.navbar.responsive a:not(:first-child){float:none;display:block;text-align:left;margin-left:40px!important;margin:20px}}#overlay{visibility:hidden;position:absolute;left:0;top:0;width:100%;height:100%;text-align:center;z-index:1000;font-family:sans-serif;font-size:medium}#overlay div{width:250px;margin:100px auto;background-color:#fff;border:1px solid grey;padding:15px;text-align:center}body{height:100%;margin:0;padding:0}
--------------------------------------------------------------------------------
/modules/css/modal.css:
--------------------------------------------------------------------------------
1 | .modal_password, .modal_copy {
2 | position: fixed;
3 | left: 0;
4 | top: 0;
5 | width: 100%;
6 | height: 100%;
7 | background-color: rgba(0, 0, 0, 0.5);
8 | opacity: 0;
9 | visibility: hidden;
10 | transform: scale(1.1);
11 | }
12 |
13 | .modal-content {
14 | font-family: sans-serif;
15 | position: absolute;
16 | top: 50%;
17 | left: 50%;
18 | transform: translate(-50%, -50%);
19 | background-color: white;
20 | padding: 1rem 3rem;
21 | /*width: 24rem; */
22 | border-radius: 0.5rem;
23 | }
24 |
25 | @media screen and (max-width: 600px) {
26 | .modal-content {
27 | width: 90%;
28 | padding: 1rem 1rem;
29 | }
30 | }
31 |
32 | .close-button_password, .close-button_copy {
33 | float: right;
34 | width: 1.5rem;
35 | line-height: 1.5rem;
36 | text-align: center;
37 | cursor: pointer;
38 | border-radius: 0.25rem;
39 | /* background-color: lightgray; */
40 | }
41 |
42 | .show-modal {
43 | opacity: 1;
44 | visibility: visible;
45 | transform: scale(1.0);
46 | }
47 |
48 | .input,
49 | .submit {
50 | display: inline-block;
51 | padding: 10px 15px;
52 | margin-top: 10px;
53 | font-size: 10px;
54 | border-radius: 0;
55 | -webkit-appearance: none;
56 | }
57 |
58 | /* https://martinwolf.org/before-2018/blog/2015/07/equal-height-input-and-submit-button/ */
59 | .input {
60 | border: 1px solid lightgray;
61 | }
62 |
63 | #allowReadOnlyView {
64 | margin-left:0;
65 | margin-top: 5px;
66 | }
67 |
68 | .submit {
69 | color: #fff;
70 | background-color: #337ab7;
71 | border-color: #2e6da4;;
72 | /**
73 | * If the input field has a border,
74 | * you need it here too to achieve equal heights.
75 | */
76 | border: 1px solid transparent;
77 | }
78 |
79 | /* Firefox Fix - * Without that the submit button will be too high. */
80 | .submit::-moz-focus-inner {
81 | border: 0;
82 | }
83 |
--------------------------------------------------------------------------------
/modules/css/modal.min.css:
--------------------------------------------------------------------------------
1 | .modal_password,.modal_copy{position:fixed;left:0;top:0;width:100%;height:100%;background-color:rgba(0,0,0,0.5);opacity:0;visibility:hidden;transform:scale(1.1)}.modal-content{font-family:sans-serif;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background-color:white;padding:1rem 3rem;border-radius:.5rem}@media screen and (max-width:600px){.modal-content{width:90%;padding:1rem 1rem}}.close-button_password,.close-button_copy{float:right;width:1.5rem;line-height:1.5rem;text-align:center;cursor:pointer;border-radius:.25rem}.show-modal{opacity:1;visibility:visible;transform:scale(1.0)}.input,.submit{display:inline-block;padding:10px 15px;margin-top:10px;font-size:10px;border-radius:0;-webkit-appearance:none}.input{border:1px solid lightgray}#allowReadOnlyView{margin-left:0;margin-top:5px}.submit{color:#fff;background-color:#337ab7;border-color:#2e6da4;border:1px solid transparent}.submit::-moz-focus-inner{border:0}
--------------------------------------------------------------------------------
/modules/header.php:
--------------------------------------------------------------------------------
1 | if (typeof showRemovePassword === 'function') {showRemovePassword();}".PHP_EOL; // showRemovePassword if defined (in modal.js)
41 | if ($allowReadOnlyView == '1') {
42 | echo "".PHP_EOL;
43 | } // check allowReadOnlyView if set in the header
44 | }
45 |
46 | if (!isset($_SESSION)) {
47 | session_start();
48 | }
49 |
50 | if ($allowReadOnlyView == '1' and basename($_SERVER['PHP_SELF']) == 'view.php') { /* viewing the page in readonly is ok from the view.php is ok so don't prompt for password */
51 | } else {
52 | // if readonly view is not allowed and the calling page is not view.php then prompt for the password
53 | require_once 'modules/protect.php';
54 | Protect\with('modules/protect_form.php', '', $passwordhash, $allowReadOnlyView);
55 | }
56 | }
57 | }
58 | return $headerFound;
59 | }
60 |
61 | function setHeader($allow_password)
62 | {
63 | // Add header data to the first line of the file - this will not be shown on the note
64 | if (!empty($_POST['notepwd'])) {
65 | $passwordhash = password_hash($_POST['notepwd'], PASSWORD_DEFAULT);
66 | } else {
67 | $passwordhash = '';
68 | }
69 | if (!empty($_POST['allowReadOnlyView'])) {
70 | $allowReadOnlyView = $_POST['allowReadOnlyView'];
71 | } else {
72 | $allowReadOnlyView = 0;
73 | }
74 | $scope = current_url();
75 | $session_key = 'password_protect_'.preg_replace('/\W+/', '_', $scope);
76 | if (!isset($_SESSION)) {
77 | session_start();
78 | }
79 | // if the password and allowReadOnlyView hasn't been set from the form fields then get it from the session values
80 | // this solves the issue of not having the password on the page after it has been set
81 | if (isset($_SESSION[$session_key])) {
82 | if ($passwordhash == '' && $_SESSION[$session_key]) {
83 | $passwordhash=$_SESSION[$session_key.'hash'];
84 | }
85 | if (!empty($_POST['allowReadOnlyView']) == '' && $_SESSION[$session_key]) {
86 | $allowReadOnlyView=$_SESSION[$session_key.'allowReadOnlyView'];
87 | }
88 | }
89 | $noteHash = base64_encode($_GET['note']); // could also use rtrim(strtr(base64_encode($_GET['note']), '+/', '-_'), '='); to remove the = chars used for padding
90 | $header = "[header] " . "¬eName=" . $_GET['note'] . "¬eHash=" . $noteHash; // create the basic header content, really just an identifier
91 | $pwd = "";
92 | if ($allow_password) {
93 | $pwd = "&password=" . $passwordhash; //. "&pwd=" . (isset($_POST['notepwd']) ? $_POST['notepwd'] : '');
94 | $_SESSION[$session_key] = true;
95 | $_SESSION[$session_key.'hash'] = $passwordhash;
96 | // logic for allowing readonly view of note without password
97 | $pwd = $pwd . "&allowReadOnlyView=" . $allowReadOnlyView;
98 | $_SESSION[$session_key.'allowReadOnlyView'] = $allowReadOnlyView;
99 | // TODO: if the page is simple then rely on session setting
100 | } // create the password string for the header
101 | if (!empty($_POST['removePassword'])) {
102 | if ($_POST['removePassword'] == "1") {
103 | $pwd="";
104 | unset($_SESSION[$session_key]);
105 | unset($_SESSION[$session_key.'hash']);
106 | unset($_SESSION[$session_key.'allowReadOnlyView']);
107 | } //remove the password
108 | }
109 | $header = $header . $pwd . "\n"; //add the password string to the header
110 | // check if anything has been added to the header (password or other)
111 | if (trim($header) == $header) {
112 | // if nothing has been added then no header is needed so set it to empty
113 | $header = "";
114 | }
115 | return ($header);
116 | }
117 |
118 | function stripFirstLine($text)
119 | {
120 | // from http://stackoverflow.com/questions/7740405/php-delete-the-first-line-of-a-text-and-return-the-rest
121 | return substr($text, strpos($text, "\n")+1); //using \n instead of PHP_EOL as better compatibility moving files between Linux and Windows
122 | }
123 |
--------------------------------------------------------------------------------
/modules/js/copy.js:
--------------------------------------------------------------------------------
1 | function copyToClipboard(elementId) {
2 | //https://jsfiddle.net/alvaroAV/a2pt16yq/
3 |
4 | // Create an auxiliary hidden input
5 | var aux = document.createElement("textarea");
6 |
7 | // Get the text from the element passed into the input
8 | if (elementId == 'copyURL') {
9 | aux.value = window.location.href; //get the url not the content
10 | }
11 | else if (elementId == 'copyURLViewOnly') {
12 | aux.value = window.location.href + '?view'; //get the view only url not the content
13 | }
14 | else {
15 | aux.value = document.getElementById(elementId).innerHTML;
16 | }
17 |
18 | // Append the aux input to the body
19 | document.body.appendChild(aux);
20 |
21 | // Highlight the content
22 | aux.select();
23 |
24 | // Execute the copy command
25 | document.execCommand("copy");
26 |
27 | // Remove the input from the body
28 | document.body.removeChild(aux);
29 |
30 | document.getElementById("copyMessage").innerHTML = "
Copied";
31 | }
32 |
--------------------------------------------------------------------------------
/modules/js/copy.min.js:
--------------------------------------------------------------------------------
1 | function copyToClipboard(b){var a=document.createElement("textarea");if(b=="copyURL"){a.value=window.location.href}else{if(b=="copyURLViewOnly"){a.value=window.location.href+"?view"}else{a.value=document.getElementById(b).innerHTML}}document.body.appendChild(a);a.select();document.execCommand("copy");document.body.removeChild(a);document.getElementById("copyMessage").innerHTML="
Copied"};
--------------------------------------------------------------------------------
/modules/js/lastsaved.js:
--------------------------------------------------------------------------------
1 | function lastUpdated(responseText) {
2 | // called when a note is saved
3 | var now = new Date();
4 | var saved = '';
5 | saved += ('0' + now.getHours()).slice(-2) + ':' + ('0' + now.getMinutes()).slice(-2) + ':' + ('0' + now.getSeconds()).slice(-2);
6 | var selector = document.getElementById('savedStatus');
7 | selector.setAttribute('datetime', now.getTime());
8 | //update the status so the user can see it has been saved
9 | document.getElementById("savedStatus").innerHTML = lastText() + saved;
10 | if (responseText.search("error") !== -1 && responseText.search("saved") > 0) {
11 | selector.setAttribute('datetime', '');
12 | document.getElementById("savedStatus").innerHTML = responseText;
13 | }
14 | }
15 |
16 | function lastSaved() {
17 | // Update how long ago it was saved (comment out next 2 lines if do not want a status that is dynamic (showing how long ago it was last saved)
18 | // this will fire if there is no change to the file - basically just a clock
19 | var lastSave = document.getElementById('savedStatus').getAttribute("datetime");
20 | if (lastSave) {
21 | var result = lastSave;
22 | if (isNaN(lastSave)) {
23 | var myDate = new Date(lastSave);
24 | result = myDate.getTime();
25 | }
26 | var savedStatus = lastText() + ago(result) + ' ago';
27 | //update the saved status if it has changed
28 | if (savedStatus != document.getElementById("savedStatus").innerHTML) document.getElementById("savedStatus").innerHTML = savedStatus;
29 | }
30 | }
31 |
32 | function lastText() {
33 | var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
34 | var lastSavedText = "Last saved: ";
35 | if (w < 600) {
36 | lastSavedText = "Saved: ";
37 | }
38 | return lastSavedText;
39 | }
40 |
--------------------------------------------------------------------------------
/modules/js/lastsaved.min.js:
--------------------------------------------------------------------------------
1 | function lastUpdated(d){var b=new Date();var c="";c+=("0"+b.getHours()).slice(-2)+":"+("0"+b.getMinutes()).slice(-2)+":"+("0"+b.getSeconds()).slice(-2);var a=document.getElementById("savedStatus");a.setAttribute("datetime",b.getTime());document.getElementById("savedStatus").innerHTML=lastText()+c;if(d.search("error")!==-1&&d.search("saved")>0){a.setAttribute("datetime","");document.getElementById("savedStatus").innerHTML=d}}function lastSaved(){var c=document.getElementById("savedStatus").getAttribute("datetime");if(c){var a=c;if(isNaN(c)){var b=new Date(c);a=b.getTime()}var d=lastText()+ago(a)+" ago";if(d!=document.getElementById("savedStatus").innerHTML){document.getElementById("savedStatus").innerHTML=d}}}function lastText(){var a=Math.max(document.documentElement.clientWidth,window.innerWidth||0);var b="Last saved: ";if(a<600){b="Saved: "}return b};
--------------------------------------------------------------------------------
/modules/js/menu.js:
--------------------------------------------------------------------------------
1 | // based on https://www.w3schools.com/howto/howto_js_bottom_nav_responsive.asp
2 | function navbarResponsive() {
3 | var x = document.getElementById("navbar");
4 | if (x.className === "navbar") {
5 | x.className += " responsive";
6 | } else {
7 | x.className = "navbar";
8 | }
9 | }
10 |
11 | var menuButton = document.getElementById("menuButton");
12 |
13 | function windowOnClick_navbar(event) {
14 | // hide responsive menu if displayed by clicking outside of it
15 | if (event.target.id !== "menuButton") {
16 | var el = document.getElementById('navbar');
17 | if (el.className.indexOf('responsive') > -1) {
18 | el.className = 'navbar';
19 | }
20 | }
21 | }
22 |
23 | window.addEventListener("click", windowOnClick_navbar);
24 |
25 | function downloadFile() {
26 | var link = document.createElement("a");
27 | var content = document.getElementById('content').value;
28 | link.href = "data:application/txt," + encodeURIComponent(content)
29 | link.download = "note_" + document.title + ".txt";
30 | link.dispatchEvent(new MouseEvent('click', {
31 | bubbles: true,
32 | cancelable: true,
33 | view: window
34 | }));
35 | // a [save as] dialog will be shown
36 | //window.open("data:application/txt," + encodeURIComponent(content), "_self");
37 | }
38 |
39 | function toggleMonospace(lnk_obj) {
40 | var x = document.getElementById("content");
41 | lnk_obj.innerHTML = (lnk_obj.innerHTML == '放大字体') ? '缩小字体' : '放大字体';
42 | if (x.style.fontFamily == "monospace") {
43 | x.style.fontFamily = "sans-serif";
44 | } else {
45 | x.style.fontFamily = "monospace";
46 | }
47 | }
48 |
49 | function deleteFile() {
50 | var r = confirm("你确定要删除这个便签吗?");
51 | if (r == true) {
52 | document.getElementById('content').value = '';
53 | uploadContent();
54 | alert('便签已删除');
55 | // Note has been deleted so open a new note (going back to the same note, not a new note, looks confusing)
56 | var url = window.location.href;
57 | window.location.href = url.substring(0, url.lastIndexOf('/'));
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/modules/js/menu.min.js:
--------------------------------------------------------------------------------
1 | // based on https://www.w3schools.com/howto/howto_js_bottom_nav_responsive.asp
2 | function navbarResponsive() {
3 | var x = document.getElementById("navbar");
4 | if (x.className === "navbar") {
5 | x.className += " responsive";
6 | } else {
7 | x.className = "navbar";
8 | }
9 | }
10 |
11 | var menuButton = document.getElementById("menuButton");
12 |
13 | function windowOnClick_navbar(event) {
14 | // hide responsive menu if displayed by clicking outside of it
15 | if (event.target.id !== "menuButton") {
16 | var el = document.getElementById('navbar');
17 | if (el.className.indexOf('responsive') > -1) {
18 | el.className = 'navbar';
19 | }
20 | }
21 | }
22 |
23 | window.addEventListener("click", windowOnClick_navbar);
24 |
25 | function downloadFile() {
26 | var link = document.createElement("a");
27 | var content = document.getElementById('content').value;
28 | link.href = "data:application/txt," + encodeURIComponent(content)
29 | link.download = "note_" + document.title + ".txt";
30 | link.dispatchEvent(new MouseEvent('click', {
31 | bubbles: true,
32 | cancelable: true,
33 | view: window
34 | }));
35 | // a [save as] dialog will be shown
36 | //window.open("data:application/txt," + encodeURIComponent(content), "_self");
37 | }
38 |
39 | function toggleMonospace(lnk_obj) {
40 | var x = document.getElementById("content");
41 | lnk_obj.innerHTML = (lnk_obj.innerHTML == '放大字体') ? '缩小字体' : '放大字体';
42 | if (x.style.fontFamily == "monospace") {
43 | x.style.fontFamily = "sans-serif";
44 | } else {
45 | x.style.fontFamily = "monospace";
46 | }
47 | }
48 |
49 | function deleteFile() {
50 | var r = confirm("你确定要删除这个便签吗?");
51 | if (r == true) {
52 | document.getElementById('content').value = '';
53 | uploadContent();
54 | alert('便签已删除');
55 | // Note has been deleted so open a new note (going back to the same note, not a new note, looks confusing)
56 | var url = window.location.href;
57 | window.location.href = url.substring(0, url.lastIndexOf('/'));
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/modules/js/modal.js:
--------------------------------------------------------------------------------
1 | //make sure the querySelector code is run *after* the page content loads
2 | // based on https://sabe.io/tutorials/how-to-create-modal-popup-box
3 | var modal_password = document.querySelector(".modal_password");
4 | var modal_copy = document.querySelector(".modal_copy");
5 | var closeButton_password = document.querySelector(".close-button_password");
6 | var closeButton_copy = document.querySelector(".close-button_copy");
7 |
8 | function toggleModal_Password() {
9 | //todo: add parameter for which modal to just a single function?
10 | inputboxLocation.innerHTML = ""
11 | modal_password.classList.toggle("show-modal");
12 | document.getElementById("notepwd").focus();
13 | }
14 |
15 | function toggleModal_Copy() {
16 | //todo: add parameter for which modal?
17 | document.getElementById("copyMessage").innerHTML = "
";
18 | modal_copy.classList.toggle("show-modal");
19 | }
20 |
21 | function windowOnClick_Modal(event) {
22 | // modal window windows if clicking outside of them
23 | if (event.target === modal_password) {
24 | toggleModal_Password();
25 | }
26 | if (event.target === modal_copy) {
27 | toggleModal_Copy();
28 | }
29 | }
30 |
31 | if (closeButton_password) closeButton_password.addEventListener("click", toggleModal_Password);
32 | if (closeButton_copy) closeButton_copy.addEventListener("click", toggleModal_Copy);
33 | window.addEventListener("click", windowOnClick_Modal);
34 |
35 | function showRemovePassword() {
36 | el = document.getElementById("removePassword");
37 | el.style.display = (el.style.display == "none") ? "inline" : "none";
38 | }
39 |
40 | function checkallowReadOnlyView() {
41 | el = document.getElementById('allowReadOnlyView');
42 | el.checked = true;
43 | }
44 |
45 | function removePassword() {
46 | inputboxLocation.innerHTML = ""
47 | el = document.getElementById("overlay");
48 | el.style.visibility = (el.style.visibility == "visible") ? "hidden" : "visible";
49 | document.getElementById("notepwd").focus();
50 | }
51 |
52 | function isValid(str) {
53 | return str.replace(/^\s+/g, '').length; // boolean ('true' if field is empty)
54 | }
55 |
--------------------------------------------------------------------------------
/modules/js/modal.min.js:
--------------------------------------------------------------------------------
1 | var modal_password=document.querySelector(".modal_password");var modal_copy=document.querySelector(".modal_copy");var closeButton_password=document.querySelector(".close-button_password");var closeButton_copy=document.querySelector(".close-button_copy");function toggleModal_Password(){inputboxLocation.innerHTML="";modal_password.classList.toggle("show-modal");document.getElementById("notepwd").focus()}function toggleModal_Copy(){document.getElementById("copyMessage").innerHTML="
";modal_copy.classList.toggle("show-modal")}function windowOnClick_Modal(a){if(a.target===modal_password){toggleModal_Password()}if(a.target===modal_copy){toggleModal_Copy()}}if(closeButton_password){closeButton_password.addEventListener("click",toggleModal_Password)}if(closeButton_copy){closeButton_copy.addEventListener("click",toggleModal_Copy)}window.addEventListener("click",windowOnClick_Modal);function showRemovePassword(){el=document.getElementById("removePassword");el.style.display=(el.style.display=="none")?"inline":"none"}function checkallowReadOnlyView(){el=document.getElementById("allowReadOnlyView");el.checked=true}function removePassword(){inputboxLocation.innerHTML="";el=document.getElementById("overlay");el.style.visibility=(el.style.visibility=="visible")?"hidden":"visible";document.getElementById("notepwd").focus()}function isValid(a){return a.replace(/^\s+/g,"").length};
--------------------------------------------------------------------------------
/modules/js/password.js:
--------------------------------------------------------------------------------
1 | function passwordRequest_Add(requestToSend) {
2 | var notepwd = (document.getElementById("notepwd")) ? document.getElementById("notepwd").value : '';
3 | if (!isEmpty(notepwd)) {
4 | requestToSend = requestToSend + '¬epwd=' + encodeURIComponent(notepwd);
5 | }
6 | if ( document.getElementById("allowReadOnlyView").checked ) {
7 | requestToSend = requestToSend + '&allowReadOnlyView=1';
8 | }
9 | return requestToSend;
10 | }
11 |
12 | function passwordRequest_Remove(requestToSend) {
13 | var removePassword = (document.getElementById("hdnRemovePassword")) ? document.getElementById("hdnRemovePassword").value : '';
14 | if (!isEmpty(removePassword)) {
15 | requestToSend = requestToSend + '&removePassword=' + encodeURIComponent(removePassword);
16 | }
17 | return requestToSend;
18 | }
19 |
20 | function metadataGet(requestToSend) {
21 | if (!isEmpty(notepwd)) {
22 | requestToSend = requestToSend + '&metadataGet=1';
23 | }
24 | return requestToSend;
25 | }
26 |
27 | function isEmpty(value) {
28 | return (value == null || value.length === 0);
29 | }
30 |
31 | function passwordRemove() {
32 | document.getElementById("hdnRemovePassword").value = "1";
33 | uploadContent(true);
34 | toggleModal_Password();
35 | document.getElementById("hdnRemovePassword").value = "";
36 | showRemovePassword();
37 | }
38 |
39 | function submitPassword() {
40 | if (isValid(notepwd.value)) {
41 | uploadContent(true);
42 | pwdMessage.innerHTML = "";
43 | showRemovePassword();
44 | toggleModal_Password();
45 | } else {
46 | pwdMessage.innerHTML = "Please enter a password
";
47 | }
48 | }
49 |
50 | // https://www.w3schools.com/howto/howto_js_trigger_button_enter.asp
51 | var passwordInput = document.getElementById("notepwd");
52 | // Execute a function when the user releases a key on the keyboard
53 | if (passwordInput) {
54 | passwordInput.addEventListener("keyup", function(event) {
55 | event.preventDefault(); // Cancel the default action, if needed
56 | if (event.keyCode === 13) { // Number 13 is the "Enter" key on the keyboard
57 | document.getElementById("submitpwd").click(); // Trigger the button element with a click
58 | }
59 | }); }
60 |
--------------------------------------------------------------------------------
/modules/js/password.min.js:
--------------------------------------------------------------------------------
1 | function passwordRequest_Add(a){var b=(document.getElementById("notepwd"))?document.getElementById("notepwd").value:"";if(!isEmpty(b)){a=a+"¬epwd="+encodeURIComponent(b)}if(document.getElementById("allowReadOnlyView").checked){a=a+"&allowReadOnlyView=1"}return a}function passwordRequest_Remove(b){var a=(document.getElementById("hdnRemovePassword"))?document.getElementById("hdnRemovePassword").value:"";if(!isEmpty(a)){b=b+"&removePassword="+encodeURIComponent(a)}return b}function metadataGet(a){if(!isEmpty(notepwd)){a=a+"&metadataGet=1"}return a}function isEmpty(a){return(a==null||a.length===0)}function passwordRemove(){document.getElementById("hdnRemovePassword").value="1";uploadContent(true);toggleModal_Password();document.getElementById("hdnRemovePassword").value="";showRemovePassword()}function submitPassword(){if(isValid(notepwd.value)){uploadContent(true);pwdMessage.innerHTML="";showRemovePassword();toggleModal_Password()}else{pwdMessage.innerHTML="Please enter a password
"}}var passwordInput=document.getElementById("notepwd");if(passwordInput){passwordInput.addEventListener("keyup",function(a){a.preventDefault();if(a.keyCode===13){document.getElementById("submitpwd").click()}})};
--------------------------------------------------------------------------------
/modules/js/tinyago.js:
--------------------------------------------------------------------------------
1 | function ago(val) {
2 | // https://github.com/odyniec/tinyAgo-js
3 | // val is datetime in milliseconds
4 | val = 0 | (Date.now() - val) / 1000;
5 | var unit, length = {
6 | second: 60,
7 | minute: 60,
8 | hour: 24,
9 | day: 7,
10 | week: 4.35,
11 | month: 12,
12 | year: 10000
13 | },
14 | result;
15 |
16 | for (unit in length) {
17 | result = val % length[unit];
18 | if (!(val = 0 | val / length[unit]))
19 | return result + ' ' + (result - 1 ? unit + 's' : unit);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/modules/js/tinyago.min.js:
--------------------------------------------------------------------------------
1 | function ago(d){d=0|(Date.now()-d)/1000;var c,b={second:60,minute:60,hour:24,day:7,week:4.35,month:12,year:10000},a;for(c in b){a=d%b[c];if(!(d=0|d/b[c])){return a+" "+(a-1?c+"s":c)}}};
--------------------------------------------------------------------------------
/modules/js/view.js:
--------------------------------------------------------------------------------
1 | function linkify(inputText) {
2 | // from https://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links
3 | var replacedText, replacePattern1, replacePattern2, replacePattern3;
4 |
5 | //URLs starting with http://, https://, or ftp://
6 | replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
7 | replacedText = inputText.replace(replacePattern1, '$1');
8 |
9 | //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
10 | replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
11 | replacedText = replacedText.replace(replacePattern2, '$1$2');
12 |
13 | //Change email addresses to mailto:: links.
14 | replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
15 | replacedText = replacedText.replace(replacePattern3, '$1');
16 |
17 | return replacedText;
18 | }
19 |
20 | function CreateViewable(noBorder) {
21 | var newNode = document.createElement("div"); // Create the new node to insert
22 | newNode.id = "contentWithLinks"; // give it an id attribute called 'newSpan'
23 | var referenceNode = document.getElementById("content"); // Get the reference node
24 | referenceNode.parentNode.insertBefore(newNode, referenceNode); // Insert the new node before the reference node
25 | document.getElementById("contentWithLinks").innerHTML = linkify(document.getElementById("printable").innerHTML).replace(/\r\n|\r|\n/g, "
");
26 |
27 | //added for IE9 compatibility
28 | //https://www.w3schools.com/howto/howto_js_add_class.asp
29 | var element, name, arr;
30 | element = document.getElementById("contentWithLinks");
31 | name = "content wordwrap";
32 | arr = element.className.split(" ");
33 | if (arr.indexOf(name) == -1) {
34 | element.className += " " + name;
35 | }
36 | if (noBorder) element.style.border='none';
37 | }
38 |
39 | function toggleView(lnk_obj) {
40 | var x = document.getElementById("content");
41 | lnk_obj.innerHTML = (lnk_obj.innerHTML == 'view') ? 'edit' : 'view';
42 | if (x.style.display === "none") {
43 | x.style.display = "block";
44 | var element = document.getElementById("contentWithLinks");
45 | element.parentNode.removeChild(element);
46 | } else {
47 | x.style.display = "none";
48 | CreateViewable();
49 | }
50 | }
51 |
52 | function viewOnly() {
53 | //no textarea available with the view option so show the links enabled view
54 | var x = document.getElementById("content");
55 | x.style.display = "none";
56 | CreateViewable(true);
57 | }
58 |
59 | // Go back to Edit (from View with links) by pressing the Esc key
60 | document.onkeydown = function(evt) {
61 | evt = evt || window.event;
62 | if (evt.keyCode == 27) {
63 | if (document.getElementById("password_modal").className == 'modal_password show-modal') {
64 | toggleModal_Password();
65 | return;
66 | }
67 | if (document.getElementById("content").style.display == "none") {
68 | toggleView(document.getElementById("a_view"));
69 | }
70 | }
71 | };
72 |
--------------------------------------------------------------------------------
/modules/js/view.min.js:
--------------------------------------------------------------------------------
1 | function linkify(e) {
2 | var b, d, c, a;
3 | d = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
4 | b = e.replace(d, '$1');
5 | c = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
6 | b = b.replace(c, '$1$2');
7 | a = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
8 | b = b.replace(a, '$1');
9 | return b;
10 | }
11 | function CreateViewable(f) {
12 | var e = document.createElement("div");
13 | e.id = "contentWithLinks";
14 | var b = document.getElementById("content");
15 | b.parentNode.insertBefore(e, b);
16 | document.getElementById("contentWithLinks").innerHTML = linkify(
17 | document.getElementById("printable").innerHTML
18 | ).replace(/\r\n|\r|\n/g, "
");
19 | var d, c, a;
20 | d = document.getElementById("contentWithLinks");
21 | c = "content wordwrap";
22 | a = d.className.split(" ");
23 | if (a.indexOf(c) == -1) {
24 | d.className += " " + c;
25 | }
26 | if (f) {
27 | d.style.border = "none";
28 | }
29 | }
30 | function toggleView(b) {
31 | var a = document.getElementById("content");
32 | b.innerHTML = b.innerHTML == "查看便签" ? "编辑便签" : "查看便签";
33 | if (a.style.display === "none") {
34 | a.style.display = "block";
35 | var c = document.getElementById("contentWithLinks");
36 | c.parentNode.removeChild(c);
37 | } else {
38 | a.style.display = "none";
39 | CreateViewable();
40 | }
41 | }
42 | function viewOnly() {
43 | var a = document.getElementById("content");
44 | a.style.display = "none";
45 | CreateViewable(true);
46 | }
47 | document.onkeydown = function (a) {
48 | a = a || window.event;
49 | if (a.keyCode == 27) {
50 | if (
51 | document.getElementById("password_modal").className ==
52 | "modal_password show-modal"
53 | ) {
54 | toggleModal_Password();
55 | return;
56 | }
57 | if (document.getElementById("content").style.display == "none") {
58 | toggleView(document.getElementById("a_view"));
59 | }
60 | }
61 | };
62 |
--------------------------------------------------------------------------------
/modules/lastsaved.php:
--------------------------------------------------------------------------------
1 |
2 | ">
5 |
6 |
7 |
--------------------------------------------------------------------------------
/modules/menu.php:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
29 |
30 | ".PHP_EOL; ?>
31 |
--------------------------------------------------------------------------------
/modules/password.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
×
5 |
此便签的密码
6 |
7 |
无密码查看
8 |
9 |
移除密码
10 |
11 |
12 |
13 |
密码保护详细信息
14 |
15 |
16 |
--------------------------------------------------------------------------------
/modules/protect.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
62 |
63 |
64 |
65 |
79 |
80 |