@dynvis/datocms-plugin-typed-list
Version:
This plugin transforms JSON fields of array type into editable lists.
348 lines (297 loc) • 9.87 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<script src="https://unpkg.com/datocms-plugins-sdk"></script>
<link href="https://unpkg.com/datocms-plugins-sdk/dist/sdk.css" media="all" rel="stylesheet" />
<style>
ul {
margin-bottom: 16px;
}
ul#list {
border: 1px solid #f0f0f0;
color: #34363a;
font-size: 16px;
font-family: Roboto, Helvetica Neue, Helvetica, Arial, sans-serif;
line-height: 1.5;
}
ul#list li {
border-bottom: 1px solid #f0f0f0;
display: flex;
min-height: 36px;
align-items: center;
}
ul#list li:last-child {
border-bottom: none;
}
ul#list li .item-value {
flex: 1 1 auto;
padding: 10px 0;
cursor: pointer;
}
ul#list li .edit-controls {
flex: 1 1 auto;
position: relative;
}
ul#list li .edit-input {
width: 100%;
border: 0;
font-size: 16px;
padding-right: 40px;
box-sizing: border-box;
}
ul#list li .edit-button {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
color: #777;
}
ul#list li .remove-button {
display: inline-block;
flex: 0 0 auto;
height: 32px;
width: 32px;
cursor: pointer;
text-align: center;
padding-right: 5px;
}
ul#list li .remove-button .fas {
vertical-align: bottom;
color: #777;
}
ul#list li .drag-handle {
padding: 0 16px;
cursor: move;
color: #777;
}
ul#list li.moving {
background-color: #c8effb;
}
ul#list.is-dragging {
cursor: move;
}
.inputLabel {
color: #34363a;
font-size: 16px;
font-family: Roboto, Helvetica Neue, Helvetica, Arial, sans-serif;
}
.inputLine {
display: flex;
}
.inputLine input {
flex: 1 1 auto;
}
.inputLine button {
flex: 0 0;
}
#selectWrapper {
flex: 1 1 auto;
position: relative;
}
select#optionSelect {
display: block;
box-sizing: border-box;
width: 100%;
padding: 10px;
border: 1px solid #f0f0f0;
-moz-appearance: none;
-webkit-appearance: none;
border-radius: 0;
background-image: none;
font-size: 16px;
font-family: Roboto, Helvetica Neue, Helvetica, Arial, sans-serif;
}
.select-icon {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 40px;
display: flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<ul id="list" style="display:none"></ul>
<div class="inputField">
<label for="itemInput" class="inputLabel"><span>Select item</span></label>
<div class="inputLine">
<input id="itemInput" type="text" autocomplete="off" name="item_input" />
<div id="selectWrapper" style="display: none;">
<select id="optionSelect" name="option_select"></select>
<i class="select-icon fas fa-lg fa-chevron-down"></i>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<script type="text/javascript">
function deserializeValue(value) {
if (!value) {
return [];
}
return JSON.parse(value);
}
function getFieldValue(plugin) {
var fieldValue = plugin.getFieldValue(plugin.fieldPath);
return deserializeValue(fieldValue);
}
function setFieldValue(plugin, value) {
return plugin.setFieldValue(plugin.fieldPath, JSON.stringify(value));
}
function getFieldType(plugin) {
var type = _.get(plugin, 'parameters.instance.type', 'string');
if (!_.includes(['string', 'number'], type)) {
console.error('illegal type "' + type + '" for datocms-plugin-typed-list');
return 'string';
}
return type;
}
function getOptions(plugin) {
var type = getFieldType(plugin);
if (type === 'string') {
var options = _.get(plugin, 'parameters.instance.options', '');
var optionsArr = _.chain(options).split(',').map(option => _.trim(option)).compact().value();
return _.isEmpty(optionsArr) ? null : optionsArr;
} else {
return null;
}
}
function showSelect(options, inputElm, selectElm, selectWrapperElm) {
// inputElm.style.display = 'none';
selectWrapperElm.style.display = '';
_.forEach([''].concat(options), option => {
var optionElm = document.createElement('option');
optionElm.name = option;
optionElm.appendChild(document.createTextNode(option));
selectElm.appendChild(optionElm);
});
}
function resetList(list, listElm, plugin) {
while (listElm.firstChild) {
listElm.removeChild(listElm.firstChild);
}
_.forEach(list, item => {
var liElm = createListItem(item, listElm, list, plugin);
listElm.appendChild(liElm);
});
if (_.isEmpty(list)) {
listElm.style.display = 'none';
} else {
listElm.style.display = 'none';
// listElm.style.display = '';
}
}
function createListItem(value, listElm, list, plugin) {
var liElm = document.createElement('li');
var buttonElm = document.createElement('span');
var removeIcon = document.createElement('i');
var dragContainer = document.createElement('span');
var dragIcon = document.createElement('i');
var span = document.createElement('span');
var textNode = document.createTextNode(value);
span.className = 'item-value';
buttonElm.className = 'remove-button';
removeIcon.className = 'fas fa-times';
dragContainer.className = 'drag-handle';
dragIcon.className = 'fas fa-grip-lines';
dragContainer.appendChild(dragIcon);
buttonElm.appendChild(removeIcon);
span.appendChild(textNode);
liElm.setAttribute('draggable', 'true');
liElm.appendChild(dragContainer);
liElm.appendChild(span);
liElm.appendChild(buttonElm);
buttonElm.addEventListener('click', function() {
removeItem(liElm, listElm, list, plugin);
});
return liElm;
}
function addItem(inputElm, list, listElm, plugin, type, options) {
var value = inputElm.value;
if (value !== '') {
if (type === 'string') {
if (_.isEmpty(options) || _.includes(options, value)) {
inputElm.value = '';
list.push(value);
setFieldValue(plugin, list);
}
} else if (type === 'number') {
var number = _.toNumber(value);
if (_.isNumber(number)) {
inputElm.value = '';
list.push(number);
setFieldValue(plugin, list);
}
}
}
}
function parentElement(el, sel) {
do {
if (el.matches(sel)) {
return el;
}
} while (el = el.parentElement);
return null;
}
function init(plugin) {
plugin.startAutoResizer();
var type = getFieldType(plugin);
var options = getOptions(plugin);
var list = getFieldValue(plugin);
var inputElm = document.getElementById('itemInput');
var selectElm = document.getElementById('optionSelect');
var selectWrapperElm = document.getElementById('selectWrapper');
var listElm = document.getElementById('list');
var addItemButtonElm = document.getElementById('addItemButton');
if (!_.isEmpty(options)) {
showSelect(options, inputElm, selectElm, selectWrapperElm);
}
resetList(list, listElm, plugin);
if (type === 'number') {
inputElm.type = 'number';
}
plugin.addFieldChangeListener(plugin.fieldPath, function(newValue) {
list = deserializeValue(newValue);
resetList(list, listElm, plugin);
});
selectElm.addEventListener("change", function(e) {
plugin.setFieldValue(plugin.fieldPath, "[" + JSON.stringify(e.target.value) + "]");
// var formElement = _.isEmpty(options) ? inputElm : selectElm;
});
inputElm.addEventListener("keyup", function(event) {
if ((event.keyCode === 13 || event.key === 'Enter')) {
addItem(inputElm, list, listElm, plugin, type, options);
plugin.setFieldValue(plugin.fieldPath, "[" + JSON.stringify(e.target.value) + "]");
}
});
}
if (!_.isUndefined(DatoCmsPlugin) && window.parent !== window) {
DatoCmsPlugin.init(init);
} else {
var list = JSON.stringify(["foo", "bar"]);
init({
callbacks: {},
startAutoResizer: () => {},
addFieldChangeListener: function(fieldPath, callback) {
this.callbacks[fieldPath] = callback;
},
getFieldValue: () => list,
setFieldValue: function(fieldPath, value) {
list = value;
_.invoke(this.callbacks, fieldPath, [value]);
},
fieldPath: 'some_field',
parameters: {
instance: {
type: 'string'
}
}
});
}
</script>
</body>
</html>