/*! * Globalize * * http://github.com/jquery/globalize * * Copyright Software Freedom Conservancy, Inc. * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license */ (function( window, undefined ) { var Globalize, // private variables regexHex, regexInfinity, regexParseFloat, regexTrim, // private JavaScript utility functions arrayIndexOf, endsWith, extend, isArray, isFunction, isObject, startsWith, trim, truncate, zeroPad, // private Globalization utility functions appendPreOrPostMatch, expandFormat, formatDate, formatNumber, getTokenRegExp, getEra, getEraYear, parseExact, parseNegativePattern; // Global variable (Globalize) or CommonJS module (globalize) Globalize = function( cultureSelector ) { return new Globalize.prototype.init( cultureSelector ); }; if ( typeof require !== "undefined" && typeof exports !== "undefined" && typeof module !== "undefined" ) { // Assume CommonJS module.exports = Globalize; } else { // Export as global variable window.Globalize = Globalize; } Globalize.cultures = {}; Globalize.prototype = { constructor: Globalize, init: function( cultureSelector ) { this.cultures = Globalize.cultures; this.cultureSelector = cultureSelector; return this; } }; Globalize.prototype.init.prototype = Globalize.prototype; // 1. When defining a culture, all fields are required except the ones stated as optional. // 2. Each culture should have a ".calendars" object with at least one calendar named "standard" // which serves as the default calendar in use by that culture. // 3. Each culture should have a ".calendar" object which is the current calendar being used, // it may be dynamically changed at any time to one of the calendars in ".calendars". Globalize.cultures[ "default" ] = { // A unique name for the culture in the form - name: "en", // the name of the culture in the english language englishName: "English", // the name of the culture in its own language nativeName: "English", // whether the culture uses right-to-left text isRTL: false, // "language" is used for so-called "specific" cultures. // For example, the culture "es-CL" means "Spanish, in Chili". // It represents the Spanish-speaking culture as it is in Chili, // which might have different formatting rules or even translations // than Spanish in Spain. A "neutral" culture is one that is not // specific to a region. For example, the culture "es" is the generic // Spanish culture, which may be a more generalized version of the language // that may or may not be what a specific culture expects. // For a specific culture like "es-CL", the "language" field refers to the // neutral, generic culture information for the language it is using. // This is not always a simple matter of the string before the dash. // For example, the "zh-Hans" culture is netural (Simplified Chinese). // And the "zh-SG" culture is Simplified Chinese in Singapore, whose lanugage // field is "zh-CHS", not "zh". // This field should be used to navigate from a specific culture to it's // more general, neutral culture. If a culture is already as general as it // can get, the language may refer to itself. language: "en", // numberFormat defines general number formatting rules, like the digits in // each grouping, the group separator, and how negative numbers are displayed. numberFormat: { // [negativePattern] // Note, numberFormat.pattern has no "positivePattern" unlike percent and currency, // but is still defined as an array for consistency with them. // negativePattern: one of "(n)|-n|- n|n-|n -" pattern: [ "-n" ], // number of decimal places normally shown decimals: 2, // string that separates number groups, as in 1,000,000 ",": ",", // string that separates a number from the fractional portion, as in 1.99 ".": ".", // array of numbers indicating the size of each number group. // TODO: more detailed description and example groupSizes: [ 3 ], // symbol used for positive numbers "+": "+", // symbol used for negative numbers "-": "-", // symbol used for NaN (Not-A-Number) "NaN": "NaN", // symbol used for Negative Infinity negativeInfinity: "-Infinity", // symbol used for Positive Infinity positiveInfinity: "Infinity", percent: { // [negativePattern, positivePattern] // negativePattern: one of "-n %|-n%|-%n|%-n|%n-|n-%|n%-|-% n|n %-|% n-|% -n|n- %" // positivePattern: one of "n %|n%|%n|% n" pattern: [ "-n %", "n %" ], // number of decimal places normally shown decimals: 2, // array of numbers indicating the size of each number group. // TODO: more detailed description and example groupSizes: [ 3 ], // string that separates number groups, as in 1,000,000 ",": ",", // string that separates a number from the fractional portion, as in 1.99 ".": ".", // symbol used to represent a percentage symbol: "%" }, currency: { // [negativePattern, positivePattern] // negativePattern: one of "($n)|-$n|$-n|$n-|(n$)|-n$|n-$|n$-|-n $|-$ n|n $-|$ n-|$ -n|n- $|($ n)|(n $)" // positivePattern: one of "$n|n$|$ n|n $" pattern: [ "($n)", "$n" ], // number of decimal places normally shown decimals: 2, // array of numbers indicating the size of each number group. // TODO: more detailed description and example groupSizes: [ 3 ], // string that separates number groups, as in 1,000,000 ",": ",", // string that separates a number from the fractional portion, as in 1.99 ".": ".", // symbol used to represent currency symbol: "$" } }, // calendars defines all the possible calendars used by this culture. // There should be at least one defined with name "standard", and is the default // calendar used by the culture. // A calendar contains information about how dates are formatted, information about // the calendar's eras, a standard set of the date formats, // translations for day and month names, and if the calendar is not based on the Gregorian // calendar, conversion functions to and from the Gregorian calendar. calendars: { standard: { // name that identifies the type of calendar this is name: "Gregorian_USEnglish", // separator of parts of a date (e.g. "/" in 11/05/1955) "/": "/", // separator of parts of a time (e.g. ":" in 05:44 PM) ":": ":", // the first day of the week (0 = Sunday, 1 = Monday, etc) firstDay: 0, days: { // full day names names: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // abbreviated day names namesAbbr: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // shortest day names namesShort: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ] }, months: { // full month names (13 months for lunar calendards -- 13th month should be "" if not lunar) names: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "" ], // abbreviated month names namesAbbr: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "" ] }, // AM and PM designators in one of these forms: // The usual view, and the upper and lower case versions // [ standard, lowercase, uppercase ] // The culture does not use AM or PM (likely all standard date formats use 24 hour time) // null AM: [ "AM", "am", "AM" ], PM: [ "PM", "pm", "PM" ], eras: [ // eras in reverse chronological order. // name: the name of the era in this culture (e.g. A.D., C.E.) // start: when the era starts in ticks (gregorian, gmt), null if it is the earliest supported era. // offset: offset in years from gregorian calendar { "name": "A.D.", "start": null, "offset": 0 } ], // when a two digit year is given, it will never be parsed as a four digit // year greater than this year (in the appropriate era for the culture) // Set it as a full year (e.g. 2029) or use an offset format starting from // the current year: "+19" would correspond to 2029 if the current year 2010. twoDigitYearMax: 2029, // set of predefined date and time patterns used by the culture // these represent the format someone in this culture would expect // to see given the portions of the date that are shown. patterns: { // short date pattern d: "M/d/yyyy", // long date pattern D: "dddd, MMMM dd, yyyy", // short tim
<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>jQuery UI Autocomplete - Custom data and display</title>
	<link rel="stylesheet" href="../../themes/base/all.css">
	<script src="../../external/jquery/jquery.js"></script>
	<script src="../../ui/core.js"></script>
	<script src="../../ui/widget.js"></script>
	<script src="../../ui/position.js"></script>
	<script src="../../ui/menu.js"></script>
	<script src="../../ui/autocomplete.js"></script>
	<link rel="stylesheet" href="../demos.css">
	<style>
	#project-label {
		display: block;
		font-weight: bold;
		margin-bottom: 1em;
	}
	#project-icon {
		float: left;
		height: 32px;
		width: 32px;
	}
	#project-description {
		margin: 0;
		padding: 0;
	}
	</style>
	<script>
	$(function() {
		var projects = [
			{
				value: "jquery",
				label: "jQuery",
				desc: "the write less, do more, JavaScript library",
				icon: "jquery_32x32.png"
			},
			{
				value: "jquery-ui",
				label: "jQuery UI",
				desc: "the official user interface library for jQuery",
				icon: "jqueryui_32x32.png"
			},
			{
				value: "sizzlejs",
				label: "Sizzle JS",
				desc: "a pure-JavaScript CSS selector engine",
				icon: "sizzlejs_32x32.png"
			}
		];

		$( "#project" ).autocomplete({
			minLength: 0,
			source: projects,
			focus: function( event, ui ) {
				$( "#project" ).val( ui.item.label );
				return false;
			},
			select: function( event, ui ) {
				$( "#project" ).val( ui.item.label );
				$( "#project-id" ).val( ui.item.value );
				$( "#project-description" ).html( ui.item.desc );
				$( "#project-icon" ).attr( "src", "images/" + ui.item.icon );

				return false;
			}
		})
		.autocomplete( "instance" )._renderItem = function( ul, item ) {
			return $( "<li>" )
				.append( "<div>" + item.label + "<br>" + item.desc + "</div>" )
				.appendTo( ul );
		};
	});
	</script>
</head>
<body>

<div id="project-label">Select a project (type "j" for a start):</div>
<img id="project-icon" src="images/transparent_1x1.png" class="ui-state-default" alt="">
<input id="project">
<input type="hidden" id="project-id">
<p id="project-description"></p>

<div class="demo-description">
<p>You can use your own custom data formats and displays by simply overriding the default focus and select actions.</p>
<p>Try typing "j" to get a list of projects or just press the down arrow.</p>
</div>
</body>
</html>
d": case "d": // Day of month. date = matchInt; // check that date is generally in valid range, also checking overflow below. if ( outOfRange(date, 1, 31) ) return null; break; case "MMM": case "MMMM": month = getMonthIndex( cal, matchGroup, clength === 3 ); if ( outOfRange(month, 0, 11) ) return null; break; case "M": case "MM": // Month. month = matchInt - 1; if ( outOfRange(month, 0, 11) ) return null; break; case "y": case "yy": case "yyyy": year = clength < 4 ? expandYear( cal, matchInt ) : matchInt; if ( outOfRange(year, 0, 9999) ) return null; break; case "h": case "hh": // Hours (12-hour clock). hour = matchInt; if ( hour === 12 ) hour = 0; if ( outOfRange(hour, 0, 11) ) return null; break; case "H": case "HH": // Hours (24-hour clock). hour = matchInt; if ( outOfRange(hour, 0, 23) ) return null; break; case "m": case "mm": // Minutes. min = matchInt; if ( outOfRange(min, 0, 59) ) return null; break; case "s": case "ss": // Seconds. sec = matchInt; if ( outOfRange(sec, 0, 59) ) return null; break; case "tt": case "t": // AM/PM designator. // see if it is standard, upper, or lower case PM. If not, ensure it is at least one of // the AM tokens. If not, fail the parse for this format. pmHour = cal.PM && ( matchGroup === cal.PM[0] || matchGroup === cal.PM[1] || matchGroup === cal.PM[2] ); if ( !pmHour && ( !cal.AM || ( matchGroup !== cal.AM[0] && matchGroup !== cal.AM[1] && matchGroup !== cal.AM[2] ) ) ) return null; break; case "f": // Deciseconds. case "ff": // Centiseconds. case "fff": // Milliseconds. msec = matchInt * Math.pow( 10, 3 - clength ); if ( outOfRange(msec, 0, 999) ) return null; break; case "ddd": // Day of week. case "dddd": // Day of week. weekDay = getDayIndex( cal, matchGroup, clength === 3 ); if ( outOfRange(weekDay, 0, 6) ) return null; break; case "zzz": // Time zone offset in +/- hours:min. var offsets = matchGroup.split( /:/ ); if ( offsets.length !== 2 ) return null; hourOffset = parseInt( offsets[0], 10 ); if ( outOfRange(hourOffset, -12, 13) ) return null; var minOffset = parseInt( offsets[1], 10 ); if ( outOfRange(minOffset, 0, 59) ) return null; tzMinOffset = ( hourOffset * 60 ) + ( startsWith(matchGroup, "-") ? -minOffset : minOffset ); break; case "z": case "zz": // Time zone offset in +/- hours. hourOffset = matchInt; if ( outOfRange(hourOffset, -12, 13) ) return null; tzMinOffset = hourOffset * 60; break; case "g": case "gg": var eraName = matchGroup; if ( !eraName || !cal.eras ) return null; eraName = trim( eraName.toLowerCase() ); for ( var i = 0, l = cal.eras.length; i < l; i++ ) { if ( eraName === cal.eras[i].name.toLowerCase() ) { era = i; break; } } // could not find an era with that name if ( era === null ) return null; break; } } } var result = new Date(), defaultYear, convert = cal.convert; defaultYear = convert ? convert.fromGregorian( result )[ 0 ] : result.getFullYear(); if ( year === null ) { year = defaultYear; } else if ( cal.eras ) { // year must be shifted to normal gregorian year // but not if year was not specified, its already normal gregorian // per the main if clause above. year += cal.eras[( era || 0 )].offset; } // set default day and month to 1 and January, so if unspecified, these are the defaults // instead of the current day/month. if ( month === null ) { month = 0; } if ( date === null ) { date = 1; } // now have year, month, and date, but in the culture's calendar. // convert to gregorian if necessary if ( convert ) { result = convert.toGregorian( year, month, date ); // conversion failed, must be an invalid match if ( result === null ) return null; } else { // have to set year, month and date together to avoid overflow based on current date. result.setFullYear( year, month, date ); // check to see if date overflowed for specified month (only checked 1-31 above). if ( result.getDate() !== date ) return null; // invalid day of week. if ( weekDay !== null && result.getDay() !== weekDay ) { return null; } } // if pm designator token was found make sure the hours fit the 24-hour clock. if ( pmHour && hour < 12 ) { hour += 12; } result.setHours( hour, min, sec, msec ); if ( tzMinOffset !== null ) { // adjust timezone to utc before applying local offset. var adjustedMin = result.getMinutes() - ( tzMinOffset + result.getTimezoneOffset() ); // Safari limits hours and minutes to the range of -127 to 127. We need to use setHours // to ensure both these fields will not exceed this range. adjustedMin will range // somewhere between -1440 and 1500, so we only need to split this into hours. result.setHours( result.getHours() + parseInt(adjustedMin / 60, 10), adjustedMin % 60 ); } return result; }; }()); parseNegativePattern = function( value, nf, negativePattern ) { var neg = nf[ "-" ], pos = nf[ "+" ], ret; switch ( negativePattern ) { case "n -": neg = " " + neg; pos = " " + pos; /* falls through */ case "n-": if ( endsWith(value, neg) ) { ret = [ "-", value.substr(0, value.length - neg.length) ]; } else if ( endsWith(value, pos) ) { ret = [ "+", value.substr(0, value.length - pos.length) ]; } break; case "- n": neg += " "; pos += " "; /* falls through */ case "-n": if ( startsWith(value, neg) ) { ret = [ "-", value.substr(neg.length) ]; } else if ( startsWith(value, pos) ) { ret = [ "+", value.substr(pos.length) ]; } break; case "(n)": if ( startsWith(value, "(") && endsWith(value, ")") ) { ret = [ "-", value.substr(1, value.length - 2) ]; } break; } return ret || [ "", value ]; }; // // public instance functions // Globalize.prototype.findClosestCulture = function( cultureSelector ) { return Globalize.findClosestCulture.call( this, cultureSelector ); }; Globalize.prototype.format = function( value, format, cultureSelector ) { return Globalize.format.call( this, value, format, cultureSelector ); }; Globalize.prototype.localize = function( key, cultureSelector ) { return Globalize.localize.call( this, key, cultureSelector ); }; Globalize.prototype.parseInt = function( value, radix, cultureSelector ) { return Globalize.parseInt.call( this, value, radix, cultureSelector ); }; Globalize.prototype.parseFloat = function( value, radix, cultureSelector ) { return Globalize.parseFloat.call( this, value, radix, cultureSelector ); }; Globalize.prototype.culture = function( cultureSelector ) { return Globalize.culture.call( this, cultureSelector ); }; // // public singleton functions // Globalize.addCultureInfo = function( cultureName, baseCultureName, info ) { var base = {}, isNew = false; if ( typeof cultureName !== "string" ) { // cultureName argument is optional string. If not specified, assume info is first // and only argument. Specified info deep-extends current culture. info = cultureName; cultureName = this.culture().name; base = this.cultures[ cultureName ]; } else if ( typeof baseCultureName !== "string" ) { // baseCultureName argument is optional string. If not specified, assume info is second // argument. Specified info deep-extends specified culture. // If specified culture does not exist, create by deep-extending default info = baseCultureName; isNew = ( this.cultures[ cultureName ] == null ); base = this.cultures[ cultureName ] || this.cultures[ "default" ]; } else { // cultureName and baseCultureName specified. Assume a new culture is being created // by deep-extending an specified base culture isNew = true; base = this.cultures[ baseCultureName ]; } this.cultures[ cultureName ] = extend(true, {}, base, info ); // Make the standard calendar the current culture if it's a new culture if ( isNew ) { this.cultures[ cultureName ].calendar = this.cultures[ cultureName ].calendars.standard; } }; Globalize.findClosestCulture = function( name ) { var match; if ( !name ) { return this.findClosestCulture( this.cultureSelector ) || this.cultures[ "default" ]; } if ( typeof name === "string" ) { name = name.split( "," ); } if ( isArray(name) ) { var lang, cultures = this.cultures, list = name, i, l = list.length, prioritized = []; for ( i = 0; i < l; i++ ) { name = trim( list[i] ); var pri, parts = name.split( ";" ); lang = trim( parts[0] ); if ( parts.length === 1 ) { pri = 1; } else { name = trim( parts[1] ); if ( name.indexOf("q=") === 0 ) { name = name.substr( 2 ); pri = parseFloat( name ); pri = isNaN( pri ) ? 0 : pri; } else { pri = 1; } } prioritized.push({ lang: lang, pri: pri }); } prioritized.sort(function( a, b ) { if ( a.pri < b.pri ) { return 1; } else if ( a.pri > b.pri ) { return -1; } return 0; }); // exact match for ( i = 0; i < l; i++ ) { lang = prioritized[ i ].lang; match = cultures[ lang ]; if ( match ) { return match; } } // neutral language match for ( i = 0; i < l; i++ ) { lang = prioritized[ i ].lang; do { var index = lang.lastIndexOf( "-" ); if ( index === -1 ) { break; } // strip off the last part. e.g. en-US => en lang = lang.substr( 0, index ); match = cultures[ lang ]; if ( match ) { return match; } } while ( 1 ); } // last resort: match first culture using that language for ( i = 0; i < l; i++ ) { lang = prioritized[ i ].lang; for ( var cultureKey in cultures ) { var culture = cultures[ cultureKey ]; if ( culture.language === lang ) { return culture; } } } } else if ( typeof name === "object" ) { return name; } return match || null; }; Globalize.format = function( value, format, cultureSelector ) { var culture = this.findClosestCulture( cultureSelector ); if ( value instanceof Date ) { value = formatDate( value, format, culture ); } else if ( typeof value === "number" ) { value = formatNumber( value, format, culture ); } return value; }; Globalize.localize = function( key, cultureSelector ) { return this.findClosestCulture( cultureSelector ).messages[ key ] || this.cultures[ "default" ].messages[ key ]; }; Globalize.parseDate = function( value, formats, culture ) { culture = this.findClosestCulture( culture ); var date, prop, patterns; if ( formats ) { if ( typeof formats === "string" ) { formats = [ formats ]; } if ( formats.length ) { for ( var i = 0, l = formats.length; i < l; i++ ) { var format = formats[ i ]; if ( format ) { date = parseExact( value, format, culture ); if ( date ) { break; } } } } } else { patterns = culture.calendar.patterns; for ( prop in patterns ) { date = parseExact( value, patterns[prop], culture ); if ( date ) { break; } } } return date || null; }; Globalize.parseInt = function( value, radix, cultureSelector ) { return truncate( Globalize.parseFloat(value, radix, cultureSelector) ); }; Globalize.parseFloat = function( value, radix, cultureSelector ) { // radix argument is optional if ( typeof radix !== "number" ) { cultureSelector = radix; radix = 10; } var culture = this.findClosestCulture( cultureSelector ); var ret = NaN, nf = culture.numberFormat; if ( value.indexOf(culture.numberFormat.currency.symbol) > -1 ) { // remove currency symbol value = value.replace( culture.numberFormat.currency.symbol, "" ); // replace decimal seperator value = value.replace( culture.numberFormat.currency["."], culture.numberFormat["."] ); } //Remove percentage character from number string before parsing if ( value.indexOf(culture.numberFormat.percent.symbol) > -1){ value = value.replace( culture.numberFormat.percent.symbol, "" ); } // remove spaces: leading, trailing and between - and number. Used for negative currency pt-BR value = value.replace( / /g, "" ); // allow infinity or hexidecimal if ( regexInfinity.test(value) ) { ret = parseFloat( value ); } else if ( !radix && regexHex.test(value) ) { ret = parseInt( value, 16 ); } else { // determine sign and number var signInfo = parseNegativePattern( value, nf, nf.pattern[0] ), sign = signInfo[ 0 ], num = signInfo[ 1 ]; // #44 - try parsing as "(n)" if ( sign === "" && nf.pattern[0] !== "(n)" ) { signInfo = parseNegativePattern( value, nf, "(n)" ); sign = signInfo[ 0 ]; num = signInfo[ 1 ]; } // try parsing as "-n" if ( sign === "" && nf.pattern[0] !== "-n" ) { signInfo = parseNegativePattern( value, nf, "-n" ); sign = signInfo[ 0 ]; num = signInfo[ 1 ]; } sign = sign || "+"; // determine exponent and number var exponent, intAndFraction, exponentPos = num.indexOf( "e" ); if ( exponentPos < 0 ) exponentPos = num.indexOf( "E" ); if ( exponentPos < 0 ) { intAndFraction = num; exponent = null; } else { intAndFraction = num.substr( 0, exponentPos ); exponent = num.substr( exponentPos + 1 ); } // determine decimal position var integer, fraction, decSep = nf[ "." ], decimalPos = intAndFraction.indexOf( decSep ); if ( decimalPos < 0 ) { integer = intAndFraction; fraction = null; } else { integer = intAndFraction.substr( 0, decimalPos ); fraction = intAndFraction.substr( decimalPos + decSep.length ); } // handle groups (e.g. 1,000,000) var groupSep = nf[ "," ]; integer = integer.split( groupSep ).join( "" ); var altGroupSep = groupSep.replace( /\u00A0/g, " " ); if ( groupSep !== altGroupSep ) { integer = integer.split( altGroupSep ).join( "" ); } // build a natively parsable number string var p = sign + integer; if ( fraction !== null ) { p += "." + fraction; } if ( exponent !== null ) { // exponent itself may have a number patternd var expSignInfo = parseNegativePattern( exponent, nf, "-n" ); p += "e" + ( expSignInfo[0] || "+" ) + expSignInfo[ 1 ]; } if ( regexParseFloat.test(p) ) { ret = parseFloat( p ); } } return ret; }; Globalize.culture = function( cultureSelector ) { // setter if ( typeof cultureSelector !== "undefined" ) { this.cultureSelector = cultureSelector; } // getter return this.findClosestCulture( cultureSelector ) || this.cultures[ "default" ]; }; }( this ));