UI: fixes based on Actionable Feedback from devtalk and frontend changes #40
@ -127,6 +127,7 @@
|
||||
|
||||
a
|
||||
overflow: hidden
|
||||
// TODO: consider changing text-decoration underlines to border-bottoms for improved, more spatious vertical spacings
|
||||
text-decoration: underline
|
||||
text-overflow: ellipsis
|
||||
white-space: nowrap
|
||||
@ -339,6 +340,7 @@
|
||||
width: var(--preview-thumbnail-max-size)
|
||||
|
||||
.previews-list-item-thumbnail-img
|
||||
background-color: var(--background-color)
|
||||
background-position: center
|
||||
background-size: cover
|
||||
border-radius: var(--border-radius)
|
||||
@ -368,6 +370,11 @@
|
||||
pointer-events: none
|
||||
user-select: none
|
||||
|
||||
.form-control
|
||||
&[type="file"]
|
||||
font-size: var(--font-size-extra-small)
|
||||
max-width: 50%
|
||||
|
||||
.ext-version-history
|
||||
summary
|
||||
display: flex
|
||||
|
@ -1,3 +1,5 @@
|
||||
// TODO: improve and refactor variable namings
|
||||
|
||||
const formsetContainer = document.getElementById('add-image-container');
|
||||
const form = document.getElementById('update-extension-form');
|
||||
const btnAddImage = document.getElementById('btn-add-image');
|
||||
@ -5,35 +7,173 @@ const formsetPrefix = 'form';
|
||||
const inputTotalForms = document.getElementById(`id_${formsetPrefix}-TOTAL_FORMS`);
|
||||
const tagInput = document.getElementById('id_tags');
|
||||
|
||||
// Create function addImgUploadFormClasses
|
||||
function addImgUploadFormClasses() {
|
||||
// Function intializes img upload widgets' custom classes for js manage
|
||||
const inputImgHelper = document.querySelector('.js-input-img-helper');
|
||||
const inputImgCaptionHelper = document.querySelector('.js-input-img-caption-helper');
|
||||
|
||||
inputImgHelper.querySelector('input')
|
||||
.classList.add('js-input-img');
|
||||
|
||||
inputImgHelper.querySelector('label')
|
||||
.classList.add('d-none');
|
||||
|
||||
inputImgCaptionHelper.querySelector('input')
|
||||
.classList.add('js-input-img-caption');
|
||||
}
|
||||
|
||||
function appendImageUploadForm() {
|
||||
const i = inputTotalForms.value;
|
||||
const formRow = document.createElement('div');
|
||||
const newFormHTML = `
|
||||
<div class="col">
|
||||
<input type="file" name="${formsetPrefix}-${i}-source"
|
||||
accept="image/*" class="form-control"
|
||||
id="id_${formsetPrefix}-${i}-source">
|
||||
<div class="invalid-feedback"></div>
|
||||
<div class="previews-list-item">
|
||||
<div class="align-items-center d-flex previews-list-item-thumbnail pl-3">
|
||||
<div class="js-input-img-thumbnail previews-list-item-thumbnail-img" title="Preview">
|
||||
<div class="align-items-center d-flex js-input-img-thumbnail-icon justify-content-center">
|
||||
<i class="i-image"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="details flex-grow-1">
|
||||
<div class="mb-2">
|
||||
<label for="${formsetPrefix}-${i}-caption">Caption</label>
|
||||
<input class="js-input-img-caption form-control" id="${formsetPrefix}-${i}-caption" type="text" maxlength="255" name="${formsetPrefix}-${i}-caption" placeholder="Describe the preview">
|
||||
</div>
|
||||
<div class="align-items-center d-flex justify-content-between">
|
||||
<input accept="image/*" class="form-control js-input-img" id="id_${formsetPrefix}-${i}-source" type="file" name="${formsetPrefix}-${i}-source">
|
||||
<ul class="pt-0">
|
||||
<li>
|
||||
<button class="btn btn-link btn-sm js-btn-reset-img-upload-form pl-2 pr-0"><i class="i-refresh"></i> Reset</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="btn btn-link btn-sm js-btn-remove-img-upload-form pl-2 pr-0"><i class="i-trash"></i> Delete</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" name="${formsetPrefix}-${i}-caption"
|
||||
maxlength="255" placeholder="Describe the preview"
|
||||
class="form-control" id="id_${formsetPrefix}-${i}-caption">
|
||||
<div class="invalid-feedback"></div>
|
||||
</div>
|
||||
`;
|
||||
formRow.classList.add('row', 'ext-edit-field-row');
|
||||
formRow.classList.add('ext-edit-field-row', 'fade', 'js-ext-edit-field-row');
|
||||
formRow.innerHTML = newFormHTML;
|
||||
formsetContainer.appendChild(formRow);
|
||||
inputTotalForms.value = parseInt(inputTotalForms.value) + 1;
|
||||
|
||||
setTimeout(function() {
|
||||
// TODO: fix jump coming from grid gap on parent
|
||||
formRow.classList.add('show');
|
||||
}, 20);
|
||||
}
|
||||
|
||||
btnAddImage.addEventListener('click', function(ev) {
|
||||
ev.preventDefault();
|
||||
appendImageUploadForm();
|
||||
|
||||
// Init function removeImgUploadForm
|
||||
removeImgUploadForm();
|
||||
|
||||
// Init function resetImgUploadForm
|
||||
resetImgUploadForm();
|
||||
|
||||
// Init function setImgUploadFormThumbnail
|
||||
setImgUploadFormThumbnail();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Create function removeImgUploadForm
|
||||
function removeImgUploadForm() {
|
||||
const btnRemoveImgUploadForm = document.querySelectorAll('.js-btn-remove-img-upload-form');
|
||||
|
||||
btnRemoveImgUploadForm.forEach(function(item) {
|
||||
item.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Find the row parent
|
||||
const rowParent = this.closest('.js-ext-edit-field-row');
|
||||
|
||||
// Remove the row
|
||||
rowParent.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Create function resetImgUploadForm
|
||||
function resetImgUploadForm() {
|
||||
const btnResetImgUploadForm = document.querySelectorAll('.js-btn-reset-img-upload-form');
|
||||
|
||||
btnResetImgUploadForm.forEach(function(item) {
|
||||
item.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Find the row parent
|
||||
const rowParent = this.closest('.js-ext-edit-field-row');
|
||||
|
||||
// Find the input image
|
||||
const inputImg = rowParent.querySelector('.js-input-img');
|
||||
|
||||
// Find the input image caption
|
||||
const inputImgCaption = rowParent.querySelector('.js-input-img-caption');
|
||||
|
||||
// Find the input image thumbnail
|
||||
const inputImgThumbnail = rowParent.querySelector('.js-input-img-thumbnail');
|
||||
|
||||
// Find the input image thumbnail icon
|
||||
const inputImgThumbnailIcon = rowParent.querySelector('.js-input-img-thumbnail-icon');
|
||||
|
||||
// Reset the selected image (if any)
|
||||
inputImg.value = ''; // Clear the input value
|
||||
|
||||
// Reset the selected image caption
|
||||
inputImgCaption.value='';
|
||||
|
||||
// Reset the selected image thumbnail
|
||||
inputImgThumbnail.removeAttribute('style');
|
||||
|
||||
// Hide the selected image thumbnail icon
|
||||
inputImgThumbnailIcon.classList.add('d-flex');
|
||||
inputImgThumbnailIcon.classList.remove('d-none');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Create function setImgUploadFormThumbnail
|
||||
function setImgUploadFormThumbnail() {
|
||||
const inputImg = document.querySelectorAll('.js-input-img');
|
||||
|
||||
inputImg.forEach(function(item) {
|
||||
item.addEventListener('change', function(e) {
|
||||
// Init file image
|
||||
const file = event.target.files[0];
|
||||
|
||||
// Find the row parent
|
||||
const rowParent = this.closest('.js-ext-edit-field-row');
|
||||
|
||||
// Find the thumbnail image
|
||||
const inputImgThumbnail = rowParent.querySelector('.js-input-img-thumbnail');
|
||||
|
||||
// Find the input image thumbnail icon
|
||||
const inputImgThumbnailIcon = rowParent.querySelector('.js-input-img-thumbnail-icon');
|
||||
|
||||
// Set thumbnail img
|
||||
if (file) {
|
||||
inputImgThumbnail.style.backgroundImage = `url('${URL.createObjectURL(file)}')`;
|
||||
}
|
||||
|
||||
// Hide the selected image thumbnail icon
|
||||
inputImgThumbnailIcon.classList.add('d-none');
|
||||
inputImgThumbnailIcon.classList.remove('d-flex');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Create function init
|
||||
function init() {
|
||||
addImgUploadFormClasses();
|
||||
resetImgUploadForm();
|
||||
setImgUploadFormThumbnail();
|
||||
}
|
||||
|
||||
// Configure tag selection, if present on the page
|
||||
if (tagInput) {
|
||||
const taggerOptions = {
|
||||
@ -51,3 +191,5 @@ if (tagInput) {
|
||||
tagger(tagInput, taggerOptions);
|
||||
// FIXME: changes to the tags input don't trigger form change
|
||||
};
|
||||
|
||||
init();
|
||||
|
@ -307,9 +307,11 @@
|
||||
{% endif %}
|
||||
{% for rating in extension.ratings.listed_texts|slice:":3" %}
|
||||
{% include "ratings/components/review.html" %}
|
||||
{% empty %}
|
||||
<a href="{{ extension.get_rate_url }}">{% trans "Be the first to review." %}</a>
|
||||
{% endfor %}
|
||||
|
||||
{% if not extension.ratings.listed.count and not my_rating %}
|
||||
<a href="{{ extension.get_rate_url }}">{% trans "Be the first to review." %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{# Rating #}
|
||||
|
@ -1,22 +1,40 @@
|
||||
{% load common %}
|
||||
{# Upload new preview images #}
|
||||
{% load i18n %}
|
||||
<div id="add-image-container">
|
||||
<div class="previews-upload">
|
||||
<div id="add-image-container" class="previews-list">
|
||||
{{ add_preview_formset.management_form }}
|
||||
{{ add_preview_formset.non_form_errors }}
|
||||
{% for newform in add_preview_formset %}
|
||||
{% with inlineform=newform|add_form_classes %}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{% include "common/components/field.html" with field=inlineform.source label='File' %}
|
||||
<div class="ext-edit-field-row js-ext-edit-field-row">
|
||||
<div class="previews-list-item">
|
||||
<div class="align-items-center d-flex previews-list-item-thumbnail pl-3">
|
||||
<div class="js-input-img-thumbnail previews-list-item-thumbnail-img" title="Preview">
|
||||
<div class="align-items-center d-flex js-input-img-thumbnail-icon justify-content-center">
|
||||
<i class="i-image"></i>
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
<div class="details flex-grow-1">
|
||||
<div class="js-input-img-caption-helper mb-2">
|
||||
{% include "common/components/field.html" with field=inlineform.caption label='Caption' %}
|
||||
</div>
|
||||
<div class="align-items-center d-flex js-input-img-helper justify-content-between">
|
||||
{% include "common/components/field.html" with field=inlineform.source label='File' %}
|
||||
<ul class="pt-0">
|
||||
<li>
|
||||
<button class="btn btn-link btn-sm js-btn-reset-img-upload-form pl-2 pr-0"><i class="i-refresh"></i> Reset</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ inlineform.non_form_errors }}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-right mt-3">
|
||||
|
@ -126,13 +126,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# TODO: remove comment to show btn delete if deletion works #}
|
||||
{% comment %}
|
||||
<div class="btn-col justify-content-end">
|
||||
{# TODO: Make deletion work #}
|
||||
<a href="{{ extension.get_delete_url }}" class="btn btn-danger btn-link w-100">
|
||||
<i class="i-trash"></i> {% trans 'Delete Extension' %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% endcomment %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -32,8 +32,9 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% elif not my_rating %}
|
||||
<span class="text-muted">Be the first to review.</span>
|
||||
{% else %}
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-3">
|
||||
|
@ -27,9 +27,11 @@
|
||||
{% endif %}
|
||||
{% for rating in object_list %}
|
||||
{% include "ratings/components/review.html" %}
|
||||
{% empty %}
|
||||
{% trans "Be the first to review." %}
|
||||
{% endfor %}
|
||||
|
||||
{% if not extension.ratings.listed.count and not my_rating %}
|
||||
{% trans "Be the first to review." %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user