First Commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.exe
|
||||||
|
Manuals/
|
||||||
0
Dockerfile
Normal file
0
Dockerfile
Normal file
9
go.mod
Normal file
9
go.mod
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module Server
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/mux v1.7.0
|
||||||
|
github.com/jbowtie/gokogiri v0.0.0-20190301021639-37f655d3078f
|
||||||
|
github.com/jbowtie/ratago v0.0.0-20180115094149-33a9dca16476
|
||||||
|
)
|
||||||
6
go.sum
Normal file
6
go.sum
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
|
||||||
|
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/jbowtie/gokogiri v0.0.0-20190301021639-37f655d3078f h1:6UIvzqlGM38lOpKP380Wbl0kUyyjutcc7KJUaDM/U4o=
|
||||||
|
github.com/jbowtie/gokogiri v0.0.0-20190301021639-37f655d3078f/go.mod h1:C3R3VzPq+DAwilxue7DiV6F2QL1rrQX0L56GyI+sBxM=
|
||||||
|
github.com/jbowtie/ratago v0.0.0-20180115094149-33a9dca16476 h1:oJjMBS3C2YJEWJDRuIGCcLahNlpfID52BlqDmZx40Ks=
|
||||||
|
github.com/jbowtie/ratago v0.0.0-20180115094149-33a9dca16476/go.mod h1:6IMkzlV446Sd3u2cvB69IdW8uJDphLzkPf05hjOyKvM=
|
||||||
159
html/index.html
Normal file
159
html/index.html
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>Service Information</title>
|
||||||
|
<link href='https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons' rel="stylesheet">
|
||||||
|
<link href="static/vuetify.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
.v-treeview-node__content,
|
||||||
|
.v-treeview-node__label{flex-shrink:1;font-size:0.9rem;}
|
||||||
|
.v-treeview-node__root{height:auto;}
|
||||||
|
[class="1-column-portrait"]{float:right;max-width:330px;}
|
||||||
|
.dtwarning{color:red;}
|
||||||
|
.dtnote{color:blue;}
|
||||||
|
.dtcaution{color:goldenrod;}
|
||||||
|
@media print {.v-content{padding:0 !important;}}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<v-app>
|
||||||
|
<v-toolbar app clipped-left class="hidden-print-only">
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-flex xs3 d-flex>
|
||||||
|
<v-select
|
||||||
|
v-model="year"
|
||||||
|
:items="yearitems"
|
||||||
|
label="Year"
|
||||||
|
outline
|
||||||
|
height=18
|
||||||
|
v-on:input="changeYear"
|
||||||
|
></v-select>
|
||||||
|
</v-flex>
|
||||||
|
<v-flex xs3 d-flex>
|
||||||
|
<v-select
|
||||||
|
v-model="model"
|
||||||
|
:items="modelitems"
|
||||||
|
label="Model"
|
||||||
|
outline
|
||||||
|
height=18
|
||||||
|
v-on:input="changeEngine"
|
||||||
|
></v-select>
|
||||||
|
</v-flex>
|
||||||
|
<v-flex xs3 d-flex>
|
||||||
|
<v-select
|
||||||
|
v-model="engine"
|
||||||
|
:items="engineitems"
|
||||||
|
label="Engine"
|
||||||
|
outline
|
||||||
|
height=18
|
||||||
|
v-on:input="changeCar"
|
||||||
|
></v-select>
|
||||||
|
</v-flex>
|
||||||
|
</v-toolbar>
|
||||||
|
<v-navigation-drawer permanent app fixed clipped class="hidden-print-only">
|
||||||
|
<v-text-field
|
||||||
|
v-model="search"
|
||||||
|
label="Search Manuals"
|
||||||
|
flat
|
||||||
|
solo-inverted
|
||||||
|
hide-details
|
||||||
|
clearable
|
||||||
|
></v-text-field>
|
||||||
|
<v-treeview
|
||||||
|
:open.sync="listactive"
|
||||||
|
:items="sidebar"
|
||||||
|
:search="search"
|
||||||
|
item-key="id"
|
||||||
|
open-on-click>
|
||||||
|
<template v-slot:label="{ item }">
|
||||||
|
<a v-if="item.file" @click="index(item.file)">{{item.name}}</a>
|
||||||
|
<span v-else :id="item.id">{{item.name}}</span>
|
||||||
|
</template>
|
||||||
|
</v-treeview>
|
||||||
|
</v-navigation-drawer>
|
||||||
|
<v-content>
|
||||||
|
<v-container fluid>
|
||||||
|
<div :is="dynamicHtml"></div>
|
||||||
|
</v-container>
|
||||||
|
</v-content>
|
||||||
|
</v-app>
|
||||||
|
</div>
|
||||||
|
<script src="static/vue.min.js"></script>
|
||||||
|
<script src="static/vuetify.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var app = new Vue({
|
||||||
|
el: '#app',
|
||||||
|
data: {
|
||||||
|
listactive: [],
|
||||||
|
body: "",
|
||||||
|
sidebar: [],
|
||||||
|
search:"",
|
||||||
|
items: [],
|
||||||
|
yearitems: [],
|
||||||
|
year:" ",
|
||||||
|
modelitems: [],
|
||||||
|
model:" ",
|
||||||
|
engineitems: [],
|
||||||
|
engine:" "
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dynamicHtml() {
|
||||||
|
return {
|
||||||
|
template: this.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created: function() {
|
||||||
|
fetch('cars')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(json => {
|
||||||
|
this.items = json;
|
||||||
|
this.yearitems = Object.keys(json);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updated: function() {
|
||||||
|
const refs = document.querySelectorAll('.intxref');
|
||||||
|
refs.forEach(refitem => {
|
||||||
|
var pointedAt = document.querySelector(refitem.getAttribute('href'));
|
||||||
|
refitem.innerText = pointedAt.getElementsByTagName("em")[0].innerText;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeYear() {
|
||||||
|
this.modelitems = Object.keys(this.items[this.year])
|
||||||
|
},
|
||||||
|
changeEngine() {
|
||||||
|
this.engineitems = Object.keys(this.items[this.year][this.model])
|
||||||
|
},
|
||||||
|
changeCar() {
|
||||||
|
document.title = [this.year, this.model, this.engine].join(" ");
|
||||||
|
fetch(this.items[this.year][this.model][this.engine])
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(json => {
|
||||||
|
this.sidebar=json;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
switchToc(list) {
|
||||||
|
var temp = JSON.parse(list);
|
||||||
|
temp.forEach(item => this.listactive.push(item));
|
||||||
|
var element = document.getElementById(temp[0]);
|
||||||
|
element.scrollIntoView({block: "start"});
|
||||||
|
},
|
||||||
|
index (folder) {
|
||||||
|
fetch("file/" + folder)
|
||||||
|
.then(res => res.text())
|
||||||
|
.then(json => {
|
||||||
|
this.$set(this, 'body', json);
|
||||||
|
console.log(this.body);
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
})
|
||||||
|
.catch(err => console.warn(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
html/static/vue.min.js
vendored
Normal file
6
html/static/vue.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
html/static/vuetify.min.css
vendored
Normal file
5
html/static/vuetify.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
html/static/vuetify.min.js
vendored
Normal file
6
html/static/vuetify.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
137
main.go
Normal file
137
main.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/jbowtie/gokogiri/xml"
|
||||||
|
"github.com/jbowtie/ratago/xslt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TOCNode struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
File string `json:"file,omitempty"`
|
||||||
|
Key string `json:"id"`
|
||||||
|
Children []TOCNode `json:"children,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CarInfo struct {
|
||||||
|
SoftLink url.Values `json:"softlink"`
|
||||||
|
ToC []TOCNode `json:"toc"`
|
||||||
|
Values map[string]url.Values `json:"tocpath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var indexList CarInfo
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := mux.NewRouter()
|
||||||
|
r.PathPrefix("/static/").Handler(http.StripPrefix("/static", http.FileServer(http.Dir("html/static"))))
|
||||||
|
r.HandleFunc("/cars", HomeHandler)
|
||||||
|
r.HandleFunc("/{car}", CarHandler)
|
||||||
|
r.HandleFunc("/file/{page}", PageHandler)
|
||||||
|
r.HandleFunc("/img/{file}", ImgHandler)
|
||||||
|
r.PathPrefix("/").Handler(http.FileServer(http.Dir("html")))
|
||||||
|
err := http.ListenAndServe(":8080", r)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("ListenAndServe: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HomeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, _ := ioutil.ReadFile("Manuals/vehicles.json")
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write(body)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func CarHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
folder := vars["car"]
|
||||||
|
indexList = CarInfo{}
|
||||||
|
file, err := os.Open(path.Join("Manuals", folder+".toc"))
|
||||||
|
if err != nil {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
empty := []TOCNode{TOCNode{Name: "Not Available", Key: "1"}}
|
||||||
|
json.NewEncoder(w).Encode(empty)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
json.NewDecoder(file).Decode(&indexList)
|
||||||
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
writer := gzip.NewWriter(w)
|
||||||
|
json.NewEncoder(writer).Encode(indexList.ToC)
|
||||||
|
writer.Close()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func PageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
img := vars["page"]
|
||||||
|
style, _ := xml.ReadFile(path.Join("Manuals", "techauth.xsl"), xml.StrictParseOption)
|
||||||
|
stylesheet, _ := xslt.ParseStylesheet(style, path.Join("Manuals", "techauth.xsl"))
|
||||||
|
|
||||||
|
input, err := xml.ReadFile(path.Join("Manuals", "files", img), xml.StrictParseOption)
|
||||||
|
if err != nil {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params := make(map[string]interface{})
|
||||||
|
params["TOCPath"] = indexList.Values[img]["TOCPath"][0]
|
||||||
|
params["modelyear"] = indexList.Values[img]["year"][0]
|
||||||
|
params["modelname"] = indexList.Values[img]["platform"][0]
|
||||||
|
params["ENG"] = indexList.Values[img]["ENG"][0]
|
||||||
|
params["locale"] = indexList.Values[img]["lang"][0]
|
||||||
|
params["vid"] = indexList.Values[img]["VID"][0]
|
||||||
|
params["contentPath"] = "img/"
|
||||||
|
output, err := stylesheet.Process(input, xslt.StylesheetOptions{false, params})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
if strings.Contains(output, "REPLACEME") {
|
||||||
|
reg := regexp.MustCompile(`REPLACEME="(\d+?)"`)
|
||||||
|
matches := reg.FindAllStringSubmatch(output, -1)
|
||||||
|
for _, item := range matches {
|
||||||
|
location := indexList.SoftLink[item[1]]
|
||||||
|
if len(location) > 1 {
|
||||||
|
string2 := FindToc(indexList.ToC, location[0])
|
||||||
|
place, _ := json.Marshal(string2)
|
||||||
|
output = strings.Replace(output, item[0], fmt.Sprintf(`v-on:click="app.switchToc('%s')"`, strings.Replace(string(place), `"`, `"`, -1)), -1)
|
||||||
|
} else {
|
||||||
|
output = strings.Replace(output, item[0], fmt.Sprintf(`v-on:click="app.index('%s')"`, location[0]), -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.Write([]byte(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImgHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
img := vars["file"]
|
||||||
|
img = strings.Replace(img, ".tif", ".jpg", -1)
|
||||||
|
http.ServeFile(w, r, path.Join("Manuals", "files", "img", img))
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindToc(toc []TOCNode, file string) []string {
|
||||||
|
var list []string
|
||||||
|
for _, item := range toc {
|
||||||
|
if item.File == file {
|
||||||
|
list = append([]string{item.Key}, list...)
|
||||||
|
}
|
||||||
|
list2 := FindToc(item.Children, file)
|
||||||
|
if len(list2) > 0 {
|
||||||
|
list = append([]string{item.Key}, list2...)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user