1 /** 2 * @fileOverview 3 * widget.enchant.js 4 * @version 0.2.0 5 * @require enchant.js v0.6.0+ 6 * @author UEI Corporation 7 * 8 * @description 9 * Library for making mobile webpage-style UIs in enchant.js. 10 */ 11 12 (function() { 13 14 /** 15 * @type {Object} 16 */ 17 enchant.widget = { 18 assets: [ 19 'listItemBg.png', 20 'iconMenuBg.png', 21 'button.png', 22 'buttonPushed.png', 23 'dialog.png', 24 'navigationBar.png' 25 ], 26 _env: { 27 // default font 28 font: '12px helvetica', 29 buttonFont: '23px helvetica', 30 navigationBarFont: '16px helvetica', 31 textareaFont: '8px monospace', 32 listItemMargin: 4, 33 dialogMargin: 24, 34 itemHeight: 48, 35 buttonWidth: 64, 36 buttonHeight: 36, 37 dialogWidth: 300, 38 dialogHeight: 225, 39 inputMinHeight: 160, 40 inputMaxHeight: 240, 41 acceptName: 'OK', 42 cancelName: 'NO', 43 HOLDTIME: 300, 44 DBLLIMIT: 300, 45 FLINGVEL: 3 46 }, 47 48 /** 49 * Return objects that cannot be displayed as units in string or enchant.Surface in displayable form. 50 * @param {*} content Data you wish to display. 51 * @return {*} enchant Entity object. 52 */ 53 parseContent: function(content, font, color) { 54 var en, metrics; 55 if (typeof content === 'undefined') { 56 content = ''; 57 } 58 if (typeof content === 'number') { 59 content = '' + content; 60 } 61 if (content instanceof enchant.Entity) { 62 } else if (content instanceof enchant.Surface) { 63 en = new enchant.Sprite(content.width, content.height); 64 en.image = content; 65 content = en; 66 } else if (typeof content == 'string') { 67 en = new enchant.Label(content); 68 if (font) { 69 en.font = font; 70 } else { 71 en.font = enchant.widget._env.font; 72 } 73 if (color) { 74 en.color = color; 75 } 76 metrics = en.getMetrics(); 77 en.width = metrics.width; 78 en.height = metrics.height; 79 content = en; 80 } 81 return content; 82 } 83 }; 84 85 /** 86 * Events occurring during Scene beginning. 87 * Issued when ended {@link enchant.Core#transitionPush} animation. 88 * @type {String} 89 */ 90 enchant.Event.TRANSITIONENTER = 'transitionenter'; 91 92 /** 93 * Events occurring during Scene end. 94 * Issued when ended {@link enchant.Core#transitionPop} animation. 95 * @type {String} 96 */ 97 enchant.Event.TRANSITIONEXIT = 'transitionexit'; 98 99 /** 100 * Event issued when positive button in enchant.widget.Confirm is pushed. 101 * @type {String} 102 */ 103 enchant.Event.ACCEPT = 'accept'; 104 105 /** 106 * Event issued when negative button in enchant.widget.Confirm is pushed. 107 * @type {String} 108 */ 109 enchant.Event.CANCEL = 'cancel'; 110 111 /** 112 * Event issued when form object content is changed. 113 * @type {String} 114 */ 115 enchant.Event.CHANGE = 'change'; 116 117 /** 118 * Event issued when tap is detected. 119 * Detected when touch ends without movement, and when double touch has ended. 120 * @type {String} 121 */ 122 enchant.Event.TAP = 'tap'; 123 124 /** 125 * Event issued when double tap is detected. 126 * Detected when two taps are detected within a set time and distance. 127 * @type {String} 128 */ 129 enchant.Event.DOUBLETAP = 'doubletap'; 130 131 /** 132 * Event issued when hold is detected. 133 * Detected when touch continues for a set time without movement. 134 * @type {String} 135 */ 136 enchant.Event.HOLD = 'hold'; 137 138 /** 139 * Event issued when drag is detected. 140 * Detected when touch position changes during hold. 141 * @type {String} 142 */ 143 enchant.Event.DRAG = 'drag'; 144 145 /** 146 * Event issued when release is detected. 147 * Detected when touch ends during hold. 148 * @type {String} 149 */ 150 enchant.Event.RELEASE = 'release'; 151 152 /** 153 * Event issued when slip is detected. 154 * Detected when touch position changes without holding. 155 * @type {String} 156 */ 157 enchant.Event.SLIP = 'slip'; 158 159 /** 160 * Event issued when fling is detected. 161 * Detected when touch ends and position moves faster than set speed. 162 * @type {String} 163 */ 164 enchant.Event.FLING = 'fling'; 165 166 167 /** 168 * Event which will be dispatched when additional content should be loaded for a view. 169 */ 170 enchant.Event.CONTENT_REQUESTED = 'contentRequested'; 171 172 var NOTOUCH = 0; 173 var WAITDBL = 1; 174 var NOMOVE = 2; 175 var NOMOVEDBL = 3; 176 var MOVED = 4; 177 var HOLD = 5; 178 179 var getElementMetrics = function(string, font) { 180 var e = document.createElement('div'); 181 var cvs = document.createElement('canvas'); 182 var ctx = cvs.getContext('2d'); 183 var arr, str, w; 184 var width = 0; 185 var height = 0; 186 if (!font) { 187 font = enchant.widget._env.font; 188 } 189 ctx.font = font; 190 e.style.font = font; 191 string = string || ''; 192 string = string.replace(/<(br|BR) ?\/?>/g, '<br>'); 193 arr = string.split('<br>'); 194 for (var i = 0, l = arr.length; i < l; i++) { 195 str = arr[i]; 196 w = ctx.measureText(str).width; 197 if (width < w) { 198 width = w; 199 } 200 } 201 202 e.innerHTML = string; 203 204 if (document.body) { 205 document.body.appendChild(e); 206 height = parseInt(getComputedStyle(e).height, 10); 207 e.style.position = 'absolute'; 208 width = parseInt(getComputedStyle(e).width, 10); 209 document.body.removeChild(e); 210 } else { 211 height = 14 * arr.length; 212 } 213 214 return { 215 width: width + 1, 216 height: height + 1 217 }; 218 }; 219 220 var calcLeastPosition = function(margin) { 221 margin |= 0; 222 return margin; 223 }; 224 225 var calcMostPosition = function(child, parent, margin) { 226 margin |= 0; 227 return parent - margin - child; 228 }; 229 230 var calcCenteredPosition = function(child, parent) { 231 return ~~(parent / 2) - ~~(child / 2); 232 }; 233 234 var getScaleOffest = function(length, scale) { 235 var half = ~~(length / 2); 236 scale = scale || 1; 237 return half - ~~(half * scale); 238 }; 239 240 var distribute = function(value, div) { 241 if (typeof div == 'array') { 242 var ratio = div; 243 var ret = new Array(ratio.length); 244 var retSum = 0; 245 var maxi = 0; 246 var max = 0; 247 var sum = 0; 248 var quo; 249 250 ratio.forEach(function(n) { 251 sum += n; 252 }); 253 quo = value / sum; 254 255 for (var i = 0, l = ret.length; i < l; i++) { 256 ret[i] = Math.round(quo * ratio[i]); 257 if (ratio[i] < max) { 258 maxi = i; 259 max = ratio[i]; 260 } 261 } 262 263 ret.forEach(function(n) { 264 retSum += n; 265 }); 266 267 ret[maxi] += value - retSum; 268 } else if (typeof div == 'number') { 269 var ret = new Array(div); 270 var quo = ~~(value / div); 271 var rem = ~~(value % div); 272 for (var i = 0, l = div; i < l; i++) { 273 ret[i] = quo; 274 } 275 for (var i = 0, l = rem; i < l; i++) { 276 ret[i % div] += 1; 277 } 278 } 279 return ret; 280 }; 281 282 var Adjust = { 283 fitToX: function(parent, margin) { 284 var l = parent.width; 285 var s = Math.min( 286 (l - margin * 2) / this.width, 287 (l - margin * 2) / this.height 288 ); 289 if (this instanceof enchant.Sprite) { 290 this.scaleX = s; 291 this.scaleY = s; 292 } else { 293 this.width = ~~(this.width * s); 294 this.height = ~~(this.height * s); 295 } 296 }, 297 fitToY: function(parent, margin) { 298 var l = parent.height; 299 var s = Math.min( 300 (l - margin * 2) / this.width, 301 (l - margin * 2) / this.height 302 ); 303 if (this instanceof enchant.Sprite) { 304 this.scaleX = s; 305 this.scaleY = s; 306 } else { 307 this.width = ~~(this.width * s); 308 this.height = ~~(this.height * s); 309 } 310 }, 311 fillX: function(parent, margin) { 312 var s = (parent.width - margin * 2) / this.width; 313 if (this instanceof enchant.Sprite) { 314 this.scaleX = s; 315 this.scaleY = s; 316 } else { 317 this.width = ~~(this.width * s); 318 this.height = ~~(this.height * s); 319 } 320 }, 321 fillY: function(parent, margin) { 322 var s = (parent.height - margin * 2) / this.height; 323 if (this instanceof enchant.Sprite) { 324 this.scaleX = s; 325 this.scaleY = s; 326 } else { 327 this.width = ~~(this.width * s); 328 this.height = ~~(this.height * s); 329 } 330 } 331 }; 332 333 var Effect = { 334 transitForwardIn: function(time) { 335 var core = enchant.Core.instance; 336 var child; 337 this.x = core.width; 338 var e = new enchant.Event(enchant.Event.RENDER); 339 for (var i = 0, l = this.childNodes.length; i < l; i++) { 340 child = this.childNodes[i]; 341 child.dispatchEvent(e); 342 } 343 this.tl 344 .moveTo(0, 0, time, enchant.Easing.QUAD_EASEINOUT); 345 }, 346 transitForwardOut: function(time) { 347 var core = enchant.Core.instance; 348 this.x = 0; 349 this.tl 350 .moveTo(-core.width, 0, time, enchant.Easing.QUAD_EASEINOUT); 351 }, 352 transitBackIn: function(time) { 353 var core = enchant.Core.instance; 354 this.x = -core.width; 355 this.tl 356 .moveTo(0, 0, time, enchant.Easing.QUAD_EASEINOUT); 357 }, 358 transitBackOut: function(time) { 359 var core = enchant.Core.instance; 360 this.x = 0; 361 this.tl 362 .moveTo(core.width, 0, time, enchant.Easing.QUAD_EASEINOUT); 363 }, 364 popup: function() { 365 this.scaleX = 0.1; 366 this.scaleY = 0.1; 367 this.opacity = 0.1; 368 this.tl 369 .fadeTo(0.8, 3, enchant.Easing.QUAD_EASEOUT) 370 .and() 371 .scaleTo(1, 3, enchant.Easing.BOUNCE_EASEOUT); 372 }, 373 popdown: function() { 374 this.tl 375 .fadeTo(0.1, 3, enchant.Easing.QUAD_EASEOUT) 376 .and() 377 .scaleTo(0.1, 3, enchant.Easing.BOUNCE_EASEOUT); 378 }, 379 resizeTo: function(width, height, time, easing) { 380 return this.tl.tween({ 381 width: width, 382 height: height, 383 time: time, 384 easing: easing 385 }); 386 } 387 }; 388 389 var Align = { 390 391 /** 392 * @scope enchant.Entity 393 */ 394 395 /** 396 * Moves to left side of specified object. 397 * @param {*} another Object that becomes standard. 398 * @param {Number} margin Number of pixels shifted. 399 * @requires widget.enchant.js 400 */ 401 alignLeftOf: function(another, margin) { 402 margin |= 0; 403 var anotherScaleOffset = getScaleOffest(another.width, another.scaleX); 404 var scaleOffset = getScaleOffest(this.width, this.scaleX); 405 this.x = another.x + anotherScaleOffset - scaleOffset - this.width - margin; 406 return this; 407 }, 408 /** 409 * Moves to right side of specified object. 410 * @param {*} another Object that becomes standard. 411 * @param {Number} margin Number of pixels shifted. 412 * @requires widget.enchant.js 413 */ 414 alignRightOf: function(another, margin) { 415 margin |= 0; 416 var anotherScaleOffset = getScaleOffest(another.width, another.scaleX); 417 var scaleOffset = getScaleOffest(this.width, this.scaleX); 418 this.x = another.x + another.width - anotherScaleOffset - scaleOffset + margin; 419 return this; 420 }, 421 /** 422 * Moves to upper side of specified object. 423 * @param {*} another Object that becomes standard. 424 * @param {Number} margin Number of pixels shifted. 425 * @requires widget.enchant.js 426 */ 427 alignTopOf: function(another, margin) { 428 margin |= 0; 429 var anotherScaleOffset = getScaleOffest(another.height, another.scaleY); 430 var scaleOffset = getScaleOffest(this.height, this.scaleY); 431 this.y = another.y + anotherScaleOffset - scaleOffset - this.height - margin; 432 return this; 433 }, 434 /** 435 * Moves to lower side of specified object. 436 * @param {*} another Object that becomes standard. 437 * @param {Number} margin Number of pixels shifted. 438 * @requires widget.enchant.js 439 */ 440 alignBottomOf: function(another, margin) { 441 margin |= 0; 442 var anotherScaleOffset = getScaleOffest(another.height, another.scaleY); 443 var scaleOffset = getScaleOffest(this.height, this.scaleY); 444 this.y = another.y + another.height - anotherScaleOffset - scaleOffset + margin; 445 return this; 446 }, 447 /** 448 * Performs leftwards movement within specified object. 449 * @param {*} another Object that becomes standard. 450 * @param {Number} margin Number of pixels shifted. 451 * @requires widget.enchant.js 452 */ 453 alignLeftIn: function(another, margin) { 454 var scaleOffset = getScaleOffest(this.width, this.scaleX); 455 this.x = calcLeastPosition(margin) - scaleOffset; 456 return this; 457 }, 458 /** 459 * Performs rightwards movement within specified object. 460 * @param {*} another Object that becomes standard. 461 * @param {Number} margin Number of pixels shifted. 462 * @requires widget.enchant.js 463 */ 464 alignRightIn: function(another, margin) { 465 var scaleOffset = getScaleOffest(this.width, this.scaleX); 466 this.x = calcMostPosition(this.width, another.width, margin) + scaleOffset; 467 return this; 468 }, 469 /** 470 * Performs upwards movement within specified object. 471 * @param {*} another Object that becomes standard. 472 * @param {Number} margin Number of pixels shifted. 473 * @requires widget.enchant.js 474 */ 475 alignTopIn: function(another, margin) { 476 var scaleOffset = getScaleOffest(this.height, this.scaleY); 477 this.y = calcLeastPosition(margin) - scaleOffset; 478 return this; 479 }, 480 /** 481 * Performs downwards movement within specified object. 482 * @param {*} another Object that becomes standard. 483 * @param {Number} margin Number of pixels shifted. 484 * @requires widget.enchant.js 485 */ 486 alignBottomIn: function(another, margin) { 487 var scaleOffset = getScaleOffest(this.height, this.scaleY); 488 this.y = calcMostPosition(this.height, another.height, margin) + scaleOffset; 489 return this; 490 }, 491 /** 492 * Performs central movement along x axis within specified object. 493 * @param {*} another Object that becomes standard. 494 * @param {Number} margin Number of pixels shifted. 495 * @requires widget.enchant.js 496 */ 497 alignHorizontalCenterIn: function(another) { 498 this.x = calcCenteredPosition(this.width, another.width); 499 return this; 500 }, 501 /** 502 * Performs central movement along y axis within specified object. 503 * @param {*} another object that becomes standard. 504 * @param {Number} margin Number of pictures shifted. 505 * @requires widget.enchant.js 506 */ 507 alignVerticalCenterIn: function(another) { 508 this.y = calcCenteredPosition(this.height, another.height); 509 return this; 510 } 511 }; 512 513 for (var prop in Align) { 514 enchant.Entity.prototype[prop] = Align[prop]; 515 } 516 517 var _transitionLock = false; 518 519 /** 520 * @scope enchant.Core 521 */ 522 523 /** 524 * Perform pushScene with transition animation. 525 * @param {enchant.Scene} inScene New scene transitioned to. 526 * @return {enchant.Scene} New scene 527 * @requires widget.enchant.js 528 */ 529 enchant.Core.prototype.transitionPush = function(inScene) { 530 if (_transitionLock) return null; 531 _transitionLock = true; 532 var time = 15; 533 var c = 0; 534 var outScene = this.currentScene; 535 Effect.transitForwardIn.call(inScene, time); 536 Effect.transitForwardOut.call(outScene, time); 537 this.addEventListener(enchant.Event.ENTER_FRAME, function(e) { 538 outScene.dispatchEvent(e); 539 if (c > time) { 540 _transitionLock = false; 541 this.removeEventListener(enchant.Event.ENTER_FRAME, arguments.callee); 542 inScene.dispatchEvent(new enchant.Event(enchant.Event.TRANSITIONENTER)); 543 outScene.dispatchEvent(new enchant.Event(enchant.Event.TRANSITIONEXIT)); 544 } 545 c++; 546 }); 547 return this.pushScene(inScene); 548 }; 549 550 /** 551 * Perform popScene with transition animation. 552 * @return {enchant.Scene} Finished scene. 553 * @requires widget.enchant.js 554 */ 555 enchant.Core.prototype.transitionPop = function() { 556 if (_transitionLock) return null; 557 if (this.currentScene == this.rootScene) return null; 558 _transitionLock = true; 559 var time = 15; 560 var c = 0; 561 var outScene = this.currentScene; 562 var inScene = this._scenes[this._scenes.length - 2]; 563 this.addEventListener(enchant.Event.ENTER_FRAME, function(e) { 564 inScene.dispatchEvent(e); 565 if (c > time) { 566 _transitionLock = false; 567 this.removeEventListener(enchant.Event.ENTER_FRAME, arguments.callee); 568 this.popScene(); 569 outScene.dispatchEvent(new enchant.Event(enchant.Event.TRANSITIONEXIT)); 570 inScene.dispatchEvent(new enchant.Event(enchant.Event.TRANSITIONENTER)); 571 } 572 c++; 573 }); 574 Effect.transitBackIn.call(inScene, time); 575 Effect.transitBackOut.call(outScene, time); 576 return this._scenes[this._scenes.length - 1]; 577 }; 578 579 /** 580 * @scope enchant.widget.GestureDetector 581 */ 582 enchant.widget.GestureDetector = enchant.Class.create(enchant.EventTarget, { 583 /** 584 * Issue event after detecting several gestures. 585 * Can detect tap, double tap, hold, drag, flick, and more. 586 * @param {enchant.Entity} target Object for which you wish to detect input. 587 * @constructs 588 * @extends enchant.EventTarget 589 */ 590 initialize: function(target) { 591 var core = enchant.Core.instance; 592 enchant.EventTarget.call(this); 593 this._target; 594 this._startX = 0; 595 this._startY = 0; 596 this._lastX = 0; 597 this._lastY = 0; 598 this._touchElapsed = 0; 599 this._releaseElapsed = 0; 600 this._state = NOTOUCH; 601 this._velobase = (core.width > core.height) ? core.height : core.width; 602 603 var detector = this; 604 this._handler = function(e) { 605 detector.dispatchEvent(e); 606 }; 607 608 this._types = [ 609 enchant.Event.TOUCH_START, 610 enchant.Event.TOUCH_MOVE, 611 enchant.Event.TOUCH_END, 612 enchant.Event.ENTER_FRAME 613 ]; 614 615 if (target) { 616 this.attach(target); 617 } 618 }, 619 attach: function(target) { 620 this._target = target; 621 this._types.forEach(function(event) { 622 this._target.addEventListener(event, this._handler); 623 }, this); 624 }, 625 detach: function() { 626 this._types.forEach(function(event) { 627 this._target.removeEventListener(event, this._handler); 628 }, this); 629 this._target = null; 630 }, 631 ontouchstart: function(e) { 632 var core = enchant.Core.instance; 633 this._startFrame = core.frame; 634 this._startX = this._lastX = e.x; 635 this._startY = this._lastY = e.y; 636 if (this._state == WAITDBL) { 637 this._state = NOMOVEDBL; 638 } else if (this._state == NOTOUCH) { 639 this._state = NOMOVE; 640 } 641 }, 642 ontouchmove: function(e) { 643 var dx = e.x - this._lastX; 644 var dy = e.y - this._lastY; 645 this._lastX = e.x; 646 this._lastY = e.y; 647 switch (this._state) { 648 case NOMOVE: 649 case NOMOVEDBL: 650 this._state = MOVED; 651 case MOVED: 652 var evt = new enchant.Event(enchant.Event.SLIP); 653 evt.x = this._lastX; 654 evt.y = this._lastY; 655 evt.dx = dx; 656 evt.dy = dy; 657 this._target.dispatchEvent(evt); 658 break; 659 case HOLD: 660 var evt = new enchant.Event(enchant.Event.DRAG); 661 evt.x = this._lastX; 662 evt.y = this._lastY; 663 evt.dx = dx; 664 evt.dy = dy; 665 this._target.dispatchEvent(evt); 666 break; 667 default: 668 break; 669 } 670 }, 671 ontouchend: function(e) { 672 var core = enchant.Core.instance; 673 switch (this._state) { 674 case MOVED: 675 velocityX = (this._lastX - this._startX) / this._velobase / this._touchElapsed * 1000; 676 velocityY = (this._lastY - this._startY) / this._velobase / this._touchElapsed * 1000; 677 if (velocityX > enchant.widget._env.FLINGVEL || velocityY > enchant.widget._env.FLINGVEL) { 678 var evt = new enchant.Event(enchant.Event.FLING); 679 evt.x = this._startX; 680 evt.y = this._startY; 681 evt.ex = this._lastX; 682 evt.ey = this._lastY; 683 evt.velocityX = velocityX; 684 evt.velocityY = velocityY; 685 this._target.dispatchEvent(evt); 686 } 687 this._state = NOTOUCH; 688 break; 689 case HOLD: 690 var evt = new enchant.Event(enchant.Event.RELEASE); 691 evt.x = this._lastX; 692 evt.y = this._lastY; 693 this._target.dispatchEvent(evt); 694 this._state = NOTOUCH; 695 break; 696 case NOMOVEDBL: 697 var evt = new enchant.Event(enchant.Event.DOUBLETAP); 698 evt.x = this._lastX; 699 evt.y = this._lastY; 700 this._target.dispatchEvent(evt); 701 this._state = NOTOUCH; 702 this._releaseElapsed = 0; 703 break; 704 case NOMOVE: 705 this._state = WAITDBL; 706 break; 707 default: 708 this._state = NOTOUCH; 709 break; 710 } 711 this._touchElapsed = 0; 712 this._startX = 0; 713 this._startY = 0; 714 }, 715 onenterframe: function(e) { 716 var elapsed = e.elapsed; 717 switch (this._state) { 718 case WAITDBL: 719 this._releaseElapsed += elapsed; 720 if (this._releaseElapsed >= enchant.widget._env.DBLLIMIT) { 721 var evt = new enchant.Event(enchant.Event.TAP); 722 evt.x = this._lastX; 723 evt.y = this._lastY; 724 this._lastX = 0; 725 this._lastY = 0; 726 this._target.dispatchEvent(evt); 727 this._state = NOTOUCH; 728 this._releaseElapsed = 0; 729 } 730 break; 731 case NOMOVEDBL: 732 this._releaseElapsed += elapsed; 733 if (this._releaseElapsed >= enchant.widget._env.DBLLIMIT) { 734 this._state = NOMOVE; 735 this._releaseElapsed = 0; 736 } 737 case NOMOVE: 738 this._touchElapsed += elapsed; 739 if (this._touchElapsed >= enchant.widget._env.HOLDTIME) { 740 var evt = new enchant.Event(enchant.Event.HOLD); 741 evt.x = this._lastX; 742 evt.y = this._lastY; 743 this._target.dispatchEvent(evt); 744 this._state = HOLD; 745 this._touchElapsed = 0; 746 } 747 break; 748 case MOVED: 749 this._touchElapsed += elapsed; 750 break; 751 case NOTOUCH: 752 case HOLD: 753 default: 754 break; 755 } 756 } 757 }); 758 enchant.widget.GestureDetector.gestureEvents = [ 759 enchant.Event.ACCEPT, 760 enchant.Event.CANCEL, 761 enchant.Event.TAP, 762 enchant.Event.DOUBLETAP, 763 enchant.Event.HOLD, 764 enchant.Event.DRAG, 765 enchant.Event.RELEASE, 766 enchant.Event.SLIP, 767 enchant.Event.FLING 768 ]; 769 770 /** 771 * @scope enchant.widget.Ninepatch 772 */ 773 enchant.widget.Ninepatch = enchant.Class.create(enchant.Surface, { 774 /** 775 * Surface corresponding to 9patch. 776 * Does not respond to settings in content area. 777 * @param {Number} width Surface width. 778 * @param {Number} height Surface height. 779 * @constructs 780 * @extends enchant.Surface 781 */ 782 initialize: function(width, height) { 783 enchant.Surface.call(this, width, height); 784 785 this._horScStore = []; 786 this._horNoScStore = []; 787 this._verScStore = []; 788 this._verNoScStore = []; 789 this._src; 790 }, 791 /** 792 * 9patch source. 793 * @type {enchant.Surface} 794 */ 795 src: { 796 get: function() { 797 return this._src; 798 }, 799 set: function(surface) { 800 if (surface == this._src || !(surface instanceof enchant.Surface)) { 801 return; 802 } 803 this._slicedraw(surface); 804 this._src = surface; 805 } 806 }, 807 _detect: function(img) { 808 this._horScStore = []; 809 this._horNoScStore = []; 810 this._verScStore = []; 811 this._verNoScStore = []; 812 var elem = img._element; 813 var cvs = document.createElement('canvas'); 814 var width = cvs.width = img.width; 815 var height = cvs.height = img.height; 816 var ctx = cvs.getContext('2d'); 817 ctx.drawImage(elem, 0, 0, width, height); 818 var pixels = ctx.getImageData(0, 0, width, height); 819 820 var isBlack = function(i) { 821 return pixels.data[i] == 0 && pixels.data[i + 1] == 0 && pixels.data[i + 2] == 0 && pixels.data[i + 3] == 255; 822 }; 823 824 var last = false; 825 var tmp = []; 826 var scalable = []; 827 var noscalable = []; 828 829 for (var i = 1, l = width - 1; i < l; i++) { 830 last = isBlack(i * 4); 831 if (last) { 832 if (scalable.length == 0) { 833 scalable.push(i); 834 } 835 if (noscalable.length == 1) { 836 noscalable.push(i - 1); 837 this._horNoScStore.push(noscalable); 838 noscalable = []; 839 } 840 } else { 841 if (noscalable.length == 0) { 842 noscalable.push(i); 843 } 844 if (scalable.length == 1) { 845 scalable.push(i - 1); 846 this._horScStore.push(scalable); 847 scalable = []; 848 } 849 } 850 } 851 if (scalable.length == 1) { 852 scalable.push(i - 1); 853 this._horScStore.push(scalable); 854 } 855 if (noscalable.length == 1) { 856 noscalable.push(i - 1); 857 this._horNoScStore.push(noscalable); 858 } 859 scalable = []; 860 noscalable = []; 861 862 for (var i = 1, l = height - 1; i < l; i++) { 863 last = isBlack(i * width * 4); 864 if (last) { 865 if (scalable.length == 0) { 866 scalable.push(i); 867 } 868 if (noscalable.length == 1) { 869 noscalable.push(i - 1); 870 this._verNoScStore.push(noscalable); 871 noscalable = []; 872 } 873 } else { 874 if (noscalable.length == 0) { 875 noscalable.push(i); 876 } 877 if (scalable.length == 1) { 878 scalable.push(i - 1); 879 this._verScStore.push(scalable); 880 scalable = []; 881 } 882 } 883 } 884 if (scalable.length == 1) { 885 scalable.push(i - 1); 886 this._verScStore.push(scalable); 887 } 888 if (noscalable.length == 1) { 889 noscalable.push(i - 1); 890 this._verNoScStore.push(noscalable); 891 } 892 }, 893 _slicedraw: function(img) { 894 this._detect(img); 895 var elem = img._element; 896 var w = img.width; 897 var h = img.height; 898 var width = this.width; 899 var height = this.height; 900 var ctx = this.context; 901 902 var getSum = function(store) { 903 var s; 904 var sum = 0; 905 for (var i = 0, l = store.length; i < l; i++) { 906 s = store[i]; 907 sum += s[1] - s[0] + 1; 908 } 909 return sum; 910 }; 911 var getRatio = function(array) { 912 var a, ret = []; 913 for (var i = 0, l = array.length; i < l; i++) { 914 a = array[i]; 915 ret.push(a[1] - a[0] + 1); 916 } 917 return ret; 918 }; 919 var fix = function(array, fix) { 920 var a; 921 for (var i = 0, l = array.length; i < l; i++) { 922 a = array[i]; 923 a.fix = fix[i]; 924 } 925 }; 926 var distribute = function(value, ratio) { 927 var ret = new Array(ratio.length); 928 var retSum = 0; 929 var maxi = 0; 930 var max = 0; 931 var sum = 0; 932 var quo; 933 934 ratio.forEach(function(n) { 935 sum += n; 936 }); 937 quo = value / sum; 938 939 for (var i = 0, l = ret.length; i < l; i++) { 940 ret[i] = Math.round(quo * ratio[i]); 941 if (ratio[i] < max) { 942 maxi = i; 943 max = ratio[i]; 944 } 945 } 946 947 ret.forEach(function(n) { 948 retSum += n; 949 }); 950 951 ret[maxi] += value - retSum; 952 953 return ret; 954 }; 955 956 var ratioH = getRatio(this._horScStore); 957 var valueH = width - getSum(this._horNoScStore); 958 var scaledW = distribute(valueH, ratioH); 959 960 var ratioV = getRatio(this._verScStore); 961 var valueV = height - getSum(this._verNoScStore); 962 var scaledH = distribute(valueV, ratioV); 963 964 fix(this._horScStore, scaledW); 965 fix(this._verScStore, scaledH); 966 967 var verQueue = this._verScStore.concat(this._verNoScStore).sort(function(a, b) { 968 return a[0] - b[0]; 969 }); 970 var horQueue = this._horScStore.concat(this._horNoScStore).sort(function(a, b) { 971 return a[0] - b[0]; 972 }); 973 974 var verQ; 975 var horQ; 976 var sx, sy, sw, sh, dw, dh; 977 var dx = 0; 978 var dy = 0; 979 980 ctx.clearRect(0, 0, this.width, this.height); 981 for (var i = 0, l = horQueue.length; i < l; i++) { 982 horQ = horQueue[i]; 983 sx = horQ[0]; 984 sw = horQ[1] - horQ[0] + 1; 985 dw = (typeof horQ.fix == 'number') ? horQ.fix : sw; 986 dy = 0; 987 for (var j = 0, ll = verQueue.length; j < ll; j++) { 988 verQ = verQueue[j]; 989 sy = verQ[0]; 990 sh = verQ[1] - verQ[0] + 1; 991 dh = (typeof verQ.fix == 'number') ? verQ.fix : sh; 992 ctx.drawImage(elem, sx, sy, sw, sh, dx, dy, dw, dh); 993 dy += dh; 994 } 995 dx += dw; 996 } 997 }, 998 /** 999 * @type {Number} 1000 */ 1001 width: { 1002 get: function() { 1003 return this._width; 1004 }, 1005 set: function(width) { 1006 this._width = width; 1007 if (this._element) { 1008 this._element.width = width; 1009 } 1010 if (this._src instanceof enchant.Surface) { 1011 this._slicedraw(this._src); 1012 } 1013 } 1014 }, 1015 /** 1016 * @type {Number} 1017 */ 1018 height: { 1019 get: function() { 1020 return this._height; 1021 }, 1022 set: function(height) { 1023 this._height = height; 1024 if (this._element) { 1025 this._element.height = height; 1026 } 1027 if (this._src instanceof enchant.Surface) { 1028 this._slicedraw(this._src); 1029 } 1030 } 1031 }, 1032 /** 1033 * Recreate set size. 1034 * @param {Number} width New width. 1035 * @param {Number} height New height. 1036 */ 1037 resize: function(width, height) { 1038 this._width = width; 1039 this._height = height; 1040 this._element.width = width; 1041 this._element.height = height; 1042 if (this._src instanceof enchant.Surface) { 1043 this._slicedraw(this._src); 1044 } 1045 } 1046 }); 1047 1048 /** 1049 * @scope enchant.widget.EntityGroup 1050 */ 1051 enchant.widget.EntityGroup = enchant.Class.create(enchant.Entity, { 1052 /** 1053 * Entity that can have children. 1054 * @param {Number} width Entity width. 1055 * @param {Number} height Entity height. 1056 * @constructs 1057 * @extends enchant.Entity 1058 */ 1059 initialize: function(width, height) { 1060 enchant.Entity.call(this); 1061 this.childNodes = []; 1062 this._background; 1063 this.width = width; 1064 this.height = height; 1065 1066 [ enchant.Event.ADDED_TO_SCENE, enchant.Event.REMOVED_FROM_SCENE ] 1067 .forEach(function(event) { 1068 this.addEventListener(event, function(e) { 1069 this.childNodes.slice().forEach(function(child) { 1070 child.scene = this.scene; 1071 child.dispatchEvent(e); 1072 }, this); 1073 }); 1074 }, this); 1075 }, 1076 /** 1077 * @type {Number} 1078 */ 1079 width: { 1080 get: function() { 1081 return this._width; 1082 }, 1083 set: function(width) { 1084 this._width = width; 1085 this._dirty = true; 1086 if (this.background instanceof enchant.widget.Ninepatch) { 1087 this.background.width = this.width; 1088 } 1089 } 1090 }, 1091 /** 1092 * @type {Number} 1093 */ 1094 height: { 1095 get: function() { 1096 return this._height; 1097 }, 1098 set: function(height) { 1099 this._height = height; 1100 this._dirty = true; 1101 if (this.background instanceof enchant.widget.Ninepatch) { 1102 this.background.height = this.height; 1103 } 1104 } 1105 }, 1106 /** 1107 * Surface used as background. 1108 * @type {enchant.Surface} 1109 */ 1110 background: { 1111 get: function() { 1112 return this._background; 1113 }, 1114 set: function(surface) { 1115 if (surface instanceof enchant.Surface) { 1116 this._background = surface; 1117 if (surface._css) { 1118 this._style['background-image'] = surface._css; 1119 } 1120 } 1121 } 1122 }, 1123 /** 1124 * Add Node to EntityGroup. 1125 * @param {enchant.Node} child Node to be added. 1126 */ 1127 addChild: enchant.Group.prototype.addChild, 1128 /** 1129 * Insert Node to EntityGroup. 1130 * @param {enchant.Node} child Node to be inserted. 1131 * @param {enchant.Node} reference Node before insertion postion. 1132 */ 1133 insertBefore: enchant.Group.prototype.insertBefore, 1134 /** 1135 * Delete Node from EntityGroup. 1136 * @param {enchant.Node} child Node to delete. 1137 */ 1138 removeChild: enchant.Group.prototype.removeChild, 1139 /** 1140 * First child Node. 1141 * @type {enchant.Node} 1142 */ 1143 firstChild: Object.getOwnPropertyDescriptor(enchant.Group.prototype, 'firstChild'), 1144 /** 1145 * Last child Node. 1146 * @type {enchant.Node} 1147 */ 1148 lastChild: Object.getOwnPropertyDescriptor(enchant.Group.prototype, 'lastChild'), 1149 _dirty: Object.getOwnPropertyDescriptor(enchant.Group.prototype, '_dirty'), 1150 cvsRender: function(ctx) { 1151 if (this.background && 1152 this.background._element.width > 0 && 1153 this.background._element.height > 0) { 1154 ctx.drawImage(this.background._element, 0, 0, this.width, this.height); 1155 } 1156 } 1157 }); 1158 1159 /** 1160 * @scope enchant.widget.Modal 1161 */ 1162 enchant.widget.Modal = enchant.Class.create(enchant.Scene, { 1163 /** 1164 * Model scene. 1165 * @constructs 1166 * @extends enchant.Scene 1167 */ 1168 initialize: function() { 1169 enchant.Scene.call(this); 1170 var core = enchant.Core.instance; 1171 var shade = new enchant.Sprite(core.width, core.height); 1172 shade.backgroundColor = 'rgba(0, 0, 0, 0.1)'; 1173 this.addChild(shade); 1174 this.addEventListener(enchant.Event.ENTER, function() { 1175 shade.tl.fadeTo(0.7, 5, enchant.Easing.QUAD_EASEOUT); 1176 }); 1177 } 1178 }); 1179 1180 /** 1181 * @scope enchant.widget.Button.prototype 1182 */ 1183 enchant.widget.Button = enchant.Class.create(enchant.widget.EntityGroup, { 1184 /** 1185 * Button. 1186 * Set normal background and background when pushed down. 1187 * @param {*} Button content. 1188 * @constructs 1189 * @extends enchant.widget.EntityGroup 1190 */ 1191 initialize: function(content) { 1192 var core = enchant.Core.instance; 1193 content = content || ''; 1194 var minwidth = enchant.widget._env.buttonWidth; 1195 var minheight = enchant.widget._env.buttonHeight; 1196 enchant.widget.EntityGroup.call(this, minwidth, minheight); 1197 this._image; 1198 this._pushedimage; 1199 this._content; 1200 this._rawContent; 1201 var bg1 = new enchant.widget.Ninepatch(minwidth, minheight); 1202 bg1.src = core.assets['button.png']; 1203 this.image = bg1; 1204 1205 var bg2 = new enchant.widget.Ninepatch(minwidth, minheight); 1206 bg2.src = core.assets['buttonPushed.png']; 1207 this.pushedimage = bg2; 1208 1209 this.content = content; 1210 this.width = Math.max(this._content.width, minwidth); 1211 this.height = Math.max(this._content.height, minheight); 1212 this.addEventListener(enchant.Event.TOUCH_START, function() { 1213 if (!this._pushedimage) { 1214 return; 1215 } 1216 this.background = this._pushedimage; 1217 }); 1218 this.addEventListener(enchant.Event.TOUCH_END, function() { 1219 if (!this._pushedimage) { 1220 return; 1221 } 1222 this.background = this._image; 1223 }); 1224 }, 1225 refresh: function() { 1226 if (this._content) { 1227 this._content.alignHorizontalCenterIn(this).alignVerticalCenterIn(this); 1228 } 1229 }, 1230 /** 1231 * width of button 1232 * @type number 1233 */ 1234 width: { 1235 get: function() { 1236 return this._width; 1237 }, 1238 set: function(width) { 1239 this._style.width = (this._width = width) + 'px'; 1240 if (this._image instanceof enchant.widget.Ninepatch) { 1241 this._image.width = width; 1242 } 1243 if (this._pushedimage instanceof enchant.widget.Ninepatch) { 1244 this._pushedimage.width = width; 1245 } 1246 this.refresh(); 1247 } 1248 }, 1249 /** 1250 * height of button 1251 * @type number 1252 */ 1253 height: { 1254 get: function() { 1255 return this._height; 1256 }, 1257 set: function(height) { 1258 this._style.height = (this._height = height) + 'px'; 1259 if (this._image instanceof enchant.widget.Ninepatch) { 1260 this._image.height = height; 1261 } 1262 if (this._pushedimage instanceof enchant.widget.Ninepatch) { 1263 this._pushedimage.height = height; 1264 } 1265 this.refresh(); 1266 } 1267 }, 1268 /** 1269 * Button background. 1270 * @type {enchant.Surface} 1271 */ 1272 image: { 1273 get: function() { 1274 return this._image; 1275 }, 1276 set: function(image) { 1277 if (image == this._image) { 1278 return; 1279 } 1280 this.background = image; 1281 this._image = image; 1282 } 1283 }, 1284 /** 1285 * Background when button is pushed. 1286 * @type {enchant.Surface} 1287 */ 1288 pushedimage: { 1289 get: function() { 1290 return this._pushedimage; 1291 }, 1292 set: function(image) { 1293 if (image == this._pushedimage) { 1294 return; 1295 } 1296 this._pushedimage = image; 1297 } 1298 }, 1299 /** 1300 * Button content 1301 * @type {String} 1302 */ 1303 content: { 1304 get: function() { 1305 return this._rawContent; 1306 }, 1307 set: function(content) { 1308 this._rawContent = content; 1309 var font = enchant.widget._env.buttonFont; 1310 content = enchant.widget.parseContent(content, font); 1311 if (this._content) { 1312 this.removeChild(this._content); 1313 } 1314 this.addChild(content); 1315 this._content = content; 1316 this.refresh(); 1317 } 1318 } 1319 }); 1320 1321 /** 1322 * @scope enchant.widget.Alert 1323 */ 1324 enchant.widget.Alert = enchant.Class.create(enchant.widget.EntityGroup, { 1325 /** 1326 * Alert dialog. 1327 * Use from normal {@link enchant.widget.AlertScene}. 1328 * @param {*} content Content to display. 1329 * @param {String} ac Label for acceptance button. 1330 * @see enchant.widget.AlertScene 1331 * @constructs 1332 * @extends enchant.widget.EntityGroup 1333 */ 1334 initialize: function(content, ac) { 1335 var core = enchant.Core.instance; 1336 var dialogwidth = enchant.widget._env.dialogWidth; 1337 var dialogheight = enchant.widget._env.dialogHeight; 1338 enchant.widget.EntityGroup.call(this, dialogwidth, dialogheight); 1339 var margin = enchant.widget._env.dialogMargin; 1340 1341 content = enchant.widget.parseContent(content); 1342 content.alignHorizontalCenterIn(this).alignTopIn(this, margin); 1343 1344 var accept = new enchant.widget.Button(ac); 1345 accept.alignHorizontalCenterIn(this).alignBottomIn(this, margin); 1346 1347 var that = this; 1348 accept.addEventListener(enchant.Event.TOUCH_END, function() { 1349 that.dispatchEvent(new enchant.Event(enchant.Event.ACCEPT)); 1350 }); 1351 1352 var np = new enchant.widget.Ninepatch(this.width, this.height); 1353 np.src = core.assets['dialog.png']; 1354 this.background = np; 1355 1356 this._content = content; 1357 this._accept = accept; 1358 1359 this.addChild(content); 1360 this.addChild(accept); 1361 }, 1362 /** 1363 * Function executed when agreement button is pushed. 1364 * @type {Function} 1365 */ 1366 onaccept: function() { 1367 } 1368 }); 1369 1370 /** 1371 * @scope enchant.widget.Confirm 1372 */ 1373 enchant.widget.Confirm = enchant.Class.create(enchant.widget.EntityGroup, { 1374 /** 1375 * Confirm dialog. 1376 * Use from normal {@link enchant.widget.ConfirmScene}. 1377 * @param {*} content Content to display. 1378 * @param {String} ac Label for agreement button. 1379 * @param {String} ig Label for cancel button. 1380 * @see enchant.widget.ConfirmScene 1381 * @constructs 1382 * @extends enchant.widget.EntityGroup 1383 */ 1384 initialize: function(content, ac, ig) { 1385 var core = enchant.Core.instance; 1386 var dialogwidth = enchant.widget._env.dialogWidth; 1387 var dialogheight = enchant.widget._env.dialogHeight; 1388 enchant.widget.EntityGroup.call(this, dialogwidth, dialogheight); 1389 var margin = enchant.widget._env.dialogMargin; 1390 1391 var content = enchant.widget.parseContent(content); 1392 content.alignHorizontalCenterIn(this).alignTopIn(this, margin); 1393 1394 var cancel = new enchant.widget.Button(ig); 1395 cancel.alignLeftIn(this, margin).alignBottomIn(this, margin); 1396 1397 var accept = new enchant.widget.Button(ac); 1398 accept.alignRightIn(this, margin).alignBottomIn(this, margin); 1399 1400 var that = this; 1401 cancel.addEventListener(enchant.Event.TOUCH_END, function() { 1402 that.dispatchEvent(new enchant.Event(enchant.Event.CANCEL)); 1403 }); 1404 accept.addEventListener(enchant.Event.TOUCH_END, function() { 1405 that.dispatchEvent(new enchant.Event(enchant.Event.ACCEPT)); 1406 }); 1407 1408 var np = new enchant.widget.Ninepatch(this.width, this.height); 1409 np.src = core.assets['dialog.png']; 1410 this.background = np; 1411 1412 this._content = content; 1413 this._cancel = cancel; 1414 this._accept = accept; 1415 1416 this.addChild(content); 1417 this.addChild(cancel); 1418 this.addChild(accept); 1419 }, 1420 /** 1421 * Function executed when cancel button is pushed. 1422 * @type {Function} 1423 */ 1424 oncancel: function() { 1425 }, 1426 /** 1427 * Function executed when agreement button is pushed. 1428 */ 1429 onaccept: function() { 1430 } 1431 }); 1432 1433 /** 1434 * @scope enchant.widget.Prompt 1435 */ 1436 enchant.widget.Prompt = enchant.Class.create(enchant.widget.Confirm, { 1437 /** 1438 * Prompt dialog. 1439 * Use from normal {@link enchant.widget.PromptScene}. 1440 * @param {*} content Content to display. 1441 * @param {String} ac Label for agreement label. 1442 * @param {String} ig Label for cancel button. 1443 * @see enchant.widget.PromptScene 1444 * @constructs 1445 * @extends enchant.widget.Confirm 1446 */ 1447 initialize: function(content, ac, ig, placeholder) { 1448 enchant.widget.Confirm.call(this, content, ac, ig); 1449 var margin = enchant.widget._env.dialogMargin; 1450 var input = this._input = new enchant.widget.InputTextBox(); 1451 input.width = this.width / 4 * 3; 1452 input.placeholder = placeholder; 1453 input.alignHorizontalCenterIn(this).alignBottomOf(this._content, margin); 1454 this.addChild(input); 1455 }, 1456 /** 1457 * content of prompt. 1458 */ 1459 value: { 1460 get: function() { 1461 return this._input.value; 1462 }, 1463 set: function(value) { 1464 this._input.value = value; 1465 } 1466 } 1467 }); 1468 1469 /** 1470 * @scope enchant.widget.Input 1471 */ 1472 enchant.widget.Input = enchant.Class.create(enchant.Entity, { 1473 /** 1474 * Entity containing <input>. 1475 * @param {String} type <input>のtype. 1476 * @constructs 1477 * @extends enchant.Entity 1478 */ 1479 initialize: function(type) { 1480 enchant.Entity.call(this); 1481 if (!type) { 1482 type = 'input'; 1483 } 1484 var that = this; 1485 this._input = document.createElement(type); 1486 1487 this._input.addEventListener('change', function(e) { 1488 that.dispatchEvent(new enchant.Event(enchant.Event.CHANGE)); 1489 }); 1490 1491 this._element = document.createElement('div'); 1492 this._element.appendChild(this._input); 1493 }, 1494 /** 1495 * Determine whether or not to allow input. 1496 * @type {Boolean} 1497 */ 1498 disabled: { 1499 get: function() { 1500 return this._input.disbaled; 1501 }, 1502 set: function(value) { 1503 this._input.disabled = !!value; 1504 } 1505 } 1506 }); 1507 1508 /** 1509 * @scope enchant.widget.InputTextBox 1510 */ 1511 enchant.widget.InputTextBox = enchant.Class.create(enchant.widget.Input, { 1512 /** 1513 * Text box. 1514 * @constructs 1515 * @extends enchant.widget.Input 1516 */ 1517 initialize: function() { 1518 enchant.widget.Input.call(this); 1519 this._input.type = 'text'; 1520 1521 var metrics = getElementMetrics(this._element.innerHTML); 1522 this.width = metrics.width; 1523 this.height = metrics.height; 1524 1525 var that = this; 1526 this._focused = false; 1527 1528 this._input.addEventListener('focus', function() { 1529 that._focused = true; 1530 }); 1531 1532 this._input.addEventListener('blur', function() { 1533 that._focused = false; 1534 }); 1535 }, 1536 /** 1537 * @type {Number} 1538 */ 1539 selectionStart: { 1540 get: function() { 1541 return this._input.selectionStart; 1542 }, 1543 set: function(n) { 1544 this._input.selectionStart = n; 1545 } 1546 }, 1547 /** 1548 * @type {Number} 1549 */ 1550 selectionEnd: { 1551 get: function() { 1552 return this._input.selectionEnd; 1553 }, 1554 set: function(n) { 1555 this._input.selectionEnd = n; 1556 } 1557 }, 1558 /** 1559 * @type {Boolean} 1560 */ 1561 focused: { 1562 get: function() { 1563 return this._focused; 1564 }, 1565 set: function(bool) { 1566 this._focused = bool; 1567 if (bool) { 1568 this._input.focus(); 1569 } else { 1570 this._input.blur(); 1571 } 1572 } 1573 }, 1574 /** 1575 * Place holder. 1576 * @type {String} 1577 */ 1578 placeholder: { 1579 get: function() { 1580 return this._input.placeholder; 1581 }, 1582 set: function(value) { 1583 this._input.placeholder = value; 1584 } 1585 }, 1586 /** 1587 * Level input into text box. 1588 * @type {String} 1589 */ 1590 value: { 1591 get: function() { 1592 return this._input.value; 1593 }, 1594 set: function(value) { 1595 this._input.value = value; 1596 } 1597 }, 1598 /** 1599 * Text box width. 1600 * @type {Number} 1601 */ 1602 width: { 1603 get: function() { 1604 return this._width; 1605 }, 1606 set: function(width) { 1607 this._width = width; 1608 this._style.width = width + 'px'; 1609 this._input.style.width = width + 'px'; 1610 } 1611 }, 1612 /** 1613 * Text box height. 1614 * @type {Number} 1615 */ 1616 height: { 1617 get: function() { 1618 return this._height; 1619 }, 1620 set: function(height) { 1621 this._height = height; 1622 this._style.height = height + 'px'; 1623 this._input.style.height = height + 'px'; 1624 } 1625 } 1626 }); 1627 1628 /** 1629 * @scope enchant.widget.InputSelectBox 1630 */ 1631 enchant.widget.InputSelectBox = enchant.Class.create(enchant.widget.Input, { 1632 /** 1633 * Select box. 1634 * @param {*} option Levels set in options. 1635 * @example 1636 * var option = { 1637 * male: 'Man', 1638 * female: 'Woman' 1639 * }; 1640 * var selectbox = new InputSelectBox(option); 1641 * 1642 * @constructs 1643 * @extends enchant.widget.Input 1644 */ 1645 initialize: function(table) { 1646 enchant.widget.Input.call(this, 'select'); 1647 var content; 1648 for (var prop in table) { 1649 content = table[prop]; 1650 opt = document.createElement('option'); 1651 opt.value = prop; 1652 opt.textContent = content; 1653 this._input.appendChild(opt); 1654 } 1655 1656 this._input.addEventListener('mousedown', function(e) { 1657 e.stopPropagation(); 1658 }); 1659 1660 var metrics = getElementMetrics(this._element.innerHTML); 1661 this.width = metrics.width; 1662 this.height = metrics.height; 1663 }, 1664 /** 1665 * Level selected. 1666 * @type {String} 1667 */ 1668 selected: { 1669 get: function() { 1670 return this._input.options[this._input.selectedIndex].value; 1671 }, 1672 set: function(value) { 1673 var opt; 1674 for (var i = 0, l = this._input.options.length; i < l; i++) { 1675 opt = this._input.options[i]; 1676 if (opt.getAttribute('value') == value) { 1677 opt.selected = true; 1678 } else { 1679 opt.selected = false; 1680 } 1681 } 1682 return value; 1683 } 1684 } 1685 }); 1686 1687 /** 1688 * @scope enchant.widget.InputCheckBox 1689 */ 1690 enchant.widget.InputCheckBox = enchant.Class.create(enchant.widget.Input, { 1691 /** 1692 * Checkbox. 1693 * @param {String} value Level. 1694 * @param {String} text Label text. 1695 * @param {Boolean} checked Whether or not it is checked. 1696 * @constructs 1697 * @extends enchant.widget.Input 1698 */ 1699 initialize: function(value, text, checked) { 1700 enchant.widget.Input.call(this); 1701 this._input.type = 'checkbox'; 1702 var label = document.createDocumentFragment(); 1703 label.textContent = text; 1704 this._element.appendChild(label); 1705 this.checked = checked; 1706 var metrics = getElementMetrics(this._element.innerHTML); 1707 this.width = metrics.width; 1708 this.height = metrics.height; 1709 }, 1710 /** 1711 * Whether or not it is checked. 1712 * @type {Boolean} 1713 */ 1714 checked: { 1715 get: function() { 1716 return this._input.checked; 1717 }, 1718 set: function(value) { 1719 this._input.checked = !!value; 1720 } 1721 } 1722 }); 1723 1724 /** 1725 * @scope enchant.widget.InputTextArea 1726 */ 1727 enchant.widget.InputTextArea = enchant.Class.create(enchant.Entity, { 1728 /** 1729 * Text area. 1730 * @constructs 1731 * @extends enchant.Entity 1732 */ 1733 initialize: function() { 1734 enchant.Entity.call(this); 1735 var textarea = this._textarea = document.createElement('textarea'); 1736 textarea.style.resize = 'none'; 1737 textarea.style.font = enchant.widget._env.textareaFont; 1738 this._element = document.createElement('div'); 1739 this._element.appendChild(textarea); 1740 var that = this; 1741 this._focused = false; 1742 this._next = null; 1743 this._prev = null; 1744 1745 var that = this; 1746 this.addEventListener(enchant.Event.TOUCH_END, function() { 1747 this._updateVerticalDist(); 1748 }); 1749 this._textarea.addEventListener('input', function() { 1750 that._updateVerticalDist(); 1751 }); 1752 this._textarea.addEventListener('focus', function() { 1753 that._focused = true; 1754 }); 1755 this._textarea.addEventListener('blur', function() { 1756 that._focused = false; 1757 }); 1758 this._textarea.addEventListener('change', function(e) { 1759 that.dispatchEvent(new enchant.Event(enchant.Event.CHANGE)); 1760 }); 1761 }, 1762 _updateVerticalDist: function() { 1763 var w = this.value.split('\n'); 1764 var n = this.selectionStart; 1765 var s = 0; 1766 for (var i = 0, l = w.length; i < l; i++) { 1767 n -= w[i].length + 1; 1768 if (n < 0) { 1769 break; 1770 } 1771 s += w[i].length + 1; 1772 } 1773 var ind = this.selectionStart - s; 1774 if (0 < i) { 1775 this._prev = -Math.max(w[i - 1].length, ind) - 1; 1776 } else { 1777 this._prev = -ind; 1778 } 1779 if (i < l - 1) { 1780 this._next = w[i].length - ind + Math.min(ind, w[i + 1].length) + 1; 1781 } else { 1782 this._next = w[i].length - ind; 1783 } 1784 }, 1785 /** 1786 * @type {Number} 1787 */ 1788 selectionStart: { 1789 get: function() { 1790 return this._textarea.selectionStart; 1791 }, 1792 set: function(n) { 1793 this._textarea.selectionStart = n; 1794 } 1795 }, 1796 /** 1797 * @type {Number} 1798 */ 1799 selectionEnd: { 1800 get: function() { 1801 return this._textarea.selectionEnd; 1802 }, 1803 set: function(n) { 1804 this._textarea.selectionEnd = n; 1805 } 1806 }, 1807 /** 1808 * @type {Boolean} 1809 */ 1810 focused: { 1811 get: function() { 1812 return this._focused; 1813 }, 1814 set: function(bool) { 1815 this._focused = bool; 1816 if (bool) { 1817 this._textarea.focus(); 1818 } else { 1819 this._textarea.blur(); 1820 } 1821 } 1822 }, 1823 /** 1824 [lang]ja] 1825 * プレースホルダ. 1826 [/lang] 1827 * Placeholder. 1828 * @type {String} 1829 */ 1830 placeholder: { 1831 get: function() { 1832 return this._textarea.placeholder; 1833 }, 1834 set: function(value) { 1835 this._textarea.placeholder = value; 1836 } 1837 }, 1838 /** 1839 * Level input into text area. 1840 * @type {String} 1841 */ 1842 value: { 1843 get: function() { 1844 return this._textarea.value; 1845 }, 1846 set: function(value) { 1847 this._textarea.value = value; 1848 } 1849 }, 1850 /** 1851 * Text area width. 1852 * @type {Number} 1853 */ 1854 width: { 1855 get: function() { 1856 return this._width; 1857 }, 1858 set: function(width) { 1859 this._width = width; 1860 this._style.width = width + 'px'; 1861 this._textarea.style.width = width + 'px'; 1862 } 1863 }, 1864 /** 1865 * Text area height. 1866 * @type {Number} 1867 */ 1868 height: { 1869 get: function() { 1870 return this._height; 1871 }, 1872 set: function(height) { 1873 this._height = height; 1874 this._style.height = height + 'px'; 1875 this._textarea.style.height = height + 'px'; 1876 } 1877 } 1878 }); 1879 1880 /** 1881 * @scope enchant.widget.AlertScene 1882 */ 1883 enchant.widget.AlertScene = enchant.Class.create(enchant.widget.Modal, { 1884 /** 1885 * Alert scene. 1886 * Interrupt other input, display alert. 1887 * @param {*} content Content to display. 1888 * @param {String} acceptName Label for acceptance button. 1889 * @example 1890 * var alert = new ConfirmScene('Not possible', 'OK'); 1891 * alert.callback = function() { 1892 * }; 1893 * alert.onaccept = function() { 1894 * }; 1895 * @constructs 1896 * @extends enchant.widget.Modal 1897 */ 1898 initialize: function(content, acceptName) { 1899 var core = enchant.Core.instance; 1900 enchant.widget.Modal.call(this); 1901 this._onaccept = function() { 1902 }; 1903 this.callback = function() { 1904 }; 1905 acceptName = acceptName || enchant.widget._env.acceptName; 1906 1907 var alert = new enchant.widget.Alert(content, acceptName); 1908 this.addChild(alert); 1909 alert.alignHorizontalCenterIn(this).alignVerticalCenterIn(this); 1910 1911 var scene = this; 1912 1913 alert.onaccept = function() { 1914 core.popScene(); 1915 scene._onaccept.apply(this, arguments); 1916 }; 1917 alert.addEventListener(enchant.Event.ACCEPT, function() { 1918 scene.callback(); 1919 }); 1920 this.addEventListener(enchant.Event.ENTER, function() { 1921 Effect.popup.call(alert); 1922 }); 1923 }, 1924 /** 1925 * @type {Function} 1926 */ 1927 onaccept: { 1928 get: function() { 1929 return this._onaccept; 1930 }, 1931 set: function(func) { 1932 this._onaccept = func; 1933 } 1934 } 1935 }); 1936 1937 /** 1938 * @scope enchant.widget.ConfirmScene 1939 */ 1940 enchant.widget.ConfirmScene = enchant.Class.create(enchant.widget.Modal, { 1941 /** 1942 * Confirm scene. 1943 * Interrupt other input, display selection screen. 1944 * @param {*} content Content to display. 1945 * @param {String} acceptName Label for agreement button. 1946 * @param {String} cancelName Label for cancel button. 1947 * @example 1948 * var confirm = new ConfirmScene('Okay?', 'OK', 'NO'); 1949 * confirm.callback = function(bool) { 1950 * // true will return for accept, false will return for cancel. 1951 * }; 1952 * // Processing for cancel and accept can be set separately. 1953 * confirm.oncancel = function() { 1954 * }; 1955 * confirm.onaccept = function() { 1956 * }; 1957 * @constructs 1958 * @extends enchant.widget.Modal 1959 */ 1960 initialize: function(content, acceptName, cancelName) { 1961 var core = enchant.Core.instance; 1962 enchant.widget.Modal.call(this); 1963 this._oncancel = function() { 1964 }; 1965 this._onaccept = function() { 1966 }; 1967 this.callback = function() { 1968 }; 1969 cancelName = cancelName || enchant.widget._env.cancelName; 1970 acceptName = acceptName || enchant.widget._env.acceptName; 1971 1972 var confirm = new enchant.widget.Confirm(content, acceptName, cancelName); 1973 this.addChild(confirm); 1974 confirm.alignHorizontalCenterIn(this).alignVerticalCenterIn(this); 1975 var scene = this; 1976 1977 confirm.oncancel = function() { 1978 core.popScene(); 1979 scene._oncancel.apply(this, arguments); 1980 }; 1981 confirm.onaccept = function() { 1982 core.popScene(); 1983 scene._onaccept.apply(this, arguments); 1984 }; 1985 confirm.addEventListener(enchant.Event.CANCEL, function() { 1986 scene.callback(false); 1987 }); 1988 confirm.addEventListener(enchant.Event.ACCEPT, function() { 1989 scene.callback(true); 1990 }); 1991 this.addEventListener(enchant.Event.ENTER, function() { 1992 Effect.popup.call(confirm); 1993 }); 1994 }, 1995 /** 1996 * @type {Function} 1997 */ 1998 oncancel: { 1999 get: function() { 2000 return this._oncancel; 2001 }, 2002 set: function(func) { 2003 this._oncancel = func; 2004 } 2005 }, 2006 /** 2007 * @type {Function} 2008 */ 2009 onaccept: { 2010 get: function() { 2011 return this._onaccept; 2012 }, 2013 set: function(func) { 2014 this._onaccept = func; 2015 } 2016 } 2017 }); 2018 2019 /** 2020 * @scope enchant.widget.PromptScene 2021 */ 2022 enchant.widget.PromptScene = enchant.Class.create(enchant.widget.Modal, { 2023 /** 2024 * Confirm scene. 2025 * Interrupt other input and display input screen. 2026 * When you wish to allow input to multiple lines, use {@link enchant.widget.InputScene}. 2027 * @param {*} content Content to display. 2028 * @param {String} acceptName Label for agreement button. 2029 * @param {String} cancelName Label for cancel button. 2030 * @param {String} placeholder Placeholder. 2031 * @example 2032 * var confirm = new PromptScene('Input name', 'OK', 'cancel'); 2033 * confirm.placeholder = 'Name'; 2034 * confirm.callback = function(text) { 2035 * // Input array will be returned for accept, whereas null will be returned for cancel. 2036 * }; 2037 * // Processing for cancel and accept can be set separately. 2038 * confirm.oncancel = function() { 2039 * }; 2040 * confirm.onaccept = function(text) { 2041 * }; 2042 * @see enchant.widget.InputScene 2043 * @constructs 2044 * @extends enchant.widget.Modal 2045 */ 2046 initialize: function(content, acceptName, cancelName, placeholder) { 2047 var core = enchant.Core.instance; 2048 var margin = enchant.widget._env.dialogMargin; 2049 enchant.widget.Modal.call(this); 2050 cancelName = cancelName || enchant.widget._env.cancelName; 2051 acceptName = acceptName || enchant.widget._env.acceptName; 2052 this.callback = function() { 2053 }; 2054 this._oncancel = function() { 2055 }; 2056 this._onaccept = function() { 2057 }; 2058 placeholder = placeholder || ''; 2059 2060 var prompt = this._prompt = new enchant.widget.Prompt(content, acceptName, cancelName, placeholder); 2061 prompt.alignHorizontalCenterIn(this).alignVerticalCenterIn(this); 2062 this.addChild(prompt); 2063 var scene = this; 2064 2065 prompt.oncancel = function() { 2066 core.popScene(); 2067 scene._oncancel.apply(this, arguments); 2068 }; 2069 prompt.onaccept = function() { 2070 core.popScene(); 2071 scene._onaccept.apply(this, arguments); 2072 }; 2073 prompt.addEventListener(enchant.Event.CANCEL, function() { 2074 scene.callback(null); 2075 }); 2076 prompt.addEventListener(enchant.Event.ACCEPT, function() { 2077 scene.callback(prompt.value); 2078 }); 2079 this.addEventListener(enchant.Event.ENTER, function() { 2080 Effect.popup.call(prompt); 2081 }); 2082 this.addEventListener(enchant.Event.UP_BUTTON_DOWN, function() { 2083 if (prompt._input.focused) { 2084 prompt._input.selectionStart = 0; 2085 prompt._input.selectionEnd = 0; 2086 } 2087 }); 2088 this.addEventListener(enchant.Event.DOWN_BUTTON_DOWN, function() { 2089 if (prompt._input.focused) { 2090 prompt._input.selectionStart = prompt._input.value.length; 2091 prompt._input.selectionEnd = prompt._input.value.length; 2092 } 2093 }); 2094 this.addEventListener(enchant.Event.LEFT_BUTTON_DOWN, function() { 2095 if (prompt._input.focused) { 2096 prompt._input.selectionStart -= 1; 2097 prompt._input.selectionEnd -= 1; 2098 } 2099 }); 2100 this.addEventListener(enchant.Event.RIGHT_BUTTON_DOWN, function() { 2101 if (prompt._input.focused) { 2102 prompt._input.selectionStart += 1; 2103 } 2104 }); 2105 }, 2106 /** 2107 * content of prompt 2108 * @type {String} 2109 */ 2110 value: { 2111 get: function() { 2112 return this._prompt.value; 2113 2114 }, 2115 set: function(value) { 2116 this._prompt.value = value; 2117 } 2118 }, 2119 /** 2120 * @type {Function} 2121 */ 2122 oncancel: { 2123 get: function() { 2124 return this._oncancel; 2125 }, 2126 set: function(func) { 2127 this._oncancel = func; 2128 } 2129 }, 2130 /** 2131 * @type {Function} 2132 */ 2133 onaccept: { 2134 get: function() { 2135 return this._onaccept; 2136 }, 2137 set: function(func) { 2138 this._onaccept = func; 2139 } 2140 } 2141 }); 2142 2143 /** 2144 * @scope enchant.widget.InputScene 2145 */ 2146 enchant.widget.InputScene = enchant.Class.create(enchant.widget.Modal, { 2147 /** 2148 * Information. 2149 * Interrupts other input and displays input screen. 2150 * Unlike {@link enchant.widget.PromptScene}, you can input to multiple lines. 2151 * @param {*} content Content to display. 2152 * @param {String} acceptName Label for agreement button. 2153 * @param {String} cancelName Label for cancel button. 2154 * @param {String} placeholder Placeholder. 2155 * @example 2156 * var input = new InputScene('New Tweet', 'Tweet', 'Stop', '@twitter '); 2157 * input.callback = function(text) { 2158 * // Input array will be returned for accept, and null for cancel. 2159 * }; 2160 * // Processing for cancel and accept can be set separately. 2161 * input.oncancel = function() { 2162 * }; 2163 * input.onaccept = function(text) { 2164 * }; 2165 * @constructs 2166 * @extends enchant.widget.Modal 2167 */ 2168 initialize: function(text, acceptName, cancelName, placeholder) { 2169 var core = enchant.Core.instance; 2170 var minheight = enchant.widget._env.inputMinHeight; 2171 var maxheight = enchant.widget._env.inputMaxHeight; 2172 var dh = maxheight - minheight; 2173 this.callback = function() { 2174 }; 2175 this._oncancel = function() { 2176 }; 2177 this._onaccept = function() { 2178 }; 2179 this._menu = null; 2180 cancelName = cancelName || enchant.widget._env.cancelName; 2181 acceptName = acceptName || enchant.widget._env.acceptName; 2182 placeholder = placeholder || ''; 2183 2184 enchant.widget.Modal.call(this); 2185 var scene = this; 2186 2187 var cancel = new enchant.widget.Button(cancelName); 2188 var accept = new enchant.widget.Button(acceptName); 2189 var bar = new enchant.widget.NavigationBar(text, cancel, accept); 2190 this.addChild(bar); 2191 var textarea = this._textarea = new enchant.widget.InputTextArea(); 2192 textarea.y += bar.height; 2193 textarea.width = core.width; 2194 textarea.height = maxheight; 2195 textarea.placeholder = placeholder; 2196 textarea.oncancel = function() { 2197 core.popScene(); 2198 scene._oncancel.apply(this, arguments); 2199 }; 2200 textarea.onaccept = function() { 2201 core.popScene(); 2202 scene._onaccept.apply(this, arguments); 2203 }; 2204 this.addChild(textarea); 2205 2206 var _area = textarea._textarea; 2207 _area.onfocus = function() { 2208 Effect.resizeTo.call(textarea, core.width, minheight, 5, enchant.Easing.QUAD_EASEOUT); 2209 if (scene._menu != null) { 2210 scene._menu.tl.moveBy(0, -dh, 5, enchant.Easing.QUAD_EASEOUT); 2211 } 2212 }; 2213 _area.onblur = function() { 2214 Effect.resizeTo.call(textarea, core.width, maxheight, 5, enchant.Easing.QUAD_EASEOUT); 2215 if (scene._menu != null) { 2216 scene._menu.tl.moveBy(0, dh, 5, enchant.Easing.QUAD_EASEOUT); 2217 } 2218 }; 2219 cancel.addEventListener(enchant.Event.TOUCH_END, function() { 2220 textarea.dispatchEvent(new enchant.Event(enchant.Event.CANCEL)); 2221 scene.callback(null); 2222 }); 2223 accept.addEventListener(enchant.Event.TOUCH_END, function() { 2224 textarea.dispatchEvent(new enchant.Event(enchant.Event.ACCEPT)); 2225 scene.callback(textarea.value); 2226 }); 2227 this.addEventListener(enchant.Event.UP_BUTTON_DOWN, function() { 2228 if (textarea.focused) { 2229 textarea.selectionStart += textarea._prev; 2230 textarea.selectionEnd += textarea._prev; 2231 textarea._updateVerticalDist(); 2232 } 2233 }); 2234 this.addEventListener(enchant.Event.DOWN_BUTTON_DOWN, function() { 2235 if (textarea.focused) { 2236 textarea.selectionStart += textarea._next; 2237 textarea._updateVerticalDist(); 2238 } 2239 }); 2240 this.addEventListener(enchant.Event.LEFT_BUTTON_DOWN, function() { 2241 if (textarea.focused) { 2242 textarea.selectionStart -= 1; 2243 textarea.selectionEnd -= 1; 2244 textarea._updateVerticalDist(); 2245 } 2246 }); 2247 this.addEventListener(enchant.Event.RIGHT_BUTTON_DOWN, function() { 2248 if (textarea.focused) { 2249 textarea.selectionStart += 1; 2250 textarea._updateVerticalDist(); 2251 } 2252 }); 2253 }, 2254 /** 2255 * @type {*} 2256 */ 2257 menu: { 2258 get: function() { 2259 return this._menu; 2260 }, 2261 set: function(menu) { 2262 if (this._menu) { 2263 this.removeChild(this._menu); 2264 } 2265 this.x = 0; 2266 this.y = enchant.widget._env.itemHeight + enchant.widget._env.inputMaxHeight; 2267 this.addChild(menu); 2268 this._menu = menu; 2269 } 2270 }, 2271 /** 2272 * Level input into text area. 2273 * @type {String} 2274 */ 2275 value: { 2276 get: function() { 2277 return this._textarea.value; 2278 }, 2279 set: function(value) { 2280 this._textarea.value = value; 2281 } 2282 }, 2283 /** 2284 * @type {String} 2285 */ 2286 placeholder: { 2287 get: function() { 2288 return this._textarea.placeholder; 2289 }, 2290 set: function(str) { 2291 this._textarea.placeholder = str; 2292 } 2293 }, 2294 /** 2295 * @type {Function} 2296 */ 2297 oncancel: { 2298 get: function() { 2299 return this._oncancel; 2300 }, 2301 set: function(func) { 2302 this._oncancel = func; 2303 } 2304 }, 2305 /** 2306 * @type {Function} 2307 */ 2308 onaccept: { 2309 get: function() { 2310 return this._onaccept; 2311 }, 2312 set: function(func) { 2313 this._onaccept = func; 2314 } 2315 } 2316 }); 2317 2318 /** 2319 * @scope enchant.widget.ListElement 2320 */ 2321 enchant.widget.ListElement = enchant.Class.create(enchant.widget.EntityGroup, { 2322 /** 2323 * List items. 2324 * Normally {@link enchant.widget.ListItem} or {@link enchant.widget.ListItemVertical} are used. 2325 * @param {Number} width Element width. 2326 * @param {Number} height Element height. 2327 * @see enchant.widget.ListItem 2328 * @see enchant.widget.ListItemVertical 2329 * @constructs 2330 * @extends enchant.widget.EntityGroup 2331 */ 2332 initialize: function(width, height) { 2333 enchant.widget.EntityGroup.call(this, width, height); 2334 this._content; 2335 this._rawContent; 2336 }, 2337 /** 2338 * Renew change. 2339 */ 2340 refresh: function() { 2341 var content = this._content; 2342 var margin = enchant.widget._env.listItemMargin; 2343 if (content) { 2344 content.alignLeftIn(this, margin).alignVerticalCenterIn(this); 2345 } 2346 this.background = this._background; 2347 }, 2348 /** 2349 * ListElement content. 2350 * @type {enchant.Entity[]} 2351 */ 2352 content: { 2353 get: function() { 2354 return this._rawContent; 2355 }, 2356 set: function(content) { 2357 this._rawContent = content; 2358 content = enchant.widget.parseContent(content); 2359 if (this._content) { 2360 this.removeChild(this._content); 2361 } 2362 this.addChild(content); 2363 this._content = content; 2364 this.refresh(); 2365 } 2366 }, 2367 /** 2368 * @type {Number} 2369 */ 2370 width: { 2371 get: function() { 2372 return this._width; 2373 }, 2374 set: function(width) { 2375 this._style.width = (this._width = width) + 'px'; 2376 if (this.background instanceof enchant.widget.Ninepatch) { 2377 this.background.width = this.width; 2378 } 2379 if (this._content) { 2380 this.refresh(); 2381 } 2382 } 2383 }, 2384 /** 2385 * @type {Number} 2386 */ 2387 height: { 2388 get: function() { 2389 return this._height; 2390 }, 2391 set: function(height) { 2392 this._style.height = (this._height = height) + 'px'; 2393 if (this.background instanceof enchant.widget.Ninepatch) { 2394 this.background.height = this.height; 2395 } 2396 if (this._content) { 2397 this.refresh(); 2398 } 2399 } 2400 } 2401 }); 2402 2403 /** 2404 * @scope enchant.widget.ListItem 2405 */ 2406 enchant.widget.ListItem = enchant.Class.create(enchant.widget.ListElement, { 2407 /** 2408 * List elements. 2409 * Icons and leftmost buttons can be set. 2410 * Use {@link enchant.widget.ListItemVertical} to set items lined up vertically. 2411 * @param {Number} width Element width. 2412 * @param {Number} height Element height. 2413 * @param {*} [content] ListItem content. 2414 * @param {enchant.Sprite|enchant.Surface} [icon] ListItem icon. 2415 * @param {enchant.Sprite|enchant.Surface} [icon] ListItem right side icon. 2416 * @see enchant.widget.ListItemVertical 2417 * @constructs 2418 * @extends enchant.widget.ListElement 2419 */ 2420 initialize: function(width, height, content, icon, rightIcon) { 2421 var core = enchant.Core.instance; 2422 width = width || core.width; 2423 height = height || enchant.widget._env.itemHeight; 2424 content = content || ''; 2425 enchant.widget.ListElement.call(this, width, height); 2426 this._icon; 2427 this._rawIcon; 2428 this._rightIcon; 2429 this._rawRightIcon; 2430 this.content = content; 2431 if (icon) { 2432 this.icon = icon; 2433 } 2434 if (rightIcon) { 2435 this.rightIcon = rightIcon; 2436 } 2437 var np = new enchant.widget.Ninepatch(this.width, this.height); 2438 np.src = core.assets['listItemBg.png']; 2439 this.background = np; 2440 }, 2441 /** 2442 * Renew changes. 2443 */ 2444 refresh: function() { 2445 var icon = this._icon; 2446 var content = this._content; 2447 var right = this._rightIcon; 2448 var margin = enchant.widget._env.listItemMargin; 2449 if (icon) { 2450 Adjust.fitToY.call(icon, this, margin, margin); 2451 icon.alignLeftIn(this, margin).alignVerticalCenterIn(this); 2452 if (content) { 2453 content.alignRightOf(icon, margin).alignVerticalCenterIn(this); 2454 } 2455 } else if (content) { 2456 content.alignLeftIn(this, margin).alignVerticalCenterIn(this); 2457 } 2458 if (right) { 2459 right.alignRightIn(this, margin).alignVerticalCenterIn(this); 2460 } 2461 }, 2462 /** 2463 * Icon. 2464 * It appear on the left. 2465 * @type {enchant.Sprite|enchant.Surface} 2466 */ 2467 icon: { 2468 get: function() { 2469 return this._rawIcon; 2470 }, 2471 set: function(icon) { 2472 this._rawIcon = icon; 2473 icon = enchant.widget.parseContent(icon); 2474 if (this._icon) { 2475 this.removeChild(this._icon); 2476 } 2477 this.addChild(icon); 2478 this._icon = icon; 2479 this.refresh(); 2480 } 2481 }, 2482 /** 2483 * Icon on the right. 2484 * It appear on the right. 2485 * @type {enchant.Sprite|enchant.Surface} 2486 */ 2487 rightIcon: { 2488 get: function() { 2489 return this._rawRightIcon; 2490 }, 2491 set: function(right) { 2492 this._rawRightIcon = right; 2493 right = enchant.widget.parseContent(right); 2494 if (this._rightIcon) { 2495 this.removeChild(this._rightIcon); 2496 } 2497 this.addChild(right); 2498 this._rightIcon = right; 2499 this.refresh(); 2500 } 2501 } 2502 }); 2503 2504 /** 2505 * @scope enchant.widget.ListItemVertical 2506 */ 2507 enchant.widget.ListItemVertical = enchant.Class.create(enchant.widget.ListElement, { 2508 /** 2509 * List items. 2510 * Header and footer can be set. 2511 * @param {Number} width Element width. 2512 * @param {Number} height Element height. 2513 * @param {*} [content] ListItemVertical content. 2514 * @param {*} [header] ListItemVertical header. 2515 * @param {*} [footer] ListItemVertical footer. 2516 * @constructs 2517 * @extends enchant.widget.ListElement 2518 */ 2519 initialize: function(width, height, content, header, footer) { 2520 var core = enchant.Core.instance; 2521 enchant.widget.ListElement.call(this, width, height); 2522 this._header; 2523 this._rawHeader; 2524 this._footer; 2525 this._rawFooter; 2526 if (content) { 2527 this.content = content; 2528 } 2529 if (header) { 2530 this.header = header; 2531 } 2532 if (footer) { 2533 this.footer = footer; 2534 } 2535 this.refresh(); 2536 var np = new enchant.widget.Ninepatch(this.width, this.height); 2537 np.src = core.assets['listItemBg.png']; 2538 this.background = np; 2539 }, 2540 /** 2541 * Renew change. 2542 */ 2543 refresh: function() { 2544 var header = this._header; 2545 var footer = this._footer; 2546 var content = this._content; 2547 var margin = enchant.widget._env.listItemMargin; 2548 if (header) { 2549 header.alignLeftIn(this, margin).alignTopIn(this, margin); 2550 2551 Adjust.fillX.call(content, this, margin); 2552 if (content) { 2553 content.alignLeftIn(this, margin).alignBottomOf(header, margin); 2554 } 2555 } else { 2556 Adjust.fillX.call(content, this, margin); 2557 if (content) { 2558 content.alignLeftIn(this, margin).alignTopIn(this, margin); 2559 } 2560 } 2561 if (footer) { 2562 footer.alignLeftIn(this, margin).alignBottomOf(content, margin); 2563 } 2564 var height = 0; 2565 var p; 2566 var scale; 2567 var contents = [ header, content, footer ]; 2568 for (prop in contents) { 2569 p = contents[prop]; 2570 if (p) { 2571 scale = p.scaleY || 1; 2572 height += ~~(p.height * scale); 2573 height += margin * 2; 2574 } 2575 } 2576 this._style.height = (this._height = height) + 'px'; 2577 if (this.background instanceof enchant.widget.Ninepatch) { 2578 this.background.height = this.height; 2579 } 2580 }, 2581 /** 2582 * Header. 2583 * It appear above the content. 2584 * @type {*} 2585 */ 2586 header: { 2587 get: function() { 2588 return this._rawHeader; 2589 }, 2590 set: function(header) { 2591 this._rawHeader = header; 2592 header = enchant.widget.parseContent(header); 2593 if (this._header) { 2594 this.removeChild(this._header); 2595 } 2596 this.addChild(header); 2597 this._header = header; 2598 this.refresh(); 2599 } 2600 }, 2601 /** 2602 * Footer. 2603 * It appear below the content. 2604 * @type {*} 2605 */ 2606 footer: { 2607 get: function() { 2608 return this._rawFooter; 2609 }, 2610 set: function(footer) { 2611 this._rawFooter = footer; 2612 footer = enchant.widget.parseContent(footer); 2613 if (this._footer) { 2614 this.removeChild(this._footer); 2615 } 2616 this.addChild(footer); 2617 this._footer = footer; 2618 this.refresh(); 2619 } 2620 } 2621 }); 2622 2623 /** 2624 * @scope enchant.widget.ScrollView 2625 */ 2626 enchant.widget.ScrollView = enchant.Class.create(enchant.widget.EntityGroup, { 2627 /** 2628 * Scroll view. 2629 * Scroll is possible for content set. 2630 * @param {Number} width View width. 2631 * @param {Number} height View height. 2632 * @constructs 2633 * @extends enchant.widget.EntityGroup 2634 */ 2635 initialize: function(width, height) { 2636 enchant.widget.EntityGroup.call(this, width, height); 2637 this._style.overflow = 'hidden'; 2638 this._content; 2639 }, 2640 /** 2641 * ScrollView content. 2642 * @type {enchant.Entity} 2643 */ 2644 content: { 2645 get: function() { 2646 return this._content; 2647 }, 2648 set: function(content) { 2649 if (this._content) { 2650 this.removeChild(this._content); 2651 } 2652 this.addChild(content); 2653 this._content = content; 2654 } 2655 }, 2656 /** 2657 * Scroll content. 2658 * Correct level will become upwards scroll. 2659 * @param {Number} dy Scroll level. 2660 */ 2661 scroll: function(dy) { 2662 if (!this._content) { 2663 return; 2664 } 2665 if (this.height >= this._content.height) { 2666 this._content.y = 0; 2667 return; 2668 } 2669 var max = 0 2670 var min = this.height - this._content.height 2671 2672 var sy = this._content.y + dy; 2673 if (sy > max) { 2674 dy = max - this._content.y; 2675 } else if (sy < min) { 2676 dy = min - this._content.y; 2677 } 2678 this._content.y += dy; 2679 } 2680 }); 2681 2682 /** 2683 * @scope enchant.widget.ListView 2684 */ 2685 enchant.widget.ListView = enchant.Class.create(enchant.widget.ScrollView, { 2686 /** 2687 * @param {Number} width View width. 2688 * @param {Number} height View height. 2689 * @param {Boolean} draggable Sets whether or not item can be dragged. 2690 * @constructs 2691 * @extends enchant.widget.ScrollView 2692 */ 2693 initialize: function(width, height, draggable) { 2694 enchant.widget.ScrollView.call(this, width, height); 2695 var detector = new enchant.widget.GestureDetector(this); 2696 this.draggable = !!draggable; 2697 this.content = []; 2698 var dragging = null; 2699 var dy = 0; 2700 var prev = null; 2701 var next = null; 2702 var pthreshold = 0; 2703 var nthreshold = 0; 2704 this._clipping = true; 2705 2706 enchant.widget.GestureDetector.gestureEvents.forEach(function(type) { 2707 this.addEventListener(type, function(e) { 2708 var item = this.getSelectedItem(e); 2709 if (item != null) { 2710 item.dispatchEvent(e); 2711 } 2712 }); 2713 }, this); 2714 2715 var removeChild = enchant.widget.EntityGroup.prototype.removeChild; 2716 var insertBefore = enchant.widget.EntityGroup.prototype.insertBefore; 2717 2718 var that = this; 2719 var checkChangePos = function(direction) { 2720 var y = dragging.y; 2721 var my = dragging.height; 2722 var nextSibling; 2723 if (prev && y <= pthreshold && direction < 0) { 2724 prev.y += my; 2725 removeChild.call(that._content, dragging); 2726 insertBefore.call(that._content, dragging, prev); 2727 updateHoldStat(dragging); 2728 } else if (next && nthreshold <= y && direction > 0) { 2729 next.y -= my; 2730 removeChild.call(that._content, dragging); 2731 var nextSibling = that._content.childNodes[that._content.childNodes.indexOf(next) + 1]; 2732 insertBefore.call(that._content, dragging, nextSibling); 2733 updateHoldStat(dragging); 2734 } 2735 }; 2736 2737 var updateHoldStat = function(element) { 2738 var i = that._content.childNodes.indexOf(element); 2739 if (i > 0) { 2740 prev = that._content.childNodes[i - 1]; 2741 pthreshold = prev.y + prev.height - element.height / 2; 2742 } else { 2743 prev = null; 2744 } 2745 if (i < that._content.childNodes.length - 1) { 2746 next = that._content.childNodes[i + 1]; 2747 nthreshold = next.y - element.height / 2; 2748 } else { 2749 next = null; 2750 } 2751 }; 2752 this.addEventListener(enchant.Event.ENTER_FRAME, function() { 2753 if (dy != 0) { 2754 var old = this._content.y; 2755 this.scroll(dy); 2756 checkChangePos(-dy); 2757 dragging.y -= this._content.y - old; 2758 } 2759 }); 2760 this.addEventListener(enchant.Event.HOLD, function(e) { 2761 if (!this.draggable) { 2762 return; 2763 } 2764 dragging = this.getSelectedItem(e); 2765 if (dragging == null) { 2766 return; 2767 } 2768 dragging.opacity = 0.8; 2769 dragging._style.zIndex = 2; 2770 updateHoldStat(dragging); 2771 }); 2772 this.addEventListener(enchant.Event.RELEASE, function() { 2773 if (!this.draggable || dragging == null) { 2774 return; 2775 } 2776 dy = 0; 2777 if (prev) { 2778 dragging.y = prev.y + prev.height; 2779 } else { 2780 dragging.y = 0; 2781 } 2782 dragging.opacity = 1.0; 2783 dragging._style.zIndex = 0; 2784 dragging = null; 2785 prev = null; 2786 next = null; 2787 }); 2788 var spd = 40; 2789 this.addEventListener(enchant.Event.DRAG, function(e) { 2790 if (!this.draggable || dragging == null) { 2791 return; 2792 } 2793 checkChangePos(e.dy); 2794 dragging.y += e.dy; 2795 if (e.localY < spd) { 2796 dy = spd - e.localY; 2797 } else if (this.height - spd < e.localY) { 2798 dy = this.height - spd - e.localY; 2799 } else { 2800 dy = 0; 2801 } 2802 }); 2803 this.addEventListener(enchant.Event.SLIP, function(e) { 2804 this.scroll(e.dy); 2805 }); 2806 }, 2807 /** 2808 * ListView content. 2809 * @type {enchant.widget.ListElement[]} 2810 */ 2811 content: { 2812 get: function() { 2813 return this._content.childNodes; 2814 }, 2815 set: function(content) { 2816 var addChild = enchant.widget.EntityGroup.prototype.addChild; 2817 var removeChild = enchant.widget.EntityGroup.prototype.removeChild; 2818 if (this._content) { 2819 removeChild.call(this, this._content); 2820 } 2821 var list = new List(content); 2822 list.width = this.width; 2823 addChild.call(this, list); 2824 this._content = list; 2825 } 2826 }, 2827 /** 2828 * Acquires event target. 2829 * @param {enchant.Event} event 2830 * @return {enchant.widget.ListElement} 2831 */ 2832 getSelectedItem: function(e) { 2833 var y = e.localY - this._content.y; 2834 var list = this._content; 2835 var child; 2836 var h = 0; 2837 for (var i = 0, l = list.childNodes.length; i < l; i++) { 2838 child = list.childNodes[i]; 2839 h += child.height; 2840 if (h > y) { 2841 return child; 2842 } 2843 } 2844 return null; 2845 }, 2846 addChild: function(child) { 2847 this._content.addChild(child); 2848 }, 2849 removeChild: function(child) { 2850 this._content.removeChild(child); 2851 }, 2852 insertBefore: function(child, reference) { 2853 this._content.insertBefore(child, reference); 2854 } 2855 }); 2856 2857 2858 var _emptyFunction = function(){}; 2859 2860 /** 2861 * @scope enchant.widget.LazyListItem 2862 */ 2863 enchant.widget.LazyListItem = enchant.Class.create(enchant.widget.ListItem, { 2864 /** 2865 * LazyListItem is a class which can be used in an enchant.widget.LazyListView instance 2866 * to enable the lazy loading of the content of a list item. 2867 * The LazyListView instance will call the loadResources function of the LazyListItem instance 2868 * when it feels like the content will be required soon. 2869 * Implementors must implement the loadResources function. 2870 * See the LazyListView example of enchant.js (examples/plugins/widget/LazyListView/). 2871 * 2872 * @see enchant.widget.LazyListView 2873 * @see enchant.widget.ListItem 2874 * @constructs 2875 * @extends enchant.widget.ListItem 2876 */ 2877 initialize: function() { 2878 enchant.widget.ListItem.apply(this, arguments); 2879 }, 2880 _loadResources: function() { 2881 if(this.loadResources) { 2882 this.loadResources(); 2883 this._loadResources = _emptyFunction; 2884 } 2885 } 2886 }); 2887 2888 var _enchantWidgetListViewPrototypeScroll = enchant.widget.ListView.prototype.scroll; 2889 var _enchantWidgetListViewPrototypeAddChild = enchant.widget.ListView.prototype.addChild; 2890 var _enchantWidgetListViewPrototypeRemoveChild = enchant.widget.ListView.prototype.removeChild; 2891 var _enchantWidgetListViewPrototypeInsertBefore = enchant.widget.ListView.prototype.insertBefore; 2892 2893 /** 2894 * @scope enchant.widget.LazyListView 2895 */ 2896 enchant.widget.LazyListView = enchant.Class.create(enchant.widget.ListView, { 2897 /** 2898 * LazyListView is a class which enables a ListView to load the content of it's 2899 * child ListItems lazily by using enchant.widget.LazyListItem (s). 2900 * It is also possible to use regular ListItems which will behave 2901 * like if they where added to a ListView (therefore, no lazy initialization). 2902 * Furthermore, this LazyListView will dispatch an enchant.Event.CONTENT_REQUESTED event 2903 * when the ListView feels like the available content is not sufficient. 2904 * The enchant.Event.CONTENT_REQUESTED can be used to add new items to the LazyListView. 2905 * See the LazyListView example of enchant.js (examples/plugins/widget/LazyListView/). 2906 * 2907 * @see enchant.widget.ListView 2908 * @see enchant.widget.LazyListItem 2909 * @constructs 2910 * @extends enchant.widget.ListView 2911 */ 2912 initialize: function() { 2913 enchant.widget.ListView.apply(this, arguments); 2914 }, 2915 _updateContent: function() { 2916 var visibleHeight = this.height - this._content.y + 100; 2917 var content = this.content; 2918 var contentLength = content.length; 2919 for(var i = 0; i < contentLength; i++) { 2920 if(content[i].y <= visibleHeight && content[i]._loadResources) { 2921 content[i]._loadResources.call(content[i]); 2922 } else if(content[i].y > visibleHeight) { 2923 return; 2924 } 2925 } 2926 2927 var event = new enchant.Event(enchant.Event.CONTENT_REQUESTED); 2928 this.dispatchEvent(event); // as we did not return in the loop there are not enough list items available, request new content 2929 }, 2930 scroll: function() { 2931 _enchantWidgetListViewPrototypeScroll.apply(this, arguments); 2932 this._updateContent(); 2933 }, 2934 addChild: function(child) { 2935 _enchantWidgetListViewPrototypeAddChild.apply(this, arguments); 2936 this._updateContent(); 2937 }, 2938 removeChild: function(child) { 2939 _enchantWidgetListViewPrototypeRemoveChild.apply(this, arguments); 2940 this._updateContent(); 2941 }, 2942 insertBefore: function(child, reference) { 2943 _enchantWidgetListViewPrototypeInsertBefore.apply(this, arguments); 2944 this._updateContent(); 2945 } 2946 }); 2947 2948 var List = enchant.Class.create(enchant.widget.EntityGroup, { 2949 initialize: function(array) { 2950 var core = enchant.Core.instance; 2951 enchant.widget.EntityGroup.call(this); 2952 this.width = core.width; 2953 this.height = core.height; 2954 this._itemHeight = 0; 2955 var element; 2956 for (var i = 0, l = array.length; i < l; i++) { 2957 element = array[i]; 2958 this.addChild(element); 2959 } 2960 2961 this._dragging = null; 2962 this._pthreshold = 0; 2963 this._nthreshold = 0; 2964 this._index = 0; 2965 }, 2966 addChild: function(child) { 2967 var i = this.childNodes.length; 2968 enchant.widget.EntityGroup.prototype.addChild.call(this, child); 2969 this.refresh(i - 1); 2970 }, 2971 insertBefore: function(child, reference) { 2972 enchant.widget.EntityGroup.prototype.insertBefore.call(this, child, reference); 2973 var i = this.childNodes.indexOf(child); 2974 this.refresh(i - 1); 2975 }, 2976 removeChild: function(child) { 2977 var i = this.childNodes.indexOf(child); 2978 if (i != -1) { 2979 enchant.widget.EntityGroup.prototype.removeChild.call(this, child); 2980 this.refresh(i - 1); 2981 } 2982 }, 2983 refresh: function(i) { 2984 var i, l, h, start, child; 2985 if (i > 0) { 2986 start = this.childNodes[i - 1]; 2987 h = start.y + start.height; 2988 } else { 2989 i = 0; 2990 h = 0; 2991 } 2992 for (l = this.childNodes.length; i < l; i++) { 2993 child = this.childNodes[i]; 2994 child.y = h; 2995 h += child.height; 2996 } 2997 this.height = this._itemHeight = h; 2998 }, 2999 _getElementByLocalPosition: function(localX, localY) { 3000 var child; 3001 var h = 0; 3002 for (var i = 0, l = this.childNodes.length; i < l; i++) { 3003 child = this.childNodes[i]; 3004 h += child.height; 3005 if (h > localY) { 3006 break; 3007 } 3008 } 3009 return child; 3010 } 3011 }); 3012 3013 /** 3014 * @scope enchant.widget.NavigationBar 3015 */ 3016 enchant.widget.NavigationBar = enchant.Class.create(enchant.widget.EntityGroup, { 3017 /** 3018 * Navigation bar. 3019 * Items are set for sent, right, and left. 3020 * @param {*} center Object you wish to display in center. 3021 * @param {*} left Item you wish to display to left. 3022 * @param {*} right Item you wish to display to right. 3023 * @constructs 3024 * @extends enchant.widget.EntityGroup 3025 */ 3026 initialize: function(center, left, right) { 3027 var core = enchant.Core.instance; 3028 enchant.widget.EntityGroup.call(this, core.width, enchant.widget._env.itemHeight); 3029 this._center; 3030 this._rawCenter; 3031 this._left; 3032 this._rawLeft; 3033 this._right; 3034 this._rawRight; 3035 this.center = center; 3036 if (left) { 3037 this.left = left; 3038 } 3039 if (right) { 3040 this.right = right; 3041 } 3042 this.refresh(); 3043 3044 var np = new enchant.widget.Ninepatch(this.width, this.height); 3045 np.src = core.assets['navigationBar.png']; 3046 this.background = np; 3047 }, 3048 /** 3049 * Renew change. 3050 */ 3051 refresh: function() { 3052 var center = this._center; 3053 var left = this._left; 3054 var right = this._right; 3055 var margin = enchant.widget._env.listItemMargin; 3056 if (center) { 3057 center.alignHorizontalCenterIn(this).alignVerticalCenterIn(this); 3058 } 3059 if (left) { 3060 left.alignLeftIn(this, margin).alignVerticalCenterIn(this); 3061 } 3062 if (right) { 3063 right.alignRightIn(this, margin).alignVerticalCenterIn(this); 3064 } 3065 }, 3066 /** 3067 * Central content. 3068 * @type {*} 3069 */ 3070 center: { 3071 get: function() { 3072 return this._rawCenter; 3073 }, 3074 set: function(center) { 3075 this._rawCenter = center; 3076 center = enchant.widget.parseContent(center, enchant.widget._env.navigationBarFont); 3077 if (this._center) { 3078 this.removeChild(this._center); 3079 } 3080 this.addChild(center); 3081 this._center = center; 3082 this.refresh(); 3083 } 3084 }, 3085 /** 3086 * Left content. 3087 * It appear in left aligned position. 3088 * @type {*} 3089 */ 3090 left: { 3091 get: function() { 3092 return this._rawLeft; 3093 }, 3094 set: function(left) { 3095 this._rawLeft = left; 3096 left = enchant.widget.parseContent(left); 3097 if (this._left) { 3098 this.removeChild(this._left); 3099 } 3100 this.addChild(left); 3101 this._left = left; 3102 this.refresh(); 3103 } 3104 }, 3105 /** 3106 * Right content. 3107 * It appear in right aligned position. 3108 * @type {*} 3109 */ 3110 right: { 3111 get: function() { 3112 return this._rawRight; 3113 }, 3114 set: function(right) { 3115 this._rawRight = right; 3116 right = enchant.widget.parseContent(right); 3117 if (this._right) { 3118 this.removeChild(this._right); 3119 } 3120 this.addChild(right); 3121 this._right = right; 3122 this.refresh(); 3123 } 3124 } 3125 }); 3126 3127 enchant.widget.Icon = enchant.Class.create(enchant.widget.EntityGroup, { 3128 initialize: function(icon, text) { 3129 enchant.widget.EntityGroup.call(this, 44, 44); 3130 icon = enchant.widget.parseContent(icon); 3131 text = enchant.widget.parseContent(text, enchant.widget._env.font); 3132 var sx = 32 / icon.width; 3133 var sy = 32 / icon.height; 3134 icon.scaleX = icon.scaleY = Math.min(sx, sy); 3135 icon.alignHorizontalCenterIn(this).alignTopIn(this); 3136 text.alignHorizontalCenterIn(this).alignBottomOf(icon, -7); 3137 this.addChild(icon); 3138 this.addChild(text); 3139 } 3140 }); 3141 3142 /** 3143 * @scope enchant.widget.IconMenu 3144 */ 3145 enchant.widget.IconMenu = enchant.Class.create(enchant.widget.EntityGroup, { 3146 /** 3147 * Menu with items lined up horizontally. 3148 * @param {enchant.Entity[]} Array of button. 3149 * @constructs 3150 * @extends enchant.widget.EntityGroup 3151 */ 3152 initialize: function(buttons) { 3153 var core = enchant.Core.instance; 3154 if (!(buttons instanceof Array)) { 3155 buttons = Array.prototype.slice.call(arguments); 3156 } 3157 enchant.widget.EntityGroup.call(this, core.width, enchant.widget._env.itemHeight); 3158 this._bgs = []; 3159 this._icons = []; 3160 this.content = buttons; 3161 this.refresh(); 3162 this._bgs.forEach(function(bg) { 3163 var width = bg.width; 3164 var height = bg.height; 3165 var np = new enchant.widget.Ninepatch(width, height); 3166 np.src = core.assets['iconMenuBg.png']; 3167 bg.image = np; 3168 }); 3169 }, 3170 /** 3171 * Renew change. 3172 */ 3173 getSelectedItem: function(e) { 3174 var x = e.localX; 3175 var list = this._bgs; 3176 var child; 3177 var w = 0; 3178 for (var i = 0, l = list.childNodes.length; i < l; i++) { 3179 child = list.childNodes[i]; 3180 w += child.width; 3181 if (w > x) { 3182 return this._icons[i]; 3183 } 3184 } 3185 return null; 3186 }, 3187 refresh: function() { 3188 var icon, bg, bgwidth; 3189 var margin = enchant.widget._env.listItemMargin; 3190 var arr = distribute(this.width, this._icons.length); 3191 var _width = 0; 3192 var menu = this; 3193 3194 for (var i = 0, l = this._icons.length; i < l; i++) { 3195 bgwidth = arr[i]; 3196 icon = this._icons[i]; 3197 bg = this._bgs[i]; 3198 bg.width = bgwidth; 3199 bg.height = this.height; 3200 bg.image.resize(bg.width, bg.height); 3201 bg.x = _width; 3202 3203 icon.addEventListener(enchant.Event.TOUCH_END, (function(bg) { 3204 return function(e) { 3205 bg.dispatchEvent(e); 3206 }; 3207 })(bg)); 3208 bg.addEventListener(enchant.Event.TOUCH_END, (function(i, elem) { 3209 return function(e) { 3210 var evt = new enchant.Event(enchant.Event.TAP); 3211 evt.x = e.x; 3212 evt.y = e.y; 3213 evt.index = i; 3214 evt.element = elem; 3215 menu.dispatchEvent(evt); 3216 }; 3217 })(i, icon)); 3218 3219 icon.alignHorizontalCenterIn(bg).alignVerticalCenterIn(bg); 3220 icon.x += _width; 3221 3222 _width += bg.width; 3223 } 3224 }, 3225 addChild: function(child) { 3226 var core = enchant.Core.instance; 3227 var addChild = enchant.widget.EntityGroup.prototype.addChild; 3228 var size = enchant.widget._env.itemHeight; 3229 var sp = new enchant.Sprite(size, size); 3230 addChild.call(this, sp); 3231 this._bgs.push(sp); 3232 addChild.call(this, child); 3233 this._icons.push(child); 3234 var np = new enchant.widget.Ninepatch(sp.width, sp.height); 3235 np.src = core.assets['iconMenuBg.png']; 3236 sp.image = np; 3237 this.refresh(); 3238 }, 3239 insertBefore: function(child, target) { 3240 var core = enchant.Core.instance; 3241 var insertBefore = enchant.widget.EntityGroup.prototype.insertBefore; 3242 var i = this._icons.indexOf(target); 3243 var size = enchant.widget._env.itemHeight; 3244 var sp, np; 3245 if (i != -1) { 3246 target = this._bgs[i]; 3247 sp = new enchant.Sprite(size, size); 3248 insertBefore.call(this, sp, target); 3249 this._bgs.splice(i, 0, sp); 3250 insertBefore.call(this, child, target); 3251 this._icons.splice(i, 0, child); 3252 np = new enchant.widget.Ninepatch(sp.width, sp.height); 3253 np.src = core.assets['iconMenuBg.png']; 3254 sp.image = np; 3255 this.refresh(); 3256 } 3257 }, 3258 removeChild: function(child) { 3259 var removeChild = enchant.widget.EntityGroup.prototype.removeChild; 3260 var i = this._icons.indexOf(child); 3261 if (i != -1) { 3262 var bg = this._bgs[this._bgs.length - 1]; 3263 removeChild.call(this, bg); 3264 this._bgs.pop(); 3265 removeChild.call(this, child); 3266 this._icons.splice(i, 1); 3267 this.refresh(); 3268 } 3269 }, 3270 /** 3271 * Set icon. 3272 * @param {enchant.Entity[]} content Array for object you wish to display. 3273 */ 3274 content: { 3275 get: function() { 3276 return this._icons; 3277 }, 3278 set: function(content) { 3279 var removeChild = enchant.widget.EntityGroup.prototype.removeChild; 3280 var menu = this; 3281 if (this.childNodes) { 3282 this.childNodes.slice().forEach(function(child) { 3283 removeChild.call(menu, child); 3284 }); 3285 } 3286 content.forEach(function(child) { 3287 menu.addChild(child); 3288 }); 3289 } 3290 } 3291 }); 3292 3293 })(); 3294