1/** 2 * Provides custom elements and functionality used with widgets 3 * 4 * @version 0.6.12 2012-07-28 5 * @author Gregor Kofler 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code 9 */ 10 11/** 12 * vxJS.widget.shared.overlay() 13 * vxJS.widget.shared.hiLite(text, node, className) 14 * vxJS.widget.shared.shadeTableRows(parameterObject) 15 * vxJS.widget.shared.list(parameterObject) 16 * 17 * @todo list: Safari doesn't follow keystrokes 18 */ 19 20"use strict"; 21 22vxJS.widget.shared = { 23 24 overlay: function() { 25 var that; 26 27 return function(config) { 28 var size, resizeListenerId, shown, elem, body = vxJS.dom.getBody(); 29 30 if(that) { 31 return that; 32 } 33 34 var resize = function() { 35 var sizeTo = vxJS.dom.getViewportSize(); 36 37 if(sizeTo.x <= size.x && sizeTo.y <= size.y) { 38 return; 39 } 40 41 size = sizeTo; 42 vxJS.dom.setElementSize(elem, size); 43 }; 44 45 var show = function() { 46 if(shown || !body) { 47 return; 48 } 49 50 shown = true; 51 52 if(!elem) { 53 elem = "div".setProp("class", "vxJS_overlay").create(); 54 vxJS.dom.setElementPosition(elem, new Coord()); 55 56 body.appendChild(elem); // IE requires attached element to check properties 57 elem.style.position = vxJS.dom.allowsFixedPosition() ? "fixed" : "absolute"; 58 } 59 60 else { 61 body.appendChild(elem); 62 } 63 size = vxJS.dom.getViewportSize(); 64 vxJS.dom.setElementSize(elem, size); 65 66 resizeListenerId = vxJS.event.addListener(window, "resize", resize); 67 }; 68 69 var hide = function() { 70 if(!shown || !elem) { 71 return; 72 } 73 74 shown = false; 75 vxJS.event.removeListener(resizeListenerId); 76 elem = body.removeChild(elem); 77 }; 78 79 that = { 80 show: show, 81 hide: hide 82 }; 83 84 return that; 85 }; 86 }(), 87 88 /** 89 * hilight text beneath a given node 90 */ 91 hiLite: function(text, node, cN) { 92 93 var rex = new RegExp(text, "gi"), fixRex = new RegExp("^" + text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i"), 94 chunks, hits, frag = document.createDocumentFragment(), i; 95 96 if(!cN) { cN = "hiLite"; } 97 if(!node) { node = document; } 98 99 vxJS.dom.walk(node, function(n) { 100 if(n.nodeType !== 3) { 101 return; 102 } 103 104 hits = n.nodeValue.match(rex); 105 106 if(hits && hits.length) { 107 108 chunks = n.nodeValue.split(rex); 109 110 if(chunks.length < 2) { 111 if(fixRex.test(n.nodeValue)) { 112 frag.appendChild("span".setProp("class", cN).create(hits[0])); 113 frag.appendChild(document.createTextNode(chunks[0])); 114 } 115 else { 116 frag.appendChild(document.createTextNode(chunks[0])); 117 frag.appendChild("span".setProp("class", cN).create(hits[0])); 118 } 119 } 120 else { 121 for(i = 0; i < chunks.length-1; ++i) { 122 frag.appendChild(document.createTextNode(chunks[i])); 123 frag.appendChild("span".setProp("class", cN).create(hits.shift())); 124 } 125 frag.appendChild(document.createTextNode(chunks[i])); 126 } 127 n.parentNode.replaceChild(frag, n); 128 } 129 }); 130 }, 131 132 /** 133 * shade table rows by assigning alternating class names 134 */ 135 shadeTableRows: function(param) { 136 var t, r, c, i, j, l; 137 if(!param || !(t = param.element)) { 138 return; 139 } 140 141 if (t.nodeName.toUpperCase() !== "TBODY") { 142 if (!t.tBodies || !(t = t.tBodies[0])) { 143 return; 144 } 145 } 146 if(!(r = t.rows)) { 147 return; 148 } 149 c = param.classNames && param.classNames.length && param.classNames.length > 1 ? param.classNames : ["row0", "row1"]; 150 151 for(i = 0, j = 0, l = r.length; l--; ++j) { 152 if(r[j].style.display !== "none") { 153 r[j].className = [r[j].className.replace(new RegExp("(^| )(" + c.join("|") +")( |$)"), ""), c[i++ % c.length]].join(" "); 154 } 155 } 156 }, 157 158 /** 159 * a list widget, used with vxJS.widget.autoSuggest(), vxJS.widget.queryPopup(), etc. 160 * 161 * served events: "choose", "toggle", "cancel" 162 */ 163 list: function(param) { 164 param = param || {}; 165 166 var ul = "ul".setProp("class", param.className || "vxJS_list").create(), 167 entries, multiple = param.multiple || false, selected = [], current, that = {}, 168 kc, kdFlag; 169 170 ul.style.position = "relative"; 171 172 var setCurrent = function(n) { 173 if(current === n) { 174 return; 175 } 176 if(current) { 177 vxJS.dom.removeClassName(current, "current"); 178 } 179 vxJS.dom.addClassName(n, "current"); 180 current = n; 181 182 if(!multiple) { 183 selected[0] = n; 184 } 185 }; 186 187 var focus = function() { 188 ul.tabIndex = -1; 189 ul.focus(); 190 }; 191
192 var toggleSelected = function(n) { 193 var i; 194 if(!multiple) { 195 return; 196 } 197 for(i = selected.length; i--;) { 198 if(selected[i] === n) { 199 selected.splice(i, 1); 200 n.className = n.className.replace(/([ ]?selected)/, ""); 201 vxJS.serve(that, "toggle"); 202 return; 203 } 204 } 205 n.className += n.className ? " selected" : "selected"; 206 selected.push(n); 207 vxJS.serve(that, "toggle"); 208 }; 209 210 var scrollIn = function() { 211 var d = vxJS.dom.getElementOffset(current, ul).y, 212 liH = d + vxJS.dom.getElementSize(current).y, 213 ulH = vxJS.dom.getElementSize(ul).y; 214 215 if(d < ul.scrollTop) { 216 ul.scrollTop = d; 217 } 218 219 else if(liH > ulH + ul.scrollTop) { 220 ul.scrollTop = liH - ulH; 221 } 222 }; 223 224 var hiLite = function(n) { 225 if(n !== ul) { 226 setCurrent(n.nodeName.toUpperCase() !== "LI" ? vxJS.dom.getParentElement(n, "li") : n); 227 } 228 }; 229 230 var findEntry = function(n) { 231 var i; 232 for(i = entries.length; i--;) { 233 if(entries[i].elem === n) { 234 return entries[i]; 235 } 236 } 237 }; 238 239 var fill = function(newEntries) { 240 var i; 241 entries = newEntries || []; 242 243 if(!entries.length) { 244 ul.style.display = "none"; 245 return; 246 } 247 248 vxJS.dom.deleteChildNodes(ul); 249 for(i = 0; i < entries.length; ++i) { 250 entries[i].elem = "li".create(entries[i].elements ? vxJS.dom.parse(entries[i].elements) : entries[i].text); 251 entries[i].elem.style.position = "relative"; 252 ul.appendChild(entries[i].elem); 253 } 254 255 ul.style.display = ""; 256 setCurrent(ul.firstChild); 257 scrollIn(); 258 }; 259 260 var keypress = function(e) { 261 if(!kdFlag) { 262 switch (kc) { 263 case 38: 264 that.up(); 265 break; 266 case 40: 267 that.down(); 268 break; 269 } 270 } 271 kdFlag = false; 272 vxJS.event.preventDefault(e); 273 }; 274 275 var mousedown = function() { 276 if(!param.hoverSelect) { 277 hiLite(this); 278 } 279 if(this !== ul) { 280 vxJS.event.serve(that, "choose"); 281 } 282 }; 283 284 var click = function() { 285 if(this !== ul) { 286 toggleSelected(this.nodeName.toUpperCase() !== "LI" ? vxJS.dom.getParentElement(this, "li") : this); 287 } 288 }; 289 290 var keydown = function(e) { 291 292 kdFlag = true; 293 kc = e.keyCode; 294 295 switch (kc) { 296 case 13: 297 vxJS.event.serve(that, "choose"); break; 298 case 27: 299 vxJS.event.serve(that, "cancel"); break; 300 case 38: 301 that.up(); break; 302 case 40: 303 that.down(); break; 304 case 36: 305 that.first(); break; 306 case 35: 307 that.last(); break; 308 case 32: 309 toggleSelected(current); break; 310 } 311 vxJS.event.preventDefault(e); 312 }; 313 314 vxJS.event.addListener(ul, "mousedown", mousedown); 315 vxJS.event.addListener(ul, "click", click); 316 vxJS.event.addListener(ul, "keydown", keydown); 317 vxJS.event.addListener(ul, "keypress", keypress); 318 319 vxJS.event.addMousewheelListener(ul, function(e) { that[vxJS.event.getMousewheelDirection(e)](); }); 320 321 if(param.hoverSelect) { 322 vxJS.event.addListener(ul, "mouseover", function() { 323 hiLite(this); 324 } 325 ); 326 } 327 fill(param.entries); 328 329 /** 330 * public properties and functions 331 */ 332 that.getSelected = function() { 333 var s = [], i; 334 if(selected.length) { 335 for(i = 0; i < selected.length; ++i) { 336 s.push(findEntry(selected[i])); 337 } 338 return s; 339 } 340 }; 341 342 that.up = function() { 343 if(current === ul.firstChild) { 344 return; 345 } 346 if(!current && ul.lastChild) { 347 setCurrent(ul.lastChild); 348 } 349 else { 350 setCurrent(current.previousSibling); 351 } 352 scrollIn(); 353 }; 354 355 that.down = function() { 356 if(current === ul.lastChild) { 357 return; 358 } 359 if(!current && ul.firstChild) { 360 setCurrent(ul.firstChild); 361 } 362 else { 363 setCurrent(current.nextSibling); 364 } 365 scrollIn(); 366 }; 367 368 that.first = function() { 369 if(current === ul.firstChild) { 370 return; 371 } 372 setCurrent(ul.firstChild); 373 scrollIn(); 374 }; 375 376 that.last = function() { 377 if(current === ul.lastChild) { 378 return; 379 } 380 setCurrent(ul.lastChild); 381 scrollIn(); 382 }; 383 384 that.getRows = function() { return entries ? entries.length : 0; }; 385 that.focus = focus; 386 that.fill = fill; 387 that.element = ul; 388 389 return that; 390 } 391};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.