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 }
// 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 }
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 }
// 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 }
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 }
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 }
// 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 }
// 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 }