diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | Makefile | 11 | ||||
| -rw-r--r-- | _content/index.html | 33 | ||||
| -rw-r--r-- | _content/index.js | 106 | ||||
| -rw-r--r-- | _content/kbbiclient.js | 35 | ||||
| -rw-r--r-- | generate.go | 7 | ||||
| -rw-r--r-- | internal/generate/main.go | 31 | ||||
| -rw-r--r-- | kbbi.go | 1 | ||||
| -rw-r--r-- | server.go | 12 |
9 files changed, 235 insertions, 4 deletions
@@ -1,5 +1,8 @@ +/cmd/www-kbbi/static.go /internal/cmd/mergedic/id_ID.dic /internal/cmd/mergedic/id_ID.dic.new +/kamus.gob +/kamus.gob.new /kbbi /testdata/kamus.gob /testdata/kamus.gob.new @@ -2,10 +2,14 @@ ## Use of this source code is governed by a BSD-style ## license that can be found in the LICENSE file. -.PHONY: all build lint test install deploy +.PHONY: all build lint test install generate deploy LINT_OPTS = +GENERATE_INPUTS = _content/index.html \ + _content/index.js \ + _content/kbbiclient.js + all: build lint test build: @@ -27,7 +31,10 @@ test: install: go install ./cmd/kbbi/ -deploy: +cmd/www-kbbi/static.go: $(GENERATE_INPUTS) + go generate + +deploy: cmd/www-kbbi/static.go CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ go build -o www-kbbi-linux-amd64 ./cmd/www-kbbi/ rsync --progress ./www-kbbi-linux-amd64 www-kbbi:~/bin/www-kbbi diff --git a/_content/index.html b/_content/index.html new file mode 100644 index 0000000..328e00a --- /dev/null +++ b/_content/index.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> + <head> + <title>Project KBBI</title> + + <script type="text/javascript" src="kbbiclient.js"></script> + <script type="text/javascript" src="index.js"></script> + <style> + .kelas-kata, + .contoh { + margin-left: 2em; + } + </style> + </head> + <body> + <h1>Proyek KBBI</h1> + <p> + Proyek implementasi API untuk Kamus Besar Bahasa Indonesia. + </p> + + <h2>Definisi kata</h2> + <label> + Daftar kata: + <input type="text" id="kata" maxlength="64" /> + </label> + <button onclick="cariDefinisi()">Cari definisi</button> + <p class="note"> + Catatan: gunakan koma untuk mencari lebih dari satu kata. + </p> + + <div id="definisi-result"></div> + </body> +</html> diff --git a/_content/index.js b/_content/index.js new file mode 100644 index 0000000..72482e9 --- /dev/null +++ b/_content/index.js @@ -0,0 +1,106 @@ +/** + * Copyright 2020, Shulhan <m.shulhan@gmail.com>. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +let kbbiClient = new KBBIClient("") + +function cariDefinisi() { + let kata = document.getElementById("kata").value + kbbiClient.getDefinitions(kata, cariDefinisiCallback) +} + +function cariDefinisiCallback(res) { + let out = document.getElementById("definisi-result") + out.innerHTML = "" + + for (let kata in res) { + let root = document.createElement("div") + printResultKata(root, kata, res[kata]) + out.appendChild(root) + } +} + +function printResultKata(out, kata, defKata) { + let el = document.createElement("b") + el.appendChild(document.createTextNode(kata)) + out.appendChild(el) + + printKataDasar(out, defKata.dasar) + printDefinitions(out, defKata.definisi) +} + +function printKataDasar(out, kataDasar) { + let root = document.createElement("div") + root.appendChild(document.createTextNode("Kata dasar: ")) + + if (kataDasar === "") { + root.appendChild(document.createTextNode("-")) + } else { + let italic = document.createElement("i") + italic.appendChild(document.createTextNode(kataDasar)) + root.appendChild(italic) + } + + out.appendChild(root) +} + +function printDefinitions(out, definitions) { + for (let x = 0; x < definitions.length; x++) { + let def = definitions[x] + + let root = document.createElement("div") + let el = document.createElement("p") + el.classList.add("definisi") + el.appendChild( + document.createTextNode( + "Definisi #" + (x + 1) + ": " + def.isi + ".", + ), + ) + root.appendChild(el) + + printKelasKata(root, def.kelas) + printContoh(root, def.contoh) + out.appendChild(root) + } +} + +function printKelasKata(out, daftarKelas) { + if (typeof daftarKelas === "undefined") { + return + } + + let root = document.createElement("div") + root.classList.add("kelas-kata") + root.appendChild(document.createTextNode("Kelas,")) + + let el = document.createElement("ul") + for (let x = 0; x < daftarKelas.length; x++) { + let li = document.createElement("li") + li.appendChild(document.createTextNode(daftarKelas[x])) + el.appendChild(li) + } + root.appendChild(el) + out.appendChild(root) +} + +function printContoh(out, examples) { + if (typeof examples === "undefined") { + return + } + + let root = document.createElement("div") + root.classList.add("contoh") + root.appendChild(document.createTextNode("Contoh,")) + + let ul = document.createElement("ul") + + for (let x = 0; x < examples.length; x++) { + let li = document.createElement("li") + li.appendChild(document.createTextNode(examples[x])) + ul.appendChild(li) + } + root.appendChild(ul) + out.appendChild(root) +} diff --git a/_content/kbbiclient.js b/_content/kbbiclient.js new file mode 100644 index 0000000..ab35633 --- /dev/null +++ b/_content/kbbiclient.js @@ -0,0 +1,35 @@ +/** + * Copyright 2020, Shulhan <m.shulhan@gmail.com>. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +class KBBIClient { + constructor(baseURL) { + if (baseURL.length === 0) { + baseURL = "https://kilabit.info/project/kbbi" + } + this.baseURL = baseURL + } + + getDefinitions(words, cb) { + if (words.length === 0) { + return + } + + let params = "kata=" + words + let xhr = new XMLHttpRequest() + + xhr.addEventListener("load", function() { + cb(JSON.parse(xhr.responseText)) + }) + + xhr.open("GET", this.baseURL + "/api/definisi?" + params) + xhr.setRequestHeader( + "Content-Type", + "application/x-www-form-urlencoded", + ) + + xhr.send(null) + } +} diff --git a/generate.go b/generate.go new file mode 100644 index 0000000..05137b0 --- /dev/null +++ b/generate.go @@ -0,0 +1,7 @@ +// Copyright 2020, Shulhan <m.shulhan@gmail.com>. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run ./internal/generate + +package kbbi diff --git a/internal/generate/main.go b/internal/generate/main.go new file mode 100644 index 0000000..cb12ccf --- /dev/null +++ b/internal/generate/main.go @@ -0,0 +1,31 @@ +// Copyright 2020, Shulhan <m.shulhan@gmail.com>. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "log" + + "github.com/shuLhan/share/lib/memfs" +) + +func main() { + includes := []string{ + "index.html", + "index.js", + "kbbiclient.js", + } + + mfs, err := memfs.New(includes, nil, true) + if err != nil { + log.Fatal(err) + } + + err = mfs.Mount("./_content") + if err != nil { + log.Fatal(err) + } + + mfs.GoGenerate("main", "./cmd/www-kbbi/static.go", memfs.EncodingGzip) +} @@ -27,6 +27,7 @@ const ( attrValueRootWord = "rootword" + headerNameACAO = "Access-Control-Allow-Origin" headerNameContentType = "Content-Type" headerValueContentType = "application/x-www-form-urlencoded" @@ -12,6 +12,7 @@ import ( "sync" "time" + "github.com/shuLhan/share/lib/debug" "github.com/shuLhan/share/lib/http" ) @@ -44,9 +45,14 @@ type Server struct { // func NewServer(kamusStorage string) (server *Server, err error) { opts := &http.ServerOptions{ + Root: "_content", Address: defListen, } + if debug.Value > 0 { + opts.Development = true + } + server = &Server{ stopped: make(chan bool, 1), } @@ -78,7 +84,7 @@ func NewServer(kamusStorage string) (server *Server, err error) { // Start the HTTP server. // func (server *Server) Start() (err error) { - go server.dumpCache() + go server.dumpCacheJob() server.wg.Add(1) return server.http.Start() @@ -88,7 +94,7 @@ func (server *Server) Start() (err error) { // Shutdown the HTTP server and save the cache for future use. // func (server *Server) Shutdown() (err error) { - err = server.Shutdown() + err = server.http.Shutdown(nil) server.stopped <- true @@ -134,6 +140,8 @@ func (server *Server) handleDefinisi( httpReq *stdhttp.Request, reqBody []byte, ) (resBody []byte, err error) { + httpRes.Header().Set(headerNameACAO, "*") + paramKata := httpReq.Form.Get(paramNameKata) if len(paramKata) == 0 { return []byte(emptyResponse), nil |
