/*
Copyright © 2014–2019 Thomas Michael Edwards. All rights reserved.
Use of this source code is governed by a Simplified BSD License which
can be found in the LICENSE file.
*/
package main
import (
"bytes"
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
func (s *story) toTwee(outMode outputMode) []byte {
var data []byte
for _, p := range s.passages {
data = append(data, p.toTwee(outMode)...)
}
return data
}
func (s *story) toTwine2Archive(startName string) []byte {
return append(s.getTwine2DataChunk(startName), '\n')
}
func (s *story) toTwine1Archive(startName string) []byte {
var (
count uint
data []byte
template []byte
)
data, count = s.getTwine1PassageChunk()
// NOTE: In Twine 1.4, the passage data wrapper is part of the story formats
// themselves, so we have to create/forge one here. We use the Twine 1.4 vanilla
// `storeArea` ID, rather than SugarCube's preferred `store-area` ID, for maximum
// compatibility and interoperability.
template = append(template, fmt.Sprintf(`
`, count)...)
template = append(template, data...)
template = append(template, "
\n"...)
return template
}
func (s *story) toTwine2HTML(startName string) []byte {
var template = s.format.source()
// Story instance replacements.
if bytes.Contains(template, []byte("{{STORY_NAME}}")) {
template = bytes.Replace(template, []byte("{{STORY_NAME}}"), []byte(htmlEscapeString(s.name)), -1)
}
if bytes.Contains(template, []byte("{{STORY_DATA}}")) {
template = bytes.Replace(template, []byte("{{STORY_DATA}}"), s.getTwine2DataChunk(startName), 1)
}
return template
}
func (s *story) toTwine1HTML(startName string) []byte {
var (
formatDir = filepath.Dir(s.format.filename)
parentDir = filepath.Dir(formatDir)
template = s.format.source()
count uint
data []byte
component []byte
err error
)
// Get the story data.
data, count = s.getTwine1PassageChunk()
// Story format compiler byline replacement.
if search := []byte(`Twine`), []byte(`>Tweego`), 1)
}
// Story format component replacements (SugarCube).
if search := []byte(`"USER_LIB"`); bytes.Contains(template, search) {
component, err = fileReadAllAsUTF8(filepath.Join(formatDir, "userlib.js"))
if err == nil {
template = bytes.Replace(template, search, component, 1)
} else if !os.IsNotExist(err) {
log.Fatalf("error: %s", err.Error())
}
}
// Story format component replacements (Twine 1.4+ vanilla story formats).
if search := []byte(`"ENGINE"`); bytes.Contains(template, search) {
component, err = fileReadAllAsUTF8(filepath.Join(parentDir, "engine.js"))
if err != nil {
log.Fatalf("error: %s", err.Error())
}
template = bytes.Replace(template, search, component, 1)
}
for _, pattern := range []string{`"SUGARCANE"`, `"JONAH"`} {
if search := []byte(pattern); bytes.Contains(template, search) {
component, err = fileReadAllAsUTF8(filepath.Join(formatDir, "code.js"))
if err != nil {
log.Fatalf("error: %s", err.Error())
}
template = bytes.Replace(template, search, component, 1)
}
}
if s.twine1.settings["jquery"] == "on" {
if search := []byte(`"JQUERY"`); bytes.Contains(template, search) {
component, err = fileReadAllAsUTF8(filepath.Join(parentDir, "jquery.js"))
if err != nil {
log.Fatalf("error: %s", err.Error())
}
template = bytes.Replace(template, search, component, 1)
}
}
if s.twine1.settings["modernizr"] == "on" {
if search := []byte(`"MODERNIZR"`); bytes.Contains(template, search) {
component, err = fileReadAllAsUTF8(filepath.Join(parentDir, "modernizr.js"))
if err != nil {
log.Fatalf("error: %s", err.Error())
}
template = bytes.Replace(template, search, component, 1)
}
}
// Story instance replacements.
if startName == defaultStartName {
startName = ""
}
template = bytes.Replace(template, []byte(`"VERSION"`),
[]byte(fmt.Sprintf("Compiled with %s, %s", tweegoName, tweegoVersion.Version())), 1)
template = bytes.Replace(template, []byte(`"TIME"`),
[]byte(fmt.Sprintf("Built on %s", time.Now().Format(time.RFC1123Z))), 1)
template = bytes.Replace(template, []byte(`"START_AT"`),
[]byte(fmt.Sprintf(`%q`, startName)), 1)
template = bytes.Replace(template, []byte(`"STORY_SIZE"`),
[]byte(fmt.Sprintf(`"%d"`, count)), 1)
if bytes.Contains(template, []byte(`"STORY"`)) {
// Twine/Twee ≥1.4 style story format.
template = bytes.Replace(template, []byte(`"STORY"`), data, 1)
} else {
// Twine/Twee <1.4 style story format.
var footer []byte
footer, err = fileReadAllAsUTF8(filepath.Join(formatDir, "footer.html"))
if err != nil {
if os.IsNotExist(err) {
footer = []byte("\n