Skip to content

Commit 4175a10

Browse files
committed
Init
0 parents  commit 4175a10

6 files changed

+172
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

.prettierrc.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
semi: false,
3+
singleQuote: true
4+
}

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# A2lix JS - symfony-collection
2+
3+
Manage your Symfony collection simply with vanilla JS
4+
5+
See [Demo project](https://github.com/a2lix/Demo).

a2lix_sf_collection.js

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
'use strict'
2+
3+
const a2lix_lib = {}
4+
5+
a2lix_lib.formCollection = (() => {
6+
const init = (
7+
collectionsSelector = 'form div[data-prototype]',
8+
manageRemoveEntry = true
9+
) => {
10+
if (!('content' in document.createElement('template'))) {
11+
console.error('HTML template will not working...')
12+
return
13+
}
14+
15+
const collectionsElt = document.querySelectorAll(collectionsSelector)
16+
if (!collectionsElt.length) {
17+
return
18+
}
19+
20+
collectionsElt.forEach(collectionElt => {
21+
processCollectionElt(collectionElt, manageRemoveEntry)
22+
})
23+
}
24+
25+
const processCollectionElt = (collectionElt, manageRemoveEntry) => {
26+
collectionElt.setAttribute(
27+
'data-entry-index',
28+
collectionElt.children.length
29+
)
30+
31+
appendEntryAddLink(collectionElt)
32+
33+
if (manageRemoveEntry) {
34+
appendEntryRemoveLink(collectionElt)
35+
}
36+
37+
collectionElt.addEventListener('click', evt =>
38+
configureCollectionElt(evt, manageRemoveEntry)
39+
)
40+
}
41+
42+
const appendEntryAddLink = collectionElt => {
43+
// Allow custom label
44+
const entryLabel = collectionElt.getAttribute('data-entry-label') || ''
45+
46+
const entryAddLink = getButtonElt(
47+
`Add ${entryLabel}`,
48+
'add',
49+
'btn btn-primary btn-sm mt-2'
50+
)
51+
collectionElt.appendChild(entryAddLink)
52+
}
53+
54+
const appendEntryRemoveLink = collectionElt => {
55+
const entryRemoveLink = getButtonElt(
56+
'Remove',
57+
'remove',
58+
'btn btn-danger btn-sm'
59+
)
60+
;[...collectionElt.children]
61+
.filter(entryElt => !entryElt.hasAttribute('data-entry-action'))
62+
.forEach(entryElt => {
63+
entryElt.appendChild(entryRemoveLink.cloneNode(true))
64+
})
65+
}
66+
67+
const configureCollectionElt = (evt, manageRemoveEntry) => {
68+
if (!evt.target.hasAttribute('data-entry-action')) {
69+
return
70+
}
71+
72+
switch (evt.target.getAttribute('data-entry-action')) {
73+
case 'add':
74+
addEntry(evt.currentTarget, evt.target, manageRemoveEntry)
75+
break
76+
case 'remove':
77+
removeEntry(evt.currentTarget, evt.target)
78+
break
79+
}
80+
}
81+
82+
const addEntry = (collectionElt, entryAddButton, manageRemoveEntry) => {
83+
// Get & update entryIndex
84+
const entryIndex = collectionElt.getAttribute('data-entry-index')
85+
collectionElt.setAttribute('data-entry-index', +entryIndex + 1)
86+
87+
const entryPrototype = collectionElt.getAttribute('data-prototype'),
88+
templateContent = getTemplateContent(entryPrototype, entryIndex)
89+
90+
// Add remove button, if necessary, before insert to the DOM
91+
if (manageRemoveEntry) {
92+
const entryRemoveLink = getButtonElt(
93+
'Remove',
94+
'remove',
95+
'btn btn-danger btn-sm'
96+
)
97+
templateContent.firstChild.appendChild(entryRemoveLink)
98+
}
99+
100+
entryAddButton.parentElement.insertBefore(templateContent, entryAddButton)
101+
}
102+
103+
const removeEntry = (collectionElt, entryRemoveButton) => {
104+
entryRemoveButton.parentElement.remove()
105+
}
106+
107+
/**
108+
* HELPERS
109+
*/
110+
111+
const getButtonElt = (label, action, className = 'btn') => {
112+
const button = document.createElement('button')
113+
114+
button.type = 'button'
115+
button.textContent = label
116+
button.className = className
117+
button.dataset.entryAction = action
118+
119+
return button
120+
}
121+
122+
const getTemplateContent = (entryPrototype, entryIndex) => {
123+
const template = document.createElement('template')
124+
125+
const entryHtml = entryPrototype
126+
.replace(/__name__label__/g, `!New! ${entryIndex}`)
127+
.replace(/__name__/g, entryIndex)
128+
129+
template.innerHTML = entryHtml.trim()
130+
131+
return template.content
132+
}
133+
134+
return {
135+
init
136+
}
137+
})()

package.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "symfony-collection",
3+
"version": "0.1.0",
4+
"description": "Manage your Symfony collection simply with vanilla JS",
5+
"main": "a2lix_sf_collection.js",
6+
"repository": {
7+
"type": "git",
8+
"url": "https://github.com/a2lix/symfony-collection.git"
9+
},
10+
"keywords": ["symfony", "form", "collection", "a2lix", "vanillaJS"],
11+
"author": "David ALLIX <http://a2lix.fr>",
12+
"homepage": "https://github.com/a2lix/symfony-collection",
13+
"license": "MIT",
14+
"private": false,
15+
"devDependencies": {
16+
"prettier": "1.11.1"
17+
}
18+
}

yarn.lock

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
6+
version "1.11.1"
7+
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75"

0 commit comments

Comments
 (0)