Copybara bot | be50d49 | 2023-11-30 00:16:42 +0100 | [diff] [blame] | 1 | define( [ |
| 2 | "../core", |
| 3 | "../core/camelCase", |
| 4 | "../var/rnothtmlwhite", |
| 5 | "./var/acceptData" |
| 6 | ], function( jQuery, camelCase, rnothtmlwhite, acceptData ) { |
| 7 | |
| 8 | "use strict"; |
| 9 | |
| 10 | function Data() { |
| 11 | this.expando = jQuery.expando + Data.uid++; |
| 12 | } |
| 13 | |
| 14 | Data.uid = 1; |
| 15 | |
| 16 | Data.prototype = { |
| 17 | |
| 18 | cache: function( owner ) { |
| 19 | |
| 20 | // Check if the owner object already has a cache |
| 21 | var value = owner[ this.expando ]; |
| 22 | |
| 23 | // If not, create one |
| 24 | if ( !value ) { |
| 25 | value = {}; |
| 26 | |
| 27 | // We can accept data for non-element nodes in modern browsers, |
| 28 | // but we should not, see #8335. |
| 29 | // Always return an empty object. |
| 30 | if ( acceptData( owner ) ) { |
| 31 | |
| 32 | // If it is a node unlikely to be stringify-ed or looped over |
| 33 | // use plain assignment |
| 34 | if ( owner.nodeType ) { |
| 35 | owner[ this.expando ] = value; |
| 36 | |
| 37 | // Otherwise secure it in a non-enumerable property |
| 38 | // configurable must be true to allow the property to be |
| 39 | // deleted when data is removed |
| 40 | } else { |
| 41 | Object.defineProperty( owner, this.expando, { |
| 42 | value: value, |
| 43 | configurable: true |
| 44 | } ); |
| 45 | } |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | return value; |
| 50 | }, |
| 51 | set: function( owner, data, value ) { |
| 52 | var prop, |
| 53 | cache = this.cache( owner ); |
| 54 | |
| 55 | // Handle: [ owner, key, value ] args |
| 56 | // Always use camelCase key (gh-2257) |
| 57 | if ( typeof data === "string" ) { |
| 58 | cache[ camelCase( data ) ] = value; |
| 59 | |
| 60 | // Handle: [ owner, { properties } ] args |
| 61 | } else { |
| 62 | |
| 63 | // Copy the properties one-by-one to the cache object |
| 64 | for ( prop in data ) { |
| 65 | cache[ camelCase( prop ) ] = data[ prop ]; |
| 66 | } |
| 67 | } |
| 68 | return cache; |
| 69 | }, |
| 70 | get: function( owner, key ) { |
| 71 | return key === undefined ? |
| 72 | this.cache( owner ) : |
| 73 | |
| 74 | // Always use camelCase key (gh-2257) |
| 75 | owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; |
| 76 | }, |
| 77 | access: function( owner, key, value ) { |
| 78 | |
| 79 | // In cases where either: |
| 80 | // |
| 81 | // 1. No key was specified |
| 82 | // 2. A string key was specified, but no value provided |
| 83 | // |
| 84 | // Take the "read" path and allow the get method to determine |
| 85 | // which value to return, respectively either: |
| 86 | // |
| 87 | // 1. The entire cache object |
| 88 | // 2. The data stored at the key |
| 89 | // |
| 90 | if ( key === undefined || |
| 91 | ( ( key && typeof key === "string" ) && value === undefined ) ) { |
| 92 | |
| 93 | return this.get( owner, key ); |
| 94 | } |
| 95 | |
| 96 | // When the key is not a string, or both a key and value |
| 97 | // are specified, set or extend (existing objects) with either: |
| 98 | // |
| 99 | // 1. An object of properties |
| 100 | // 2. A key and value |
| 101 | // |
| 102 | this.set( owner, key, value ); |
| 103 | |
| 104 | // Since the "set" path can have two possible entry points |
| 105 | // return the expected data based on which path was taken[*] |
| 106 | return value !== undefined ? value : key; |
| 107 | }, |
| 108 | remove: function( owner, key ) { |
| 109 | var i, |
| 110 | cache = owner[ this.expando ]; |
| 111 | |
| 112 | if ( cache === undefined ) { |
| 113 | return; |
| 114 | } |
| 115 | |
| 116 | if ( key !== undefined ) { |
| 117 | |
| 118 | // Support array or space separated string of keys |
| 119 | if ( Array.isArray( key ) ) { |
| 120 | |
| 121 | // If key is an array of keys... |
| 122 | // We always set camelCase keys, so remove that. |
| 123 | key = key.map( camelCase ); |
| 124 | } else { |
| 125 | key = camelCase( key ); |
| 126 | |
| 127 | // If a key with the spaces exists, use it. |
| 128 | // Otherwise, create an array by matching non-whitespace |
| 129 | key = key in cache ? |
| 130 | [ key ] : |
| 131 | ( key.match( rnothtmlwhite ) || [] ); |
| 132 | } |
| 133 | |
| 134 | i = key.length; |
| 135 | |
| 136 | while ( i-- ) { |
| 137 | delete cache[ key[ i ] ]; |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | // Remove the expando if there's no more data |
| 142 | if ( key === undefined || jQuery.isEmptyObject( cache ) ) { |
| 143 | |
| 144 | // Support: Chrome <=35 - 45 |
| 145 | // Webkit & Blink performance suffers when deleting properties |
| 146 | // from DOM nodes, so set to undefined instead |
| 147 | // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) |
| 148 | if ( owner.nodeType ) { |
| 149 | owner[ this.expando ] = undefined; |
| 150 | } else { |
| 151 | delete owner[ this.expando ]; |
| 152 | } |
| 153 | } |
| 154 | }, |
| 155 | hasData: function( owner ) { |
| 156 | var cache = owner[ this.expando ]; |
| 157 | return cache !== undefined && !jQuery.isEmptyObject( cache ); |
| 158 | } |
| 159 | }; |
| 160 | |
| 161 | return Data; |
| 162 | } ); |