go vendor

This commit is contained in:
lealife
2017-11-30 19:55:33 +08:00
parent 2856da6888
commit 0fb92efbf3
670 changed files with 199010 additions and 0 deletions

View File

@ -0,0 +1,59 @@
# Ace
The [ACE](https://github.com/yosssi/ace) Templating Plugin
- Ace templates have full access to the revel.TemplateFuncs, any function
defined in there can be used by the this engine
- Ace files must be identified by using a `shebang` on the first line
(preferred method) or changing the file extension to home.ace.html.
By default the operation of revel assumes just a `.html` extension for
controller responses so it would make more sense to use the shebang
- Ace templates can be set to be case sensitive by setting
`ace.tempate.caseinsensitive=false`, default is not case sensitive. If case sensitivity
is off internal imports must be done using lower case
- All function registered in `revel.TemplateFuncs` are available for use
inside the ace framework
##### Details
Ace is a little different of a templating system, its output is a
standard go template but there is no concept of template sets,
instead you build a composite template using
a *base* template and an *inner* template. The
*inner* template can only contain items like :
```
= content main
h2 Inner Template - Main : {{.Msg}}
= content sub
h3 Inner Template - Sub : {{.Msg}}
```
The base template can contain items like
```
= doctype html
html lang=en
head
meta charset=utf-8
title Ace example
= css
h1 { color: blue; }
body
h1 Base Template : {{.Msg}}
#container.wrapper
= yield main
= yield sub
= include inc .Msg
= javascript
alert('{{.Msg}}');
```
You are allowed to include one *inner* template with the base template,
to do so in revel you can extend your controller from the ace controller
and call `RenderAceTemplate(base ,inner string)` which will insert
the inner template using the outer template.
The ace engine requires that you explicitly set the template type on the
template itself by either using the shebang method on the first line
like `#! ace` or having the file name like `template.ace.html`
either method will work.

View File

@ -0,0 +1,3 @@
package ace
// Required for vendoring see golang.org/issue/13832

View File

@ -0,0 +1,13 @@
package controllers
import "github.com/revel/revel"
type AceController struct {
*revel.Controller
}
// Called to render the ace template inner
func (c *AceController) RenderAceTemplate(base, inner string) revel.Result {
c.ViewArgs["ace_inner"] = inner
return c.RenderTemplate(base)
}

View File

@ -0,0 +1,139 @@
package app
import (
"fmt"
"github.com/revel/revel"
"github.com/yosssi/ace"
"html/template"
"io"
"strings"
)
const ACE_TEMPLATE = "ace"
// Adapter for Go Templates.
type AceTemplate struct {
*template.Template
engine *AceEngine
*revel.TemplateView
File *ace.File
Inner *ace.File
}
// A bit trick of an implementation
// If the arg contains an ace_inner field then that will be used
// to fetch a new template
func (acetmpl AceTemplate) Render(wr io.Writer, arg interface{}) error {
// We can redirect this render to another template if the arguments contain ace_content in them
if argmap, ok := arg.(map[string]interface{}); ok {
if acecontentraw, ok := argmap["ace-inner"]; ok {
acecontent := acecontentraw.(string)
newtemplatename := acetmpl.TemplateName + "-" + acecontent
// Now lookup the template again
if _, ok := acetmpl.engine.templatesByName[newtemplatename]; !ok {
if inner, ok := acetmpl.engine.templatesByName[acecontent]; !ok {
return fmt.Errorf("Inner content %s not found in ace templates", acecontent)
} else {
acetmpl.engine.templatesByName[newtemplatename] = &AceTemplate{
File: acetmpl.File,
Inner: inner.File,
engine: acetmpl.engine,
TemplateView: acetmpl.TemplateView}
}
}
return acetmpl.engine.templatesByName[newtemplatename].renderInternal(wr, arg)
}
}
return acetmpl.renderInternal(wr, arg)
}
func (acetmpl AceTemplate) renderInternal(wr io.Writer, arg interface{}) error {
if acetmpl.Template == nil {
// Compile the template first
if acetmpl.Inner == nil {
acetmpl.Inner = ace.NewFile("", nil)
}
source := ace.NewSource(acetmpl.File, acetmpl.Inner, acetmpl.engine.files)
result, err := ace.ParseSource(source, acetmpl.engine.Options)
if err != nil {
return err
}
if gtemplate, err := ace.CompileResult(acetmpl.TemplateName, result, acetmpl.engine.Options); err != nil {
return err
} else {
acetmpl.Template = gtemplate
}
}
return acetmpl.Execute(wr, arg)
}
type AceEngine struct {
loader *revel.TemplateLoader
templatesByName map[string]*AceTemplate
files []*ace.File
Options *ace.Options
CaseInsensitive bool
}
func (i *AceEngine) ConvertPath(path string) string {
if i.CaseInsensitive {
return strings.ToLower(path)
}
return path
}
func (i *AceEngine) Handles(templateView *revel.TemplateView) bool {
return revel.EngineHandles(i, templateView)
}
func (engine *AceEngine) ParseAndAdd(baseTemplate *revel.TemplateView) error {
// Ace templates must only render views specified for it (no trial and error)
if baseTemplate.EngineType != ACE_TEMPLATE {
return &revel.Error{
Title: "Template Compilation Error",
Path: baseTemplate.FilePath,
Description: "Not correct template for engine",
Line: 1,
SourceLines: baseTemplate.Content(),
}
}
baseTemplate.TemplateName = engine.ConvertPath(baseTemplate.TemplateName)
file := ace.NewFile(baseTemplate.TemplateName, baseTemplate.FileBytes)
engine.files = append(engine.files, file)
engine.templatesByName[baseTemplate.TemplateName] = &AceTemplate{File: file, engine: engine, TemplateView: baseTemplate}
return nil
}
func (engine *AceEngine) Lookup(templateName string) revel.Template {
if tpl, found := engine.templatesByName[engine.ConvertPath(templateName)]; found {
return tpl
}
return nil
}
func (engine *AceEngine) Name() string {
return ACE_TEMPLATE
}
func (engine *AceEngine) Event(action int, i interface{}) {
if action == revel.TEMPLATE_REFRESH_REQUESTED {
engine.templatesByName = map[string]*AceTemplate{}
engine.CaseInsensitive = revel.Config.BoolDefault("ace.template.caseinsensitive", true)
}
}
func init() {
revel.RegisterTemplateLoader(ACE_TEMPLATE, func(loader *revel.TemplateLoader) (revel.TemplateEngine, error) {
return &AceEngine{
loader: loader,
templatesByName: map[string]*AceTemplate{},
Options: &ace.Options{FuncMap: revel.TemplateFuncs},
}, nil
})
}

View File

@ -0,0 +1,9 @@
= doctype html
html lang=en
head
meta charset=utf-8
title Forbidden
body
h1 Base Template : {{.Error.Title}}
p : {{.Error.Description}}

View File

@ -0,0 +1,4 @@
{
"title": "{{Error.Title|escapejs}}",
"description": "{{Error.Description|escapejs}}"
}

View File

@ -0,0 +1,3 @@
{{.Error.Title}}
{{.Error.Description}}

View File

@ -0,0 +1,23 @@
package tests
import (
"github.com/revel/revel/testing"
)
type ApplicationTest struct {
testing.TestSuite
}
func (t *ApplicationTest) Before() {
println("Set up")
}
func (t *ApplicationTest) TestThatIndexPageWorks() {
t.Get("/")
t.AssertOk()
t.AssertContentType("text/html; charset=utf-8")
}
func (t *ApplicationTest) After() {
println("Tear down")
}

View File

@ -0,0 +1,149 @@
# Pongo2
The [PONGO2](https://github.com/flosch/pongo2) Templating Plugin
- Pongo2 templates may be identified by a `shebang` on the first line
(preferred method) or changing the file extension to home.pongo2.html.
By default the operation of revel assumes just a `.html` extension for
controller responses so it would make more sense to use the shebang
- Pongo2 templates can be set to be case sensitive by setting
`pongo2.tempate.caseinsensitive=false`, default is not case sensitive. If case sensitivity is
off the templates are compiled using lower case
- Currently the only functions built in are as follows:
- field
- radio
- option
- url
- checkbox
- append
Samples implementation below
##### Details
pongo2 is the successor of [pongo](https://github.com/flosch/pongo), a Django-syntax like templating-language.
Install/update using `go get` (no dependencies required by pongo2):
```
go get -u github.com/flosch/pongo2
```
Please use the [issue tracker](https://github.com/flosch/pongo2/issues) if you're encountering any problems with pongo2 or if you need help with implementing tags or filters ([create a ticket!](https://github.com/flosch/pongo2/issues/new)). If possible, please use [playground](https://www.florian-schlachter.de/pongo2/) to create a short test case on what's wrong and include the link to the snippet in your issue.
**New**: [Try pongo2 out in the pongo2 playground.](https://www.florian-schlachter.de/pongo2/)
```
{%append "moreStyles" "ui-lightness/jquery-ui-1.7.2.custom.css"%}
{%append "moreScripts" "js/jquery-ui-1.7.2.custom.min.js"%}
{% include "header.html" %}
<h1>Book hotel</h1>
<form method="POST" action="{%url "Hotels.Book" hotel.HotelId%}">
<p>
<strong>Name:</strong> {{hotel.Name}}
</p>
<p>
<strong>Address:</strong> {{hotel.Address}}
</p>
<p>
<strong>City:</strong> {{hotel.City}}
</p>
<p>
<strong>State:</strong> {{hotel.State}}
</p>
<p>
<strong>Zip:</strong> {{hotel.Zip}}
</p>
<p>
<strong>Country:</strong> {{hotel.Country}}
</p>
<p>
<strong>Nightly rate:</strong> {{hotel.Price}}
</p>
{%with field = "booking.CheckInDate"|field %}
<p class="{{field.ErrorClass}}">
<strong>Check In Date:</strong>
<input type="text" size="10" name="{{field.Name}}" class="datepicker" value="{{field.Flash}}">
* <span class="error">{{field.Error}}</span>
</p>
{% endwith %}
{%with field = "booking.CheckOutDate"|field %}
<p class="{{field.ErrorClass}}">
<strong>Check Out Date:</strong>
<input type="text" size="10" name="{{field.Name}}" class="datepicker" value="{{field.Flash}}">
* <span class="error">{{field.Error}}</span>
</p>
{% endwith %}
<p>
<strong>Room preference:</strong>
{%with field = "booking.Beds"|field %}
<select name="{{field.Name}}">
{%option field "1" "One king-size bed"%}
{%option field "2" "Two double beds"%}
{%option field "3" "Three beds"%}
</select>
{% endwith %}
</p>
<p>
<strong>Smoking preference:</strong>
{%with field = "booking.Smoking"|field %}
{%radio field "true"%} Smoking
{%radio field "false"%} Non smoking
{% endwith %}
</p>
{%with field = "booking.CardNumber"|field %}
<p class="{{field.ErrorClass}}">
<strong>Credit Card #:</strong>
<input type="text" name="{{field.Name}}" size="16" value="{{field.Flash}}">
* <span class="error">{{field.Error}}</span>
</p>
{% endwith %}
{%with field = "booking.NameOnCard"|field %}
<p class="{{field.ErrorClass}}">
<strong>Credit Card Name:</strong>
<input type="text" name="{{field.Name}}" size="16" value="{{field.Flash}}">
* <span class="error">{{field.Error}}</span>
</p>
{% endwith %}
<p>
<strong>Credit Card Expiry:</strong>
{%with field = "booking.CardExpMonth"|field %}
<select name="{{field.Name}}">
{%option field "1" "Jan"%}
{%option field "2" "Feb"%}
{%option field "3" "Mar"%}
{%option field "4" "Apr"%}
{%option field "5" "May"%}
{%option field "6" "Jun"%}
{%option field "7" "Jul"%}
{%option field "8" "Aug"%}
{%option field "9" "Sep"%}
{%option field "10" "Oct"%}
{%option field "11" "Nov"%}
{%option field "12" "Dec"%}
</select>
{% endwith %}
{%with field = "booking.CardExpYear"|field %}
<select name="{{field.Name}}">
{%option field "2008" "2008"%}
{%option field "2009" "2009"%}
{%option field "2010" "2010"%}
{%option field "2011" "2011"%}
{%option field "2012" "2012"%}
</select>
{% endwith %}
</p>
<p class="buttons">
<input type="submit" value="Proceed">
<a href="{%url "Hotels.Show" hotel.HotelId %}">Cancel</a>
</p>
</form>
<script type="text/javascript" charset="utf-8">
$(function() {
$(".datepicker").datepicker({dateFormat: 'yy-mm-dd'});
});
</script>
{% include "footer.html" %}
``

View File

@ -0,0 +1,16 @@
package pongo2
import (
p2 "github.com/flosch/pongo2"
"github.com/revel/revel"
)
func init() {
p2.RegisterFilter("field", func(in *p2.Value, param *p2.Value) (out *p2.Value, err *p2.Error) {
if nil == in.Interface() || in.String() == "" {
return nil, &p2.Error{Sender: "field argument must is string"}
}
newField := revel.NewField(in.String(), getContext())
return p2.AsValue(newField), nil
})
}

View File

@ -0,0 +1,184 @@
package pongo2
import (
"io"
"strings"
p2 "github.com/flosch/pongo2"
"github.com/revel/revel"
"github.com/tylerb/gls"
)
// Adapter for HAML Templates.
type PongoTemplate struct {
template *p2.Template
engine *PongoEngine
*revel.TemplateView
}
type Pongo2BaseTag struct {
field string
}
func (node *Pongo2BaseTag) GetField(ctx *p2.ExecutionContext) (value interface{}, found bool) {
value, found = ctx.Public[node.field]
if !found {
value, found = ctx.Private[node.field]
}
if found {
if wrapped, ok := value.(*p2.Value); ok {
value = wrapped.Interface()
}
}
return
}
type INodeImplied struct {
Exec func(*p2.ExecutionContext, p2.TemplateWriter) *p2.Error
}
func (i *INodeImplied) Execute(ctx *p2.ExecutionContext, w p2.TemplateWriter) *p2.Error {
return i.Exec(ctx, w)
}
func (tmpl PongoTemplate) Name() string {
return tmpl.TemplateName
}
func getContext() map[string]interface{} {
return gls.Get("data").(map[string]interface{})
}
// return a 'revel.Template' from HAML's template.
func (tmpl PongoTemplate) Render(wr io.Writer, arg interface{}) (err error) {
gls.With(gls.Values(map[interface{}]interface{}{"data": arg}), func() {
err = tmpl.template.ExecuteWriter(p2.Context(arg.(map[string]interface{})), wr)
if nil != err {
if e, ok := err.(*p2.Error); ok {
rerr := &revel.Error{
Title: "Template Execution Error",
Path: tmpl.TemplateName,
Description: e.Error(),
Line: e.Line,
}
if revel.DevMode {
rerr.SourceLines = tmpl.Content()
}
err = rerr
}
}
})
return err
}
// There is only a single instance of the PongoEngine initialized
type PongoEngine struct {
loader *revel.TemplateLoader
templateSetBybasePath map[string]*p2.TemplateSet
templates map[string]*PongoTemplate
CaseInsensitive bool
}
func (i *PongoEngine) ConvertPath(path string) string {
if i.CaseInsensitive {
return strings.ToLower(path)
}
return path
}
func (i *PongoEngine) Handles(templateView *revel.TemplateView) bool {
return revel.EngineHandles(i, templateView)
}
func (engine *PongoEngine) ParseAndAdd(baseTemplate *revel.TemplateView) error {
templateSet := engine.templateSetBybasePath[baseTemplate.BasePath]
if nil == templateSet {
templateSet = p2.NewSet(baseTemplate.BasePath, p2.MustNewLocalFileSystemLoader(baseTemplate.BasePath))
engine.templateSetBybasePath[baseTemplate.BasePath] = templateSet
}
tpl, err := templateSet.FromBytes(baseTemplate.FileBytes)
if nil != err {
_, line, description := parsePongo2Error(err)
return &revel.Error{
Title: "Template Compilation Error",
Path: baseTemplate.FilePath,
Description: description,
Line: line,
SourceLines: strings.Split(string(baseTemplate.FileBytes), "\n"),
}
}
baseTemplate.TemplateName = engine.ConvertPath(baseTemplate.TemplateName)
engine.templates[baseTemplate.TemplateName] = &PongoTemplate{
template: tpl,
engine: engine,
TemplateView: baseTemplate}
return nil
}
func (engine *PongoEngine) Name() string {
return "pongo2"
}
func parsePongo2Error(err error) (templateName string, line int, description string) {
pongoError := err.(*p2.Error)
if nil != pongoError {
return pongoError.Filename, pongoError.Line, pongoError.Error()
}
return "Unknown error", 0, err.Error()
}
func (engine *PongoEngine) Lookup(templateName string) revel.Template {
tpl, found := engine.templates[engine.ConvertPath(templateName)]
if !found {
return nil
}
return tpl
}
func (engine *PongoEngine) Event(action int, i interface{}) {
if action == revel.TEMPLATE_REFRESH_REQUESTED {
// At this point all the templates have been passed into the
engine.templateSetBybasePath = map[string]*p2.TemplateSet{}
engine.templates = map[string]*PongoTemplate{}
engine.CaseInsensitive = revel.Config.BoolDefault("pongo2.template.caseinsensitive", true)
}
}
func init() {
revel.RegisterTemplateLoader("pongo2", func(loader *revel.TemplateLoader) (revel.TemplateEngine, error) {
return &PongoEngine{
loader: loader,
templateSetBybasePath: map[string]*p2.TemplateSet{},
templates: map[string]*PongoTemplate{},
}, nil
})
/*
// TODO Dynamically call all the built in functions, PR welcome
for key,templateFunction := range revel.TemplateFuncs {
p2.RegisterTag(key, func(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) {
evals := []p2.IEvaluator{}
for arguments.Remaining() > 0 {
expr, err := arguments.ParseExpression()
evals = append(evals, expr)
if err != nil {
return nil, err
}
}
return &INodeImplied{Exec: func(ctx *p2.ExecutionContext,w p2.TemplateWriter) *p2.Error {
args := make([]interface{}, len(evals))
for i, ev := range evals {
obj, err := ev.Evaluate(ctx)
if err != nil {
return err
}
args[i] = obj
}
v:= &tagURLForNode{evals}
reflect.MakeFunc ....
return v.Execute(ctx,w)
}}, nil
})
}
*/
}

View File

@ -0,0 +1,87 @@
package pongo2
import (
p2 "github.com/flosch/pongo2"
"reflect"
)
type tagAppendNode struct {
isPublic bool
name string
objectEvaluators []p2.IEvaluator
}
func (node *tagAppendNode) Execute(ctx *p2.ExecutionContext, writer p2.TemplateWriter) *p2.Error {
var values []interface{}
var reflectValues reflect.Value
found := false
if o, found := ctx.Public[node.name]; found && nil != o {
values, _ = o.([]interface{})
if nil == values {
reflectValues = reflect.ValueOf(o)
if reflectValues.Kind() == reflect.Ptr {
reflectValues = reflectValues.Elem()
}
if reflectValues.Kind() != reflect.Slice {
return &p2.Error{Sender: "'" + node.name + "' isn't a slice."}
}
}
}
for _, ev := range node.objectEvaluators {
obj, err := ev.Evaluate(ctx)
if err != nil {
return err
}
if !found || reflectValues.IsNil() {
values = append(values, obj)
} else {
reflectValues = reflect.AppendSlice(reflectValues, reflect.ValueOf(obj))
}
}
if !found || reflectValues.IsNil() {
ctx.Public[node.name] = values
} else {
ctx.Public[node.name] = reflectValues.Interface()
}
return nil
}
// tagURLForParser implements a {% urlfor %} tag.
//
// urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data.
// Example: {% urlfor "UserController.View" ":slug" "oal" %}
func tagAppendParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) {
var name string
var isPublic bool
// Parse variable name
typeToken := arguments.MatchType(p2.TokenIdentifier)
if typeToken != nil {
name = typeToken.Val
} else if sToken := arguments.MatchType(p2.TokenString); nil != sToken {
name = sToken.Val
} else {
return nil, arguments.Error("Expected an identifier or string.", nil)
}
evals := []p2.IEvaluator{}
for arguments.Remaining() > 0 {
expr, err := arguments.ParseExpression()
if err != nil {
return nil, err
}
evals = append(evals, expr)
}
return &INodeImplied{Exec: func(ctx *p2.ExecutionContext, w p2.TemplateWriter) *p2.Error {
node := &tagAppendNode{isPublic, name, evals}
return node.Execute(ctx, w)
}}, nil
}
func init() {
p2.RegisterTag("append", tagAppendParser)
}

View File

@ -0,0 +1,70 @@
package pongo2
import (
"fmt"
"html"
p2 "github.com/flosch/pongo2"
"github.com/revel/revel"
)
type tagCheckboxNode struct {
value p2.IEvaluator
Pongo2BaseTag
}
func (node *tagCheckboxNode) Execute(ctx *p2.ExecutionContext, writer p2.TemplateWriter) *p2.Error {
fieldObj, _ := node.GetField(ctx)
if nil == fieldObj {
return ctx.Error("field '"+node.field+"' tagCheckboxNode is missing.", nil)
}
field, _ := fieldObj.(*revel.Field)
if nil == field {
return ctx.Error(fmt.Sprintf("field '"+node.field+"' isn't Field - %T.", fieldObj), nil)
}
val, err := node.value.Evaluate(ctx)
if err != nil {
return err
}
val_str := val.String()
checked := ""
if field.Flash() == val_str {
checked = " checked"
}
fmt.Fprintf(writer, `<input type="checkbox" name="%s" value="%s"%s>`,
html.EscapeString(field.Name), html.EscapeString(val_str), checked)
return nil
}
// tagURLForParser implements a {% urlfor %} tag.
//
// urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data.
// Example: {% urlfor "UserController.View" ":slug" "oal" %}
func tagCheckboxParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) {
var field string
typeToken := arguments.MatchType(p2.TokenIdentifier)
if typeToken != nil {
field = typeToken.Val
} else if sToken := arguments.MatchType(p2.TokenString); nil != sToken {
field = sToken.Val
} else {
return nil, arguments.Error("Expected an identifier or string.", nil)
}
expr, err := arguments.ParseExpression()
if err != nil {
return nil, err
}
return &INodeImplied{Exec: func(ctx *p2.ExecutionContext, w p2.TemplateWriter) *p2.Error {
v := tagCheckboxNode{Pongo2BaseTag: Pongo2BaseTag{field: field},
value: expr}
return v.Execute(ctx, w)
}}, nil
}
func init() {
p2.RegisterTag("checkbox", tagCheckboxParser)
}

View File

@ -0,0 +1,79 @@
package pongo2
import (
"fmt"
"html"
p2 "github.com/flosch/pongo2"
"github.com/revel/revel"
)
type tagOptionNode struct {
value p2.IEvaluator
label string
Pongo2BaseTag
}
func (node *tagOptionNode) Execute(ctx *p2.ExecutionContext, writer p2.TemplateWriter) *p2.Error {
fieldObj, _ := node.GetField(ctx)
if nil == fieldObj {
return ctx.Error("field '"+node.field+"' tagOptionNode is missing.", nil)
}
field, _ := fieldObj.(*revel.Field)
if nil == field {
return ctx.Error(fmt.Sprintf("field '"+node.field+"' isn't Field - %T.", fieldObj), nil)
}
val, err := node.value.Evaluate(ctx)
if err != nil {
return err
}
val_str := val.String()
selected := ""
if field.Flash() == val_str || (field.Flash() == "" && field.Value() == val_str) {
selected = " selected"
}
fmt.Fprintf(writer, `<option value="%s"%s>%s</option>`,
html.EscapeString(val_str), selected, html.EscapeString(node.label))
return nil
}
// tagURLForParser implements a {% urlfor %} tag.
//
// urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data.
// Example: {% urlfor "UserController.View" ":slug" "oal" %}
func tagOptionParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) {
var field string
typeToken := arguments.MatchType(p2.TokenIdentifier)
if typeToken != nil {
field = typeToken.Val
} else if sToken := arguments.MatchType(p2.TokenString); nil != sToken {
field = sToken.Val
} else {
return nil, arguments.Error("Expected an identifier or string.", nil)
}
expr, err := arguments.ParseExpression()
if err != nil {
return nil, err
}
var v *tagOptionNode
if sToken := arguments.MatchType(p2.TokenString); nil != sToken {
v = &tagOptionNode{Pongo2BaseTag: Pongo2BaseTag{field: field},
value: expr,
label: sToken.Val}
} else {
return nil, arguments.Error("Expected an string.", nil)
}
return &INodeImplied{Exec: func(ctx *p2.ExecutionContext, w p2.TemplateWriter) *p2.Error {
return v.Execute(ctx, w)
}}, nil
}
func init() {
p2.RegisterTag("option", tagOptionParser)
}

View File

@ -0,0 +1,69 @@
package pongo2
import (
"fmt"
"html"
p2 "github.com/flosch/pongo2"
"github.com/revel/revel"
)
type tagRadioNode struct {
value p2.IEvaluator
Pongo2BaseTag
}
func (node *tagRadioNode) Execute(ctx *p2.ExecutionContext, writer p2.TemplateWriter) *p2.Error {
fieldObj, _ := node.GetField(ctx)
if nil == fieldObj {
return ctx.Error("field '"+node.field+"' tagRadioNode is missing.", nil)
}
field, _ := fieldObj.(*revel.Field)
if nil == field {
return ctx.Error(fmt.Sprintf("field '"+node.field+"' isn't Field - %T.", fieldObj), nil)
}
val, err := node.value.Evaluate(ctx)
if err != nil {
return err
}
val_str := val.String()
checked := ""
if field.Flash() == val_str {
checked = " checked"
}
fmt.Fprintf(writer, `<input type="radio" name="%s" value="%s"%s>`,
html.EscapeString(field.Name), html.EscapeString(val_str), checked)
return nil
}
// tagURLForParser implements a {% urlfor %} tag.
//
// urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data.
// Example: {% urlfor "UserController.View" ":slug" "oal" %}
func tagRadioParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) {
var field string
typeToken := arguments.MatchType(p2.TokenIdentifier)
if typeToken != nil {
field = typeToken.Val
} else if sToken := arguments.MatchType(p2.TokenString); nil != sToken {
field = sToken.Val
} else {
return nil, arguments.Error("Expected an identifier or string.", nil)
}
expr, err := arguments.ParseExpression()
if err != nil {
return nil, err
}
return &INodeImplied{Exec: func(ctx *p2.ExecutionContext, w p2.TemplateWriter) *p2.Error {
v := &tagRadioNode{Pongo2BaseTag: Pongo2BaseTag{field: field},
value: expr}
return v.Execute(ctx, w)
}}, nil
}
func init() {
p2.RegisterTag("radio", tagRadioParser)
}

View File

@ -0,0 +1,64 @@
package pongo2
import (
"github.com/revel/revel"
p2 "github.com/flosch/pongo2"
)
type tagURLForNode struct {
objectEvaluators []p2.IEvaluator
}
func (node *tagURLForNode) Execute(ctx *p2.ExecutionContext, writer p2.TemplateWriter) *p2.Error {
args := make([]string, len(node.objectEvaluators))
for i, ev := range node.objectEvaluators {
obj, err := ev.Evaluate(ctx)
if err != nil {
return err
}
args[i] = obj.String()
}
params := make([]interface{}, len(args))
params[0] = args[0]
for i := range params[1:] {
params[i+1] = args[i+1]
}
url, err := revel.ReverseURL(params...)
if nil != err {
return ctx.Error(err.Error(), nil)
}
writer.WriteString(string(url))
return nil
}
// tagURLForParser implements a {% urlfor %} tag.
//
// urlfor takes one argument for the controller, as well as any number of key/value pairs for additional URL data.
// Example: {% urlfor "UserController.View" ":slug" "oal" %}
func tagURLForParser(doc *p2.Parser, start *p2.Token, arguments *p2.Parser) (p2.INodeTag, *p2.Error) {
evals := []p2.IEvaluator{}
for arguments.Remaining() > 0 {
expr, err := arguments.ParseExpression()
evals = append(evals, expr)
if err != nil {
return nil, err
}
}
if len(evals) <= 0 {
return nil, arguments.Error("URL takes one argument for the controller and any number of optional value.", nil)
}
return &INodeImplied{Exec: func(ctx *p2.ExecutionContext, w p2.TemplateWriter) *p2.Error {
v := &tagURLForNode{evals}
return v.Execute(ctx, w)
}}, nil
}
func init() {
p2.RegisterTag("url", tagURLForParser)
}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Forbidden</title>
</head>
<body>
<h1>
{{Error.Title}}
</h1>
<p>
{{Error.Description}}
</p>
{{end}}
</body>
</html>

View File

@ -0,0 +1,4 @@
{
"title": "{{Error.Title|escapejs}}",
"description": "{{Error.Description|escapejs}}"
}

View File

@ -0,0 +1,3 @@
{{Error.Title}}
{{Error.Description}}

View File

@ -0,0 +1 @@
<forbidden>{{Error.Description}}</forbidden>

View File

@ -0,0 +1,61 @@
<style type="text/css">
html, body {
margin: 0;
padding: 0;
font-family: Helvetica, Arial, Sans;
background: #EEEEEE;
}
.block {
padding: 20px;
border-bottom: 1px solid #aaa;
}
#header h1 {
font-weight: normal;
font-size: 28px;
margin: 0;
}
#more {
color: #666;
font-size: 80%;
border: none;
}
#header {
background: #FFFFCC;
}
#header p {
color: #333;
}
#routes {
background: #f6f6f6;
}
#routes h2 {
font-weight: normal;
font-size: 18px;
margin: 0 0 10px 0;
}
#routes ol {
}
#routes li {
font-size: 14px;
font-family: monospace;
color: #333;
}
</style>
<div id="header" class="block">
<h1>
{{Error.Title}}
</h1>
<p>
{{Error.Description}}
</p>
</div>
<div id="routes" class="block">
<h2>These routes have been tried, in this order :</h2>
<ol>
{% for route in Router.Routes %}
<li>{{route.Method}} {{route.Path}}{{route.Action}}</li>
{% endfor %}
</ol>
</div>

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Not found</title>
</head>
<body>
{% if DevMode %}
{% include "errors/404-dev.html" %}
{% else %}
<h1>
{{ Error.Title }}
</h1>
<p>
{{ Error.Description}}
</p>
{% endif %}
</body>
</html>

View File

@ -0,0 +1,4 @@
{
"title": "{{Error.Title|escapejs}}",
"description": "{{Error.Description|escapejs}}"
}

View File

@ -0,0 +1,3 @@
{{Error.Title}}
{{Error.Description}}

View File

@ -0,0 +1 @@
<notfound>{{Error.Description}}</notfound>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Method not allowed</title>
</head>
<body>
<h1>
{{Error.Title}}
</h1>
<p>
{{Error.Description}}
</p>
</body>
</html>

View File

@ -0,0 +1,4 @@
{
"title": "{{Error.Title|escapejs}}",
"description": "{{Error.Description|escapejs}}"
}

View File

@ -0,0 +1,3 @@
{{Error.Title}}
{{Error.Description}}

View File

@ -0,0 +1 @@
<method-not-allowed>{{Error.Description}}</method-not-allowed>

View File

@ -0,0 +1,131 @@
<style type="text/css">
html, body {
margin: 0;
padding: 0;
font-family: Helvetica, Arial, Sans;
background: #EEEEEE;
}
.block {
padding: 20px;
border-bottom: 1px solid #aaa;
}
#header h1 {
font-weight: normal;
font-size: 28px;
margin: 0;
}
#more {
color: #666;
font-size: 80%;
border: none;
}
#header {
background: #fcd2da;
}
#header p {
color: #333;
}
#source {
background: #f6f6f6;
}
#source h2 {
font-weight: normal;
font-size: 18px;
margin: 0 0 10px 0;
}
#source .lineNumber {
float: left;
display: block;
width: 40px;
text-align: right;
margin-right: 10px;
font-size: 14px;
font-family: monospace;
background: #333;
color: #fff;
}
#source .line {
clear: both;
color: #333;
margin-bottom: 1px;
}
#source pre {
font-size: 14px;
margin: 0;
overflow-x: hidden;
}
#source .error {
color: #c00 !important;
}
#source .error .lineNumber {
background: #c00;
}
#source a {
text-decoration: none;
}
#source a:hover * {
cursor: pointer !important;
}
#source a:hover pre {
background: #FAFFCF !important;
}
#source em {
font-style: normal;
text-decoration: underline;
font-weight: bold;
}
#source strong {
font-style: normal;
font-weight: bold;
}
#stack {
background: #eee;
padding:0 1em 1em;
}
#stack h3 {
font-weight: normal;
}
#stack code {
font-family:monospace;
white-space: pre;
}
</style>
<div id="header" class="block">
<h1>{{Error.Title}}</h1>
<p>
{% if Error.SourceType %}
The {{Error.SourceType}} <strong>{{Error.Path}}</strong> does not compile: <strong>{{Error.Description}}</strong>
{% else %}
{{Error.Description}}
{% endif %}
</p>
</div>
{% if Error.Path %}
<div id="source" class="block">
<h2>In {{Error.Path}}
{% if Error.Line %}
(around {% if Error.Line %}line {{Error.Line}}{% endif %}{% if Error.Column %} column {{Error.Column}}{% endif %})
{% endif %}
</h2>
{% for src in Error.ContextSource %}
<div class="line{% if src.IsError %} error{% endif %}">
<span class="lineNumber">{{src.Line}}:</span>
<pre>{{src.Source}}</pre>
</div>
{% endfor %}
</div>
{% endif %}
{% if Error.Stack %}
<div id="stack">
<h3>Call Stack</h3>
<code>{{Error.Stack}}</code>
</div>
{% endif %}
{% if Error.MetaError %}
<div id="source" class="block">
<h2>Additionally, an error occurred while handling this error.</h2>
<div class="line error">
{{Error.MetaError}}
</div>
</div>
{% endif %}

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Application error</title>
</head>
<body>
{% if DevMode %}
{% include "errors/500-dev.html" %}
{% else %}
<h1>Oops, an error occured</h1>
<p>
This exception has been logged.
</p>
{% endif %}
</body>
</html>

View File

@ -0,0 +1,4 @@
{
"title": "{{Error.Title|escapejs}}",
"description": "{{Error.Description|escapejs}}"
}

View File

@ -0,0 +1,13 @@
{{Error.Title}}
{{Error.Description}}
{% if RunMode == "dev" %}
{% if Error.Path %}
----------
In {{Error.Path}} {% if Error.Line %}(around line {{Error.Line}}){% endif %}
{% for src in Error.ContextSource %}
{% if src.IsError %}>{% else %} {% endif %} {{src.Line}}: {{src.Source}}{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,4 @@
<error>
<title>{{Error.Title}}</title>
<description>{{Error.Description}}</description>
</error>

View File

@ -0,0 +1,3 @@
package pongo2
// Required for vendoring see golang.org/issue/13832