mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-20 23:16:15 +08:00
Add checklist and list edit mode
This commit is contained in:
parent
7fc9c0d1e4
commit
7664f4be78
|
@ -1,19 +1,25 @@
|
|||
/* global dropdownSelector */
|
||||
/* global dropdownSelector I18n */
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
var ChecklistColumnHelper = (function() {
|
||||
function checklistSelect(select, url) {
|
||||
function checklistSelect(select, url, values) {
|
||||
var selectedOptions = '';
|
||||
if (values) {
|
||||
$.each(values, function(i, option) {
|
||||
selectedOptions += `<option value="${option.value}">${option.label}</option>`;
|
||||
});
|
||||
}
|
||||
return $(`<select
|
||||
id="${select}"
|
||||
data-placeholder = "Select options..."
|
||||
data-ajax-url = "${url}"
|
||||
data-combine-tags="true"
|
||||
data-select-multiple-all-selected="All options"
|
||||
data-select-multiple-name="options"
|
||||
></select>`);
|
||||
data-select-multiple-all-selected="${I18n.t('libraries.manange_modal_column.checklist_type.all_options')}"
|
||||
data-select-multiple-name="${I18n.t('libraries.manange_modal_column.checklist_type.multiple_options')}"
|
||||
>${selectedOptions}</select>`);
|
||||
}
|
||||
|
||||
function checklistHiddenField(formId, columnId, value) {
|
||||
function checklistHiddenField(formId, columnId, values) {
|
||||
return $(`<input form="${formId}"
|
||||
type="hidden"
|
||||
name="repository_cells[${columnId}]"
|
||||
|
@ -21,19 +27,18 @@ var ChecklistColumnHelper = (function() {
|
|||
data-type="RepositoryChecklistValue">`);
|
||||
}
|
||||
|
||||
function initialChecklistEditMode(formId, columnId, cell, value) {
|
||||
function initialChecklistEditMode(formId, columnId, cell, values) {
|
||||
var select = 'checklist-' + columnId;
|
||||
var checklistUrl = $('.repository-column#' + columnId).data('items-url');
|
||||
var $select = checklistSelect(select, checklistUrl);
|
||||
var $hiddenField = checklistHiddenField(formId, columnId, value)
|
||||
var $select = checklistSelect(select, checklistUrl, values);
|
||||
var $hiddenField = checklistHiddenField(formId, columnId, values);
|
||||
cell.html($select).append($hiddenField);
|
||||
dropdownSelector.init('#' + select, {
|
||||
noEmptyOption: true,
|
||||
optionClass: 'checkbox-icon',
|
||||
selectAppearance: 'simple',
|
||||
onChange: function() {
|
||||
var values = JSON.stringify(dropdownSelector.getValues('#' + select));
|
||||
$hiddenField.val(values)
|
||||
$hiddenField.val(JSON.stringify(dropdownSelector.getValues('#' + select)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
var ListColumnHelper = (function() {
|
||||
function listSelect(select, url, value) {
|
||||
var selectedOption = '';
|
||||
if (value) {
|
||||
if (value && value.value) {
|
||||
selectedOption = `<option value="${value.value}">${value.label}</option>`;
|
||||
}
|
||||
return $(`<select
|
||||
|
@ -33,7 +33,7 @@ var ListColumnHelper = (function() {
|
|||
singleSelect: true,
|
||||
selectAppearance: 'simple',
|
||||
onChange: function() {
|
||||
var values = JSON.stringify(dropdownSelector.getValues('#' + select));
|
||||
var values = dropdownSelector.getValues('#' + select);
|
||||
$hiddenField.val(values);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global List Status SmartAnnotation I18n GLOBAL_CONSTANTS */
|
||||
/* global ListColumnHelper ChecklistColumnHelper Status SmartAnnotation I18n GLOBAL_CONSTANTS */
|
||||
|
||||
$.fn.dataTable.render.editRowName = function(formId, cell) {
|
||||
let $cell = $(cell.node());
|
||||
|
@ -59,13 +59,16 @@ $.fn.dataTable.render.editRepositoryTextValue = function(formId, columnId, cell)
|
|||
|
||||
$.fn.dataTable.render.editRepositoryListValue = function(formId, columnId, cell) {
|
||||
var $cell = $(cell.node());
|
||||
var currentElement = $cell.find('.list-label')
|
||||
var currentValue = {
|
||||
value: currentElement.attr('data-value-id'),
|
||||
label: currentElement.text()
|
||||
var currentElement = $cell.find('.list-label');
|
||||
var currentValue = null;
|
||||
if (currentElement.length) {
|
||||
currentValue = {
|
||||
value: currentElement.attr('data-value-id'),
|
||||
label: currentElement.text()
|
||||
};
|
||||
}
|
||||
|
||||
ListColumnHelper.initialListEditMode(formId, columnId, $cell, currentValue)
|
||||
ListColumnHelper.initialListEditMode(formId, columnId, $cell, currentValue);
|
||||
};
|
||||
|
||||
$.fn.dataTable.render.editRepositoryStatusValue = function(formId, columnId, cell) {
|
||||
|
@ -110,5 +113,7 @@ $.fn.dataTable.render.editRepositoryTimeRangeValue = function(formId, columnId,
|
|||
};
|
||||
|
||||
$.fn.dataTable.render.editRepositoryChecklistValue = function(formId, columnId, cell) {
|
||||
return '';
|
||||
var $cell = $(cell.node());
|
||||
var currentValue = $cell.find('.checklist-options').data('checklist-items');
|
||||
ChecklistColumnHelper.initialChecklistEditMode(formId, columnId, $cell, currentValue);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global List Status SmartAnnotation I18n GLOBAL_CONSTANTS */
|
||||
/* global ListColumnHelper ChecklistColumnHelper Status SmartAnnotation I18n GLOBAL_CONSTANTS */
|
||||
|
||||
$.fn.dataTable.render.newRowName = function(formId, $cell) {
|
||||
$cell.html(`
|
||||
|
@ -48,7 +48,7 @@ $.fn.dataTable.render.newRepositoryTextValue = function(formId, columnId, $cell)
|
|||
};
|
||||
|
||||
$.fn.dataTable.render.newRepositoryListValue = function(formId, columnId, $cell) {
|
||||
ListColumnHelper.initialListEditMode(formId, columnId, $cell)
|
||||
ListColumnHelper.initialListEditMode(formId, columnId, $cell);
|
||||
};
|
||||
|
||||
$.fn.dataTable.render.newRepositoryStatusValue = function(formId, columnId, $cell) {
|
||||
|
@ -66,5 +66,5 @@ $.fn.dataTable.render.newRepositoryStatusValue = function(formId, columnId, $cel
|
|||
};
|
||||
|
||||
$.fn.dataTable.render.newRepositoryChecklistValue = function(formId, columnId, $cell) {
|
||||
ChecklistColumnHelper.initialChecklistEditMode(formId, columnId, $cell)
|
||||
ChecklistColumnHelper.initialChecklistEditMode(formId, columnId, $cell);
|
||||
};
|
||||
|
|
|
@ -97,8 +97,27 @@ $.fn.dataTable.render.RepositoryDateRangeValue = function(data) {
|
|||
};
|
||||
|
||||
$.fn.dataTable.render.RepositoryChecklistValue = function(data) {
|
||||
console.log(data)
|
||||
return '';
|
||||
var render = '—';
|
||||
var options = data.value;
|
||||
if (options.length == 1) {
|
||||
render = `<span class="checklist-options" data-checklist-items='${JSON.stringify(options)}'>
|
||||
${options[0].label}
|
||||
</span>`
|
||||
} else if (options.length > 1) {
|
||||
var optionsList = $(' <ul class="dropdown-menu checklist-dropdown-menu" role="menu"></ul');
|
||||
$.each(options, function(i, option) {
|
||||
$(`<li class="checklist-item">${option.label}</li>`).appendTo(optionsList)
|
||||
})
|
||||
|
||||
render = `
|
||||
<span class="dropdown checklist-dropdown">
|
||||
<span data-toggle="dropdown" class="checklist-options" aria-haspopup="true" data-checklist-items='${JSON.stringify(options)}'>
|
||||
${options.length} ${I18n.t('libraries.manange_modal_column.checklist_type.multiple_options')}
|
||||
</span>
|
||||
${optionsList[0].outerHTML}
|
||||
</span>`
|
||||
}
|
||||
return render;
|
||||
};
|
||||
|
||||
$.fn.dataTable.render.defaultRepositoryChecklistValue = function() {
|
||||
|
|
|
@ -63,7 +63,7 @@ var RepositoryChecklistColumnType = (function() {
|
|||
checkValidation: () => {
|
||||
var $manageModal = $(manageModal);
|
||||
var count = $manageModal.find(previewContainer).find('.items-count').attr('data-count');
|
||||
return count < GLOBAL_CONSTANTS.REPOSITORY_LIST_ITEMS_PER_COLUMN;
|
||||
return count < GLOBAL_CONSTANTS.REPOSITORY_CHECKLIST_ITEMS_PER_COLUMN;
|
||||
},
|
||||
loadParams: () => {
|
||||
var repositoryColumnParams = {};
|
||||
|
|
|
@ -5,5 +5,6 @@ const GLOBAL_CONSTANTS = {
|
|||
FILENAME_TRUNCATION_LENGTH: <%= Constants::FILENAME_TRUNCATION_LENGTH %>,
|
||||
FILE_MAX_SIZE_MB: <%= Rails.configuration.x.file_max_size_mb %>,
|
||||
IS_SAFARI: /^((?!chrome|android).)*safari/i.test(navigator.userAgent),
|
||||
REPOSITORY_LIST_ITEMS_PER_COLUMN: <%= Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN %>
|
||||
REPOSITORY_LIST_ITEMS_PER_COLUMN: <%= Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN %>,
|
||||
REPOSITORY_CHECKLIST_ITEMS_PER_COLUMN: <%= Constants::REPOSITORY_CHECKLIST_ITEMS_PER_COLUMN %>
|
||||
};
|
||||
|
|
|
@ -63,11 +63,11 @@ var dropdownSelector = (function() {
|
|||
if (modalContainer.length) {
|
||||
windowHeight = modalContainer.height() + modalContainer[0].getBoundingClientRect().top;
|
||||
modalContainerBottom = modalContainer[0].getBoundingClientRect().bottom;
|
||||
maxHeight += modalContainerBottom
|
||||
maxHeight += modalContainerBottom;
|
||||
}
|
||||
|
||||
bottomSpace = windowHeight - containerPosition - containerHeight;
|
||||
|
||||
|
||||
if ((modalContainerBottom + bottomSpace) < 280) {
|
||||
container.addClass('inverse');
|
||||
container.find('.dropdown-container').css('max-height', `${(containerPosition - 122 + maxHeight)}px`)
|
||||
|
@ -77,7 +77,7 @@ var dropdownSelector = (function() {
|
|||
container.removeClass('inverse');
|
||||
container.find('.dropdown-container').css('max-height', `${(bottomSpace - 32 + maxHeight)}px`)
|
||||
.css('width', `${containerWidth}px`)
|
||||
.css('margin-top', `${(bottomSpace * -1)}px`)
|
||||
.css('margin-top', `${(bottomSpace * -1)}px`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,7 +381,8 @@ var dropdownSelector = (function() {
|
|||
});
|
||||
|
||||
// When user will resize browser we must check dropdown position
|
||||
$(window).resize(function() { updateDropdownDirection(selectElement, dropdownContainer); });
|
||||
$(window).resize(() => { updateDropdownDirection(selectElement, dropdownContainer); });
|
||||
$(window).scroll(() => { updateDropdownDirection(selectElement, dropdownContainer); });
|
||||
|
||||
// When user will click away, we must close dropdown
|
||||
$(window).click(() => {
|
||||
|
@ -663,7 +664,7 @@ var dropdownSelector = (function() {
|
|||
// If we have alteast one tag, we need to remove placeholder from search field
|
||||
searchFieldValue.attr('placeholder',
|
||||
selectedOptions.length > 0 ? '' : (selector.data('placeholder') || ''));
|
||||
searchFieldValue.attr('data-options-selected', selectedOptions.length)
|
||||
searchFieldValue.attr('data-options-selected', selectedOptions.length);
|
||||
|
||||
// Add stretch class for visual improvments
|
||||
if (!selector.data('combine-tags')) {
|
||||
|
|
17
app/assets/stylesheets/repository/repository_table.scss
Normal file
17
app/assets/stylesheets/repository/repository_table.scss
Normal file
|
@ -0,0 +1,17 @@
|
|||
// scss-lint:disable SelectorDepth SelectorFormat QualifyingElement
|
||||
// scss-lint:disable NestingDepth ImportantRule
|
||||
|
||||
@import "constants";
|
||||
|
||||
.repository-table {
|
||||
// Cells
|
||||
|
||||
// Checklists
|
||||
.checklist-dropdown {
|
||||
.dropdown-menu {
|
||||
.checklist-item {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -167,7 +167,7 @@
|
|||
cursor: pointer;
|
||||
display: flex;
|
||||
min-height: 32px;
|
||||
padding: 0 10px;
|
||||
padding: 3px 10px;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
|
||||
|
|
|
@ -47,10 +47,9 @@ module RepositoryColumns
|
|||
|
||||
def items
|
||||
column_checklist_items = @repository_column.repository_checklist_items
|
||||
.where('data ILIKE ?',
|
||||
"%#{search_params[:query]}%")
|
||||
.limit(Constants::SEARCH_LIMIT)
|
||||
.select(:id, :data)
|
||||
.where('data ILIKE ?',
|
||||
"%#{search_params[:query]}%")
|
||||
.select(:id, :data)
|
||||
|
||||
render json: column_checklist_items.map { |i| { value: i.id, label: escape_input(i.data) } }, status: :ok
|
||||
end
|
||||
|
|
|
@ -18,5 +18,22 @@ class RepositoryChecklistValue < ApplicationRecord
|
|||
def data
|
||||
repository_cell.repository_column.repository_checklist_items
|
||||
.where(id: repository_checklist_items).select(:id, :data)
|
||||
.map { |i| { value: i.id, label: i.data } }
|
||||
end
|
||||
|
||||
def data_changed?(new_data)
|
||||
JSON.parse(new_data) != repository_checklist_items
|
||||
end
|
||||
|
||||
def update_data!(new_data, user)
|
||||
self.repository_checklist_items = JSON.parse(new_data)
|
||||
self.last_modified_by = user
|
||||
save!
|
||||
end
|
||||
|
||||
def self.new_with_payload(payload, attributes)
|
||||
value = new(attributes)
|
||||
value.repository_checklist_items = JSON.parse(payload)
|
||||
value
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,12 +14,12 @@ module RepositoryColumns
|
|||
@column.lock!
|
||||
|
||||
updating_items_names = @params[:repository_checklist_items_attributes].to_a.map { |e| e[:data] }
|
||||
existing_items_names = @column.repository_checkbox_items.pluck(:data)
|
||||
existing_items_names = @column.repository_checklist_items.pluck(:data)
|
||||
to_be_deleted = existing_items_names - updating_items_names
|
||||
to_be_created = updating_items_names - existing_items_names
|
||||
|
||||
if @column.repository_list_items.size - to_be_deleted.size + to_be_created.size >=
|
||||
Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN
|
||||
Constants::REPOSITORY_CHECKLIST_ITEMS_PER_COLUMN
|
||||
|
||||
@errors[:repository_column] = { repository_checklist_items: 'too many items' }
|
||||
end
|
||||
|
@ -30,7 +30,7 @@ module RepositoryColumns
|
|||
|
||||
ActiveRecord::Base.transaction do
|
||||
to_be_deleted.each do |item|
|
||||
@column.repository_checkbox_items.find_by(data: item).destroy!.id
|
||||
@column.repository_checklist_items.find_by(data: item).destroy!.id
|
||||
end
|
||||
|
||||
to_be_created.each do |item|
|
||||
|
|
|
@ -25,7 +25,7 @@ module RepositoryRows
|
|||
|
||||
params[:repository_cells]&.each do |column_id, value|
|
||||
column = @repository.repository_columns.find_by(id: column_id)
|
||||
next unless column
|
||||
next if !column || value.empty?
|
||||
|
||||
RepositoryCell.create_with_value!(@repository_row, column, value, @user)
|
||||
end
|
||||
|
|
|
@ -31,15 +31,12 @@ module RepositoryRows
|
|||
next
|
||||
end
|
||||
|
||||
unless cell
|
||||
RepositoryCell.create_with_value!(@repository_row, column, value, @user)
|
||||
@record_updated = true
|
||||
next
|
||||
end
|
||||
|
||||
if cell.value.data_changed?(value)
|
||||
if cell&.value&.data_changed?(value)
|
||||
cell.value.update_data!(value, @user)
|
||||
@record_updated = true
|
||||
elsif !value.empty?
|
||||
RepositoryCell.create_with_value!(@repository_row, column, value, @user)
|
||||
@record_updated = true
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</select>
|
||||
<div class="limit-counter-container">
|
||||
<span class="items-count"></span>
|
||||
<span class="items-limit">/<%= Constants::REPOSITORY_LIST_ITEMS_PER_COLUMN %> </span>
|
||||
<span class="items-limit">/<%= Constants::REPOSITORY_CHECKLIST_ITEMS_PER_COLUMN %> </span>
|
||||
<span class="items-label"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -976,6 +976,7 @@ class Constants
|
|||
EXPORTABLE_ZIP_EXPIRATION_DAYS = 7
|
||||
|
||||
REPOSITORY_LIST_ITEMS_PER_COLUMN = 500
|
||||
REPOSITORY_CHECKLIST_ITEMS_PER_COLUMN = 50
|
||||
REPOSITORY_NUMBER_TYPE_MAX_DECIMALS = 11
|
||||
|
||||
REPOSITORY_LIST_ITEMS_DELIMITERS_MAP = {
|
||||
|
|
Loading…
Reference in a new issue