[wp-trac] [WordPress Trac] #21170: JavaScript actions and filters

WordPress Trac wp-trac at lists.automattic.com
Mon Jul 16 00:21:30 UTC 2012


#21170: JavaScript actions and filters
----------------------------+--------------------------
 Reporter:  koopersmith     |       Owner:  koopersmith
     Type:  task (blessed)  |      Status:  new
 Priority:  normal          |   Milestone:  3.5
Component:  General         |     Version:  3.4
 Severity:  normal          |  Resolution:
 Keywords:                  |
----------------------------+--------------------------

Comment (by azaozz):

 Replying to [comment:32 carldanley]:
 > I understand what you're saying now. The only question I have is how do
 we traverse the array to find simulated 'parents' and 'children'.

 Yes, that's exactly the thing. This is modelled after the PHP actions API
 that has been in WP for years and works quite well. There aren't any sub-
 divisions / sub-branches / children and grandchildren in an action. That
 keeps things simple. Each action is a single branch that only has leaves
 (callbacks). It also matches the DOM events API, there's no 'click.one',
 click.other', etc. When 'click' is triggered, everything attached to it is
 fired.

 > If doAction( 'some.action' ) was called and we know there were several
 actions that existed such as 'some.action.a' and 'some.action.b', would we
 first find 'some.action' and then maybe look to a 'family' property that
 will indicate who the parent/children are? I don't think traversing each
 key in this flat array and determining who is prefixed with the correct
 action/identifier is the safest way, especially using for( var in ) to
 iterate. Thoughts?

 If we stick to the current model,

 {{{
 doAction( 'some.action' )
 doAction( 'some.action.a' )
 doAction( 'some.other' )
 }}}

 will not be supported. The action for all these would be

 {{{
 doAction( 'some' )
 }}}

 and all callbacks that were registered with

 {{{
 addAction( 'some.thing', function(){...} )
 addAction( 'some.action', function(){...} )
 addAction( 'some.identifier', function(){...} )
 }}}

 would be fired. So in `addAction()` the identifier only applies to the
 callback and has nothing to do with the action itself.

 On the other hand, as I said in [#comment:29 comment:29], perhaps we could
 support "true" namespacing for the actions. That would open some advanced
 possibilities to additionally "filter" which callbacks are called.

 In this case each action would be a container of many actions that start
 with the same name, and each child action can also be a container for even
 more actions (grandchildren), and so on. So an action would contain both
 callbacks and other actions. This would complicate the API quite a bit
 even if we limit the depth to, lets say 3 levels.

 Perhaps we should consider all pros and cons. For example, lets say we
 have an action 'init' with several namespaces/children: 'init.some',
 'init.some.more', 'init.other'.

 - Firing 'init' would fire all callbacks registered directly under 'init',
 plus all callbacks registered under 'init.some', plus all callbacks
 registered under 'init.some.more', plus all callbacks registered under
 'init.other', plus... etc. Exactly the same thing can be achieved by
 firing several actions: 'init', 'init_some', 'init_some_more',
 'init_other', etc. one after the other.

  So with namespaced actions we only need:
 {{{
 doAction( 'init' );
 }}}
  without namespaces we need:
 {{{
 doAction( 'init' );
 doAction( 'init_some' );
 doAction( 'init_some_more' );
 doAction( 'init_other' );
 }}}
  and we have control over which action is fired first, second, etc.

  Advantage of namespacing: shorter code, disadvantage: no control over
 firing order.

 - Setting a namespace first then firing the action. Lets say we can set
 the namespace to '.some'. Firing 'init' should fire only callbacks under
 'init.some' and 'init.some.more'. That's still exactly the same as firing
 'init_some' and 'init_some_more' as separate actions.

  With namespaced actions we need:
 {{{
 setNamespace( 'some' );
 doAction( 'init' );
 setNamespace( '' ); // depends on whether we reset the namespace after
 each action
 }}}
  without namespaces we need:
 {{{
 doAction( 'init_some' );
 doAction( 'init_some_more' );
 }}}
  and we can choose to do 'init_some_more' before 'init_some'. Advantage:
 none, disadvantage: same as above.

 - Firing directly 'init.some' should fire callbacks under 'init.some' and
 'init.some.more'. Still the same as firing the callbacks in 'init_some'
 and 'init_some_more' separately with the same advantages and
 disadvantages.

 - Setting the namespace to 'other' or firing directly 'init.other' should
 fire the callbacks registered under 'init.other'. That's exactly the same
 as simply firing 'init_other'.

 So the advantage of using namespaced vs. "flat" actions is a bit shorter
 code, the disadvantages are: more complex API, different than the PHP
 actions (that's a big one), no control of child actions firing order.

 Another possibility is to add namespacing support in the API and never use
 it in core. Usually the core code does `doAction` and `applyFilters`, and
 plugins do `addAction` and `addFilter`, so if core never uses action
 namespaces, the plugins wouldn't need to deal with the differences from
 the PHP API.

 > I agree in saying that we should keep the actions/filters in separate
 containers.

 Yes, they either have to be in separate containers or we can have a flag
 in each object, perhaps something like `isFilter: true/false`. Both would
 work well and require about the same amount of code.

-- 
Ticket URL: <http://core.trac.wordpress.org/ticket/21170#comment:33>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software


More information about the wp-trac mailing list