A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1import {hasClosestByClassName} from "../util/hasClosest";
2import {getRandom, isMobile} from "../../util/functions";
3import {hideElements} from "../ui/hideElements";
4import {uploadFiles} from "../upload";
5import {fetchPost} from "../../util/fetch";
6import {getRandomEmoji, openEmojiPanel, unicode2Emoji, updateFileTreeEmoji, updateOutlineEmoji} from "../../emoji";
7import {upDownHint} from "../../util/upDownHint";
8/// #if !MOBILE
9import {openGlobalSearch} from "../../search/util";
10/// #else
11import {popSearch} from "../../mobile/menu/search";
12/// #endif
13import {getEventName} from "../util/compatibility";
14import {Dialog} from "../../dialog";
15import {Constants} from "../../constants";
16import {assetMenu} from "../../menus/protyle";
17import {previewImages} from "../preview/image";
18import {Menu} from "../../plugin/Menu";
19import {escapeHtml} from "../../util/escape";
20
21const bgs = [
22 "background:radial-gradient(black 3px, transparent 4px),radial-gradient(black 3px, transparent 4px),linear-gradient(#fff 4px, transparent 0),linear-gradient(45deg, transparent 74px, transparent 75px, #a4a4a4 75px, #a4a4a4 76px, transparent 77px, transparent 109px),linear-gradient(-45deg, transparent 75px, transparent 76px, #a4a4a4 76px, #a4a4a4 77px, transparent 78px, transparent 109px),#fff;background-size: 109px 109px, 109px 109px,100% 6px, 109px 109px, 109px 109px;background-position: 54px 55px, 0px 0px, 0px 0px, 0px 0px, 0px 0px;",
23 "background: linear-gradient(45deg, #dca 12%, transparent 0, transparent 88%, #dca 0),linear-gradient(135deg, transparent 37%, #a85 0, #a85 63%, transparent 0),linear-gradient(45deg, transparent 37%, #dca 0, #dca 63%, transparent 0) #753;background-size: 25px 25px;",
24 "background: linear-gradient(315deg, transparent 75%, #d45d55 0)-10px 0, linear-gradient(45deg, transparent 75%, #d45d55 0)-10px 0, linear-gradient(135deg, #a7332b 50%, transparent 0) 0 0, linear-gradient(45deg, #6a201b 50%, #561a16 0) 0 0 #561a16;background-size: 20px 20px;",
25 "background: linear-gradient(#ffffff 50%, rgba(255,255,255,0) 0) 0 0, radial-gradient(circle closest-side, #FFFFFF 53%, rgba(255,255,255,0) 0) 0 0, radial-gradient(circle closest-side, #FFFFFF 50%, rgba(255,255,255,0) 0) 55px 0 #48B;background-size: 110px 200px;background-repeat: repeat-x;",
26 "background:radial-gradient(circle farthest-side at 0% 50%,#fb1 23.5%,rgba(240,166,17,0) 0)21px 30px, radial-gradient(circle farthest-side at 0% 50%,#B71 24%,rgba(240,166,17,0) 0)19px 30px, linear-gradient(#fb1 14%,rgba(240,166,17,0) 0, rgba(240,166,17,0) 85%,#fb1 0)0 0, linear-gradient(150deg,#fb1 24%,#B71 0,#B71 26%,rgba(240,166,17,0) 0,rgba(240,166,17,0) 74%,#B71 0,#B71 76%,#fb1 0)0 0, linear-gradient(30deg,#fb1 24%,#B71 0,#B71 26%,rgba(240,166,17,0) 0,rgba(240,166,17,0) 74%,#B71 0,#B71 76%,#fb1 0)0 0, linear-gradient(90deg,#B71 2%,#fb1 0,#fb1 98%,#B71 0%)0 0 #fb1;background-size: 40px 60px;",
27 "background-color: gray;background-image: linear-gradient(transparent 50%, rgba(255,255,255,.5) 50%);background-size: 50px 50px;",
28 "background-color: gray;background-image: linear-gradient(90deg, transparent 50%, rgba(255,255,255,.5) 50%);background-size: 50px 50px;",
29 "background-color: #026873;background-image: linear-gradient(90deg, rgba(255,255,255,.07) 50%, transparent 50%),linear-gradient(90deg, rgba(255,255,255,.13) 50%, transparent 50%),linear-gradient(90deg, transparent 50%, rgba(255,255,255,.17) 50%),linear-gradient(90deg, transparent 50%, rgba(255,255,255,.19) 50%);background-size: 13px, 29px, 37px, 53px;",
30 "background-color: gray;background-image: repeating-linear-gradient(45deg, transparent, transparent 35px, rgba(255,255,255,.5) 35px, rgba(255,255,255,.5) 70px);",
31 "background-color:white;background-image: linear-gradient(90deg, rgba(200,0,0,.5) 50%, transparent 50%),linear-gradient(rgba(200,0,0,.5) 50%, transparent 50%);background-size:50px 50px;",
32 "background-color:#269;background-image: linear-gradient(white 2px, transparent 2px),linear-gradient(90deg, white 2px, transparent 2px),linear-gradient(rgba(255,255,255,.3) 1px, transparent 1px),linear-gradient(90deg, rgba(255,255,255,.3) 1px, transparent 1px);background-size: 100px 100px, 100px 100px, 20px 20px, 20px 20px;background-position:-2px -2px, -2px -2px, -1px -1px, -1px -1px;",
33 "background-color: #fff;background-image:linear-gradient(90deg, transparent 79px, #abced4 79px, #abced4 81px, transparent 81px),linear-gradient(#eee .1em, transparent .1em);background-size: 100% 1.2em;",
34 "background-color: hsl(34, 53%, 82%);background-image: repeating-linear-gradient(45deg, transparent 5px, hsla(197, 62%, 11%, 0.5) 5px, hsla(197, 62%, 11%, 0.5) 10px, hsla(5, 53%, 63%, 0) 10px, hsla(5, 53%, 63%, 0) 35px, hsla(5, 53%, 63%, 0.5) 35px, hsla(5, 53%, 63%, 0.5) 40px, hsla(197, 62%, 11%, 0.5) 40px, hsla(197, 62%, 11%, 0.5) 50px, hsla(197, 62%, 11%, 0) 50px, hsla(197, 62%, 11%, 0) 60px, hsla(5, 53%, 63%, 0.5) 60px, hsla(5, 53%, 63%, 0.5) 70px, hsla(35, 91%, 65%, 0.5) 70px, hsla(35, 91%, 65%, 0.5) 80px, hsla(35, 91%, 65%, 0) 80px, hsla(35, 91%, 65%, 0) 90px, hsla(5, 53%, 63%, 0.5) 90px, hsla(5, 53%, 63%, 0.5) 110px, hsla(5, 53%, 63%, 0) 110px, hsla(5, 53%, 63%, 0) 120px, hsla(197, 62%, 11%, 0.5) 120px, hsla(197, 62%, 11%, 0.5) 140px),repeating-linear-gradient(135deg, transparent 5px, hsla(197, 62%, 11%, 0.5) 5px, hsla(197, 62%, 11%, 0.5) 10px, hsla(5, 53%, 63%, 0) 10px, hsla(5, 53%, 63%, 0) 35px, hsla(5, 53%, 63%, 0.5) 35px, hsla(5, 53%, 63%, 0.5) 40px, hsla(197, 62%, 11%, 0.5) 40px, hsla(197, 62%, 11%, 0.5) 50px, hsla(197, 62%, 11%, 0) 50px, hsla(197, 62%, 11%, 0) 60px, hsla(5, 53%, 63%, 0.5) 60px, hsla(5, 53%, 63%, 0.5) 70px, hsla(35, 91%, 65%, 0.5) 70px, hsla(35, 91%, 65%, 0.5) 80px, hsla(35, 91%, 65%, 0) 80px, hsla(35, 91%, 65%, 0) 90px, hsla(5, 53%, 63%, 0.5) 90px, hsla(5, 53%, 63%, 0.5) 110px, hsla(5, 53%, 63%, 0) 110px, hsla(5, 53%, 63%, 0) 140px, hsla(197, 62%, 11%, 0.5) 140px, hsla(197, 62%, 11%, 0.5) 160px);",
35 "background-color: hsl(2, 57%, 40%);background-image: repeating-linear-gradient(transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(270deg, transparent, transparent 50px, rgba(0,0,0,.4) 50px, rgba(0,0,0,.4) 53px, transparent 53px, transparent 63px, rgba(0,0,0,.4) 63px, rgba(0,0,0,.4) 66px, transparent 66px, transparent 116px, rgba(0,0,0,.5) 116px, rgba(0,0,0,.5) 166px, rgba(255,255,255,.2) 166px, rgba(255,255,255,.2) 169px, rgba(0,0,0,.5) 169px, rgba(0,0,0,.5) 179px, rgba(255,255,255,.2) 179px, rgba(255,255,255,.2) 182px, rgba(0,0,0,.5) 182px, rgba(0,0,0,.5) 232px, transparent 232px),repeating-linear-gradient(125deg, transparent, transparent 2px, rgba(0,0,0,.2) 2px, rgba(0,0,0,.2) 3px, transparent 3px, transparent 5px, rgba(0,0,0,.2) 5px);",
36 "background-color: #eee;background-image: linear-gradient(45deg, black 25%, transparent 25%, transparent 75%, black 75%, black),linear-gradient(-45deg, black 25%, transparent 25%, transparent 75%, black 75%, black);background-size: 60px 60px;",
37 "background-color: #eee;background-image: linear-gradient(45deg, black 25%, transparent 25%, transparent 75%, black 75%, black),linear-gradient(45deg, black 25%, transparent 25%, transparent 75%, black 75%, black);background-size: 60px 60px;background-position: 0 0, 30px 30px;",
38 "background:linear-gradient(-45deg, white 25%, transparent 25%, transparent 75%, black 75%, black) 0 0, linear-gradient(-45deg, black 25%, transparent 25%, transparent 75%, white 75%, white) 1em 1em, linear-gradient(45deg, black 17%, transparent 17%, transparent 25%, black 25%, black 36%, transparent 36%, transparent 64%, black 64%, black 75%, transparent 75%, transparent 83%, black 83%) 1em 1em;background-color: white;background-size: 2em 2em;",
39 "background-color:#001;background-image: radial-gradient(white 15%, transparent 16%),radial-gradient(white 15%, transparent 16%);background-size: 60px 60px;background-position: 0 0, 30px 30px;",
40 "background-color:#556;background-image: linear-gradient(30deg, #445 12%, transparent 12.5%, transparent 87%, #445 87.5%, #445),linear-gradient(150deg, #445 12%, transparent 12.5%, transparent 87%, #445 87.5%, #445),linear-gradient(30deg, #445 12%, transparent 12.5%, transparent 87%, #445 87.5%, #445),linear-gradient(150deg, #445 12%, transparent 12.5%, transparent 87%, #445 87.5%, #445),linear-gradient(60deg, #99a 25%, transparent 25.5%, transparent 75%, #99a 75%, #99a),linear-gradient(60deg, #99a 25%, transparent 25.5%, transparent 75%, #99a 75%, #99a);background-size:80px 140px;background-position: 0 0, 0 0, 40px 70px, 40px 70px, 0 0, 40px 70px;",
41 "background-color:silver;background-image:radial-gradient(circle at 100% 150%, silver 24%, white 24%, white 28%, silver 28%, silver 36%, white 36%, white 40%, transparent 40%, transparent),radial-gradient(circle at 0 150%, silver 24%, white 24%, white 28%, silver 28%, silver 36%, white 36%, white 40%, transparent 40%, transparent),radial-gradient(circle at 50% 100%, white 10%, silver 10%, silver 23%, white 23%, white 30%, silver 30%, silver 43%, white 43%, white 50%, silver 50%, silver 63%, white 63%, white 71%, transparent 71%, transparent),radial-gradient(circle at 100% 50%, white 5%, silver 5%, silver 15%, white 15%, white 20%, silver 20%, silver 29%, white 29%, white 34%, silver 34%, silver 44%, white 44%, white 49%, transparent 49%, transparent),radial-gradient(circle at 0 50%, white 5%, silver 5%, silver 15%, white 15%, white 20%, silver 20%, silver 29%, white 29%, white 34%, silver 34%, silver 44%, white 44%, white 49%, transparent 49%, transparent);background-size: 100px 50px;",
42 "background-color: silver;background-image: linear-gradient(335deg, #b00 23px, transparent 23px),linear-gradient(155deg, #d00 23px, transparent 23px),linear-gradient(335deg, #b00 23px, transparent 23px),linear-gradient(155deg, #d00 23px, transparent 23px);background-size: 58px 58px;background-position: 0px 2px, 4px 35px, 29px 31px, 34px 6px;",
43 "background-color:#def;background-image: radial-gradient(closest-side, transparent 98%, rgba(0,0,0,.3) 99%),radial-gradient(closest-side, transparent 98%, rgba(0,0,0,.3) 99%);background-size:80px 80px;background-position:0 0, 40px 40px;",
44 "background-image:radial-gradient(closest-side, transparent 0%, transparent 75%, #B6CC66 76%, #B6CC66 85%, #EDFFDB 86%, #EDFFDB 94%, #FFFFFF 95%, #FFFFFF 103%, #D9E6A7 104%, #D9E6A7 112%, #798B3C 113%, #798B3C 121%, #FFFFFF 122%, #FFFFFF 130%, #E0EAD7 131%, #E0EAD7 140%),radial-gradient(closest-side, transparent 0%, transparent 75%, #B6CC66 76%, #B6CC66 85%, #EDFFDB 86%, #EDFFDB 94%, #FFFFFF 95%, #FFFFFF 103%, #D9E6A7 104%, #D9E6A7 112%, #798B3C 113%, #798B3C 121%, #FFFFFF 122%, #FFFFFF 130%, #E0EAD7 131%, #E0EAD7 140%);background-size: 110px 110px;background-color: #C8D3A7;background-position: 0 0, 55px 55px;",
45 "background:linear-gradient(324deg, #232927 4%, transparent 4%) -70px 43px, linear-gradient( 36deg, #232927 4%, transparent 4%) 30px 43px, linear-gradient( 72deg, #e3d7bf 8.5%, transparent 8.5%) 30px 43px, linear-gradient(288deg, #e3d7bf 8.5%, transparent 8.5%) -70px 43px, linear-gradient(216deg, #e3d7bf 7.5%, transparent 7.5%) -70px 23px, linear-gradient(144deg, #e3d7bf 7.5%, transparent 7.5%) 30px 23px, linear-gradient(324deg, #232927 4%, transparent 4%) -20px 93px, linear-gradient( 36deg, #232927 4%, transparent 4%) 80px 93px, linear-gradient( 72deg, #e3d7bf 8.5%, transparent 8.5%) 80px 93px, linear-gradient(288deg, #e3d7bf 8.5%, transparent 8.5%) -20px 93px, linear-gradient(216deg, #e3d7bf 7.5%, transparent 7.5%) -20px 73px, linear-gradient(144deg, #e3d7bf 7.5%, transparent 7.5%) 80px 73px;background-color: #232927;background-size: 100px 100px;",
46 "background:radial-gradient(circle at 50% 59%, #D2CAAB 3%, #364E27 4%, #364E27 11%, rgba(54,78,39,0) 12%, rgba(54,78,39,0)) 50px 0, radial-gradient(circle at 50% 41%, #364E27 3%, #D2CAAB 4%, #D2CAAB 11%, rgba(210,202,171,0) 12%, rgba(210,202,171,0)) 50px 0, radial-gradient(circle at 50% 59%, #D2CAAB 3%, #364E27 4%, #364E27 11%, rgba(54,78,39,0) 12%, rgba(54,78,39,0)) 0 50px, radial-gradient(circle at 50% 41%, #364E27 3%, #D2CAAB 4%, #D2CAAB 11%, rgba(210,202,171,0) 12%, rgba(210,202,171,0)) 0 50px, radial-gradient(circle at 100% 50%, #D2CAAB 16%, rgba(210,202,171,0) 17%),radial-gradient(circle at 0% 50%, #364E27 16%, rgba(54,78,39,0) 17%),radial-gradient(circle at 100% 50%, #D2CAAB 16%, rgba(210,202,171,0) 17%) 50px 50px, radial-gradient(circle at 0% 50%, #364E27 16%, rgba(54,78,39,0) 17%) 50px 50px;background-color:#63773F;background-size:100px 100px;",
47 "background:radial-gradient(circle, transparent 20%, slategray 20%, slategray 80%, transparent 80%, transparent),radial-gradient(circle, transparent 20%, slategray 20%, slategray 80%, transparent 80%, transparent) 50px 50px, linear-gradient(#A8B1BB 8px, transparent 8px) 0 -4px, linear-gradient(90deg, #A8B1BB 8px, transparent 8px) -4px 0;background-color: slategray;background-size:100px 100px, 100px 100px, 50px 50px, 50px 50px;",
48 "background:radial-gradient(circle at 100% 50%, transparent 20%, rgba(255,255,255,.3) 21%, rgba(255,255,255,.3) 34%, transparent 35%, transparent),radial-gradient(circle at 0% 50%, transparent 20%, rgba(255,255,255,.3) 21%, rgba(255,255,255,.3) 34%, transparent 35%, transparent) 0 -50px;background-color: slategray;background-size:75px 100px;",
49 "background-color: #FF7D9D;background-size: 58px 58px;background-position: 0px 2px, 4px 35px, 29px 31px, 33px 6px, 0px 36px, 4px 2px, 29px 6px, 33px 30px;background-image:linear-gradient(335deg, #C90032 23px, transparent 23px),linear-gradient(155deg, #C90032 23px, transparent 23px),linear-gradient(335deg, #C90032 23px, transparent 23px),linear-gradient(155deg, #C90032 23px, transparent 23px),linear-gradient(335deg, #C90032 10px, transparent 10px),linear-gradient(155deg, #C90032 10px, transparent 10px),linear-gradient(335deg, #C90032 10px, transparent 10px),linear-gradient(155deg, #C90032 10px, transparent 10px);",
50 "background-color: #6d695c;background-image:repeating-linear-gradient(120deg, rgba(255,255,255,.1), rgba(255,255,255,.1) 1px, transparent 1px, transparent 60px),repeating-linear-gradient(60deg, rgba(255,255,255,.1), rgba(255,255,255,.1) 1px, transparent 1px, transparent 60px),linear-gradient(60deg, rgba(0,0,0,.1) 25%, transparent 25%, transparent 75%, rgba(0,0,0,.1) 75%, rgba(0,0,0,.1)),linear-gradient(120deg, rgba(0,0,0,.1) 25%, transparent 25%, transparent 75%, rgba(0,0,0,.1) 75%, rgba(0,0,0,.1));background-size: 70px 120px;",
51 "background:radial-gradient(circle closest-side at 60% 43%, #b03 26%, rgba(187,0,51,0) 27%),radial-gradient(circle closest-side at 40% 43%, #b03 26%, rgba(187,0,51,0) 27%),radial-gradient(circle closest-side at 40% 22%, #d35 45%, rgba(221,51,85,0) 46%),radial-gradient(circle closest-side at 60% 22%, #d35 45%, rgba(221,51,85,0) 46%),radial-gradient(circle closest-side at 50% 35%, #d35 30%, rgba(221,51,85,0) 31%),radial-gradient(circle closest-side at 60% 43%, #b03 26%, rgba(187,0,51,0) 27%) 50px 50px, radial-gradient(circle closest-side at 40% 43%, #b03 26%, rgba(187,0,51,0) 27%) 50px 50px, radial-gradient(circle closest-side at 40% 22%, #d35 45%, rgba(221,51,85,0) 46%) 50px 50px, radial-gradient(circle closest-side at 60% 22%, #d35 45%, rgba(221,51,85,0) 46%) 50px 50px, radial-gradient(circle closest-side at 50% 35%, #d35 30%, rgba(221,51,85,0) 31%) 50px 50px;background-color:#b03;background-size:100px 100px;",
52 "background:radial-gradient(black 15%, transparent 16%) 0 0, radial-gradient(black 15%, transparent 16%) 8px 8px, radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 0 1px, radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 8px 9px;background-color:#282828;background-size:16px 16px;",
53 "background:linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px, linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0px, linear-gradient(27deg, #222 5px, transparent 5px) 0px 10px, linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px, linear-gradient(90deg, #1b1b1b 10px, transparent 10px),linear-gradient(#1d1d1d 25%, #1a1a1a 25%, #1a1a1a 50%, transparent 50%, transparent 75%, #242424 75%, #242424);background-color: #131313;background-size: 20px 20px;",
54 "background:radial-gradient(rgba(255,255,255,0) 0, rgba(255,255,255,.15) 30%, rgba(255,255,255,.3) 32%, rgba(255,255,255,0) 33%) 0 0, radial-gradient(rgba(255,255,255,0) 0, rgba(255,255,255,.1) 11%, rgba(255,255,255,.3) 13%, rgba(255,255,255,0) 14%) 0 0, radial-gradient(rgba(255,255,255,0) 0, rgba(255,255,255,.2) 17%, rgba(255,255,255,.43) 19%, rgba(255,255,255,0) 20%) 0 110px, radial-gradient(rgba(255,255,255,0) 0, rgba(255,255,255,.2) 11%, rgba(255,255,255,.4) 13%, rgba(255,255,255,0) 14%) -130px -170px, radial-gradient(rgba(255,255,255,0) 0, rgba(255,255,255,.2) 11%, rgba(255,255,255,.4) 13%, rgba(255,255,255,0) 14%) 130px 370px, radial-gradient(rgba(255,255,255,0) 0, rgba(255,255,255,.1) 11%, rgba(255,255,255,.2) 13%, rgba(255,255,255,0) 14%) 0 0, linear-gradient(45deg, #343702 0%, #184500 20%, #187546 30%, #006782 40%, #0b1284 50%, #760ea1 60%, #83096e 70%, #840b2a 80%, #b13e12 90%, #e27412 100%);background-size: 470px 470px, 970px 970px, 410px 410px, 610px 610px, 530px 530px, 730px 730px, 100% 100%;background-color: #840b2a;",
55 "background-color:white;background-image:radial-gradient(midnightblue 9px, transparent 10px),repeating-radial-gradient(midnightblue 0, midnightblue 4px, transparent 5px, transparent 20px, midnightblue 21px, midnightblue 25px, transparent 26px, transparent 50px);background-size: 30px 30px, 90px 90px;background-position: 0 0;",
56 "background-color:black;background-image:radial-gradient(white, rgba(255,255,255,.2) 2px, transparent 40px),radial-gradient(white, rgba(255,255,255,.15) 1px, transparent 30px),radial-gradient(white, rgba(255,255,255,.1) 2px, transparent 40px),radial-gradient(rgba(255,255,255,.4), rgba(255,255,255,.1) 2px, transparent 30px);background-size: 550px 550px, 350px 350px, 250px 250px, 150px 150px;background-position: 0 0, 40px 60px, 130px 270px, 70px 100px;",
57 "background:radial-gradient(hsl(0, 100%, 27%) 4%, hsl(0, 100%, 18%) 9%, hsla(0, 100%, 20%, 0) 9%) 0 0, radial-gradient(hsl(0, 100%, 27%) 4%, hsl(0, 100%, 18%) 8%, hsla(0, 100%, 20%, 0) 10%) 50px 50px, radial-gradient(hsla(0, 100%, 30%, 0.8) 20%, hsla(0, 100%, 20%, 0)) 50px 0, radial-gradient(hsla(0, 100%, 30%, 0.8) 20%, hsla(0, 100%, 20%, 0)) 0 50px, radial-gradient(hsla(0, 100%, 20%, 1) 35%, hsla(0, 100%, 20%, 0) 60%) 50px 0, radial-gradient(hsla(0, 100%, 20%, 1) 35%, hsla(0, 100%, 20%, 0) 60%) 100px 50px, radial-gradient(hsla(0, 100%, 15%, 0.7), hsla(0, 100%, 20%, 0)) 0 0, radial-gradient(hsla(0, 100%, 15%, 0.7), hsla(0, 100%, 20%, 0)) 50px 50px, linear-gradient(45deg, hsla(0, 100%, 20%, 0) 49%, hsla(0, 100%, 0%, 1) 50%, hsla(0, 100%, 20%, 0) 70%) 0 0, linear-gradient(-45deg, hsla(0, 100%, 20%, 0) 49%, hsla(0, 100%, 0%, 1) 50%, hsla(0, 100%, 20%, 0) 70%) 0 0;background-color: #300;background-size: 100px 100px;",
58 "background:linear-gradient(135deg, #708090 21px, #d9ecff 22px, #d9ecff 24px, transparent 24px, transparent 67px, #d9ecff 67px, #d9ecff 69px, transparent 69px),linear-gradient(225deg, #708090 21px, #d9ecff 22px, #d9ecff 24px, transparent 24px, transparent 67px, #d9ecff 67px, #d9ecff 69px, transparent 69px)0 64px;background-color:#708090;background-size: 64px 128px;",
59 "background:linear-gradient(135deg, #ECEDDC 25%, transparent 25%) -50px 0, linear-gradient(225deg, #ECEDDC 25%, transparent 25%) -50px 0, linear-gradient(315deg, #ECEDDC 25%, transparent 25%),linear-gradient(45deg, #ECEDDC 25%, transparent 25%);background-size: 100px 100px;background-color: #EC173A;",
60 "background:linear-gradient(45deg, #92baac 45px, transparent 45px)64px 64px, linear-gradient(45deg, #92baac 45px, transparent 45px,transparent 91px, #e1ebbd 91px, #e1ebbd 135px, transparent 135px),linear-gradient(-45deg, #92baac 23px, transparent 23px, transparent 68px,#92baac 68px,#92baac 113px,transparent 113px,transparent 158px,#92baac 158px);background-color:#e1ebbd;background-size: 128px 128px;",
61 "background:linear-gradient(63deg, #999 23%, transparent 23%) 7px 0,linear-gradient(63deg, transparent 74%, #999 78%),linear-gradient(63deg, transparent 34%, #999 38%, #999 58%, transparent 62%),#444;background-size: 16px 48px;",
62 "background:#36c;background:linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 0 0,linear-gradient(115deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,linear-gradient(245deg, transparent 75%, rgba(255,255,255,.8) 75%) 7px -15px,#36c;background-size: 15px 30px;",
63 "background:radial-gradient(circle at 0% 50%, rgba(96, 16, 48, 0) 9px, #613 10px, rgba(96, 16, 48, 0) 11px) 0px 10px,radial-gradient(at 100% 100%,rgba(96, 16, 48, 0) 9px, #613 10px, rgba(96, 16, 48, 0) 11px),#8a3;background-size: 20px 20px;",
64 "background-image:linear-gradient(to top, #a18cd1 0%, #fbc2eb 100%)",
65 "background-image:linear-gradient(to top, #fbc2eb 0%, #a6c1ee 100%)",
66 "background-image:linear-gradient(120deg, #a6c0fe 0%, #f68084 100%)",
67 "background-image:linear-gradient(120deg, #e0c3fc 0%, #8ec5fc 100%)",
68 "background-image:linear-gradient(to right, #fa709a 0%, #fee140 100%)",
69 "background-image:linear-gradient(to top, #30cfd0 0%, #330867 100%)",
70 "background-image:linear-gradient(to top, #a8edea 0%, #fed6e3 100%)",
71 "background-image:linear-gradient(to top, #d299c2 0%, #fef9d7 100%)",
72 "background-image:linear-gradient(to top, #fddb92 0%, #d1fdff 100%)",
73 "background-image:linear-gradient(to top, #9890e3 0%, #b1f4cf 100%)",
74 "background-image:linear-gradient(to top, #96fbc4 0%, #f9f586 100%)",
75 "background-image:linear-gradient(to right, #eea2a2 0%, #bbc1bf 19%, #57c6e1 42%, #b49fda 79%, #7ac5d8 100%)",
76 "background-image:linear-gradient(to top, #9795f0 0%, #fbc8d4 100%)",
77 "background-image:linear-gradient(to top, #3f51b1 0%, #5a55ae 13%, #7b5fac 25%, #8f6aae 38%, #a86aa4 50%, #cc6b8e 62%, #f18271 75%, #f3a469 87%, #f7c978 100%)",
78 "background-image:linear-gradient(to top, #f43b47 0%, #453a94 100%)",
79 "background-image:linear-gradient(to top, #88d3ce 0%, #6e45e2 100%)",
80 "background-image:linear-gradient(to top, #d9afd9 0%, #97d9e1 100%)",
81 "background-image:linear-gradient(-20deg, #b721ff 0%, #21d4fd 100%)",
82 "background-image:linear-gradient(60deg, #abecd6 0%, #fbed96 100%)",
83 "background-image:linear-gradient(to top, #3b41c5 0%, #a981bb 49%, #ffc8a9 100%)",
84 "background-image:linear-gradient(to top, #0fd850 0%, #f9f047 100%)",
85 "background-image:linear-gradient(to top, #d5dee7 0%, #ffafbd 0%, #c9ffbf 100%)",
86 "background-image:linear-gradient(to top, #65bd60 0%, #5ac1a8 25%, #3ec6ed 50%, #b7ddb7 75%, #fef381 100%)",
87 "background-image:linear-gradient(to top, #50cc7f 0%, #f5d100 100%)",
88 "background-image:linear-gradient(to top, #df89b5 0%, #bfd9fe 100%)",
89 "background-image:linear-gradient(to top, #e14fad 0%, #f9d423 100%)",
90 "background-image:linear-gradient(to right, #ec77ab 0%, #7873f5 100%)",
91 "background-image:linear-gradient(-225deg, #2CD8D5 0%, #C5C1FF 56%, #FFBAC3 100%)",
92 "background-image:linear-gradient(-225deg, #5271C4 0%, #B19FFF 48%, #ECA1FE 100%)",
93 "background-image:linear-gradient(-225deg, #FF3CAC 0%, #562B7C 52%, #2B86C5 100%)",
94 "background-image:linear-gradient(-225deg, #69EACB 0%, #EACCF8 48%, #6654F1 100%)",
95 "background-image:linear-gradient(-225deg, #231557 0%, #44107A 29%, #FF1361 67%, #FFF800 100%)"
96];
97
98export class Background {
99 public element: HTMLElement;
100 public ial: IObject;
101 private imgElement: HTMLImageElement;
102 private iconElement: HTMLElement;
103 private actionElements: NodeListOf<Element>;
104 private tagsElement: HTMLElement;
105 private transparentData = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=";
106
107 constructor(protyle: IProtyle) {
108 this.element = document.createElement("div");
109 this.element.className = "protyle-background";
110 this.element.innerHTML = `<div class="protyle-background__img">
111 <img src="${this.transparentData}">
112 <div class="protyle-icons">
113 <span class="protyle-icon protyle-icon--first" style="position: relative;overflow: hidden"><input aria-label="${window.siyuan.languages.upload}" class="ariaLabel b3-form__upload" type="file"><svg><use xlink:href="#iconUpload"></use></svg></span>
114 <span class="protyle-icon ariaLabel" data-type="link" aria-label="${window.siyuan.languages.link}"><svg><use xlink:href="#iconLink"></use></svg></span>
115 <span class="protyle-icon ariaLabel" data-type="asset" aria-label="${window.siyuan.languages.assets}"><svg><use xlink:href="#iconImage"></use></svg></span>
116 <span class="protyle-icon ariaLabel" data-type="show-random" aria-label="${window.siyuan.languages.builtIn}"><svg><use xlink:href="#iconRefresh"></use></svg></span>
117 <span class="protyle-icon ariaLabel fn__none" data-type="position" aria-label="${window.siyuan.languages.dragPosition}"><svg><use xlink:href="#iconMove"></use></svg></span>
118 <span class="protyle-icon protyle-icon--last ariaLabel" data-type="remove" aria-label="${window.siyuan.languages.remove}"><svg><use xlink:href="#iconTrashcan"></use></svg></span>
119 </div>
120 <div class="protyle-icons fn__none"><span class="protyle-icon protyle-icon--text">${window.siyuan.languages.dragPosition}</span></div>
121 <div class="protyle-icons fn__none" style="opacity: .86;">
122 <span class="protyle-icon protyle-icon--first" data-type="cancel">${window.siyuan.languages.cancel}</span>
123 <span class="protyle-icon protyle-icon--last" data-type="confirm">${window.siyuan.languages.confirm}</span>
124 </div>
125</div>
126<div class="protyle-background__ia">
127 <div class="protyle-background__icon" data-menu="true" data-type="open-emoji"></div>
128 <div class="b3-chips b3-chips__doctag fn__none"></div>
129 <div class="protyle-background__action">
130 <button class="b3-button b3-button--cancel" data-menu="true" data-type="tag">
131 <svg><use xlink:href="#iconTags"></use></svg>
132 ${window.siyuan.languages.addTag}
133 </button>
134 <button class="b3-button b3-button--cancel" data-type="icon">
135 <svg><use xlink:href="#iconEmoji"></use></svg>
136 ${window.siyuan.languages.addIcon}
137 </button>
138 <button class="b3-button b3-button--cancel" data-type="random">
139 <svg><use xlink:href="#iconImage"></use></svg>
140 ${window.siyuan.languages.titleBg}
141 </button>
142 </div>
143</div>`;
144 this.tagsElement = this.element.querySelector(".b3-chips") as HTMLElement;
145 this.iconElement = this.element.querySelector(".protyle-background__icon") as HTMLElement;
146 this.imgElement = this.element.querySelector(".protyle-background__img img") as HTMLImageElement;
147 this.actionElements = this.element.querySelectorAll(".protyle-background__action:not(.fn__flex-center) .b3-button");
148
149 this.element.addEventListener("dragover", async (event) => {
150 event.preventDefault();
151 });
152 this.element.addEventListener("drop", async (event: DragEvent & { target: HTMLElement }) => {
153 if (event.dataTransfer.types[0] === "Files" && event.dataTransfer.files[0].type.indexOf("image") !== -1) {
154 uploadFiles(protyle, [event.dataTransfer.files[0]], undefined, (responseText) => {
155 const response = JSON.parse(responseText);
156 const style = `background-image:url("${response.data.succMap[Object.keys(response.data.succMap)[0]]}")`;
157 this.ial["title-img"] = style;
158 this.render(this.ial, protyle.block.rootID);
159 fetchPost("/api/attr/setBlockAttrs", {
160 id: protyle.block.rootID,
161 attrs: {"title-img": style}
162 });
163 });
164 }
165 });
166 this.imgElement.addEventListener("mousedown", (event: MouseEvent & { target: HTMLElement }) => {
167 event.preventDefault();
168 if (!this.element.firstElementChild.querySelector(".protyle-icons").classList.contains("fn__none")) {
169 return;
170 }
171 const y = event.clientY;
172 const documentSelf = document;
173 const height = this.imgElement.naturalHeight * this.imgElement.clientWidth / this.imgElement.naturalWidth - this.imgElement.clientHeight;
174 let originalPositionY = parseFloat(this.imgElement.style.objectPosition.substring(7)) || 50;
175 if (this.imgElement.style.objectPosition.endsWith("px")) {
176 originalPositionY = -parseInt(this.imgElement.style.objectPosition.substring(7)) / height * 100;
177 }
178 documentSelf.onmousemove = (moveEvent: MouseEvent) => {
179 this.imgElement.style.objectPosition = `center ${((y - moveEvent.clientY) / height * 100 + originalPositionY).toFixed(2)}%`;
180 event.preventDefault();
181 };
182
183 documentSelf.onmouseup = () => {
184 documentSelf.onmousemove = null;
185 documentSelf.onmouseup = null;
186 documentSelf.ondragstart = null;
187 documentSelf.onselectstart = null;
188 documentSelf.onselect = null;
189 };
190 });
191 this.element.querySelector("input").addEventListener("change", (event: InputEvent & {
192 target: HTMLInputElement
193 }) => {
194 if (event.target.files.length === 0) {
195 return;
196 }
197 uploadFiles(protyle, event.target.files, event.target, (responseText) => {
198 const response = JSON.parse(responseText);
199 const style = `background-image:url("${response.data.succMap[Object.keys(response.data.succMap)[0]]}")`;
200 this.ial["title-img"] = style;
201 this.render(this.ial, protyle.block.rootID);
202 fetchPost("/api/attr/setBlockAttrs", {
203 id: protyle.block.rootID,
204 attrs: {"title-img": style}
205 });
206 });
207 });
208 this.element.addEventListener(getEventName(), (event) => {
209 let target = event.target as HTMLElement;
210 hideElements(["gutter"], protyle);
211
212 while (target && !target.isEqualNode(this.element)) {
213 const type = target.getAttribute("data-type");
214 if (target.tagName === "IMG" && target.parentElement.classList.contains("protyle-background__img")) {
215 const imgSrc = target.getAttribute("src");
216 if (event.detail > 1 && !imgSrc.startsWith("data:image/png;base64")) {
217 previewImages([imgSrc]);
218 event.preventDefault();
219 event.stopPropagation();
220 }
221 // 点击题头图菜单无法消失
222 window.siyuan.menus.menu.remove();
223 break;
224 } else if (type === "position" && !protyle.disabled) {
225 const iconElements = this.element.firstElementChild.querySelectorAll(".protyle-icons");
226 iconElements[0].classList.add("fn__none");
227 iconElements[1].classList.remove("fn__none");
228 iconElements[2].classList.remove("fn__none");
229 this.imgElement.style.cursor = "move";
230 event.preventDefault();
231 event.stopPropagation();
232 break;
233 } else if (type === "cancel" || type === "confirm") {
234 this.imgElement.style.cursor = "";
235 const iconElements = this.element.firstElementChild.querySelectorAll(".protyle-icons");
236 iconElements[0].classList.remove("fn__none");
237 iconElements[1].classList.add("fn__none");
238 iconElements[2].classList.add("fn__none");
239 if (type === "confirm") {
240 const style = `background-image:url("${this.imgElement.getAttribute("src")}");object-position:${this.imgElement.style.objectPosition}`;
241 this.ial["title-img"] = style;
242 fetchPost("/api/attr/setBlockAttrs", {
243 id: protyle.block.rootID,
244 attrs: {"title-img": style}
245 });
246 } else {
247 this.render(this.ial, protyle.block.rootID);
248 }
249 event.preventDefault();
250 event.stopPropagation();
251 break;
252 } else if (type === "open-emoji" && !protyle.disabled) {
253 const rect = this.iconElement.getBoundingClientRect();
254 openEmojiPanel(protyle.block.rootID, "doc", {
255 x: rect.left,
256 y: rect.bottom,
257 h: rect.height,
258 w: rect.width
259 }, undefined, target.querySelector("img"));
260 event.preventDefault();
261 event.stopPropagation();
262 break;
263 } else if (type === "show-random" && !protyle.disabled) {
264 let html = "";
265 bgs.forEach((item: string, index: number) => {
266 html += `<div data-index="${index}" style="height: 128px;${item}" class="b3-card b3-card--wrap"></div>`;
267 });
268 const dialog = new Dialog({
269 title: window.siyuan.languages.builtIn,
270 content: `<div class="b3-cards">${html}</div>`,
271 width: isMobile() ? "92vw" : "912px",
272 height: isMobile() ? "80vh" : "70vh",
273 });
274 dialog.element.setAttribute("data-key", Constants.DIALOG_BACKGROUNDRANDOM);
275 dialog.element.addEventListener("click", (event) => {
276 const target = event.target as HTMLElement;
277 if (target.classList.contains("b3-card")) {
278 this.ial["title-img"] = bgs[parseInt(target.getAttribute("data-index"))];
279 this.render(this.ial, protyle.block.rootID);
280 fetchPost("/api/attr/setBlockAttrs", {
281 id: protyle.block.rootID,
282 attrs: {"title-img": this.ial["title-img"]}
283 });
284 dialog.destroy();
285 }
286 });
287 event.preventDefault();
288 event.stopPropagation();
289 break;
290 } else if (type === "random" && !protyle.disabled) {
291 this.ial["title-img"] = bgs[getRandom(0, bgs.length - 1)];
292 this.render(this.ial, protyle.block.rootID);
293 fetchPost("/api/attr/setBlockAttrs", {
294 id: protyle.block.rootID,
295 attrs: {"title-img": this.ial["title-img"]}
296 });
297 event.preventDefault();
298 event.stopPropagation();
299 break;
300 } else if (type === "asset" && !protyle.disabled) {
301 const rect = target.getBoundingClientRect();
302 assetMenu(protyle, {
303 x: target.parentElement.getBoundingClientRect().right,
304 y: rect.bottom + 8,
305 isLeft: true,
306 }, (url) => {
307 this.ial["title-img"] = `background-image:url("${url}")`;
308 this.render(this.ial, protyle.block.rootID);
309 fetchPost("/api/attr/setBlockAttrs", {
310 id: protyle.block.rootID,
311 attrs: {"title-img": this.ial["title-img"]}
312 });
313 /// #if MOBILE
314 window.siyuan.menus.menu.remove();
315 /// #endif
316 }, Constants.SIYUAN_ASSETS_IMAGE);
317 event.preventDefault();
318 event.stopPropagation();
319 break;
320 } else if (type === "remove" && !protyle.disabled) {
321 delete this.ial["title-img"];
322 this.render(this.ial, protyle.block.rootID);
323 fetchPost("/api/attr/setBlockAttrs", {
324 id: protyle.block.rootID,
325 attrs: {"title-img": ""}
326 });
327 event.preventDefault();
328 event.stopPropagation();
329 break;
330 } else if (type === "icon" && !protyle.disabled) {
331 const emoji = getRandomEmoji();
332 if (emoji) {
333 updateFileTreeEmoji(emoji, protyle.block.rootID);
334 updateOutlineEmoji(emoji, protyle.block.rootID);
335 fetchPost("/api/attr/setBlockAttrs", {
336 id: protyle.block.rootID,
337 attrs: {"icon": emoji}
338 });
339 if (protyle.model) {
340 protyle.model.parent.setDocIcon(emoji);
341 }
342 this.iconElement.classList.remove("fn__none");
343 const rect = this.iconElement.getBoundingClientRect();
344 openEmojiPanel(protyle.block.rootID, "doc", {
345 x: rect.left,
346 y: rect.bottom,
347 h: rect.height,
348 w: rect.width
349 });
350 }
351 event.preventDefault();
352 event.stopPropagation();
353 break;
354 } else if (type === "tag" && !protyle.disabled) {
355 this.openTag(protyle, target);
356 event.preventDefault();
357 event.stopPropagation();
358 break;
359 } else if (type === "link" && !protyle.disabled) {
360 const dialog = new Dialog({
361 title: window.siyuan.languages.link,
362 width: isMobile() ? "92vw" : "520px",
363 content: `<div class="b3-dialog__content">
364 <input class="b3-text-field fn__block" value="${this.imgElement.src.startsWith("data:") ? "" : this.imgElement.getAttribute("src")}">
365</div>
366<div class="b3-dialog__action">
367 <button class="b3-button b3-button--cancel">${window.siyuan.languages.cancel}</button><div class="fn__space"></div>
368 <button class="b3-button b3-button--text">${window.siyuan.languages.confirm}</button>
369</div>`,
370 });
371 dialog.element.setAttribute("data-key", Constants.DIALOG_BACKGROUNDLINK);
372 const btnsElement = dialog.element.querySelectorAll(".b3-button");
373 btnsElement[0].addEventListener("click", () => {
374 dialog.destroy();
375 });
376 btnsElement[1].addEventListener("click", () => {
377 const style = `background-image:url("${dialog.element.querySelector("input").value}");`;
378 this.ial["title-img"] = style;
379 this.render(this.ial, protyle.block.rootID);
380 fetchPost("/api/attr/setBlockAttrs", {
381 id: protyle.block.rootID,
382 attrs: {"title-img": this.ial["title-img"]}
383 });
384 dialog.destroy();
385 });
386 dialog.element.querySelector("input").focus();
387 event.preventDefault();
388 event.stopPropagation();
389 break;
390 } else if (type === "open-search") {
391 /// #if !MOBILE
392 openGlobalSearch(protyle.app, `#${target.textContent}#`, !window.siyuan.ctrlIsPressed, {method: 0});
393 /// #else
394 popSearch(protyle.app, {
395 hasReplace: false,
396 method: 0,
397 hPath: "",
398 idPath: [],
399 k: `#${target.textContent}#`,
400 r: "",
401 page: 1,
402 });
403 /// #endif
404 event.preventDefault();
405 event.stopPropagation();
406 break;
407 } else if (type === "remove-tag" && !protyle.disabled) {
408 target.parentElement.remove();
409 this.removeTag(protyle);
410 event.preventDefault();
411 event.stopPropagation();
412 break;
413 }
414 target = target.parentElement;
415 }
416 });
417 }
418
419 private removeTag(protyle: IProtyle, cb?: () => void) {
420 const tags = this.getTags();
421 fetchPost("/api/attr/setBlockAttrs", {
422 id: protyle.block.rootID,
423 attrs: {"tags": tags.toString()}
424 }, () => {
425 if (cb) {
426 cb();
427 }
428 });
429 if (tags.length === 0) {
430 delete this.ial.tags;
431 } else {
432 this.ial.tags = tags.toString();
433 }
434 this.render(this.ial, protyle.block.rootID);
435 }
436
437 public render(ial: IObject, rootId: string) {
438 const img = ial["title-img"];
439 const icon = ial.icon;
440 const tags = ial.tags;
441 this.ial = ial;
442 // 为主题提供样式基础
443 this.element.setAttribute("data-node-id", rootId);
444 if (tags) {
445 let html = "";
446 const colors = ["secondary", "primary", "info", "success", "warning", "error", "pink"];
447 Array.from(new Set(tags.split(",").map(item => item.trim()))).forEach((item, index) => {
448 if (!item.replace(/ /g, "")) {
449 return;
450 }
451 html += `<div class="b3-chip b3-chip--middle b3-chip--pointer b3-chip--${colors[index % 7]}" data-type="open-search">${escapeHtml(item)}<svg class="b3-chip__close" data-type="remove-tag"><use xlink:href="#iconCloseRound"></use></svg></div>`;
452 });
453 this.tagsElement.innerHTML = `${html}
454<div class="protyle-background__action fn__flex-center">
455 <button class="b3-button b3-button--cancel" style="margin-bottom: 8px" data-menu="true" data-type="tag"><svg><use xlink:href="#iconAdd"></use></svg>${window.siyuan.languages.addTag}</button>
456</div>`;
457 this.tagsElement.classList.remove("fn__none");
458 this.actionElements[0].classList.add("fn__none");
459 } else {
460 this.tagsElement.classList.add("fn__none");
461 this.actionElements[0].classList.remove("fn__none");
462 }
463
464 if (icon) {
465 this.iconElement.classList.remove("fn__none");
466 this.iconElement.innerHTML = unicode2Emoji(icon);
467 this.actionElements[1].classList.add("fn__none");
468 } else {
469 this.actionElements[1].classList.remove("fn__none");
470 this.iconElement.classList.add("fn__none");
471 }
472
473 if (img) {
474 // 历史数据解析:background-image: url(\"assets/沙发背景墙11-20220418171700-w6vilzt.jpeg\"); background-position: center -254px; background-size: cover; background-repeat: no-repeat; min-height: 30vh
475 this.imgElement.setAttribute("style", Lute.UnEscapeHTMLStr(img));
476 if (img.indexOf("url(") > -1) {
477 const position = this.imgElement.style.backgroundPosition || this.imgElement.style.objectPosition;
478 const url = this.imgElement.style.backgroundImage?.replace(/^url\(["']?/, "").replace(/["']?\)$/, "");
479 this.imgElement.removeAttribute("style");
480 this.imgElement.setAttribute("src", url);
481 this.imgElement.style.objectPosition = position;
482 this.element.querySelector('[data-type="position"]').classList.remove("fn__none");
483 } else {
484 this.imgElement.setAttribute("src", this.transparentData);
485 this.element.querySelector('[data-type="position"]').classList.add("fn__none");
486 }
487 this.actionElements[2].classList.add("fn__none");
488 this.imgElement.parentElement.classList.remove("fn__none");
489 this.iconElement.style.marginTop = "";
490 /// #if MOBILE
491 // 移动端键盘弹起和点击加号需保持滚动高度一致
492 this.imgElement.style.height = "200px";
493 /// #endif
494 } else {
495 this.imgElement.parentElement.classList.add("fn__none");
496 this.actionElements[2].classList.remove("fn__none");
497 this.iconElement.style.marginTop = "8px";
498 }
499
500 if (img || icon) {
501 this.iconElement.parentElement.style.marginTop = "";
502 } else {
503 this.iconElement.parentElement.style.marginTop = "8px";
504 }
505 }
506
507 private openTag(protyle: IProtyle, target: HTMLElement) {
508 window.siyuan.menus.menu.remove();
509 const menu = new Menu();
510 menu.addItem({
511 iconHTML: "",
512 type: "empty",
513 label: `<div class="fn__flex-column b3-menu__filter">
514 <input class="b3-text-field fn__flex-shrink" placeholder="${window.siyuan.languages.tag}"/>
515 <div class="fn__hr"></div>
516 <div class="b3-list fn__flex-1 b3-list--background">
517 <img style="margin: 0 auto;display: block;width: 64px;height: 64px" src="/stage/loading-pure.svg">
518 </div>
519</div>`,
520 bind: (element) => {
521 const listElement = element.querySelector(".b3-list--background");
522 fetchPost("/api/search/searchTag", {
523 k: "",
524 }, (response) => {
525 let html = "";
526 const currentTags = this.getTags();
527 response.data.tags.forEach((item: string, index: number) => {
528 html += `<div class="b3-list-item b3-list-item--narrow${index === 0 ? " b3-list-item--focus" : ""}">
529 <div class="fn__flex-1">${item}</div>
530 ${currentTags.includes(Lute.UnEscapeHTMLStr(item)) ? '<svg class="b3-menu__checked"><use xlink:href="#iconSelect"></use></svg>' : ""}
531</div>`;
532 });
533 listElement.innerHTML = html;
534 });
535 const inputElement = element.querySelector("input");
536 inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
537 event.stopPropagation();
538 if (event.isComposing) {
539 return;
540 }
541 upDownHint(listElement, event);
542 if (event.key === "Enter") {
543 const currentElement = listElement.querySelector(".b3-list-item--focus") as HTMLElement;
544 this.addTags(currentElement ?
545 (currentElement.dataset.type === "new" ? currentElement.querySelector("mark").textContent.trim() : currentElement.textContent.trim()) :
546 inputElement.value.trim(), protyle, () => {
547 inputElement.value = "";
548 inputElement.dispatchEvent(new CustomEvent("input"));
549 });
550 } else if (event.key === "Escape") {
551 window.siyuan.menus.menu.remove();
552 }
553 });
554 inputElement.addEventListener("input", (event) => {
555 event.stopPropagation();
556 fetchPost("/api/search/searchTag", {
557 k: inputElement.value.trim(),
558 }, (response) => {
559 let searchHTML = "";
560 let hasKey = false;
561 const currentTags = this.getTags();
562 response.data.tags.forEach((item: string, index: number) => {
563 searchHTML += `<div class="b3-list-item b3-list-item--narrow${index === 0 ? " b3-list-item--focus" : ""}">
564 <div class="fn__flex-1">${item}</div>
565 ${currentTags.includes(Lute.UnEscapeHTMLStr(item.replace(/<mark>/g, "").replace(/<\/mark>/g, ""))) ? '<svg class="b3-menu__checked"><use xlink:href="#iconSelect"></use></svg>' : ""}
566</div>`;
567 if (item === `<mark>${response.data.k}</mark>`) {
568 hasKey = true;
569 }
570 });
571 if (!hasKey && response.data.k) {
572 searchHTML = `<div data-type="new" class="b3-list-item b3-list-item--narrow${searchHTML ? "" : " b3-list-item--focus"}"><div class="fn__flex-1">${window.siyuan.languages.new} <mark>${escapeHtml(response.data.k)}</mark></div></div>` + searchHTML;
573 }
574 listElement.innerHTML = searchHTML;
575 });
576 });
577 listElement.addEventListener("click", (event) => {
578 const target = event.target as HTMLElement;
579 const listItemElement = hasClosestByClassName(target, "b3-list-item");
580 if (!listItemElement) {
581 return;
582 }
583 this.addTags(listItemElement.dataset.type === "new" ? listItemElement.querySelector("mark").textContent.trim() : listItemElement.textContent.trim(),
584 protyle, () => {
585 inputElement.value = "";
586 inputElement.dispatchEvent(new CustomEvent("input"));
587 inputElement.focus();
588 });
589 });
590 }
591 });
592 const itemsElement = menu.element.querySelector(".b3-menu__items");
593 itemsElement.setAttribute("style", "overflow: initial");
594 /// #if MOBILE
595 menu.fullscreen();
596 itemsElement.firstElementChild.setAttribute("style", "padding: 0 8px;height: 100%;");
597 /// #else
598 const rect = target.getBoundingClientRect();
599 menu.open({x: rect.left, y: rect.top + rect.height});
600 menu.element.querySelector("input").focus();
601 /// #endif
602 }
603
604 private getTags(removeTag?: string) {
605 const tags: string[] = [];
606 this.tagsElement.querySelectorAll(".b3-chip").forEach(item => {
607 const tagText = item.textContent.trim();
608 if (removeTag && tagText === removeTag) {
609 item.remove();
610 }
611 tags.push(tagText);
612 });
613 return tags;
614 }
615
616 private addTags(tag: string, protyle: IProtyle, cb: () => void) {
617 const tags = this.getTags(tag);
618 if (tags.includes(tag)) {
619 this.removeTag(protyle, cb);
620 return;
621 }
622 tags.push(tag);
623 fetchPost("/api/attr/setBlockAttrs", {
624 id: protyle.block.rootID,
625 attrs: {"tags": tags.toString()}
626 }, () => {
627 cb();
628 });
629 this.ial.tags = tags.toString();
630 this.render(this.ial, protyle.block.rootID);
631 }
632}