diff options
-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 %} |