Example #1
0
func (w *ViewWriter) processNodes2(htmlWriter, srcWriter, patternWriter *formatting.IndentingWriter) {
	// initialise opening quote for htmlArray
	htmlWriter.Print("`")

	// initialise starting indent for src
	srcWriter.IncrIndent()

	// initialise starting indent and openning quote
	patternWriter.IncrIndent()

	htmlIndex := 0
	patternIndex := 0
	for n := w.rootNode.children.Front(); n != nil; n = n.Next() {
		htmlIndex, _ = w.writeNode(n, htmlWriter, srcWriter, patternWriter, htmlIndex, patternIndex)
	}

	// close quote for html Array
	htmlWriter.Print("`,")

	// Ensure final html is written
	srcWriter.Printf("fmt.Fprint(w, %sHtml[%d])\n", w.viewName, htmlIndex)

	// if our last op was writing code, we need to close pattern string
	if w.writingCodeOutput {
		patternWriter.Println("`,")
	}
}
Example #2
0
func (w *ViewWriter) writeCodeExecution(nd *Node, haml *formatting.IndentingWriter, src *formatting.IndentingWriter, currentHtmlIndex int) int {
	// end most recent haml output
	haml.Println("`,")
	// start next haml output (which will follow this code output
	haml.Println("`")

	// All call to write html from array
	src.Printf("fmt.Fprint(w, %sHtml[%d])\n", w.destinationName, currentHtmlIndex)
	currentHtmlIndex++

	// attempt to keep formatting across user code.
	// Here we're checking to see if this is the end of a block statement
	// if so, we need to decrease indent
	first := getFirstChar(nd.text)
	if first == '}' {
		src.DecrIndent()
	}

	// add user's code
	src.Printf("%s\n", nd.text)

	// If user code ends in {, incr indent as they started a block statement
	last := getLastChar(nd.text)
	if last == '{' {
		src.IncrIndent()
	}

	for n := nd.children.Front(); n != nil; n = n.Next() {
		currentHtmlIndex = w.writeNode(n.Value.(*Node), haml, src, currentHtmlIndex)
	}

	return currentHtmlIndex
}
Example #3
0
func (w *ViewWriter) writeCodeOutput(nd *Node, haml *formatting.IndentingWriter, src *formatting.IndentingWriter, currentHtmlIndex int) int {
	// end most recent haml output
	haml.Println("`,")
	// start next haml output (which will follow this code output
	haml.Println("`")

	// All call to write html from array
	src.Printf("fmt.Fprint(w, %sHtml[%d])\n", w.destinationName, currentHtmlIndex)
	currentHtmlIndex++

	// add call to print output
	src.Printf("fmt.Fprint(w, %s)\n", nd.text)

	for n := nd.children.Front(); n != nil; n = n.Next() {
		currentHtmlIndex = w.writeNode(n.Value.(*Node), haml, src, currentHtmlIndex)
	}

	return currentHtmlIndex
}
Example #4
0
// Recursive function to write parsed HAML Nodes
func (w *ViewWriter) writeNode(nd *Node, haml *formatting.IndentingWriter, src *formatting.IndentingWriter, currentHtmlIndex int) int {

	if nd.name == "code_output" {
		return w.writeCodeOutput(nd, haml, src, currentHtmlIndex)
	} else if nd.name == "code_execution" {
		return w.writeCodeExecution(nd, haml, src, currentHtmlIndex)
	}

	haml.Printf("<%s", nd.name)
	if nd.id != nil {
		w.writeAttribute(nd.id, haml)
	}
	if nd.class != nil {
		w.writeAttribute(nd.class, haml)
	}

	for attrEl := nd.attributes.Front(); attrEl != nil; attrEl = attrEl.Next() {
		attr := attrEl.Value.(*nameValueStr)
		w.writeAttribute(attr, haml)
	}

	if nd.selfClosing {
		haml.Println(" />`)")
		return currentHtmlIndex
	} else {
		haml.Print(">")
	}

	// Outputting text.

	// If tag only contains short text, add it on same line
	if w.canChildContentFitOnOneLine(nd) {
		haml.Printf("%s</%s>\n", nd.text, nd.name)
		return currentHtmlIndex
	}

	// We either have long text, child tags or both
	// so we add it as indented child content
	haml.Println("")
	haml.IncrIndent()

	if len(nd.text) > 0 {
		w.writeLongText(nd.text, haml)
	}

	for n := nd.children.Front(); n != nil; n = n.Next() {
		currentHtmlIndex = w.writeNode(n.Value.(*Node), haml, src, currentHtmlIndex)
	}

	haml.DecrIndent()
	haml.Printf("</%s>\n", nd.name)

	return currentHtmlIndex
}
Example #5
0
func (w *ViewWriter) writeCodeOutput(el *list.Element, haml, src, pattern *formatting.IndentingWriter,
	currentHtmlIndex, currentPatternIndex int, nodeType CodeOutputType) (htmlIndex, patternIndex int) {

	nd := el.Value.(*Node)

	htmlIndex = currentHtmlIndex
	patternIndex = currentPatternIndex

	if !w.writingCodeOutput {
		// First code output node - close off haml node output:

		// end most recent haml output
		haml.Println("`,")
		// start next haml output (which will follow this code output
		haml.Println("`")

		// Add call to write html from array
		src.Printf("fmt.Fprint(w, %sHtml[%d])\n", w.viewName, currentHtmlIndex)

		if nodeType == Literal || nodeType == EscapedValue {
			// Add calls to execute template. However, we need to know which
			// object to inject into template. Usually this will be 'data', but
			// can be something else inside a loop, for example, so we take the
			// object from the first dynamic element
			objectToInject := "data"
			if nodeType == EscapedValue {
				objectToInject = getObjectName(nd.text)
			} else {
			LookaheadLoop:
				for n := el; n != nil; n = n.Next() {
					node := n.Value.(*Node)
					switch node.name {
					case "code_output_dynamic":
						objectToInject = getObjectName(node.text)
						break LookaheadLoop
					}
				}
			}
			src.Printf("err = wr.templates[%d].Execute(w, %s)\n", currentPatternIndex, objectToInject)
			src.Printf("handle%sError(err)\n", w.properViewName)
			// start a new pattern string
			pattern.Print("`")

			w.writingCodeOutput = true
			patternIndex++
		}

		htmlIndex++
	}

	// These stop writing patterns, so we need to close off pattern strings
	if w.writingCodeOutput && (nodeType == RawValue || nodeType == Execution) {
		pattern.Println("`,")
		w.writingCodeOutput = false
	}

	// add call to print output
	switch nodeType {
	case Literal:
		pattern.Print(nd.text)
	case EscapedValue:
		// print the path to the desired object for the template pattern
		patternStr := "."
		index := strings.Index(nd.text, ".")
		if index > 0 {
			patternStr = nd.text[index:]
		}
		pattern.Printf("{{%s}}", patternStr)
	case RawValue:
		src.Printf("fmt.Fprint(w, %s)\n", nd.text)
	case Execution:
		// attempt to keep formatting across user code.
		// Here we're checking to see if this is the end of a block statement
		// if so, we need to decrease indent
		first := getFirstChar(nd.text)
		if first == '}' {
			src.DecrIndent()
		}

		// add user's code
		src.Printf("%s\n", nd.text)

		// If user code ends in {, incr indent as they started a block statement
		last := getLastChar(nd.text)
		if last == '{' {
			src.IncrIndent()
		}
	}

	for n := nd.children.Front(); n != nil; n = n.Next() {
		htmlIndex, patternIndex = w.writeNode(n, haml, src, pattern, htmlIndex, patternIndex)
	}

	return
}
Example #6
0
func (w *ViewWriter) writeAttribute(attribute *nameValueStr, haml *formatting.IndentingWriter) {
	haml.Printf(" %s=\"%s\"", attribute.name, attribute.value)
}
Example #7
0
// Recursive function to write parsed HAML Nodes
// We have to return a bool indicating if we have escaped any HTML (XSS protection)
// so that we know if we need to include the templating library for that function
func (w *ViewWriter) writeNode(el *list.Element,
	haml, src, pattern *formatting.IndentingWriter,
	currentHtmlIndex, currentPatternIndex int) (htmlIndex, patternIndex int) {

	nd := el.Value.(*Node)

	htmlIndex = currentHtmlIndex
	patternIndex = currentPatternIndex

	switch nd.name {
	case "code_output_literal":
		return w.writeCodeOutput(el, haml, src, pattern, htmlIndex, patternIndex, Literal)
	case "code_output_value":
		return w.writeCodeOutput(el, haml, src, pattern, htmlIndex, patternIndex, EscapedValue)
	case "code_output_raw":
		return w.writeCodeOutput(el, haml, src, pattern, htmlIndex, patternIndex, RawValue)
	case "code_execution":
		return w.writeCodeOutput(el, haml, src, pattern, htmlIndex, patternIndex, Execution)
	}

	if w.writingCodeOutput {
		// we've finished writing code output and we're back to haml
		// so close off our pattern string
		pattern.Println("`,")
	}
	w.writingCodeOutput = false

	if nd.name != "" {
		haml.Printf("<%s", nd.name)
		if nd.id != nil {
			w.writeAttribute(nd.id, haml)
		}
		if nd.class != nil {
			w.writeAttribute(nd.class, haml)
		}

		for attrEl := nd.attributes.Front(); attrEl != nil; attrEl = attrEl.Next() {
			attr := attrEl.Value.(*nameValueStr)
			w.writeAttribute(attr, haml)
		}

		if nd.selfClosing {
			haml.Print(" />")
			if nd.text != "" {
				haml.Printf(" %s", nd.text)
			}
			haml.Println("")
			return
		} else {
			haml.Print(">")
		}
	}

	// Outputting text.

	// If tag only contains short text, add it on same line
	if w.canChildContentFitOnOneLine(nd) {
		if nd.name == "" {
			haml.Printf("%s\n", nd.text)
		} else {
			haml.Printf("%s</%s>\n", nd.text, nd.name)
		}
		return
	}

	// We either have long text, child tags or both
	// so we add it as indented child content
	haml.Println("")
	haml.IncrIndent()

	if len(nd.text) > 0 {
		w.writeLongText(nd.text, haml)
	}

	for n := nd.children.Front(); n != nil; n = n.Next() {
		htmlIndex, patternIndex = w.writeNode(n, haml, src, pattern, htmlIndex, patternIndex)
	}

	haml.DecrIndent()
	if nd.name != "" {
		haml.Printf("</%s>\n", nd.name)
	}

	return
}