1/* 2--- 3name: Picker 4description: Creates a Picker, which can be used for anything 5authors: Arian Stolwijk 6requires: [Core/Element.Dimensions, Core/Fx.Tween, Core/Fx.Transitions] 7provides: Picker 8... 9*/ 10 11 12var Picker = new Class({ 13 14 Implements: [Options, Events], 15 16 options: {/* 17 onShow: function(){}, 18 onOpen: function(){}, 19 onHide: function(){}, 20 onClose: function(){},*/ 21 22 pickerClass: 'datepicker', 23 inject: null, 24 animationDuration: 400, 25 useFadeInOut: true, 26 positionOffset: {x: 0, y: 0}, 27 pickerPosition: 'bottom', 28 draggable: true, 29 showOnInit: true, 30 columns: 1, 31 footer: false 32 }, 33 34 initialize: function(options){ 35 this.setOptions(options); 36 this.constructPicker(); 37 if (this.options.showOnInit) this.show(); 38 }, 39 40 constructPicker: function(){ 41 var options = this.options; 42 43 var picker = this.picker = new Element('div', { 44 'class': options.pickerClass, 45 styles: { 46 left: 0, 47 top: 0, 48 display: 'none', 49 opacity: 0 50 } 51 }).inject(options.inject || document.body); 52 picker.addClass('column_' + options.columns); 53 54 if (options.useFadeInOut){ 55 picker.set('tween', { 56 duration: options.animationDuration, 57 link: 'cancel' 58 }); 59 } 60 61 // Build the header 62 var header = this.header = new Element('div.header').inject(picker); 63 64 var title = this.title = new Element('div.title').inject(header); 65 var titleID = this.titleID = 'pickertitle-' + String.uniqueID(); 66 this.titleText = new Element('div', { 67 'role': 'heading', 68 'class': 'titleText', 69 'id': titleID, 70 'aria-live': 'assertive', 71 'aria-atomic': 'true' 72 }).inject(title); 73 74 this.closeButton = new Element('div.closeButton[text=x][role=button]') 75 .addEvent('click', this.close.pass(false, this)) 76 .inject(header); 77 78 // Build the body of the picker 79 var body = this.body = new Element('div.body').inject(picker); 80 81 if (options.footer){ 82 this.footer = new Element('div.footer').inject(picker); 83 picker.addClass('footer'); 84 } 85 86 // oldContents and newContents are used to slide from the old content to a new one. 87 var slider = this.slider = new Element('div.slider', { 88 styles: { 89 position: 'absolute', 90 top: 0, 91 left: 0 92 } 93 }).set('tween', { 94 duration: options.animationDuration, 95 transition: Fx.Transitions.Quad.easeInOut 96 }).inject(body); 97 98 this.newContents = new Element('div', { 99 styles: { 100 position: 'absolute', 101 top: 0, 102 left: 0 103 } 104 }).inject(slider); 105 106 this.oldContents = new Element('div', { 107 styles: { 108 position: 'absolute', 109 top: 0 110 } 111 }).inject(slider); 112 113 this.originalColumns = options.columns; 114 this.setColumns(options.columns); 115 116 // IFrameShim for select fields in IE 117 var shim = this.shim = window['IframeShim'] ? new IframeShim(picker) : null; 118 119 // Dragging 120 if (options.draggable && typeOf(picker.makeDraggable) == 'function'){ 121 this.dragger = picker.makeDraggable(shim ? { 122 onDrag: shim.position.bind(shim) 123 } : null); 124 picker.setStyle('cursor', 'move'); 125 } 126 }, 127 128 open: function(noFx){ 129 if (this.opened == true) return this; 130 this.opened = true; 131 var self = this, 132 picker = this.picker.setStyle('display', 'block').set('aria-hidden', 'false') 133 if (this.shim) this.shim.show(); 134 this.fireEvent('open'); 135 if (this.options.useFadeInOut && !noFx){ 136 picker.get('tween').start('opacity', 1).chain(function(){ 137 self.fireEvent('show'); 138 this.callChain(); 139 }); 140 } else { 141 picker.setStyle('opacity', 1); 142 this.fireEvent('show'); 143 } 144 if(this.options.pickerPosition == 'top') { 145 var coordinates = this.picker.getCoordinates(); 146 147 this.picker.setStyles({ 148 top: coordinates.top - coordinates.height, 149 }); 150 } 151 return this; 152 }, 153 154 show: function(){ 155 return this.open(true); 156 }, 157 158 close: function(noFx){ 159 if (this.opened == false) return this; 160 this.opened = false; 161 this.fireEvent('close'); 162 var self = this, picker = this.picker, hide = function(){ 163 picker.setStyle('display', 'none').set('aria-hidden', 'true'); 164 if (self.shim) self.shim.hide(); 165 self.fireEvent('hide'); 166 }; 167 if (this.options.useFadeInOut && !noFx){ 168 picker.get('tween').start('opacity', 0).chain(hide); 169 } else { 170 picker.setStyle('opacity', 0); 171 hide(); 172 } 173 return this; 174 }, 175 176 hide: function(){ 177 return this.close(true); 178 }, 179 180 toggle: function(){ 181 return this[this.opened == true ? 'close' : 'open'](); 182 }, 183 184 destroy: function(){ 185 this.picker.destroy(); 186 if (this.shim) this.shim.destroy(); 187 }, 188 189 position: function(x, y){ 190 var offset = this.options.positionOffset, 191 scroll = document.getScroll(), 192 size = document.getSize(), 193 pickersize = this.picker.getSize(); 194 195 if (typeOf(x) == 'element'){ 196 var element = x, 197 where = y || this.options.pickerPosition; 198 199 var elementCoords = element.getCoordinates(); 200 201 x = (where == 'left') ? elementCoords.left - pickersize.x 202 : (where == 'bottom' || where == 'top') ? elementCoords.left 203 : elementCoords.right 204 y = (where == 'bottom') ? elementCoords.bottom 205 : (where == 'top') ? elementCoords.top - pickersize.y 206 : elementCoords.top; 207 } 208 209 x += offset.x * ((where && where == 'left') ? -1 : 1); 210 y += offset.y * ((where && where == 'top') ? -1: 1); 211 212 if ((x + pickersize.x) > (size.x + scroll.x)) x = (size.x + scroll.x) - pickersize.x; 213 if ((y + pickersize.y) > (size.y + scroll.y)) y = (size.y + scroll.y) - pickersize.y;
214 if (x < 0) x = 0; 215 if (y < 0) y = 0; 216 217 this.picker.setStyles({ 218 left: x, 219 top: y 220 }); 221 if (this.shim) this.shim.position(); 222 return this; 223 }, 224 225 setBodySize: function(){ 226 var bodysize = this.bodysize = this.body.getSize(); 227 228 this.slider.setStyles({ 229 width: 2 * bodysize.x, 230 height: bodysize.y 231 }); 232 this.oldContents.setStyles({ 233 left: bodysize.x, 234 width: bodysize.x, 235 height: bodysize.y 236 }); 237 this.newContents.setStyles({ 238 width: bodysize.x, 239 height: bodysize.y 240 }); 241 }, 242 243 setColumnContent: function(column, content){ 244 var columnElement = this.columns[column]; 245 if (!columnElement) return this; 246 247 var type = typeOf(content); 248 if (['string', 'number'].contains(type)) columnElement.set('text', content); 249 else columnElement.empty().adopt(content); 250 251 return this; 252 }, 253 254 setColumnsContent: function(content, fx){ 255 var old = this.columns; 256 this.columns = this.newColumns; 257 this.newColumns = old; 258 259 content.forEach(function(_content, i){ 260 this.setColumnContent(i, _content); 261 }, this); 262 return this.setContent(null, fx); 263 }, 264 265 setColumns: function(columns){ 266 var _columns = this.columns = new Elements, _newColumns = this.newColumns = new Elements; 267 for (var i = columns; i--;){ 268 _columns.push(new Element('div.column').addClass('column_' + (columns - i))); 269 _newColumns.push(new Element('div.column').addClass('column_' + (columns - i))); 270 } 271 272 var oldClass = 'column_' + this.options.columns, newClass = 'column_' + columns; 273 this.picker.removeClass(oldClass).addClass(newClass); 274 275 this.options.columns = columns; 276 return this; 277 }, 278 279 setContent: function(content, fx){ 280 if (content) return this.setColumnsContent([content], fx); 281 282 // swap contents so we can fill the newContents again and animate 283 var old = this.oldContents; 284 this.oldContents = this.newContents; 285 this.newContents = old; 286 this.newContents.empty(); 287 288 this.newContents.adopt(this.columns); 289 290 this.setBodySize(); 291 292 if (fx){ 293 this.fx(fx); 294 } else { 295 this.slider.setStyle('left', 0); 296 this.oldContents.setStyles({left: 0, opacity: 0}); 297 this.newContents.setStyles({left: 0, opacity: 1}); 298 } 299 return this; 300 }, 301 302 fx: function(fx){ 303 var oldContents = this.oldContents, 304 newContents = this.newContents, 305 slider = this.slider, 306 bodysize = this.bodysize; 307 if (fx == 'right'){ 308 oldContents.setStyles({left: 0, opacity: 1}); 309 newContents.setStyles({left: bodysize.x, opacity: 1}); 310 slider.setStyle('left', 0).tween('left', 0, -bodysize.x); 311 } else if (fx == 'left'){ 312 oldContents.setStyles({left: bodysize.x, opacity: 1}); 313 newContents.setStyles({left: 0, opacity: 1}); 314 slider.setStyle('left', -bodysize.x).tween('left', -bodysize.x, 0); 315 } else if (fx == 'fade'){ 316 slider.setStyle('left', 0); 317 oldContents.setStyle('left', 0).set('tween', { 318 duration: this.options.animationDuration / 2 319 }).tween('opacity', 1, 0).get('tween').chain(function(){ 320 oldContents.setStyle('left', bodysize.x); 321 }); 322 newContents.setStyles({opacity: 0, left: 0}).set('tween', { 323 duration: this.options.animationDuration 324 }).tween('opacity', 0, 1); 325 } 326 }, 327 328 toElement: function(){ 329 return this.picker; 330 }, 331 332 setTitle: function(content, fn){ 333 if (!fn) fn = Function.from; 334 this.titleText.empty().adopt( 335 Array.from(content).map(function(item, i){ 336 return typeOf(item) == 'element' 337 ? item 338 : new Element('div.column', {text: fn(item, this.options)}).addClass('column_' + (i + 1)); 339 }, this) 340 ); 341 return this; 342 }, 343 344 setTitleEvent: function(fn){ 345 this.titleText.removeEvents('click'); 346 if (fn) this.titleText.addEvent('click', fn); 347 this.titleText.setStyle('cursor', fn ? 'pointer' : ''); 348 return this; 349 } 350 351});
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.