Strip down old web app
parent
52a55f71e6
commit
1a3816c1ff
|
@ -28,10 +28,6 @@
|
||||||
<meta property="og:description" content="ntfy is a simple HTTP-based pub-sub notification service. It allows you to send desktop notifications via scripts from any computer, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." />
|
<meta property="og:description" content="ntfy is a simple HTTP-based pub-sub notification service. It allows you to send desktop notifications via scripts from any computer, entirely without signup or cost. Made with ❤ by Philipp C. Heckel, Apache License 2.0, source at https://heckel.io/ntfy." />
|
||||||
<meta property="og:image" content="/static/img/ntfy.png" />
|
<meta property="og:image" content="/static/img/ntfy.png" />
|
||||||
<meta property="og:url" content="https://ntfy.sh" />
|
<meta property="og:url" content="https://ntfy.sh" />
|
||||||
{{if .Topic}}
|
|
||||||
<!-- Never index topic page -->
|
|
||||||
<meta name="robots" content="noindex, nofollow" />
|
|
||||||
{{end}}
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
@ -48,7 +44,7 @@
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div id="main"{{if .Topic}} style="display: none"{{end}}>
|
<div id="main">
|
||||||
<h1>Send push notifications to your phone or desktop via PUT/POST</h1>
|
<h1>Send push notifications to your phone or desktop via PUT/POST</h1>
|
||||||
<p>
|
<p>
|
||||||
<b>ntfy</b> (pronounce: <i>notify</i>) is a simple HTTP-based <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">pub-sub</a> notification service.
|
<b>ntfy</b> (pronounce: <i>notify</i>) is a simple HTTP-based <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">pub-sub</a> notification service.
|
||||||
|
@ -122,24 +118,11 @@
|
||||||
<figcaption>Sending push notifications to your Android phone</figcaption>
|
<figcaption>Sending push notifications to your Android phone</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
<div id="subscribeBox">
|
<h3 id="subscribe-web" class="anchor">Subscribe via web app</h3>
|
||||||
<h3 id="subscribe-web" class="anchor">Subscribe in this Web UI</h3>
|
<p>
|
||||||
<p id="error"></p>
|
Subscribe to topics here and receive messages as <b>desktop notification</b>. Topics are not password-protected,
|
||||||
<p>
|
so choose a name that's not easy to guess.
|
||||||
Subscribe to topics here and receive messages as <b>desktop notification</b>. Topics are not password-protected,
|
</p>
|
||||||
so choose a name that's not easy to guess.
|
|
||||||
</p>
|
|
||||||
<form id="subscribeForm">
|
|
||||||
<p>
|
|
||||||
<b>Topic:</b><br/>
|
|
||||||
<input type="text" id="topicField" autocomplete="off" placeholder="Topic name, e.g. phil_alerts" maxlength="64" pattern="[-_A-Za-z0-9]{1,64}" />
|
|
||||||
<button id="subscribeButton">Subscribe</button>
|
|
||||||
</p>
|
|
||||||
<p id="topicsHeader"><b>Subscribed topics:</b></p>
|
|
||||||
<ul id="topicsList"></ul>
|
|
||||||
</form>
|
|
||||||
<audio id="notifySound" src="static/sound/mixkit-message-pop-alert-2354.mp3"></audio>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3 id="subscribe-api" class="anchor">Subscribe using the API</h3>
|
<h3 id="subscribe-api" class="anchor">Subscribe using the API</h3>
|
||||||
<p>
|
<p>
|
||||||
|
@ -186,31 +169,6 @@
|
||||||
|
|
||||||
<center id="ironicCenterTagDontFreakOut"><i>Made with ❤️ by <a href="https://heckel.io">Philipp C. Heckel</a></i></center>
|
<center id="ironicCenterTagDontFreakOut"><i>Made with ❤️ by <a href="https://heckel.io">Philipp C. Heckel</a></i></center>
|
||||||
</div>
|
</div>
|
||||||
<div id="detail"{{if not .Topic}} style="display: none"{{end}}>
|
|
||||||
<div id="detailMain">
|
|
||||||
<button id="detailCloseButton"><img src="static/img/close.svg"/></button>
|
|
||||||
<h1><span id="detailTitle"></span></h1>
|
|
||||||
<p class="smallMarginBottom">
|
|
||||||
<b>ntfy</b> is a simple HTTP-based pub-sub notification service. This is a ntfy topic.
|
|
||||||
To send notifications to it, simply PUT or POST to the topic URL. Here's an example using <tt>curl</tt>:
|
|
||||||
</p>
|
|
||||||
<code>
|
|
||||||
curl -d "Backup failed" <span id="detailTopicUrl">ntfy.sh/topic</span>
|
|
||||||
</code>
|
|
||||||
<p id="detailNotificationsDisallowed">
|
|
||||||
If you'd like to receive desktop notifications when new messages arrive on this topic, you have to
|
|
||||||
<a href="#" onclick="return requestPermission()">grant the browser permission</a> to show notifications.
|
|
||||||
Click the link to do so.
|
|
||||||
</p>
|
|
||||||
<p class="smallMarginBottom">
|
|
||||||
<b>Recent notifications</b> ({{if .CacheDuration}}cached for {{.CacheDuration | durationToHuman}}{{else}}caching is disabled{{end}}):
|
|
||||||
</p>
|
|
||||||
<p id="detailNoNotifications">
|
|
||||||
<i>You haven't received any notifications for this topic yet.</i>
|
|
||||||
</p>
|
|
||||||
<div id="detailEventsList"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="lightbox" class="lightbox"></div>
|
<div id="lightbox" class="lightbox"></div>
|
||||||
<script src="static/js/emoji.js"></script>
|
<script src="static/js/emoji.js"></script>
|
||||||
<script src="static/js/app.js"></script>
|
<script src="static/js/app.js"></script>
|
||||||
|
|
|
@ -333,199 +333,3 @@ li {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subscribe box SMALL SCREEN */
|
|
||||||
@media only screen and (max-width: 1599px) {
|
|
||||||
#subscribeBox #subscribeForm {
|
|
||||||
border-left: 4px solid #3a9784;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox #topicsHeader {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox input {
|
|
||||||
height: 24px;
|
|
||||||
min-width: 200px;
|
|
||||||
max-width: 300px;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid #aaa;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox input:focus {
|
|
||||||
border-bottom: 2px solid #3a9784;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox ul {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox li {
|
|
||||||
margin: 3px 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox li img {
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox li a {
|
|
||||||
padding: 0 5px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox button {
|
|
||||||
font-size: 0.8em;
|
|
||||||
background: #3a9784;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 5px;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox button:hover {
|
|
||||||
background: #317f6f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Subscribe box BIG SCREEN */
|
|
||||||
@media only screen and (min-width: 1600px) {
|
|
||||||
#subscribeBox {
|
|
||||||
position: fixed;
|
|
||||||
top: 170px;
|
|
||||||
right: 10px;
|
|
||||||
width: 300px;
|
|
||||||
border-left: 4px solid #3a9784;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox h3 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox #topicsHeader {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox p {
|
|
||||||
font-size: 0.9em;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox ul {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox input {
|
|
||||||
height: 18px;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox input:focus {
|
|
||||||
border-bottom: 2px solid #3a9784;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox li {
|
|
||||||
margin: 3px 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox li img {
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox li a {
|
|
||||||
padding: 0 5px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox button {
|
|
||||||
font-size: 0.7em;
|
|
||||||
background: #3a9784;
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 5px;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#subscribeBox button:hover {
|
|
||||||
background: #317f6f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Detail view */
|
|
||||||
|
|
||||||
#detail .detailEntry {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail .detailDate {
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail .detailDate, #detail .detailTags {
|
|
||||||
color: #888;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail .detailTags {
|
|
||||||
margin-top: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail .detailDate img {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail .detailTitle {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail #detailMain {
|
|
||||||
max-width: 900px;
|
|
||||||
margin: 0 auto;
|
|
||||||
position: relative; /* required for close button's "position: absolute" */
|
|
||||||
padding: 0 10px 50px 10px; /* Chrome and Firefox behave differently regarding bottom margin */
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail #detailCloseButton {
|
|
||||||
background: #eee;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
padding: 5px;
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
top: 10px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail #detailCloseButton:hover {
|
|
||||||
padding: 5px;
|
|
||||||
background: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail #detailCloseButton img {
|
|
||||||
display: block; /* get rid of the weird bottom border */
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail #detailNotificationsDisallowed {
|
|
||||||
display: none;
|
|
||||||
color: darkred;
|
|
||||||
}
|
|
||||||
|
|
||||||
#detail #events {
|
|
||||||
max-width: 900px;
|
|
||||||
margin: 0 auto 50px auto;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
height="24px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24px"
|
|
||||||
fill="#000000"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1428"
|
|
||||||
sodipodi:docname="priority_1_24dp.svg"
|
|
||||||
inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
|
|
||||||
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">
|
|
||||||
<defs
|
|
||||||
id="defs1432" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1430"
|
|
||||||
pagecolor="#505050"
|
|
||||||
bordercolor="#eeeeee"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="20.517358"
|
|
||||||
inkscape:cx="22.834324"
|
|
||||||
inkscape:cy="15.742768"
|
|
||||||
inkscape:window-width="1863"
|
|
||||||
inkscape:window-height="1025"
|
|
||||||
inkscape:window-x="57"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg1428" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#999999;fill-opacity:1;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="m 12.195014,20.828316 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 l 6.646593,-4.037178 a 1.2745823,1.2745823 0 0 0 0.427537,-1.751107 1.2745823,1.2745823 0 0 0 -1.750928,-0.427718 l -5.984807,3.635327 -5.9848086,-3.635327 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427718 1.2745823,1.2745823 0 0 0 0.427536,1.751107 l 6.6464146,4.037178 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
|
|
||||||
id="rect3554" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="m 12.195014,15.694014 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 l 6.646593,-4.037176 A 1.2745823,1.2745823 0 0 0 19.930749,9.7205243 1.2745823,1.2745823 0 0 0 18.179821,9.2928073 L 12.195014,12.928134 6.2102054,9.2928073 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427717 1.2745823,1.2745823 0 0 0 0.427536,1.7511077 l 6.6464146,4.037176 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
|
|
||||||
id="path9314" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="m 12.116784,10.426777 a 1.2747098,1.2747098 0 0 0 0.661606,-0.185205 l 6.646593,-4.0371767 a 1.2745823,1.2745823 0 0 0 0.427537,-1.751108 1.2745823,1.2745823 0 0 0 -1.750928,-0.427718 l -5.984808,3.635327 -5.9848066,-3.635327 a 1.2745823,1.2745823 0 0 0 -1.750928,0.427718 1.2745823,1.2745823 0 0 0 0.427537,1.751108 L 11.455,10.241572 a 1.2747098,1.2747098 0 0 0 0.661784,0.185205 z"
|
|
||||||
id="path9316" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.7 KiB |
|
@ -1,43 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
height="24px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24px"
|
|
||||||
fill="#000000"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1428"
|
|
||||||
sodipodi:docname="priority_2_24dp.svg"
|
|
||||||
inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
|
|
||||||
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">
|
|
||||||
<defs
|
|
||||||
id="defs1432" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1430"
|
|
||||||
pagecolor="#505050"
|
|
||||||
bordercolor="#eeeeee"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="20.517358"
|
|
||||||
inkscape:cx="22.834324"
|
|
||||||
inkscape:cy="15.742768"
|
|
||||||
inkscape:window-width="1863"
|
|
||||||
inkscape:window-height="1025"
|
|
||||||
inkscape:window-x="57"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg1428" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#999999;fill-opacity:1;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="m 12.172712,17.774352 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 l 6.646593,-4.037178 a 1.2745823,1.2745823 0 0 0 0.427537,-1.751107 1.2745823,1.2745823 0 0 0 -1.750928,-0.427718 L 12.172712,15.00847 6.1879033,11.373143 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427718 1.2745823,1.2745823 0 0 0 0.427536,1.751107 l 6.6464147,4.037178 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
|
|
||||||
id="rect3554" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="m 12.172712,12.64005 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 L 19.48091,8.4176679 A 1.2745823,1.2745823 0 0 0 19.908447,6.6665602 1.2745823,1.2745823 0 0 0 18.157519,6.2388432 L 12.172712,9.8741699 6.1879033,6.2388432 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427717 1.2745823,1.2745823 0 0 0 0.427536,1.7511077 l 6.6464147,4.0371761 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
|
|
||||||
id="path9314" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.1 KiB |
|
@ -1,43 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
height="24px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24px"
|
|
||||||
fill="#000000"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1428"
|
|
||||||
sodipodi:docname="priority_4_24dp.svg"
|
|
||||||
inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
|
|
||||||
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">
|
|
||||||
<defs
|
|
||||||
id="defs1432" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1430"
|
|
||||||
pagecolor="#505050"
|
|
||||||
bordercolor="#eeeeee"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="20.517358"
|
|
||||||
inkscape:cx="22.834324"
|
|
||||||
inkscape:cy="15.742768"
|
|
||||||
inkscape:window-width="1863"
|
|
||||||
inkscape:window-height="1025"
|
|
||||||
inkscape:window-x="57"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg1428" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#c60000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="M 12.116784,6.5394415 A 1.2747098,1.2747098 0 0 0 11.455179,6.724648 l -6.6465926,4.037176 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.7509281,0.427717 l 5.9848065,-3.635327 5.984809,3.635327 A 1.2745823,1.2745823 0 0 0 19.85252,12.512932 1.2745823,1.2745823 0 0 0 19.424984,10.761824 L 12.778569,6.724648 A 1.2747098,1.2747098 0 0 0 12.116784,6.5394415 Z"
|
|
||||||
id="path9314" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#de0000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="m 12.195014,11.806679 a 1.2747098,1.2747098 0 0 0 -0.661606,0.185205 l -6.6465924,4.037177 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.750928,0.427718 l 5.9848074,-3.635327 5.984807,3.635327 a 1.2745823,1.2745823 0 0 0 1.750928,-0.427718 1.2745823,1.2745823 0 0 0 -0.427537,-1.751108 l -6.646414,-4.037177 a 1.2747098,1.2747098 0 0 0 -0.661784,-0.185205 z"
|
|
||||||
id="path9316" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.1 KiB |
|
@ -1,47 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<svg
|
|
||||||
height="24px"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24px"
|
|
||||||
fill="#000000"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1428"
|
|
||||||
sodipodi:docname="priority_5_24dp.svg"
|
|
||||||
inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
|
|
||||||
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">
|
|
||||||
<defs
|
|
||||||
id="defs1432" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1430"
|
|
||||||
pagecolor="#505050"
|
|
||||||
bordercolor="#eeeeee"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:pageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="20.517358"
|
|
||||||
inkscape:cx="22.834323"
|
|
||||||
inkscape:cy="15.742767"
|
|
||||||
inkscape:window-width="1863"
|
|
||||||
inkscape:window-height="1025"
|
|
||||||
inkscape:window-x="57"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg1428" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#aa0000;fill-opacity:1;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="M 12.116784,3.40514 A 1.2747098,1.2747098 0 0 0 11.455179,3.5903463 L 4.8085864,7.6275238 A 1.2745823,1.2745823 0 0 0 4.3810494,9.3786313 1.2745823,1.2745823 0 0 0 6.1319775,9.8063489 L 12.116784,6.1710217 18.101593,9.8063489 A 1.2745823,1.2745823 0 0 0 19.85252,9.3786313 1.2745823,1.2745823 0 0 0 19.424984,7.6275238 L 12.778569,3.5903463 A 1.2747098,1.2747098 0 0 0 12.116784,3.40514 Z"
|
|
||||||
id="rect3554" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#c60000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="M 12.116784,8.5394415 A 1.2747098,1.2747098 0 0 0 11.455179,8.724648 l -6.6465926,4.037176 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.7509281,0.427717 l 5.9848065,-3.635327 5.984809,3.635327 A 1.2745823,1.2745823 0 0 0 19.85252,14.512932 1.2745823,1.2745823 0 0 0 19.424984,12.761824 L 12.778569,8.724648 A 1.2747098,1.2747098 0 0 0 12.116784,8.5394415 Z"
|
|
||||||
id="path9314" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;fill:#de0000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
|
|
||||||
d="m 12.195014,13.806679 a 1.2747098,1.2747098 0 0 0 -0.661606,0.185205 l -6.6465924,4.037177 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.750928,0.427718 l 5.9848074,-3.635327 5.984807,3.635327 a 1.2745823,1.2745823 0 0 0 1.750928,-0.427718 1.2745823,1.2745823 0 0 0 -0.427537,-1.751108 l -6.646414,-4.037177 a 1.2747098,1.2747098 0 0 0 -0.661784,-0.185205 z"
|
|
||||||
id="path9316" />
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.7 KiB |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#ffffff"><path d="M0 0h24v24H0z" fill="none"/><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
|
|
Before Width: | Height: | Size: 195 B |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
|
|
Before Width: | Height: | Size: 269 B |
|
@ -9,233 +9,14 @@
|
||||||
|
|
||||||
/* All the things */
|
/* All the things */
|
||||||
|
|
||||||
let topics = {};
|
|
||||||
let currentTopic = "";
|
|
||||||
let currentTopicUnsubscribeOnClose = false;
|
|
||||||
let currentUrl = window.location.hostname;
|
let currentUrl = window.location.hostname;
|
||||||
if (window.location.port) {
|
if (window.location.port) {
|
||||||
currentUrl += ':' + window.location.port
|
currentUrl += ':' + window.location.port
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main view */
|
|
||||||
const main = document.getElementById("main");
|
|
||||||
const topicsHeader = document.getElementById("topicsHeader");
|
|
||||||
const topicsList = document.getElementById("topicsList");
|
|
||||||
const topicField = document.getElementById("topicField");
|
|
||||||
const notifySound = document.getElementById("notifySound");
|
|
||||||
const subscribeButton = document.getElementById("subscribeButton");
|
|
||||||
const errorField = document.getElementById("error");
|
|
||||||
const originalTitle = document.title;
|
|
||||||
|
|
||||||
/* Detail view */
|
|
||||||
const detailView = document.getElementById("detail");
|
|
||||||
const detailTitle = document.getElementById("detailTitle");
|
|
||||||
const detailEventsList = document.getElementById("detailEventsList");
|
|
||||||
const detailTopicUrl = document.getElementById("detailTopicUrl");
|
|
||||||
const detailNoNotifications = document.getElementById("detailNoNotifications");
|
|
||||||
const detailCloseButton = document.getElementById("detailCloseButton");
|
|
||||||
const detailNotificationsDisallowed = document.getElementById("detailNotificationsDisallowed");
|
|
||||||
|
|
||||||
/* Screenshots */
|
/* Screenshots */
|
||||||
const lightbox = document.getElementById("lightbox");
|
const lightbox = document.getElementById("lightbox");
|
||||||
|
|
||||||
const subscribe = (topic) => {
|
|
||||||
if (Notification.permission !== "granted") {
|
|
||||||
Notification.requestPermission().then((permission) => {
|
|
||||||
if (permission === "granted") {
|
|
||||||
subscribeInternal(topic, true, 0);
|
|
||||||
} else {
|
|
||||||
showNotificationDeniedError();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
subscribeInternal(topic, true,0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const subscribeInternal = (topic, persist, delaySec) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
// Render list entry
|
|
||||||
let topicEntry = document.getElementById(`topic-${topic}`);
|
|
||||||
if (!topicEntry) {
|
|
||||||
topicEntry = document.createElement('li');
|
|
||||||
topicEntry.id = `topic-${topic}`;
|
|
||||||
topicEntry.innerHTML = `<a href="/${topic}" onclick="return showDetail('${topic}')">${topic}</a> <button onclick="test('${topic}'); return false;"> <img src="static/img/send.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/unsubscribe.svg"> Unsubscribe</button>`;
|
|
||||||
topicsList.appendChild(topicEntry);
|
|
||||||
}
|
|
||||||
topicsHeader.style.display = '';
|
|
||||||
|
|
||||||
// Open event source
|
|
||||||
let eventSource = new EventSource(`${topic}/sse`);
|
|
||||||
eventSource.onopen = () => {
|
|
||||||
topicEntry.innerHTML = `<a href="/${topic}" onclick="return showDetail('${topic}')">${topic}</a> <button onclick="test('${topic}'); return false;"> <img src="static/img/send.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/unsubscribe.svg"> Unsubscribe</button>`;
|
|
||||||
delaySec = 0; // Reset on successful connection
|
|
||||||
};
|
|
||||||
eventSource.onerror = (e) => {
|
|
||||||
topicEntry.innerHTML = `<a href="/${topic}" onclick="return showDetail('${topic}')">${topic}</a> <i>(Reconnecting)</i> <button disabled="disabled">Test</button> <button onclick="unsubscribe('${topic}'); return false;">Unsubscribe</button>`;
|
|
||||||
eventSource.close();
|
|
||||||
const newDelaySec = (delaySec + 5 <= 15) ? delaySec + 5 : 15;
|
|
||||||
subscribeInternal(topic, persist, newDelaySec);
|
|
||||||
};
|
|
||||||
eventSource.onmessage = (e) => {
|
|
||||||
const event = JSON.parse(e.data);
|
|
||||||
topics[topic]['messages'].push(event);
|
|
||||||
topics[topic]['messages'].sort((a, b) => { return a.time < b.time ? 1 : -1; }); // Newest first
|
|
||||||
if (currentTopic === topic) {
|
|
||||||
rerenderDetailView();
|
|
||||||
}
|
|
||||||
if (Notification.permission === "granted") {
|
|
||||||
notifySound.play();
|
|
||||||
const title = formatTitle(event);
|
|
||||||
const message = formatMessage(event);
|
|
||||||
const notification = new Notification(title, {
|
|
||||||
body: message,
|
|
||||||
icon: '/static/img/favicon.png'
|
|
||||||
});
|
|
||||||
notification.onclick = (e) => {
|
|
||||||
showDetail(event.topic);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
topics[topic] = {
|
|
||||||
'eventSource': eventSource,
|
|
||||||
'messages': [],
|
|
||||||
'persist': persist
|
|
||||||
};
|
|
||||||
fetchCachedMessages(topic).then(() => {
|
|
||||||
if (currentTopic === topic) {
|
|
||||||
rerenderDetailView();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
let persistedTopicKeys = Object.keys(topics).filter(t => topics[t].persist);
|
|
||||||
localStorage.setItem('topics', JSON.stringify(persistedTopicKeys));
|
|
||||||
}, delaySec * 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsubscribe = (topic) => {
|
|
||||||
topics[topic]['eventSource'].close();
|
|
||||||
delete topics[topic];
|
|
||||||
localStorage.setItem('topics', JSON.stringify(Object.keys(topics)));
|
|
||||||
document.getElementById(`topic-${topic}`).remove();
|
|
||||||
if (Object.keys(topics).length === 0) {
|
|
||||||
topicsHeader.style.display = 'none';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const test = (topic) => {
|
|
||||||
fetch(`/${topic}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
body: `This is a test notification sent by the ntfy.sh Web UI at ${new Date().toString()}.`
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchCachedMessages = async (topic) => {
|
|
||||||
const topicJsonUrl = `/${topic}/json?poll=1`; // Poll!
|
|
||||||
for await (let line of makeTextFileLineIterator(topicJsonUrl)) {
|
|
||||||
const message = JSON.parse(line);
|
|
||||||
topics[topic]['messages'].push(message);
|
|
||||||
}
|
|
||||||
topics[topic]['messages'].sort((a, b) => { return a.time < b.time ? 1 : -1; }); // Newest first
|
|
||||||
};
|
|
||||||
|
|
||||||
const showDetail = (topic) => {
|
|
||||||
currentTopic = topic;
|
|
||||||
history.replaceState(topic, `${currentUrl}/${topic}`, `/${topic}`);
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
rerenderDetailView();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const rerenderDetailView = () => {
|
|
||||||
detailTitle.innerHTML = `${currentUrl}/${currentTopic}`; // document.location.replaceAll(..)
|
|
||||||
detailTopicUrl.innerHTML = `${currentUrl}/${currentTopic}`;
|
|
||||||
while (detailEventsList.firstChild) {
|
|
||||||
detailEventsList.removeChild(detailEventsList.firstChild);
|
|
||||||
}
|
|
||||||
topics[currentTopic]['messages'].forEach(m => {
|
|
||||||
const entryDiv = document.createElement('div');
|
|
||||||
const dateDiv = document.createElement('div');
|
|
||||||
const titleDiv = document.createElement('div');
|
|
||||||
const messageDiv = document.createElement('div');
|
|
||||||
const tagsDiv = document.createElement('div');
|
|
||||||
|
|
||||||
entryDiv.classList.add('detailEntry');
|
|
||||||
dateDiv.classList.add('detailDate');
|
|
||||||
titleDiv.classList.add('detailTitle');
|
|
||||||
messageDiv.classList.add('detailMessage');
|
|
||||||
tagsDiv.classList.add('detailTags');
|
|
||||||
|
|
||||||
const dateStr = new Date(m.time * 1000).toLocaleString();
|
|
||||||
if (m.priority && [1,2,4,5].includes(m.priority)) {
|
|
||||||
dateDiv.innerHTML = `${dateStr} <img src="static/img/priority-${m.priority}.svg"/>`;
|
|
||||||
} else {
|
|
||||||
dateDiv.innerHTML = `${dateStr}`;
|
|
||||||
}
|
|
||||||
messageDiv.innerText = formatMessage(m);
|
|
||||||
entryDiv.appendChild(dateDiv);
|
|
||||||
if (m.title) {
|
|
||||||
titleDiv.innerText = formatTitleA(m);
|
|
||||||
entryDiv.appendChild(titleDiv);
|
|
||||||
}
|
|
||||||
entryDiv.appendChild(messageDiv);
|
|
||||||
const otherTags = unmatchedTags(m.tags);
|
|
||||||
if (otherTags.length > 0) {
|
|
||||||
tagsDiv.innerText = `Tags: ${otherTags.join(", ")}`;
|
|
||||||
entryDiv.appendChild(tagsDiv);
|
|
||||||
}
|
|
||||||
detailEventsList.appendChild(entryDiv);
|
|
||||||
})
|
|
||||||
if (topics[currentTopic]['messages'].length === 0) {
|
|
||||||
detailNoNotifications.style.display = '';
|
|
||||||
} else {
|
|
||||||
detailNoNotifications.style.display = 'none';
|
|
||||||
}
|
|
||||||
if (Notification.permission === "granted") {
|
|
||||||
detailNotificationsDisallowed.style.display = 'none';
|
|
||||||
} else {
|
|
||||||
detailNotificationsDisallowed.style.display = 'block';
|
|
||||||
}
|
|
||||||
detailView.style.display = 'block';
|
|
||||||
main.style.display = 'none';
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideDetailView = () => {
|
|
||||||
if (currentTopicUnsubscribeOnClose) {
|
|
||||||
unsubscribe(currentTopic);
|
|
||||||
currentTopicUnsubscribeOnClose = false;
|
|
||||||
}
|
|
||||||
currentTopic = "";
|
|
||||||
history.replaceState('', originalTitle, '/');
|
|
||||||
detailView.style.display = 'none';
|
|
||||||
main.style.display = 'block';
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const requestPermission = () => {
|
|
||||||
if (Notification.permission !== "granted") {
|
|
||||||
Notification.requestPermission().then((permission) => {
|
|
||||||
if (permission === "granted") {
|
|
||||||
detailNotificationsDisallowed.style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const showError = (msg) => {
|
|
||||||
errorField.innerHTML = msg;
|
|
||||||
topicField.disabled = true;
|
|
||||||
subscribeButton.disabled = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const showBrowserIncompatibleError = () => {
|
|
||||||
showError("Your browser is not compatible to use the web-based desktop notifications.");
|
|
||||||
};
|
|
||||||
|
|
||||||
const showNotificationDeniedError = () => {
|
|
||||||
showError("You have blocked desktop notifications for this website. Please unblock them and refresh to use the web-based desktop notifications.");
|
|
||||||
};
|
|
||||||
|
|
||||||
const showScreenshotOverlay = (e, el, index) => {
|
const showScreenshotOverlay = (e, el, index) => {
|
||||||
lightbox.classList.add('show');
|
lightbox.classList.add('show');
|
||||||
document.addEventListener('keydown', nextScreenshotKeyboardListener);
|
document.addEventListener('keydown', nextScreenshotKeyboardListener);
|
||||||
|
@ -284,91 +65,6 @@ const nextScreenshotKeyboardListener = (e) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatTitle = (m) => {
|
|
||||||
if (m.title) {
|
|
||||||
return formatTitleA(m);
|
|
||||||
} else {
|
|
||||||
return `${location.host}/${m.topic}`; // FIXME
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatTitleA = (m) => {
|
|
||||||
const emojiList = toEmojis(m.tags);
|
|
||||||
if (emojiList.length > 0) {
|
|
||||||
return `${emojiList.join(" ")} ${m.title}`;
|
|
||||||
} else {
|
|
||||||
return m.title;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatMessage = (m) => {
|
|
||||||
if (m.title) {
|
|
||||||
return m.message;
|
|
||||||
} else {
|
|
||||||
const emojiList = toEmojis(m.tags);
|
|
||||||
if (emojiList.length > 0) {
|
|
||||||
return `${emojiList.join(" ")} ${m.message}`;
|
|
||||||
} else {
|
|
||||||
return m.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const toEmojis = (tags) => {
|
|
||||||
if (!tags) return [];
|
|
||||||
else return tags.filter(tag => tag in emojis).map(tag => emojis[tag]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const unmatchedTags = (tags) => {
|
|
||||||
if (!tags) return [];
|
|
||||||
else return tags.filter(tag => !(tag in emojis));
|
|
||||||
}
|
|
||||||
|
|
||||||
// From: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
|
|
||||||
async function* makeTextFileLineIterator(fileURL) {
|
|
||||||
const utf8Decoder = new TextDecoder('utf-8');
|
|
||||||
const response = await fetch(fileURL);
|
|
||||||
const reader = response.body.getReader();
|
|
||||||
let { value: chunk, done: readerDone } = await reader.read();
|
|
||||||
chunk = chunk ? utf8Decoder.decode(chunk) : '';
|
|
||||||
|
|
||||||
const re = /\n|\r|\r\n/gm;
|
|
||||||
let startIndex = 0;
|
|
||||||
let result;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
let result = re.exec(chunk);
|
|
||||||
if (!result) {
|
|
||||||
if (readerDone) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let remainder = chunk.substr(startIndex);
|
|
||||||
({ value: chunk, done: readerDone } = await reader.read());
|
|
||||||
chunk = remainder + (chunk ? utf8Decoder.decode(chunk) : '');
|
|
||||||
startIndex = re.lastIndex = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
yield chunk.substring(startIndex, result.index);
|
|
||||||
startIndex = re.lastIndex;
|
|
||||||
}
|
|
||||||
if (startIndex < chunk.length) {
|
|
||||||
yield chunk.substr(startIndex); // last line didn't end in a newline char
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribeButton.onclick = () => {
|
|
||||||
if (!topicField.value) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
subscribe(topicField.value);
|
|
||||||
topicField.value = "";
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
detailCloseButton.onclick = () => {
|
|
||||||
hideDetailView();
|
|
||||||
};
|
|
||||||
|
|
||||||
let currentScreenshotIndex = 0;
|
let currentScreenshotIndex = 0;
|
||||||
const screenshots = [...document.querySelectorAll("#screenshots a")];
|
const screenshots = [...document.querySelectorAll("#screenshots a")];
|
||||||
screenshots.forEach((el, index) => {
|
screenshots.forEach((el, index) => {
|
||||||
|
@ -377,37 +73,6 @@ screenshots.forEach((el, index) => {
|
||||||
|
|
||||||
lightbox.onclick = hideScreenshotOverlay;
|
lightbox.onclick = hideScreenshotOverlay;
|
||||||
|
|
||||||
// Disable Web UI if notifications of EventSource are not available
|
|
||||||
if (!window["Notification"] || !window["EventSource"]) {
|
|
||||||
showBrowserIncompatibleError();
|
|
||||||
} else if (Notification.permission === "denied") {
|
|
||||||
showNotificationDeniedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset UI
|
|
||||||
topicField.value = "";
|
|
||||||
|
|
||||||
// Restore topics
|
|
||||||
const storedTopics = JSON.parse(localStorage.getItem('topics') || "[]");
|
|
||||||
if (storedTopics) {
|
|
||||||
storedTopics.forEach((topic) => { subscribeInternal(topic, true, 0); });
|
|
||||||
if (storedTopics.length === 0) {
|
|
||||||
topicsHeader.style.display = 'none';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
topicsHeader.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// (Temporarily) subscribe topic if we navigated to /sometopic URL
|
|
||||||
const match = location.pathname.match(/^\/([-_a-zA-Z0-9]{1,64})$/) // Regex must match Go & Android app!
|
|
||||||
if (match) {
|
|
||||||
currentTopic = match[1];
|
|
||||||
if (!storedTopics.includes(currentTopic)) {
|
|
||||||
subscribeInternal(currentTopic, false,0);
|
|
||||||
currentTopicUnsubscribeOnClose = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add anchor links
|
// Add anchor links
|
||||||
document.querySelectorAll('.anchor').forEach((el) => {
|
document.querySelectorAll('.anchor').forEach((el) => {
|
||||||
if (el.hasAttribute('id')) {
|
if (el.hasAttribute('id')) {
|
||||||
|
@ -425,11 +90,3 @@ document.querySelectorAll('.ntfyUrl').forEach((el) => {
|
||||||
document.querySelectorAll('.ntfyProtocol').forEach((el) => {
|
document.querySelectorAll('.ntfyProtocol').forEach((el) => {
|
||||||
el.innerHTML = window.location.protocol + "//";
|
el.innerHTML = window.location.protocol + "//";
|
||||||
});
|
});
|
||||||
|
|
||||||
// Format emojis (see emoji.js)
|
|
||||||
const emojis = {};
|
|
||||||
rawEmojis.forEach(emoji => {
|
|
||||||
emoji.aliases.forEach(alias => {
|
|
||||||
emojis[alias] = emoji.emoji;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Loading…
Reference in New Issue