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