Commit 149cb289 authored by Benjamin Kott's avatar Benjamin Kott Committed by Anja Leichsenring
Browse files

[TASK] Streamline formatting of html templates

The indentations in the HTML templates are out of control.
Even if we provide an EditorConfig, which should ensure
that the files are all uniformly indented. There seems to
have been an increasing aversion to TABS over time.

This has led to the fact that above all newly created templates
have always been indented with SPACES instead of TABS.
We now have a mix of TABS and SPACES in our project, partly
also in a single file.

To avoid this in the future, all existing templates were converted
to indentations with SPACES and the provided EditorConfig was
adapted. In order to really, really make sure that it doesn't get
out of hand, we also introduce a new linter, which ensures
that all HTML templates are properly indented.

Resolves: #88180
Releases: master
Change-Id: I86d23120bc68e3696f398b1ae76f1efc4804d501
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/60522


Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: Andreas Fernandez's avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Oliver Wand's avatarOliver Wand <wand@itaw.de>
Reviewed-by: Oliver Klee's avatarOliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Helmut Hummel's avatarHelmut Hummel <typo3@helhum.io>
Reviewed-by: Andreas Fernandez's avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: Anja Leichsenring's avatarAnja Leichsenring <aleichsenring@ab-softlab.de>
parent 389a8db7
......@@ -17,8 +17,8 @@ indent_size = 4
# HTML-Files
[*.html]
indent_style = tab
indent_size = 2
indent_style = space
indent_size = 4
# TMPL-Files
[*.tmpl]
......
......@@ -551,6 +551,16 @@ module.exports = function (grunt) {
}
]
}
},
lintspaces: {
html: {
src: [
'<%= paths.sysext %>*/Resources/Private/**/*.html'
],
options: {
editorconfig: '../.editorconfig'
}
}
}
});
......@@ -564,6 +574,7 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-exec');
grunt.loadNpmTasks('grunt-tslint');
grunt.loadNpmTasks('grunt-stylelint');
grunt.loadNpmTasks('grunt-lintspaces');
grunt.loadNpmTasks('grunt-contrib-imagemin');
/**
......@@ -583,8 +594,9 @@ module.exports = function (grunt) {
* this task does the following things:
* - tslint
* - stylelint
* - lintspaces
*/
grunt.registerTask('lint', ['tslint', 'stylelint']);
grunt.registerTask('lint', ['tslint', 'stylelint', 'lintspaces']);
/**
* grunt format
......
......@@ -45,6 +45,7 @@
"grunt-contrib-uglify": "3.3.0",
"grunt-contrib-watch": "~1.0.0",
"grunt-exec": "^2.0.0",
"grunt-lintspaces": "^0.8.5",
"grunt-npm-install": "^0.3.1",
"grunt-npmcopy": "^0.1.0",
"grunt-postcss": "^0.8.0",
......
......@@ -1327,6 +1327,11 @@ commander@^2.12.1:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==
commander@^2.19.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
commander@^2.9.0, commander@~2.14.1:
version "2.14.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
......@@ -1863,6 +1868,11 @@ dateformat@^2.0.0:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062"
integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=
dateformat@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
......@@ -2230,6 +2240,16 @@ editorconfig@^0.13.2:
semver "^5.1.0"
sigmund "^1.0.1"
editorconfig@^0.15.0:
version "0.15.3"
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5"
integrity sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==
dependencies:
commander "^2.19.0"
lru-cache "^4.1.5"
semver "^5.6.0"
sigmund "^1.0.1"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
......@@ -3365,6 +3385,14 @@ grunt-legacy-util@~1.1.1:
underscore.string "~3.3.4"
which "~1.3.0"
grunt-lintspaces@^0.8.5:
version "0.8.5"
resolved "https://registry.yarnpkg.com/grunt-lintspaces/-/grunt-lintspaces-0.8.5.tgz#b517230f83c62e7cacdf3df6e6b514a68eff414e"
integrity sha512-km8PlO5Jm5Re10UWVSwux+d/IATsVqXZKX/YdQvSX2LoN6DFeq6Fqo2s+lV2qgZoLhdtQ9xTr7xbDVLmEgGM/Q==
dependencies:
junitwriter "^0.4.1"
lintspaces "^0.6.2"
grunt-npm-install@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/grunt-npm-install/-/grunt-npm-install-0.3.1.tgz#916170595e370e2078e1dfb04224331db1de8437"
......@@ -4573,6 +4601,16 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
junitwriter@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/junitwriter/-/junitwriter-0.4.1.tgz#351cc0548c1ba7e15f040d392f671860bd05cbff"
integrity sha512-v4U/uX3xlpAFl09yNEZjkfF7bxUPOxXVJ7U/nDTLIXI+svpCK3/jxVoMEUdkvSPenxNR47pAAS4qs/BpVFulRA==
dependencies:
dateformat "^3.0.3"
merge "^1.2.1"
mkdirp "^0.5.1"
xmlbuilder "^10.1.1"
karma-chrome-launcher@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf"
......@@ -4813,6 +4851,15 @@ libnpx@^10.2.0:
y18n "^4.0.0"
yargs "^11.0.0"
lintspaces@^0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/lintspaces/-/lintspaces-0.6.3.tgz#44a7de459032bcfbcb8b92d049070be8b4c90f32"
integrity sha512-nUwq/jK+gUhpILtV9Ms2cuF16LB9a8nnecowSQD5LRNX3+h1Bl1zIvPZNQgJYeK9xxuoR+HuWnjagQsvyJbS4w==
dependencies:
deep-extend "^0.6.0"
editorconfig "^0.15.0"
rc "^1.2.8"
livereload-js@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a"
......@@ -5106,6 +5153,14 @@ lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3:
pseudomap "^1.0.2"
yallist "^2.1.2"
lru-cache@^4.1.5:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
dependencies:
pseudomap "^1.0.2"
yallist "^2.1.2"
make-dir@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b"
......@@ -5219,6 +5274,11 @@ merge-stream@^1.0.0:
dependencies:
readable-stream "^2.0.1"
merge@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145"
integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==
micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
......@@ -6856,7 +6916,7 @@ raw-body@~2.1.5:
iconv-lite "0.4.13"
unpipe "1.0.0"
rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
......@@ -7484,6 +7544,11 @@ semver@^5.0.3, semver@^5.4.1, semver@^5.5.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==
semver@^5.6.0:
version "5.7.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
......@@ -9065,6 +9130,11 @@ xmlbuilder@8.2.2:
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=
xmlbuilder@^10.1.1:
version "10.1.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-10.1.1.tgz#8cae6688cc9b38d850b7c8d3c0a4161dcaf475b0"
integrity sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
......
<p>
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:cms_description',
arguments: '{
0: currentVersion,
1: "&copy; {copyrightYear}",
2: "Kasper Sk&aring;rh&oslash;j"
}') -> f:format.raw()}
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:cms_description',
arguments: '{
0: currentVersion,
1: "&copy; {copyrightYear}",
2: "Kasper Sk&aring;rh&oslash;j"
}') -> f:format.raw()}
</p>
<div class="panel panel-default">
<div class="panel-body panel-body-highlightlinks">
<h2 class="h4">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:coredevs" />
</h2>
<p>
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:coredevs_detail') -> f:format.raw()}
</p>
</div>
<div class="panel-body panel-body-highlightlinks">
<h2 class="h4">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:coredevs" />
</h2>
<p>
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:coredevs_detail') -> f:format.raw()}
</p>
</div>
</div>
<div class="panel panel-default">
<div class="panel-body panel-body-highlightlinks">
<h2 class="h4">
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:community_credits') -> f:format.raw()}
</h2>
<p>
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:information_detail') -> f:format.raw()}
</p>
</div>
<div class="panel-body panel-body-highlightlinks">
<h2 class="h4">
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:community_credits') -> f:format.raw()}
</h2>
<p>
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:information_detail') -> f:format.raw()}
</p>
</div>
</div>
<div class="panel panel-default">
<div class="panel-body panel-body-highlightlinks">
<h2 class="h4">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_header" />
</h2>
<p>
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_message') -> f:format.raw()}
</p>
<a href="{donationUrl}" class="btn btn-default" title="{f:translate(key:'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_button')}" target="_blank">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_button" />
</a>
</div>
<div class="panel-body panel-body-highlightlinks">
<h2 class="h4">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_header" />
</h2>
<p>
{f:translate(key: 'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_message') -> f:format.raw()}
</p>
<a href="{donationUrl}" class="btn btn-default" title="{f:translate(key:'LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_button')}" target="_blank">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:donation_button" />
</a>
</div>
</div>
<f:if condition="{loadedExtensions}">
<div class="panel panel-default">
<div class="panel-body panel-body-highlightlinks">
<h2 class="h3">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension_authors" />
</h2>
<p>
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension_list_info" />
</p>
</div>
<table class="table panel-table">
<thead>
<tr>
<th width="60%"><f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension" /></th>
<th><f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension_author" /></th>
</tr>
</thead>
<tbody>
<f:for each="{loadedExtensions}" as="loadedExtension">
<tr>
<td>
{loadedExtension.title} ({loadedExtension.key})
</td>
<td>
<f:for each="{loadedExtension.authors}" as="extensionAuthor" iteration="i">
<f:if condition="{extensionAuthor.email}">
<f:then>
<f:link.email
email="{extensionAuthor.email}?subject={f:format.urlencode(value:'Thanks for your {loadedExtension.title} extension')}"
>
{extensionAuthor.name}
</f:link.email>
</f:then>
<f:else>
{extensionAuthor.name}
</f:else>
</f:if>
<f:if condition="{i.isLast} == false">
<br>
</f:if>
</f:for>
</td>
</tr>
</f:for>
</tbody>
</table>
</div>
<div class="panel panel-default">
<div class="panel-body panel-body-highlightlinks">
<h2 class="h3">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension_authors" />
</h2>
<p>
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension_list_info" />
</p>
</div>
<table class="table panel-table">
<thead>
<tr>
<th width="60%"><f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension" /></th>
<th><f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:extension_author" /></th>
</tr>
</thead>
<tbody>
<f:for each="{loadedExtensions}" as="loadedExtension">
<tr>
<td>
{loadedExtension.title} ({loadedExtension.key})
</td>
<td>
<f:for each="{loadedExtension.authors}" as="extensionAuthor" iteration="i">
<f:if condition="{extensionAuthor.email}">
<f:then>
<f:link.email
email="{extensionAuthor.email}?subject={f:format.urlencode(value:'Thanks for your {loadedExtension.title} extension')}"
>
{extensionAuthor.name}
</f:link.email>
</f:then>
<f:else>
{extensionAuthor.name}
</f:else>
</f:if>
<f:if condition="{i.isLast} == false">
<br>
</f:if>
</f:for>
</td>
</tr>
</f:for>
</tbody>
</table>
</div>
</f:if>
<div class="panel panel-default">
<div class="panel-body panel-body-highlightlinks">
<h2 class="h3">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:external_libraries" />
</h2>
<p>
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:external_thanks" />
</p>
</div>
<table class="table panel-table">
<tr>
<td>Composer</td>
<td><a href="https://getcomposer.org" target="_blank" rel="noopener noreferrer">getcomposer.org</a></td>
</tr>
<tr>
<td>jQuery</td>
<td><a href="https://jquery.com" target="_blank" rel="noopener noreferrer">jquery.com</a></td>
</tr>
<tr>
<td>Twitter Bootstrap</td>
<td><a href="http://getbootstrap.com" target="_blank" rel="noopener noreferrer">getbootstrap.com</a></td>
</tr>
<tr>
<td>Swift Mailer</td>
<td><a href="http://swiftmailer.org" target="_blank" rel="noopener noreferrer">swiftmailer.org</a></td>
</tr>
<tr>
<td>Doctrine Project (DBAL Component and Instantiator)</td>
<td><a href="http://www.doctrine-project.org/projects/dbal.html" target="_blank" rel="noopener noreferrer">doctrine-project.org</a></td>
</tr>
<tr>
<td>Symfony Framework (YAML, Console and Finder Component)</td>
<td><a href="https://symfony.com" target="_blank" rel="noopener noreferrer">symfony.com</a></td>
</tr>
<tr>
<td>Guzzle PHP</td>
<td><a href="http://guzzlephp.org" target="_blank" rel="noopener noreferrer">guzzlephp.org</a></td>
</tr>
<tr>
<td>d3 Data Driven Documents</td>
<td><a href="https://d3js.org" target="_blank" rel="noopener noreferrer">d3js.org</a></td>
</tr>
<tr>
<td>CKEditor</td>
<td><a href="http://ckeditor.com" target="_blank" rel="noopener noreferrer">ckeditor.com</a></td>
</tr>
<tr>
<td>RequireJS</td>
<td><a href="http://requirejs.org" target="_blank" rel="noopener noreferrer">requirejs.org</a></td>
</tr>
<tr>
<td>moment.js</td>
<td><a href="https://momentjs.com" target="_blank" rel="noopener noreferrer">momentjs.com</a></td>
</tr>
<tr>
<td>NProgress</td>
<td><a href="http://ricostacruz.com/nprogress/" target="_blank" rel="noopener noreferrer">ricostacruz.com</a></td>
</tr>
<tr>
<td>jQuery UI</td>
<td><a href="https://jqueryui.com" target="_blank" rel="noopener noreferrer">jqueryui.com</a></td>
</tr>
<tr>
<td>Twitter Bootstrap Plugin: DateTimePicker</td>
<td><a href="https://eonasdan.github.io/bootstrap-datetimepicker/" target="_blank" rel="noopener noreferrer">eonasdan.github.io</a></td>
</tr>
<tr>
<td>Twitter Bootstrap Plugin: Slider</td>
<td><a href="http://seiyria.com/bootstrap-slider/" target="_blank" rel="noopener noreferrer">seiyria.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: Ajax AutoComplete</td>
<td><a href="https://www.devbridge.com/sourcery/components/jquery-autocomplete/" target="_blank" rel="noopener noreferrer">devbridge.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: Autosize</td>
<td><a href="http://www.jacklmoore.com/autosize/" target="_blank" rel="noopener noreferrer">jacklmoore.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: Cropper</td>
<td><a href="https://fengyuanchen.github.io/cropper/" target="_blank" rel="noopener noreferrer">fengyuanchen.github.io</a></td>
</tr>
<tr>
<td>jQuery Plugin: DataTables</td>
<td><a href="https://datatables.net" target="_blank" rel="noopener noreferrer">datatables.net</a></td>
</tr>
<tr>
<td>jQuery Plugin: ImagesLoaded</td>
<td><a href="http://imagesloaded.desandro.com" target="_blank" rel="noopener noreferrer">imagesloaded.desandro.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: MiniColors</td>
<td><a href="http://labs.abeautifulsite.net/jquery-minicolors/" target="_blank" rel="noopener noreferrer">labs.abeautifulsite.net</a></td>
</tr>
<tr>
<td>jQuery Plugin: Tab Override</td>
<td><a href="http://wjbryant.github.io/taboverride/" target="_blank" rel="noopener noreferrer">wjbryant.github.io</a></td>
</tr>
<tr>
<td>Neos (Form component)</td>
<td><a href="https://www.neos.io" target="_blank" rel="noopener noreferrer">neos.io</a></td>
</tr>
<tr>
<td>FineDiff</td>
<td><a href="https://github.com/cogpowered/FineDiff" target="_blank" rel="noopener noreferrer">github.com</a></td>
</tr>
<tr>
<td>IDNA Convert</td>
<td><a href="https://idnaconv.net" target="_blank" rel="noopener noreferrer">idnaconv.net</a></td>
</tr>
<tr>
<td>CodeMirror</td>
<td><a href="http://codemirror.net" target="_blank" rel="noopener noreferrer">codemirror.net</a></td>
</tr>
</table>
<div class="panel-body panel-body-highlightlinks">
<h2 class="h3">
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:external_libraries" />
</h2>
<p>
<f:translate key="LLL:EXT:about/Resources/Private/Language/Modules/about.xlf:external_thanks" />
</p>
</div>
<table class="table panel-table">
<tr>
<td>Composer</td>
<td><a href="https://getcomposer.org" target="_blank" rel="noopener noreferrer">getcomposer.org</a></td>
</tr>
<tr>
<td>jQuery</td>
<td><a href="https://jquery.com" target="_blank" rel="noopener noreferrer">jquery.com</a></td>
</tr>
<tr>
<td>Twitter Bootstrap</td>
<td><a href="http://getbootstrap.com" target="_blank" rel="noopener noreferrer">getbootstrap.com</a></td>
</tr>
<tr>
<td>Swift Mailer</td>
<td><a href="http://swiftmailer.org" target="_blank" rel="noopener noreferrer">swiftmailer.org</a></td>
</tr>
<tr>
<td>Doctrine Project (DBAL Component and Instantiator)</td>
<td><a href="http://www.doctrine-project.org/projects/dbal.html" target="_blank" rel="noopener noreferrer">doctrine-project.org</a></td>
</tr>
<tr>
<td>Symfony Framework (YAML, Console and Finder Component)</td>
<td><a href="https://symfony.com" target="_blank" rel="noopener noreferrer">symfony.com</a></td>
</tr>
<tr>
<td>Guzzle PHP</td>
<td><a href="http://guzzlephp.org" target="_blank" rel="noopener noreferrer">guzzlephp.org</a></td>
</tr>
<tr>
<td>d3 Data Driven Documents</td>
<td><a href="https://d3js.org" target="_blank" rel="noopener noreferrer">d3js.org</a></td>
</tr>
<tr>
<td>CKEditor</td>
<td><a href="http://ckeditor.com" target="_blank" rel="noopener noreferrer">ckeditor.com</a></td>
</tr>
<tr>
<td>RequireJS</td>
<td><a href="http://requirejs.org" target="_blank" rel="noopener noreferrer">requirejs.org</a></td>
</tr>
<tr>
<td>moment.js</td>
<td><a href="https://momentjs.com" target="_blank" rel="noopener noreferrer">momentjs.com</a></td>
</tr>
<tr>
<td>NProgress</td>
<td><a href="http://ricostacruz.com/nprogress/" target="_blank" rel="noopener noreferrer">ricostacruz.com</a></td>
</tr>
<tr>
<td>jQuery UI</td>
<td><a href="https://jqueryui.com" target="_blank" rel="noopener noreferrer">jqueryui.com</a></td>
</tr>
<tr>
<td>Twitter Bootstrap Plugin: DateTimePicker</td>
<td><a href="https://eonasdan.github.io/bootstrap-datetimepicker/" target="_blank" rel="noopener noreferrer">eonasdan.github.io</a></td>
</tr>
<tr>
<td>Twitter Bootstrap Plugin: Slider</td>
<td><a href="http://seiyria.com/bootstrap-slider/" target="_blank" rel="noopener noreferrer">seiyria.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: Ajax AutoComplete</td>
<td><a href="https://www.devbridge.com/sourcery/components/jquery-autocomplete/" target="_blank" rel="noopener noreferrer">devbridge.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: Autosize</td>
<td><a href="http://www.jacklmoore.com/autosize/" target="_blank" rel="noopener noreferrer">jacklmoore.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: Cropper</td>
<td><a href="https://fengyuanchen.github.io/cropper/" target="_blank" rel="noopener noreferrer">fengyuanchen.github.io</a></td>
</tr>
<tr>
<td>jQuery Plugin: DataTables</td>
<td><a href="https://datatables.net" target="_blank" rel="noopener noreferrer">datatables.net</a></td>
</tr>
<tr>
<td>jQuery Plugin: ImagesLoaded</td>
<td><a href="http://imagesloaded.desandro.com" target="_blank" rel="noopener noreferrer">imagesloaded.desandro.com</a></td>
</tr>
<tr>
<td>jQuery Plugin: MiniColors</td>
<td><a href="http://labs.abeautifulsite.net/jquery-minicolors/" target="_blank" rel="noopener noreferrer">labs.abeautifulsite.net</a></td>
</tr>
<tr>
<td>jQuery Plugin: Tab Override</td>
<td><a href="http://wjbryant.github.io/taboverride/" target="_blank" rel="noopener noreferrer">wjbryant.github.io</a></td>
</tr>
<tr>
<td>Neos (Form component)</td>
<td><a href="https://www.neos.io" target="_blank" rel="noopener noreferrer">neos.io</a></td>
</tr>
<tr>
<td>FineDiff</td>
<td><a href="https://github.com/cogpowered/FineDiff" target="_blank" rel="noopener noreferrer">github.com</a></td>