mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-14 11:05:41 +05:00
Merge branch 'staging' into profile
This commit is contained in:
commit
4fe08f760a
@ -18,7 +18,7 @@ Note that every GitHub release page has an RSS compatible feed that you can subs
|
||||
We do also communicate about this topic on:
|
||||
- [Our blog](https://blog.cryptpad.org)
|
||||
- [Our Matrix public space](https://matrix.to/#/#cryptpad:matrix.xwiki.com)
|
||||
- [Our Mastodon account](https://fosstodon.org/@cryptpad)
|
||||
- [Our Mastodon account](https://social.xwiki.com/@CryptPad)
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
<head>
|
||||
<title data-localization="main_title">CryptPad: Collaboration suite, encrypted and open-source</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/png" href="/customize/favicon/main-favicon.png" id="favicon"/>
|
||||
<script src="/customize/pre-loading.js?ver=1.1"></script>
|
||||
<link href="/customize/src/pre-loading.css?ver=1.0" rel="stylesheet" type="text/css">
|
||||
|
||||
63
customize.dist/images/forum.svg
Normal file
63
customize.dist/images/forum.svg
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 -256 1850 1850"
|
||||
id="svg3013"
|
||||
version="1.1"
|
||||
inkscape:version="1.4.1 (93de688d07, 2025-03-30)"
|
||||
width="100%"
|
||||
height="100%"
|
||||
sodipodi:docname="forum.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata3023">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3021" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1403"
|
||||
id="namedview3019"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.26081081"
|
||||
inkscape:cx="-486.943"
|
||||
inkscape:cy="498.4456"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg3013"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<g
|
||||
transform="matrix(1,0,0,-1,37.966102,1305.4576)"
|
||||
id="g3015"
|
||||
style="fill:#0087ff;fill-opacity:1">
|
||||
<path
|
||||
d="m 1664,896 q 53,0 90.5,-37.5 Q 1792,821 1792,768 1792,715 1754.5,677.5 1717,640 1664,640 V 256 q 0,-52 -38,-90 -38,-38 -90,-38 -417,347 -812,380 -58,-19 -91,-66 -33,-47 -31,-100.5 2,-53.5 40,-92.5 -20,-33 -23,-65.5 -3,-32.5 6,-58 9,-25.5 33.5,-55 Q 683,41 706.5,20.5 730,0 768,-30 739,-88 656.5,-113 574,-138 488,-124.5 402,-111 356,-69 349,-46 326.5,18.5 304,83 294.5,113 q -9.5,30 -23,89 -13.5,59 -15,101 -1.5,42 3.5,98.5 5,56.5 22,110.5 H 160 Q 94,512 47,559 0,606 0,672 v 192 q 0,66 47,113 47,47 113,47 h 480 q 435,0 896,384 52,0 90,-38 38,-38 38,-90 V 896 z M 1536,292 v 954 Q 1142,944 768,903 V 633 q 377,-42 768,-341 z"
|
||||
id="path3017"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#0087ff;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
3
customize.dist/images/forum.svg.license
Normal file
3
customize.dist/images/forum.svg.license
Normal file
@ -0,0 +1,3 @@
|
||||
SPDX-FileCopyrightText: Font Awesome by Dave Gandy
|
||||
|
||||
SPDX-License-Identifier: CC-BY-SA-3.0
|
||||
@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:url(#SVGID_2_);}
|
||||
</style>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="4.7893" y1="12.0669" x2="6.7712" y2="12.0669">
|
||||
<stop offset="0" style="stop-color:#4592C4"/>
|
||||
<stop offset="1" style="stop-color:#545ACD"/>
|
||||
</linearGradient>
|
||||
<polygon class="st0" points="4.8,13 6.4,13 6.8,11.2 5.1,11.2 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="0.4529" y1="12" x2="23.5471" y2="12">
|
||||
<stop offset="0" style="stop-color:#4592C4"/>
|
||||
<stop offset="1" style="stop-color:#545ACD"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M21.6,17.8c0-0.1,0.1-0.1,0.1-0.2c1.2-1.7,1.8-3.8,1.8-6c0-6.2-5.2-11.2-11.5-11.2S0.5,5.4,0.5,11.6
|
||||
c0,6.2,5.2,11.1,11.6,11.1c1.6,0,3.1-0.3,4.5-0.9c0,0,0.1,0,0.1,0c0,0,0,0,0,0c0.2-0.1,0.4-0.1,0.6-0.1c0.2,0,0.5,0,0.7,0.1
|
||||
l4.7,1.7l-1.2-4.9C21.4,18.3,21.4,18.1,21.6,17.8z M9.1,11.2H7.5L7.2,13h1.5v0.7H7L6.6,16H5.8l0.5-2.3H4.7L4.2,16H3.5l0.4-2.3H2.5
|
||||
V13h1.5l0.4-1.8H2.9v-0.7h1.6L5,8.1h0.7l-0.4,2.3h1.6l0.5-2.3h0.7l-0.5,2.3h1.4V11.2z M11.2,16h-0.9v-5.9h0.9V16z M11.1,8.9
|
||||
C11,9,10.9,9.1,10.7,9.1c-0.2,0-0.3,0-0.4-0.1c-0.1-0.1-0.2-0.2-0.2-0.4c0-0.2,0.1-0.4,0.2-0.4c0.1-0.1,0.2-0.1,0.4-0.1
|
||||
c0.1,0,0.3,0,0.4,0.1s0.2,0.2,0.2,0.4S11.2,8.9,11.1,8.9z M16.3,10.9c-0.2-0.1-0.5-0.1-0.6-0.1c-0.5,0-0.9,0.2-1.2,0.6
|
||||
c-0.3,0.4-0.5,0.9-0.5,1.4V16h-0.9v-5.9h0.7l0.1,1.1h0c0.2-0.4,0.5-0.7,0.8-0.9c0.3-0.2,0.6-0.3,1-0.3c0.3,0,0.5,0,0.7,0.1
|
||||
L16.3,10.9z M17.9,15.3c-0.5-0.5-0.7-1.3-0.7-2.2c0-1,0.2-1.7,0.7-2.3s1.2-0.8,2-0.8c0.3,0,0.6,0,0.8,0.1c0.3,0.1,0.5,0.1,0.7,0.2
|
||||
l-0.3,0.8c-0.2-0.1-0.4-0.1-0.6-0.2c-0.2-0.1-0.4-0.1-0.6-0.1c-1.2,0-1.8,0.8-1.8,2.3c0,0.7,0.1,1.3,0.4,1.7s0.7,0.6,1.3,0.6
|
||||
c0.5,0,1-0.1,1.5-0.3v0.8c-0.4,0.2-0.9,0.3-1.5,0.3C19.1,16.1,18.4,15.8,17.9,15.3z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#Shape_2_);}
|
||||
</style>
|
||||
<g id="Octicons_1_">
|
||||
<g id="issue-opened">
|
||||
<linearGradient id="Shape_2_" gradientUnits="userSpaceOnUse" x1="1.1619" y1="12" x2="22.8381" y2="12">
|
||||
<stop offset="0" style="stop-color:#4592C4"/>
|
||||
<stop offset="1" style="stop-color:#545ACD"/>
|
||||
</linearGradient>
|
||||
<path id="Shape_1_" class="st0" d="M12,3.2c4.9,0,8.8,4,8.8,8.8s-4,8.8-8.8,8.8s-8.8-4-8.8-8.8S7.1,3.2,12,3.2L12,3.2z M12,1.2
|
||||
C6,1.2,1.2,6,1.2,12S6,22.8,12,22.8S22.8,18,22.8,12S18,1.2,12,1.2L12,1.2z M13.5,5.8h-3.1v7.7h3.1V5.8L13.5,5.8z M13.5,15.1h-3.1
|
||||
v3.1h3.1V15.1L13.5,15.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 979 B |
@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
@ -1,69 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0.1 (1.0.1+r73)"
|
||||
sodipodi:docname="twiitter.svg"
|
||||
xml:space="preserve"
|
||||
style="enable-background:new 0 0 24 24;"
|
||||
viewBox="0 0 24 24"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="Layer_1"
|
||||
version="1.1"><metadata
|
||||
id="metadata1416"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs1414" /><sodipodi:namedview
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:window-y="10"
|
||||
inkscape:window-x="10"
|
||||
inkscape:cy="14.107333"
|
||||
inkscape:cx="-5.7258526"
|
||||
inkscape:zoom="17.645834"
|
||||
showgrid="false"
|
||||
id="namedview1412"
|
||||
inkscape:window-height="1036"
|
||||
inkscape:window-width="1900"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
inkscape:document-rotation="0" />
|
||||
<style
|
||||
id="style1402"
|
||||
type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
</style>
|
||||
<linearGradient
|
||||
y2="12"
|
||||
x2="23.6009"
|
||||
y1="12"
|
||||
x1="0.3991"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="SVGID_1_">
|
||||
<stop
|
||||
id="stop1404"
|
||||
style="stop-color:#4592C4"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop1406"
|
||||
style="stop-color:#545ACD"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<path
|
||||
style="fill:#0087ff;fill-opacity:1"
|
||||
id="path1409"
|
||||
d="M23.6,4.8c-0.9,0.4-1.8,0.6-2.7,0.8C21.9,5,22.6,4,23,2.9c-0.9,0.5-1.9,0.9-3,1.2c-0.9-0.9-2.1-1.5-3.5-1.5 c-2.6,0-4.8,2.1-4.8,4.8c0,0.4,0,0.7,0.1,1.1c-4-0.2-7.5-2.1-9.8-5C1.6,4.1,1.4,5,1.4,5.8c0,1.7,0.8,3.1,2.1,4 C2.7,9.8,2,9.6,1.3,9.2c0,0,0,0,0,0.1c0,2.3,1.6,4.2,3.8,4.7c-0.4,0.1-0.8,0.2-1.3,0.2c-0.3,0-0.6,0-0.9-0.1 c0.6,1.9,2.4,3.3,4.4,3.3c-1.6,1.3-3.7,2-5.9,2c-0.4,0-0.8,0-1.1-0.1c2.1,1.4,4.6,2.2,7.3,2.2c8.8,0,13.6-7.3,13.6-13.6 c0-0.2,0-0.4,0-0.6C22.2,6.6,23,5.8,23.6,4.8z"
|
||||
class="st0" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@ -1,3 +0,0 @@
|
||||
SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
@ -145,7 +145,11 @@ define(req, function(AppConfig, Default, Language) {
|
||||
Messages.hide_password = "Hide password";
|
||||
Messages.next_templateList = "Next template list";
|
||||
Messages.previous_templateList = "Previous template list";
|
||||
|
||||
Messages.contact_mastodon = 'Mastodon'; // XXX
|
||||
Messages.contact_forum = 'Forum'; // XXX
|
||||
Messages.toolbar_text_tools = "Text tools";
|
||||
Messages.toolbar_show_text_tools = "Show text tools";
|
||||
Messages.toolbar_hide_text_tools = "Hide text tools";
|
||||
Messages.settings_profileLinkLabel = "Edit your profile link";
|
||||
Messages.settings_profileDescLabel = "Edit your profile description";
|
||||
Messages.settings_profileAvatarLabel = "Profile picture";
|
||||
|
||||
@ -19,10 +19,38 @@ define([
|
||||
].indexOf(Config.adminEmail) === -1;
|
||||
var adminMailbox = Config.supportMailbox && LocalStore.isLoggedIn();
|
||||
|
||||
let contacts = [
|
||||
{
|
||||
name: Msg.contact_chat || "Chat",
|
||||
image: "/customize/images/sayhi.svg",
|
||||
href: "https://matrix.to/#/#cryptpad:matrix.xwiki.com",
|
||||
},
|
||||
{
|
||||
name: Msg.contact_mastodon || "Mastodon",
|
||||
image: "/customize/images/mastodon.svg",
|
||||
href: "https://social.xwiki.com/@CryptPad",
|
||||
},
|
||||
{
|
||||
name: Msg.contact_bug || "Bug report",
|
||||
image: "/customize/images/github.svg",
|
||||
href: "https://github.com/cryptpad/cryptpad/issues/",
|
||||
},
|
||||
{
|
||||
name: Msg.contact_forum || "Forum",
|
||||
image: "/customize/images/forum.svg",
|
||||
href: "https://forum.cryptpad.org/",
|
||||
},
|
||||
{
|
||||
name: Msg.contact_email || "Email",
|
||||
image: "/customize/images/email.svg",
|
||||
href: 'mailto:' + developerEmail,
|
||||
},
|
||||
];
|
||||
|
||||
return h('div#cp-main', [
|
||||
Pages.infopageTopbar(),
|
||||
h('div.container.cp-container', [
|
||||
h('div.row.cp-page-title',[
|
||||
h('div.row.cp-page-title', [
|
||||
h('div.col-12.text-center', h('h1', Msg.contact)),
|
||||
]),
|
||||
(adminEmail || adminMailbox) ? h('div.row.cp-iconCont.align-items-center', [
|
||||
@ -64,76 +92,22 @@ define([
|
||||
Pages.setHTML(h('h2.text-center'), Msg.contact_dev),
|
||||
h('p.center', Msg.contact_devHint)
|
||||
),
|
||||
].concat(contacts.map(item =>
|
||||
h('div',
|
||||
h('a.card-small', {href : "https://matrix.to/#/#cryptpad:matrix.xwiki.com"},
|
||||
h('a.card-small', { href: item.href },
|
||||
h('div.card-body',
|
||||
h('p', [
|
||||
h('img', {
|
||||
src: '/customize/images/sayhi.svg',
|
||||
src: item.image,
|
||||
alt: '',
|
||||
'aria-hidden': 'true'
|
||||
}),
|
||||
Msg.contact_chat || 'Chat'
|
||||
item.name
|
||||
])
|
||||
)
|
||||
)
|
||||
),
|
||||
h('div',
|
||||
h('a.card-small', {href : "https://fosstodon.org/@cryptpad"},
|
||||
h('div.card-body',
|
||||
h('p', [
|
||||
h('img', {
|
||||
src: '/customize/images/mastodon.svg',
|
||||
alt: '',
|
||||
'aria-hidden': 'true'
|
||||
}),
|
||||
'Mastodon'
|
||||
])
|
||||
)
|
||||
)
|
||||
),
|
||||
h('div',
|
||||
h('a.card-small', {href : "https://twitter.com/cryptpad"},
|
||||
h('div.card-body',
|
||||
h('p', [
|
||||
// this is not a typo. adblock plus blocks images with src *twitter* apparently
|
||||
h('img', {
|
||||
src: '/customize/images/twiitter.svg',
|
||||
alt: '',
|
||||
'aria-hidden': 'true'}),
|
||||
'Twitter'
|
||||
])
|
||||
)
|
||||
)
|
||||
),
|
||||
h('div',
|
||||
h('a.card-small', {href : "https://github.com/cryptpad/cryptpad/issues/"},
|
||||
h('div.card-body',
|
||||
h('p', [
|
||||
h('img', {
|
||||
src: '/customize/images/github.svg',
|
||||
alt: '',
|
||||
'aria-hidden': 'true'}),
|
||||
Msg.contact_bug || 'Bug report'
|
||||
])
|
||||
)
|
||||
)
|
||||
),
|
||||
h('div',
|
||||
h('a.card-small', {href : "mailto:" + developerEmail},
|
||||
h('div.card-body',
|
||||
h('p', [
|
||||
h('img', {
|
||||
src: '/customize/images/email.svg',
|
||||
alt: '',
|
||||
'aria-hidden': 'true'
|
||||
}),
|
||||
Msg.contact_email || 'Email'
|
||||
])
|
||||
)
|
||||
)
|
||||
),
|
||||
]),
|
||||
)
|
||||
))),
|
||||
]),
|
||||
Pages.infopageFooter(),
|
||||
]);
|
||||
|
||||
@ -138,6 +138,12 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#cp-app-drive-content-container {
|
||||
.cp-splitter {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,7 +499,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* CONTENT */
|
||||
#cp-app-drive-content-container {
|
||||
display: flex;
|
||||
@ -512,6 +518,13 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
touch-action: none;
|
||||
-ms-touch-action: none;
|
||||
-webkit-touch-action: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
&:hover {
|
||||
border-left: 1px solid @cryptpad_text_col;
|
||||
}
|
||||
|
||||
@ -289,3 +289,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
//reusable styling for the markdown toggle button across all apps
|
||||
.markdown-toolbar-button-style() {
|
||||
padding: 3px 5px;
|
||||
height: fit-content;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
border-radius: @variables_radius;
|
||||
display: inline-flex;
|
||||
background-color: @cp_toolbar-bottom-bg;
|
||||
color: @cp_toolbar-bottom-fg;
|
||||
|
||||
&:hover {
|
||||
background-color: fade(@cryptpad_text_col, 20%);
|
||||
border-color: @cryptpad_text_col;
|
||||
color: @cryptpad_text_col;
|
||||
}
|
||||
|
||||
&.cp-toolbar-button-active {
|
||||
background-color: @cp_toolbar-bg;
|
||||
border-color: @cp_toolbar-fg;
|
||||
color: @cp_toolbar-fg;
|
||||
|
||||
&:hover {
|
||||
background-color: fade(@cryptpad_text_col, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -64,7 +64,10 @@
|
||||
}
|
||||
|
||||
.cp-markdown-toolbar {
|
||||
height: @toolbar_line-height;
|
||||
min-height: @toolbar_line-height;
|
||||
padding: 0.1rem 0;
|
||||
height: auto;
|
||||
flex-wrap: wrap;
|
||||
background-color: @cp_toolbar-bg;
|
||||
color: @cp_toolbar-fg;
|
||||
display: none;
|
||||
@ -74,7 +77,10 @@
|
||||
border-radius: @variables_radius;
|
||||
color: @toolbar-color;
|
||||
.toolbar_button;
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
.fa {
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-family: FontAwesome;
|
||||
}
|
||||
&:hover {
|
||||
background-color: contrast(@cp_toolbar-bg, darken(@cp_toolbar-bg, 5%), lighten(@cp_toolbar-bg, 5%));
|
||||
}
|
||||
@ -85,6 +91,11 @@
|
||||
button:nth-of-type(1) {
|
||||
margin-left: 0.3rem;
|
||||
}
|
||||
@media screen and (max-width: @browser_media-medium-screen) {
|
||||
button:nth-of-type(1) {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cp-toolbar-container {
|
||||
@ -400,7 +411,6 @@
|
||||
|
||||
.fa {
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-family: FontAwesome;
|
||||
}
|
||||
|
||||
.tools_unselectable();
|
||||
|
||||
@ -86,4 +86,28 @@ removeBlock.complete = function (Env, body, cb) {
|
||||
Block.removeLoginBlock(Env, publicKey, reason, edPublic, cb);
|
||||
};
|
||||
|
||||
// Get an upload cookie
|
||||
// Get a cookie allowing you to upload to the blobstage of your user
|
||||
const uploadCookie = Commands.UPLOAD_COOKIE = function (Env, body, cb) {
|
||||
const { publicKey } = body;
|
||||
|
||||
// they must provide a valid public key
|
||||
if (publicKey && typeof(publicKey) === "string"
|
||||
&& publicKey.length === 44) {
|
||||
return cb();
|
||||
}
|
||||
|
||||
cb("INVALID_KEY");
|
||||
};
|
||||
|
||||
uploadCookie.complete = function (Env, body, cb) {
|
||||
const { publicKey } = body;
|
||||
|
||||
const safeKey = Util.escapeKeyCharacters(publicKey);
|
||||
Env.blobStore.uploadCookie(safeKey, (err, cookie) => {
|
||||
if (err) { return void cb(err); }
|
||||
cb(void 0, {cookie});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@ Upload.status = function (Env, safeKey, filesize, _cb) { // FIXME FILES
|
||||
};
|
||||
|
||||
Upload.upload = function (Env, safeKey, chunk, cb) {
|
||||
Env.blobStore.upload(safeKey, chunk, cb);
|
||||
Env.blobStore.uploadWs(safeKey, chunk, cb);
|
||||
};
|
||||
|
||||
Upload.cancel = function (Env, safeKey, arg, cb) {
|
||||
|
||||
@ -69,6 +69,7 @@ const NOAUTH = require("./challenge-commands/base.js");
|
||||
COMMANDS.MFA_CHECK = NOAUTH.MFA_CHECK;
|
||||
COMMANDS.WRITE_BLOCK = NOAUTH.WRITE_BLOCK; // Account creation + password change
|
||||
COMMANDS.REMOVE_BLOCK = NOAUTH.REMOVE_BLOCK;
|
||||
COMMANDS.UPLOAD_COOKIE = NOAUTH.UPLOAD_COOKIE;
|
||||
|
||||
const TOTP = require("./challenge-commands/totp.js");
|
||||
COMMANDS.TOTP_SETUP = TOTP.TOTP_SETUP;
|
||||
|
||||
@ -19,6 +19,7 @@ const BlobStore = require("./storage/blob");
|
||||
const BlockStore = require("./storage/block");
|
||||
const plugins = require("./plugin-manager");
|
||||
const gzipStatic = require('connect-gzip-static');
|
||||
const CPCrypto = require('./crypto');
|
||||
|
||||
const DEFAULT_QUERY_TIMEOUT = 5000;
|
||||
const PID = process.pid;
|
||||
@ -26,6 +27,8 @@ const PID = process.pid;
|
||||
let SSOUtils = plugins.SSO && plugins.SSO.utils;
|
||||
|
||||
var Env = JSON.parse(process.env.Env);
|
||||
let blobStore;
|
||||
let cpcrypto;
|
||||
Env.plugins = plugins;
|
||||
const response = Util.response(function (errLabel, info) {
|
||||
if (!Env.Log) { return; }
|
||||
@ -70,6 +73,7 @@ const EVENTS = {};
|
||||
EVENTS.ENV_UPDATE = function (data /*, cb */) {
|
||||
try {
|
||||
Env = JSON.parse(data);
|
||||
Env.blobStore = blobStore;
|
||||
Env.Log = Log;
|
||||
Env.plugins = plugins;
|
||||
Env.sendMessage = sendMessage;
|
||||
@ -263,7 +267,6 @@ app.use('/ssoauth', (req, res, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
app.use('/blob', function (req, res, next) {
|
||||
/* Head requests are used to check the size of a blob.
|
||||
Clients can configure a maximum size to download automatically,
|
||||
@ -774,6 +777,51 @@ app.get('/api/logo', function (req, res) {
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/upload-blob', Express.json({limit:"500kb"}), (req, res) => {
|
||||
const { chunk, sig, edPublic } = req.body;
|
||||
if (!cpcrypto) {
|
||||
return void res.status(500).send({error: 'NOCRYPTO'});
|
||||
}
|
||||
|
||||
const forbidden = reason => {
|
||||
return void res.status(403).send({error: reason});
|
||||
};
|
||||
|
||||
try {
|
||||
// Check signature
|
||||
const sigu8 = Util.decodeBase64(sig);
|
||||
const vkey = Util.decodeBase64(edPublic);
|
||||
const ok = cpcrypto.open(sigu8, vkey);
|
||||
if (!ok) { return forbidden('INVALID_KEY'); }
|
||||
const cookie = Util.encodeUTF8(sigu8.subarray(64));
|
||||
// Check cookie
|
||||
const safeKey = Util.escapeKeyCharacters(edPublic);
|
||||
Env.blobStore.checkUploadCookie(safeKey, value => {
|
||||
if (value !== cookie) {
|
||||
return forbidden('INVALID_COOKIE');
|
||||
}
|
||||
// Upload chunk
|
||||
Env.blobStore.upload(safeKey, chunk, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).send({error: err});
|
||||
}
|
||||
// Get new cookie
|
||||
Env.blobStore.uploadCookie(safeKey, (err, _c) => {
|
||||
if (err) {
|
||||
return res.status(500).send({error: err});
|
||||
}
|
||||
res.status(200).send({
|
||||
cookie: _c
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
return void res.status(500).send({error: e.message});
|
||||
}
|
||||
});
|
||||
|
||||
// This endpoint handles authenticated RPCs over HTTP
|
||||
// via an interactive challenge-response protocol
|
||||
app.use(Express.json());
|
||||
@ -781,6 +829,7 @@ app.post('/api/auth', function (req, res, next) {
|
||||
AuthCommands.handle(Env, req, res, next);
|
||||
});
|
||||
|
||||
|
||||
app.use(function (req, res /*, next */) {
|
||||
if (/^(\/favicon\.ico\/|.*\.js\.map|.*\/translations\/.*\.json)/.test(req.url)) {
|
||||
// ignore common 404s
|
||||
@ -824,7 +873,10 @@ nThen(function (w) {
|
||||
getSession: function () {},
|
||||
}, w(function (err, blob) {
|
||||
if (err) { return; }
|
||||
Env.blobStore = blob;
|
||||
Env.blobStore = blobStore = blob;
|
||||
}));
|
||||
CPCrypto.init(w(function (err, crypto) {
|
||||
cpcrypto = crypto;
|
||||
}));
|
||||
}).nThen(function () {
|
||||
// TODO inform the parent process that this worker is ready
|
||||
|
||||
@ -10,6 +10,8 @@ var BlobStore = module.exports;
|
||||
var nThen = require("nthen");
|
||||
var Semaphore = require("saferphore");
|
||||
var Util = require("../common-util");
|
||||
const Crypto = require('crypto');
|
||||
|
||||
const PERMISSIVE = 511;
|
||||
|
||||
const readFileBin = require("../stream-file").readFileBin;
|
||||
@ -270,15 +272,17 @@ var readBlobMetadata = function (env, blobId, handler, _cb) {
|
||||
|
||||
/********** METHODS **************/
|
||||
|
||||
var upload = function (Env, safeKey, content, cb) {
|
||||
var uploadWs = function (Env, safeKey, content, cb) {
|
||||
var dec;
|
||||
|
||||
try { dec = Buffer.from(content, 'base64'); }
|
||||
catch (e) { return void cb('DECODE_BUFFER'); }
|
||||
|
||||
var len = dec.length;
|
||||
|
||||
var session = Env.getSession(safeKey);
|
||||
|
||||
/*
|
||||
if (typeof(session.currentUploadSize) !== 'number' ||
|
||||
typeof(session.pendingUploadSize) !== 'number') {
|
||||
// improperly initialized... maybe they didn't check before uploading?
|
||||
@ -289,6 +293,7 @@ var upload = function (Env, safeKey, content, cb) {
|
||||
if (session.currentUploadSize > session.pendingUploadSize) {
|
||||
return cb('E_OVER_LIMIT');
|
||||
}
|
||||
*/
|
||||
|
||||
var stagePath = makeStagePath(Env, safeKey);
|
||||
|
||||
@ -300,15 +305,50 @@ var upload = function (Env, safeKey, content, cb) {
|
||||
blobstage.write(dec);
|
||||
session.currentUploadSize += len;
|
||||
cb(void 0, dec.length);
|
||||
//Env.incrementBytesWritten(len);
|
||||
});
|
||||
} else {
|
||||
session.blobstage.write(dec);
|
||||
session.currentUploadSize += len;
|
||||
cb(void 0, dec.length);
|
||||
//Env.incrementBytesWritten(len);
|
||||
}
|
||||
};
|
||||
var upload = function (Env, safeKey, content, cb) {
|
||||
var dec;
|
||||
|
||||
try { dec = Buffer.from(content, 'base64'); }
|
||||
catch (e) { return void cb('DECODE_BUFFER'); }
|
||||
|
||||
var path = makeStagePath(Env, safeKey);
|
||||
Fs.appendFile(path, dec, cb);
|
||||
};
|
||||
const getRandomCookie = function () {
|
||||
return Crypto.randomBytes(16).toString('hex');
|
||||
};
|
||||
var uploadCookie = function (Env, safeKey, cb) {
|
||||
var stagePath = makeStagePath(Env, safeKey);
|
||||
var cookiePath = stagePath + '.cookie';
|
||||
const cookie = getRandomCookie();
|
||||
|
||||
Fse.mkdirp(Path.dirname(cookiePath), PERMISSIVE, function (err) {
|
||||
if (err && err.code !== 'EEXIST') { return void cb(err); }
|
||||
Fs.writeFile(cookiePath, cookie, err => {
|
||||
cb(err, cookie);
|
||||
});
|
||||
});
|
||||
};
|
||||
var checkUploadCookie = function (Env, safeKey, cb) {
|
||||
var stagePath = makeStagePath(Env, safeKey);
|
||||
var cookiePath = stagePath + '.cookie';
|
||||
|
||||
Fs.readFile(cookiePath, function (err, content) {
|
||||
if (err) { return void cb(); }
|
||||
let expireTime = +new Date() - (5*60*1000);
|
||||
Fs.stat(cookiePath, function (err, stats) {
|
||||
if (stats.mtime < expireTime) { return void cb(); }
|
||||
cb(content.toString('utf8'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var closeBlobstage = function (Env, safeKey) {
|
||||
var session = Env.getSession(safeKey);
|
||||
@ -370,6 +410,10 @@ var upload_complete = function (Env, safeKey, id, cb) {
|
||||
// FIXME we could just move and handle the EEXISTS instead of the above block
|
||||
Fse.move(oldPath, newPath, function (e) {
|
||||
if (e) { return void cb('RENAME_ERR'); }
|
||||
|
||||
// clear upload cookie
|
||||
Fs.unlink(oldPath+'.cookie', function () {});
|
||||
|
||||
cb(void 0, id);
|
||||
});
|
||||
});
|
||||
@ -448,6 +492,9 @@ var owned_upload_complete = function (Env, safeKey, id, cb) {
|
||||
// otherwise it worked...
|
||||
}));
|
||||
}).nThen(function () {
|
||||
// clear upload cookie
|
||||
Fs.unlink(oldPath+'.cookie', function () {});
|
||||
|
||||
// clean up their session when you're done
|
||||
// call back with the blob id...
|
||||
cb(void 0, id);
|
||||
@ -734,11 +781,26 @@ BlobStore.create = function (config, _cb) {
|
||||
if (!isValidSafeKey(safeKey)) { return void cb('INVALID_SAFEKEY'); }
|
||||
isFile(makeStagePath(Env, safeKey), cb);
|
||||
},
|
||||
uploadWs: function (safeKey, content, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
if (!isValidSafeKey(safeKey)) { return void cb('INVALID_SAFEKEY'); }
|
||||
uploadWs(Env, safeKey, content, Util.once(Util.mkAsync(cb)));
|
||||
},
|
||||
upload: function (safeKey, content, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
if (!isValidSafeKey(safeKey)) { return void cb('INVALID_SAFEKEY'); }
|
||||
upload(Env, safeKey, content, Util.once(Util.mkAsync(cb)));
|
||||
},
|
||||
uploadCookie: function (safeKey, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
if (!isValidSafeKey(safeKey)) { return void cb('INVALID_SAFEKEY'); }
|
||||
uploadCookie(Env, safeKey, Util.once(Util.mkAsync(cb)));
|
||||
},
|
||||
checkUploadCookie: function (safeKey, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
if (!isValidSafeKey(safeKey)) { return void cb('INVALID_SAFEKEY'); }
|
||||
checkUploadCookie(Env, safeKey, Util.once(Util.mkAsync(cb)));
|
||||
},
|
||||
|
||||
cancel: function (safeKey, fileSize, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
|
||||
3221
package-lock.json
generated
3221
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -80,7 +80,7 @@ More information about this can be found in [our translation guide](/customize.d
|
||||
|
||||
The best places to reach the development team and the community are the [CryptPad Forum](https://forum.cryptpad.org) and the [Matrix chat](https://matrix.to/#/#cryptpad:matrix.xwiki.com)
|
||||
|
||||
The team is also on the fediverse: [@cryptpad@fosstodon.org](https://fosstodon.org/@cryptpad)
|
||||
The team is also on the fediverse: [@cryptpad@xwiki.com](https://social.xwiki.com/@CryptPad)
|
||||
|
||||
# Team
|
||||
|
||||
|
||||
@ -423,7 +423,7 @@ const factory = (Sortify, UserObject, ProxyManager,
|
||||
var initTempRpc = (clientId, cb) => {
|
||||
if (store.rpc) { return void cb(store.rpc); }
|
||||
var kp = Crypto.Nacl.sign.keyPair();
|
||||
var keys = {
|
||||
var keys = store.tempKeys = {
|
||||
edPublic: Util.encodeBase64(kp.publicKey),
|
||||
edPrivate: Util.encodeBase64(kp.secretKey)
|
||||
};
|
||||
@ -2715,6 +2715,10 @@ const factory = (Sortify, UserObject, ProxyManager,
|
||||
if (obj?.error) {
|
||||
Feedback.send("NO_DRIVE_ERROR", true);
|
||||
}
|
||||
if (!!data.neverDrive) {
|
||||
// Send temp RPC keys to the browser to allow upload
|
||||
obj.tempKeys = store?.tempKeys;
|
||||
}
|
||||
cb(obj);
|
||||
}, !!data.neverDrive);
|
||||
}
|
||||
|
||||
@ -578,6 +578,13 @@ define([
|
||||
framework.setCursorGetter(CodeMirror.getCursor);
|
||||
editor.on('cursorActivity', updateCursor);
|
||||
|
||||
editor.setOption("extraKeys", {
|
||||
"Esc": function(cm, event) {
|
||||
event.preventDefault();
|
||||
document.body.focus();
|
||||
}
|
||||
});
|
||||
|
||||
framework.onEditableChange(function () {
|
||||
editor.setOption('readOnly', framework.isLocked() || framework.isReadOnly());
|
||||
});
|
||||
|
||||
@ -1256,6 +1256,10 @@ define([
|
||||
arrow: true,
|
||||
maxWidth: '200px',
|
||||
flip: true,
|
||||
onShow: () => {
|
||||
// Hide other tooltips
|
||||
$('body').find('.tippy-popper').hide();
|
||||
},
|
||||
popperOptions: {
|
||||
modifiers: {
|
||||
preventOverflow: { boundariesElement: 'window' }
|
||||
|
||||
@ -905,7 +905,8 @@ define([
|
||||
case 'toggle':
|
||||
button = $(h('button.cp-toolbar-tools', {
|
||||
//title: data.title || '', // TODO display if the label text is collapsed
|
||||
'aria-label': data.text || Messages.toolbar_tools // Fallback
|
||||
'aria-label': data.text || Messages.toolbar_tools, // Fallback
|
||||
'aria-pressed': false
|
||||
}, [
|
||||
h('i.fa.' + (data.icon || 'fa-wrench')),
|
||||
h('span.cp-toolbar-name', data.text || Messages.toolbar_tools)
|
||||
@ -923,6 +924,7 @@ define([
|
||||
button.click(function (e) {
|
||||
data.element.toggle();
|
||||
var isVisible = data.element.is(':visible');
|
||||
button.attr('aria-pressed', isVisible ? 'true' : 'false');
|
||||
if (callback) { callback(isVisible); }
|
||||
if (isVisible) {
|
||||
button.addClass('cp-toolbar-button-active');
|
||||
@ -1157,20 +1159,40 @@ define([
|
||||
};
|
||||
for (var k in actions) {
|
||||
let $b = $('<button>', {
|
||||
'data-notippy':1,
|
||||
'data-type': k,
|
||||
'class': 'pure-button fa ' + actions[k].icon,
|
||||
title: Messages['mdToolbar_' + k] || k
|
||||
}).click(onClick);
|
||||
'class': 'pure-button cp-markdown-' + k,
|
||||
'title': Messages['mdToolbar_' + k] || k,
|
||||
'aria-label': Messages['mdToolbar_' + k] || k
|
||||
}).append(
|
||||
$('<i>', {
|
||||
'class': 'fa ' + actions[k].icon,
|
||||
'aria-hidden': 'true'
|
||||
})).click(onClick);
|
||||
if (k === "embed") { $toolbar.prepend($b); }
|
||||
else { $toolbar.append($b); }
|
||||
}
|
||||
$('<button>', {
|
||||
'class': 'pure-button fa fa-question cp-markdown-help',
|
||||
title: Messages.mdToolbar_help
|
||||
}).click(function () {
|
||||
'data-notippy':1,
|
||||
'class': 'pure-button cp-markdown-help',
|
||||
'title': Messages.mdToolbar_help,
|
||||
'aria-label': Messages.mdToolbar_help
|
||||
}).append(
|
||||
$('<i>', {
|
||||
'class': 'fa fa-question',
|
||||
'aria-hidden': 'true'
|
||||
})).click(function () {
|
||||
var href = Messages.mdToolbar_tutorial;
|
||||
common.openUnsafeURL(href);
|
||||
}).appendTo($toolbar);
|
||||
|
||||
$toolbar.on('keydown', function (e) {
|
||||
if (e.key === 'Escape' || e.keyCode === 27) {
|
||||
editor.focus();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
return $toolbar;
|
||||
};
|
||||
UIElements.createMarkdownToolbar = function (common, editor, opts) {
|
||||
@ -1229,6 +1251,71 @@ define([
|
||||
$toolbarButton.show();
|
||||
};
|
||||
|
||||
function isSmallScreen() {
|
||||
return window.innerHeight < 530 || window.innerWidth < 530;
|
||||
}
|
||||
|
||||
var toolbarVisibleOnSmallScreen = false;
|
||||
var $toolbarToggleButton = null;
|
||||
var appType = common.getMetadataMgr().getPrivateData().app;
|
||||
|
||||
function updateToolbarVisibility() {
|
||||
var $wrapper = $(opts && opts.wrapper ? opts.wrapper : $toolbar.parent());
|
||||
|
||||
if (isSmallScreen()) {
|
||||
if (!$toolbarToggleButton) {
|
||||
$toolbarToggleButton = $(h('button.btn.cp-markdown-toggle-button', {
|
||||
'aria-label': Messages.toolbar_show_text_tools,
|
||||
'aria-pressed': 'false',
|
||||
'data-notippy': 1,
|
||||
'type': 'button',
|
||||
'title': Messages.toolbar_show_text_tools
|
||||
})).append([
|
||||
h('i.fa.fa-wrench', { 'aria-hidden': 'true' }),
|
||||
h('span.cp-toolbar-label', {}, Messages.toolbar_text_tools)
|
||||
]).click(function () {
|
||||
var isExpanded = $toolbar.is(':visible');
|
||||
$toolbar.toggle();
|
||||
$(this).toggleClass('cp-toolbar-button-active', !isExpanded)
|
||||
.attr('aria-pressed', String(!isExpanded))
|
||||
.attr('title', !isExpanded ? Messages.toolbar_hide_text_tools : Messages.toolbar_show_text_tools)
|
||||
.attr('aria-label', !isExpanded ? Messages.toolbar_hide_text_tools : Messages.toolbar_show_text_tools);
|
||||
toolbarVisibleOnSmallScreen = !isExpanded;
|
||||
}).on('keydown keyup', e => {
|
||||
// don't close modals when pressing Enter
|
||||
// on the button
|
||||
e.stopPropagation();
|
||||
});
|
||||
$wrapper.append($toolbarToggleButton);
|
||||
}
|
||||
|
||||
if (toolbarVisibleOnSmallScreen) {
|
||||
$toolbar.show();
|
||||
$toolbarToggleButton.addClass('cp-toolbar-button-active')
|
||||
.attr('aria-pressed', 'true');
|
||||
} else {
|
||||
$toolbar.hide();
|
||||
$toolbarToggleButton.removeClass('cp-toolbar-button-active')
|
||||
.attr('aria-pressed', 'false');
|
||||
}
|
||||
} else {
|
||||
if ($toolbarToggleButton) {
|
||||
$toolbarToggleButton.remove();
|
||||
$toolbarToggleButton = null;
|
||||
}
|
||||
$toolbar.show();
|
||||
}
|
||||
}
|
||||
|
||||
if (appType !== 'code' && appType !== 'slide') {
|
||||
$(window).on('resize', updateToolbarVisibility);
|
||||
updateToolbarVisibility();
|
||||
// Small delay to ensure the toolbar layout has rendered before checking for wrapping (ex: profile medium screen size)
|
||||
setTimeout(() => {
|
||||
updateToolbarVisibility();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
return {
|
||||
toolbar: $toolbar,
|
||||
button: $toolbarButton,
|
||||
@ -1318,7 +1405,6 @@ define([
|
||||
text: text
|
||||
};
|
||||
};
|
||||
|
||||
/* Create a usage bar which keeps track of how much storage space is used
|
||||
by your CryptDrive. The getPinnedUsage RPC is one of the heavier calls,
|
||||
so we throttle its usage. Clients will not update more than once per
|
||||
|
||||
@ -48,6 +48,8 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
const Env = {};
|
||||
|
||||
// Upgrade and donate URLs duplicated in pages.js
|
||||
var origin = encodeURIComponent(window.location.hostname);
|
||||
var common = window.Cryptpad = {
|
||||
@ -79,6 +81,12 @@ define([
|
||||
common.getAccessKeys = function (cb) {
|
||||
var keys = [];
|
||||
nThen(function (waitFor) {
|
||||
// Not logged in? check for temp RPC keys
|
||||
if (!LocalStore.isLoggedIn() && Env?.returned?.tempKeys) {
|
||||
keys.push(Env.returned.tempKeys);
|
||||
return;
|
||||
}
|
||||
|
||||
// Push account keys
|
||||
postMessage("GET", {
|
||||
key: ['edPrivate'],
|
||||
@ -631,7 +639,7 @@ define([
|
||||
|
||||
common.uploadChunk = function (teamId, data, cb) {
|
||||
postMessage("UPLOAD_CHUNK", {teamId: teamId, chunk: data}, function (obj) {
|
||||
if (obj && obj.error) { return void cb(obj.error); }
|
||||
if (obj && obj.error) { return void cb(obj.error); }
|
||||
cb(null, obj);
|
||||
});
|
||||
};
|
||||
@ -2737,6 +2745,7 @@ define([
|
||||
|
||||
console.log('Posting CONNECT');
|
||||
postMessage('CONNECT', cfg, function (data) {
|
||||
Env.returned = data;
|
||||
// FIXME data should always exist
|
||||
// this indicates a false condition in sharedWorker
|
||||
// got here via a reference error:
|
||||
|
||||
@ -660,25 +660,30 @@ define([
|
||||
var $trashContextMenu = $("#cp-app-drive-context-trash");
|
||||
|
||||
$content.attr("tabindex", "0");
|
||||
var splitter = h('div.cp-splitter', [
|
||||
h('i.fa.fa-ellipsis-v')
|
||||
]);
|
||||
$contentContainer.append(splitter);
|
||||
APP.$splitter = $(splitter).on('mousedown', function (e) {
|
||||
e.preventDefault();
|
||||
var x = e.pageX;
|
||||
var w = $tree.width();
|
||||
var handler = function (evt) {
|
||||
if (evt.type === 'mouseup') {
|
||||
$(window).off('mouseup mousemove', handler);
|
||||
return;
|
||||
}
|
||||
$tree.css('width', (w - x + evt.pageX) + 'px');
|
||||
};
|
||||
$(window).off('mouseup mousemove', handler);
|
||||
$(window).on('mouseup mousemove', handler);
|
||||
});
|
||||
|
||||
if (APP.loggedIn) {
|
||||
var splitter = h('div.cp-splitter', [
|
||||
h('i.fa.fa-ellipsis-v')
|
||||
]);
|
||||
$contentContainer.append(splitter);
|
||||
APP.$splitter = $(splitter).on('mousedown touchstart', function (e) {
|
||||
e.preventDefault();
|
||||
var x = e.type === 'touchstart' ? e.originalEvent.touches[0].pageX : e.pageX;
|
||||
var w = $tree.width();
|
||||
|
||||
var handler = function (evt) {
|
||||
if (evt.type === 'mouseup' || evt.type === 'touchend') {
|
||||
$(window).off('mouseup mousemove touchend touchmove', handler);
|
||||
return;
|
||||
}
|
||||
var pageX = evt.type === 'touchmove'
|
||||
? evt.originalEvent.touches[0].pageX
|
||||
: evt.pageX;
|
||||
$tree.css('width', (w - x + pageX) + 'px');
|
||||
};
|
||||
$(window).off('mouseup mousemove touchend touchmove', handler, { passive: false });
|
||||
$(window).on('mouseup mousemove touchend touchmove', handler);
|
||||
});
|
||||
}
|
||||
// TOOLBAR
|
||||
|
||||
// DRIVE
|
||||
@ -3462,19 +3467,23 @@ define([
|
||||
b = [b];
|
||||
}
|
||||
|
||||
if(a.length === 0 && b.length === 0) {
|
||||
if (a.length === 0 && b.length === 0) {
|
||||
return 0;
|
||||
} else if (a.length === 0) {
|
||||
return -1;
|
||||
} else if (b.length === 0) {
|
||||
return 1;
|
||||
} else if(a[0] < b[0]) {
|
||||
return -1;
|
||||
} else if(a[0] > b[0]) {
|
||||
return 1;
|
||||
} else if (typeof (a[0]) !== typeof (b[0])) {
|
||||
return String(a[0]) < String(b[0]) ? -1 : 1;
|
||||
} else {
|
||||
// This means `a[0] == b[0]`. Chop off the first elements and compare the rest.
|
||||
return lexicographicCompare(a.slice(1), b.slice(1));
|
||||
if (a[0] < b[0]) {
|
||||
return -1;
|
||||
} else if (a[0] > b[0]) {
|
||||
return 1;
|
||||
} else {
|
||||
// This means `a[0] == b[0]`. Chop off the first elements and compare the rest.
|
||||
return lexicographicCompare(a.slice(1), b.slice(1));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -3792,8 +3801,6 @@ define([
|
||||
});
|
||||
$element.contextmenu(openContextMenu('default'));
|
||||
$element.data('context', 'default');
|
||||
var $fileMenu = $('<li>').append($fileMenuIcon);
|
||||
$element.append($fileMenu);
|
||||
$container.append($element);
|
||||
});
|
||||
createGhostIcon($container);
|
||||
|
||||
@ -1090,6 +1090,7 @@ define([
|
||||
if (content.version <= 2) {
|
||||
setEditable(false, true);
|
||||
}
|
||||
console.log("OO loading");
|
||||
};
|
||||
|
||||
|
||||
@ -2124,6 +2125,7 @@ define([
|
||||
}];
|
||||
common.checkTrimHistory(channels);
|
||||
}
|
||||
console.log("OO ready");
|
||||
};
|
||||
|
||||
const copy = (a, b) => {
|
||||
|
||||
@ -3,15 +3,19 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
define([
|
||||
'/api/config',
|
||||
'/file/file-crypto.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/cache-store.js',
|
||||
'/common/outer/http-command.js',
|
||||
'/components/chainpad-crypto/crypto.js',
|
||||
'/components/nthen/index.js',
|
||||
], function (FileCrypto, Hash, Util, Cache, nThen) {
|
||||
], function (ApiConfig, FileCrypto, Hash, Util, Cache, ServerCommand, Crypto, nThen) {
|
||||
var module = {};
|
||||
const USE_WS = false;
|
||||
|
||||
module.uploadU8 =function (common, data, cb) {
|
||||
module.uploadU8 = function (common, data, cb) {
|
||||
var teamId = data.teamId;
|
||||
var u8 = data.u8;
|
||||
var metadata = data.metadata;
|
||||
@ -27,13 +31,53 @@ define([
|
||||
|
||||
var estimate = FileCrypto.computeEncryptedSize(u8.length, metadata);
|
||||
|
||||
var sendChunk = function (box, cb) {
|
||||
|
||||
|
||||
var sendChunkWs = function (box, cb) {
|
||||
var enc = Util.encodeBase64(box);
|
||||
common.uploadChunk(teamId, enc, function (e, msg) {
|
||||
cb(e, msg);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
let uploadUrl = '/upload-blob';
|
||||
let size = 0;
|
||||
if (ApiConfig.fileHost) {
|
||||
const origin = new URL(ApiConfig.fileHost).origin;
|
||||
uploadUrl = origin + uploadUrl;
|
||||
}
|
||||
var sendChunk = function (box, cb) {
|
||||
const enc = Util.encodeBase64(box);
|
||||
size += enc.length;
|
||||
|
||||
const c = Util.decodeUTF8(cookie);
|
||||
const sig_str = window.nacl.sign(c, keys.secretKey);
|
||||
const sig = Util.encodeBase64(sig_str);
|
||||
|
||||
const body = {
|
||||
chunk: enc,
|
||||
sig: sig,
|
||||
edPublic: keys.edPublic
|
||||
};
|
||||
|
||||
fetch(uploadUrl, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
}).then(res => res.json())
|
||||
.then(json => {
|
||||
if (json?.error) {
|
||||
return cb(json.error);
|
||||
}
|
||||
cookie = json.cookie;
|
||||
cb();
|
||||
}).catch(cb);
|
||||
};
|
||||
|
||||
let keys, cookie;
|
||||
var actual = 0;
|
||||
var encryptedArr = [];
|
||||
var again = function (err, box) {
|
||||
@ -45,7 +89,11 @@ define([
|
||||
progressValue = Math.min(progressValue, 100);
|
||||
updateProgress(progressValue);
|
||||
|
||||
return void sendChunk(box, function (e) {
|
||||
let send = sendChunk;
|
||||
if (USE_WS) {
|
||||
send = sendChunkWs;
|
||||
}
|
||||
return void send(box, function (e) {
|
||||
if (e) { return console.error(e); }
|
||||
next(again);
|
||||
});
|
||||
@ -69,6 +117,30 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
const startUpload = () => {
|
||||
if (USE_WS) {
|
||||
return void next(again);
|
||||
}
|
||||
common.getAccessKeys(arr => {
|
||||
const myKeys = arr.find(obj => {
|
||||
return (!obj.id && !teamId) || +obj.id === +teamId;
|
||||
});
|
||||
if (!myKeys) { return void onError('NO_KEYS'); }
|
||||
keys = {
|
||||
edPublic: myKeys.edPublic,
|
||||
publicKey: Util.decodeBase64(myKeys.edPublic),
|
||||
secretKey: Util.decodeBase64(myKeys.edPrivate)
|
||||
};
|
||||
ServerCommand(keys, {
|
||||
command: 'UPLOAD_COOKIE',
|
||||
}, (err, data) => {
|
||||
cookie = data?.cookie;
|
||||
if (err || !cookie) { return void onError(err || 'NOCOOKIE'); }
|
||||
next(again);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
common.uploadStatus(teamId, estimate, function (e, pending) {
|
||||
if (e) {
|
||||
console.error(e);
|
||||
@ -83,11 +155,11 @@ define([
|
||||
if (e) {
|
||||
return void console.error(e);
|
||||
}
|
||||
next(again);
|
||||
startUpload();
|
||||
});
|
||||
});
|
||||
}
|
||||
next(again);
|
||||
startUpload();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
2
www/common/worker.bundle.min.js
vendored
2
www/common/worker.bundle.min.js
vendored
File diff suppressed because one or more lines are too long
@ -176,6 +176,16 @@
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
min-width: 300px;
|
||||
.cp-markdown-toggle-row {
|
||||
margin: 0.5rem 0;
|
||||
position: relative;
|
||||
.cp-markdown-toggle-button {
|
||||
.markdown-toolbar-button-style() !important;
|
||||
&.cp-toolbar-button-active {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.timeline-container {
|
||||
width: 100%;
|
||||
@ -381,6 +391,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
div.cp-form-response-msg-container {
|
||||
.cp-markdown-toolbar {
|
||||
background-color: transparent;
|
||||
border-radius: @variables_radius @variables_radius 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
div.cp-form-creator-results {
|
||||
.cp-form-block {
|
||||
@ -431,6 +447,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.cp-editor-wrapper {
|
||||
.cp-form-edit-options-block {
|
||||
padding: 1px;
|
||||
overflow: hidden;
|
||||
border: 1px solid @cp_forms-border;
|
||||
}
|
||||
}
|
||||
|
||||
.cp-form-creator-add-inline {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
@ -532,7 +556,6 @@
|
||||
padding-bottom: 75px;
|
||||
button {
|
||||
white-space: initial;
|
||||
line-height: 25px;
|
||||
padding: 5.5px 6px;
|
||||
}
|
||||
.cp-form-response-msg-hint {
|
||||
@ -819,6 +842,9 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
border-radius: @variables_radius;
|
||||
margin-top: 0.5rem;
|
||||
padding: 1px;
|
||||
.CodeMirror {
|
||||
cursor: default;
|
||||
flex: 1;
|
||||
@ -827,13 +853,16 @@
|
||||
width: 80%;
|
||||
min-height: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid @cp_forms-border;
|
||||
.CodeMirror-placeholder {
|
||||
color: #777;
|
||||
}
|
||||
}
|
||||
.cp-markdown-toolbar {
|
||||
display: block;
|
||||
padding: 0.1rem 0;
|
||||
border-radius: @variables_radius 0;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
.cp-form-edit-block {
|
||||
@ -1358,8 +1387,12 @@
|
||||
}
|
||||
}
|
||||
.cp-form-response-modal {
|
||||
.CodeMirror {
|
||||
.cp-form-markdown-editor-wrapper {
|
||||
border: 1px solid @cp_forms-border;
|
||||
border-radius: @variables_radius;
|
||||
}
|
||||
.CodeMirror {
|
||||
border-radius: 0 0 @variables_radius @variables_radius;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1098,6 +1098,7 @@ define([
|
||||
editor.setOption("extraKeys", {
|
||||
"Esc": function () {
|
||||
editor.display.input.blur();
|
||||
$(cancelBlock).focus();
|
||||
},
|
||||
});
|
||||
editor.setOption('lineNumbers', true);
|
||||
@ -1115,18 +1116,25 @@ define([
|
||||
}
|
||||
editor.refresh();
|
||||
editor.save();
|
||||
editor.focus();
|
||||
var firstBtn = $(markdownTb.toolbar).find('button').get(0);
|
||||
if (firstBtn) {
|
||||
firstBtn.focus();
|
||||
} else {
|
||||
editor.focus(); // fallback
|
||||
}
|
||||
});
|
||||
var toggleRow = h('div.cp-markdown-toggle-row');
|
||||
|
||||
if (APP.common && !(tmp && tmp.block) && cm) {
|
||||
var markdownTb = APP.common.createMarkdownToolbar(editor, {
|
||||
embed: function (mt) {
|
||||
editor.focus();
|
||||
editor.replaceSelection($(mt)[0].outerHTML);
|
||||
}
|
||||
},
|
||||
wrapper: toggleRow
|
||||
});
|
||||
$(block).prepend(markdownTb.toolbar);
|
||||
$(markdownTb.toolbar).show();
|
||||
$(block).prepend(toggleRow);
|
||||
cm.configureTheme(APP.common, function () {});
|
||||
}
|
||||
|
||||
@ -1159,8 +1167,13 @@ define([
|
||||
};
|
||||
};
|
||||
|
||||
var outerWrapper = h('div.cp-editor-wrapper', [
|
||||
toggleRow,
|
||||
block
|
||||
]);
|
||||
|
||||
return [
|
||||
block,
|
||||
outerWrapper,
|
||||
cancelBlock
|
||||
];
|
||||
},
|
||||
@ -2113,7 +2126,10 @@ define([
|
||||
|
||||
Object.keys(answers).forEach(function (author) {
|
||||
var obj = answers[author];
|
||||
var answer = Flatpickr.formatDate(new Date(obj.msg[uid]), dateFormat);
|
||||
var answer;
|
||||
if (obj.msg[uid]) {
|
||||
answer = Flatpickr.formatDate(new Date(obj.msg[uid]), dateFormat);
|
||||
}
|
||||
if (isEmpty(answer)) { return empty++; }
|
||||
results.push(h('div.cp-charts-row', h('span.cp-value', answer)));
|
||||
});
|
||||
@ -5558,30 +5574,39 @@ define([
|
||||
]);
|
||||
var editButtons = h('div.cp-form-edit-buttons-container', [ preview, edit, del ]);
|
||||
|
||||
var toggleRow = h('div.cp-markdown-toggle-row');
|
||||
var markdownWrapper = h('div.cp-form-markdown-editor-wrapper', t);
|
||||
var editDiv, previewDiv;
|
||||
var div = h('div.cp-form-block.editable.nodrag.cp-form-submit-message', [
|
||||
h('div.cp-form-block-content', [
|
||||
p,
|
||||
editDiv = h('div.cp-form-response-modal', t),
|
||||
editDiv = h('div.cp-form-response-modal', toggleRow, markdownWrapper),
|
||||
previewDiv = h('div.cp-form-response-preview#cp-response-preview'),
|
||||
editButtons
|
||||
]),
|
||||
]);
|
||||
var cm = APP.responseCM = SFCodeMirror.create("gfm", CMeditor, t);
|
||||
var editor = APP.responseEditor = cm.editor;
|
||||
|
||||
editor.setOption("extraKeys", {
|
||||
"Esc": function() {
|
||||
editor.display.input.blur();
|
||||
$(preview).focus();
|
||||
}
|
||||
});
|
||||
var markdownTb = APP.common.createMarkdownToolbar(editor, {
|
||||
embed: function (mt) {
|
||||
editor.focus();
|
||||
editor.replaceSelection($(mt)[0].outerHTML);
|
||||
}
|
||||
},
|
||||
wrapper: toggleRow
|
||||
});
|
||||
var $tb = $(markdownTb.toolbar).insertAfter($(p));
|
||||
$(markdownWrapper).prepend(markdownTb.toolbar);
|
||||
|
||||
var $edit = $(editDiv);
|
||||
var $preview = $(previewDiv);
|
||||
var $p = $(preview);
|
||||
var $e = $(edit);
|
||||
var $tb = $(markdownTb);
|
||||
var previewState = true;
|
||||
|
||||
var updatePreview = function () {
|
||||
@ -5598,6 +5623,14 @@ define([
|
||||
$preview.hide();
|
||||
editor.refresh();
|
||||
$tb.show();
|
||||
setTimeout(function () {
|
||||
var firstBtn = $(markdownTb.toolbar).find('button').get(0);
|
||||
if (firstBtn) {
|
||||
firstBtn.focus();
|
||||
} else {
|
||||
editor.focus(); // fallback
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
APP.$e = $e;
|
||||
APP.$p = $p;
|
||||
|
||||
@ -120,9 +120,31 @@
|
||||
}
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.cp-markdown-label-row {
|
||||
margin-bottom: 0.5rem;
|
||||
position: relative;
|
||||
}
|
||||
.cp-markdown-label-row label {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.cp-markdown-toggle-button {
|
||||
.markdown-toolbar-button-style();
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
&.cp-toolbar-button-active {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
#cp-kanban-edit-body {
|
||||
border: 1px solid @cp_forms-border;
|
||||
border-radius: @variables_radius;
|
||||
overflow: hidden;
|
||||
.CodeMirror {
|
||||
height: 105px;
|
||||
resize: vertical;
|
||||
@ -132,7 +154,7 @@
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.cp-markdown-toolbar {
|
||||
background-color: @cp_kanban-conflict-bg;
|
||||
background-color: transparent;
|
||||
color: @cp_kanban-fg;
|
||||
border-radius: @variables_radius @variables_radius 0px 0px;
|
||||
button {
|
||||
@ -141,6 +163,20 @@
|
||||
color: @cp_kanban-conflict-bg;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
outline: 0;
|
||||
border-radius: @variables_radius;
|
||||
.fa {
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
font-family: FontAwesome;
|
||||
}
|
||||
&:hover {
|
||||
background-color: contrast(@cp_toolbar-bg, darken(@cp_toolbar-bg, 5%), lighten(@cp_toolbar-bg, 5%));
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: @variables_focus_style;
|
||||
}
|
||||
}
|
||||
}
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@ -241,9 +277,8 @@
|
||||
background: @cp_kanban-item-bg;
|
||||
box-shadow: @cryptpad_ui_shadow;
|
||||
.tools_unselectable();
|
||||
touch-action: none;
|
||||
&:not(.no-drag) {
|
||||
cursor: move;
|
||||
touch-action: none;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
|
||||
@ -174,7 +174,6 @@ define([
|
||||
}
|
||||
_updateBoardsThrottle(framework, kanban, boards);
|
||||
};
|
||||
|
||||
var editModal;
|
||||
var PROPERTIES = ['title', 'body', 'tags', 'color'];
|
||||
var BOARD_PROPERTIES = ['title', 'color'];
|
||||
@ -200,6 +199,10 @@ define([
|
||||
commit();
|
||||
});
|
||||
|
||||
var markdownEditorWrapper = h('div.cp-markdown-label-row', [
|
||||
h('label', { for: 'cp-kanban-edit-body' }, Messages.kanban_body)
|
||||
]);
|
||||
|
||||
var conflicts, conflictContainer, titleInput, tagsDiv, text;
|
||||
var content = h('div', [
|
||||
conflictContainer = h('div#cp-kanban-edit-conflicts', [
|
||||
@ -208,7 +211,7 @@ define([
|
||||
]),
|
||||
h('label', {for:'cp-kanban-edit-title'}, Messages.kanban_title),
|
||||
titleInput = h('input#cp-kanban-edit-title'),
|
||||
h('label', {for:'cp-kanban-edit-body'}, Messages.kanban_body),
|
||||
markdownEditorWrapper,
|
||||
h('div#cp-kanban-edit-body', [
|
||||
text = h('textarea')
|
||||
]),
|
||||
@ -280,10 +283,20 @@ define([
|
||||
embed: function (mt) {
|
||||
editor.focus();
|
||||
editor.replaceSelection($(mt)[0].outerHTML);
|
||||
},
|
||||
wrapper: markdownEditorWrapper
|
||||
});
|
||||
$(markdownTb.toolbar).on('keydown', function (e) {
|
||||
if (e.which === 27) { // Escape key
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
editor.focus(); // Focus the editor instead of closing the modal
|
||||
}
|
||||
else if (e.which === 13 || e.which === 9) { // "Enter" or "Tab" key should not close modal
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
$(text).before(markdownTb.toolbar);
|
||||
$(markdownTb.toolbar).show();
|
||||
editor.refresh();
|
||||
var body = {
|
||||
getValue: function () {
|
||||
|
||||
@ -90,6 +90,12 @@
|
||||
margin: 5px !important;
|
||||
}
|
||||
}
|
||||
.cp-markdown-toggle-row {
|
||||
margin-bottom: 0.5rem;
|
||||
.btn.cp-markdown-toggle-button {
|
||||
.markdown-toolbar-button-style() !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cp-app-profile-resizer {
|
||||
text-align: center;
|
||||
@ -184,9 +190,9 @@
|
||||
.cp-app-profile-description-code {
|
||||
display: none;
|
||||
.cp-markdown-toolbar {
|
||||
display: flex;
|
||||
height: auto;
|
||||
flex-wrap: wrap;
|
||||
max-width: 31rem;
|
||||
background-color: @cp_toolbar-bg;
|
||||
border-radius: @variables_radius @variables_radius 0 0;
|
||||
}
|
||||
}
|
||||
#cp-app-profile-description-info {
|
||||
@ -209,6 +215,7 @@
|
||||
font-size: 16px;
|
||||
line-height: initial;
|
||||
max-width: 31rem;
|
||||
border-radius: 0 0 @variables_radius @variables_radius;
|
||||
pre {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
|
||||
@ -517,19 +517,28 @@ define([
|
||||
cm.configureTheme(common, function () {});
|
||||
editor.setOption("extraKeys", {
|
||||
"Esc": function () {
|
||||
cm.getInputField().blur();
|
||||
editor.getInputField().blur();
|
||||
$(save).focus();
|
||||
}
|
||||
});
|
||||
|
||||
var markdownTb = common.createMarkdownToolbar(editor);
|
||||
var toggleRow = h('div.cp-markdown-toggle-row');
|
||||
var markdownTb = common.createMarkdownToolbar(editor, {
|
||||
wrapper: toggleRow
|
||||
});
|
||||
$(code).prepend(markdownTb.toolbar);
|
||||
$(markdownTb.toolbar).show();
|
||||
|
||||
$(code).prepend(toggleRow);
|
||||
if(!Util.isSmallScreen()) {
|
||||
$(markdownTb.toolbar).show();
|
||||
}
|
||||
$(button).click(function () {
|
||||
$(code).show();
|
||||
APP.editor.refresh();
|
||||
$(button).hide();
|
||||
var firstBtn = $(markdownTb.toolbar).find('button').get(0);
|
||||
if (firstBtn) {
|
||||
firstBtn.focus();
|
||||
}
|
||||
});
|
||||
$(save).click(function () {
|
||||
$(save).hide();
|
||||
|
||||
@ -208,14 +208,21 @@ define([
|
||||
var addEvent = function () {
|
||||
console.log($modal);
|
||||
var icon_to;
|
||||
$modal.mousemove(function () {
|
||||
var mousemove = function () {
|
||||
var $buttons = $modal.find('.cp-app-slide-modal-button');
|
||||
$buttons.show();
|
||||
if (icon_to) { window.clearTimeout(icon_to); }
|
||||
icon_to = window.setTimeout(function() {
|
||||
$buttons.fadeOut();
|
||||
}, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
$modal.mousemove(mousemove);
|
||||
$modal.on('touchstart', mousemove);
|
||||
$modal.on('touchend', mousemove);
|
||||
$modal.on('touchcancel', mousemove);
|
||||
$modal.on('touchmove', mousemove);
|
||||
|
||||
$modal.find('#cp-app-slide-modal-exit').click(function () {
|
||||
var ev = $.Event("keyup");
|
||||
ev.which = 27;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user