~evanj/cms

4c5571c0385bfc05edb370d418437fb5a9270750 — Evan M Jones 7 months ago 9d4babd
Feat(contenttype+content update): Content types and contents will proper
diff on update (eg when content type updates, children can properly add
their new field values and so on).
M internal/c/content/content.go => internal/c/content/content.go +63 -13
@@ 39,7 39,7 @@ type dber interface {
	ContentTypeGet(space space.Space, contenttypeID string) (contenttype.ContentType, error)
	ContentNew(space space.Space, ct contenttype.ContentType, params []db.ContentNewParam) (content.Content, error)
	ContentGet(space space.Space, ct contenttype.ContentType, contentID string) (content.Content, error)
	ContentUpdate(space space.Space, ct contenttype.ContentType, content content.Content, params []db.ContentUpdateParam) (content.Content, error)
	ContentUpdate(space space.Space, ct contenttype.ContentType, content content.Content, newParams []db.ContentNewParam, updateParams []db.ContentUpdateParam) (content.Content, error)
	ContentDelete(space space.Space, ct contenttype.ContentType, content content.Content) error
	ContentSearch(space space.Space, ct contenttype.ContentType, name, query string, page int) ([]content.Content, error)
	ContentPerContentType(space space.Space, ct contenttype.ContentType, page int, order db.OrderType, sortField string) ([]content.Content, error)


@@ 225,27 225,57 @@ func (c *Content) update(w http.ResponseWriter, r *http.Request) {
		return
	}

	var params []db.ContentUpdateParam
	var newParams []db.ContentNewParam
	var updateParams []db.ContentUpdateParam

	for key := range r.Form {
		if key == "space" || key == "contenttype" || key == "content" {
			continue
		}

		// Man, there must be a better way.
		// All this form nonsense is driving me insane.

		// Check if new param of update param
		if strings.Contains(key, "value_update_") {

			parts := strings.Split(strings.ReplaceAll(key, "value_update_", ""), "-")
			if len(parts) < 2 {
				c.Error(w, r, http.StatusInternalServerError, "invalid name field for value")
				return
			}

			typ, id, val := parts[0], parts[1], r.FormValue(key)
			if typ == valuetype.File && strings.TrimSpace(val) == "" {
				// Don't update empty file fields.
				continue
			}

			updateParams = append(updateParams, db.ContentUpdateParam{
				ID:    id,
				Type:  typ,
				Value: val,
			})

			continue
		}

		// Now we're a new value.

		parts := strings.Split(key, "-")
		if len(parts) < 2 {
			c.Error(w, r, http.StatusInternalServerError, "invalid name field for value")
			return
		}

		typ, id, val := parts[0], parts[1], r.FormValue(key)
		if typ == valuetype.File && strings.TrimSpace(val) == "" {
			// Don't update empty file fields.
		typ, name, val := parts[0], parts[1], r.FormValue(key)
		if typ == valuetype.File {
			continue
		}

		params = append(params, db.ContentUpdateParam{
			ID:    id,
		newParams = append(newParams, db.ContentNewParam{
			Type:  typ,
			Name:  name,
			Value: val,
		})
	}


@@ 259,7 289,7 @@ func (c *Content) update(w http.ResponseWriter, r *http.Request) {
			return
		}

		// TODO: Change public to false
		// Note: All upload public by default.
		url, err := c.e3.Upload(r.Context(), true, header.Filename, file)
		if err != nil {
			c.log.Println("failed to upload file", err)


@@ 267,22 297,42 @@ func (c *Content) update(w http.ResponseWriter, r *http.Request) {
			return
		}

		// Check if we're update image value.
		if strings.Contains(key, "value_update_") {

			parts := strings.Split(strings.ReplaceAll(key, "value_update_", ""), "-")
			if len(parts) < 2 {
				c.Error(w, r, http.StatusInternalServerError, "invalid name field for value")
				return
			}

			_, id := parts[0], parts[1]

			updateParams = append(updateParams, db.ContentUpdateParam{
				ID:    id,
				Type:  valuetype.File,
				Value: url,
			})

			continue
		}

		parts := strings.Split(key, "-")
		if len(parts) < 2 {
			c.Error(w, r, http.StatusInternalServerError, "invalid name field for value")
			return
		}

		_, id := parts[0], parts[1]
		typ, name := parts[0], parts[1]

		params = append(params, db.ContentUpdateParam{
			ID:    id,
			Type:  valuetype.File,
		newParams = append(newParams, db.ContentNewParam{
			Type:  typ,
			Name:  name,
			Value: url,
		})
	}

	content, err = c.db.ContentUpdate(space, ct, content, params)
	content, err = c.db.ContentUpdate(space, ct, content, newParams, updateParams)
	if err != nil {
		c.log.Println(err)
		c.Error(w, r, http.StatusInternalServerError, "failed to update content")

M internal/s/cache/content.go => internal/s/cache/content.go +2 -2
@@ 38,11 38,11 @@ func (c *Cache) ContentGet(space space.Space, ct contenttype.ContentType, conten
	)
}

func (c *Cache) ContentUpdate(space space.Space, ct contenttype.ContentType, item content.Content, params []db.ContentUpdateParam) (content.Content, error) {
func (c *Cache) ContentUpdate(space space.Space, ct contenttype.ContentType, item content.Content, newParams []db.ContentNewParam, updateParams []db.ContentUpdateParam) (content.Content, error) {
	return c.content(
		true,
		fmt.Sprintf("%s::%s::%s::%s", c.baseKey, space.ID(), ct.ID(), item.ID()),
		func() (content.Content, error) { return c.db.ContentUpdate(space, ct, item, params) },
		func() (content.Content, error) { return c.db.ContentUpdate(space, ct, item, newParams, updateParams) },
	)
}


M internal/s/db/content.go => internal/s/db/content.go +70 -20
@@ 51,6 51,18 @@ type contentValueJSON struct {
	FieldReferenceList []*Content `json:",omitempty"`
}

type ContentNewParam struct {
	Type  string
	Name  string
	Value string
}

type ContentUpdateParam struct {
	ID    string
	Type  string
	Value string
}

var (
	queryContentNew = `
		INSERT INTO cms_content (CONTENTTYPE_ID) 


@@ 474,12 486,6 @@ func (db *DB) valueReferenceListNew(s space.Space, ct contenttype.ContentType, c
	return nil
}

type ContentNewParam struct {
	Type  string
	Name  string
	Value string
}

func (db *DB) contentNew(space space.Space, ct contenttype.ContentType, params []ContentNewParam, depth int) (content.Content, error) {
	t, err := db.Begin()
	if err != nil {


@@ 560,13 566,7 @@ func (db *DB) ContentNew(space space.Space, ct contenttype.ContentType, params [
	return db.contentNew(space, ct, params, defaultDepth)
}

type ContentUpdateParam struct {
	ID    string
	Type  string
	Value string
}

func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, content content.Content, params []ContentUpdateParam) (content.Content, error) {
func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, content content.Content, newParams []ContentNewParam, updateParams []ContentUpdateParam) (content.Content, error) {
	depth := defaultDepth

	t, err := db.Begin()


@@ 575,15 575,16 @@ func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, conte
	}
	defer t.Rollback()

	for _, item := range params {
	// TODO: Do we have to do this w/ types? Can you not find a better way?
	// I'm beginning to think we're over using interfaces and it's hurting.
	c, ok := content.(*Content)
	if !ok {
		return nil, fmt.Errorf("failed to type cast value type before attempting to update content")
	}

	for _, item := range updateParams {
		// Special data type. Life is hard.
		if item.Type == valuetype.ReferenceList {
			// TODO: Do we have to do this w/ types? Can you not find a better way?
			// I'm beginning to think we're over using interfaces and it's hurting.
			c, ok := content.(*Content)
			if !ok {
				return nil, fmt.Errorf("failed to type cast value type before attempting to update content")
			}

			if err := db.valueReferenceListUpdate(space, ct, c, t, item.ID, strings.Split(item.Value, "-"), depth); err != nil {
				return nil, err


@@ 597,10 598,59 @@ func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, conte
		}

		if _, err := t.Exec(queryValueUpdate, item.Value, item.ID); err != nil {
			db.log.Println(err)
			return nil, fmt.Errorf("failed to create update content value '%s'", item.Value)
		}
	}

	for _, item := range newParams {
		// Special data type. Life is hard.
		if item.Type == valuetype.ReferenceList {
			if err := db.valueReferenceListNew(space, ct, c, t, item.Name, strings.Split(item.Value, "-"), depth); err != nil {
				return nil, err
			}
			continue
		}

		queryValueNewType, queryValueGetTypeByID, _, err := db.valueQuerySetByType(item.Type)
		if err != nil {
			return nil, err
		}

		res, err := t.Exec(queryValueNewType, item.Value)
		if err != nil {
			db.log.Println(err)
			return nil, fmt.Errorf("failed to attach field value of content")
		}

		valueID, err := res.LastInsertId()
		if err != nil {
			return nil, fmt.Errorf("failed to read new field value of content")
		}

		res, err = t.Exec(queryValueNew, content.ID(), ct.ID(), item.Name, valueID)
		if err != nil {
			db.log.Println(err)
			return nil, fmt.Errorf("failed to attach field value of content")
		}

		valueID, err = res.LastInsertId()
		if err != nil {
			return nil, fmt.Errorf("failed to read new field value of content")
		}

		var value ContentValue
		if err := t.QueryRow(queryValueGetTypeByID, valueID).Scan(&value.FieldID, &value.FieldType, &value.FieldName, &value.FieldValue); err != nil {
			return nil, fmt.Errorf("failed to find value created")
		}

		if err := db.contentValueAttachRef(&value, depth); err != nil {
			return nil, err
		}

		c.ContentValues = append(c.ContentValues, value)
	}

	if err := t.Commit(); err != nil {
		return nil, err
	}

M internal/s/tmpl/css/main.css => internal/s/tmpl/css/main.css +7 -0
@@ 20,3 20,10 @@ form[action='/contenttype/update'] input {
  display: initial;
}

textarea { 
  display: block;
  resize: vertical;
  min-height: 600px;
  width: 100%%;
  box-sizing: content-box;
}

M internal/s/tmpl/html/content.html => internal/s/tmpl/html/content.html +118 -54
@@ 23,71 23,135 @@
          <input required type=hidden name=contenttype value="{{ .ContentType.ID }}" />
          <input required type=hidden name=content value="{{ .Content.ID }}" />

          {{ range .Content.Values }}
          {{ range $index, $item := .ContentType.Fields }}
            {{ $val := $.Content.MustValueByName ( $item.Name ) }}

            <label>{{ .Name }}</label>
            {{ if $val }} 
              <label>{{ $val.Name }}</label>

            {{ if eq .Type "StringSmall" }}
              <input value="{{ .Value }}" required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}" />
            {{ end }}

            {{ if eq .Type "StringBig" }}
              <textarea required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}">{{ .Value }}</textarea>
            {{ end }}
              {{ if eq $val.Type "StringSmall" }}
                <input value="{{ $val.Value }}" required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}" />
              {{ end }}

            {{ if eq .Type "InputHTML" }}
              <textarea class='input-html' value="{{ .Value }}" required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}">{{ .Value }}</textarea>
            {{ end }}
              {{ if eq $val.Type "StringBig" }}
                <textarea required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}">{{ $val.Value }}</textarea>
              {{ end }}

            {{ if eq .Type "InputMarkdown" }}
              <textarea class='input-markdown' value="{{ .Value }}" required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}">{{ .Value }}</textarea>
            {{ end }}
              {{ if eq $val.Type "InputHTML" }}
                <textarea class='input-html' value="{{ $val.Value }}" required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}">{{ $val.Value }}</textarea>
              {{ end }}

            {{ if eq .Type "File" }}
              <input value="{{ .Value }}" type=file name="{{ .Type }}-{{ .ID }}" multiple=false />
            {{ end }}
              {{ if eq $val.Type "InputMarkdown" }}
                <textarea class='input-markdown' value="{{ $val.Value }}" required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}">{{ $val.Value }}</textarea>
              {{ end }}

            {{ if eq .Type "Date" }}
              <input value="{{ .Value }}" required type=date name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}" />
            {{ end }}
              {{ if eq $val.Type "File" }}
                <input value="{{ $val.Value }}" type=file name="value_update_{{ $val.Type }}-{{ $val.ID }}" multiple=false />
              {{ end }}

            {{ if eq .Type "Reference" }}
              <input class='output-ref' required type=hidden value="{{ .Value }}" name="{{ .Type }}-{{ .ID}}" />
              <input class='input-ref' type=button value="{{ if  .RefName }}{{ .RefName }}{{ else }}Open{{ end}}"/>
              <dialog>
                <menu>
                  <div>
                    <center>
                      <p>Search for content to use as reference.</p>
                    </center>
                    <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                    <input disabled class='input-content' type=text placeholder='Search by content name' />
                  </div>
                </menu>
              </dialog>
            {{ end }}
              {{ if eq $val.Type "Date" }}
                <input value="{{ $val.Value }}" required type=date name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}" />
              {{ end }}

            {{ if eq .Type "ReferenceList" }}
              <input class='output-ref' required type=hidden value="{{ .Value }}" name="{{ .Type }}-{{ .ID }}" />
              <input class='input-ref' type=button value="{{ if  .RefListNames }}{{ .RefListNames }}{{ else }}Open{{ end}}"/>
              <dialog>
                <menu>
                  <div>
                    <center>
                      <p>Search for content to use as reference.</p>
                    </center>
                    <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                    <input disabled class='input-content' type=text placeholder='Search by content name' />
              {{ if eq $val.Type "Reference" }}
                <input class='output-ref' required type=hidden value="{{ $val.Value }}" name="value_update_{{ $val.Type }}-{{ $val.ID}}" />
                <input class='input-ref' type=button value="{{ if  $val.RefName }}{{ $val.RefName }}{{ else }}Open{{ end}}"/>
                <dialog>
                  <menu>
                    <div>
                      <input class=left type=button value=Clear />
                      <input class=right type=button value=Done />
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                    </div>
                  </div>
                </menu>
              </dialog>
                  </menu>
                </dialog>
              {{ end }}

              {{ if eq $val.Type "ReferenceList" }}
                <input class='output-ref' required type=hidden value="{{ $val.Value }}" name="value_update_{{ $val.Type }}-{{ $val.ID }}" />
                <input class='input-ref' type=button value="{{ if  $val.RefListNames }}{{ $val.RefListNames }}{{ else }}Open{{ end}}"/>
                <dialog>
                  <menu>
                    <div>
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                      <div>
                        <input class=left type=button value=Clear />
                        <input class=right type=button value=Done />
                      </div>
                    </div>
                  </menu>
                </dialog>
              {{ end }}
            {{ else }}
              <label>{{ .Name }}</label>

              {{ if eq .Type "StringSmall" }}
                <input required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" />
              {{ end }}

              {{ if eq .Type "StringBig" }}
                <textarea required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" ></textarea>
              {{ end }}

              {{ if eq .Type "InputHTML" }}
                <textarea class='input-html' required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" ></textarea>
              {{ end }}

              {{ if eq .Type "InputMarkdown" }}
                <textarea class='input-markdown' required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" ></textarea>
              {{ end }}

              {{ if eq .Type "File" }}
                <input required type=file name="{{ .Type }}-{{ .Name }}" multiple=false />
              {{ end }}

              {{ if eq .Type "Date" }}
                <input required type=date name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" />
              {{ end }}

              {{ if eq .Type "Reference" }}
                <input class='output-ref' required type=hidden name="{{ .Type }}-{{ .Name }}" />
                <input class='input-ref' type=button value=Open />
                <dialog>
                  <menu>
                    <div>
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                    </div>
                  </menu>
                </dialog>
              {{ end }}

              {{ if eq .Type "ReferenceList" }}
                <input class='output-ref' required type=hidden name="{{ .Type }}-{{ .Name }}" />
                <input class='input-ref' type=button value=Open />
                <dialog>
                  <menu>
                    <div>
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                      <div>
                        <input class=left type=button value=Clear />
                        <input class=right type=button value=Done />
                      </div>
                    </div>
                  </menu>
                </dialog>
              {{ end }}
            {{ end }}

          {{ end }}
          {{ end}}

          <input type=submit value=Update />
        </form>

M internal/s/tmpl/js/space.js => internal/s/tmpl/js/space.js +0 -1
@@ 40,7 40,6 @@
  var btns = document.querySelectorAll("form div input[type=button]");
  for (var e = 0; e < btns.length; e++) {
    (function(btn) {
      console.log(btn)
      btn.addEventListener("click", function handelClick() { 
        btn.parentElement.parentElement.removeChild(btn.parentElement);
      });

M internal/s/tmpl/tmpls_embed.go => internal/s/tmpl/tmpls_embed.go +124 -54
@@ 29,6 29,13 @@ form[action='/contenttype/update'] input {
  display: initial;
}

textarea { 
  display: block;
  resize: vertical;
  min-height: 600px;
  width: 100%;
  box-sizing: content-box;
}
`

	tmpls["css/mvp.css"] = `:root {


@@ 443,71 450,135 @@ blockquote footer {
          <input required type=hidden name=contenttype value="{{ .ContentType.ID }}" />
          <input required type=hidden name=content value="{{ .Content.ID }}" />

          {{ range .Content.Values }}
          {{ range $index, $item := .ContentType.Fields }}
            {{ $val := $.Content.MustValueByName ( $item.Name ) }}

            <label>{{ .Name }}</label>
            {{ if $val }} 
              <label>{{ $val.Name }}</label>

            {{ if eq .Type "StringSmall" }}
              <input value="{{ .Value }}" required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}" />
            {{ end }}
              {{ if eq $val.Type "StringSmall" }}
                <input value="{{ $val.Value }}" required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}" />
              {{ end }}

            {{ if eq .Type "StringBig" }}
              <textarea required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}">{{ .Value }}</textarea>
            {{ end }}
              {{ if eq $val.Type "StringBig" }}
                <textarea required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}">{{ $val.Value }}</textarea>
              {{ end }}

            {{ if eq .Type "InputHTML" }}
              <textarea class='input-html' value="{{ .Value }}" required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}">{{ .Value }}</textarea>
            {{ end }}
              {{ if eq $val.Type "InputHTML" }}
                <textarea class='input-html' value="{{ $val.Value }}" required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}">{{ $val.Value }}</textarea>
              {{ end }}

            {{ if eq .Type "InputMarkdown" }}
              <textarea class='input-markdown' value="{{ .Value }}" required type=text name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}">{{ .Value }}</textarea>
            {{ end }}
              {{ if eq $val.Type "InputMarkdown" }}
                <textarea class='input-markdown' value="{{ $val.Value }}" required type=text name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}">{{ $val.Value }}</textarea>
              {{ end }}

            {{ if eq .Type "File" }}
              <input value="{{ .Value }}" type=file name="{{ .Type }}-{{ .ID }}" multiple=false />
            {{ end }}
              {{ if eq $val.Type "File" }}
                <input value="{{ $val.Value }}" type=file name="value_update_{{ $val.Type }}-{{ $val.ID }}" multiple=false />
              {{ end }}

            {{ if eq .Type "Date" }}
              <input value="{{ .Value }}" required type=date name="{{ .Type }}-{{ .ID }}" placeholder="{{ .Name }}" />
            {{ end }}
              {{ if eq $val.Type "Date" }}
                <input value="{{ $val.Value }}" required type=date name="value_update_{{ $val.Type }}-{{ $val.ID }}" placeholder="{{ $val.Name }}" />
              {{ end }}

            {{ if eq .Type "Reference" }}
              <input class='output-ref' required type=hidden value="{{ .Value }}" name="{{ .Type }}-{{ .ID}}" />
              <input class='input-ref' type=button value="{{ if  .RefName }}{{ .RefName }}{{ else }}Open{{ end}}"/>
              <dialog>
                <menu>
                  <div>
                    <center>
                      <p>Search for content to use as reference.</p>
                    </center>
                    <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                    <input disabled class='input-content' type=text placeholder='Search by content name' />
                  </div>
                </menu>
              </dialog>
            {{ end }}
              {{ if eq $val.Type "Reference" }}
                <input class='output-ref' required type=hidden value="{{ $val.Value }}" name="value_update_{{ $val.Type }}-{{ $val.ID}}" />
                <input class='input-ref' type=button value="{{ if  $val.RefName }}{{ $val.RefName }}{{ else }}Open{{ end}}"/>
                <dialog>
                  <menu>
                    <div>
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                    </div>
                  </menu>
                </dialog>
              {{ end }}

              {{ if eq $val.Type "ReferenceList" }}
                <input class='output-ref' required type=hidden value="{{ $val.Value }}" name="value_update_{{ $val.Type }}-{{ $val.ID }}" />
                <input class='input-ref' type=button value="{{ if  $val.RefListNames }}{{ $val.RefListNames }}{{ else }}Open{{ end}}"/>
                <dialog>
                  <menu>
                    <div>
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                      <div>
                        <input class=left type=button value=Clear />
                        <input class=right type=button value=Done />
                      </div>
                    </div>
                  </menu>
                </dialog>
              {{ end }}
            {{ else }}
              <label>{{ .Name }}</label>

            {{ if eq .Type "ReferenceList" }}
              <input class='output-ref' required type=hidden value="{{ .Value }}" name="{{ .Type }}-{{ .ID }}" />
              <input class='input-ref' type=button value="{{ if  .RefListNames }}{{ .RefListNames }}{{ else }}Open{{ end}}"/>
              <dialog>
                <menu>
                  <div>
                    <center>
                      <p>Search for content to use as reference.</p>
                    </center>
                    <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                    <input disabled class='input-content' type=text placeholder='Search by content name' />
              {{ if eq .Type "StringSmall" }}
                <input required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" />
              {{ end }}

              {{ if eq .Type "StringBig" }}
                <textarea required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" ></textarea>
              {{ end }}

              {{ if eq .Type "InputHTML" }}
                <textarea class='input-html' required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" ></textarea>
              {{ end }}

              {{ if eq .Type "InputMarkdown" }}
                <textarea class='input-markdown' required type=text name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" ></textarea>
              {{ end }}

              {{ if eq .Type "File" }}
                <input required type=file name="{{ .Type }}-{{ .Name }}" multiple=false />
              {{ end }}

              {{ if eq .Type "Date" }}
                <input required type=date name="{{ .Type }}-{{ .Name }}" placeholder="{{ .Name }}" />
              {{ end }}

              {{ if eq .Type "Reference" }}
                <input class='output-ref' required type=hidden name="{{ .Type }}-{{ .Name }}" />
                <input class='input-ref' type=button value=Open />
                <dialog>
                  <menu>
                    <div>
                      <input class=left type=button value=Clear />
                      <input class=right type=button value=Done />
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                    </div>
                  </div>
                </menu>
              </dialog>
                  </menu>
                </dialog>
              {{ end }}

              {{ if eq .Type "ReferenceList" }}
                <input class='output-ref' required type=hidden name="{{ .Type }}-{{ .Name }}" />
                <input class='input-ref' type=button value=Open />
                <dialog>
                  <menu>
                    <div>
                      <center>
                        <p>Search for content to use as reference.</p>
                      </center>
                      <input autofocus class='input-contenttype' type=text placeholder='Search by content type' />
                      <input disabled class='input-content' type=text placeholder='Search by content name' />
                      <div>
                        <input class=left type=button value=Clear />
                        <input class=right type=button value=Done />
                      </div>
                    </div>
                  </menu>
                </dialog>
              {{ end }}
            {{ end }}

          {{ end }}
          {{ end}}

          <input type=submit value=Update />
        </form>


@@ 1188,7 1259,6 @@ blockquote footer {
  var btns = document.querySelectorAll("form div input[type=button]");
  for (var e = 0; e < btns.length; e++) {
    (function(btn) {
      console.log(btn)
      btn.addEventListener("click", function handelClick() { 
        btn.parentElement.parentElement.removeChild(btn.parentElement);
      });