diff --git a/apidoc/Titanium/UI/Switch.yml b/apidoc/Titanium/UI/Switch.yml index 099376d476e..cd69c9c8295 100644 --- a/apidoc/Titanium/UI/Switch.yml +++ b/apidoc/Titanium/UI/Switch.yml @@ -7,6 +7,9 @@ description: | On iOS, the switch appears as an iOS on/off switch and doesn't have any text associated with it. + + On Mobile Web, a switch always has text associated with it, and appears as a + toggle button, similar to Android. Use the method to create a switch. extends: Titanium.UI.View @@ -22,14 +25,14 @@ properties: - name: color summary: Color to use for switch text. type: String - platforms: [android] + platforms: [android, mobileweb] - name: enabled summary: Set to `true` to enable the switch, `false` to disable the switch. type: Boolean - name: font summary: Font to use for the switch text. type: Font - platforms: [android] + platforms: [android, mobileweb] - name: style summary: Style of the switch, either checkbox or toggle button. description: | @@ -43,7 +46,7 @@ properties: Text alignment, specified using one of the text alignment constants: [TEXT_ALIGNMENT_LEFT](Titanium.UI.TEXT_ALIGNMENT_LEFT), [TEXT_ALIGNMENT_CENTER](Titanium.UI.TEXT_ALIGNMENT_CENTER), or [TEXT_ALIGNMENT_RIGHT](Titanium.UI.TEXT_ALIGNMENT_RIGHT). type: [String,Number] default: - platforms: [android] + platforms: [android, mobileweb] - name: title summary: text to display with checkbox. Used if style is type: String @@ -53,13 +56,13 @@ properties: description: | Used if style is type: String - platforms: [android] + platforms: [android, mobileweb] - name: titleOn summary: Text to display when a toggle button-style switch is toggled off. description: | Used if style is type: String - platforms: [android] + platforms: [android, mobileweb] - name: value summary: Current switch value, `true` if the switch is on, and `false` if switch is off. @@ -73,7 +76,7 @@ properties: [TEXT_VERTICAL_ALIGNMENT_TOP](Titanium.UI.TEXT_VERTICAL_ALIGNMENT_TOP). type: [Number,String] default: Titanium.UI.TEXT_VERTICAL_ALIGNMENT_CENTER - platforms: [android] + platforms: [android, mobileweb] examples: - title: Simple Switch Example diff --git a/mobileweb/src/Ti/UI/Button.js b/mobileweb/src/Ti/UI/Button.js index 1e8323a639a..3d3004a5f1b 100644 --- a/mobileweb/src/Ti/UI/Button.js +++ b/mobileweb/src/Ti/UI/Button.js @@ -41,6 +41,21 @@ define("Ti/UI/Button", ["Ti/_/declare", "Ti/_/UI/FontWidget", "Ti/_/dom", "Ti/_/ this._setDefaultLook(); + // Add the enabled/disabled dimmer + this._disabledDimmer = dom.create("div", { + className: "TiUISwitchDisableDimmer", + style: { + pointerEvents: "none", + opacity: 0, + backgroundColor: "white", + width: "100%", + height: "100%", + position: "absolute", + top: 0, + left: 0 + } + }, this.domNode); + this.addEventListener("touchstart",function(){ if (this.selectedColor) { setStyle(this._buttonTitle,"color",this.selectedColor); @@ -62,22 +77,6 @@ define("Ti/UI/Button", ["Ti/_/declare", "Ti/_/UI/FontWidget", "Ti/_/dom", "Ti/_/ _defaultHeight: "auto", - backgroundColor: postDoBackground, - - backgroundDisabledColor: postDoBackground, - - backgroundDisabledImage: postDoBackground, - - backgroundFocusedColor: postDoBackground, - - backgroundFocusedImage: postDoBackground, - - backgroundImage: postDoBackground, - - backgroundSelectedColor: postDoBackground, - - backgroundSelectedImage: postDoBackground, - _updateLook: function() { if (this.backgroundColor || this.backgroundDisabledColor || this.backgroundDisabledImage || this.backgroundFocusedColor || this.backgroundFocusedImage || this.backgroundImage || this.backgroundSelectedColor || this.backgroundSelectedImage) { @@ -106,6 +105,9 @@ define("Ti/UI/Button", ["Ti/_/declare", "Ti/_/UI/FontWidget", "Ti/_/dom", "Ti/_/ this.domNode.className = className.substring(0,className.length - " TiUIButtonDefault".length); this.borderWidth = this._previousBorderWidth; this.borderColor = this._previousBorderColor; + setStyle(this._disabledDimmer,{ + opacity: 0 + }); } }, @@ -151,6 +153,27 @@ define("Ti/UI/Button", ["Ti/_/declare", "Ti/_/UI/FontWidget", "Ti/_/dom", "Ti/_/ return value; } }, + + enabled: { + set: function(value, oldValue) { + + if (value !== oldValue) { + if (!value) { + this._hasDefaultLook && setStyle(this._disabledDimmer,{ + opacity: 0.5 + }); + } else { + this._hasDefaultLook && setStyle(this._disabledDimmer,{ + opacity: 0 + }); + } + this._setTouchEnabled(value); + } + return value; + }, + value: true + }, + image: { set: function(value) { require.on(this._buttonImage, "load", lang.hitch(this, function () { diff --git a/mobileweb/src/Ti/UI/Switch.js b/mobileweb/src/Ti/UI/Switch.js index f89d389c924..da9eb2826ac 100644 --- a/mobileweb/src/Ti/UI/Switch.js +++ b/mobileweb/src/Ti/UI/Switch.js @@ -1,79 +1,258 @@ -define("Ti/UI/Switch", ["Ti/_/declare", "Ti/_/UI/Widget", "Ti/_/dom", "Ti/_/css", "Ti/_/style"], function(declare, Widget, dom, css, style) { +define("Ti/UI/Switch", ["Ti/_/declare", "Ti/_/UI/FontWidget", "Ti/_/dom", "Ti/_/css", "Ti/_/style", "Ti/_/lang"], function(declare, FontWidget, dom, css, style, lang) { - var set = style.set, - undef; + var setStyle = style.set, + postDoBackground = { + post: "_updateLook" + }, + undef, + unitize = dom.unitize; - return declare("Ti.UI.Switch", Widget, { + return declare("Ti.UI.Switch", FontWidget, { + + domType: "button", constructor: function(args) { - this._switch = dom.create("input", { - className: css.clean("TiUISwitchSwitch") - }); - set(this._switch,"width","100%"); - set(this._switch,"height","100%"); - this._switch.type = "checkbox"; - this.domNode.appendChild(this._switch); + + // This container holds the flex boxes used to position the elements + this._contentContainer = dom.create("div", { + className: "TiUIButtonContentContainer", + style: {display: ["-webkit-box", "-moz-box"], + boxOrient: "vertical", + boxPack: "center", + boxAlign: "stretch", + width: "100%", + height: "100%" + } + }, this.domNode) + + // Create the text box and a flex box to align it + this._titleContainer = dom.create("div", { + className: "TiUIButtonTextAligner", + style: { + display: ["-webkit-box", "-moz-box"], + boxOrient: "vertical", + boxPack: "center", + boxAlign: "center", + boxFlex: 1 + } + }, this._contentContainer); + this._switchTitle = dom.create("div", { + className: "TiUISwitchTitle", + style: { + whiteSpace: "nowrap", + pointerEvents: "none", + textAlign: "center" + } + }, this._titleContainer); + this._addStyleableDomNode(this._switchTitle); + + // Create the switch indicator and a flex box to contain it + this._indicatorContainer = dom.create("div", { + className: "TiUIButtonTextAligner", + style: { + display: ["-webkit-box", "-moz-box"], + boxPack: "center", + boxAlign: "center", + marginTop: "3px" + } + }, this._contentContainer); + this._switchIndicator = dom.create("div", { + className: "TiUISwitchIndicator", + style: { + padding: "4px 4px", + borderRadius: "4px", + border: "1px solid #888", + pointerEvents: "none", + width: "40px" + } + }, this._indicatorContainer); + this._switchIndicator.domNode += " TiUISwitchIndicator"; + + // Add the enabled/disabled dimmer + this._disabledDimmer = dom.create("div", { + className: "TiUISwitchDisableDimmer", + style: { + pointerEvents: "none", + opacity: 0, + backgroundColor: "white", + width: "100%", + height: "100%", + position: "absolute", + top: 0, + left: 0 + } + }, this.domNode); + + // Set the default look + this._setDefaultLook(); + this.domNode.addEventListener("click",lang.hitch(this,function(){ + this.value = !this.value; + })); + + this.value = false; }, - _defaultWidth: "auto", - _defaultHeight: "auto", + _updateLook: function() { + if (this.backgroundColor || this.backgroundDisabledColor || this.backgroundDisabledImage || this.backgroundFocusedColor || + this.backgroundFocusedImage || this.backgroundImage || this.backgroundSelectedColor || this.backgroundSelectedImage) { + this._clearDefaultLook(); + } else { + this._setDefaultLook(); + } + this._doBackground(); + }, + + _setDefaultLook: function() { + if (!this._hasDefaultLook) { + this._hasDefaultLook = true; + this.domNode.className += " TiUIButtonDefault"; + setStyle(this.domNode,"padding","6px 6px"); + this._previousBorderWidth = this.borderWidth; + this._previousBorderColor = this.borderColor; + this.borderWidth = 1; + this.borderColor = "#aaa"; + } + }, + + _clearDefaultLook: function() { + if (this._hasDefaultLook) { + this._hasDefaultLook = false; + var className = this.domNode.className; + this.domNode.className = className.substring(0,className.length - " TiUIButtonDefault".length); + setStyle(this.domNode,"padding",0); + this.borderWidth = this._previousBorderWidth; + this.borderColor = this._previousBorderColor; + setStyle(this._disabledDimmer,{ + opacity: 0 + }); + } + }, + _getContentWidth: function() { - return this._switch.clientWidth; + return Math.max(this._measureText(this._switchTitle.innerHTML, this._switchTitle).width, this._switchIndicator.offsetWidth) + (this._hasDefaultLook ? 12 : 0); }, + _getContentHeight: function() { - return this.textArea.clientHeight; - }, - _setTouchEnabled: function(value) { - Widget.prototype._setTouchEnabled.apply(this,arguments); - this.slider && set(this._switch,"pointerEvents", value ? "auto" : "none"); + return this._measureText(this._switchTitle.innerHTML, this._switchTitle).height + // Text height + this._switchIndicator.offsetHeight + // Indicator height + 3 + // Padding between the indicator and text + (this._hasDefaultLook ? 12 : 0); // Border of the default style }, + + _defaultWidth: "auto", + + _defaultHeight: "auto", properties: { - title: { - get: function(value) { - // TODO - console.debug('Property "Titanium.UI.Switch#.title" is not implemented yet.'); - return value; - }, + + // Override the default background info so we can hook into it + backgroundColor: postDoBackground, + + backgroundDisabledColor: postDoBackground, + + backgroundDisabledImage: postDoBackground, + + backgroundFocusedColor: postDoBackground, + + backgroundFocusedImage: postDoBackground, + + backgroundImage: postDoBackground, + + backgroundSelectedColor: postDoBackground, + + backgroundSelectedImage: postDoBackground, + + color: { set: function(value) { - console.debug('Property "Titanium.UI.Switch#.title" is not implemented yet.'); + setStyle(this._switchTitle, "color", value); return value; } }, - titleOff: { - get: function(value) { - // TODO - console.debug('Property "Titanium.UI.Switch#.titleOff" is not implemented yet.'); + enabled: { + set: function(value, oldValue) { + + if (value !== oldValue) { + if (!value) { + this._oldValue = this.value; + this.value && (this.value = false); + this._hasDefaultLook && setStyle(this._disabledDimmer,{ + opacity: 0.5 + }); + } else { + this.value = this._oldValue; + this._hasDefaultLook && setStyle(this._disabledDimmer,{ + opacity: 0 + }); + } + this._setTouchEnabled(value); + } return value; }, + value: true + }, + + textAlign: { set: function(value) { - console.debug('Property "Titanium.UI.Switch#.titleOff" is not implemented yet.'); + var cssValue = ""; + switch(value) { + case Ti.UI.TEXT_VERTICAL_ALIGNMENT_TOP: cssValue = "start"; break; + case Ti.UI.TEXT_VERTICAL_ALIGNMENT_CENTER: cssValue = "center"; break; + case Ti.UI.TEXT_VERTICAL_ALIGNMENT_BOTTOM: cssValue = "end"; break; + } + setStyle(this._titleContainer, "boxAlign", cssValue); return value; } }, - titleOn: { - get: function(value) { - // TODO - console.debug('Property "Titanium.UI.Switch#.titleOn" is not implemented yet.'); + titleOff: { + set: function(value) { + if (!this.value) { + this._switchTitle.innerHTML = value; + this._hasAutoDimensions() && this._triggerParentLayout(); + } return value; }, + value: "Off" + }, + + titleOn: { set: function(value) { - console.debug('Property "Titanium.UI.Switch#.titleOn" is not implemented yet.'); + if (this.value) { + this._switchTitle.innerHTML = value; + this._hasAutoDimensions() && this._triggerParentLayout(); + } return value; - } + }, + value: "On" }, value: { - get: function(value) { - return this._switch.value; - }, set: function(value) { - this._switch.value = value ? true : false - return this._switch.value; + setStyle(this._switchIndicator,{ + backgroundColor: value ? "#0f0" : "#aaa" + }); + this._switchTitle.innerHTML = value ? this.titleOn : this.titleOff; + this._hasAutoDimensions() && this._triggerParentLayout(); + this.fireEvent("change",{ + value: !!value + }); + return value; } - } + }, + + verticalAlign: { + set: function(value) { + var cssValue = ""; + switch(value) { + case Ti.UI.TEXT_VERTICAL_ALIGNMENT_TOP: cssValue = "start"; break; + case Ti.UI.TEXT_VERTICAL_ALIGNMENT_CENTER: cssValue = "center"; break; + case Ti.UI.TEXT_VERTICAL_ALIGNMENT_BOTTOM: cssValue = "end"; break; + } + setStyle(this._titleContainer, "boxPack", cssValue); + }, + value: Ti.UI.TEXT_VERTICAL_ALIGNMENT_CENTER + }, } });