예제 #1
0
func extractTemplateFiles(v *fb.FileCollectionView) (map[string]string, error) {
	templates := make(map[string]string)
	for _, filename := range v.FileList() {
		log.Debugf("Filename: %s\n", filename)
		att, ok := v.GetFile(filename)
		if !ok {
			return nil, errors.Errorf("Error fetching expected file '%s' from Model", filename)
		}
		log.Debugf("ContentType: %s\n", att.ContentType)
		if _, ok := templateTypes[att.ContentType]; ok {
			templates[filename] = string(att.Content)
		}
	}
	return templates, nil
}
예제 #2
0
// NewDB returns a DB handle, complete with binding to the Find plugin, to the
// requested DB
func NewDB(name string) (*DB, error) {
	db := newDB(name)
	parts := strings.SplitN(name, "-", 2)
	if initFunc, ok := initFuncs[parts[0]]; ok {
		log.Debugf("Initializing DB %s", name)
		return db, initFunc(db)
	}
	return db, nil
}
예제 #3
0
func (n *Note) fetchTheme() error {
	if n.theme != nil {
		// Nothing to do
		return nil
	}
	log.Debugf("Fetching theme %s", n.ThemeID)
	t := &fb.Theme{}
	if err := n.db.Get(n.ThemeID, t, pouchdb.Options{Attachments: true}); err != nil {
		fmt.Printf("Error: %s\n", err)
		return errors.Wrapf(err, "fetchTheme() can't fetch %s", n.ThemeID)
	}
	m := t.Models[n.ModelID]
	n.theme = &Theme{t}
	n.model = &Model{m}
	n.model.Theme = t
	n.SetModel(m)

	log.Debugf("Fetched this model: %v\n", n.model)
	log.Debugf("Fetched this theme: %v\n", n.theme)
	return nil
}
예제 #4
0
// BeforeTransition prepares the page to study
func BeforeTransition(event *jquery.Event, ui *js.Object, p url.Values) bool {
	u, err := repo.CurrentUser()
	if err != nil {
		log.Printf("No user logged in: %s\n", err)
		return false
	}
	log.Debugf("card = %s\n", p.Get("card"))
	go func() {
		container := jQuery(":mobile-pagecontainer")
		// Ensure the indexes are created before trying to use them
		u.DB()

		card, err := repo.GetRandomCard()
		if err != nil {
			log.Printf("Error fetching card: %+v\n", err)
			return
		}
		log.Debugf("card = %s\n", card)
		body, iframeID, err := card.Body()
		if err != nil {
			log.Printf("Error parsing body: %+v\n", err)
			return
		}
		log.Debugf("body = %s\niframe = %s\n", body, iframeID)

		iframe := js.Global.Get("document").Call("createElement", "iframe")
		iframe.Call("setAttribute", "sandbox", "allow-scripts")
		iframe.Call("setAttribute", "seamless", nil)
		iframe.Set("id", iframeID)
		iframe.Set("src", "data:text/html;charset=utf-8;base64,"+base64.StdEncoding.EncodeToString([]byte(body)))

		js.Global.Get("document").Call("getElementById", "cardframe").Call("appendChild", iframe)

		jQuery(".show-until-load", container).Hide()
		jQuery(".hide-until-load", container).Show()
	}()

	return true
}
예제 #5
0
func (c *Card) inlineSrc(n *html.Node) error {
	doc := goquery.NewDocumentFromNode(n)
	doc.Find("img").Each(func(i int, s *goquery.Selection) {
		src, ok := s.Attr("src")
		if !ok {
			log.Print("Found an image with no source!!??")
			return
		}
		log.Debugf("Found image with src of '%s'", src)
		att, err := c.GetAttachment(src)
		if err != nil {
			log.Printf("Error inlining file '%s': %s", src, err)
			return
		}
		s.SetAttr("src", fmt.Sprintf("data:%s;base64,%s", att.ContentType, base64.StdEncoding.EncodeToString(att.Content)))
		// iframe.Set("src", "data:text/html;charset=utf-8;base64,"+base64.StdEncoding.EncodeToString([]byte(body)))
	})
	return nil
}
예제 #6
0
func (c *Card) fetchNote() error {
	if c.note != nil {
		// Nothing to do
		return nil
	}
	log.Debugf("Fetching note %s", c.NoteID())
	db, err := NewDB(c.BundleID())
	if err != nil {
		return errors.Wrap(err, "fetchNote() can't connect to bundle DB")
	}
	n := &fb.Note{}
	if err := db.Get(c.NoteID(), n, pouchdb.Options{Attachments: true}); err != nil {
		return errors.Wrapf(err, "fetchNote() can't fetch %s", c.NoteID())
	}
	c.note = &Note{
		Note: n,
		db:   db,
	}
	return nil
}
예제 #7
0
// GenerateTemplate returns a string representing the Model's rendered template.
func (m *Model) GenerateTemplate() (*template.Template, error) {
	log.Debugf("model: %v", m)
	mainTemplate := fmt.Sprintf("$template.%d.html", m.ID)
	if _, ok := m.Files.GetFile(mainTemplate); !ok {
		return nil, errors.New("Main template not found in model")
	}
	templates, err := extractTemplateFiles(m.Files)
	if err != nil {
		return nil, errors.Wrap(err, "Error with Model attachments")
	}
	log.Debugf("templates = %v\n", templates)
	tmpl2, err := extractTemplateFiles(m.Theme.Files)
	if err != nil {
		return nil, errors.Wrap(err, "Error with Theme attachments")
	}
	log.Debugf("templates = %v\n", templates)
	log.Debugf("tmpl2 = %v\n", tmpl2)
	for k, v := range tmpl2 {
		templates[k] = v
	}
	log.Debugf("templates = %v\n", templates)
	// Rename to match the masterTemplate expectation
	templates["template.html"] = templates[mainTemplate]
	delete(templates, mainTemplate)
	tmpl, err := template.New("template").Parse(masterTemplate)
	if err != nil {
		return nil, errors.Wrap(err, "Error parsing master template")
	}
	for filename, t := range templates {
		log.Debugf("Defining template '%s'", filename)
		content := fmt.Sprintf("{{define \"%s\"}}%s{{end}}", filename, t)
		if _, err := tmpl.Parse(content); err != nil {
			return nil, errors.Wrapf(err, "Error parsing template file `%s`", filename)
		}
	}
	return tmpl, nil
}
예제 #8
0
// Body returns the card's body and iframe ID
func (c *Card) Body() (string, string, error) {
	note, err := c.Note()
	if err != nil {
		return "", "", errors.Wrap(err, "Unable to retrieve Note")
	}
	model, err := note.Model()
	if err != nil {
		return "", "", errors.Wrap(err, "Unable to retrieve Model")
	}
	tmpl, err := model.GenerateTemplate()
	if err != nil {
		return "", "", errors.Wrap(err, "Error generating template")
	}
	ctx := cardContext{
		IframeID: RandString(8),
		Card:     c,
		Note:     note,
		Model:    model,
		BaseURI:  util.BaseURI(),
		Fields:   make(map[string]template.HTML),
	}

	for i, f := range model.Fields {
		switch note.FieldValues[i].Type() {
		case fb.AnkiField, fb.TextField:
			text, e := note.FieldValues[i].Text()
			if e != nil {
				return "", "", errors.Wrap(e, "Unable to fetch text for field value")
			}
			ctx.Fields[f.Name] = template.HTML(text)
		}
	}

	htmlDoc := new(bytes.Buffer)
	if e := tmpl.Execute(htmlDoc, ctx); e != nil {
		return "", "", errors.Wrap(e, "Unable to execute template")
	}
	doc, err := html.Parse(htmlDoc)
	if err != nil {
		return "", "", errors.Wrap(err, "Unable to parse generated HTML")
	}
	body := findBody(doc)
	if body == nil {
		return "", "", errors.New("No <body> in the template output")
	}
	log.Debugf("%s", htmlDoc)

	container := findContainer(body.FirstChild, strconv.Itoa(int(c.TemplateID())), "question")
	if container == nil {
		return "", "", errors.Errorf("No div matching '%d' found in template output", c.TemplateID())
	}
	log.Debug("Found container: %s", container)

	// Delete unused divs
	for c := body.FirstChild; c != nil; c = body.FirstChild {
		body.RemoveChild(c)
	}
	inner := container.FirstChild
	inner.Parent = body
	body.FirstChild = inner

	if err := c.inlineSrc(body); err != nil {
		return "", "", errors.Wrap(err, "Error inlining images")
	}

	newBody := new(bytes.Buffer)
	if err := html.Render(newBody, doc); err != nil {
		return "", "", errors.Wrap(err, "Error rendering new HTML")
	}

	nbString := newBody.String()
	log.Debugf("original size = %d\n", len(htmlDoc.String()))
	log.Debugf("new body size = %d\n", len(nbString))
	return nbString, ctx.IframeID, nil
}