PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/book/bower_components/jquery/src/attributes.js

https://gitlab.com/jeichert/essential-js-design-patterns
JavaScript | 659 lines | 492 code | 95 blank | 72 comment | 151 complexity | 88b20604f06ef1154fa702571259c3e4 MD5 | raw file
  1. var nodeHook, boolHook,
  2. rclass = /[\t\r\n\f]/g,
  3. rreturn = /\r/g,
  4. rfocusable = /^(?:input|select|textarea|button|object)$/i,
  5. rclickable = /^(?:a|area)$/i,
  6. ruseDefault = /^(?:checked|selected)$/i,
  7. getSetAttribute = jQuery.support.getSetAttribute,
  8. getSetInput = jQuery.support.input;
  9. jQuery.fn.extend({
  10. attr: function( name, value ) {
  11. return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
  12. },
  13. removeAttr: function( name ) {
  14. return this.each(function() {
  15. jQuery.removeAttr( this, name );
  16. });
  17. },
  18. prop: function( name, value ) {
  19. return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
  20. },
  21. removeProp: function( name ) {
  22. name = jQuery.propFix[ name ] || name;
  23. return this.each(function() {
  24. // try/catch handles cases where IE balks (such as removing a property on window)
  25. try {
  26. this[ name ] = undefined;
  27. delete this[ name ];
  28. } catch( e ) {}
  29. });
  30. },
  31. addClass: function( value ) {
  32. var classes, elem, cur, clazz, j,
  33. i = 0,
  34. len = this.length,
  35. proceed = typeof value === "string" && value;
  36. if ( jQuery.isFunction( value ) ) {
  37. return this.each(function( j ) {
  38. jQuery( this ).addClass( value.call( this, j, this.className ) );
  39. });
  40. }
  41. if ( proceed ) {
  42. // The disjunction here is for better compressibility (see removeClass)
  43. classes = ( value || "" ).match( core_rnotwhite ) || [];
  44. for ( ; i < len; i++ ) {
  45. elem = this[ i ];
  46. cur = elem.nodeType === 1 && ( elem.className ?
  47. ( " " + elem.className + " " ).replace( rclass, " " ) :
  48. " "
  49. );
  50. if ( cur ) {
  51. j = 0;
  52. while ( (clazz = classes[j++]) ) {
  53. if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
  54. cur += clazz + " ";
  55. }
  56. }
  57. elem.className = jQuery.trim( cur );
  58. }
  59. }
  60. }
  61. return this;
  62. },
  63. removeClass: function( value ) {
  64. var classes, elem, cur, clazz, j,
  65. i = 0,
  66. len = this.length,
  67. proceed = arguments.length === 0 || typeof value === "string" && value;
  68. if ( jQuery.isFunction( value ) ) {
  69. return this.each(function( j ) {
  70. jQuery( this ).removeClass( value.call( this, j, this.className ) );
  71. });
  72. }
  73. if ( proceed ) {
  74. classes = ( value || "" ).match( core_rnotwhite ) || [];
  75. for ( ; i < len; i++ ) {
  76. elem = this[ i ];
  77. // This expression is here for better compressibility (see addClass)
  78. cur = elem.nodeType === 1 && ( elem.className ?
  79. ( " " + elem.className + " " ).replace( rclass, " " ) :
  80. ""
  81. );
  82. if ( cur ) {
  83. j = 0;
  84. while ( (clazz = classes[j++]) ) {
  85. // Remove *all* instances
  86. while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
  87. cur = cur.replace( " " + clazz + " ", " " );
  88. }
  89. }
  90. elem.className = value ? jQuery.trim( cur ) : "";
  91. }
  92. }
  93. }
  94. return this;
  95. },
  96. toggleClass: function( value, stateVal ) {
  97. var type = typeof value;
  98. if ( typeof stateVal === "boolean" && type === "string" ) {
  99. return stateVal ? this.addClass( value ) : this.removeClass( value );
  100. }
  101. if ( jQuery.isFunction( value ) ) {
  102. return this.each(function( i ) {
  103. jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
  104. });
  105. }
  106. return this.each(function() {
  107. if ( type === "string" ) {
  108. // toggle individual class names
  109. var className,
  110. i = 0,
  111. self = jQuery( this ),
  112. classNames = value.match( core_rnotwhite ) || [];
  113. while ( (className = classNames[ i++ ]) ) {
  114. // check each className given, space separated list
  115. if ( self.hasClass( className ) ) {
  116. self.removeClass( className );
  117. } else {
  118. self.addClass( className );
  119. }
  120. }
  121. // Toggle whole class name
  122. } else if ( type === core_strundefined || type === "boolean" ) {
  123. if ( this.className ) {
  124. // store className if set
  125. jQuery._data( this, "__className__", this.className );
  126. }
  127. // If the element has a class name or if we're passed "false",
  128. // then remove the whole classname (if there was one, the above saved it).
  129. // Otherwise bring back whatever was previously saved (if anything),
  130. // falling back to the empty string if nothing was stored.
  131. this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
  132. }
  133. });
  134. },
  135. hasClass: function( selector ) {
  136. var className = " " + selector + " ",
  137. i = 0,
  138. l = this.length;
  139. for ( ; i < l; i++ ) {
  140. if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
  141. return true;
  142. }
  143. }
  144. return false;
  145. },
  146. val: function( value ) {
  147. var ret, hooks, isFunction,
  148. elem = this[0];
  149. if ( !arguments.length ) {
  150. if ( elem ) {
  151. hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
  152. if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
  153. return ret;
  154. }
  155. ret = elem.value;
  156. return typeof ret === "string" ?
  157. // handle most common string cases
  158. ret.replace(rreturn, "") :
  159. // handle cases where value is null/undef or number
  160. ret == null ? "" : ret;
  161. }
  162. return;
  163. }
  164. isFunction = jQuery.isFunction( value );
  165. return this.each(function( i ) {
  166. var val;
  167. if ( this.nodeType !== 1 ) {
  168. return;
  169. }
  170. if ( isFunction ) {
  171. val = value.call( this, i, jQuery( this ).val() );
  172. } else {
  173. val = value;
  174. }
  175. // Treat null/undefined as ""; convert numbers to string
  176. if ( val == null ) {
  177. val = "";
  178. } else if ( typeof val === "number" ) {
  179. val += "";
  180. } else if ( jQuery.isArray( val ) ) {
  181. val = jQuery.map(val, function ( value ) {
  182. return value == null ? "" : value + "";
  183. });
  184. }
  185. hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
  186. // If set returns undefined, fall back to normal setting
  187. if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
  188. this.value = val;
  189. }
  190. });
  191. }
  192. });
  193. jQuery.extend({
  194. valHooks: {
  195. option: {
  196. get: function( elem ) {
  197. // Use proper attribute retrieval(#6932, #12072)
  198. var val = jQuery.find.attr( elem, "value" );
  199. return val != null ?
  200. val :
  201. elem.text;
  202. }
  203. },
  204. select: {
  205. get: function( elem ) {
  206. var value, option,
  207. options = elem.options,
  208. index = elem.selectedIndex,
  209. one = elem.type === "select-one" || index < 0,
  210. values = one ? null : [],
  211. max = one ? index + 1 : options.length,
  212. i = index < 0 ?
  213. max :
  214. one ? index : 0;
  215. // Loop through all the selected options
  216. for ( ; i < max; i++ ) {
  217. option = options[ i ];
  218. // oldIE doesn't update selected after form reset (#2551)
  219. if ( ( option.selected || i === index ) &&
  220. // Don't return options that are disabled or in a disabled optgroup
  221. ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
  222. ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
  223. // Get the specific value for the option
  224. value = jQuery( option ).val();
  225. // We don't need an array for one selects
  226. if ( one ) {
  227. return value;
  228. }
  229. // Multi-Selects return an array
  230. values.push( value );
  231. }
  232. }
  233. return values;
  234. },
  235. set: function( elem, value ) {
  236. var optionSet, option,
  237. options = elem.options,
  238. values = jQuery.makeArray( value ),
  239. i = options.length;
  240. while ( i-- ) {
  241. option = options[ i ];
  242. if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
  243. optionSet = true;
  244. }
  245. }
  246. // force browsers to behave consistently when non-matching value is set
  247. if ( !optionSet ) {
  248. elem.selectedIndex = -1;
  249. }
  250. return values;
  251. }
  252. }
  253. },
  254. attr: function( elem, name, value ) {
  255. var hooks, ret,
  256. nType = elem.nodeType;
  257. // don't get/set attributes on text, comment and attribute nodes
  258. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  259. return;
  260. }
  261. // Fallback to prop when attributes are not supported
  262. if ( typeof elem.getAttribute === core_strundefined ) {
  263. return jQuery.prop( elem, name, value );
  264. }
  265. // All attributes are lowercase
  266. // Grab necessary hook if one is defined
  267. if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
  268. name = name.toLowerCase();
  269. hooks = jQuery.attrHooks[ name ] ||
  270. ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
  271. }
  272. if ( value !== undefined ) {
  273. if ( value === null ) {
  274. jQuery.removeAttr( elem, name );
  275. } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
  276. return ret;
  277. } else {
  278. elem.setAttribute( name, value + "" );
  279. return value;
  280. }
  281. } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
  282. return ret;
  283. } else {
  284. ret = jQuery.find.attr( elem, name );
  285. // Non-existent attributes return null, we normalize to undefined
  286. return ret == null ?
  287. undefined :
  288. ret;
  289. }
  290. },
  291. removeAttr: function( elem, value ) {
  292. var name, propName,
  293. i = 0,
  294. attrNames = value && value.match( core_rnotwhite );
  295. if ( attrNames && elem.nodeType === 1 ) {
  296. while ( (name = attrNames[i++]) ) {
  297. propName = jQuery.propFix[ name ] || name;
  298. // Boolean attributes get special treatment (#10870)
  299. if ( jQuery.expr.match.bool.test( name ) ) {
  300. // Set corresponding property to false
  301. if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
  302. elem[ propName ] = false;
  303. // Support: IE<9
  304. // Also clear defaultChecked/defaultSelected (if appropriate)
  305. } else {
  306. elem[ jQuery.camelCase( "default-" + name ) ] =
  307. elem[ propName ] = false;
  308. }
  309. // See #9699 for explanation of this approach (setting first, then removal)
  310. } else {
  311. jQuery.attr( elem, name, "" );
  312. }
  313. elem.removeAttribute( getSetAttribute ? name : propName );
  314. }
  315. }
  316. },
  317. attrHooks: {
  318. type: {
  319. set: function( elem, value ) {
  320. if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
  321. // Setting the type on a radio button after the value resets the value in IE6-9
  322. // Reset value to default in case type is set after value during creation
  323. var val = elem.value;
  324. elem.setAttribute( "type", value );
  325. if ( val ) {
  326. elem.value = val;
  327. }
  328. return value;
  329. }
  330. }
  331. }
  332. },
  333. propFix: {
  334. "for": "htmlFor",
  335. "class": "className"
  336. },
  337. prop: function( elem, name, value ) {
  338. var ret, hooks, notxml,
  339. nType = elem.nodeType;
  340. // don't get/set properties on text, comment and attribute nodes
  341. if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  342. return;
  343. }
  344. notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
  345. if ( notxml ) {
  346. // Fix name and attach hooks
  347. name = jQuery.propFix[ name ] || name;
  348. hooks = jQuery.propHooks[ name ];
  349. }
  350. if ( value !== undefined ) {
  351. return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
  352. ret :
  353. ( elem[ name ] = value );
  354. } else {
  355. return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
  356. ret :
  357. elem[ name ];
  358. }
  359. },
  360. propHooks: {
  361. tabIndex: {
  362. get: function( elem ) {
  363. // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
  364. // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  365. // Use proper attribute retrieval(#12072)
  366. var tabindex = jQuery.find.attr( elem, "tabindex" );
  367. return tabindex ?
  368. parseInt( tabindex, 10 ) :
  369. rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
  370. 0 :
  371. -1;
  372. }
  373. }
  374. }
  375. });
  376. // Hooks for boolean attributes
  377. boolHook = {
  378. set: function( elem, value, name ) {
  379. if ( value === false ) {
  380. // Remove boolean attributes when set to false
  381. jQuery.removeAttr( elem, name );
  382. } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
  383. // IE<8 needs the *property* name
  384. elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
  385. // Use defaultChecked and defaultSelected for oldIE
  386. } else {
  387. elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
  388. }
  389. return name;
  390. }
  391. };
  392. jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
  393. var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
  394. jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
  395. function( elem, name, isXML ) {
  396. var fn = jQuery.expr.attrHandle[ name ],
  397. ret = isXML ?
  398. undefined :
  399. /* jshint eqeqeq: false */
  400. (jQuery.expr.attrHandle[ name ] = undefined) !=
  401. getter( elem, name, isXML ) ?
  402. name.toLowerCase() :
  403. null;
  404. jQuery.expr.attrHandle[ name ] = fn;
  405. return ret;
  406. } :
  407. function( elem, name, isXML ) {
  408. return isXML ?
  409. undefined :
  410. elem[ jQuery.camelCase( "default-" + name ) ] ?
  411. name.toLowerCase() :
  412. null;
  413. };
  414. });
  415. // fix oldIE attroperties
  416. if ( !getSetInput || !getSetAttribute ) {
  417. jQuery.attrHooks.value = {
  418. set: function( elem, value, name ) {
  419. if ( jQuery.nodeName( elem, "input" ) ) {
  420. // Does not return so that setAttribute is also used
  421. elem.defaultValue = value;
  422. } else {
  423. // Use nodeHook if defined (#1954); otherwise setAttribute is fine
  424. return nodeHook && nodeHook.set( elem, value, name );
  425. }
  426. }
  427. };
  428. }
  429. // IE6/7 do not support getting/setting some attributes with get/setAttribute
  430. if ( !getSetAttribute ) {
  431. // Use this for any attribute in IE6/7
  432. // This fixes almost every IE6/7 issue
  433. nodeHook = {
  434. set: function( elem, value, name ) {
  435. // Set the existing or create a new attribute node
  436. var ret = elem.getAttributeNode( name );
  437. if ( !ret ) {
  438. elem.setAttributeNode(
  439. (ret = elem.ownerDocument.createAttribute( name ))
  440. );
  441. }
  442. ret.value = value += "";
  443. // Break association with cloned elements by also using setAttribute (#9646)
  444. return name === "value" || value === elem.getAttribute( name ) ?
  445. value :
  446. undefined;
  447. }
  448. };
  449. jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
  450. // Some attributes are constructed with empty-string values when not defined
  451. function( elem, name, isXML ) {
  452. var ret;
  453. return isXML ?
  454. undefined :
  455. (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
  456. ret.value :
  457. null;
  458. };
  459. jQuery.valHooks.button = {
  460. get: function( elem, name ) {
  461. var ret = elem.getAttributeNode( name );
  462. return ret && ret.specified ?
  463. ret.value :
  464. undefined;
  465. },
  466. set: nodeHook.set
  467. };
  468. // Set contenteditable to false on removals(#10429)
  469. // Setting to empty string throws an error as an invalid value
  470. jQuery.attrHooks.contenteditable = {
  471. set: function( elem, value, name ) {
  472. nodeHook.set( elem, value === "" ? false : value, name );
  473. }
  474. };
  475. // Set width and height to auto instead of 0 on empty string( Bug #8150 )
  476. // This is for removals
  477. jQuery.each([ "width", "height" ], function( i, name ) {
  478. jQuery.attrHooks[ name ] = {
  479. set: function( elem, value ) {
  480. if ( value === "" ) {
  481. elem.setAttribute( name, "auto" );
  482. return value;
  483. }
  484. }
  485. };
  486. });
  487. }
  488. // Some attributes require a special call on IE
  489. // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
  490. if ( !jQuery.support.hrefNormalized ) {
  491. // href/src property should get the full normalized URL (#10299/#12915)
  492. jQuery.each([ "href", "src" ], function( i, name ) {
  493. jQuery.propHooks[ name ] = {
  494. get: function( elem ) {
  495. return elem.getAttribute( name, 4 );
  496. }
  497. };
  498. });
  499. }
  500. if ( !jQuery.support.style ) {
  501. jQuery.attrHooks.style = {
  502. get: function( elem ) {
  503. // Return undefined in the case of empty string
  504. // Note: IE uppercases css property names, but if we were to .toLowerCase()
  505. // .cssText, that would destroy case senstitivity in URL's, like in "background"
  506. return elem.style.cssText || undefined;
  507. },
  508. set: function( elem, value ) {
  509. return ( elem.style.cssText = value + "" );
  510. }
  511. };
  512. }
  513. // Safari mis-reports the default selected property of an option
  514. // Accessing the parent's selectedIndex property fixes it
  515. if ( !jQuery.support.optSelected ) {
  516. jQuery.propHooks.selected = {
  517. get: function( elem ) {
  518. var parent = elem.parentNode;
  519. if ( parent ) {
  520. parent.selectedIndex;
  521. // Make sure that it also works with optgroups, see #5701
  522. if ( parent.parentNode ) {
  523. parent.parentNode.selectedIndex;
  524. }
  525. }
  526. return null;
  527. }
  528. };
  529. }
  530. jQuery.each([
  531. "tabIndex",
  532. "readOnly",
  533. "maxLength",
  534. "cellSpacing",
  535. "cellPadding",
  536. "rowSpan",
  537. "colSpan",
  538. "useMap",
  539. "frameBorder",
  540. "contentEditable"
  541. ], function() {
  542. jQuery.propFix[ this.toLowerCase() ] = this;
  543. });
  544. // IE6/7 call enctype encoding
  545. if ( !jQuery.support.enctype ) {
  546. jQuery.propFix.enctype = "encoding";
  547. }
  548. // Radios and checkboxes getter/setter
  549. jQuery.each([ "radio", "checkbox" ], function() {
  550. jQuery.valHooks[ this ] = {
  551. set: function( elem, value ) {
  552. if ( jQuery.isArray( value ) ) {
  553. return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
  554. }
  555. }
  556. };
  557. if ( !jQuery.support.checkOn ) {
  558. jQuery.valHooks[ this ].get = function( elem ) {
  559. // Support: Webkit
  560. // "" is returned instead of "on" if a value isn't specified
  561. return elem.getAttribute("value") === null ? "on" : elem.value;
  562. };
  563. }
  564. });