|
22 | 22 | delegate: "[data-menu]", // selector
|
23 | 23 | hide: { effect: "fadeOut", duration: "fast"},
|
24 | 24 | ignoreParentSelect: true, // Don't trigger 'select' for sub-menu parents
|
25 |
| - menu: null, // selector or jQuery or a function returning such |
| 25 | + menu: null, // selector or jQuery pointing to <UL>, or a definition hash |
26 | 26 | position: null, // popup positon
|
27 | 27 | preventSelect: false, // disable text selection of target
|
28 | 28 | show: { effect: "slideDown", duration: "fast"},
|
|
43 | 43 | opts = this.options;
|
44 | 44 |
|
45 | 45 | this.$headStyle = null;
|
46 |
| - this.orgMenu = null; |
| 46 | + this.$menu = null; |
| 47 | + this.menuIsTemp = false; |
47 | 48 | this.currentTarget = null;
|
48 | 49 | this.ns = "." + this.widgetName;
|
49 | 50 |
|
|
69 | 70 | });
|
70 | 71 | }
|
71 | 72 | }
|
| 73 | + this._createUiMenu(opts.menu); |
| 74 | + |
| 75 | + eventNames = "contextmenu" + this.ns; |
| 76 | + if(opts.taphold){ |
| 77 | + eventNames += " taphold" + this.ns; |
| 78 | + } |
| 79 | + this.element.delegate(opts.delegate, eventNames, $.proxy(this._openMenu, this)); |
| 80 | + |
| 81 | + this._trigger("init"); |
| 82 | + }, |
| 83 | + /** Destructor, called on $().contextmenu("destroy"). */ |
| 84 | + _destroy: function(key, value){ |
| 85 | + this._createUiMenu(null); |
| 86 | + if(this.$headStyle){ |
| 87 | + this.$headStyle.remove(); |
| 88 | + this.$headStyle = null; |
| 89 | + } |
| 90 | + }, |
| 91 | + /** (Re)Create jQuery UI Menu. */ |
| 92 | + _createUiMenu: function(menuDef){ |
| 93 | + // Remove temporary <ul> if any |
| 94 | + if(this.menuIsTemp){ |
| 95 | + this.$menu.remove(); // this will also destroy ui.menu |
| 96 | + this.menuIsTemp = false; |
| 97 | + } else if(this.$menu){ |
| 98 | + this.$menu.menu("destroy").hide(); |
| 99 | + } |
72 | 100 | // If a menu definition array was passed, create a hidden <ul>
|
73 | 101 | // and generate the structure now
|
74 |
| - if($.isArray(opts.menu)){ |
75 |
| - this.orgMenu = opts.menu; |
76 |
| - opts.menu = $.moogle.contextmenu.createMenuMarkup(opts.menu); |
| 102 | + if( ! menuDef ){ |
| 103 | + this.$menu = null; |
| 104 | + return; |
| 105 | + } else if($.isArray(menuDef)){ |
| 106 | + this.$menu = $.moogle.contextmenu.createMenuMarkup(menuDef); |
| 107 | + this.menuIsTemp = true; |
| 108 | + }else if ( typeof menuDef === "string" ){ |
| 109 | + this.$menu = $(menuDef); |
| 110 | + }else{ |
| 111 | + this.$menu = menuDef; |
77 | 112 | }
|
78 |
| - // Create - but hide - the jQuery UI Menu |
79 |
| - this._getMenu() |
| 113 | + // Create - but hide - the jQuery UI Menu widget |
| 114 | + this.$menu |
80 | 115 | .hide()
|
81 | 116 | .addClass("ui-contextmenu")
|
82 | 117 | // Create a menu instance that delegates events to our widget
|
|
97 | 132 | }
|
98 | 133 | }, this)
|
99 | 134 | });
|
100 |
| - |
101 |
| - eventNames = "contextmenu" + this.ns; |
102 |
| - if(opts.taphold){ |
103 |
| - eventNames += " taphold" + this.ns; |
104 |
| - } |
105 |
| - this.element.delegate(opts.delegate, eventNames, $.proxy(this._openMenu, this)); |
106 |
| - |
107 |
| - this._trigger("init"); |
108 |
| - }, |
109 |
| - /** Destructor, called on $().contextmenu("destroy"). */ |
110 |
| - _destroy: function(key, value){ |
111 |
| - if(this.$headStyle){ |
112 |
| - this.$headStyle.remove(); |
113 |
| - this.$headStyle = null; |
114 |
| - } |
115 |
| - // Remove temporary <ul> if any |
116 |
| - if(this.orgMenu){ |
117 |
| - this.options.menu.remove(); |
118 |
| - this.options.menu = this.orgMenu; |
119 |
| - this.orgMenu = null; |
120 |
| - } |
121 | 135 | },
|
122 | 136 | /** Open popup (called on 'contextmenu' event). */
|
123 | 137 | _openMenu: function(event){
|
124 | 138 | var opts = this.options,
|
125 | 139 | posOption = opts.position,
|
126 | 140 | self = this,
|
127 |
| - $menu = this._getMenu(), |
128 |
| - ui = {menu: $menu, target: $(event.target)}; |
| 141 | + ui = {menu: this.$menu, target: $(event.target)}; |
129 | 142 | this.currentTarget = event.target;
|
130 | 143 | // Prevent browser from opening the system context menu
|
131 | 144 | event.preventDefault();
|
132 | 145 |
|
133 | 146 | if( this._trigger("beforeOpen", event, ui) === false ){
|
134 | 147 | return false;
|
135 | 148 | }
|
| 149 | + ui.menu = this.$menu; // Might have changed in beforeOpen |
136 | 150 | // Register global event handlers that close the dropdown-menu
|
137 | 151 | $(document).bind("keydown" + this.ns, function(event){
|
138 | 152 | if( event.which === $.ui.keyCode.ESCAPE ){
|
|
158 | 172 | }, posOption);
|
159 | 173 |
|
160 | 174 | // Finally display the popup
|
161 |
| - $menu |
| 175 | + this.$menu |
162 | 176 | .show() // required to fix positioning error
|
163 | 177 | .css({
|
164 | 178 | position: "absolute",
|
165 | 179 | left: 0,
|
166 | 180 | top: 0
|
167 | 181 | }).position(posOption)
|
168 |
| - .hide(); |
| 182 | + .hide(); // hide again, so we can apply nice effects |
169 | 183 |
|
170 |
| - this._show($menu, this.options.show, function(){ |
| 184 | + this._show(this.$menu, this.options.show, function(){ |
171 | 185 | self._trigger.call(self, "open", event, ui);
|
172 | 186 | });
|
173 | 187 | },
|
174 | 188 | /** Close popup. */
|
175 | 189 | _closeMenu: function(){
|
176 |
| - var self = this, |
177 |
| - $menu = this._getMenu(); |
| 190 | + var self = this; |
178 | 191 |
|
179 |
| - this._hide($menu, this.options.hide, function() { |
| 192 | + this._hide(this.$menu, this.options.hide, function() { |
180 | 193 | self._trigger("close");
|
181 | 194 | this.currentTarget = null;
|
182 | 195 | });
|
|
195 | 208 | }
|
196 | 209 | $.Widget.prototype._setOption.apply(this, arguments);
|
197 | 210 | },
|
198 |
| - /** Return ui-menu root element as jQuery object. */ |
199 |
| - _getMenu: function(){ |
200 |
| - var $menu = this.options.menu; |
201 |
| - return (typeof $menu === "string") ? $($menu) : $menu; |
202 |
| - }, |
203 | 211 | /** Return ui-menu entry (<A> or <LI> tag). */
|
204 | 212 | _getMenuEntry: function(cmd, wantLi){
|
205 |
| - var $entry = this._getMenu().find("li a[href=#" + normCommand(cmd) + "]"); |
| 213 | + var $entry = this.$menu.find("li a[href=#" + normCommand(cmd) + "]"); |
206 | 214 | return wantLi ? $entry.closest("li") : $entry;
|
207 | 215 | },
|
208 | 216 | /** Open context menu on a specific target (must match options.delegate) */
|
|
221 | 229 | },
|
222 | 230 | /** Redefine the whole menu. */
|
223 | 231 | replaceMenu: function(data){
|
224 |
| - var opts = this.options, |
225 |
| - $menu = this._getMenu(); |
226 |
| - |
227 |
| - if($.isArray(data)){ |
228 |
| - if(this.orgMenu){ |
229 |
| - // re-use existing temporary <ul> |
230 |
| - $menu.empty(); |
231 |
| - $.moogle.contextmenu.createMenuMarkup(data, opts.menu); |
232 |
| - $menu.menu("refresh"); |
233 |
| - }else{ |
234 |
| - $.error("not implemented"); |
235 |
| -// this.orgMenu = opts.menu; |
236 |
| -// opts.menu = $.ui.contextmenu.createMenuMarkup(data); |
237 |
| - } |
238 |
| - }else{ |
239 |
| -// if(this.orgMenu){ |
240 |
| -// // re-use existing temporary <ul> |
241 |
| -// }else{ |
242 |
| -// } |
243 |
| -// $menu.menu("option", "menu", opts.menu); |
244 |
| - $.error("not implemented"); |
245 |
| - } |
| 232 | + this._createUiMenu(data); |
246 | 233 | },
|
247 | 234 | /** Redefine menu entry (title or all of it). */
|
248 | 235 | setEntry: function(cmd, titleOrData){
|
|
0 commit comments