mirror of
https://github.com/alecthomas/chroma.git
synced 2025-03-23 21:29:15 +02:00
Make playground completely dynamic.
This commit is contained in:
parent
2332264124
commit
bdb587cd37
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -32,63 +33,91 @@ type context struct {
|
||||
Languages []string
|
||||
SelectedStyle string
|
||||
Styles []string
|
||||
Text string
|
||||
HTML template.HTML
|
||||
Error string
|
||||
CSRFField template.HTML
|
||||
}
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := contextFromRequest(r)
|
||||
style := styles.Get(ctx.SelectedStyle)
|
||||
if style == nil {
|
||||
style = styles.Fallback
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := newContext(r)
|
||||
err := htmlTemplate.Execute(w, &ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx.Background = template.CSS(html.StyleEntryToCSS(style.Get(chroma.Background)))
|
||||
}
|
||||
|
||||
language := lexers.Get(ctx.SelectedLanguage)
|
||||
type renderRequest struct {
|
||||
Language string `json:"language"`
|
||||
Style string `json:"style"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type renderResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
HTML string `json:"html,omitempty"`
|
||||
Language string `json:"language,omitempty"`
|
||||
Background string `json:"background,omitempty"`
|
||||
}
|
||||
|
||||
func renderHandler(w http.ResponseWriter, r *http.Request) {
|
||||
req := &renderRequest{}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
var rep *renderResponse
|
||||
if err != nil {
|
||||
rep = &renderResponse{Error: err.Error()}
|
||||
} else {
|
||||
rep, err = render(req)
|
||||
if err != nil {
|
||||
rep = &renderResponse{Error: err.Error()}
|
||||
}
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(rep)
|
||||
}
|
||||
|
||||
func render(req *renderRequest) (*renderResponse, error) {
|
||||
language := lexers.Get(req.Language)
|
||||
if language == nil {
|
||||
language = lexers.Analyse(ctx.Text)
|
||||
language = lexers.Analyse(req.Text)
|
||||
if language != nil {
|
||||
ctx.SelectedLanguage = language.Config().Name
|
||||
req.Language = language.Config().Name
|
||||
}
|
||||
}
|
||||
if language == nil {
|
||||
language = lexers.Fallback
|
||||
}
|
||||
|
||||
tokens, err := language.Tokenise(nil, ctx.Text)
|
||||
tokens, err := language.Tokenise(nil, req.Text)
|
||||
if err != nil {
|
||||
ctx.Error = err.Error()
|
||||
} else {
|
||||
buf := &strings.Builder{}
|
||||
formatter := html.New()
|
||||
err = formatter.Format(buf, style, tokens)
|
||||
if err != nil {
|
||||
ctx.Error = err.Error()
|
||||
} else {
|
||||
ctx.HTML = template.HTML(buf.String()) // nolint: gosec
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = htmlTemplate.Execute(w, &ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
style := styles.Get(req.Style)
|
||||
if style == nil {
|
||||
style = styles.Fallback
|
||||
}
|
||||
|
||||
buf := &strings.Builder{}
|
||||
formatter := html.New()
|
||||
err = formatter.Format(buf, style, tokens)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &renderResponse{
|
||||
Language: language.Config().Name,
|
||||
HTML: buf.String(),
|
||||
Background: html.StyleEntryToCSS(style.Get(chroma.Background)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func contextFromRequest(r *http.Request) context {
|
||||
err := r.ParseForm()
|
||||
func newContext(r *http.Request) context {
|
||||
ctx := context{
|
||||
SelectedLanguage: r.Form.Get("language"),
|
||||
SelectedStyle: r.Form.Get("style"),
|
||||
Text: r.Form.Get("text"),
|
||||
CSRFField: csrf.TemplateField(r),
|
||||
SelectedStyle: "monokailight",
|
||||
CSRFField: csrf.TemplateField(r),
|
||||
}
|
||||
if err != nil {
|
||||
ctx.Error = err.Error()
|
||||
return ctx
|
||||
style := styles.Get(ctx.SelectedStyle)
|
||||
if style == nil {
|
||||
style = styles.Fallback
|
||||
}
|
||||
ctx.Background = template.CSS(html.StyleEntryToCSS(style.Get(chroma.Background)))
|
||||
if ctx.SelectedStyle == "" {
|
||||
ctx.SelectedStyle = "monokailight"
|
||||
}
|
||||
@ -114,8 +143,9 @@ func main() {
|
||||
log.Println("Starting")
|
||||
|
||||
router := mux.NewRouter()
|
||||
router.Handle("/", http.HandlerFunc(handler))
|
||||
router.Handle("/static/{file:.*}", http.StripPrefix("/static/", http.FileServer(staticFiles.HTTPBox())))
|
||||
router.Handle("/", http.HandlerFunc(index)).Methods("GET")
|
||||
router.Handle("/api/render", http.HandlerFunc(renderHandler))
|
||||
router.Handle("/static/{file:.*}", http.StripPrefix("/static/", http.FileServer(staticFiles.HTTPBox()))).Methods("GET")
|
||||
|
||||
options := []csrf.Option{}
|
||||
if cli.CSRFKey == "" {
|
||||
|
@ -1,7 +1,73 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
var style = document.createElement('style');
|
||||
var ref = document.querySelector('script');
|
||||
ref.parentNode.insertBefore(style, ref);
|
||||
|
||||
var form = document.getElementById('chroma');
|
||||
var textArea = form.elements["text"];
|
||||
var csrfToken = form.elements["gorilla.csrf.Token"].value;
|
||||
var elms = document.getElementsByTagName("select");
|
||||
for (e of elms) {
|
||||
e.addEventListener('change', () => form.submit());
|
||||
var output = document.getElementById("output");
|
||||
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function () {
|
||||
var context = this, args = arguments;
|
||||
var later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
};
|
||||
|
||||
function getFormJSON() {
|
||||
return {
|
||||
"language": document.getElementById("language").value,
|
||||
"style": document.getElementById("style").value,
|
||||
"text": document.getElementById("text").value,
|
||||
}
|
||||
}
|
||||
|
||||
function update(event) {
|
||||
fetch("api/render", {
|
||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||
mode: 'cors', // no-cors, cors, *same-origin
|
||||
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
|
||||
credentials: 'same-origin', // include, *same-origin, omit
|
||||
headers: {
|
||||
'X-CSRF-Token': csrfToken,
|
||||
'Content-Type': 'application/json',
|
||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
redirect: 'follow', // manual, *follow, error
|
||||
referrer: 'no-referrer', // no-referrer, *client
|
||||
body: JSON.stringify(getFormJSON()),
|
||||
|
||||
}).then(data => {
|
||||
data.json().then(
|
||||
value => {
|
||||
style.innerHTML = "#output { " + value.background + "}";
|
||||
output.innerHTML = value.html;
|
||||
}
|
||||
);
|
||||
}).catch(reason => {
|
||||
console.log(reason);
|
||||
})
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
var eventHandler = (event) => update(event);
|
||||
for (e of elms) {
|
||||
e.addEventListener('change', eventHandler);
|
||||
}
|
||||
form.addEventListener('submit', eventHandler);
|
||||
|
||||
var debouncedEventHandler = debounce(eventHandler, 250);
|
||||
textArea.addEventListener('input', debouncedEventHandler);
|
||||
textArea.addEventListener('change', debouncedEventHandler)
|
||||
});
|
||||
|
@ -9,7 +9,7 @@
|
||||
}
|
||||
|
||||
#output {
|
||||
{{.Background}}
|
||||
{{.Background}}
|
||||
}
|
||||
|
||||
#output pre {
|
||||
@ -20,7 +20,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{{if .Error}}<div class="notification">{{.Error}}</div>{{end}}
|
||||
<div class="notification is-hidden"></div>
|
||||
|
||||
<h1 class="title">Chroma Playground</h1>
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
<label class="label">Language</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select name="language">
|
||||
<select name="language" id="language">
|
||||
<option value="" disabled{{if eq "" $.SelectedLanguage}} selected{{end}}>Language</option>
|
||||
{{- range .Languages}}
|
||||
<option value="{{.}}"{{if eq . $.SelectedLanguage}} selected{{end}}>{{.}}</option>
|
||||
@ -45,7 +45,7 @@
|
||||
<label class="label">Style</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select name="style">
|
||||
<select name="style" id="style">
|
||||
<option value="" disabled{{if eq "" $.SelectedStyle}} selected{{end}}>Style</option>
|
||||
{{- range .Styles}}
|
||||
<option value="{{.}}"{{if eq . $.SelectedStyle}} selected{{end}}>{{.}}</option>
|
||||
@ -59,22 +59,20 @@
|
||||
<div class="field">
|
||||
<label class="label">Code</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea" name="text" rows="25" cols="80">{{.Text}}</textarea>
|
||||
<textarea class="textarea" id="text" name="text" rows="25" cols="80"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button class="button is-link">Submit</button>
|
||||
<button type="submit" class="button is-link">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<label class="label">Output</label>
|
||||
<div class="field box" id="output">
|
||||
{{.HTML}}
|
||||
</div>
|
||||
<div class="field box" id="output"></div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
|
Loading…
x
Reference in New Issue
Block a user