diff options
| author | Bryan Newbold <bnewbold@robocracy.org> | 2019-04-01 22:09:48 -0700 | 
|---|---|---|
| committer | Bryan Newbold <bnewbold@robocracy.org> | 2019-04-01 22:09:48 -0700 | 
| commit | 4a08a4ef405e451db0a8251c05a193874b64cddb (patch) | |
| tree | 9cf878df4779cbc72c1b5a0de1943a8fdb7de3c8 /python/fatcat_web | |
| parent | 1a371b894a80510241c5804a8fba43a744174716 (diff) | |
| download | fatcat-4a08a4ef405e451db0a8251c05a193874b64cddb.tar.gz fatcat-4a08a4ef405e451db0a8251c05a193874b64cddb.zip | |
basic release editing
Diffstat (limited to 'python/fatcat_web')
| -rw-r--r-- | python/fatcat_web/forms.py | 37 | ||||
| -rw-r--r-- | python/fatcat_web/routes.py | 50 | ||||
| -rw-r--r-- | python/fatcat_web/templates/edit_macros.html | 36 | ||||
| -rw-r--r-- | python/fatcat_web/templates/release_create.html | 254 | ||||
| -rw-r--r-- | python/fatcat_web/templates/release_edit.html | 231 | 
5 files changed, 345 insertions, 263 deletions
| diff --git a/python/fatcat_web/forms.py b/python/fatcat_web/forms.py index baff62d7..632e36c6 100644 --- a/python/fatcat_web/forms.py +++ b/python/fatcat_web/forms.py @@ -6,7 +6,7 @@ but can't find one that is actually maintained.  from flask_wtf import FlaskForm  from wtforms import SelectField, DateField, StringField, IntegerField, \ -    FormField, FieldList, validators +    HiddenField, FormField, FieldList, validators  from fatcat_client import ContainerEntity, CreatorEntity, FileEntity, \      ReleaseEntity, ReleaseContrib @@ -51,6 +51,7 @@ class ReleaseContribForm(FlaskForm):      #given_name      #creator_id (?)      #orcid (for match?) +    prev_index = HiddenField('prev_revision index', default=None)      raw_name = StringField('Display Name',          [validators.DataRequired()])      role = SelectField( @@ -108,7 +109,14 @@ class ReleaseEntityForm(EntityEditForm):          """          ref = ReleaseEntityForm()          for simple_attr in RELEASE_SIMPLE_ATTRS: -            setattr(ref, simple_attr, getattr(re, simple_attr)) +            a = getattr(ref, simple_attr) +            a.data = getattr(re, simple_attr) +        for i, c in enumerate(re.contribs): +            rcf = ReleaseContribForm() +            rcf.prev_index = i +            rcf.role = c.role +            rcf.raw_name = c.raw_name +            ref.contribs.append_entry(rcf)          return ref      def to_entity(self): @@ -130,13 +138,26 @@ class ReleaseEntityForm(EntityEditForm):              if a == '':                  a = None              setattr(re, simple_attr, a) -        # TODO: don't update authors unless necessary! -        re.contribs = [] +        # bunch of complexity here to preserve old contrib metadata (eg, +        # affiliation and extra) not included in current forms +        # TODO: this may be broken; either way needs tests +        if re.contribs: +            old_contribs = re.contribs.copy() +            re.contribs = [] +        else: +            old_contribs = [] +            re.contribs = []          for c in self.contribs: -            re.contribs.append(ReleaseContrib( -                role=c.role.data or None, -                raw_name=c.raw_name.data or None, -            )) +            if c.prev_index.data not in ('', None): +                rc = old_contribs[int(c.prev_index.data)] +                rc.role = c.role.data or None +                rc.raw_name = c.raw_name.data or None +            else: +                rc = ReleaseContrib( +                    role=c.role.data or None, +                    raw_name=c.raw_name.data or None, +                ) +            re.contribs.append(rc)          if self.edit_description.data:              re.edit_extra = dict(description=self.edit_description.data) diff --git a/python/fatcat_web/routes.py b/python/fatcat_web/routes.py index eb62d338..118f402b 100644 --- a/python/fatcat_web/routes.py +++ b/python/fatcat_web/routes.py @@ -325,7 +325,7 @@ def release_create():              user_api = auth_api(session['api_token'])              if form.editgroup_id.data:                  # TODO: error handling -                eg = api.get_editgroup(form.editgroup_id.data) +                eg = user_api.get_editgroup(form.editgroup_id.data)              else:                  # if no editgroup, create one from description                  eg = user_api.create_editgroup( @@ -345,8 +345,9 @@ def release_create():              print("didn't validate...")      elif len(form.contribs) == 0:          form.contribs.append_entry() -    # TODO: check for editgroup in session -    editgroup_id = session.get('active_editgroup_id', None) +    if not form.is_submitted(): +        editgroup_id = session.get('active_editgroup_id', None) +        form.editgroup_id.data = editgroup_id      return render_template('release_create.html',          form=form, editgroup_id=editgroup_id) @@ -363,13 +364,50 @@ def release_history(ident):          entity=entity,          history=history) -@app.route('/release/<ident>/edit', methods=['GET']) -def release_edit_view(ident): +# XXX: figure out CSRF stuff for local dev +@login_required +@app.csrf.exempt +@app.route('/release/<ident>/edit', methods=['GET', 'POST']) +def release_edit(ident): +    # TODO: prev_rev interlock +    # TODO: factor out editgroup active/creation stuff      try:          entity = api.get_release(ident)      except ApiException as ae:          abort(ae.status) -    return render_template('entity_edit.html') +    form = ReleaseEntityForm(csrf_enabled=False) # XXX: +    if form.is_submitted(): +        if form.validate_on_submit(): +            # API on behalf of user +            user_api = auth_api(session['api_token']) +            if form.editgroup_id.data: +                # TODO: error handling +                eg = user_api.get_editgroup(form.editgroup_id.data) +            else: +                # if no editgroup, create one from description +                eg = user_api.create_editgroup( +                    Editgroup(description=form.editgroup_description.data or None)) +                # set this session editgroup_id +                session['active_editgroup_id'] = eg.editgroup_id +                print(eg.editgroup_id) # XXX: debug +                flash('Started new editgroup <a href="/editgroup/{}">{}</a>' \ +                    .format(eg.editgroup_id, eg.editgroup_id)) +            # all the tricky logic is in the update method +            form.update_entity(entity) +            edit = user_api.update_release(entity.ident, entity, +                editgroup_id=eg.editgroup_id) +            # redirect to release revision +            # TODO: release_rev_view +            return redirect('/release/{}'.format(edit.ident)) +        elif form.errors: +            print("user form errors (didn't validate): {}".format(form.errors)) +    else: +        form = ReleaseEntityForm.from_entity(entity) +    if not form.is_submitted(): +        editgroup_id = session.get('active_editgroup_id', None) +        form.editgroup_id.data = editgroup_id +    return render_template('release_edit.html', +        form=form, editgroup_id=editgroup_id, entity=entity)  @app.route('/release/<ident>', methods=['GET'])  def release_view(ident): diff --git a/python/fatcat_web/templates/edit_macros.html b/python/fatcat_web/templates/edit_macros.html new file mode 100644 index 00000000..ad563066 --- /dev/null +++ b/python/fatcat_web/templates/edit_macros.html @@ -0,0 +1,36 @@ + +{% macro form_field_errors(field) -%} +  {% if field.errors %} +    <div class="ui pointing red label"> +    {% for err in field.errors %} +        {{ err }} +    {% endfor %} +    </div> +  {% endif %} +{%- endmacro %} + +{% macro form_field_basic(field, div_classes="") -%} +<div class="field {{ div_classes }} {% if field.errors %}error{% endif %}"> +  {{ field.label }} +  {{ field() }} +  {{ form_field_errors(field) }} +</div> +{%- endmacro %} + +{% macro form_field_inline(field, div_classes="") -%} +<div class="ui grid"> +  <div class="three wide column middle aligned right aligned" {# style="padding-right: 0.5rem;" #}> +    <div class="field inline {{ div_classes }} {% if field.errors %}error{% endif %}"> +      {{ field.label }} +    </div> +  </div> +  <div class="twelve wide column" {# style="padding-left: 0.5rem;" #}> +    <div class="field {{ div_classes }} {% if field.errors %}error{% endif %}"> +      {{ field() }} +      {{ form_field_errors(field) }} +    </div> +  </div> +  <div class="one wide column"> +  </div> +</div> +{%- endmacro %} diff --git a/python/fatcat_web/templates/release_create.html b/python/fatcat_web/templates/release_create.html index 7ede5dfd..5ea3470d 100644 --- a/python/fatcat_web/templates/release_create.html +++ b/python/fatcat_web/templates/release_create.html @@ -1,260 +1,16 @@ -{% extends "base.html" %} +{% extends "release_edit.html" %} -{% macro form_field_errors(field) -%} -  {% if field.errors %} -    <div class="ui pointing red label"> -    {% for err in field.errors %} -        {{ err }} -    {% endfor %} -    </div> -  {% endif %} -{%- endmacro %} - -{% macro form_field_basic(field, div_classes="") -%} -<div class="field {{ div_classes }} {% if field.errors %}error{% endif %}"> -  {{ field.label }} -  {{ field() }} -  {{ form_field_errors(field) }} -</div> -{%- endmacro %} - -{% macro form_field_inline(field, div_classes="") -%} -<div class="ui grid"> -  <div class="three wide column middle aligned right aligned" {# style="padding-right: 0.5rem;" #}> -    <div class="field inline {{ div_classes }} {% if field.errors %}error{% endif %}"> -      {{ field.label }} -    </div> -  </div> -  <div class="twelve wide column" {# style="padding-left: 0.5rem;" #}> -    <div class="field {{ div_classes }} {% if field.errors %}error{% endif %}"> -      {{ field() }} -      {{ form_field_errors(field) }} -    </div> -  </div> -  <div class="one wide column"> -  </div> -</div> -{%- endmacro %} - -{% block body %} +{% block edit_form_prefix %}  <div class="ui segment">  <h1 class="ui header">Create New Release Entity</h1> +<form class="ui form" id="create_release_form" method="POST" action="/release/create"> +{% endblock %} -<form class="ui form" id="add_work_form" method="POST" action="/release/create"> -  {{ form.hidden_tag() }} - -  <br> -  <div class="ui accordion"> -    <div class="{% if not editgroup_id %}active{% endif %} title"> -      <h3><i class="dropdown icon"></i>Editgroup Meta</h3> -    </div> -    <div class="{% if not editgroup_id %}active{% endif %} content"> -      {% if editgroup_id %} -        <p>You have an editgroup in progress, and this edit will be included by -        default. You can override this below. -      {% else %} -        <p>No existing editgroup is in progress (or at least, not is selected). -        An existing ID can be pasted in, or if you leave that blank but give a -        description, a new editgroup will be created for this edit. -      {% endif %} -      {{ form_field_inline(form.editgroup_id) }} -      {{ form_field_inline(form.editgroup_description) }} -    </div> -  </div> - -  <br> -  <h3 class="ui dividing header">The Basics</h3> -  <div class="ui grid"> -    <div class="three wide column" style="padding-bottom: 0px;"></div> -    <div class="twelve wide column" style="padding-bottom: 0px;"> -      <div class="ui equal width fields"> -        {{ form_field_basic(form.release_type, "required") }} -        {{ form_field_basic(form.release_status) }} -      </div> -    </div> -    <div class="one wide column" style="padding-bottom: 0px;"></div> -  </div> - -  {{ form_field_inline(form.title, "required") }} -  {{ form_field_inline(form.original_title) }} -  {{ form_field_inline(form.work_id) }} -  {{ form_field_inline(form.release_date) }} -  <div class="ui grid"> -    <div class="three wide column" style="padding-bottom: 0px;"></div> -    <div class="twelve wide column" style="padding-bottom: 0px;"> -      <div class="ui equal width fields"> -        {{ form_field_basic(form.language) }} -        {{ form_field_basic(form.license_slug) }} -      </div> -    </div> -    <div class="one wide column" style="padding-bottom: 0px;"></div> -  </div> - -  <br> -  <h3 class="ui dividing header">Contributors</h3> -  <div class="list-group" id="contrib_list" name="contrib_list"> -  {% for cform in form.contribs %} -    <div class="list-group-item ui grid" style="padding-right: 1em;"> -      <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;"> -        <i class="arrows alternate vertical icon"></i> -      </div> -      <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;"> -        <div class="field {% if cform.role.errors %}error{% endif %}"> -          {{ cform.role }} -        </div> -      </div> -      <div class="eleven wide column" style="padding-bottom: 0px;"> -        <div class="field {% if cform.raw_name.errors %}error{% endif %}"> -          {{ cform.raw_name}} -        </div> -      </div> -      <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;"> -        <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button> -      </div> -    </div> -  {% endfor %} -  </div> -  <br> -  <button type="button" id="add-contrib-button" class="ui right floated icon green button" style="margin-right: 0.3rem;"> -    <i class="plus icon"></i> -  </button> -  <br> - -  <br> -  <h3 class="ui dividing header">Identifers</h3> -  <br> -  {{ form_field_inline(form.doi) }} -  {{ form_field_inline(form.wikidata_qid) }} -  {{ form_field_inline(form.isbn13) }} -  <div class="ui grid"> -    <div class="three wide column" style="padding-bottom: 0px;"></div> -    <div class="twelve wide column" style="padding-bottom: 0px;"> -      <div class="ui equal width fields"> -        {{ form_field_basic(form.pmid) }} -        {{ form_field_basic(form.pmcid) }} -      </div> -    </div> -    <div class="one wide column" style="padding-bottom: 0px;"></div> -  </div> - -  <br> -  <h3 class="ui dividing header">Container</h3> -  <br> -  {{ form_field_inline(form.container_id) }} -  {{ form_field_inline(form.publisher) }} -  <br> -  <div class="ui grid"> -    <div class="three wide column" style="padding-bottom: 0px;"></div> -    <div class="twelve wide column" style="padding-bottom: 0px;"> -      <div class="ui equal width fields"> -        {{ form_field_basic(form.pages) }} -        {{ form_field_basic(form.volume) }} -        {{ form_field_basic(form.issue) }} -      </div> -    </div> -    <div class="one wide column" style="padding-bottom: 0px;"></div> -  </div> - -  <br><br> -  <h3 class="ui dividing header">Submit</h3> -  {{ form_field_basic(form.edit_description) }} -  This description will be attached to this specific action, not to the -  editgroup as a whole. +{% block edit_form_suffix %}    <br><br>    <input class="ui primary submit button" type="submit" value="Create Release!"> -  </form> -  </div>  {% endblock %} -{% block postscript %} -<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script> -<script> -<!-- Form code --> -$(document).ready(function() { - -  // these javascript dropdowns hide the original <input>, which breaks browser -  // form focusing (eg, for required fields) :( -  //$('#release_type').dropdown(); -  //$('#release_status').dropdown(); -  $('.ui.accordion').accordion(); - -  var fixup_contrib_numbering = function(group_item) { -    items = Array.from(group_item.querySelectorAll(".list-group-item")) -    for (var i = 0; i < items.length; i++) { -      var item_el = items[i]; -      input_el = item_el.querySelectorAll("input")[0]; -      select_el = item_el.querySelectorAll("select")[0]; -      //console.log(input_el.id); -      //console.log(select_el.id); -      input_el.id = "contribs-" + i + "-raw_name"; -      input_el.name = input_el.id; -      select_el.id = "contribs-" + i + "-role"; -      select_el.name = select_el.id; -      //console.log(input_el.id); -      //console.log(select_el.id); -    }; -    console.log("re-named contrib rows up to i=" + i); -  }; - -  var contrib_list = document.getElementById('contrib_list'); -  var contrib_sortable = Sortable.create(contrib_list, { -    handle: '.sortable-handle', -    animation: 150, -    onSort: function(evt) { -      fixup_contrib_numbering(contrib_list); -    }, -  }); -  fixup_contrib_numbering(contrib_list); - -  var contrib_delete_handler = function(ev) { -    row = ev.target.parentNode.parentNode; -    // I don't understand why this hack is needed; maybe because of the sortable stuff? -    if(!row.classList.contains("list-group-item")) { -        row = row.parentNode; -    } -    // console.log(row); -    console.assert(row.classList.contains("list-group-item")); -    row.parentNode.removeChild(row); -    fixup_contrib_numbering(contrib_list); -  }; - -  var attach_contrib_delete_handler = function(topthing) { -    Array.from(topthing.querySelectorAll(".delete-contrib-button")).forEach((el) => { -      el.addEventListener("click", contrib_delete_handler); -    }); -  }; -  attach_contrib_delete_handler(document); - -  // XXX: really need some way to not duplicate this code from above... -  var contrib_template = ` -  <div class="list-group-item ui grid" style="padding-right: 1em;"> -      <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;"> -        <i class="arrows alternate vertical icon"></i> -      </div> -      <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;"> -        <select id="contribs-X-role" name="contribs-X-role"><option value="author">Author</option><option value="editor">Editor</option><option value="translator">Translator</option></select> -      </div> -      <div class="eleven wide column" style="padding-bottom: 0px;"> -        <input id="contribs-X-raw_name" name="contribs-X-raw_name" type="text" value=""> -      </div> -      <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;"> -        <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button> -      </div> -    </div> -  `; - -  var add_contrib_button = document.getElementById("add-contrib-button"); -  add_contrib_button.addEventListener("click", function(){ -    contrib_list.insertAdjacentHTML('beforeend', contrib_template); -    attach_contrib_delete_handler(contrib_list.lastElementChild); -    fixup_contrib_numbering(contrib_list); -  }); - -  console.log("Page loaded"); - -}); -</script> -{% endblock %} diff --git a/python/fatcat_web/templates/release_edit.html b/python/fatcat_web/templates/release_edit.html new file mode 100644 index 00000000..867ae665 --- /dev/null +++ b/python/fatcat_web/templates/release_edit.html @@ -0,0 +1,231 @@ +{% import "edit_macros.html" as edit_macros %} +{% extends "base.html" %} + +{% block body %} +{% block edit_form_prefix %} +<div class="ui segment"> +<h1 class="ui header">Edit Release Entity</h1> + +<form class="ui form" id="edit_release_form" method="POST" action="/release/{{ entity.ident }}/edit"> +{% endblock %} +  {{ form.hidden_tag() }} + +  <br> +  <div class="ui accordion"> +    <div class="{% if not editgroup_id %}active{% endif %} title"> +      <h3><i class="dropdown icon"></i>Editgroup Meta</h3> +    </div> +    <div class="{% if not editgroup_id %}active{% endif %} content"> +      {% if editgroup_id %} +        <p>You have an editgroup in progress, and this edit will be included by +        default. You can override this below. +      {% else %} +        <p>No existing editgroup is in progress (or at least, not is selected). +        An existing ID can be pasted in, or if you leave that blank but give a +        description, a new editgroup will be created for this edit. +      {% endif %} +      {{ edit_macros.form_field_inline(form.editgroup_id) }} +      {{ edit_macros.form_field_inline(form.editgroup_description) }} +    </div> +  </div> + +  <br> +  <h3 class="ui dividing header">The Basics</h3> +  <div class="ui grid"> +    <div class="three wide column" style="padding-bottom: 0px;"></div> +    <div class="twelve wide column" style="padding-bottom: 0px;"> +      <div class="ui equal width fields"> +        {{ edit_macros.form_field_basic(form.release_type, "required") }} +        {{ edit_macros.form_field_basic(form.release_status) }} +      </div> +    </div> +    <div class="one wide column" style="padding-bottom: 0px;"></div> +  </div> + +  {{ edit_macros.form_field_inline(form.title, "required") }} +  {{ edit_macros.form_field_inline(form.original_title) }} +  {{ edit_macros.form_field_inline(form.work_id) }} +  {{ edit_macros.form_field_inline(form.release_date) }} +  <div class="ui grid"> +    <div class="three wide column" style="padding-bottom: 0px;"></div> +    <div class="twelve wide column" style="padding-bottom: 0px;"> +      <div class="ui equal width fields"> +        {{ edit_macros.form_field_basic(form.language) }} +        {{ edit_macros.form_field_basic(form.license_slug) }} +      </div> +    </div> +    <div class="one wide column" style="padding-bottom: 0px;"></div> +  </div> + +  <br> +  <h3 class="ui dividing header">Contributors</h3> +  <div class="list-group" id="contrib_list" name="contrib_list"> +  {% for cform in form.contribs %} +    <div class="list-group-item ui grid" style="padding-right: 1em;"> +      {{ cform.hidden_tag() }} +      <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;"> +        <i class="arrows alternate vertical icon"></i> +      </div> +      <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;"> +        <div class="field {% if cform.role.errors %}error{% endif %}"> +          {{ cform.role() }} +        </div> +      </div> +      <div class="eleven wide column" style="padding-bottom: 0px;"> +        <div class="field {% if cform.raw_name.errors %}error{% endif %}"> +          {{ cform.raw_name() }} +        </div> +      </div> +      <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;"> +        <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button> +      </div> +    </div> +  {% endfor %} +  </div> +  <br> +  <button type="button" id="add-contrib-button" class="ui right floated icon green button" style="margin-right: 0.3rem;"> +    <i class="plus icon"></i> +  </button> +  <br> + +  <br> +  <h3 class="ui dividing header">Identifers</h3> +  <br> +  {{ edit_macros.form_field_inline(form.doi) }} +  {{ edit_macros.form_field_inline(form.wikidata_qid) }} +  {{ edit_macros.form_field_inline(form.isbn13) }} +  <div class="ui grid"> +    <div class="three wide column" style="padding-bottom: 0px;"></div> +    <div class="twelve wide column" style="padding-bottom: 0px;"> +      <div class="ui equal width fields"> +        {{ edit_macros.form_field_basic(form.pmid) }} +        {{ edit_macros.form_field_basic(form.pmcid) }} +      </div> +    </div> +    <div class="one wide column" style="padding-bottom: 0px;"></div> +  </div> + +  <br> +  <h3 class="ui dividing header">Container</h3> +  <br> +  {{ edit_macros.form_field_inline(form.container_id) }} +  {{ edit_macros.form_field_inline(form.publisher) }} +  <br> +  <div class="ui grid"> +    <div class="three wide column" style="padding-bottom: 0px;"></div> +    <div class="twelve wide column" style="padding-bottom: 0px;"> +      <div class="ui equal width fields"> +        {{ edit_macros.form_field_basic(form.pages) }} +        {{ edit_macros.form_field_basic(form.volume) }} +        {{ edit_macros.form_field_basic(form.issue) }} +      </div> +    </div> +    <div class="one wide column" style="padding-bottom: 0px;"></div> +  </div> + +  <br><br> +  <h3 class="ui dividing header">Submit</h3> +  {{ edit_macros.form_field_basic(form.edit_description) }} +  This description will be attached to this specific action, not to the +  editgroup as a whole. +{% block edit_form_suffix %} +  <br><br> +  <input class="ui primary submit button" type="submit" value="Update Release!"> +</form> +</div> +{% endblock %} +{% endblock %} + +{% block postscript %} +<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script> +<script> +<!-- Form code --> +$(document).ready(function() { + +  // these javascript dropdowns hide the original <input>, which breaks browser +  // form focusing (eg, for required fields) :( +  //$('#release_type').dropdown(); +  //$('#release_status').dropdown(); +  $('.ui.accordion').accordion(); + +  var fixup_contrib_numbering = function(group_item) { +    items = Array.from(group_item.querySelectorAll(".list-group-item")) +    for (var i = 0; i < items.length; i++) { +      var item_el = items[i]; +      prev_el = item_el.querySelectorAll("input")[0]; +      input_el = item_el.querySelectorAll("input")[1]; +      select_el = item_el.querySelectorAll("select")[0]; +      //console.log(input_el.id); +      //console.log(select_el.id); +      input_el.id = "contribs-" + i + "-raw_name"; +      input_el.name = input_el.id; +      prev_el.id = "contribs-" + i + "-prev_index"; +      prev_el.name = prev_el.id; +      select_el.id = "contribs-" + i + "-role"; +      select_el.name = select_el.id; +      //console.log(input_el.id); +      //console.log(select_el.id); +    }; +    console.log("re-named contrib rows up to i=" + i); +  }; + +  var contrib_list = document.getElementById('contrib_list'); +  var contrib_sortable = Sortable.create(contrib_list, { +    handle: '.sortable-handle', +    animation: 150, +    onSort: function(evt) { +      fixup_contrib_numbering(contrib_list); +    }, +  }); +  fixup_contrib_numbering(contrib_list); + +  var contrib_delete_handler = function(ev) { +    row = ev.target.parentNode.parentNode; +    // I don't understand why this hack is needed; maybe because of the sortable stuff? +    if(!row.classList.contains("list-group-item")) { +        row = row.parentNode; +    } +    // console.log(row); +    console.assert(row.classList.contains("list-group-item")); +    row.parentNode.removeChild(row); +    fixup_contrib_numbering(contrib_list); +  }; + +  var attach_contrib_delete_handler = function(topthing) { +    Array.from(topthing.querySelectorAll(".delete-contrib-button")).forEach((el) => { +      el.addEventListener("click", contrib_delete_handler); +    }); +  }; +  attach_contrib_delete_handler(document); + +  // XXX: really need some way to not duplicate this code from above... +  var contrib_template = ` +  <div class="list-group-item ui grid" style="padding-right: 1em;"> +      <input id="contribs-X-prev_index" name="contribs-X-prev_index" type="hidden" value=""> +      <div class="one wide column middle aligned center aligned sortable-handle" style="padding-bottom: 0px; padding-right: 0px; padding-left: 0px;"> +        <i class="arrows alternate vertical icon"></i> +      </div> +      <div class="three wide column" style="padding-bottom: 0px; padding-left: 0px;"> +        <select id="contribs-X-role" name="contribs-X-role"><option value="author">Author</option><option value="editor">Editor</option><option value="translator">Translator</option></select> +      </div> +      <div class="eleven wide column" style="padding-bottom: 0px;"> +        <input id="contribs-X-raw_name" name="contribs-X-raw_name" type="text" value=""> +      </div> +      <div class="one wide column right aligned" style="padding-bottom: 0px; padding-left: 0rem;"> +        <button type="button" class="ui icon red button delete-contrib-button"><i class="trash icon"></i></button> +      </div> +    </div> +  `; + +  var add_contrib_button = document.getElementById("add-contrib-button"); +  add_contrib_button.addEventListener("click", function(){ +    contrib_list.insertAdjacentHTML('beforeend', contrib_template); +    attach_contrib_delete_handler(contrib_list.lastElementChild); +    fixup_contrib_numbering(contrib_list); +  }); + +  console.log("Page loaded"); + +}); +</script> +{% endblock %} | 
