UNPKG

@dynvis/datocms-plugin-typed-list

Version:

This plugin transforms JSON fields of array type into editable lists.

348 lines (297 loc) 9.87 kB
<!doctype 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>