Skip to content

Commit

Permalink
Merge pull request #133 from nicolaslabbe/drag_autocomplete
Browse files Browse the repository at this point in the history
Drag autocomplete
  • Loading branch information
gregorybesson committed Feb 3, 2017
2 parents df9cf42 + 5a9d13f commit 2b5b2ac
Show file tree
Hide file tree
Showing 17 changed files with 191 additions and 63 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -58,6 +58,7 @@
"csurf": "^1.8.3",
"deepmerge": "^1.3.2",
"dir-compare": "^1.2.0",
"dragula": "^3.7.2",
"express": "^4.13.3",
"express-handlebars": "^3.0.0",
"express-secure-handlebars": "^2.1.0",
Expand Down
17 changes: 12 additions & 5 deletions src/cli/cms/editor/handlebars/printInput.js
Expand Up @@ -19,7 +19,7 @@ export function getAttributes(params) {
if(params.placeholder != null) attributes += ` placeholder="${params.placeholder}"`
if(params.thumbs != null) attributes += ` data-size="${params.thumbs}"`
if(params.toolbar != null) attributes += ` data-toolbar="${params.toolbar}"`
if(params.multiple != null) attributes += ` ${params.multiple}`
if(params.multiple != null) attributes += ` data-multiple="${params.multiple}"`
if(params.disabled != null) attributes += ` ${params.disabled}`
return attributes
}
Expand All @@ -44,7 +44,10 @@ export function hint(params) {
export function createInputSource(attributes, inputClass, params) {
var inputSource = `<div class="parent-${params.type} parent-${params.key}" data-parent="${params.key}">`
var lastValues
if(params.autocomplete != null && params.autocomplete === 'true') {

if((params.autocomplete != null && params.autocomplete === 'true')
|| params.multiple != null && params.multiple === 'multiple') {

if(params.sourceString.indexOf('http') === 0) lastValues = params.source
else lastValues = JSON.stringify(params.source).replace(/\'/g, '&quote;')
inputSource += '<div class="autocomplete-result-wrapper">'
Expand All @@ -61,11 +64,15 @@ export function createInputSource(attributes, inputClass, params) {
Array.prototype.forEach.call(params.value, (val) => {
inputSource += sourceAutocomplete(val, params)
})
inputSource += `</div><input value="" type="text" autocomplete="off" data-value='${lastValues}' ${attributes} class="${inputClass}" />`
inputSource += `</div>`
}

if(params.autocomplete != null && params.autocomplete === 'true') {
inputSource += `<input value="" type="text" autocomplete="off" data-value='${lastValues}' ${attributes} class="${inputClass}" />`
}
else {
lastValues = JSON.stringify(params.value).replace(/\'/g, '&quote;')
inputSource += `<select ${attributes} class="${inputClass}" last-values='${lastValues}'>`
// lastValues = JSON.stringify(params.value).replace(/\'/g, '&quote;')
inputSource += `<select ${attributes} class="${inputClass}">`

// if (!params.required) inputSource += '<option value=\'\'></option>'
var options = ''
Expand Down
12 changes: 7 additions & 5 deletions src/cli/cms/editor/handlebars/sourceAttr.js
Expand Up @@ -18,11 +18,13 @@ export default function sourceAttr(obj, params) {
values = [params.value]
}

Array.prototype.forEach.call(values, (pValue) => {
if (isSelected(pValue, displayName, str)) {
selected = 'selected'
}
})
if (params.multiple != 'multiple') {
Array.prototype.forEach.call(values, (pValue) => {
if (isSelected(pValue, displayName, str)) {
selected = 'selected'
}
})
}

return {
hiddenVal: (typeof obj == 'object') ? JSON.stringify(obj).replace(/\'/g, '&quote;') : obj,
Expand Down
2 changes: 1 addition & 1 deletion src/cli/cms/editor/handlebars/sourceOption.js
Expand Up @@ -2,5 +2,5 @@ import sourceAttr from './sourceAttr'

export default function sourceOption(val, params) {
var attr = sourceAttr(val, params)
return `<option value='${attr.hiddenVal}' ${attr.selected}>${attr.val}</option>`
return `<option value='${attr.hiddenVal}' data-value='${attr.hiddenVal}' ${attr.selected}>${attr.val}</option>`
}
2 changes: 1 addition & 1 deletion src/server/public/abecms/css/styles.css

Large diffs are not rendered by default.

42 changes: 39 additions & 3 deletions src/server/public/abecms/scripts/modules/EditorAutocomplete.js
Expand Up @@ -7,6 +7,7 @@ import Handlebars from 'handlebars'
import Nanoajax from 'nanoajax'
import on from 'on'
import qs from 'qs'
import dragula from 'dragula'

export default class EditorAutocomplete {
constructor() {
Expand All @@ -22,6 +23,7 @@ export default class EditorAutocomplete {
this._handleRemove = this._remove.bind(this)
this._handleDocumentClick = this._documentClick.bind(this)
this._handleSelectValue = this._selectValue.bind(this)
this._handleChangeSelect = this._changeSelect.bind(this)
this._handleRefresh = this._refresh.bind(this)

this._currentInput = null
Expand All @@ -30,10 +32,28 @@ export default class EditorAutocomplete {

this._visible = false

this._dragAutocomplete = document.querySelectorAll('.autocomplete-result-wrapper')
Array.prototype.forEach.call(this._dragAutocomplete, (drag) => {
var drake = dragula([drag])
drake.on('drag', (el, source) => {
el.classList.add('moving')
})
drake.on('dragend', (el) => {
el.classList.remove('moving')
var input = el.parentNode.parentNode.querySelector('input')
if(input == null) {
input = el.parentNode.parentNode.querySelector('select')
}
this._currentInput = input
this._saveData()
})
})

this.rebind()
}

rebind() {
this._selectsMultiple = [].slice.call(document.querySelectorAll('select[data-multiple="multiple"]'))
this._autocompletesRemove = [].slice.call(document.querySelectorAll('[data-autocomplete-remove=true]'))
this._autocompletes = [].slice.call(document.querySelectorAll('[data-autocomplete=true]'))
this._autocompletesRefresh = [].slice.call(document.querySelectorAll('[data-autocomplete-refresh=true]'))
Expand All @@ -60,6 +80,19 @@ export default class EditorAutocomplete {
autocomplete.removeEventListener('blur', this._handleBlur)
autocomplete.addEventListener('blur', this._handleBlur)
})

Array.prototype.forEach.call(this._selectsMultiple, (select) => {
select.removeEventListener('change', this._handleChangeSelect)
select.addEventListener('change', this._handleChangeSelect)
})
}

_changeSelect(e) {
var target = e.currentTarget
var option = target.querySelector('option:checked')
this._currentInput = target
this._addResult(option, target.getAttribute('data-display'), target.parentNode.querySelector('.autocomplete-result-wrapper'))
target.selectedIndex = 0
}

_saveData() {
Expand Down Expand Up @@ -149,6 +182,10 @@ export default class EditorAutocomplete {
}

_select(target) {
this._addResult(target, this._currentInput.getAttribute('data-display'), this._divWrapper.parentNode.querySelector('.autocomplete-result-wrapper'))
}

_addResult(target, display, resultWrapper) {
var json = target.getAttribute('data-value').replace(/&quote;/g, '\'')
if (json.indexOf('{') > -1) {
json = JSON.parse(json)
Expand All @@ -163,13 +200,12 @@ export default class EditorAutocomplete {
}

this._add(
this._currentInput.getAttribute('data-display'),
display,
target.getAttribute('data-value'),
json,
this._divWrapper.parentNode.querySelector('.autocomplete-result-wrapper')
resultWrapper
)
this._saveData()

}

_selectValue(e) {
Expand Down
38 changes: 38 additions & 0 deletions src/server/public/abecms/scripts/modules/EditorBlock.js
Expand Up @@ -10,6 +10,7 @@ import RichText from '../utils/rich-texarea'
import Json from './EditorJson'
import EditorUtils from './EditorUtils'
import on from 'on'
import dragula from 'dragula'

export default class EditorBlock {
constructor() {
Expand Down Expand Up @@ -40,10 +41,47 @@ export default class EditorBlock {

this.onNewBlock = on(this)
this.onRemoveBlock = on(this)
this.onMoveBlock = on(this)

this._dragBlock = document.querySelectorAll('.list-group[data-block]')
Array.prototype.forEach.call(this._dragBlock, (drag) => {
var drake = dragula([drag],
{
moves: function (el, source, handle, sibling) {
return handle.getAttribute("data-toggle") != null
}
})
drake.on('drag', (el, source) => {
el.classList.add('moving')
})
drake.on('dragend', (el) => {
el.classList.remove('moving')
this._changeIndexOfBlocksFromElement(el)
})
})

this._bindEvents()
}

_changeIndexOfBlocksFromElement(target) {
var blocks = target.parentNode.querySelectorAll('[data-block]')
var parentName = target.parentNode.getAttribute('data-block')
var i = 0
Array.prototype.forEach.call(blocks, (block) => {
var name = block.getAttribute('data-block')

block.setAttribute('data-block', `${parentName}${i}`)
block.querySelector('.label-count').innerHTML = i
var replaceHtml = block.innerHTML
replaceHtml = replaceHtml.replace(new RegExp(`${parentName}\\[.*?\\]`, 'g'), `${parentName}[${i}]`)
replaceHtml = replaceHtml.replace(new RegExp(name, 'g'), `${parentName}${i}`)
block.innerHTML = replaceHtml

i++
})
this.onMoveBlock._fire()
}

/**
* bind events
* @return {[type]} [description]
Expand Down
4 changes: 2 additions & 2 deletions src/server/public/abecms/scripts/modules/EditorInputs.js
Expand Up @@ -38,7 +38,7 @@ export default class EditorInputs {
}

rebind() {
this._reloads = [].slice.call(document.querySelectorAll('[reload=true]'))
this._reloads = [].slice.call(document.querySelectorAll('[reload=true]:not([data-multiple="multiple"])'))
this._inputs = [].slice.call(document.querySelectorAll('input.form-abe'))
this._inputs = this._inputs.concat([].slice.call(document.querySelectorAll('textarea.form-abe')))

Expand All @@ -52,7 +52,7 @@ export default class EditorInputs {
input.addEventListener('focus', this._handleInputFocus)
})

this._selects = [].slice.call(document.querySelectorAll('#abeForm select'))
this._selects = [].slice.call(document.querySelectorAll('#abeForm select:not([data-multiple="multiple"])'))
Array.prototype.forEach.call(this._selects, (select) => {
select.removeEventListener('change', this._handleChangeSelect)
select.addEventListener('change', this._handleChangeSelect)
Expand Down
19 changes: 5 additions & 14 deletions src/server/public/abecms/scripts/modules/EditorSave.js
Expand Up @@ -101,19 +101,7 @@ export default class EditorSave {
delete this._json.data[obj][index]
}
} else {
if (input.nodeName === 'SELECT' && maxlength != '1') {
var checked = input.querySelectorAll('option:checked')
value = []
Array.prototype.forEach.call(checked, (check) => {
if(check.value !== '') {
if(check.value.indexOf('{') > -1 || check.value.indexOf('[') > -1) {
value.push(JSON.parse(check.value))
} else {
value.push(check.value)
}
}
})
} else if (input.getAttribute('data-autocomplete') === 'true') {
if (input.getAttribute('data-autocomplete') === 'true' || input.getAttribute('data-multiple') === 'multiple') {
var results = input.parentNode.querySelectorAll('.autocomplete-result-wrapper .autocomplete-result')
value = []
Array.prototype.forEach.call(results, (result) => {
Expand Down Expand Up @@ -207,7 +195,10 @@ export default class EditorSave {
}

var autocomplete = input.getAttribute('data-autocomplete')
if(typeof autocomplete !== 'undefined' && autocomplete !== null && (autocomplete === 'true' || autocomplete === true)) {
var multiple = input.getAttribute('data-multiple')
if((typeof autocomplete !== 'undefined' && autocomplete !== null
&& (autocomplete === 'true' || autocomplete === true))
|| multiple != null && multiple == 'multiple') {
var countValue = input.parentNode.querySelectorAll('.autocomplete-result')
if (countValue.length <= 0) {
formGroup.classList.add('has-error')
Expand Down
8 changes: 8 additions & 0 deletions src/server/public/abecms/scripts/template-engine.js
Expand Up @@ -204,6 +204,14 @@ class Engine {
this._autocomplete.rebind()
})

this._blocks.onMoveBlock(() => {
this._files.rebind()
this._inputs.rebind()
this._autocomplete.rebind()
this._save.serializeForm()
EditorReload.instance.reload()
})

this._manager.remove((el) => {
this.table.ajax.reload()
})
Expand Down
7 changes: 6 additions & 1 deletion src/server/sass/modules/_autocomplete.scss
@@ -1,4 +1,5 @@
.autocomplete-result {
cursor: move;
background: $autocomplete-select-bg-color;
font-size: 12px;
color: $autocomplete-select-color;
Expand All @@ -7,6 +8,10 @@
border-radius: 3px;
margin: 1px 2px;

&.moving {
box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.4);
}

.glyphicon {
cursor: pointer;
padding: 3px;
Expand Down Expand Up @@ -45,7 +50,7 @@
position: absolute;
overflow-x: hidden;
background: $autocomplete-result-bg;
z-index: 999;
z-index: 9999999;
max-height: 200px;
overflow-y: auto;
font-size: 12px;
Expand Down
26 changes: 12 additions & 14 deletions src/server/sass/modules/_editor-blocks.scss
Expand Up @@ -3,20 +3,18 @@
}

.manager-wrapper .form-wrapper form,
.form-wrapper form {
.add-block,
.remove-block {
width: inherit;
border-radius: 0px;
}
.remove-block {
position: absolute;
z-index: 5656;
right: 10px;
top: 10px;
height: 15px;
width: 15px;
}
.add-block,
.remove-block {
width: inherit;
border-radius: 0px;
}
.remove-block {
position: absolute;
z-index: 5656;
right: 10px;
top: 10px;
height: 15px;
width: 15px;
}

.abeform-wrapper {
Expand Down
18 changes: 16 additions & 2 deletions src/server/sass/modules/_editor-menu.scss
Expand Up @@ -10,8 +10,22 @@
}
}

.form-wrapper
{
.list-block {
.btn-info {
color: #fff;
background-color: #f0f0f0;
border-bottom: 0;
text-align: right;
width: 100%;
color: #8E8E8E;
margin-bottom: 3px;
}
.btn-hidden{
display: none;
}
}

.form-wrapper {
.btns
{
.btn-info {
Expand Down

0 comments on commit 2b5b2ac

Please sign in to comment.