JQuery UI widget - how to create events using a shell element

I am developing a jquery widget that extends ui.mouse.

The widget must respond to mouse events by creating elements and adding them to this element.

When the widget is applied to an HTML element, such as an IMG tag that cannot contain children, the widget creates a surrogate wrapper and wraps this.element.

If I replaced this.element with shell element events that widget triggers are never processed because the .bind () calls in the widget instance apply the handler to the source element, not to the wrapper.

If I do not replace this.element with a wrapper element, then the _mouse * events defined by ui.mouse are not raised correctly because they are applied to this element and not to the wrapper.

Is there an elegant way to somehow return a wrapper element so that subsequent calls to bind () apply to it or create a ui.mouse prototype for an element other than this.element?

Any other elegant solution or advice would be very welcome.

These are two scenarios that I have tried.

No replacement for this.element

$.widget("ui.example", ui.mouse, { _containerElement: null, _create: function () { if (this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { this._applyContainer(); }else{ this._containerElement = this.element; } // Applies mouse interaction handlers to this.element this._mouseInit(); }, _applyContainer: function () { this.element.wrap("<span>"); this._containerElement = this.element.parent(); this._containerElement.css({position:'relative'}); }, _mouseStart: function (event) { // Not always called because it handles mouse interaction with // the IMG element rather than the wrapper element this._trigger("mouseevent"); } }) $("IMG").example().bind("examplemouseevent", function(){ //This fires but only when the original IMG element is clicked, not the wrapper }) 

Replace this.element

 $.widget("ui.example", ui.mouse, { _create: function () { if (this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { this._applyContainer(); } // Applies mouse interaction handlers to this.element this._mouseInit(); }, _applyContainer: function () { this.element.wrap("<span>"); this.element = this.element.parent(); this.element.css({position:'relative'}); }, _mouseStart: function (event) { // This event is never handled because it is not raised on the original element. this._trigger("mouseevent"); } }) $("IMG").example().bind("examplemouseevent", function(){ //This never fires because the bind is to the IMG element, not the wrapper }) 

I am sure that the problem is due to the flaws in the way I understand jquery ui.mouse to work or the limitations of the jquery widget frame.

Replacing this.element with an element that wraps the original this.element, but events are NOT dispatched to handlers bound to the widget later.

Without replacing this.element and maintaining a separate wrapper link, the jQuery behavior of the ui.mouse base associates events with the wrong element.

The code works the way it is designed, my problem is to find the best way to work with design constraints.

I see several ways to solve this problem. For instance; duck-punching _trigger method to trigger an event on the correct element or replace the value of this.element back and forth, while ui.mouse attaches the necessary handlers. These and any other methods that I considered seem rather dirty.

I looked at my own jquery.resizable widget code, which also creates a wrapper, but from what I can say, it will also suffer from the same problem if it tries to trigger events.

This is the first time I have worked with jQuery widgets, so I would like to confirm from the jQuery guru that I have not missed anything here?

+4
source share
2 answers

I'm not quite happy with this, but the solution I went with is to change this one. element call _mouseInit and swap it back.

 _containerElement: null, _applyContainer: function () { var origionalElement = this.element; this.element.wrap("<div>"); this._containerElement = this.element.parent(); this.element = this._containerElement; this._mouseInit(); this.element = origionalElement; this._containerElement.css({position:'relative'}); }, 

I'm not pretty, but she works. At some point, I could go for an override of _mouseInit, but right now it is suitable for my purposes.

0
source

I would try an approach like:

 _applyContainer: function () { this.element.wrap("<span>"); this.element.bind("list of events", function(){ this.element.parent().trigger("name of event"); }); this.element = this.element.parent(); this.element.css({position:'relative'}); } 

When creating a shell element, binding to child elements, any list of events (you can iterate if this concept does not work) and fire a parent (cloud, known) event with the same name. Note: The “Event List” should look like “mouseover mouseout click”, etc., And then the “Event Name” should be replaced with some logic to determine which of these lists was fired.

+1
source

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


All Articles