-
-
Notifications
You must be signed in to change notification settings - Fork 190
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cb51ce9
commit 16e2d20
Showing
1 changed file
with
174 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
import PluginBase from '../abstracts/PluginBase'; | ||
|
||
/** | ||
* Trigger handler for HTML elements. | ||
* | ||
* This is a re-imagining of the Input.Trigger functionality in the original Winter CMS framework, | ||
* initialised through the `data-trigger` attributes. | ||
* | ||
* In addition to remaining backwards-compatible with the original Input.Trigger functionality, this | ||
* handler adds additional conditions and configuration for more flexible trigger usage. | ||
* | ||
* @see https://wintercms.com/docs/v1.2/ui/script/input-trigger | ||
* | ||
* @copyright 2024 Winter. | ||
* @author Ben Thomson <git@alfreido.com> | ||
*/ | ||
export default class Trigger extends PluginBase { | ||
/** | ||
* Constructor. | ||
* | ||
* @param {HTMLElement} element | ||
*/ | ||
construct(element) { | ||
/** | ||
* The element this instance is attached to. | ||
*/ | ||
this.element = element; | ||
/** | ||
* The triggers for this element. | ||
*/ | ||
this.triggers = new Map(); | ||
|
||
this.parseTriggers(); | ||
|
||
// this.config = this.snowboard.dataConfig(this, element); | ||
|
||
// this.trigger = this.config.get('trigger'); | ||
// if (!this.trigger) { | ||
// this.snowboard.error('Trigger selector is not specified.', element); | ||
// return; | ||
// } | ||
|
||
// this.condition = this.config.get('triggerWhen') | ||
// ?? this.config.get('triggerCondition'); | ||
|
||
// if (!this.condition || !this.isValidCondition(this.condition)) { | ||
// this.snowboard.error('Trigger condition is not specified or not valid.', element); | ||
// return; | ||
// } | ||
|
||
// this.action = this.config.get('triggerAction'); | ||
// if (!this.action || !this.isValidAction(this.condition)) { | ||
// this.snowboard.error('Trigger action is not specified or not valid.', element); | ||
// return; | ||
// } | ||
|
||
// console.log(this.parseCommand(this.condition)); | ||
// console.log(this.parseCommand(this.action)); | ||
} | ||
|
||
parseTriggers() { | ||
const { dataset } = this.element; | ||
const triggers = new Map(); | ||
|
||
Object.keys(dataset).forEach((key) => { | ||
if (!key.startsWith('trigger')) { | ||
return; | ||
} | ||
|
||
let trigger = key.replace('trigger', '').toLowerCase(); | ||
|
||
|
||
|
||
if (trigger.endsWith('Parent')) { | ||
trigger = trigger.replace('Parent', ''); | ||
if (!triggers.has(trigger)) { | ||
triggers.set(trigger, new Map()); | ||
triggers.get(trigger).set('parent', dataset[key]); | ||
} | ||
return; | ||
} | ||
if (trigger.endsWith('When')) { | ||
trigger = trigger.replace('When', ''); | ||
if (!triggers.has(trigger)) { | ||
triggers.set(trigger, new Map()); | ||
triggers.get(trigger).set('parent', dataset[key]); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Determines if the provided trigger condition is valid. | ||
* | ||
* @param {string} condition | ||
* @returns | ||
*/ | ||
isValidCondition(condition) { | ||
return [ | ||
'checked', | ||
'unchecked', | ||
'empty', | ||
'value', | ||
'oneOf', | ||
'allOf', | ||
'focus', | ||
'blur', | ||
].includes(this.parseCommand(condition).name.toLowerCase()); | ||
} | ||
|
||
parseCommand(command) { | ||
// Support old-format value command (value[foo,bar]) | ||
if (command.startsWith('value')) { | ||
const match = command.match(/[^[\]]+(?=])/g); | ||
const values = []; | ||
|
||
// Split values with commas | ||
match.forEach((value) => { | ||
if (!value.includes(',')) { | ||
values.push(value.replace(/^['"]|['"]$/g, '').trim()); | ||
return; | ||
} | ||
|
||
const splitValues = value.replace(/("[^"]*")|('[^']*')/g, (quoted) => quoted.replace(/,/g, '|||')) | ||
.split(',') | ||
.map((splitValue) => splitValue.replace(/\|\|\|/g, ',').replace(/^['"]|['"]$/g, '').trim()); | ||
|
||
values.push(...splitValues); | ||
}); | ||
|
||
return { | ||
name: 'value', | ||
parameters: values, | ||
}; | ||
} | ||
|
||
if (!command.includes(':')) { | ||
return { | ||
name: command, | ||
parameters: [], | ||
}; | ||
} | ||
|
||
const [name, parameters] = command.split(':', 2); | ||
|
||
if (!parameters.includes(',')) { | ||
return { | ||
name, | ||
parameters: [parameters], | ||
}; | ||
} | ||
|
||
const splitValues = parameters.replace(/("[^"]*")|('[^']*')/g, (quoted) => quoted.replace(/,/g, '|||')) | ||
.split(',') | ||
.map((splitValue) => splitValue.replace(/\|\|\|/g, ',').replace(/^['"]|['"]$/g, '').trim()); | ||
|
||
return { | ||
name, | ||
parameters: splitValues, | ||
}; | ||
} | ||
|
||
isValidAction(action) { | ||
return [ | ||
'show', | ||
'hide', | ||
'enable', | ||
'disable', | ||
'value', | ||
'empty', | ||
'attr', | ||
].includes(this.parseCommand(action).name.toLowerCase()); | ||
} | ||
} |