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