53 Commits

Author SHA1 Message Date
b24ad687df tsconfig.json: commit 2017-11-12 12:57:51 +13:00
dd1c6b7968 bindata.go: rebuild 2017-11-12 12:57:42 +13:00
224263afad ts: fix this parameter when calling minifier-helper versions of document functions 2017-11-12 12:57:38 +13:00
d2dd96dcd3 ts: add minifier helpers, add a ton of function comments 2017-11-12 12:52:51 +13:00
48d58f4cc2 typescript: fix issue with el() function removal 2017-11-12 12:37:12 +13:00
19a665d61d typescript: initial package conversion 2017-11-12 12:21:52 +13:00
d5f6a5f2cb makefile: add separate all / dist targets 2017-11-12 11:09:52 +13:00
a17886e300 webpack: fix loading socket.io dependency inside webpack build 2017-11-12 11:09:44 +13:00
3af9423871 css: simplify nesting by employing some LESS features 2017-11-12 10:57:55 +13:00
5a6c798e93 package.json: re-sort dependency entries 2017-11-12 10:51:31 +13:00
02e8b407c3 reinstate css minification, rename *.css to *.less 2017-11-12 10:51:09 +13:00
e44298c172 hgignore 2017-11-12 10:39:21 +13:00
8df09ddb11 package.json: fill in metadata fields to suppress some warnings from npm 2017-11-12 10:39:17 +13:00
bd59534bac makefile: use explicit paths to binary dependencies in $GOPATH/bin 2017-11-12 10:39:05 +13:00
0679ad31a7 makefile: reinstate copying in remaining file assets 2017-11-12 10:38:47 +13:00
83ecd84d78 makefile: fix webpack path to bundle.min.js file 2017-11-12 10:38:35 +13:00
055a73fb05 makefile: use hg/git archive command to build source tarball 2017-11-12 10:36:42 +13:00
584a6b632f makefile: add clean-deps target 2017-11-12 10:35:46 +13:00
d90b08f45e node: commit package-lock.json 2017-11-12 10:31:25 +13:00
7934c926d9 Replace install deps script with a simple "npm i" 2017-11-10 09:53:14 +00:00
hanneshdc
8364e9a146 Add typescript and typescript loader 2017-11-10 21:03:58 +13:00
hanneshdc
ab89f5f93f Remove from code from makefile that is now handled by webpack 2017-11-10 20:45:31 +13:00
hanneshdc
29bcf75470 Install webpack and create a webpack config 2017-11-10 20:38:47 +13:00
hanneshdc
fcddbf85b0 Add package.json and gitignore 2017-11-10 19:56:24 +13:00
54e21f2b2d clear owner/group from linux64 release tarball 2017-10-28 14:15:23 +13:00
dd166cf0e9 doc: mention supercedes 2017-10-28 14:00:48 +13:00
92b1c4daa5 doc: fix cosmetic issue with readme generation on code.ivysaur.me 2017-10-28 13:43:02 +13:00
ea4135888d bump all versions to 1.2.3 2017-10-28 13:32:29 +13:00
8e999f5ddb Added tag v1.2.2 for changeset 0c6b957de432 2017-10-28 13:32:16 +13:00
62c03cf9f1 doc: mention download options 2017-10-28 13:30:51 +13:00
6abdc8d2a9 server: use real content length, use system MIME info instead of handrolling it 2017-10-28 13:27:44 +13:00
1a281095f0 regenerate bindata.go 2017-10-28 13:27:19 +13:00
69613d07a5 build: remove timestamps from generated bindata.go file 2017-10-28 13:27:07 +13:00
19b2221ea1 doc: mention unminified development instructions 2017-10-28 13:24:18 +13:00
9840c1024e doc: preliminary changelog update 2017-10-28 13:17:50 +13:00
00cdce5f5a doc: add instructions on setting up a development environment 2017-10-28 13:17:13 +13:00
312cbb7bc1 commit a copy of bindata.go, to allow installation via go get 2017-10-28 13:11:05 +13:00
bea598f7a3 retag in vX.Y.Z format 2017-10-28 12:53:54 +13:00
ef9a61e9cf hgignore vendor directory 2017-10-28 12:49:10 +13:00
0ec079cfd4 use 'dep' for dependency management 2017-10-28 12:48:55 +13:00
54ecffd0d4 build: remove dead code 2017-10-28 11:56:11 +13:00
41e244c255 build: replace minipack shell script with sed commands 2017-10-28 11:51:23 +13:00
a109e2dc29 build: replace IIFEMODE/sed with cat in makefile 2017-10-28 11:40:09 +13:00
0bafa59358 build: remove php, replace with bash script 2017-10-28 11:32:51 +13:00
78ced31e9d further conversion to makefile build 2017-10-28 00:21:20 +13:00
16a4a2556b partial conversion to makefile build 2017-10-28 00:06:45 +13:00
fafca96711 fix not being able to close PM tabs 2017-10-27 23:44:18 +13:00
2eacb06c9e Added tag release-1.2.1 for changeset c8cd84947e45 2017-10-16 18:48:21 +13:00
1f2871b917 doc: preliminary changelog update 2017-10-16 18:47:32 +13:00
855206feed hide (0) from page title 2017-10-16 18:33:43 +13:00
efa195df5b bump scrollback limit from 50->200 2017-10-16 18:30:56 +13:00
89c8cb0dc8 contented: fix upload item disappearing once logged in 2017-10-15 22:55:00 +13:00
c2de4c8d45 Added tag release-1.2.0 for changeset 0eeab5594ba4 2017-10-15 22:54:41 +13:00
20 changed files with 5697 additions and 492 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
clientpack/**
node_modules/**

View File

@@ -3,6 +3,10 @@ mode:regex
\.exe$
^nmdc-webfrontend\.conf$
^clientpack/
^node_modules/
^_dist/
^bindata\.go$
^vendor/
^nmdc-webfrontend$
^nmdc-webfrontend\.exe$

19
.hgtags
View File

@@ -1,8 +1,11 @@
769fad81e3f8db8f7e5f5c164656a382a169d735 release-1.0.0
9ed95938d809a8226aca529e34b655e6d8c8c379 release-1.0.1
46fe533682419c8a519836ac95b5575053aa0fa8 release-1.0.2
a2c92b262f339f82eb01c8d92dda252a27432255 release-1.1.0
d14041daa7bbbd37ea2ff47aa978b9595af67ca3 release-1.1.1
7278eb0d067d8ed2a653de6a1feeeb7f76fb9891 release-1.1.2
6cbd9d59630372c0dff430e3dc6c1fbd7dcee734 release-1.1.3
76c178b8f27ec894e79b8f73649fcb3e45a73729 release-1.1.4
769fad81e3f8db8f7e5f5c164656a382a169d735 v1.0.0
9ed95938d809a8226aca529e34b655e6d8c8c379 v1.0.1
46fe533682419c8a519836ac95b5575053aa0fa8 v1.0.2
a2c92b262f339f82eb01c8d92dda252a27432255 v1.1.0
d14041daa7bbbd37ea2ff47aa978b9595af67ca3 v1.1.1
7278eb0d067d8ed2a653de6a1feeeb7f76fb9891 v1.1.2
6cbd9d59630372c0dff430e3dc6c1fbd7dcee734 v1.1.3
76c178b8f27ec894e79b8f73649fcb3e45a73729 v1.1.4
0eeab5594ba4d683e6a268ef971675c73b226bd0 v1.2.0
c8cd84947e4516215e50639914adfaecf350fe91 v1.2.1
0c6b957de43252f89688ba73c4857f6d912b2912 v1.2.2

23
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,23 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"showOutput": "always",
"suppressTaskName": true,
"tasks": [
{
"taskName": "install",
"args": ["install"]
},
{
"taskName": "update",
"args": ["update"]
},
{
"taskName": "test",
"args": ["run", "test"]
}
]
}

33
Gopkg.lock generated Normal file
View File

@@ -0,0 +1,33 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "code.ivysaur.me/libnmdc"
packages = ["."]
revision = "21847db9fdc1b983285de44e789cd9e921bdf1bb"
version = "v0.14.0"
[[projects]]
branch = "master"
name = "github.com/googollee/go-engine.io"
packages = [".","message","parser","polling","transport","websocket"]
revision = "80ae0e43aca17b4c5a6834999d0f2eaa16b9afda"
[[projects]]
branch = "master"
name = "github.com/googollee/go-socket.io"
packages = ["."]
revision = "5447e71f36d394766bf855d5714a487596809f0d"
[[projects]]
name = "github.com/gorilla/websocket"
packages = ["."]
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
version = "v1.2.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "928468c40a3a664870459e1d5a1fa97fcbc45802fdd498ebf89bcffe0b44ec6e"
solver-name = "gps-cdcl"
solver-version = 1

30
Gopkg.toml Normal file
View File

@@ -0,0 +1,30 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "code.ivysaur.me/libnmdc"
version = "0.14.0"
[[constraint]]
branch = "master"
name = "github.com/googollee/go-socket.io"

59
Makefile Normal file
View File

@@ -0,0 +1,59 @@
# Makefile for nmdc-webfrontend
BINNAME=nmdc-webfrontend
VERSION=1.2.3
GOFLAGS=-a \
-ldflags "-s -w -X main.VERSION=$(BINNAME)/$(VERSION)" \
-gcflags "-trimpath ${GOPATH}" \
-asmflags "-trimpath ${GOPATH}"
.PHONY: all dist deps clean clean-deps
all: $(BINNAME) $(BINNAME).exe
dist: $(BINNAME)-$(VERSION)-win32.7z $(BINNAME)-$(VERSION)-linux64.tar.xz $(BINNAME)-$(VERSION)-src.zip
deps:
npm i
go get -u github.com/jteeuwen/go-bindata/...
go get -u github.com/golang/dep/cmd/dep
$(GOPATH)/bin/dep ensure
clean:
rm -f ./$(BINNAME)
rm -f ./$(BINNAME).exe
rm -fr ./clientpack
rm -f ./bindata.go
clean-deps:
rm -fr ./vendor
rm -fr ./node_modules
bindata.go: client client/*
mkdir -p clientpack
cp client/favicon.ico client/apple-touch-icon.png clientpack/
npm run webpack
cat client/index.htm \
| sed -e '/bundle.js/{i <script>' -e 'r clientpack/bundle.min.js' -e 'a </script>' -e 'd}' \
> clientpack/index.htm
html-minifier --collapse-whitespace -o clientpack/index.min.htm clientpack/index.htm
mv clientpack/index.min.htm clientpack/index.htm
rm clientpack/bundle.min.js
$(GOPATH)/bin/go-bindata -nomemcopy -nometadata -prefix clientpack clientpack
$(BINNAME).exe: bindata.go *.go
GOARCH=386 GOOS=windows go build $(GOFLAGS) -o $(BINNAME).exe
$(BINNAME): bindata.go *.go
GOARCH=amd64 GOOS=linux go build $(GOFLAGS) -o $(BINNAME)
$(BINNAME)-$(VERSION)-win32.7z: $(BINNAME).exe nmdc-webfrontend.conf.SAMPLE
7z a -mx9 "$(BINNAME)-$(VERSION)-win32.7z" $(BINNAME).exe nmdc-webfrontend.conf.SAMPLE
$(BINNAME)-$(VERSION)-linux64.tar.xz: $(BINNAME) nmdc-webfrontend.conf.SAMPLE
XZ_OPT='-9' tar caf "$(BINNAME)-$(VERSION)-linux64.tar.xz" $(BINNAME) nmdc-webfrontend.conf.SAMPLE --owner=0 --group=0
$(BINNAME)-$(VERSION)-src.zip:
hg archive "$(BINNAME)-$(VERSION)-src.zip" || git archive -o "$(BINNAME)-$(VERSION)-src.zip" HEAD

View File

@@ -6,13 +6,38 @@ Written in Golang
Tags: nmdc
This project supercedes [entry=dcwebui]dcwebui[/entry], [entry=flexdc]flexdc[/entry], and [entry=dcwebui2]dcwebui2[/entry].
=UPGRADING FROM DCWEBUI2=
- The configuration file content is identical between nmdc-webfrontend 1.0.0 and dcwebui2 1.3.0, but please now ensure it's valid JSON instead of arbitrary javascript. This means no assignment, use double-quoted strings, and no comments.
- Future changes to the configuration file since nmdc-webfrontend 1.0.0 are backward compatible (see the changelog for more details).
=DEVELOPING=
[go-get]code.ivysaur.me/nmdc-webfrontend git https://git.ivysaur.me/code.ivysaur.me/nmdc-webfrontend.git[/go-get]
1. Install Go, Node.js, NPM, and 7-Zip (`p7zip-full` on Debian)
2. Set up your `$GOPATH`
3. Download the source code
    - `git clone https://git.ivysaur.me/code.ivysaur.me/nmdc-webfrontend.git `; or
    - `go get code.ivysaur.me/nmdc-webfrontend` ; or
    - download and extract a source archive
4. Install dependencies: `sudo make deps`
5. Build: `make`
6. Optional: Set `web.external_webroot: true` in the config file for unminified development
=CHANGELOG=
2017-10-28 1.2.2
- Enhancement: Simplify build process
- Fix an issue with closing PM tabs
2017-10-16 1.2.1
- Enhancement: Increase scrollback buffer size
- Fix an issue with missing `contented` upload link once logged in
- Fix a cosmetic issue with `(0)` appearing in page title
2017-10-15 1.2.0
- Feature: Add `contented` integration (set `app.contented_server` in config file)
- Fix a cosmetic issue with the menu icon on devices without unicode font coverage

281
bindata.go Normal file

File diff suppressed because one or more lines are too long

184
build.sh
View File

@@ -1,184 +0,0 @@
#!/bin/bash
# godist.sh is a template build script for golang applications.
#
# Copyright (c) 2016, The godist.sh Author(s)
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
set -eu
DIST_DIR=./_dist
EXTRA_FILES=(
nmdc-webfrontend.conf.SAMPLE
)
get_package_name() {
# Binaries are named after the containing folder.
pwd | tr / $'\n' | tail -n1
}
check_dependencies() {
# `set -e` will take care of killing the application if the dependency
# goes unresolved.
which 7z > /dev/null
which php > /dev/null
}
get_platform_description() {
if [[ $GOOS == windows ]] ; then
echo -n "win"
else
echo -n "${GOOS}"
fi
if [[ $GOARCH == 386 ]] ; then
echo -n 32
elif [[ $GOARCH == amd64 ]] ; then
echo -n 64
else
echo -n "-${GOARCH}"
if [[ -v $GOARM ]] ; then
echo -n "v${GOARM}"
fi
fi
}
pathfix() {
if [[ $(uname -o) == Cygwin ]] ; then
cygpath -w "$1"
else
echo "$1"
fi
}
single_build() {
local version="$1"
# Determine build output name
local bin_name=''
if [[ $GOOS == windows ]] ; then
local_bin_name="$(get_package_name).exe"
else
local_bin_name="$(get_package_name)"
fi
if [[ -f ./$local_bin_name ]] ; then
rm -f "./$local_bin_name"
fi
local tmpdir=$(mktemp -d)
# Platform identifier
local platform="$(get_platform_description)"
echo "[INFO] Building ${version} for ${platform}..."
# Build.
# GOARCH/GOOS supplied in function env
local gofwdpath=$(echo -n $GOPATH | sed 's/[\\/]$//')
go build \
-a \
-ldflags "-s -w -X main.VERSION=nmdc-webfrontend/${version}" \
-gcflags "-trimpath ${gofwdpath}" \
-asmflags "-trimpath ${gofwdpath}" \
-o "$(pathfix "${tmpdir}/${local_bin_name}")"
# Archive.
if [[ ! -d $DIST_DIR ]] ; then
mkdir "$DIST_DIR"
fi
local archive_name="${DIST_DIR}/$(get_package_name)-${version}-${platform}"
if [[ $GOOS == windows ]] ; then
archive_name="${archive_name}.7z"
7z a -mx9 "$archive_name" "${tmpdir}/${local_bin_name}" "${EXTRA_FILES[@]}" >/dev/null
else
archive_name="${archive_name}.tar.xz"
XZ_OPT='-9' tar caf "$archive_name" -C "${tmpdir}" "${local_bin_name}" -C "$(pwd)" "${EXTRA_FILES[@]}" --owner=0 --group=0 >/dev/null
fi
# Cleanup
rm -f "${tmpdir}/${local_bin_name}"
rmdir "$tmpdir"
}
datestamp() {
( TZ=UTC date +%Y%m%d%H%M%SZ )
}
usage() {
cat <<EOD
Usage: ./godist.sh [-v VERSION]
EOD
exit 0
}
main() {
check_dependencies
if [[ ! -v GOPATH ]] ; then
echo "Please set GOPATH." >&2
exit 1
fi
if [[ ! -d $GOPATH ]] ; then
echo "Invalid GOPATH set." >&2
exit 1
fi
local version=""
while getopts ':v:' flag ; do
case "$flag" in
v)
version="$OPTARG"
;;
*)
usage
;;
esac
done
if [[ $version == "" ]] ; then
read -p "Enter version string (blank for timestamp)> " version
if [[ $version == "" ]] ; then
version=$(datestamp)
fi
fi
if [[ -f ./bindata.go ]] ; then
rm ./bindata.go
fi
php clientpack.php
go-bindata -nomemcopy -prefix clientpack clientpack
GOARCH=386 GOOS=windows single_build "$version"
GOARCH=amd64 GOOS=linux single_build "$version"
# Also make source tarball
local SOURCE_FILES=(
client/
build.sh
clientpack.php
Config.go
main.go
nmdc-webfrontend.conf.SAMPLE
)
XZ_OPT='-9' tar caf "_dist/$(get_package_name)-${version}-src.tar.xz" "${SOURCE_FILES[@]}" --owner=0 --group=0 >/dev/null
echo "[INFO] Build complete."
}
main "$@"

View File

@@ -51,14 +51,16 @@ html,body {
}
/* WiiU placements */
.navigator-wiiu .placement-mid {
bottom:120px;
}
.navigator-wiiu .placement-bottom {
height:120px;
}
.navigator-wiiu .placement-panel {
bottom:120px;
.navigator-wiiu {
.placement-mid {
bottom:120px;
}
.placement-bottom {
height:120px;
}
.placement-panel {
bottom:120px;
}
}
/* Menu button */
@@ -75,14 +77,17 @@ html,body {
height:18px;
width:18px;
text-align:center;
svg {
width: 18px;
height: 18px;
}
&:hover {
background:white;
}
}
.menubutton svg {
width: 18px;
height: 18px;
}
.menubutton:hover {
background:white;
}
/* Menu list */
.menu {
background:#DDD;
@@ -97,20 +102,24 @@ html,body {
z-index:10; /* above placement-panel */
overflow-y:auto;
ul {
margin:0;
padding:0;
}
li {
list-style-type:none;
padding:6px;
cursor:pointer;
&:hover {
background:#333;
color:white;
}
}
}
.menu ul {
margin:0;
padding:0;
}
.menu li {
list-style-type:none;
padding:6px;
cursor:pointer;
}
.menu li:hover {
background:#333;
color:white;
}
/* Tabs */
.tabbar {
position:relative;
@@ -132,16 +141,20 @@ html,body {
border-right:1px solid lightgrey;
margin-top:2px;
padding:0 8px;
&:hover {
border-top:2px solid #EEE;
}
&.selected {
border-top:2px solid darkgreen;
}
&.unread {
background:lightyellow;
}
}
.tabitem:hover {
border-top:2px solid #EEE;
}
.tabitem.selected {
border-top:2px solid darkgreen;
}
.tabitem.unread {
background:lightyellow;
}
.tab-label {
cursor:pointer;
}
@@ -170,12 +183,14 @@ html,body {
-webkit-transition:0.1s linear all;
-moz-transition:0.1s linear all;
transition:0.1s linear all;
&:hover {
background:#FFDDDD;
border:1px solid red;
color:black;
}
}
.tab-closer:hover {
background:#FFDDDD;
border:1px solid red;
color:black;
}
/* */
.content {
display:block;
@@ -241,7 +256,10 @@ html,body {
}
#submit-container {
position:absolute;
top:0;bottom:0;right:0;width:32px;
top:0;
bottom:0;
right:0;
width:32px;
}
#btsubmit {
width:100%;
@@ -265,42 +283,42 @@ html,body {
-webkit-border-radius: 12px;
-moz-border-radius: 12px;
border-radius: 12px;
}
.ul-large li {
color: #333;
font: bold 15px Geneva, Arial, Helvetica, sans-serif;
vertical-align: middle;
border-bottom: 1px solid #ccc;
list-style-type: none;
text-align: left;
white-space: nowrap;
overflow: hidden;
height: 30px;
list-style-type: none;
display: block;
padding: 15px 5px 5px 10px;
}
.ul-large li:first-child {
border-top: 0;
-webkit-border-top-left-radius: 12px;
-webkit-border-top-right-radius: 12px;
-moz-border-top-left-radius: 12px;
-moz-border-top-right-radius: 12px;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
}
.ul-large li:last-child {
border-bottom: 0;
-webkit-border-bottom-left-radius: 12px;
-webkit-border-bottom-right-radius: 12px;
-moz-border-bottom-left-radius: 12px;
-moz-border-bottom-right-radius: 12px;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
}
.ul-large li {
cursor:pointer;
li {
color: #333;
font: bold 15px Geneva, Arial, Helvetica, sans-serif;
vertical-align: middle;
border-bottom: 1px solid #ccc;
list-style-type: none;
text-align: left;
white-space: nowrap;
overflow: hidden;
height: 30px;
list-style-type: none;
display: block;
padding: 15px 5px 5px 10px;
cursor:pointer;
&:first-child {
border-top: 0;
-webkit-border-top-left-radius: 12px;
-webkit-border-top-right-radius: 12px;
-moz-border-top-left-radius: 12px;
-moz-border-top-right-radius: 12px;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
}
&:last-child {
border-bottom: 0;
-webkit-border-bottom-left-radius: 12px;
-webkit-border-bottom-right-radius: 12px;
-moz-border-bottom-left-radius: 12px;
-moz-border-bottom-right-radius: 12px;
border-bottom-left-radius: 12px;
border-bottom-right-radius: 12px;
}
}
}
/* Text */
@@ -368,19 +386,21 @@ html,body {
.ul-mini {
padding-left: 4px;
margin-top:4px;
}
.ul-mini li {
list-style-type:none;
min-height:13px;
line-height:13px;
padding-left:14px;
margin-bottom:5px;
cursor:pointer;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAANCAYAAACQN/8FAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABh0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzT7MfTgAAAZJJREFUKJFtz71rE2EAgPHnrknbXBKkLWhx0DhoWsEOxk0taMGlQ7cimElK5uroH5DFSUQ3KQpV2qlQEDJ4mKFQ0MVS6kfN1dQP2ss1ydW79y6Xu3udBG36zL/lUaSUVKtVqes6hmGgaRqlUulUoVAw+ScV4P2bFfrEPhnF4+v2NuVy+QFHSjiNXWV2cgzh+dRqX1hsNflcr5/tgcJ14larSdDxCYIOuWEV0c3+7oEAxk4NANu2GUnFFIt3FnvgydxFZb9hSRmFCCGwmjb3i3OVo1AFyF2bZm/PxDRN4rDDo4WHt4+F77RfmKNZ1MQA9ukTPPeXXt14OvXita5f+guVJ+uPZ1brlZUJI08qG/F26AP9chDXO8RpeyzNvMyMnc+7fembmU9WYJFXL7M1YtBNhqRIEYURh1Gb/u+DH69fubqRaLQOcAccHDy++TW0pEaATzcOkFHMxs/NCQD13oV50laaH/EuQdhBhAIRClzF/W9GkVIC8Gx54dZafa3SDmxc1SEdZxgfHmdu+m7y3Jlc+AextbuG6q1RSQAAAABJRU5ErkJggg==') no-repeat 0 0;
}
.ul-mini li:hover {
background-color:#EEE;
li {
list-style-type:none;
min-height:13px;
line-height:13px;
padding-left:14px;
margin-bottom:5px;
cursor:pointer;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAANCAYAAACQN/8FAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABh0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzT7MfTgAAAZJJREFUKJFtz71rE2EAgPHnrknbXBKkLWhx0DhoWsEOxk0taMGlQ7cimElK5uroH5DFSUQ3KQpV2qlQEDJ4mKFQ0MVS6kfN1dQP2ss1ydW79y6Xu3udBG36zL/lUaSUVKtVqes6hmGgaRqlUulUoVAw+ScV4P2bFfrEPhnF4+v2NuVy+QFHSjiNXWV2cgzh+dRqX1hsNflcr5/tgcJ14larSdDxCYIOuWEV0c3+7oEAxk4NANu2GUnFFIt3FnvgydxFZb9hSRmFCCGwmjb3i3OVo1AFyF2bZm/PxDRN4rDDo4WHt4+F77RfmKNZ1MQA9ukTPPeXXt14OvXita5f+guVJ+uPZ1brlZUJI08qG/F26AP9chDXO8RpeyzNvMyMnc+7fembmU9WYJFXL7M1YtBNhqRIEYURh1Gb/u+DH69fubqRaLQOcAccHDy++TW0pEaATzcOkFHMxs/NCQD13oV50laaH/EuQdhBhAIRClzF/W9GkVIC8Gx54dZafa3SDmxc1SEdZxgfHmdu+m7y3Jlc+AextbuG6q1RSQAAAABJRU5ErkJggg==') no-repeat 0 0;
&:hover {
background-color:#EEE;
}
}
}
/* Display userlist alongside main chat for wide screens */

View File

@@ -1,30 +1,37 @@
/* dcwebui.js */
//IIFEMODE:;(function() {
import "./dcwebui.less"; // for webpack
import * as io from 'socket.io-client'
"use strict";
/**
* Display value when loading a saved password
*/
var SENTINEL_PASSWORD = "************";
var CHAT_SCROLLBACK_LIMIT = 50; // Once over 2x $limit, the first $limit will be trimmed off the list
/**
* Number of lines of chat to keep in the scroll area.
* Once there are over 2x $limit lines, the first $limit lines will be trimmed off the list
*/
var CHAT_SCROLLBACK_LIMIT = 200;
/**
* Our externally-accessible URL
*/
var EXTERN_ROOT = window.location.protocol + "//" + window.location.host + "/";
var el = function(s) {
// There used to be a querySelectorAll implementation, but, better that we don't have
// potentially-incompatible implementations if this one does actually work.
// i'm not writing a selector engine...
if (! s.length) {
return [];
}
if (s[0] === '#') {
return document.getElementById(s.slice(1)); // single element
} else if (s[0] === '.') {
return document.getElementsByClassName(s.slice(1)); // multiple elements
} else {
return document.getElementsByTagName(s); // multiple elements
}
};
// Help out the braindead minifier, use these functions instead
var document_getElementById = function(x) { return document.getElementById(x); }
var document_getElementsByClassName = function(x) { return document.getElementsByClassName(x); }
var document_createElement = function(x) { return document.createElement(x); }
var nmdc_escape = function(str) {
/**
* Encode a string for NMDC
*
* @param str
*/
var nmdc_escape = function(str: string): string {
return (
(''+str).length
? (''+str).replace(/&/g,'&amp;').replace(/\|/g,'&#124;').replace(/\$/g,'&#36;')
@@ -32,14 +39,24 @@ var nmdc_escape = function(str) {
);
};
var hesc = function(s) {
/**
* Encode a string for HTML
*
* @param s
*/
var hesc = function(s: string): string {
var filter = {
'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&#34;', '\'': '&#39;'
};
return s.toString().replace(/[&<>'"]/g, function(s) { return filter[s]; });
};
var fmtBytes = function(b) {
/**
* Format a number of bytes as a human-readable string
*
* @param b
*/
var fmtBytes = function(b: number): string {
if (b == 0) {
return '(nothing)';
}
@@ -50,12 +67,21 @@ var fmtBytes = function(b) {
return parseFloat((b / Math.pow(k, i)).toFixed(3)) + sizes[i];
};
var urldesc = function(s) {
/**
* Decode a string that was previously encoded in raw-url format.
*
* @param s
*/
var urldesc = function(s: string):string {
return decodeURIComponent(s.replace(/\+/g, " "));
}
var linkify = function(str) {
/**
* Enhance an HTML string by automatically making links clickable, etc.
*
* @param str An HTML-safe string
*/
var linkify = function(str : string):string {
// n.b. str is already hesced
return (str
.replace(
@@ -69,17 +95,39 @@ var linkify = function(str) {
);
};
var sanitise = function(s) {
/**
* Convert a plain-text string into an enhanced, HTML-safe string.
*
* @param s
*/
var sanitise = function(s:string): string {
return linkify(hesc(s));
};
var textContent = function($el) {
if ($el.textContent) return $el.textContent;
if ($el.innerText) return $el.innerText;
/**
* Retrieve the plain-text content from an HTML element in a browser-compatible way.
*
* @param $el
*/
var textContent = function($el : HTMLElement) : string {
if ($el.textContent) {
return $el.textContent;
}
if ($el.innerText) {
return $el.innerText;
}
return "";
};
var negmod = function(l, r) {
/**
* Calculate the positive modulo of (l % r).
*
* @param l
* @param r
*/
var negmod = function(l:number, r:number):number {
var ret = l % r;
if (l < 0) {
return ret + r;
@@ -88,16 +136,27 @@ var negmod = function(l, r) {
}
};
// @ref https://developer.mozilla.org/en/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
var b64 = function(str) {
/**
* Encode a string to base64 in a UTF8-safe way.
*
* @ref https://developer.mozilla.org/en/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
* @param str
*/
var b64 = function(str : string):string {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
return String.fromCharCode(parseInt('0x' + p1));
})).replace(/=/g, '');
}
// @ref https://gist.github.com/eligrey/1276030
var appendInnerHTML = function($el, html) {
var child = document.createElement("span");
/**
* Append content to an HTML element in a browser-compatible way.
*
* @ref https://gist.github.com/eligrey/1276030
* @param $el
* @param html
*/
var appendInnerHTML = function($el: HTMLElement, html:string) {
var child = document_createElement("span");
child.innerHTML = html;
var node;
@@ -106,30 +165,48 @@ var appendInnerHTML = function($el, html) {
}
};
// @ref http://stackoverflow.com/a/5598797
function getOffsetLeft( elem ) {
/**
* Retrieve the left offset of a DOM element relative to the document.
*
* @ref http://stackoverflow.com/a/5598797
* @param elem
*/
function getOffsetLeft( elem: HTMLElement ):number {
var offsetLeft = 0;
do {
if (!isNaN(elem.offsetLeft)) {
offsetLeft += elem.offsetLeft;
}
} while (elem = elem.offsetParent);
} while (elem = <HTMLElement>elem.offsetParent);
return offsetLeft;
}
function getOffsetTop( elem ) {
/**
* Retrieve the top offset for a DOM element relative to the document.
*
* @ref http://stackoverflow.com/a/5598797
* @param elem
*/
function getOffsetTop( elem: HTMLElement ):number {
var offsetTop = 0;
do {
if (!isNaN(elem.offsetTop)) {
offsetTop += elem.offsetTop;
}
} while (elem = elem.offsetParent);
} while (elem = <HTMLElement>elem.offsetParent);
return offsetTop;
}
/* */
var date_format = function(d, format) {
/**
* Format a string in a date format, analgous to strftime().
*
* @param d
* @param format Formatting string, supporting HisYmd character specifiers
* @return Plain text string
*/
var date_format = function(d:Date, format:string):string {
var pad = function(s) {
return (s < 10) ? '0'+s : ''+s ;
};
@@ -138,20 +215,25 @@ var date_format = function(d, format) {
ret = ret.replace(/H/g, pad(d.getHours()));
ret = ret.replace(/i/g, pad(d.getMinutes()));
ret = ret.replace(/s/g, pad(d.getSeconds()));
ret = ret.replace(/Y/g, d.getFullYear());
ret = ret.replace(/Y/g, "" + d.getFullYear());
ret = ret.replace(/m/g, pad(d.getMonth() + 1));
ret = ret.replace(/d/g, pad(d.getDate()));
return ret;
};
/* */
var notify = function(title, body, tab) {
/**
* Emit an HTML5 notification.
*
* @param title
* @param body
* @param tab
*/
var notify = function(title:string, body:string, tab:string) {
if (!("Notification" in window)) {
return; // not supported by browser
}
switch (window.Notification.permission) {
switch ( (window as any).Notification.permission) {
case "granted": {
var n = new Notification(title, {
body: body,
@@ -170,7 +252,7 @@ var notify = function(title, body, tab) {
default: {
// Clarify permission and retry
Notification.requestPermission(function(permission) {
notify(title, body);
notify(title, body, "tab-main");
});
} break;
}
@@ -179,7 +261,7 @@ var notify = function(title, body, tab) {
/* Tab writers */
var write = function(tab) {
var $tab = el('#inner-'+tab);
var $tab = document_getElementById("inner-"+tab);
return {
'cls': function() {
$tab.innerHTML = '';
@@ -255,11 +337,11 @@ var userlist = {
'add': function(u) {
if (this.has(u)) return;
var userlists = el(".userlist");
var userlists = document_getElementsByClassName("userlist");
for (var l = 0, e = userlists.length; l !== e; ++l) {
var userlist = userlists[l];
var to_add = document.createElement('li');
var to_add = document_createElement('li');
to_add.className = "user-" + b64(u);
to_add.innerHTML = hesc(u);
@@ -284,7 +366,7 @@ var userlist = {
return this;
},
'del': function(u) {
var userlists = el(".userlist");
var userlists = document_getElementsByClassName("userlist");
for (var l = 0, e = userlists.length; l !== e; ++l) {
if (! userlists[l].children) continue;
var userlist = userlists[l];
@@ -301,7 +383,7 @@ var userlist = {
return this;
},
'clear': function() {
var userlists = el(".userlist");
var userlists = document_getElementsByClassName("userlist");
for (var i in userlists) {
if (! userlists[i].children) continue;
var userlist = userlists[i];
@@ -314,22 +396,22 @@ var userlist = {
return this;
},
'names': function() {
var userlist = el(".userlist")[0].children;
var userlist = document_getElementsByClassName("userlist")[0].children;
var ret = [];
for (var i = 0, e = userlist.length; i < e; ++i) {
ret.push( textContent(userlist[i]) );
ret.push( textContent((<HTMLElement>userlist[i])) );
}
return ret;
},
'has': function(u) {
return el(".user-" + b64(u)).length !== 0; /* there are two - large and non-large */
return document_getElementsByClassName("user-" + b64(u)).length !== 0; /* there are two - large and non-large */
},
'count': function() {
return el(".userlist")[0].children.length;
return document_getElementsByClassName("userlist")[0].children.length;
},
'setInfo': function(nick, props) {
var baseClass = "user-" + b64(nick);
var $el = el("." + baseClass);
var $el = document_getElementsByClassName("" + baseClass);
var prop_str = [];
if (props.Description.length > 0) {
prop_str.push(props.Description);
@@ -346,7 +428,7 @@ var userlist = {
prop_str.push("Sharing " + fmtBytes(props.ShareSize));
for (var i = 0; i < $el.length; ++i) {
$el[i].title = prop_str.join("\n");
(<HTMLElement> $el[i]).title = prop_str.join("\n");
if (props.IsOperator) {
$el[i].className = baseClass + " user-is-operator";
@@ -358,7 +440,7 @@ var userlist = {
};
var submit = function() {
var str = el("#chatbox").value;
var str = (<HTMLInputElement>document_getElementById("chatbox")).value;
if (! str.length) return;
if (hub_state === STATE_READY_FOR_LOGIN) {
@@ -384,7 +466,7 @@ var submit = function() {
write("tab-main").system("Connecting...");
} else if (hub_state === STATE_ACTIVE) {
if (pm_target !== false) {
if (pm_target !== PM_TARGET_NONE) {
sock.emit('priv', {'user': pm_target, 'message': str});
writerFor(pm_target).pub(hub_last_nick, str );
} else {
@@ -401,7 +483,7 @@ var submit = function() {
write("tab-main").system("Invalid internal state.");
}
el("#chatbox").value = '';
(<HTMLInputElement>document_getElementById("chatbox")).value = '';
};
/* page visibility */
@@ -414,10 +496,10 @@ var pagevis_setup = function(fnActive, fnInactive) {
if (typeof document.hidden !== "undefined") {
h = "hidden";
vc = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
} else if (typeof (document as any).msHidden !== "undefined") {
h = "msHidden";
vc = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
} else if (typeof (document as any).webkitHidden !== "undefined") {
h = "webkitHidden";
vc = "webkitvisibilitychange";
}
@@ -448,13 +530,13 @@ var pagevis_setup = function(fnActive, fnInactive) {
*/
var tab_set = function(tab) {
var tabs = el(".tabpane");
var tabs = document_getElementsByClassName("tabpane");
for (var i in tabs) {
try {
tabs[i].style.display = (tabs[i].id === tab ? 'block' : 'none');
(<HTMLElement> tabs[i]).style.display = (tabs[i].id === tab ? 'block' : 'none');
} catch (e) {};
}
var tabitems = el(".tabitem");
var tabitems = document_getElementsByClassName("tabitem");
for (var i in tabitems) {
try {
// Update UNREAD/SELECTED flags for the target
@@ -467,7 +549,7 @@ var tab_set = function(tab) {
} catch (e) {};
}
pm_target = false;
pm_target = PM_TARGET_NONE;
for (var i in pm_tabs) {
if (pm_tabs[i] === tab) {
pm_target = i;
@@ -482,13 +564,13 @@ var tab_set = function(tab) {
updateTitle();
write(tab).scroll();
el("#chatbox").focus();
document_getElementById("chatbox").focus();
last_tab = tab;
};
var tab_new = function(id, name) {
appendInnerHTML(el("#bar"),
appendInnerHTML(document_getElementById("bar"),
' <div class="tabitem" data-tab="tab-ext-'+id+'" id="tabitem-tab-ext-'+id+'">'+
'<span class="tab-label">'+
hesc(name)+
@@ -496,7 +578,7 @@ var tab_new = function(id, name) {
'<a class="tab-closer" data-tab="tab-ext-'+id+'">&times;</a>'+
'</div> '
);
appendInnerHTML(el("#extratabs"),
appendInnerHTML(document_getElementById("extratabs"),
' <div class="tabpane content placement-mid" id="tab-ext-'+id+'" style="display:none;">'+
'<div class="content-inner" id="inner-tab-ext-'+id+'"></div>'+
'</div>'
@@ -509,11 +591,11 @@ var tab_free = function(id) {
if (id === "tab-main") return;
// remove tab item and body
var el = el("#tabitem-"+id);
el.parentNode.removeChild(el);
var $el = document_getElementById("tabitem-"+id);
$el.parentNode.removeChild($el);
var el = el("#"+id);
el.parentNode.removeChild(el);
$el = document_getElementById(""+id);
$el.parentNode.removeChild($el);
// clear from PM tabs
for (var i in pm_tabs) {
@@ -547,22 +629,26 @@ var noprop = function(ev) {
}
var tab_addHandlers = function() {
var tabitems = el(".tabitem");
var tabitems = document_getElementsByClassName("tabitem");
for (var i = 0; i < tabitems.length; i++) {
if (! tabitems[i]) continue;
if (! tabitems[i]) {
continue;
}
tabitems[i].onclick = function(ev) {
(<HTMLElement> tabitems[i]).onclick = function(ev) {
tab_set( this.getAttribute('data-tab') );
return noprop(ev);
};
}
var tabclosers = el(".tab-closer");
var tabclosers = document_getElementsByClassName("tab-closer");
for (var i = 0; i < tabclosers.length; i++) {
if (! tabclosers[i]) continue;
if (! tabclosers[i]) {
continue;
}
tabclosers[i].onclick = function(ev) {
(<HTMLElement> tabclosers[i]).onclick = function(ev) {
tab_free( this.getAttribute('data-tab') );
return noprop(ev);
@@ -572,8 +658,8 @@ var tab_addHandlers = function() {
/* */
var maybeWriterFor = function(username) {
if (! username in pm_tabs || ! pm_tabs[username]) {
var maybeWriterFor = function(username: string) {
if (! (username in pm_tabs) || ! pm_tabs[username]) {
return null;
}
@@ -598,7 +684,7 @@ var tabcomplete_state = '';
var tabcompletion_start = function(direction) {
var cursor = el("#chatbox").value.replace(/^.*\s([^\s]+)$/, '$1');
var cursor = (<HTMLInputElement>document_getElementById("chatbox")).value.replace(/^.*\s([^\s]+)$/, '$1');
if (tabcomplete_state === '') {
// new tab completion
@@ -634,10 +720,11 @@ var tabcompletion_start = function(direction) {
// Replace in textbox
var chatprefix = el("#chatbox").value.substr(0, el("#chatbox").value.length - cursor.length);
var $chatbox = (<HTMLInputElement>document_getElementById("chatbox"));
var chatprefix = $chatbox.value.substr(0, $chatbox.value.length - cursor.length);
el("#chatbox").value = chatprefix + targetName;
el("#chatbox").focus();
$chatbox.value = chatprefix + targetName;
$chatbox.focus();
};
var tabcompletion_inactive = function() {
@@ -649,11 +736,11 @@ var tabcompletion_inactive = function() {
var MenuList = function(el) {
this.el = el;
this.div = document.createElement("div");
this.div = document_createElement("div");
this.div.classList.add("menu");
this.div.style.position = "absolute";
this.ul = document.createElement("ul");
this.ul = document_createElement("ul");
this.div.appendChild(this.ul);
document.body.appendChild(this.div);
@@ -665,7 +752,7 @@ MenuList.prototype.clear = function() {
}
};
MenuList.prototype.add = function(txt, cb) {
var li = document.createElement("li");
var li = document_createElement("li");
li.innerHTML = txt;
li.onclick = cb;
this.ul.appendChild(li);
@@ -686,10 +773,17 @@ MenuList.prototype.toggle = function() {
/* */
var menu = new MenuList(el("#menubutton"));
var menu = new MenuList(document_getElementById("menubutton"));
menu.reset = function() {
this.clear();
if (contented_url.length > 0) {
menu.add("Upload", function() {
contented_load();
});
}
this.add(joinparts_getstr(), toggle_joinparts);
this.add(desktop_notifications_fmtstr(), desktop_notifications_toggle);
this.add(warnonclose_fmtstr(), warnonclose_toggle);
@@ -782,24 +876,29 @@ var toggle_joinparts = function(ev) {
var updateTitle = function() {
var prefix = "";
var unrTabs = el(".unread");
var unrTabs = document_getElementsByClassName("unread");
if (unrTabs.length === 1 && unrTabs[0].getAttribute('data-tab') == "tab-main") {
prefix = "[" + mainchat_unread_count + " NEW] "
} else if (unrTabs.length > 0) {
prefix = "[NEW PM] "
}
document.title = prefix + hub_hubname + " ("+userlist.count()+")"
var suffix = "";
if (userlist.count() > 0) {
suffix = " ("+userlist.count()+")";
}
document.title = prefix + hub_hubname + suffix;
};
var sock = {};
var sock:SocketIOClient.Socket = null;
var hub_state = 0; // [disconnected, sent-nick, connected]
var hub_last_nick = '';
var hub_hubname = "Loading...";
var pm_tabs = {}; // nick => tabid
var next_tabid = 1;
var pm_target = false;
const PM_TARGET_NONE = "";
var pm_target = PM_TARGET_NONE;
var last_tab = "tab-main";
@@ -883,7 +982,7 @@ var scrollback_move = function(delta) {
}
}
el("#chatbox").value = chat_scrollback[chat_scrollback_index];
(<HTMLInputElement>document_getElementById("chatbox")).value = chat_scrollback[chat_scrollback_index];
};
/* */
@@ -904,29 +1003,30 @@ var persistence_get = function(key, fallback) {
var transition = function(new_state) {
hub_state = new_state;
var $chatbox = (<HTMLInputElement>document_getElementById("chatbox"));
switch(new_state) {
case STATE_DISCONNECTED: {
userlist.clear();
el("#chatbox").disabled = true;
el("#chatbox").value = ''; // clear
$chatbox.disabled = true;
$chatbox.value = ''; // clear
} break;
case STATE_READY_FOR_LOGIN: {
userlist.clear();
el("#chatbox").spellcheck = false;
el("#chatbox").disabled = false;
el("#chatbox").value = ''; // clear
$chatbox.spellcheck = false;
$chatbox.disabled = false;
$chatbox.value = ''; // clear
} break;
case STATE_CONNECTING: {
el("#chatbox").disabled = true;
$chatbox.disabled = true;
} break;
case STATE_ACTIVE: {
write("tab-main").system("Now talking on "+hub_hubname);
el("#chatbox").disabled = false;
el("#chatbox").spellcheck = true;
$chatbox.disabled = false;
$chatbox.spellcheck = true;
} break;
}
};
@@ -936,14 +1036,15 @@ var tab_is_visible = function(tabref) {
}
var tab_mark_unread = function(tabref) {
if (el("#tabitem-"+tabref).className.indexOf('unread') === -1) {
el("#tabitem-"+tabref).className += " unread";
if (document_getElementById("tabitem-"+tabref).className.indexOf('unread') === -1) {
document_getElementById("tabitem-"+tabref).className += " unread";
updateTitle();
}
}
//
declare var contented: any;
var contented_url = "";
var contented_loaded_sdk = false;
var contented_load = function() {
@@ -953,21 +1054,21 @@ var contented_load = function() {
var onceSDKLoaded = function() {
contented.init("#inner-tab-main", function(items) {
var val = el("#chatbox").value;
var val = (<HTMLInputElement> document_getElementById("chatbox")).value;
for (var i = 0; i < items.length; ++i) {
if (val.length > 0) {
val += " ";
}
val += contented.getPreviewURL(items[i]);
}
el("#chatbox").value = val;
(<HTMLInputElement> document_getElementById("chatbox")).value = val;
});
};
if (contented_loaded_sdk) {
onceSDKLoaded();
} else {
var scriptElement = document.createElement('script');
var scriptElement = document_createElement('script');
scriptElement.onload = function() {
contented_loaded_sdk = true;
onceSDKLoaded();
@@ -988,13 +1089,13 @@ window.onload = function() {
// HTML event handlers
el("#form-none").onsubmit = function(ev) {
document_getElementById("form-none").onsubmit = function(ev) {
submit();
return noprop(ev); // don't submit form
};
el("#chatbox").onkeydown = function(ev) {
document_getElementById("chatbox").onkeydown = function(ev) {
if (ev.keyCode === 9 /* Tab */) {
tabcompletion_start( ev.shiftKey ? -1 : 1 );
return noprop(ev);
@@ -1022,7 +1123,7 @@ window.onload = function() {
usermenu.hide();
};
el("#menubutton").onclick = function(ev) {
document_getElementById("menubutton").onclick = function(ev) {
menu.toggle();
return noprop(ev);
};
@@ -1080,7 +1181,7 @@ window.onload = function() {
if (pre_login.indexOf(":") !== -1) {
pre_login = pre_login.substr(0, pre_login.indexOf(":")) + ":" + SENTINEL_PASSWORD;
}
el("#chatbox").value = pre_login;
(<HTMLInputElement>document_getElementById("chatbox")).value = pre_login;
if (have_cleared_once) {
// re-log-in automatically
@@ -1176,10 +1277,6 @@ window.onload = function() {
});
sock.on('contented', function(url) {
contented_url = url;
menu.add("Upload", function() {
contented_load();
});
menu.reset(); // sent before login
});
};
//IIFEMODE:})();

View File

@@ -5,8 +5,7 @@
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="/dcwebui.css">
<link rel="apple-touch-icon" href="./apple-touch-icon.png">
<title>Loading...</title>
</head>
<body>
@@ -56,7 +55,6 @@
</form>
</div>
<script type="text/javascript" src="/socket.io-1.7.2.js"></script>
<script type="text/javascript" src="/dcwebui.js"></script>
<script type="text/javascript" src="/bundle.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -1,60 +0,0 @@
#!/usr/bin/php
<?php
# Dependencies:
# - PHP
# - Uglifyjs (`npm install -g uglify-js`)
# - Lessc (`npm install -g less`)
# - Lessc minifier (`npm install -g less-plugin-clean-css`)
# - HTML minifier (`npm install -g html-minifier`)
echo "Compressing/minifying web resources...\n";
if (is_dir('clientpack')) {
`rm -r clientpack`;
}
`cp -r client clientpack`;
// Toggle IIFE on
`sed -i -re 's~//IIFEMODE:~~g' clientpack/dcwebui.js`;
// Minify JS
`uglifyjs clientpack/dcwebui.js -o clientpack/dcwebui.min.js -c -m`;
// Minify CSS
`lessc --clean-css clientpack/dcwebui.css clientpack/dcwebui.min.css`;
// Embed css into HTML file
$html_content = file_get_contents('clientpack/index.htm');
$html_content = preg_replace_callback('~<link[^>]+dcwebui.css[^>]*>~', function() { return '<style type="text/css">'.file_get_contents('clientpack/dcwebui.min.css').'</style>'; }, $html_content);
// Embed JS into HTML file
$html_content = preg_replace_callback('~<script[^>]+dcwebui.js[^>]*>~', function() { return '<script type="text/javascript">'.file_get_contents('clientpack/dcwebui.min.js').'</script>'; }, $html_content);
// Embed socketio into HTML file
define('SIO_NAME', 'socket.io-1.7.2.js');
$html_content = preg_replace_callback('~<script[^>]+'.SIO_NAME.'[^>]*>~', function() { return '<script type="text/javascript">'.file_get_contents('clientpack/'.SIO_NAME).'</script>'; }, $html_content);
// Minify the combined file
file_put_contents('clientpack/index.htm', $html_content);
`html-minifier --collapse-whitespace -o clientpack/index.min.htm clientpack/index.htm`;
// Clean up files
unlink('clientpack/index.htm');
unlink('clientpack/dcwebui.js');
unlink('clientpack/dcwebui.min.js');
unlink('clientpack/dcwebui.css');
unlink('clientpack/dcwebui.min.css');
unlink('clientpack/'.SIO_NAME);
rename('clientpack/index.min.htm', 'clientpack/index.htm');

26
main.go
View File

@@ -5,8 +5,9 @@ import (
"fmt"
"io/ioutil"
"log"
"mime"
"net/http"
"strings"
"path/filepath"
"code.ivysaur.me/libnmdc"
"github.com/googollee/go-socket.io"
@@ -204,27 +205,8 @@ func (this *App) StaticRequestHandler(w http.ResponseWriter, r *http.Request) {
return
}
knownContentTypes := map[string]string{
".htm": "text/html",
".png": "image/png",
".ico": "image/x-icon",
// No CSS/JS since they're embedded in the HTML
}
foundMime := false
for ext, mimeType := range knownContentTypes {
if strings.HasSuffix(fileName, ext) {
w.Header().Set("Content-Type", mimeType)
foundMime = true
break
}
}
if !foundMime {
w.Header().Set("Content-Type", "application/x-octet-stream")
}
dataInfo, _ := AssetInfo(fileName)
w.Header().Set("Content-Length", fmt.Sprintf("%d", dataInfo.Size()))
w.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(fileName)))
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(data)))
w.Write(data)
}

4802
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

32
package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "nmdc-webfrontend",
"version": "1.0.0",
"description": "A web interface to an NMDC hub",
"homepage": "https://code.ivysaur.me/nmdc-webfrontend/",
"main": "s",
"scripts": {
"webpack": "webpack"
},
"repository": {
"type": "git",
"url": "https://git.ivysaur.me/code.ivysaur.me/nmdc-webfrontend"
},
"author": "",
"license": "ISC",
"dependencies": {
"@types/socket.io-client": "^1.4.31",
"awesome-typescript-loader": "^3.3.0",
"css-loader": "^0.28.7",
"html-minifier": "^3.5.6",
"less": "^2.7.3",
"less-loader": "^4.0.5",
"less-plugin-clean-css": "^1.5.1",
"socket.io-client": "^2.0.4",
"style-loader": "^0.19.0",
"ts-loader": "^3.1.1",
"typescript": "^2.6.1",
"uglify-js": "^3.1.8",
"webpack": "^3.8.1"
},
"devDependencies": {}
}

9
tsconfig.json Normal file
View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "es3",
"removeComments": true
},
"include": [
"client/*"
]
}

53
webpack.config.js Normal file
View File

@@ -0,0 +1,53 @@
/*! webpack.config.js */
const webpack = require("webpack");
const path = require('path');
const CleanCSSPlugin = require("less-plugin-clean-css");
module.exports = {
entry: "./client/dcwebui.ts",
output: {
path: path.resolve(__dirname, 'clientpack'),
filename: "bundle.min.js"
},
resolve: {
// Add '.ts' and '.tsx' as a resolvable extension.
extensions: [ '.tsx', '.ts', '.js' ]
},
module: {
loaders: [
// all files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'
{ test: /\.tsx?$/, loader: "ts-loader" },
// Plain CSS files (no longer present)
{ test: /\.css$/, loader: "style-loader!css-loader" },
// LESS CSS files
{
test: /\.less$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{
loader: "less-loader",
options: {
noIeCompat: false,
plugins: [
new CleanCSSPlugin({ advanced: true })
]
}
}
]
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
};