mirror of
https://github.com/jquery/jquery-ui.git
synced 2024-11-21 11:04:24 +00:00
Datepicker: Make sure text option are text, shorten HTML strings
Instead of using enormous HTML strings, various elements are now constructed using jQuery APIs. This makes it more obvious user-provided data is used correctly. Fixes #15284 Closes gh-1953
This commit is contained in:
parent
effa323f15
commit
afe20b79a6
@ -1171,4 +1171,55 @@ QUnit.test( "Ticket 7602: Stop datepicker from appearing with beforeShow event h
|
|||||||
inp.datepicker( "destroy" );
|
inp.datepicker( "destroy" );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
QUnit.test( "Ticket #15284: escaping text parameters", function( assert ) {
|
||||||
|
assert.expect( 7 );
|
||||||
|
|
||||||
|
var done = assert.async();
|
||||||
|
|
||||||
|
var qf = $( "#qunit-fixture" );
|
||||||
|
|
||||||
|
window.uiGlobalXss = [];
|
||||||
|
|
||||||
|
var inp = testHelper.init( "#inp", {
|
||||||
|
showButtonPanel: true,
|
||||||
|
showOn: "both",
|
||||||
|
prevText: "<script>uiGlobalXss = uiGlobalXss.concat( [ 'prevText XSS' ] )</script>",
|
||||||
|
nextText: "<script>uiGlobalXss = uiGlobalXss.concat( [ 'nextText XSS' ] )</script>",
|
||||||
|
currentText: "<script>uiGlobalXss = uiGlobalXss.concat( [ 'currentText XSS' ] )</script>",
|
||||||
|
closeText: "<script>uiGlobalXss = uiGlobalXss.concat( [ 'closeText XSS' ] )</script>",
|
||||||
|
buttonText: "<script>uiGlobalXss = uiGlobalXss.concat( [ 'buttonText XSS' ] )</script>",
|
||||||
|
appendText: "<script>uiGlobalXss = uiGlobalXss.concat( [ 'appendText XSS' ] )</script>"
|
||||||
|
} );
|
||||||
|
|
||||||
|
var dp = $( "#ui-datepicker-div" );
|
||||||
|
|
||||||
|
testHelper.onFocus( inp, function() {
|
||||||
|
assert.equal( dp.find( ".ui-datepicker-prev" ).text().trim(),
|
||||||
|
"<script>uiGlobalXss = uiGlobalXss.concat( [ 'prevText XSS' ] )</script>",
|
||||||
|
"prevText escaped" );
|
||||||
|
assert.equal( dp.find( ".ui-datepicker-next" ).text().trim(),
|
||||||
|
"<script>uiGlobalXss = uiGlobalXss.concat( [ 'nextText XSS' ] )</script>",
|
||||||
|
"nextText escaped" );
|
||||||
|
assert.equal( dp.find( ".ui-datepicker-current" ).text().trim(),
|
||||||
|
"<script>uiGlobalXss = uiGlobalXss.concat( [ 'currentText XSS' ] )</script>",
|
||||||
|
"currentText escaped" );
|
||||||
|
assert.equal( dp.find( ".ui-datepicker-close" ).text().trim(),
|
||||||
|
"<script>uiGlobalXss = uiGlobalXss.concat( [ 'closeText XSS' ] )</script>",
|
||||||
|
"closeText escaped" );
|
||||||
|
|
||||||
|
assert.equal( qf.find( ".ui-datepicker-trigger" ).text().trim(),
|
||||||
|
"<script>uiGlobalXss = uiGlobalXss.concat( [ 'buttonText XSS' ] )</script>",
|
||||||
|
"buttonText escaped" );
|
||||||
|
assert.equal( qf.find( ".ui-datepicker-append" ).text().trim(),
|
||||||
|
"<script>uiGlobalXss = uiGlobalXss.concat( [ 'appendText XSS' ] )</script>",
|
||||||
|
"appendText escaped" );
|
||||||
|
|
||||||
|
assert.deepEqual( window.uiGlobalXss, [], "No XSS" );
|
||||||
|
|
||||||
|
delete window.uiGlobalXss;
|
||||||
|
inp.datepicker( "hide" ).datepicker( "destroy" );
|
||||||
|
done();
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
} );
|
} );
|
||||||
|
@ -240,7 +240,9 @@ $.extend( Datepicker.prototype, {
|
|||||||
inst.append.remove();
|
inst.append.remove();
|
||||||
}
|
}
|
||||||
if ( appendText ) {
|
if ( appendText ) {
|
||||||
inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
|
inst.append = $( "<span>" )
|
||||||
|
.addClass( this._appendClass )
|
||||||
|
.text( appendText );
|
||||||
input[ isRTL ? "before" : "after" ]( inst.append );
|
input[ isRTL ? "before" : "after" ]( inst.append );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,12 +259,32 @@ $.extend( Datepicker.prototype, {
|
|||||||
if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
|
if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
|
||||||
buttonText = this._get( inst, "buttonText" );
|
buttonText = this._get( inst, "buttonText" );
|
||||||
buttonImage = this._get( inst, "buttonImage" );
|
buttonImage = this._get( inst, "buttonImage" );
|
||||||
inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
|
|
||||||
$( "<img/>" ).addClass( this._triggerClass ).
|
if ( this._get( inst, "buttonImageOnly" ) ) {
|
||||||
attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
|
inst.trigger = $( "<img>" )
|
||||||
$( "<button type='button'></button>" ).addClass( this._triggerClass ).
|
.addClass( this._triggerClass )
|
||||||
html( !buttonImage ? buttonText : $( "<img/>" ).attr(
|
.attr( {
|
||||||
{ src:buttonImage, alt:buttonText, title:buttonText } ) ) );
|
src: buttonImage,
|
||||||
|
alt: buttonText,
|
||||||
|
title: buttonText
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
inst.trigger = $( "<button type='button'>" )
|
||||||
|
.addClass( this._triggerClass );
|
||||||
|
if ( buttonImage ) {
|
||||||
|
inst.trigger.html(
|
||||||
|
$( "<img>" )
|
||||||
|
.attr( {
|
||||||
|
src: buttonImage,
|
||||||
|
alt: buttonText,
|
||||||
|
title: buttonText
|
||||||
|
} )
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
inst.trigger.text( buttonText );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
input[ isRTL ? "before" : "after" ]( inst.trigger );
|
input[ isRTL ? "before" : "after" ]( inst.trigger );
|
||||||
inst.trigger.on( "click", function() {
|
inst.trigger.on( "click", function() {
|
||||||
if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
|
if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
|
||||||
@ -1703,32 +1725,104 @@ $.extend( Datepicker.prototype, {
|
|||||||
this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
|
this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
|
||||||
this._getFormatConfig( inst ) ) );
|
this._getFormatConfig( inst ) ) );
|
||||||
|
|
||||||
prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
|
if ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ) {
|
||||||
"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
|
prev = $( "<a>" )
|
||||||
" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
|
.attr( {
|
||||||
( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );
|
"class": "ui-datepicker-prev ui-corner-all",
|
||||||
|
"data-handler": "prev",
|
||||||
|
"data-event": "click",
|
||||||
|
title: prevText
|
||||||
|
} )
|
||||||
|
.append(
|
||||||
|
$( "<span>" )
|
||||||
|
.addClass( "ui-icon ui-icon-circle-triangle-" +
|
||||||
|
( isRTL ? "e" : "w" ) )
|
||||||
|
.text( prevText )
|
||||||
|
)[ 0 ].outerHTML;
|
||||||
|
} else if ( hideIfNoPrevNext ) {
|
||||||
|
prev = "";
|
||||||
|
} else {
|
||||||
|
prev = $( "<a>" )
|
||||||
|
.attr( {
|
||||||
|
"class": "ui-datepicker-prev ui-corner-all ui-state-disabled",
|
||||||
|
title: prevText
|
||||||
|
} )
|
||||||
|
.append(
|
||||||
|
$( "<span>" )
|
||||||
|
.addClass( "ui-icon ui-icon-circle-triangle-" +
|
||||||
|
( isRTL ? "e" : "w" ) )
|
||||||
|
.text( prevText )
|
||||||
|
)[ 0 ].outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
nextText = this._get( inst, "nextText" );
|
nextText = this._get( inst, "nextText" );
|
||||||
nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
|
nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
|
||||||
this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
|
this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
|
||||||
this._getFormatConfig( inst ) ) );
|
this._getFormatConfig( inst ) ) );
|
||||||
|
|
||||||
next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
|
if ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ) {
|
||||||
"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
|
next = $( "<a>" )
|
||||||
" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
|
.attr( {
|
||||||
( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );
|
"class": "ui-datepicker-next ui-corner-all",
|
||||||
|
"data-handler": "next",
|
||||||
|
"data-event": "click",
|
||||||
|
title: nextText
|
||||||
|
} )
|
||||||
|
.append(
|
||||||
|
$( "<span>" )
|
||||||
|
.addClass( "ui-icon ui-icon-circle-triangle-" +
|
||||||
|
( isRTL ? "w" : "e" ) )
|
||||||
|
.text( nextText )
|
||||||
|
)[ 0 ].outerHTML;
|
||||||
|
} else if ( hideIfNoPrevNext ) {
|
||||||
|
next = "";
|
||||||
|
} else {
|
||||||
|
next = $( "<a>" )
|
||||||
|
.attr( {
|
||||||
|
"class": "ui-datepicker-next ui-corner-all ui-state-disabled",
|
||||||
|
title: nextText
|
||||||
|
} )
|
||||||
|
.append(
|
||||||
|
$( "<span>" )
|
||||||
|
.attr( "class", "ui-icon ui-icon-circle-triangle-" +
|
||||||
|
( isRTL ? "w" : "e" ) )
|
||||||
|
.text( nextText )
|
||||||
|
)[ 0 ].outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
currentText = this._get( inst, "currentText" );
|
currentText = this._get( inst, "currentText" );
|
||||||
gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
|
gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
|
||||||
currentText = ( !navigationAsDateFormat ? currentText :
|
currentText = ( !navigationAsDateFormat ? currentText :
|
||||||
this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
|
this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
|
||||||
|
|
||||||
controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
|
controls = "";
|
||||||
this._get( inst, "closeText" ) + "</button>" : "" );
|
if ( !inst.inline ) {
|
||||||
|
controls = $( "<button>" )
|
||||||
|
.attr( {
|
||||||
|
type: "button",
|
||||||
|
"class": "ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all",
|
||||||
|
"data-handler": "hide",
|
||||||
|
"data-event": "click"
|
||||||
|
} )
|
||||||
|
.text( this._get( inst, "closeText" ) )[ 0 ].outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
|
buttonPanel = "";
|
||||||
( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
|
if ( showButtonPanel ) {
|
||||||
">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
|
buttonPanel = $( "<div class='ui-datepicker-buttonpane ui-widget-content'>" )
|
||||||
|
.append( isRTL ? controls : "" )
|
||||||
|
.append( this._isInRange( inst, gotoDate ) ?
|
||||||
|
$( "<button>" )
|
||||||
|
.attr( {
|
||||||
|
type: "button",
|
||||||
|
"class": "ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all",
|
||||||
|
"data-handler": "today",
|
||||||
|
"data-event": "click"
|
||||||
|
} )
|
||||||
|
.text( currentText ) :
|
||||||
|
"" )
|
||||||
|
.append( isRTL ? "" : controls )[ 0 ].outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
|
firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
|
||||||
firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
|
firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
|
||||||
|
Loading…
Reference in New Issue
Block a user