mirror of
https://github.com/jquery/jquery-ui.git
synced 2024-11-21 11:04:24 +00:00
Core: Add $.fn.labels, $.fn.form, and $.ui.escapeSelector methods
$.fn.labels and $.fn.form mimic the native labels and form properties $.ui.escapeSelector is for escaping attributes and urls for use as selectors Closes gh-1546
This commit is contained in:
parent
6a03b0f2ba
commit
803eaf29f7
@ -108,6 +108,83 @@
|
||||
|
||||
<div id="dimensions" style="float: left; height: 50px; width: 100px; margin: 1px 12px 11px 2px; border-style: solid; border-width: 3px 14px 13px 4px; padding: 5px 16px 15px 6px;"></div>
|
||||
|
||||
<div id="labels-fragment">
|
||||
<label for="test">1</label>
|
||||
<div>
|
||||
<div>
|
||||
<form>
|
||||
<label for="test">2</label>
|
||||
<label>3
|
||||
<input id="test">
|
||||
</label>
|
||||
<label for="test">4</label>
|
||||
</form>
|
||||
<label for="test">5</label>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<form>
|
||||
<label for="test">6</label>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<form>
|
||||
<label for="test">7</label>
|
||||
<label>
|
||||
</label>
|
||||
<label for="test">8</label>
|
||||
</form>
|
||||
<label for="test">9</label>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<form>
|
||||
<input id="test-2">
|
||||
<label for="test">10</label>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="weird-['x']-id"></div>
|
||||
</div>
|
||||
|
||||
<!-- This is intentionally outside the test fixture. We don't want this
|
||||
markup to be removed and reinserted between tests, as it will remove saved
|
||||
refrences in the tests. -->
|
||||
<div id="form-test">
|
||||
<input id="body:_implicit_form">
|
||||
<input id="body:_explicit_form" form="form-1">
|
||||
<form id="form-1">
|
||||
<input id="form-1:_implicit_form">
|
||||
<input id="form-1:_explicit_form" form="form-1">
|
||||
</form>
|
||||
<form id="form-2">
|
||||
<input id="form-2:_implicit_form">
|
||||
<input id="form-2:_explicit_form_other_form" form="form-1">
|
||||
</form>
|
||||
</div>
|
||||
<div id="form-test-detached">
|
||||
<input id="fragment:_implicit_form">
|
||||
|
||||
<!-- Support: Chrome > 33
|
||||
When an input with a form attribute is inside a fragment, and not contained by any form,
|
||||
the form property returns the proper form. However resetting the form does not reset the
|
||||
input. The following input is commented out to stop the test from failing in this case.
|
||||
<input id="fragment:_explicit_form" form="form-3">
|
||||
-->
|
||||
<form id="form-3">
|
||||
<input id="form-3:_implicit_form">
|
||||
<input id="form-3:_explicit_form" form="form-3">
|
||||
</form>
|
||||
<form id="form-4">
|
||||
<input id="form-4:_implicit_form">
|
||||
<input id="form-4:_explicit_form_other_form" form="form-3">
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -138,4 +138,67 @@ test( "uniqueId / removeUniqueId", function() {
|
||||
equal( el.attr( "id" ), null, "unique id has been removed from element" );
|
||||
});
|
||||
|
||||
test( "Labels", function() {
|
||||
expect( 2 );
|
||||
|
||||
var expected = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ];
|
||||
var dom = $( "#labels-fragment" );
|
||||
|
||||
function testLabels( testType ) {
|
||||
var labels = dom.find( "#test" ).labels();
|
||||
var found = labels.map( function() {
|
||||
|
||||
// Support: Core 1.9 Only
|
||||
// We use $.trim() because core 1.9.x silently fails when white space is present
|
||||
return $.trim( $( this ).text() );
|
||||
} ).get();
|
||||
|
||||
deepEqual( found, expected,
|
||||
".labels() finds all labels in " + testType + ", and sorts them in DOM order" );
|
||||
}
|
||||
|
||||
testLabels( "the DOM" );
|
||||
|
||||
// Detach the dom to test on a fragment
|
||||
dom.detach();
|
||||
testLabels( "document fragments" );
|
||||
} );
|
||||
|
||||
( function() {
|
||||
var domAttached = $( "#form-test" );
|
||||
var domDetached = $( "#form-test-detached" ).detach();
|
||||
|
||||
function testForm( name, dom ) {
|
||||
var inputs = dom.find( "input" );
|
||||
|
||||
inputs.each( function() {
|
||||
var input = $( this );
|
||||
|
||||
asyncTest( name + this.id.replace( /_/g, " " ), function() {
|
||||
expect( 1 );
|
||||
var form = input.form();
|
||||
|
||||
// If input has a form the value should reset to "" if not it should be "changed"
|
||||
var value = form.length ? "" : "changed";
|
||||
|
||||
input.val( "changed" );
|
||||
|
||||
// If there is a form we reset just that. If there is not a form, reset every form.
|
||||
// The idea is if a form is found resetting that form should reset the input.
|
||||
// If no form is found no amount of resetting should change the value.
|
||||
( form.length ? form : dom.find( "form" ).addBack( "form" ) ).each( function() {
|
||||
this.reset();
|
||||
} );
|
||||
|
||||
setTimeout( function() {
|
||||
equal( input.val(), value, "Proper form found for #" + input.attr( "id" ) );
|
||||
start();
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
testForm( "form: attached: ", domAttached );
|
||||
testForm( "form: detached: ", domDetached );
|
||||
} )();
|
||||
} );
|
||||
|
@ -254,4 +254,11 @@ test( "tabbable - dimensionless parent with overflow", function() {
|
||||
isTabbable( "#dimensionlessParent", "input" );
|
||||
});
|
||||
|
||||
test( "escapeSelector", function() {
|
||||
expect( 1 );
|
||||
|
||||
equal( $( "#" + $.ui.escapeSelector( "weird-['x']-id" ) ).length, 1,
|
||||
"properly escapes selectors to use as an id" );
|
||||
} );
|
||||
|
||||
} );
|
||||
|
52
ui/core.js
52
ui/core.js
@ -88,7 +88,15 @@ $.extend( $.ui, {
|
||||
if ( element && element.nodeName.toLowerCase() !== "body" ) {
|
||||
$( element ).blur();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Internal use only
|
||||
escapeSelector: ( function() {
|
||||
var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
|
||||
return function( selector ) {
|
||||
return selector.replace( selectorEscape, "\\$1" );
|
||||
};
|
||||
} )()
|
||||
} );
|
||||
|
||||
// plugins
|
||||
@ -126,6 +134,48 @@ $.fn.extend( {
|
||||
$( this ).removeAttr( "id" );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
// Support: IE8 Only
|
||||
// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
|
||||
// with a string, so we need to find the proper form.
|
||||
form: function() {
|
||||
return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
|
||||
},
|
||||
|
||||
labels: function() {
|
||||
var ancestor, selector, id, labels, ancestors;
|
||||
|
||||
// Check control.labels first
|
||||
if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
|
||||
return this.pushStack( this[ 0 ].labels );
|
||||
}
|
||||
|
||||
// Support: IE <= 11, FF <= 37, Android <= 2.3 only
|
||||
// Above browsers do not support control.labels. Everything below is to support them
|
||||
// as well as document fragments. control.labels does not work on document fragments
|
||||
labels = this.eq( 0 ).parents( "label" );
|
||||
|
||||
// Look for the label based on the id
|
||||
id = this.attr( "id" );
|
||||
if ( id ) {
|
||||
|
||||
// We don't search against the document in case the element
|
||||
// is disconnected from the DOM
|
||||
ancestor = this.eq( 0 ).parents().last();
|
||||
|
||||
// Get a full set of top level ancestors
|
||||
ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
|
||||
|
||||
// Create a selector for the label based on the id
|
||||
selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
|
||||
|
||||
labels = labels.add( ancestors.find( selector ).addBack( selector ) );
|
||||
|
||||
}
|
||||
|
||||
// Return whatever we have found for labels
|
||||
return this.pushStack( labels );
|
||||
}
|
||||
} );
|
||||
|
||||
|
@ -90,8 +90,8 @@ return $.widget( "ui.selectmenu", {
|
||||
);
|
||||
|
||||
// Associate existing label with the new button
|
||||
this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
|
||||
this._on( this.label, {
|
||||
this.labels = this.element.labels();
|
||||
this._on( this.labels, {
|
||||
click: function( event ) {
|
||||
this.button.focus();
|
||||
event.preventDefault();
|
||||
@ -671,7 +671,7 @@ return $.widget( "ui.selectmenu", {
|
||||
this.button.remove();
|
||||
this.element.show();
|
||||
this.element.removeUniqueId();
|
||||
this.label.attr( "for", this.ids.element );
|
||||
this.labels.attr( "for", this.ids.element );
|
||||
}
|
||||
} );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user