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