1 /** 2 * @fileOverview dom-data 3 * @author lifesinger@gmail.com,yiminghe@gmail.com 4 */ 5 KISSY.add('dom/data', function (S, DOM, undefined) { 6 7 var win = S.Env.host, 8 EXPANDO = '__ks_data_' + S.now(), // 让每一份 kissy 的 expando 都不同 9 dataCache = { }, // 存储 node 节点的 data 10 winDataCache = { }; // 避免污染全局 11 12 13 // The following elements throw uncatchable exceptions if you 14 // attempt to add expando properties to them. 15 var noData = { 16 }; 17 noData['applet'] = 1; 18 noData['object'] = 1; 19 noData['embed'] = 1; 20 21 var commonOps = { 22 hasData:function (cache, name) { 23 if (cache) { 24 if (name !== undefined) { 25 if (name in cache) { 26 return true; 27 } 28 } else if (!S.isEmptyObject(cache)) { 29 return true; 30 } 31 } 32 return false; 33 } 34 }; 35 36 var objectOps = { 37 hasData:function (ob, name) { 38 // 只判断当前窗口,iframe 窗口内数据直接放入全局变量 39 if (ob == win) { 40 return objectOps.hasData(winDataCache, name); 41 } 42 // 直接建立在对象内 43 var thisCache = ob[EXPANDO]; 44 return commonOps.hasData(thisCache, name); 45 }, 46 47 data:function (ob, name, value) { 48 if (ob == win) { 49 return objectOps.data(winDataCache, name, value); 50 } 51 var cache = ob[EXPANDO]; 52 if (value !== undefined) { 53 cache = ob[EXPANDO] = ob[EXPANDO] || {}; 54 cache[name] = value; 55 } else { 56 if (name !== undefined) { 57 return cache && cache[name]; 58 } else { 59 cache = ob[EXPANDO] = ob[EXPANDO] || {}; 60 return cache; 61 } 62 } 63 }, 64 removeData:function (ob, name) { 65 if (ob == win) { 66 return objectOps.removeData(winDataCache, name); 67 } 68 var cache = ob[EXPANDO]; 69 if (name !== undefined) { 70 delete cache[name]; 71 if (S.isEmptyObject(cache)) { 72 objectOps.removeData(ob); 73 } 74 } else { 75 try { 76 // ob maybe window in iframe 77 // ie will throw error 78 delete ob[EXPANDO]; 79 } catch (e) { 80 ob[EXPANDO] = undefined; 81 } 82 } 83 } 84 }; 85 86 var domOps = { 87 hasData:function (elem, name) { 88 var key = elem[EXPANDO]; 89 if (!key) { 90 return false; 91 } 92 var thisCache = dataCache[key]; 93 return commonOps.hasData(thisCache, name); 94 }, 95 96 data:function (elem, name, value) { 97 if (noData[elem.nodeName.toLowerCase()]) { 98 return undefined; 99 } 100 var key = elem[EXPANDO], cache; 101 if (!key) { 102 // 根本不用附加属性 103 if (name !== undefined && 104 value === undefined) { 105 return undefined; 106 } 107 // 节点上关联键值也可以 108 key = elem[EXPANDO] = S.guid(); 109 } 110 cache = dataCache[key]; 111 if (value !== undefined) { 112 // 需要新建 113 cache = dataCache[key] = dataCache[key] || {}; 114 cache[name] = value; 115 } else { 116 if (name !== undefined) { 117 return cache && cache[name]; 118 } else { 119 // 需要新建 120 cache = dataCache[key] = dataCache[key] || {}; 121 return cache; 122 } 123 } 124 }, 125 126 removeData:function (elem, name) { 127 var key = elem[EXPANDO], cache; 128 if (!key) { 129 return; 130 } 131 cache = dataCache[key]; 132 if (name !== undefined) { 133 delete cache[name]; 134 if (S.isEmptyObject(cache)) { 135 domOps.removeData(elem); 136 } 137 } else { 138 delete dataCache[key]; 139 try { 140 delete elem[EXPANDO]; 141 } catch (e) { 142 elem[EXPANDO] = undefined; 143 //S.log("delete expando error : "); 144 //S.log(e); 145 } 146 if (elem.removeAttribute) { 147 elem.removeAttribute(EXPANDO); 148 } 149 } 150 } 151 }; 152 153 154 S.mix(DOM, 155 /** 156 * @lends DOM 157 */ 158 { 159 160 __EXPANDO:EXPANDO, 161 162 /** 163 * Determine whether an element has any data or specified data name associated with it. 164 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements 165 * @param {String} [name] A string naming the piece of data to set. 166 * @returns {Boolean} 167 */ 168 hasData:function (selector, name) { 169 var ret = false, 170 elems = DOM.query(selector); 171 for (var i = 0; i < elems.length; i++) { 172 var elem = elems[i]; 173 if (elem.nodeType) { 174 ret = domOps.hasData(elem, name); 175 } else { 176 ret = objectOps.hasData(elem, name); 177 } 178 if (ret) { 179 return ret; 180 } 181 } 182 return ret; 183 }, 184 185 /** 186 * If name set and data unset Store arbitrary data associated with the specified element. Returns undefined. 187 * or 188 * If name set and data unset returns value at named data store for the element 189 * or 190 * If name unset and data unset returns the full data store for the element. 191 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements 192 * @param {String} [name] A string naming the piece of data to set. 193 * @param [data] The new data value. 194 * @returns {Object|undefined} 195 */ 196 data:function (selector, name, data) { 197 198 var elems = DOM.query(selector), elem = elems[0]; 199 200 // supports hash 201 if (S.isPlainObject(name)) { 202 for (var k in name) { 203 DOM.data(elems, k, name[k]); 204 } 205 return undefined; 206 } 207 208 // getter 209 if (data === undefined) { 210 if (elem) { 211 if (elem.nodeType) { 212 return domOps.data(elem, name, data); 213 } else { 214 return objectOps.data(elem, name, data); 215 } 216 } 217 } 218 // setter 219 else { 220 for (var i = elems.length - 1; i >= 0; i--) { 221 elem = elems[i]; 222 if (elem.nodeType) { 223 domOps.data(elem, name, data); 224 } else { 225 objectOps.data(elem, name, data); 226 } 227 } 228 } 229 return undefined; 230 }, 231 232 /** 233 * Remove a previously-stored piece of data from matched elements. 234 * or 235 * Remove all data from matched elements if name unset. 236 * @param {HTMLElement[]|String|HTMLElement} selector Matched elements 237 * @param {String} [name] A string naming the piece of data to delete. 238 */ 239 removeData:function (selector, name) { 240 var els = DOM.query(selector), elem, i; 241 for (i = els.length - 1; i >= 0; i--) { 242 elem = els[i]; 243 if (elem.nodeType) { 244 domOps.removeData(elem, name); 245 } else { 246 objectOps.removeData(elem, name); 247 } 248 } 249 } 250 }); 251 252 return DOM; 253 254 }, { 255 requires:["./base"] 256 }); 257 /** 258 * 承玉:2011-05-31 259 * - 分层 ,节点和普通对象分开处理 260 **/