📜 ⬆️ ⬇️

Flexible event management in jQuery - jquery-behavior plugin

Hi, Habr!

My name is Vyacheslav Grimalsky, I am working on a landing page designer, in which a page is assembled by dragging blocks.

I will talk about the event tool, which was originally part of the constructor, but then was put into a separate jQuery plugin, jquery-behavior.
')
The plugin uses jQuery functionality, complementing it with the following features:


I will show right away what is at stake:

//   . //       ,      . var behavior = $.Behavior(); //   .    ,   jQuery. behavior('body').click(function () {}); behavior(window).on('resize.demo', function () {}); behavior('.top').on('click.demo', '.btn', function () {}); //    ,  . behavior.pause({ types: '.demo' }); //    ,  . behavior.resume({ target: 'span', types: 'click.demo' }); //    ,  . behavior.off(); 

Event controllers


 var behavior = $.Behavior(); 

An event controller is an object that can add event handlers and that stores all information about them.

It can delete and suspend event handlers, but only those that have been added to it.

This allows you to separate event handlers of different, independent, parts of the project, and work with them separately.

Working with jQuery style wrappers


The plugin allows you to create object wrappers for working with them.

jQuery:
 $('body').click(function () {}); $(window).on('resize', function () {}); 

Plugin:
 behavior('body').click(function () {}); behavior(window).on('resize', function () {}); 

Here, all functions and their syntax are copied from jQuery, a complete list of them:
bang unbind delegate undelegate hover blur focus on focusin focusout load resize scroll unload click dblclick mousedown mouse up mouse

You can simply take the event-handling code on jQuery and replace the "$" function with "behavior", or whatever your event controller is called, and everything will work.

jQuery:
 $('body').click(function () {}).one('mousemove', function () {}).trigger('click'); 

Plugin:
 behavior('body').click(function () {}).one('mousemove', function () {}).trigger('click'); 

In this case, all the functions created in this way will be assigned to the controller being used, and you will be able to work with them using all the other functions of the controller.

Adding event handlers — the behavior.on () and behavior.one () functions


Similar to jQuery functions, on adds an event handler, and one adds an event handler that runs only once.

The syntax is:

 behavior.on({ //   target: 'body', // ,     types: 'click.namespace', //        selector: '.btn', //  .     handler: function (event) {}, //   //   throttle: { //  .     _.throttle wait: 1000, leading: true, trailing: true }, after: 1, //  .     _.after log: true //  .  ""  ,   . }); 

A few examples.

 behavior.on({ target: window, types: 'resize', handler: handlerFn }); //  behavior(window).on('resize', handlerFn); 

 behavior.on({ target: window, types: 'resize', handler: handlerFn, throttle: { wait: 200, leading: false } }); //  behavior(window).on('resize', _.throttle(handlerFn, 200, { leading: false })); 

 behavior.on({ target: 'body', types: 'click', selector: '.btn', handler: handlerFn, after: 2 }); //  behavior('body').on('click', '.btn', _.after(2, handlerFn)); 

When using a "full" record with the after and throttle parameters, the presence of the underscore or lodash library is not necessary, since these functions are built into the plugin.

Disabling events - the function behavior.off ()


You can disable all the event handlers created by the controller with one call.

 behavior.off(); 

You can disable all event handlers for a specific item or group of items:

 behavior.off({ target: window }); //  behavior(window).off(); 

 behavior.off({ target: $btns }); //  behavior($btns).off(); 

 behavior.off({ target: 'body .btn' }); //  behavior('body .btn').off(); 

You can disable all event handlers of a particular type and namespace:

 behavior.off({ types: 'click' }); 

 behavior.off({ types: 'click.namespace' }); 

 behavior.off({ types: '.namespace1, .namespace2' }); 

 behavior.off({ types: 'click.namespace1, .namespace2' }); 

You can delete and delegated events.

 behavior.off({ target: 'body', types: 'click', selector: '.btn' }); //  behavior('body').off('click', '.btn'); 

 behavior.off({ target: 'body', types: '.namespace', selector: '**' }); //  behavior('body').off('.namespace', '**'); 

And also remove all handlers by reference.

 behavior.off({ handler: handlerFunction }); 

And of course, you can combine all this.

 behavior.off({ target: 'body', types: '.namespace', handler: handlerFunction1 }); //  behavior('body').off('.namespace', handlerFunction1); 

 behavior.off({ target: 'body', handler: handlerFunction1 }); 

Suspending and resuming handlers - the behavior.pause () and behavior.resume () functions


The arguments are the same as the behavior.off () function.

Suspend all event handlers created by the controller with one call.

 behavior.pause(); 

And return them to work:

 behavior.resume(); 

And then all the examples by analogy with behavior.off ().

 behavior.pause({ target: window }); 

 behavior.pause({ types: 'click.namespace1, .namespace2' }); 

 behavior.pause({ target: 'body', types: 'click', selector: '.btn' }); 

 behavior.pause({ target: 'body', types: '.namespace', handler: handlerFunction1 }); 

Suspending and resuming a controller operation - functions behavior.start () and behavior.stop ()


These functions are similar to behavior.pause () and behavior.resume (), but have some differences.

They work not at the level of specific event handlers, but at the level of the controller, that is, it is not the event handlers that stop, but the controller itself. Since the entire controller is stopping, event handlers added after the execution of behavior.stop () will not work until we resume the controller’s operation with the behavior.start () function.

When creating a controller, behavior.start () is also called, and when it is destroyed, behavior.stop () is called.

Controller events


When creating a controller, you can specify the onStart, onStop and onFire parameters.

 var behavior = $.Behavior({ onStart: function (data) {}, onStop: function (data) {}, onFire: function (event) {} }); 

The onFire function is called each time any of the controller's event handlers is fired. The arguments and context get the same as the event handler.

The onStart function is executed when calling behavior.start (). May take the first argument.

The onStop function, which is logical, is executed when you call behavior.stop (), and it can also take its first argument.

To create the event controller that was initially turned off, onStop was not called, and events did not run until you call behavior.start (), you need to specify active flag with the value false when creating the controller:

 var behavior = $.Behavior({ active: false }); 

Destruction of the controller - behavior.destroy ()


If the controller is no longer needed, events need to be turned off, and to clear all memory, you should use this function.

Using multiple controllers


You can use one controller for the whole project, or you can effectively divide events into different controllers.

A good example is the implementation of Drag'n'Drop using a plugin.

One controller is a “sleeping” state event, the other is a drag and drop event, and we simply switch between them.



JSFiddle demo: http://jsfiddle.net/fm22ptxv/
Large red pixels are dragged with the mouse.

Debugging tools


The plugin has built-in debugging tools to help you understand what's happening with the handlers. Which of them are still active, which are called, and which are inactive, and how many of them are left alive.

Getting controller information - behavior.data ()


Returns all the necessary information about the controller - the current state, a list of event handlers.

 { log: false, namespace: "bhvr", onFire: null, onStart: null, onStop: null, records: Array } 

It is important to understand what objects from the records array are.

Suppose we have 2 buttons with the classes .btn1 and .btn2, and we want to assign 2 identical event handlers to them:

 behavior('.btn1, .btn2').on('mousedown mouseup', handler); 

In fact, 4 “low-level” event handlers will be added, as if we wrote:

 behavior('.btn1').on('mousedown', handler); behavior('.btn1').on('mouseup', handler); behavior('.btn2').on('mousedown', handler); behavior('.btn2').on('mouseup', handler); 

So, the records field will contain information about the handlers as we declare them.

In our example, this is:

 { targets: JQuery[], //  $('.btn1, .btn2') types: 'mousedown mouseup', //      handler: function (event) {}, //   selector: undefined, //     calls: 0, //    handler bindings: Array //   " " } 

And already in bindings from records there will be 4 similar objects:

 { target: JQuery[], //  $('.btn1') type: 'mouseup', //   namespaces: string[], //    handler: function (event) {}, //   selector: undefined, //     calls: 0, //    handler paused: false //   } 

The number of calls (calls) of an object in records will always be equal to the sum of the number of calls of all its bindings.

And in bindings they are different, and are considered separately, which is convenient when you need to know which specific event handlers are called and on which elements they work.

Getting a list of event handlers - the behavior.filter () function


Searches all “low-level” handlers, and returns a list of them.

The syntax of the function is the same as that of behavior.off (), behavior.pause () and behavior.resume ().

Getting a complete list of handlers.

 behavior.filter(); 

Getting object event handlers:

 behavior.filter({ target: window }); 

And so on.

 behavior.filter({ types: 'click.namespace1, .namespace2' }); 

 behavior.filter({ target: 'body', types: 'click', selector: '.btn' }); 

 behavior.filter({ target: 'body', types: '.namespace', handler: handlerFunction1 }); 

Event logs


Sometimes it is convenient to keep track of which event is executed.

The controller has a built-in logging mechanism that displays information about each execution of the event handler, as well as about stopping and continuing the operation of the controller itself (functions behavior.stop () and behavior.start ()) to the console.

In order for the event controller to display information about everything that happens in the console, it is enough to specify the log flag with the value true when creating the controller:

 var behavior = $.Behavior({ log: true }); 

You can also enable logs after creating the controller:

 behavior.logOn(); 

You can turn off logs like this:

 behavior.logOff(); 

You can assign your own log handler, which instead of outputting messages to the console will do what you need.

To do this, you need to specify the logFn function when creating the controller:

 var behavior = $.Behavior({ logFn: function (type, behavior, event, data) {} }); 

The type argument contains the type of log — start, stop, or fire. The behavior argument contains a link to the controller itself. Next are the arguments that are passed to the event handler, this event and data. The data argument may be missing.

Testing


In order to test the work of the plugin, native tests of jQuery events were taken, and slightly adapted for themselves.

At the same time, several event handlers were detected in the tests, which were not deleted, although they are trying to keep track of this in the tests. My commit with fixing this was passed to jQuery .

We also wrote tests for functions and situations that are not affected by native tests.

Conclusion


The first version of the plugin was written about a year and a half ago. Since then, the plugin has repeatedly corresponded and refined until it took its current form.

All this time it has been actively used by me in the development, and it is actually very convenient.

I will welcome any comments, comments and suggestions.

Link to githab: https://github.com/grimalschi/jquery-behavior

Thank you very much!

Source: https://habr.com/ru/post/237501/


All Articles