WinJS 自定义控件之 VItemContainer

ItemContainer的变异控件

基本使用

<div id="testcon" data-win-control="XboxJS.OK.VItemContainer" style="width: 200px; height: 200px; background-color: red;"
data-win-voice="{ srcElement: select('.win-text-tiletitle'), targetElement: select('.win-voice-textdisplay')}">
<div class="win-text-tiletitle win-voice-inactivetext">SUBMIT</div>
</div>

效果: 点击无声音,无css效果

支持VUI NUI focus event invoked event 等 其他itemContainer所有功能

(function itemContainerInit(global, WinJS, undefined) {
"use strict";

var utilities = WinJS.Utilities;
var createEvent = utilities._createEventProperty;
var eventNames = {
invoked: "invoked"
};

WinJS.Namespace.define("XboxJS.OK", {
/// <summary locid="XboxJS.UI.ItemContainer">
/// Displays an item that can be invoked.
/// </summary>
/// <icon src="XboxJS.ui.itemcontainer.12x12.png" width="12" height="12" />
/// <icon src="ui_xboxjs.ui.itemcontainer.16x16.png" width="16" height="16" />
/// <htmlSnippet><![CDATA[
/// <div data-win-control="XboxJS.UI.ItemContainer">HTML content</div>
/// </div>]]></htmlSnippet>
/// <event name="invoked" bubbles="true" locid="WinJS.UI.ItemContainer_e:invoked">Raised when the user taps or clicks the item.</event>
/// <part name="itemcontainer" class="win-itemcontainer" locid="XboxJS.UI.ItemContainer_part:itemcontainer">Main container for the selection item control.</part>
/// <part name="focusedoutline" class="win-focusedoutline" locid="XboxJS.UI.ItemContainer_part:focusedoutline">Used to display an outline when the main container has keyboard focus.</part>
/// <resource type="javascript" src="//Microsoft.Xbox.WinJS.1.0/js/base.js" shared="true" />
/// <resource type="javascript" src="//Microsoft.Xbox.WinJS.1.0/js/ui.js" shared="true" />
/// <resource type="css" src="//Microsoft.Xbox.WinJS.1.0/css/ui-dark.css" shared="true" />
VItemContainer: WinJS.Namespace._lazy(function () {
var strings = {
get duplicateConstruction() { return WinJS.Resources._getWinJSString("ui/duplicateConstruction").value; }
};

var VItemContainer = WinJS.Class.define(function VItemContainer_ctor(element, options) {
/// <signature helpKeyword="XboxJS.UI.ItemContainer.ItemContainer">
/// <summary locid="XboxJS.UI.ItemContainer.constructor">
/// Creates a new ItemContainer control.
/// </summary>
/// <param name="element" type="HTMLElement" domElement="true" isOptional="true" locid="XboxJS.UI.ItemContainer.constructor_p:element">
/// The DOM element that hosts the ItemContainer control.
/// </param>
/// <param name="options" type="Object" isOptional="true" locid="XboxJS.UI.ItemContainer.constructor_p:options">
/// An object that contains one or more property/value pairs to apply to the new control.
/// Each property of the options object corresponds to one of the control's properties or events.
/// </param>
/// <returns type="XboxJS.UI.ItemContainer" locid="XboxJS.UI.ItemContainer.constructor_returnValue">
/// The new itemContainer control.
/// </returns>
/// </signature>
element = element || document.createElement("DIV");
this._id = element.id || element.uniqueID;
this._writeProfilerMark("constructor,StartTM");

options = options || {};

if (element.winControl) {
throw new WinJS.ErrorFromName("XboxJS.OK.ItemContainer.DuplicateConstruction", strings.duplicateConstruction);
}

// Attaching JS control to DOM element
element.winControl = this;

this._element = element;
WinJS.Utilities.addClass(this.element, "win-focusable win-disposable " + XboxJS.OK.VItemContainer._ClassName.itemContainer);

// Div elements are not always focusable unless they have a tabIndex. Because the ItemContainer must always be focusable, we
// assign a tabIndex if one does not already exist. We use a tabIndex of 0, which instructs Trident to choose the default tabbing
// flow order for the control.
if (!this.element.tabIndex) {
this.element.tabIndex = 0;
}

this._focusableIndicator = null;

// Handler to route click events to children of the container first
this._setupInternalTree();

WinJS.UI.setOptions(this, options);

var that = this;
this._handleKeyDownBind = function _handleKeyDown(ev) {
if ((ev.key === "Spacebar" ||
ev.key === "Enter" ||
ev.key === "GamepadA") &&
!ev.repeat) {
// WinJS.Utilities.addClass(that._element, "win-itemcontainer-active");
}
};

this._handleKeyUpBind = function _handleKeyUp(ev) {
if ((ev.key === "Spacebar" ||
ev.key === "Enter" ||
ev.key === "GamepadA") &&
!ev.repeat &&
WinJS.Utilities.hasClass(that._element, "win-itemcontainer-active")) {
that._fireInvokeEvent(ev.deviceSessionId);
WinJS.Utilities.removeClass(that._element, "win-itemcontainer-active");
}
};

this._handlePointerDownBind = function _handlePointerDown(ev) {
// WinJS.Utilities.addClass(that._element, "win-itemcontainer-active");
if (XboxJS.OK.VItemContainer._sounds.selectButtonPressingKinect &&
ev.pressExtent !== 0) {
//XboxJS.OK.VItemContainer._sounds.selectButtonPressingKinect.play();
}
};

this._handlePointerUpBind = function _handlePointerUp(ev) {
WinJS.Utilities.removeClass(that._element, "win-itemcontainer-active");
};

this._handlePointerOutBind = function _handlePointerOut(ev) {
WinJS.Utilities.removeClass(that._element, "win-itemcontainer-active");
};

this._handleClickBind = function _handleClick(ev) {
that._fireInvokeEvent(ev.deviceSessionId);
};

// We need to remove the active class when the ItemContainer loses focus otherwise, the user can
// focus on an ItemContainer, press down on gamepadA, then press left to move to another element.
// Because the user will never keyup on this ItemContainer, the ItemContainer will always be stuck
// in the pressed visual state.
this._handleBlurBind = function _handleBlur(ev) {
// WinJS.Utilities.removeClass(that._element, "win-itemcontainer-active");
};

this._element.addEventListener("keydown", this._handleKeyDownBind, false);
this._element.addEventListener("keyup", this._handleKeyUpBind, false);
this._element.addEventListener("MSPointerDown", this._handlePointerDownBind, false);
this._element.addEventListener("MSPointerUp", this._handlePointerUpBind, false);
this._element.addEventListener("MSPointerOut", this._handlePointerOutBind, false);
this._element.addEventListener("click", this._handleClickBind, false);
this._element.addEventListener("blur", this._handleBlurBind, false);

//if (WinJS.Utilities.hasWinRT && Windows.Xbox && Windows.Xbox.Audio && Windows.Xbox.Audio.SoundClip && !XboxJS.OK.VItemContainer._sounds.initialized) {
// XboxJS.OK.VItemContainer._sounds.selectButtonClick = new Windows.Xbox.Audio.SoundClip(new Windows.Foundation.Uri("ms-winsoundevent:///SelectButtonClick"));
// XboxJS.OK.VItemContainer._sounds.selectButtonPressingKinect = new Windows.Xbox.Audio.SoundClip(new Windows.Foundation.Uri("ms-winsoundevent:///SelectButtonPressingKinect"));
// XboxJS.OK.VItemContainer._sounds.initialized = true;
//};

this._writeProfilerMark("constructor,StopTM");
}, {
/// <field type="HTMLElement" domElement="true" hidden="true" locid="XboxJS.UI.ItemContainer.element" helpKeyword="XboxJS.UI.ItemContainer.element">
/// Gets the DOM element that hosts the itemContainer control.
/// </field>
element: {
get: function () {
return this._element;
}
},

/// <field type="Function" locid="XboxJS.UI.ItemCotrol.oninvoked" helpKeyword="XboxJS.UI.ItemCotrol.oninvoked">
/// Raised when the user taps or clicks the item.
/// </field>
oninvoked: createEvent(eventNames.invoked),

dispose: function () {
/// <signature helpKeyword="XboxJS.UI.ItemContainer.dispose">
/// <summary locid="XboxJS.UI.ItemContainer.dispose">
/// Disposes this control.
/// </summary>
/// </signature>

if (this._disposed) {
return;
}
this._disposed = true;

this._element.removeEventListener("keydown", this._handleKeyDownBind);
this._element.removeEventListener("keyup", this._handleKeyUpBind);
this._element.removeEventListener("MSPointerDown", this._handlePointerDownBind);
this._element.removeEventListener("MSPointerUp", this._handlePointerUpBind);
this._element.removeEventListener("MSPointerOut", this._handlePointerOutBind);
this._element.removeEventListener("click", this._handleClickBind);
this._element.removeEventListener("blur", this._handleBlurBind);

this._handleKeyDownBind = null;
this._handleKeyUpBind = null;
this._handlePointerDownBind = null;
this._handlePointerUpBind = null;
this._handlePointerOutBind = null;
this._handleClickBind = null;
this._voiceUIhost = null;

WinJS.Utilities.disposeSubTree(this.element);

this._element.winControl = null;
this._element = null;
},

_setupInternalTree: function VItemContainer_setupInternalTree() {
var item = document.createElement("div");
item.className = WinJS.UI._itemClass;
this._focusableIndicator = document.createElement("div");
this._focusableIndicator.className = XboxJS.OK.VItemContainer._ClassName.focusableIndicator;

this._captureProxy = document.createElement("div");
this._captureProxy.className = XboxJS.OK.VItemContainer._ClassName.captureProxy;

this._voiceUIhost = document.createElement("div");
this._voiceUIhost.className = XboxJS.OK.VItemContainer._ClassName.voiceUIhost;

var innerHTML = "<div class='" + XboxJS.OK.VItemContainer._ClassName.voiceUIContainer + "'>" +
" <div class='" + XboxJS.OK.VItemContainer._ClassName.voiceOverlay + "'></div>" +
" <div class='" + XboxJS.OK.VItemContainer._ClassName.voiceTextDisplay + "'></div>" +
"</div>";
this._voiceUIhost.innerHTML += innerHTML;

this._itemBox = document.createElement("div");
this._itemBox.className = WinJS.UI._itemBoxClass;

var child = this.element.firstChild;
while (child) {
var sibling = child.nextSibling;
item.appendChild(child);
child = sibling;
}

this.element.appendChild(this._itemBox);
this._itemBox.appendChild(item);
this.element.appendChild(this._focusableIndicator);
this.element.appendChild(this._voiceUIhost);
this.element.appendChild(this._captureProxy);

this._voiceUIContainer = this._element.querySelector(XboxJS.OK.VItemContainer._ClassName.voiceUIContainer);
this._voiceOverlay = this._element.querySelector(XboxJS.OK.VItemContainer._ClassName.voiceOverlay);
this._voiceTextDisplay = this._element.querySelector(XboxJS.OK.VItemContainer._ClassName.voiceTextDisplay);
},

_fireInvokeEvent: function VItemContainer_fireInvokeEvent(deviceSessionId) {
var eventObject = document.createEvent("CustomEvent");
// We set the deviceSessionId to zero for unrecognized devices (eg. if the event that caused the invoke event doesn't
// have a deviceSessionId). Invokation via voice is one example. 0 is just a convention.
eventObject.initCustomEvent(eventNames.invoked, true, false, { deviceSessionId: deviceSessionId || 0 });
this.element.dispatchEvent(eventObject);

if (XboxJS.OK.VItemContainer._sounds.selectButtonClick) {
XboxJS.OK.VItemContainer._sounds.selectButtonClick.play();
}
},

_writeProfilerMark: function VItemContainer_writeProfilerMark(text) {
var message = "XboxJS.OK.ItemContainer:" + this._id + ":" + text;
msWriteProfilerMark(message);
WinJS.log && WinJS.log(message, null, "itemcontainerprofiler");
}
}, {

// Names of classes used by the ItemContainer.
_ClassName: {
itemContainer: "win-itemcontainer",
focusableIndicator: "win-tile-focusindicator",
captureProxy: "win-itemcontainer-captureproxy",
voiceUIhost: "win-voice-host",
voiceUIContainer: "win-voice-container",
voiceOverlay: "win-voice-overlay",
voiceTextDisplay: "win-voice-textdisplay win-voice-activetext"
},

_sounds: {
initialized: false,
selectButtonClick: null,
selectButtonPressingKinect: null
}
});
WinJS.Class.mix(VItemContainer, WinJS.UI.DOMEventMixin);
return VItemContainer;
}),
});
})(this, WinJS);