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?