Skip to content

Commit 930343f

Browse files
committed
Add dynamic tooltip option
Update mar10#59
1 parent 411dcc6 commit 930343f

File tree

5 files changed

+130
-29
lines changed

5 files changed

+130
-29
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 1.17.0-1 / Unreleased
22

3-
* [FEATURE] #59 Allow callbacks for `disabled` and `title` options
3+
* [FEATURE] #59 Allow callbacks for `disabled`, `title`, and `tooltip` options
44
* [FEATURE] #116 `autoFocus` skips leading disabled entries.
55
* [FEATURE] #118 New option `closeOnWindowBlur`
66
* Use `.on()` / `.off()` syntax

Gruntfile.coffee

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,10 @@ module.exports = (grunt) ->
186186
# The following tools are run in order:
187187
check: { branch: ['master'], canPush: true, clean: true, cmpVersion: 'gte' }
188188
run_test: { tasks: ['test'] }
189-
bump: {} # 'bump' also uses the increment mode `yabs:release:MODE`
189+
bump: {} # 'bump' uses the increment mode `yabs:release:MODE` by default
190190
run_build: { tasks: ['build'] }
191191
commit: {}
192-
check_after_build: { clean: true } # Fails if new files found
192+
check_after_build: { clean: true } # Fails if new files are found
193193
tag: {}
194194
push: { tags: true, useFollowTags: true }
195195
githubRelease:
@@ -198,7 +198,7 @@ module.exports = (grunt) ->
198198
npmPublish: {}
199199
bump_develop: { inc: 'prepatch' }
200200
commit_develop: { message: 'Bump prerelease ({%= version %}) [ci skip]' }
201-
push_develop: {}
201+
push_develop: {} # another push (append a suffix for a uniqu ename)
202202

203203

204204
# Load "grunt*" dependencies

demo/index-1-12.html

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,19 @@
9696
{title: "----"},
9797
{title: "More", children: [
9898
{title: "Sub 1 (callback)", action: function(event, ui) { alert("action callback sub1");} },
99-
{title: "Edit <kbd>[F2]</kbd>", cmd: "sub2", tooltip: "Edit the title"},
99+
{title: "Sub 2 (dynamic state)", cmd: "sub2", disabled: function(event, ui) {
100+
return true;
101+
} },
102+
{title: "Sub 3 (dynamic hide)", cmd: "sub3", disabled: function(event, ui) {
103+
return "hide";
104+
} },
105+
{title: "Sub 4 (tooltip)", cmd: "sub4", tooltip: "My tooltip"},
106+
{title: "Sub 5 (dynamic tooltip)", cmd: "sub5", tooltip: function(event, ui) {
107+
return ui.item.text() + " !!!";
108+
} },
109+
{cmd: "sub6", title: function(event, ui) {
110+
return "Sub 6 (dynamic title): " + ui.target.text();
111+
} }
100112
]}
101113
],
102114
// Handle menu selection to implement a fake-clipboard

jquery.ui-contextmenu.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -348,24 +348,33 @@ $.widget("moogle.contextmenu", {
348348
},
349349
/* Apply status callbacks when menu is opened. */
350350
_updateEntries: function() {
351-
var self = this;
351+
var self = this,
352+
ui = {
353+
menu: this.$menu, target: $(this.currentTarget), extraData: this.extraData };
352354

353355
$.each(this.$menu.find(".ui-menu-item"), function(i, o) {
354356
var $entry = $(o),
355-
ui = { item: $entry, cmd: $entry.attr("data-command") },
356357
fn = $entry.data("disabledHandler"),
357-
res = fn ? fn(null, ui) : null;
358+
res = fn ? fn({ type: "disabled" }, ui) : null;
358359

360+
ui.item = $entry;
361+
ui.cmd = $entry.attr("data-command");
359362
// Evaluate `disabled()` callback
360363
if ( res != null ) {
361364
self.enableEntry(ui.cmd, !res);
362365
self.showEntry(ui.cmd, res !== "hide");
363366
}
364367
// Evaluate `title()` callback
365368
fn = $entry.data("titleHandler"),
366-
res = fn ? fn(null, ui) : null;
369+
res = fn ? fn({ type: "title" }, ui) : null;
370+
if ( res != null ) {
371+
self.setEntry(ui.cmd, "" + res);
372+
}
373+
// Evaluate `tooltip()` callback
374+
fn = $entry.data("tooltipHandler"),
375+
res = fn ? fn({ type: "tooltip" }, ui) : null;
367376
if ( res != null ) {
368-
self.setEntry(ui.cmd, res);
377+
$entry.attr("title", "" + res);
369378
}
370379
});
371380
},
@@ -474,10 +483,10 @@ $.extend($.moogle.contextmenu, {
474483
$wrapper.append($("<span class='ui-icon' />").addClass(entry.uiIcon));
475484
}
476485
}
477-
$.each( [ "action", "disabled", "title" ], function(i, attr) {
486+
// Store option callbacks in entry's data
487+
$.each( [ "action", "disabled", "title", "tooltip" ], function(i, attr) {
478488
if ( $.isFunction(entry[attr]) ) {
479489
$parentLi.data(attr + "Handler", entry[attr]);
480-
// console.log("handler", $parentLi, attr);
481490
}
482491
});
483492
if ( entry.disabled === true ) {
@@ -492,7 +501,7 @@ $.extend($.moogle.contextmenu, {
492501
if ( $.isPlainObject(entry.data) ) {
493502
$parentLi.data(entry.data);
494503
}
495-
if ( entry.tooltip != null ) {
504+
if ( typeof entry.tooltip === "string" ) {
496505
$parentLi.attr("title", entry.tooltip);
497506
}
498507
}

test/tests.js

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -375,24 +375,25 @@ QUnit.test("UL menu", function(assert) {
375375

376376
// ****************************************************************************
377377

378-
QUnit.module("'action' option", lifecycle);
378+
QUnit.module("Dynmic options", lifecycle);
379379

380-
QUnit.test("Array menu", function(assert) {
380+
QUnit.test("'action' option", function(assert) {
381381
var $ctx, $popup,
382382
menu = [
383-
{ title: "Cut", cmd: "cut", uiIcon: "ui-icon-scissors",
384-
data: { foo: "bar" }, addClass: "custom-class-1",
385-
action: function(event, ui) {
386-
log("cut action");
387-
assert.equal( ui.cmd, "cut", "action: ui.cmd is set" );
388-
assert.equal( ui.target.text(), "AAA", "action: ui.target is set" );
389-
assert.equal( ui.item.data().foo, "bar", "action: ui.item.data() is set" );
390-
assert.ok( ui.item.hasClass("custom-class-1"), "action: addClass property works" );
391-
}
392-
},
393-
{ title: "Copy", cmd: "copy", uiIcon: "ui-icon-copy" },
394-
{ title: "Paste", cmd: "paste", uiIcon: "ui-icon-clipboard", disabled: true }
395-
],
383+
{ title: "Cut", cmd: "cut", uiIcon: "ui-icon-scissors",
384+
data: { foo: "bar" }, addClass: "custom-class-1",
385+
action: function(event, ui) {
386+
log("cut action");
387+
assert.equal( ui.cmd, "cut", "action: ui.cmd is set" );
388+
assert.equal( ui.target.text(), "AAA", "action: ui.target is set" );
389+
assert.equal( ui.item.data().foo, "bar", "action: ui.item.data() is set" );
390+
assert.ok( ui.item.hasClass("custom-class-1"),
391+
"action: addClass property works" );
392+
}
393+
},
394+
{ title: "Copy", cmd: "copy", uiIcon: "ui-icon-copy" },
395+
{ title: "Paste", cmd: "paste", uiIcon: "ui-icon-clipboard", disabled: true }
396+
],
396397
done = assert.async();
397398

398399
assert.expect(9);
@@ -416,7 +417,86 @@ QUnit.test("Array menu", function(assert) {
416417
},
417418
close: function(event) {
418419
log("close");
419-
assert.equal(logOutput(), "open(),after open(),open,select(cut),cut action,close",
420+
assert.equal(logOutput(),
421+
"open(),after open(),open,select(cut),cut action,close",
422+
"Event sequence OK.");
423+
done();
424+
}
425+
});
426+
427+
$ctx = $(":moogle-contextmenu");
428+
$popup = $ctx.contextmenu("getMenu");
429+
430+
log("open()");
431+
$ctx.contextmenu("open", $("span.hasmenu:first"));
432+
log("after open()");
433+
});
434+
435+
QUnit.test("'tooltip' / 'disabled' options", function(assert) {
436+
var $ctx, $popup,
437+
menu = [ {
438+
title: "Cut", cmd: "cut", tooltip: function(event, ui) {
439+
log("tooltip(cut)");
440+
assert.equal( ui.cmd, "cut", "ui.cmd is set" );
441+
assert.equal( ui.target.text(), "AAA", "ui.target is set" );
442+
assert.equal( ui.item.text(), "Cut", "ui.item is set" );
443+
return "dynamic tt";
444+
}
445+
},
446+
{ title: "Copy", cmd: "copy", tooltip: "static tt" },
447+
{ title: "Paste", cmd: "paste", disabled: true },
448+
{ title: "Delete", cmd: "delete", disabled: function(event, ui) {
449+
log("disabled(delete)");
450+
return false;
451+
}
452+
},
453+
{ title: "Edit", cmd: "edit", disabled: function(event, ui) {
454+
log("disabled(edit)");
455+
return true; }
456+
},
457+
{ title: "Hidden", cmd: "hidden", disabled: function(event, ui) {
458+
log("disabled(hidden)");
459+
return "hide";
460+
}
461+
}
462+
],
463+
done = assert.async();
464+
465+
assert.expect(12);
466+
467+
$("#container").contextmenu({
468+
delegate: ".hasmenu",
469+
menu: menu,
470+
open: function(event) {
471+
log("open");
472+
assert.equal(entry($popup, "cut").attr("title"), "dynamic tt",
473+
"tooltip callback result was used");
474+
assert.equal(entry($popup, "copy").attr("title"), "static tt",
475+
"static tooltip value was used");
476+
477+
assert.equal(entry($popup, "paste").hasClass("ui-state-disabled"), true,
478+
"static disabled value was used");
479+
assert.equal(entry($popup, "delete").hasClass("ui-state-disabled"), false,
480+
"dynamic disabled value 'false' was used");
481+
assert.ok(entry($popup, "delete").is(":visible"),
482+
"dynamic disabled value 'false' does not hide");
483+
assert.equal(entry($popup, "paste").hasClass("ui-state-disabled"), true,
484+
"dynamic disabled value 'true' was used");
485+
assert.ok(entry($popup, "delete").is(":visible"),
486+
"dynamic disabled value 'true' does not hide");
487+
assert.ok(entry($popup, "hidden").is(":hidden"),
488+
"dynamic disabled value 'hide' was used");
489+
490+
// Click s.th. to close the menu
491+
setTimeout(function() {
492+
click($popup, 0);
493+
}, 10);
494+
},
495+
close: function(event) {
496+
log("close");
497+
assert.equal(logOutput(),
498+
"open(),tooltip(cut),disabled(delete),disabled(edit),disabled(hidden)," +
499+
"after open(),open,close",
420500
"Event sequence OK.");
421501
done();
422502
}

0 commit comments

Comments
 (0)