Created
March 18, 2024 03:29
-
-
Save LarryBarker/50e95d1740a929185d90f8f906eecf81 to your computer and use it in GitHub Desktop.
Input Trigger API - This API allows you to change an elements' visibility or status (enabled/disabled) based on another elements' status(es)
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
/* | |
* Input Trigger API | |
* This API allows to change elements' visibility or status (enabled/disabled) basing on other elements' statuses. | |
* Example: enable a button if any checkbox inside another element is checked. | |
* - Checked Condition: | |
<input type="checkbox" id="triggerChk1" /> | |
<button class="btn disabled" | |
data-trigger-action="enable" | |
data-trigger="#triggerChk1" | |
data-trigger-condition="checked"> | |
Check the checkbox | |
</button> | |
* | |
* - Value Condition: | |
* <p> | |
<input | |
type="text" | |
id="triggerTxt1" | |
value="" | |
onkeyup="$(this).trigger('change')" | |
placeholder="Enter 'foo' or 'bar' here" | |
class="form-control" /> | |
</p> | |
<div | |
class="callout callout-success" | |
data-trigger-action="show" | |
data-trigger="#triggerTxt1" | |
data-trigger-condition="value[foo][bar]"> | |
<div class="content"> | |
Passphrase is valid! | |
</div> | |
</div> | |
* | |
* Supported data attributes: | |
* - data-trigger-action, values: show, hide, enable, disable, empty | |
* - data-trigger: a CSS selector for elements that trigger the action (checkboxes) | |
* - data-trigger-condition, values: | |
* - checked: determines the condition the elements specified in the data-trigger should satisfy in order the condition to be considered as "true". | |
* - unchecked: inverse condition of "checked". | |
* - value[somevalue]: determines if the value of data-trigger equals the specified value (somevalue) the condition is considered "true". | |
* - data-trigger-closest-parent: optional, specifies a CSS selector for a closest common parent for the source and destination input elements. | |
* | |
* Example code: | |
* <input type="button" class="btn disabled" | |
data-trigger-action="enable" | |
data-trigger="#cblist input[type=checkbox]" | |
data-trigger-condition="checked" ... > | |
* | |
* Multiple actions are supported: | |
* data-trigger-action="hide|empty" | |
* | |
* Multiple value conditions are supported: | |
* data-trigger-condition="value[foo][bar]" | |
* | |
* Supported events: | |
* - fn.triggerOn.update - triggers the update. Trigger this event on the element the plugin is bound to, forcing it to check the condition and update itself. This is useful when the page ontent is updated via AJAX. | |
* - fn.triggerOn.afterUpdate - triggered after the element is updated | |
* | |
* JavaScript API: | |
* $('#mybutton').triggerOn({ | |
triggerCondition: 'checked', | |
trigger: '#cblist input[type=checkbox]', | |
triggerAction: 'enable' | |
}) | |
* | |
*/ | |
(function() { "use strict"; | |
var oldOnload = onload ? onload : function () {}; | |
onload = function () { | |
oldOnload(); | |
var TriggerOn = function (element, options) { | |
var $el = this.$el = $(element); | |
this.options = options || {}; | |
if (this.options.triggerCondition === false) | |
throw new Error('Trigger condition is not specified.') | |
if (this.options.trigger === false) | |
throw new Error('Trigger selector is not specified.') | |
if (this.options.triggerAction === false) | |
throw new Error('Trigger action is not specified.') | |
this.triggerCondition = this.options.triggerCondition | |
if (this.options.triggerCondition.indexOf('value') == 0) { | |
var match = this.options.triggerCondition.match(/[^[\]]+(?=])/g) | |
this.triggerCondition = 'value' | |
this.triggerConditionValue = (match) ? match : [""] | |
} | |
this.triggerParent = undefined | |
if (this.options.triggerClosestParent !== undefined) { | |
var closestParentElements = this.options.triggerClosestParent.split(',') | |
for (var i = 0; i < closestParentElements.length; i++) { | |
var $triggerElement = $el.closest(closestParentElements[i]) | |
if ($triggerElement.length) { | |
this.triggerParent = $triggerElement | |
break | |
} | |
} | |
} | |
if ( | |
this.triggerCondition == 'checked' || | |
this.triggerCondition == 'unchecked' || | |
this.triggerCondition == 'value' | |
) { | |
$(document).on('change', this.options.trigger, $.proxy(this.onConditionChanged, this)) | |
} | |
var self = this | |
$el.on('fn.triggerOn.update', function(e){ | |
e.stopPropagation() | |
self.onConditionChanged() | |
}) | |
// Make any triggered fields optional to begin with | |
// If they are required, the trigger action will re-apply the attribute | |
self.normalizeInputs() | |
self.onConditionChanged() | |
} | |
TriggerOn.prototype.normalizeInputs = function() { | |
this.$el | |
.find('input, select') | |
.prop('required', false) | |
} | |
TriggerOn.prototype.onConditionChanged = function() { | |
if (this.triggerCondition == 'checked') { | |
this.updateTarget(!!$(this.options.trigger + ':checked', this.triggerParent).length) | |
} | |
else if (this.triggerCondition == 'unchecked') { | |
this.updateTarget(!$(this.options.trigger + ':checked', this.triggerParent).length) | |
} | |
else if (this.triggerCondition == 'value') { | |
var trigger, triggered = false | |
trigger = $(this.options.trigger, this.triggerParent) | |
.not('input[type=checkbox], input[type=radio], input[type=button], input[type=submit]') | |
if (!trigger.length) { | |
trigger = $(this.options.trigger, this.triggerParent) | |
.not(':not(input[type=checkbox]:checked, input[type=radio]:checked)') | |
} | |
var self = this | |
trigger.each(function() { | |
var triggerValue = $(this).val(); | |
$.each($.isArray(triggerValue) ? triggerValue : [triggerValue], function(key, val) { | |
triggered = $.inArray(val, self.triggerConditionValue) != -1 | |
return !triggered | |
}) | |
return !triggered | |
}) | |
this.updateTarget(triggered) | |
} | |
} | |
TriggerOn.prototype.updateTarget = function(status) { | |
var self = this, | |
actions = this.options.triggerAction.split('|') | |
$.each(actions, function(index, action) { | |
self.updateTargetAction(action, status) | |
}) | |
$(window).trigger('resize') | |
this.$el.trigger('fn.triggerOn.afterUpdate', status) | |
} | |
TriggerOn.prototype.updateTargetAction = function(action, status) { | |
if (action == 'show') { | |
this.$el | |
.toggleClass('hide', !status) | |
.trigger('hide.fn.triggerapi', [!status]) | |
} | |
else if (action == 'hide') { | |
this.$el | |
.toggleClass('hide', status) | |
.trigger('hide.fn.triggerapi', [status]) | |
} | |
else if (action == 'enable') { | |
this.$el | |
.prop('disabled', !status) | |
.toggleClass('control-disabled', !status) | |
.trigger('disable.fn.triggerapi', [!status]) | |
} | |
else if (action == 'disable') { | |
this.$el | |
.prop('disabled', status) | |
.toggleClass('control-disabled', status) | |
.trigger('disable.oc.triggerapi', [status]) | |
} | |
else if (action == 'empty' && status) { | |
this.$el | |
.not('input[type=checkbox], input[type=radio], input[type=button], input[type=submit]') | |
.val('') | |
this.$el | |
.not(':not(input[type=checkbox], input[type=radio])') | |
.prop('checked', false) | |
this.$el | |
.trigger('empty.fn.triggerapi') | |
.trigger('change') | |
} | |
if (action == 'require') { | |
this.$el | |
.find('input, select') | |
.prop('required', status) | |
} | |
if (action == 'show' || action == 'hide') { | |
this.fixButtonClasses() | |
} | |
} | |
TriggerOn.prototype.fixButtonClasses = function() { | |
var group = this.$el.closest('.btn-group') | |
if (group.length > 0 && this.$el.is(':last-child')) | |
this.$el.prev().toggleClass('last', this.$el.hasClass('hide')) | |
} | |
TriggerOn.DEFAULTS = { | |
triggerAction: false, | |
triggerCondition: false, | |
triggerClosestParent: undefined, | |
trigger: false | |
} | |
// TRIGGERON PLUGIN DEFINITION | |
// ============================ | |
var old = $.fn.triggerOn | |
$.fn.triggerOn = function (option) { | |
return this.each(function () { | |
var $this = $(this) | |
var data = $this.data('fn.triggerOn') | |
var options = $.extend({}, TriggerOn.DEFAULTS, $this.data(), typeof option == 'object' && option) | |
if (!data) $this.data('fn.triggerOn', (data = new TriggerOn(this, options))) | |
}) | |
} | |
$.fn.triggerOn.Constructor = TriggerOn | |
// TRIGGERON NO CONFLICT | |
// ================= | |
$.fn.triggerOn.noConflict = function () { | |
$.fn.triggerOn = old | |
return this | |
} | |
// TRIGGERON DATA-API | |
// =============== | |
$('[data-trigger]').triggerOn() | |
} | |
}(window.jQuery)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment