ui.js 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. */
  4. var UI = {};
  5. UI.Element = function ( dom ) {
  6. this.dom = dom;
  7. };
  8. UI.Element.prototype = {
  9. add: function () {
  10. for ( var i = 0; i < arguments.length; i ++ ) {
  11. var argument = arguments[ i ];
  12. if ( argument instanceof UI.Element ) {
  13. this.dom.appendChild( argument.dom );
  14. } else {
  15. console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' );
  16. }
  17. }
  18. return this;
  19. },
  20. remove: function () {
  21. for ( var i = 0; i < arguments.length; i ++ ) {
  22. var argument = arguments[ i ];
  23. if ( argument instanceof UI.Element ) {
  24. this.dom.removeChild( argument.dom );
  25. } else {
  26. console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' );
  27. }
  28. }
  29. return this;
  30. },
  31. clear: function () {
  32. while ( this.dom.children.length ) {
  33. this.dom.removeChild( this.dom.lastChild );
  34. }
  35. },
  36. setId: function ( id ) {
  37. this.dom.id = id;
  38. return this;
  39. },
  40. getId: function ( id ) {
  41. return this.dom.id;
  42. },
  43. setClass: function ( name ) {
  44. this.dom.className = name;
  45. return this;
  46. },
  47. addClass: function ( name ) {
  48. this.dom.classList.add( name );
  49. return this;
  50. },
  51. removeClass: function ( name ) {
  52. this.dom.classList.remove( name );
  53. return this;
  54. },
  55. setStyle: function ( style, array ) {
  56. for ( var i = 0; i < array.length; i ++ ) {
  57. this.dom.style[ style ] = array[ i ];
  58. }
  59. return this;
  60. },
  61. setDisabled: function ( value ) {
  62. this.dom.disabled = value;
  63. return this;
  64. },
  65. setTextContent: function ( value ) {
  66. this.dom.textContent = value;
  67. return this;
  68. }
  69. };
  70. // properties
  71. var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft',
  72. 'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
  73. 'background', 'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ];
  74. properties.forEach( function ( property ) {
  75. var method = 'set' + property.substr( 0, 1 ).toUpperCase() + property.substr( 1, property.length );
  76. UI.Element.prototype[ method ] = function () {
  77. this.setStyle( property, arguments );
  78. return this;
  79. };
  80. } );
  81. // events
  82. var events = [ 'KeyUp', 'KeyDown', 'MouseOver', 'MouseOut', 'Click', 'DblClick', 'Change' ];
  83. events.forEach( function ( event ) {
  84. var method = 'on' + event;
  85. UI.Element.prototype[ method ] = function ( callback ) {
  86. this.dom.addEventListener( event.toLowerCase(), callback.bind( this ), false );
  87. return this;
  88. };
  89. } );
  90. // Span
  91. UI.Span = function () {
  92. UI.Element.call( this );
  93. this.dom = document.createElement( 'span' );
  94. return this;
  95. };
  96. UI.Span.prototype = Object.create( UI.Element.prototype );
  97. UI.Span.prototype.constructor = UI.Span;
  98. // Div
  99. UI.Div = function () {
  100. UI.Element.call( this );
  101. this.dom = document.createElement( 'div' );
  102. return this;
  103. };
  104. UI.Div.prototype = Object.create( UI.Element.prototype );
  105. UI.Div.prototype.constructor = UI.Div;
  106. // Row
  107. UI.Row = function () {
  108. UI.Element.call( this );
  109. var dom = document.createElement( 'div' );
  110. dom.className = 'Row';
  111. this.dom = dom;
  112. return this;
  113. };
  114. UI.Row.prototype = Object.create( UI.Element.prototype );
  115. UI.Row.prototype.constructor = UI.Row;
  116. // Panel
  117. UI.Panel = function () {
  118. UI.Element.call( this );
  119. var dom = document.createElement( 'div' );
  120. dom.className = 'Panel';
  121. this.dom = dom;
  122. return this;
  123. };
  124. UI.Panel.prototype = Object.create( UI.Element.prototype );
  125. UI.Panel.prototype.constructor = UI.Panel;
  126. // Text
  127. UI.Text = function ( text ) {
  128. UI.Element.call( this );
  129. var dom = document.createElement( 'span' );
  130. dom.className = 'Text';
  131. dom.style.cursor = 'default';
  132. dom.style.display = 'inline-block';
  133. dom.style.verticalAlign = 'middle';
  134. this.dom = dom;
  135. this.setValue( text );
  136. return this;
  137. };
  138. UI.Text.prototype = Object.create( UI.Element.prototype );
  139. UI.Text.prototype.constructor = UI.Text;
  140. UI.Text.prototype.getValue = function () {
  141. return this.dom.textContent;
  142. };
  143. UI.Text.prototype.setValue = function ( value ) {
  144. if ( value !== undefined ) {
  145. this.dom.textContent = value;
  146. }
  147. return this;
  148. };
  149. // Input
  150. UI.Input = function ( text ) {
  151. UI.Element.call( this );
  152. var scope = this;
  153. var dom = document.createElement( 'input' );
  154. dom.className = 'Input';
  155. dom.style.padding = '2px';
  156. dom.style.border = '1px solid transparent';
  157. dom.addEventListener( 'keydown', function ( event ) {
  158. event.stopPropagation();
  159. }, false );
  160. this.dom = dom;
  161. this.setValue( text );
  162. return this;
  163. };
  164. UI.Input.prototype = Object.create( UI.Element.prototype );
  165. UI.Input.prototype.constructor = UI.Input;
  166. UI.Input.prototype.getValue = function () {
  167. return this.dom.value;
  168. };
  169. UI.Input.prototype.setValue = function ( value ) {
  170. this.dom.value = value;
  171. return this;
  172. };
  173. // TextArea
  174. UI.TextArea = function () {
  175. UI.Element.call( this );
  176. var scope = this;
  177. var dom = document.createElement( 'textarea' );
  178. dom.className = 'TextArea';
  179. dom.style.padding = '2px';
  180. dom.spellcheck = false;
  181. dom.addEventListener( 'keydown', function ( event ) {
  182. event.stopPropagation();
  183. if ( event.keyCode === 9 ) {
  184. event.preventDefault();
  185. var cursor = dom.selectionStart;
  186. dom.value = dom.value.substring( 0, cursor ) + '\t' + dom.value.substring( cursor );
  187. dom.selectionStart = cursor + 1;
  188. dom.selectionEnd = dom.selectionStart;
  189. }
  190. }, false );
  191. this.dom = dom;
  192. return this;
  193. };
  194. UI.TextArea.prototype = Object.create( UI.Element.prototype );
  195. UI.TextArea.prototype.constructor = UI.TextArea;
  196. UI.TextArea.prototype.getValue = function () {
  197. return this.dom.value;
  198. };
  199. UI.TextArea.prototype.setValue = function ( value ) {
  200. this.dom.value = value;
  201. return this;
  202. };
  203. // Select
  204. UI.Select = function () {
  205. UI.Element.call( this );
  206. var scope = this;
  207. var dom = document.createElement( 'select' );
  208. dom.className = 'Select';
  209. dom.style.padding = '2px';
  210. this.dom = dom;
  211. return this;
  212. };
  213. UI.Select.prototype = Object.create( UI.Element.prototype );
  214. UI.Select.prototype.constructor = UI.Select;
  215. UI.Select.prototype.setMultiple = function ( boolean ) {
  216. this.dom.multiple = boolean;
  217. return this;
  218. };
  219. UI.Select.prototype.setOptions = function ( options ) {
  220. var selected = this.dom.value;
  221. while ( this.dom.children.length > 0 ) {
  222. this.dom.removeChild( this.dom.firstChild );
  223. }
  224. for ( var key in options ) {
  225. var option = document.createElement( 'option' );
  226. option.value = key;
  227. option.innerHTML = options[ key ];
  228. this.dom.appendChild( option );
  229. }
  230. this.dom.value = selected;
  231. return this;
  232. };
  233. UI.Select.prototype.getValue = function () {
  234. return this.dom.value;
  235. };
  236. UI.Select.prototype.setValue = function ( value ) {
  237. value = String( value );
  238. if ( this.dom.value !== value ) {
  239. this.dom.value = value;
  240. }
  241. return this;
  242. };
  243. // Checkbox
  244. UI.Checkbox = function ( boolean ) {
  245. UI.Element.call( this );
  246. var scope = this;
  247. var dom = document.createElement( 'input' );
  248. dom.className = 'Checkbox';
  249. dom.type = 'checkbox';
  250. this.dom = dom;
  251. this.setValue( boolean );
  252. return this;
  253. };
  254. UI.Checkbox.prototype = Object.create( UI.Element.prototype );
  255. UI.Checkbox.prototype.constructor = UI.Checkbox;
  256. UI.Checkbox.prototype.getValue = function () {
  257. return this.dom.checked;
  258. };
  259. UI.Checkbox.prototype.setValue = function ( value ) {
  260. if ( value !== undefined ) {
  261. this.dom.checked = value;
  262. }
  263. return this;
  264. };
  265. // Color
  266. UI.Color = function () {
  267. UI.Element.call( this );
  268. var scope = this;
  269. var dom = document.createElement( 'input' );
  270. dom.className = 'Color';
  271. dom.style.width = '64px';
  272. dom.style.height = '17px';
  273. dom.style.border = '0px';
  274. dom.style.padding = '2px';
  275. dom.style.backgroundColor = 'transparent';
  276. try {
  277. dom.type = 'color';
  278. dom.value = '#ffffff';
  279. } catch ( exception ) {}
  280. this.dom = dom;
  281. return this;
  282. };
  283. UI.Color.prototype = Object.create( UI.Element.prototype );
  284. UI.Color.prototype.constructor = UI.Color;
  285. UI.Color.prototype.getValue = function () {
  286. return this.dom.value;
  287. };
  288. UI.Color.prototype.getHexValue = function () {
  289. return parseInt( this.dom.value.substr( 1 ), 16 );
  290. };
  291. UI.Color.prototype.setValue = function ( value ) {
  292. this.dom.value = value;
  293. return this;
  294. };
  295. UI.Color.prototype.setHexValue = function ( hex ) {
  296. this.dom.value = '#' + ( '000000' + hex.toString( 16 ) ).slice( - 6 );
  297. return this;
  298. };
  299. // Number
  300. UI.Number = function ( number ) {
  301. UI.Element.call( this );
  302. var scope = this;
  303. var dom = document.createElement( 'input' );
  304. dom.className = 'Number';
  305. dom.value = '0.00';
  306. dom.addEventListener( 'keydown', function ( event ) {
  307. event.stopPropagation();
  308. if ( event.keyCode === 13 ) dom.blur();
  309. }, false );
  310. this.value = 0;
  311. this.min = - Infinity;
  312. this.max = Infinity;
  313. this.precision = 2;
  314. this.step = 1;
  315. this.unit = '';
  316. this.dom = dom;
  317. this.setValue( number );
  318. var changeEvent = document.createEvent( 'HTMLEvents' );
  319. changeEvent.initEvent( 'change', true, true );
  320. var distance = 0;
  321. var onMouseDownValue = 0;
  322. var pointer = [ 0, 0 ];
  323. var prevPointer = [ 0, 0 ];
  324. function onMouseDown( event ) {
  325. event.preventDefault();
  326. distance = 0;
  327. onMouseDownValue = scope.value;
  328. prevPointer = [ event.clientX, event.clientY ];
  329. document.addEventListener( 'mousemove', onMouseMove, false );
  330. document.addEventListener( 'mouseup', onMouseUp, false );
  331. }
  332. function onMouseMove( event ) {
  333. var currentValue = scope.value;
  334. pointer = [ event.clientX, event.clientY ];
  335. distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] );
  336. var value = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step;
  337. value = Math.min( scope.max, Math.max( scope.min, value ) );
  338. if ( currentValue !== value ) {
  339. scope.setValue( value );
  340. dom.dispatchEvent( changeEvent );
  341. }
  342. prevPointer = [ event.clientX, event.clientY ];
  343. }
  344. function onMouseUp( event ) {
  345. document.removeEventListener( 'mousemove', onMouseMove, false );
  346. document.removeEventListener( 'mouseup', onMouseUp, false );
  347. if ( Math.abs( distance ) < 2 ) {
  348. dom.focus();
  349. dom.select();
  350. }
  351. }
  352. function onTouchStart( event ) {
  353. if ( event.touches.length === 1 ) {
  354. distance = 0;
  355. onMouseDownValue = scope.value;
  356. prevPointer = [ event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ];
  357. document.addEventListener( 'touchmove', onTouchMove, false );
  358. document.addEventListener( 'touchend', onTouchEnd, false );
  359. }
  360. }
  361. function onTouchMove( event ) {
  362. var currentValue = scope.value;
  363. pointer = [ event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ];
  364. distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] );
  365. var value = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step;
  366. value = Math.min( scope.max, Math.max( scope.min, value ) );
  367. if ( currentValue !== value ) {
  368. scope.setValue( value );
  369. dom.dispatchEvent( changeEvent );
  370. }
  371. prevPointer = [ event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ];
  372. }
  373. function onTouchEnd( event ) {
  374. if ( event.touches.length === 0 ) {
  375. document.removeEventListener( 'touchmove', onTouchMove, false );
  376. document.removeEventListener( 'touchend', onTouchEnd, false );
  377. }
  378. }
  379. function onChange( event ) {
  380. scope.setValue( dom.value );
  381. }
  382. function onFocus( event ) {
  383. dom.style.backgroundColor = '';
  384. dom.style.cursor = '';
  385. }
  386. function onBlur( event ) {
  387. dom.style.backgroundColor = 'transparent';
  388. dom.style.cursor = 'col-resize';
  389. }
  390. onBlur();
  391. dom.addEventListener( 'mousedown', onMouseDown, false );
  392. dom.addEventListener( 'touchstart', onTouchStart, false );
  393. dom.addEventListener( 'change', onChange, false );
  394. dom.addEventListener( 'focus', onFocus, false );
  395. dom.addEventListener( 'blur', onBlur, false );
  396. return this;
  397. };
  398. UI.Number.prototype = Object.create( UI.Element.prototype );
  399. UI.Number.prototype.constructor = UI.Number;
  400. UI.Number.prototype.getValue = function () {
  401. return this.value;
  402. };
  403. UI.Number.prototype.setValue = function ( value ) {
  404. if ( value !== undefined ) {
  405. value = parseFloat( value );
  406. if ( value < this.min ) value = this.min;
  407. if ( value > this.max ) value = this.max;
  408. this.value = value;
  409. this.dom.value = value.toFixed( this.precision );
  410. if ( this.unit !== '' ) this.dom.value += ' ' + this.unit;
  411. }
  412. return this;
  413. };
  414. UI.Number.prototype.setPrecision = function ( precision ) {
  415. this.precision = precision;
  416. return this;
  417. };
  418. UI.Number.prototype.setStep = function ( step ) {
  419. this.step = step;
  420. return this;
  421. };
  422. UI.Number.prototype.setRange = function ( min, max ) {
  423. this.min = min;
  424. this.max = max;
  425. return this;
  426. };
  427. UI.Number.prototype.setUnit = function ( unit ) {
  428. this.unit = unit;
  429. return this;
  430. };
  431. // Integer
  432. UI.Integer = function ( number ) {
  433. UI.Element.call( this );
  434. var scope = this;
  435. var dom = document.createElement( 'input' );
  436. dom.className = 'Number';
  437. dom.value = '0';
  438. dom.addEventListener( 'keydown', function ( event ) {
  439. event.stopPropagation();
  440. }, false );
  441. this.value = 0;
  442. this.min = - Infinity;
  443. this.max = Infinity;
  444. this.step = 1;
  445. this.dom = dom;
  446. this.setValue( number );
  447. var changeEvent = document.createEvent( 'HTMLEvents' );
  448. changeEvent.initEvent( 'change', true, true );
  449. var distance = 0;
  450. var onMouseDownValue = 0;
  451. var pointer = [ 0, 0 ];
  452. var prevPointer = [ 0, 0 ];
  453. function onMouseDown( event ) {
  454. event.preventDefault();
  455. distance = 0;
  456. onMouseDownValue = scope.value;
  457. prevPointer = [ event.clientX, event.clientY ];
  458. document.addEventListener( 'mousemove', onMouseMove, false );
  459. document.addEventListener( 'mouseup', onMouseUp, false );
  460. }
  461. function onMouseMove( event ) {
  462. var currentValue = scope.value;
  463. pointer = [ event.clientX, event.clientY ];
  464. distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] );
  465. var value = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step;
  466. value = Math.min( scope.max, Math.max( scope.min, value ) ) | 0;
  467. if ( currentValue !== value ) {
  468. scope.setValue( value );
  469. dom.dispatchEvent( changeEvent );
  470. }
  471. prevPointer = [ event.clientX, event.clientY ];
  472. }
  473. function onMouseUp( event ) {
  474. document.removeEventListener( 'mousemove', onMouseMove, false );
  475. document.removeEventListener( 'mouseup', onMouseUp, false );
  476. if ( Math.abs( distance ) < 2 ) {
  477. dom.focus();
  478. dom.select();
  479. }
  480. }
  481. function onChange( event ) {
  482. scope.setValue( dom.value );
  483. }
  484. function onFocus( event ) {
  485. dom.style.backgroundColor = '';
  486. dom.style.cursor = '';
  487. }
  488. function onBlur( event ) {
  489. dom.style.backgroundColor = 'transparent';
  490. dom.style.cursor = 'col-resize';
  491. }
  492. onBlur();
  493. dom.addEventListener( 'mousedown', onMouseDown, false );
  494. dom.addEventListener( 'change', onChange, false );
  495. dom.addEventListener( 'focus', onFocus, false );
  496. dom.addEventListener( 'blur', onBlur, false );
  497. return this;
  498. };
  499. UI.Integer.prototype = Object.create( UI.Element.prototype );
  500. UI.Integer.prototype.constructor = UI.Integer;
  501. UI.Integer.prototype.getValue = function () {
  502. return this.value;
  503. };
  504. UI.Integer.prototype.setValue = function ( value ) {
  505. if ( value !== undefined ) {
  506. value = parseInt( value );
  507. this.value = value;
  508. this.dom.value = value;
  509. }
  510. return this;
  511. };
  512. UI.Integer.prototype.setStep = function ( step ) {
  513. this.step = parseInt( step );
  514. return this;
  515. };
  516. UI.Integer.prototype.setRange = function ( min, max ) {
  517. this.min = min;
  518. this.max = max;
  519. return this;
  520. };
  521. // Break
  522. UI.Break = function () {
  523. UI.Element.call( this );
  524. var dom = document.createElement( 'br' );
  525. dom.className = 'Break';
  526. this.dom = dom;
  527. return this;
  528. };
  529. UI.Break.prototype = Object.create( UI.Element.prototype );
  530. UI.Break.prototype.constructor = UI.Break;
  531. // HorizontalRule
  532. UI.HorizontalRule = function () {
  533. UI.Element.call( this );
  534. var dom = document.createElement( 'hr' );
  535. dom.className = 'HorizontalRule';
  536. this.dom = dom;
  537. return this;
  538. };
  539. UI.HorizontalRule.prototype = Object.create( UI.Element.prototype );
  540. UI.HorizontalRule.prototype.constructor = UI.HorizontalRule;
  541. // Button
  542. UI.Button = function ( value ) {
  543. UI.Element.call( this );
  544. var dom = document.createElement( 'button' );
  545. dom.className = 'Button';
  546. this.dom = dom;
  547. this.dom.textContent = value;
  548. return this;
  549. };
  550. UI.Button.prototype = Object.create( UI.Element.prototype );
  551. UI.Button.prototype.constructor = UI.Button;
  552. UI.Button.prototype.setLabel = function ( value ) {
  553. this.dom.textContent = value;
  554. return this;
  555. };
  556. // TabbedPanel
  557. UI.TabbedPanel = function ( ) {
  558. UI.Element.call( this );
  559. var dom = document.createElement('div');
  560. this.dom = dom;
  561. this.setClass( 'TabbedPanel' );
  562. this.tabs = [];
  563. this.panels = [];
  564. this.tabsDiv = new UI.Div();
  565. this.tabsDiv.setClass( 'Tabs' );
  566. this.panelsDiv = new UI.Div();
  567. this.panelsDiv.setClass( 'Panels' );
  568. this.add( this.tabsDiv );
  569. this.add( this.panelsDiv );
  570. this.selected = '';
  571. return this;
  572. }
  573. UI.TabbedPanel.prototype = Object.create( UI.Element.prototype );
  574. UI.TabbedPanel.prototype.constructor = UI.TabbedPanel;
  575. UI.TabbedPanel.prototype.select = function ( id ) {
  576. var tab;
  577. var panel;
  578. var scope = this;
  579. // Deselect current selection
  580. if ( this.selected && this.selected.length ) {
  581. tab = this.tabs.find( function ( item ) { return item.dom.id === scope.selected } );
  582. panel = this.panels.find( function ( item ) { return item.dom.id === scope.selected } );
  583. if ( tab ) {
  584. tab.removeClass( 'selected' );
  585. }
  586. if( panel ) {
  587. panel.setDisplay( 'none' );
  588. }
  589. }
  590. tab = this.tabs.find( function ( item ) { return item.dom.id === id } );
  591. panel = this.panels.find( function ( item ) { return item.dom.id === id } );
  592. if ( tab ) {
  593. tab.addClass( 'selected' );
  594. }
  595. if( panel ) {
  596. panel.setDisplay( '' );
  597. }
  598. this.selected = id;
  599. return this;
  600. }
  601. UI.TabbedPanel.prototype.addTab = function ( id, label, items ) {
  602. var tab = new UI.TabbedPanel.Tab( label, this );
  603. tab.setId( id );
  604. this.tabs.push( tab );
  605. this.tabsDiv.add( tab );
  606. var panel = new UI.Div();
  607. panel.setId( id );
  608. panel.add( items );
  609. panel.setDisplay( 'none' );
  610. this.panels.push( panel );
  611. this.panelsDiv.add( panel );
  612. this.select( id );
  613. }
  614. UI.TabbedPanel.Tab = function ( text, parent ) {
  615. UI.Text.call( this, text );
  616. this.parent = parent;
  617. this.setClass( 'Tab' );
  618. var scope = this;
  619. this.dom.addEventListener( 'click', function ( event ) {
  620. scope.parent.select( scope.dom.id );
  621. } )
  622. return this;
  623. }
  624. UI.TabbedPanel.Tab.prototype = Object.create( UI.Text.prototype );
  625. UI.TabbedPanel.Tab.prototype.constructor = UI.TabbedPanel.Tab;
  626. // Listbox
  627. UI.Listbox = function ( ) {
  628. UI.Element.call( this );
  629. var dom = document.createElement( 'div' );
  630. dom.className = 'Listbox';
  631. dom.tabIndex = 0;
  632. this.dom = dom;
  633. this.items = [];
  634. this.listitems = [];
  635. this.selectedIndex = 0;
  636. this.selectedValue = null;
  637. return this;
  638. }
  639. UI.Listbox.prototype = Object.create( UI.Element.prototype );
  640. UI.Listbox.prototype.constructor = UI.ListboxItem;
  641. UI.Listbox.prototype.setItems = function ( items ) {
  642. if ( Array.isArray( items ) ) {
  643. this.items = items;
  644. }
  645. this.render( );
  646. }
  647. UI.Listbox.prototype.render = function ( ) {
  648. while( this.listitems.length ) {
  649. var item = this.listitems[0];
  650. item.dom.remove();
  651. this.listitems.splice(0, 1);
  652. }
  653. for ( var i = 0; i < this.items.length; i ++ ) {
  654. var item = this.items[i];
  655. var listitem = new UI.Listbox.ListboxItem( this );
  656. listitem.setId( item.id || `Listbox-${i}` );
  657. listitem.setTextContent( item.name || item.type );
  658. this.add( listitem );
  659. }
  660. }
  661. // Assuming user passes valid list items
  662. UI.Listbox.prototype.add = function ( ) {
  663. var items = Array.from( arguments );
  664. this.listitems = this.listitems.concat( items );
  665. UI.Element.prototype.add.apply( this, items );
  666. }
  667. UI.Listbox.prototype.selectIndex = function ( index ) {
  668. if ( index >= 0 && index < this.items.length ) {
  669. this.setValue( this.listitems[ index ].getId( ) );
  670. }
  671. this.selectIndex = index;
  672. }
  673. UI.Listbox.prototype.getValue = function ( index ) {
  674. return this.selectedValue;
  675. }
  676. UI.Listbox.prototype.setValue = function ( value ) {
  677. for ( var i = 0; i < this.listitems.length; i ++ ) {
  678. var element = this.listitems[ i ];
  679. if ( element.getId( ) === value ) {
  680. element.addClass( 'active' );
  681. } else {
  682. element.removeClass( 'active' );
  683. }
  684. }
  685. this.selectedValue = value;
  686. var changeEvent = document.createEvent( 'HTMLEvents' );
  687. changeEvent.initEvent( 'change', true, true );
  688. this.dom.dispatchEvent( changeEvent );
  689. }
  690. // Listbox Item
  691. UI.Listbox.ListboxItem = function ( parent ) {
  692. UI.Element.call( this );
  693. var dom = document.createElement( 'div' );
  694. dom.className = 'ListboxItem';
  695. this.parent = parent;
  696. this.dom = dom;
  697. var scope = this;
  698. function onClick ( ) {
  699. if( scope.parent ) {
  700. scope.parent.setValue( scope.getId( ) );
  701. }
  702. }
  703. dom.addEventListener( 'click', onClick, false );
  704. return this;
  705. }
  706. UI.Listbox.ListboxItem.prototype = Object.create( UI.Element.prototype );
  707. UI.Listbox.ListboxItem.prototype.constructor = UI.Listbox.ListboxItem;