diff --git a/lib/filters/add_class/definition.js b/lib/filters/add_class/definition.js new file mode 100644 index 0000000..1977317 --- /dev/null +++ b/lib/filters/add_class/definition.js @@ -0,0 +1,40 @@ +/** + * @file The safe_join filter + * + * Docs for TwigExtension::safeJoin (Drupal 9.3.x): + * + * ``` + * new TwigFilter('safe_join', + * [$this, 'safeJoin'], + * [ + * 'needs_environment' => TRUE, + * 'is_safe' => ['html'] + * ] + * ) + * ``` + * + * ``` + * Joins several strings together safely. + * + * @param \Twig\Environment $env + * A Twig Environment instance. + * @param mixed[]|\Traversable|null $value + * The pieces to join. + * @param string $glue + * The delimiter with which to join the string. Defaults to an empty string. + * This value is expected to be safe for output and user provided data + * should never be used as a glue. + * + * @return string + * The strings joined together. + * ``` + */ + +export const name = 'add_class'; + +export const options = { + needs_environment: true, + is_safe: ['html'], +}; + +export const acceptedArguments = [{ name: 'className', defaultValue: '' }]; diff --git a/lib/filters/add_class/twing.js b/lib/filters/add_class/twing.js new file mode 100644 index 0000000..dda66ea --- /dev/null +++ b/lib/filters/add_class/twing.js @@ -0,0 +1,21 @@ +import { newTwingFilter } from '../../helpers/twing.js'; +import { name, options, acceptedArguments } from './definition.js'; + +function surround(value, className) { + if (Array.isArray(className)) { + className = className.join(' '); + } + return `
${value}
`; +} +export function callable(value, clasName) { + if (typeof value === 'object') { + const output = []; + Object.values(value).forEach((value) => { + output.push(surround(value, clasName)); + }); + return output.join(' '); + } + return surround(value, clasName); +} + +export default newTwingFilter(name, callable, options, acceptedArguments); diff --git a/lib/filters/set_attribute/definition.js b/lib/filters/set_attribute/definition.js new file mode 100644 index 0000000..537111e --- /dev/null +++ b/lib/filters/set_attribute/definition.js @@ -0,0 +1,11 @@ +export const name = 'set_attribute'; + +export const options = { + needs_environment: true, + is_safe: ['html'], +}; + +export const acceptedArguments = [ + { name: 'attributeName', defaultValue: '' }, + { name: 'attributeValue', defaultValue: '' }, +]; diff --git a/lib/filters/set_attribute/twing.js b/lib/filters/set_attribute/twing.js new file mode 100644 index 0000000..68365ae --- /dev/null +++ b/lib/filters/set_attribute/twing.js @@ -0,0 +1,18 @@ +import { newTwingFilter } from '../../helpers/twing.js'; +import { name, options, acceptedArguments } from './definition.js'; + +function surround(value, attributeName, attributeValue) { + return `
${value}
`; +} +export function callable(value, attributeName, attributeValue) { + if (typeof value === 'object') { + const output = []; + Object.values(value).forEach((value) => { + output.push(surround(value, attributeName, attributeValue)); + }); + return output.join(' '); + } + return surround(value, attributeName, attributeValue); +} + +export default newTwingFilter(name, callable, options, acceptedArguments); diff --git a/lib/filters/twing.js b/lib/filters/twing.js index 40eb942..10ea473 100644 --- a/lib/filters/twing.js +++ b/lib/filters/twing.js @@ -4,6 +4,8 @@ import cleanIdFilter from './clean_id/twing.js'; import drupalEscapeFilter from './drupal_escape/twing.js'; import formatDateFilter from './format_date/twing.js'; import placeholderFilter from './placeholder/twing.js'; +import addClassFilter from './add_class/twing.js'; +import setAttributeFilter from './set_attribute/twing.js'; import renderFilter from './render/twing.js'; import safeJoinFilter from './safe_join/twing.js'; import { @@ -18,7 +20,9 @@ import withoutFilter from './without/twing.js'; const filters = [ cleanClassFilter, + setAttributeFilter, cleanIdFilter, + addClassFilter, drupalEscapeFilter, formatDateFilter, placeholderFilter, diff --git a/tests/Twing/filters/add_class.js b/tests/Twing/filters/add_class.js new file mode 100644 index 0000000..adf2bf2 --- /dev/null +++ b/tests/Twing/filters/add_class.js @@ -0,0 +1,31 @@ +import test from 'ava'; +import { setupTwingBefore, renderTemplateMacro } from '#twing-fixture'; + +test.before(setupTwingBefore); + +const template = `{{ content|add_class("sample-class") }}`; + +test('Add class to simple content', renderTemplateMacro, { + template, + data: { + content: 'Inner content', + }, + expected: '
Inner content
', +}); + +test('Add class to content array', renderTemplateMacro, { + template, + data: { + content: ['Inner content', 'Inner content2'], + }, + expected: + '
Inner content
Inner content2
', +}); + +test('Add array class to simple content', renderTemplateMacro, { + template: `{{ content|add_class(["sample-class" , "sample-class2"]) }}`, + data: { + content: 'Inner content', + }, + expected: '
Inner content
', +}); diff --git a/tests/Twing/filters/set_attribute.js b/tests/Twing/filters/set_attribute.js new file mode 100644 index 0000000..7f6bd18 --- /dev/null +++ b/tests/Twing/filters/set_attribute.js @@ -0,0 +1,14 @@ +import test from 'ava'; +import { setupTwingBefore, renderTemplateMacro } from '#twing-fixture'; + +test.before(setupTwingBefore); + +const template = `{{ content|set_attribute('role', "xxx") }}`; + +test('set attribute to simple content', renderTemplateMacro, { + template, + data: { + content: 'Inner content', + }, + expected: '
Inner content
', +});