1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 /** @class
  9 
 10   Represents a Checkbox Button.
 11 
 12   The view is an `SC.ButtonView` put into toggle mode and with the 'theme' property
 13   set to "checkbox".
 14 
 15   Rendering
 16   ----------------------------
 17   SC.ButtonView delegates its rendering to its theme. As the theme is set
 18   to "checkbox", the way the checkbox renders (including DOM) will actually
 19   be different than SC.ButtonView's.
 20 
 21   @extends SC.ButtonView
 22   @since SproutCore 1.0
 23 */
 24 SC.CheckboxView = SC.ButtonView.extend(
 25 /** @scope SC.CheckboxView.prototype */ {
 26 
 27   /**
 28     @type Array
 29     @default ['sc-checkbox-view', 'sc-checkbox-control']
 30     @see SC.View#classNames
 31   */
 32   classNames: ['sc-checkbox-view', 'sc-checkbox-control'],
 33 
 34   /**
 35     The WAI-ARIA role of checkbox.
 36 
 37     @type String
 38     @readOnly
 39   */
 40   ariaRole: 'checkbox',
 41 
 42   // no special theme for Checkbox; button defaults to 'square', so we have to stop that.
 43   themeName: null,
 44 
 45   /**
 46     @type String
 47     @default 'checkboxRenderDelegate'
 48   */
 49   renderDelegateName: 'checkboxRenderDelegate',
 50 
 51   /**
 52     Ellipsis is disabled by default to allow multiline text
 53 
 54     @type Boolean
 55     @default NO
 56   */
 57   needsEllipsis: NO,
 58 
 59   /**
 60     `YES` if `isEnabledInPane` is `YES`, `NO` otherwise
 61 
 62     @type Boolean
 63     @default NO
 64     @observes isEnabledInPane
 65   */
 66   acceptsFirstResponder: function() {
 67     if (SC.FOCUS_ALL_CONTROLS) { return this.get('isEnabledInPane'); }
 68     return NO;
 69   }.property('isEnabledInPane'),
 70 
 71   /** @private */
 72   _toggleValue: function(){
 73     var isOn = this.get('value') === this.get('toggleOnValue');
 74     this.set('value', isOn ? this.get('toggleOffValue') : this.get('toggleOnValue'));
 75   },
 76 
 77   /** @private */
 78   mouseDown: function(evt) {
 79     // Fast path, reject secondary clicks.
 80     if (evt.which && evt.which !== 1) return false;
 81 
 82     if(!this.get('isEnabledInPane')) return YES;
 83     this.set('isActive', YES);
 84     this._isMouseDown = YES;
 85     if (evt && this.get('acceptsFirstResponder')) evt.allowDefault();
 86     return YES;
 87   },
 88 
 89   /** @private */
 90   mouseUp: function(evt) {
 91     if(!this.get('isEnabledInPane')) return YES;
 92 
 93     this.set('isActive', NO);
 94     this._isMouseDown = NO;
 95 
 96     // fire action
 97     if (this.get('buttonBehavior') !== SC.HOLD_BEHAVIOR) {
 98       if (this.$().within(evt.target)) {
 99         this._toggleValue();
100         this._action(evt);
101       }
102     }
103 
104     return YES;
105 
106   },
107 
108   /** @private */
109   keyDown: function(evt) {
110     // handle tab key
111     if(!this.get('isEnabledInPane')) return YES;
112 
113     if (evt.which === 9 || evt.keyCode === 9) {
114       var view = evt.shiftKey ? this.get('previousValidKeyView') : this.get('nextValidKeyView');
115       if(view) view.becomeFirstResponder();
116       else evt.allowDefault();
117       return YES ; // handled
118     }
119 
120     if (evt.which === 13 || evt.which === 32) {
121       this._toggleValue();
122 
123       // fire action
124       if (this.get('buttonBehavior') !== SC.HOLD_BEHAVIOR) {
125         if (this.$().within(evt.target)) { this._action(evt); }
126       }
127 
128       return YES ; // handled
129     }
130 
131     // let other keys through to browser
132     evt.allowDefault();
133 
134     return NO;
135   },
136 
137 
138 
139   /** @private */
140   touchStart: function(evt) {
141     return this.mouseDown(evt);
142   },
143 
144   /** @private */
145   touchEnd: function(evt) {
146     return this.mouseUp(evt);
147   }
148 
149 });
150