8000 Dialog: Add option to put the dialog title in a header element by rpkoller · Pull Request #2275 · jquery/jquery-ui · GitHub
[go: up one dir, main page]

Skip to content

Dialog: Add option to put the dialog title in a header element #2275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tests/unit/dialog/common-deprecated.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ common.testWidget( "dialog", {
resizable: true,
show: null,
title: null,
uiDialogTitleTagName: "<span>",
width: 300,

// Callbacks
Expand Down
1 change: 1 addition & 0 deletions tests/unit/dialog/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ common.testWidget( "dialog", {
resizable: true,
show: null,
title: null,
uiDialogTitleTagName: "<span>",
width: 300,

// Callbacks
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/dialog/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ QUnit.test( "aria-modal", function( assert ) {
element.remove();
} );

QUnit.test( "ui dialog title tagname", function( assert ) {
assert.expect( 1 );

var element, nodeName;

element = $( "<div>" ).dialog( { modal: true, uiDialogTitleTagName: "<h2>" } );
nodeName = element.dialog( "widget" ).find( ".ui-dialog-title" ).get( 0 ).nodeName.toLowerCase();
assert.equal( nodeName, "h2", "The dialog title element is h2" );
} );

QUnit.test( "widget method", function( assert ) {
assert.expect( 1 );
var dialog = $( "<div>" ).appendTo( "#qunit-fixture" ).dialog();
Expand Down
4 changes: 3 additions & 1 deletion ui/widgets/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ $.widget( "ui.dialog", {
resizable: true,
show: null,
title: null,
uiDialogTitleTagName: "<span>",
width: 300,

// Callbacks
Expand Down Expand Up @@ -437,7 +438,8 @@ $.widget( "ui.dialog", {
}
} );

uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
uiDialogTitle = $( this.options.uiDialogTitleTagName )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing user input directly to the jQuery factory is dangerous - apart from obvious abuse when people pass selectors instead of tags here, they can e.g. pass <script>, etc. Protecting from that would require significantly more code, so I'm thinking we should actually change the approach.

How about introducing an option called uiDialogTitleHeadingLevel with the default of 0 and possible values all integers between 0 & 6; you can use Number.isInteger for that. We can check the value and revert to 0 if it's invalid. Then, for 0 we use <span> but for other values we use a proper heading level.

That should cover the important use cases here and avoid possible security issues. Thoughts?

Copy link
Contributor Author
@rpkoller rpkoller Aug 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my initial draft i kept the <> out of the option but thought it would over complicate things so i ended up with the current version. but i agree that your suggested approach would be the better choice. would something like that work?

function between ( headingLvl ) {
  return Number.isInteger( headingLvl ) && headingLvl > 0 && headingLvl <= 6 ? "h" + headingLvl : "span";
};
uiDialogTitle = $( "<" + between( this.options.uiDialogTitleHeadingLevel ) + ">" ).uniqueId().prependTo( this.uiDialogTitlebar );

i am not sure if it would be a clean code wise and i also dont know what the preferred name for the function would be. but the shown snippet is at least already working: the only difference to your suggestion is that the condition is only true between 1 and 6 everything else 0 included becomes a span.

and i would also add a few test cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works, but since this logic is quite simple and only used in a single place, it's not necessary to create a function for it, I think. You can just define a local variable with the computed tag name & use it below.

Try to keep lines ideally below 80 characters (and definitely below 100), breaking them into multiple lines when necessary.

And yes, a few test cases would be needed, when the option was:

  1. not passed (testing default behavior).
  2. 0
  3. 1
  4. 6
  5. 7 (testing that it reverts to span)
  6. "foo" (testing that it reverts to span)

Those should be enough, I think. Optionally, instead of testing 1 & 5 individually, you can create a loop through values 1-6, but I don't think it's absolutely necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok thanks! the suggested changes are in place and the tests are green.

.uniqueId().prependTo( this.uiDialogTitlebar );
this._addClass( uiDialogTitle, "ui-dialog-title" );
this._title( uiDialogTitle );

Expand Down
0