Más contenido relacionado Similar a Instant Dynamic Forms with #states (20) Más de Konstantin Käfer (6) Instant Dynamic Forms with #states5. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
6. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
7. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
8. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
9. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
10. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
11. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
12. Anatomy of a state
5
$form['payment_information'] = array(
'#type' => 'fieldset',
'#title' => t('Payment information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
13. Declarative definition
6
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
➜ Expanded when the element “payment”
is checked
14. Dependencies
7
$form['payment_information'] = array(...
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
<fieldset>
Depends on Influences
<input type="checkbox">
15. Targeting elements
8
◆ Uses plain CSS selectors with jQuery
◆ [name="payment"]
#edit-payment
.payment :checkbox, #edit-payment
◆ Don’t use #selector for auto-assigned IDs
16. States
9
◆ Arbitrary names are possible
◆ visible irrelevant confirmed
checked valid important
◆ Prefixing with ! negates
◆ visible = !invisible
invisible = !visible
17. State aliases
10
◆ Associate custom aliases Primary
name
◆ Drupal.states.State.aliases
['unimportant'] = '!important';
◆ enabled = !disabled invisible = !visible
invalid = !valid untouched = !touched
optional = !required filled = !empty
unchecked = !checked irrelevant = !relevant
expanded = !collapsed readwrite = !readonly
18. Drawbacks
11
◆ Doesn’t support OR and XOR
19. Drawbacks
11
◆ Doesn’t !
chsupport OR and XOR
Pat
drupal.org/node/735528
20. AND operator
12
'disabled' => array(
'[name="ccv"]' => array(
'invalid' => TRUE
),
'[name="card_number"]' => array(
'invalid' => TRUE
),
),
21. OR operator
13
'disabled' => array(
array(
'[name="ccv"]' => array(
'invalid' => TRUE
),
),
array(
'[name="card_number"]' => array(
'invalid' => TRUE
),
),
),
22. OR operator
13
'disabled' => array(
array(
'[name="ccv"]' => array(
'invalid' => TRUE
),
), Numeric keys
array(
'[name="card_number"]' => array(
'invalid' => TRUE
),
),
),
23. XOR operator
14
'disabled' => array('xor',
array(
'[name="ccv"]' => array(
'invalid' => TRUE
),
),
array(
'[name="card_number"]' => array(
'invalid' => TRUE
),
),
),
24. XOR operator
14
'disabled' => array('xor', Operator
array(
'[name="ccv"]' => array(
'invalid' => TRUE
),
),
array(
'[name="card_number"]' => array(
'invalid' => TRUE
),
),
),
25. Drawbacks
15
◆ Doesn’t !
chsupport OR and XOR
Pat
drupal.org/node/735528
26. Drawbacks
15
◆ Doesn’t !
chsupport OR and XOR
Pat
drupal.org/node/735528
◆ Doesn’t support radio buttons
27. Drawbacks
15
◆ Doesn’t !
chsupport OR and XOR
Pat
drupal.org/node/735528
◆ Doesn’t support radio buttons
end!
E xt
29. Default Triggers
17
Drupal.states.Trigger.states = {
...
checked: {
'change': function () {
return this.attr('checked');
}
},
...
};
30. Default Triggers
17
Drupal.states.Trigger.states = {
...
checked: { Native DOM event
'change': function () {
return this.attr('checked');
}
},
...
};
31. Default Triggers
17
Drupal.states.Trigger.states = {
...
checked: {
'change': function () {
return this.attr('checked');
}
},
...
};
32. Default Triggers
17
Drupal.states.Trigger.states = {
...
checked: {
'change': function () {
return this.attr('checked');
}
},
...
}; Value function
33. Default Triggers
18
Initialization Execution
Drupal.states.Trigger.states = { Drupal.states.Trigger.states = {
... ...
checked: { checked: {
'change': function () { 'change': function () {
return this.attr('checked'); return this.attr('checked');
} }
}, },
... ...
}; };
$('#element').bind('change', $('#element').bind('change',
function() { function() {
... ...
} }
); );
34. Default Triggers
18
Initialization Execution
Drupal.states.Trigger.states = { Drupal.states.Trigger.states = {
... ...
checked: { checked: {
'change': function () { 'change': function () {
return this.attr('checked'); return this.attr('checked');
} }
}, },
... ...
}; };
$('#element').bind('change', $('#element').bind('change',
function() { function() {
... ...
} }
); );
35. Default Triggers
18
Initialization Execution
Drupal.states.Trigger.states = { Drupal.states.Trigger.states = {
... ...
checked: { checked: {
'change': function () { 'change': function () {
return this.attr('checked'); return this.attr('checked');
} }
}, },
... ...
}; };
$('#element').bind('change', $('#element').bind('change',
function() { function() {
... ...
} }
); );
36. Multiple Triggers
19
Drupal.states.Trigger.states = {
...
value: {
'keyup': function () {
return this.val();
},
'change': function () {
return this.val();
}
},
...
};
37. Multiple Triggers
20
Drupal.states.Trigger.states = {
...
value: {
'keyup change': function () {
return this.val();
}
},
...
};
38. Custom Triggers
21
'#states' => array(
'disabled' => array(
'[name="delayed"]' => array('value' => 'foo')
),
),
39. Custom Triggers
22
Drupal.states.Trigger.states.delayedValue =
function(element) {
var value = element.val(), oldValue, timeout;
var trigger = function() {
if (oldValue !== value) {
element.trigger({
type: 'state:delayedValue',
value: value,
oldValue: oldValue
});
oldValue = value;
}
};
...
};
40. Custom Triggers
22
Drupal.states.Trigger.states.delayedValue =
function(element) {
var value = element.val(), oldValue, timeout;
var trigger = function() {
if (oldValue !== value) {
element.trigger({
type: 'state:delayedValue',
value: value,
oldValue: oldValue
});
oldValue = value;
}
};
...
};
41. Custom Triggers
22
Drupal.states.Trigger.states.delayedValue =
function(element) {
var value = element.val(), oldValue, timeout;
var trigger = function() {
if (oldValue !== value) {
element.trigger({
type: 'state:delayedValue',
value: value,
oldValue: oldValue
});
oldValue = value;
}
};
...
};
42. Custom Triggers
22
Drupal.states.Trigger.states.delayedValue =
function(element) {
var value = element.val(), oldValue, timeout;
var trigger = function() {
if (oldValue !== value) {
element.trigger({
type: 'state:delayedValue',
value: value,
oldValue: oldValue
});
oldValue = value;
}
};
...
};
43. Custom Triggers
22
Drupal.states.Trigger.states.delayedValue =
function(element) {
var value = element.val(), oldValue, timeout;
var trigger = function() {
if (oldValue !== value) {
element.trigger({
type: 'state:delayedValue',
value: value,
oldValue: oldValue
});
oldValue = value;
}
};
...
};
44. Custom Triggers
23
Drupal.states.Trigger.states.delayedValue =
function(element) {
...
element.bind('keyup change', function (e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
value = element.val();
trigger();
}, 1000);
});
Drupal.states.postponed.push(trigger);
};
45. Custom Triggers
23
Drupal.states.Trigger.states.delayedValue =
function(element) {
...
element.bind('keyup change', function (e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
value = element.val();
trigger();
}, 1000);
});
Drupal.states.postponed.push(trigger);
};
46. Custom Triggers
23
Drupal.states.Trigger.states.delayedValue =
function(element) {
...
element.bind('keyup change', function (e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
value = element.val();
trigger();
}, 1000);
});
Drupal.states.postponed.push(trigger);
};
47. Custom Triggers
23
Drupal.states.Trigger.states.delayedValue =
function(element) {
...
element.bind('keyup change', function (e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
value = element.val();
trigger();
}, 1000);
});
Drupal.states.postponed.push(trigger);
};
48. Custom Triggers
23
Drupal.states.Trigger.states.delayedValue =
function(element) {
...
element.bind('keyup change', function (e) {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
value = element.val();
trigger();
}, 1000);
});
Drupal.states.postponed.push(trigger);
};
49. Custom Triggers
24
Drupal.states.Trigger.states.toggle =
function(element) {
var value = true, oldValue = undefined;
var trigger = function() {
value = !value;
element.trigger({
type: 'state:toggle',
value: value,
oldValue: oldValue
});
oldValue = value;
};
setInterval(trigger, 1000);
Drupal.states.postponed.push(trigger);
};
51. Comparisons
26
$form['payment_information'] = array(
...
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
),
);
52. Comparisons
26
$form['payment_information'] = array(
...
'#states' => array(
'expanded' => array(
'[name="payment"]' => array('checked' => TRUE)
),
), ===
);
53. Advanced Comparisons
27
states.Dependant.comparisons = {
'RegExp': function (reference, value) {
return reference.test(value);
},
'Function': function (reference, value) {
return reference(value);
}
};
54. Advanced Comparisons
27
states.Dependant.comparisons = {
'RegExp': function (reference, value) {
return reference.test(value);
},
'Function': function (reference, value) {
return reference(value);
}
};
Prototype name
57. Advanced Comparisons
30
'invalid' => array(
'[name="card_number"]' => array(
'!value' => '0000 0000 0000 0000',
),
),
'invalid' => array(
'[name="card_number"]' => array(
'!value' => array('regex' => '^(d{4}[ -]*){4}$'),
),
),
58. Advanced Comparisons
30
'invalid' => array(
'[name="card_number"]' => array(
'!value' => '0000 0000 0000 0000',
),
),
'invalid' => array(
'[name="card_number"]' => array(
'!value' => array('regex' => '^(d{4}[ -]*){4}$'),
),
),
59. Advanced Comparisons
31
Drupal.states.Dependant.comparisons.Object =
function(reference, value) {
if ('regex' in reference) {
return RegExp(reference.regex, ↵
reference.flags).test(value);
}
else {
return reference.indexOf(value) !== false;
}
};
60. Advanced Comparisons
32
'invalid' => array(
'[name="card_number"]' => array(
'!value' => array('regex' => '^(d{4}[ -]*){4}$'),
),
),
62. State changes
34
◆ Transition an element from one state
to another
Direct Indirect
◆ Triggered by user ◆ Triggered by other
◆ Notify listeners element
◆ Transition element
63. State changes
35
$(document).bind('state:checked', function(e) {
if (e.trigger) {
$(e.target).attr('checked', e.value);
}
});
64. State changes
35
$(document).bind('state:checked', function(e) {
if (e.trigger) {
$(e.target).attr('checked', e.value);
}
});
65. State changes
35
$(document).bind('state:checked', function(e) {
if (e.trigger) {
$(e.target).attr('checked', e.value);
}
});
66. State changes
35
$(document).bind('state:checked', function(e) {
if (e.trigger) {
$(e.target).attr('checked', e.value);
}
});
67. State changes
35
$(document).bind('state:checked', function(e) {
if (e.trigger) {
$(e.target).attr('checked', e.value);
}
});
68. document
<html> ◆ Event bubbling allows
overwriting handlers
<body> for specific regions
<div id="body"> ◆ CSS selectors allow
overwriting handlers
<div class="element"> for specific elements
36
<input type="text"> State changes
70. Domain-specific language
38
state_of('[name="baz"]')
->is('checked')
->when('[name="bar"]')->checked()
->and('[name="foo"]')->value('foo')
->orWhen('[name="bar"]')->unchecked()
->is('disabled')
->when('[name="bar"]')->unchecked()
->is('invisible')
->when('[name="foo"]')->empty();
Ideas?
72. Multi-value support
40
// The value of at least one element is true.
{'any': true}
// At least two elements are true.
{'n > 2': true}
// The third element is false.
{'2': false}
73. Extended values
41
// The value is greater than 8 or smaller than 5.
[ {'>': 8}, {'<': 5} ]
// At least two elements are between 5 and 8.
{'n > 2': {'>': 5, '<': 8}}
// The sum of the values of all elements is
// greater than 10.
{'sum': {'>=': 10}}
74. Questions?
42
kkaefer.com/2010/states.pdf
mail@kkaefer.com