SlideShare una empresa de Scribd logo
1 de 74
Descargar para leer sin conexión
Instant
Dynamic Forms
      with
             #states
Konstantin Käfer
                   2




    2006
#states   3
4
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)
      ),
   ),
);
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)
      ),
   ),
);
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)
      ),
   ),
);
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)
      ),
   ),
);
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)
      ),
   ),
);
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)
      ),
   ),
);
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)
      ),
   ),
);
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)
      ),
   ),
);
Declarative definition
                                                    6


'expanded' => array(
   '[name="payment"]' => array('checked' => TRUE)
),



 ➜ Expanded when the element “payment”
   is checked
Dependencies
                                                         7


$form['payment_information'] = array(...
   '#states' => array(
     'expanded' => array(
        '[name="payment"]' => array('checked' => TRUE)
      ),
   ),
);
                      <fieldset>

           Depends on           Influences


           <input type="checkbox">
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
States
                                           9


◆   Arbitrary names are possible
◆   visible    irrelevant      confirmed
    checked    valid           important


◆   Prefixing with ! negates
◆   visible = !invisible
    invisible = !visible
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
Drawbacks
                                 11


◆   Doesn’t support OR and XOR
Drawbacks
                                       11


◆   Doesn’t !
         chsupport OR and XOR
      Pat
              drupal.org/node/735528
AND operator
                                        12


'disabled' => array(

     '[name="ccv"]' => array(
       'invalid' => TRUE
     ),


     '[name="card_number"]' => array(
       'invalid' => TRUE
     ),

),
OR operator
                                        13


'disabled' => array(
   array(
     '[name="ccv"]' => array(
        'invalid' => TRUE
      ),
   ),
   array(
     '[name="card_number"]' => array(
        'invalid' => TRUE
      ),
   ),
),
OR operator
                                        13


'disabled' => array(
   array(
     '[name="ccv"]' => array(
        'invalid' => TRUE
      ),
   ),     Numeric keys
   array(
     '[name="card_number"]' => array(
        'invalid' => TRUE
      ),
   ),
),
XOR operator
                                        14


'disabled' => array('xor',
   array(
     '[name="ccv"]' => array(
        'invalid' => TRUE
      ),
   ),
   array(
     '[name="card_number"]' => array(
        'invalid' => TRUE
      ),
   ),
),
XOR operator
                                             14


'disabled' => array('xor',        Operator
   array(
     '[name="ccv"]' => array(
        'invalid' => TRUE
      ),
   ),
   array(
     '[name="card_number"]' => array(
        'invalid' => TRUE
      ),
   ),
),
Drawbacks
                                       15


◆   Doesn’t !
         chsupport OR and XOR
      Pat
              drupal.org/node/735528
Drawbacks
                                       15


◆   Doesn’t !
         chsupport OR and XOR
      Pat
              drupal.org/node/735528

◆   Doesn’t support radio buttons
Drawbacks
                                       15


◆   Doesn’t !
         chsupport OR and XOR
      Pat
              drupal.org/node/735528

◆   Doesn’t support radio buttons
          end!
      E xt
Triggers
Default Triggers
                                       17


Drupal.states.Trigger.states = {
   ...
   checked: {
     'change': function () {
        return this.attr('checked');
      }
   },
   ...
};
Default Triggers
                                       17


Drupal.states.Trigger.states = {
   ...
   checked: {   Native DOM event
     'change': function () {
        return this.attr('checked');
      }
   },
   ...
};
Default Triggers
                                       17


Drupal.states.Trigger.states = {
   ...
   checked: {
     'change': function () {
        return this.attr('checked');
      }
   },
   ...
};
Default Triggers
                                       17


Drupal.states.Trigger.states = {
   ...
   checked: {
     'change': function () {
        return this.attr('checked');
      }
   },
   ...
};           Value function
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() {
     ...                                    ...
   }                                      }
);                                     );
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() {
     ...                                    ...
   }                                      }
);                                     );
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() {
     ...                                    ...
   }                                      }
);                                     );
Multiple Triggers
                                   19


Drupal.states.Trigger.states = {
   ...
   value: {
     'keyup': function () {
        return this.val();
      },
     'change': function () {
        return this.val();
      }
   },
   ...
};
Multiple Triggers
                                     20


Drupal.states.Trigger.states = {
   ...
   value: {
     'keyup change': function () {
        return this.val();
      }
   },
   ...
};
Custom Triggers
                                                     21


'#states' => array(
   'disabled' => array(
     '[name="delayed"]' => array('value' => 'foo')
   ),
),
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;
       }
    };

    ...
  };
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;
       }
    };

    ...
  };
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;
       }
    };

    ...
  };
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;
       }
    };

    ...
  };
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;
       }
    };

    ...
  };
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);
  };
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);
  };
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);
  };
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);
  };
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);
  };
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);
  };
Comparisons
Comparisons
                                                         26


$form['payment_information'] = array(
   ...
   '#states' => array(
     'expanded' => array(
        '[name="payment"]' => array('checked' => TRUE)
      ),
   ),
);
Comparisons
                                                         26


$form['payment_information'] = array(
   ...
   '#states' => array(
     'expanded' => array(
        '[name="payment"]' => array('checked' => TRUE)
      ),
   ),                                      ===
);
Advanced Comparisons
                                               27


states.Dependant.comparisons = {
   'RegExp': function (reference, value) {
     return reference.test(value);
   },
   'Function': function (reference, value) {
     return reference(value);
   }
};
Advanced Comparisons
                                               27


states.Dependant.comparisons = {
   'RegExp': function (reference, value) {
     return reference.test(value);
   },
   'Function': function (reference, value) {
     return reference(value);
   }
};
       Prototype name
JSON only allows
strings and numbers   28
:(   29
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}$'),
   ),
),
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}$'),
   ),
),
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;
     }
  };
Advanced Comparisons
                                                      32




'invalid' => array(
   '[name="card_number"]' => array(
     '!value' => array('regex' => '^(d{4}[ -]*){4}$'),
   ),
),
Transitions
State changes
                                               34


◆   Transition an element from one state
    to another

 Direct                  Indirect
◆ Triggered by user     ◆ Triggered by other

◆ Notify listeners        element
                        ◆ Transition element
State changes
                                                  35




$(document).bind('state:checked', function(e) {
  if (e.trigger) {
    $(e.target).attr('checked', e.value);
  }
});
State changes
                                                  35




$(document).bind('state:checked', function(e) {
  if (e.trigger) {
    $(e.target).attr('checked', e.value);
  }
});
State changes
                                                  35




$(document).bind('state:checked', function(e) {
  if (e.trigger) {
    $(e.target).attr('checked', e.value);
  }
});
State changes
                                                  35




$(document).bind('state:checked', function(e) {
  if (e.trigger) {
    $(e.target).attr('checked', e.value);
  }
});
State changes
                                                  35




$(document).bind('state:checked', function(e) {
  if (e.trigger) {
    $(e.target).attr('checked', e.value);
  }
});
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
Future Work
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?
Copy & Paste support   39
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}
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}}
Questions?
                              42




kkaefer.com/2010/states.pdf
    mail@kkaefer.com

Más contenido relacionado

Similar a Instant Dynamic Forms with #states

PHP record- with all programs and output
PHP record- with all programs and outputPHP record- with all programs and output
PHP record- with all programs and output
KavithaK23
 
Desarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesDesarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móviles
Luis Curo Salvatierra
 
Refactoring group 1 - chapter 3,4,6
Refactoring   group 1 - chapter 3,4,6Refactoring   group 1 - chapter 3,4,6
Refactoring group 1 - chapter 3,4,6
Duy Lâm
 
R57shell
R57shellR57shell
R57shell
ady36
 

Similar a Instant Dynamic Forms with #states (20)

Gta v savegame
Gta v savegameGta v savegame
Gta v savegame
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
 
Drupal7 dbtng
Drupal7  dbtngDrupal7  dbtng
Drupal7 dbtng
 
PHP record- with all programs and output
PHP record- with all programs and outputPHP record- with all programs and output
PHP record- with all programs and output
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Taking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order FunctionsTaking Perl to Eleven with Higher-Order Functions
Taking Perl to Eleven with Higher-Order Functions
 
The Art of Transduction
The Art of TransductionThe Art of Transduction
The Art of Transduction
 
Slaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in RubySlaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in Ruby
 
Presentation1
Presentation1Presentation1
Presentation1
 
Advanced jQuery
Advanced jQueryAdvanced jQuery
Advanced jQuery
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
 
Arrays in php
Arrays in phpArrays in php
Arrays in php
 
Desarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesDesarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móviles
 
Fields in Core: How to create a custom field
Fields in Core: How to create a custom fieldFields in Core: How to create a custom field
Fields in Core: How to create a custom field
 
TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
 
Refactoring group 1 - chapter 3,4,6
Refactoring   group 1 - chapter 3,4,6Refactoring   group 1 - chapter 3,4,6
Refactoring group 1 - chapter 3,4,6
 
R57shell
R57shellR57shell
R57shell
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
究極のコントローラを目指す
究極のコントローラを目指す究極のコントローラを目指す
究極のコントローラを目指す
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
 

Más de Konstantin Käfer

Más de Konstantin Käfer (6)

Front End Performance
Front End PerformanceFront End Performance
Front End Performance
 
Front End Performance
Front End PerformanceFront End Performance
Front End Performance
 
Developing JavaScript Widgets
Developing JavaScript WidgetsDeveloping JavaScript Widgets
Developing JavaScript Widgets
 
Front End Performance
Front End PerformanceFront End Performance
Front End Performance
 
Typography on the Web
Typography on the WebTypography on the Web
Typography on the Web
 
What's New in Web Development
What's New in Web DevelopmentWhat's New in Web Development
What's New in Web Development
 

Último

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Último (20)

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 

Instant Dynamic Forms with #states

  • 1. Instant Dynamic Forms with #states
  • 4. 4
  • 5. 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
  • 55. JSON only allows strings and numbers 28
  • 56. :( 29
  • 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?
  • 71. Copy & Paste support 39
  • 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