diff --git a/composer/translate-composer.js b/composer/translate-composer.js
index 4edba8276f..c7e68dc687 100644
--- a/composer/translate-composer.js
+++ b/composer/translate-composer.js
@@ -1333,6 +1333,7 @@ var TranslateComposer = exports.TranslateComposer = Composer.specialize(/** @len
translateStartEvent.initCustomEvent("translateStart", true, true, null);
translateStartEvent.translateX = x;
translateStartEvent.translateY = y;
+ translateStartEvent.targetElement = this.element;
// Event needs to be the same shape as the one in flow-translate-composer
translateStartEvent.scroll = 0;
translateStartEvent.pointer = this._observedPointer;
@@ -1347,6 +1348,7 @@ var TranslateComposer = exports.TranslateComposer = Composer.specialize(/** @len
translateEndEvent.initCustomEvent("translateEnd", true, true, null);
translateEndEvent.translateX = this._translateX;
translateEndEvent.translateY = this._translateY;
+ translateEndEvent.targetElement = this.element;
// Event needs to be the same shape as the one in flow-translate-composer
translateEndEvent.scroll = 0;
translateEndEvent.pointer = this._observedPointer;
@@ -1361,6 +1363,7 @@ var TranslateComposer = exports.TranslateComposer = Composer.specialize(/** @len
translateCancelEvent.initCustomEvent("translateCancel", true, true, null);
translateCancelEvent.translateX = this._translateX;
translateCancelEvent.translateY = this._translateY;
+ translateCancelEvent.targetElement = this.element;
// Event needs to be the same shape as the one in flow-translate-composer
translateCancelEvent.scroll = 0;
translateCancelEvent.pointer = this._observedPointer;
@@ -1374,6 +1377,7 @@ var TranslateComposer = exports.TranslateComposer = Composer.specialize(/** @len
translateEvent.initCustomEvent("translate", true, true, null);
translateEvent.translateX = this._translateX;
translateEvent.translateY = this._translateY;
+ translateEvent.targetElement = this.element;
// Event needs to be the same shape as the one in flow-translate-composer
translateEvent.scroll = 0;
translateEvent.pointer = this._observedPointer;
diff --git a/core/core.js b/core/core.js
index fcd2f05df5..671173a7cd 100644
--- a/core/core.js
+++ b/core/core.js
@@ -5,6 +5,7 @@
require("collections/shim");
require("./shim/object");
require("./shim/array");
+require("./shim/math");
require("./extras/object");
require("./extras/date");
require("./extras/element");
diff --git a/core/shim/math.js b/core/shim/math.js
new file mode 100644
index 0000000000..54927647f8
--- /dev/null
+++ b/core/shim/math.js
@@ -0,0 +1,8 @@
+if (!Math.sign) {
+ /**
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
+ */
+ Math.sign = function (x) {
+ return ((x > 0) - (x < 0)) || +x;
+ };
+}
diff --git a/index.html b/index.html
index d8ed569d0d..9215af1a12 100644
--- a/index.html
+++ b/index.html
@@ -34,6 +34,7 @@
Components:
HTML Fragment
List
ListItem
+ ListItemMenu
NumberField
Placeholder
Radio
diff --git a/test/mocks/data/icons/check.reel/check.html b/test/mocks/data/icons/check.reel/check.html
index e51aa98f67..c27ae1c6b9 100644
--- a/test/mocks/data/icons/check.reel/check.html
+++ b/test/mocks/data/icons/check.reel/check.html
@@ -2,7 +2,7 @@
-
+
+
+
+
+
+
diff --git a/ui/list-item-menu.info/sample/package.json b/ui/list-item-menu.info/sample/package.json
new file mode 100644
index 0000000000..d81a128285
--- /dev/null
+++ b/ui/list-item-menu.info/sample/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "list-item-menu-sample",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../"
+ }
+}
diff --git a/ui/list-item-menu.info/sample/ui/main.reel/main.css b/ui/list-item-menu.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..77d2cdd06b
--- /dev/null
+++ b/ui/list-item-menu.info/sample/ui/main.reel/main.css
@@ -0,0 +1,82 @@
+html, body, .Main {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.Main {
+ padding: 20px;
+}
+
+header {
+ margin: 60px 0;
+ font-size: 2rem;
+ text-align: center;
+ color: #33495d;
+ height: 40px;
+}
+
+.items {
+ margin: auto;
+ height: 500px;
+ width: 300px;
+}
+
+.ListItemMenu.gray .ListItemMenu-options button {
+ font-size: 14px;
+ white-space: nowrap;
+ color: rgb(100, 100, 100);
+}
+
+.ListItemMenu.gray .ListItemMenu-options button .dot {
+ background-color: rgb(100, 100, 100);
+}
+
+.ListItemMenu.gray.is-opened.right-side .ListItemMenu-content {
+ border-right: 1px solid #bdc3c7;
+}
+
+.ListItemMenu.gray.is-opened.left-side .ListItemMenu-content {
+ border-left: 1px solid #bdc3c7;
+}
+
+.ListItemMenu .archive {
+ background-color: #2C82C9;
+}
+
+.ListItemMenu .delete {
+ background-color: #e74c3c;
+}
+
+.ListItemMenu .more {
+ background-color: #9E9D9B;
+}
+
+.ListItemMenu .dot {
+ height: 5px;
+ width: 5px;
+ background-color: white;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.ListItemMenu .move {
+ background-color: #5659C9;
+}
+
+.ListItemMenu .pin {
+ background-color: #2CC990;
+}
+
+.ListItemMenu[data-montage-id='list-item-menu-8'] .ListItemMenu-content {
+ padding-left: 16px;
+ padding-right: 16px;
+}
diff --git a/ui/list-item-menu.info/sample/ui/main.reel/main.html b/ui/list-item-menu.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..209b0e9a9e
--- /dev/null
+++ b/ui/list-item-menu.info/sample/ui/main.reel/main.html
@@ -0,0 +1,436 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Item 8 (injected)
+
+
+
+
+
+
+
diff --git a/ui/list-item-menu.info/sample/ui/main.reel/main.js b/ui/list-item-menu.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..c8d75171c5
--- /dev/null
+++ b/ui/list-item-menu.info/sample/ui/main.reel/main.js
@@ -0,0 +1,21 @@
+var Component = require("montage/ui/component").Component,
+ Promise = require('montage/core/promise');
+
+exports.Main = Component.specialize(/** @lends Main# */{
+
+
+ handleArchiveAction: {
+ value: function () {
+ console.log("archive");
+ this.listItem.close();
+ }
+ },
+
+ handleDeleteAction: {
+ value: function () {
+ console.log("delete");
+ this.listItem.close();
+ }
+ }
+
+});
diff --git a/ui/list-item-menu.reel/list-item-menu.css b/ui/list-item-menu.reel/list-item-menu.css
new file mode 100644
index 0000000000..47aa60aa37
--- /dev/null
+++ b/ui/list-item-menu.reel/list-item-menu.css
@@ -0,0 +1,227 @@
+.ListItemMenu {
+ position: relative;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 42px;
+ border: 1px solid #c8c7cc;
+ box-sizing: border-box;
+ overflow: hidden;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.ListItemMenu .hot-corners {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.ListItemMenu .hot-corners::before,
+.ListItemMenu .hot-corners::after {
+ content: "";
+ animation-name: none;
+ animation-timing-function: linear;
+ animation-fill-mode: forwards;
+ border-style: solid;
+ border-color: #e9e9e9 transparent;
+ position: absolute;
+ bottom: -1px;
+ border-width: 0;
+ border-radius: 0;
+ z-index: 2;
+ box-sizing: border-box;
+}
+
+.ListItemMenu .hot-corners::after {
+ right: -1px;
+}
+
+.ListItemMenu .hot-corners::before {
+ left: -1px;
+}
+
+.ListItemMenu.has-options-left.fold-left .hot-corners::before,
+.ListItemMenu.has-options-right.fold-right .hot-corners::after {
+ box-shadow: -1px -1px 3px #c8c7cc;
+ animation-duration: 0.3s;
+}
+
+.ListItemMenu.has-options-left.fold-left .ListItemMenu-zone.left,
+.ListItemMenu.has-options-right.fold-right .ListItemMenu-zone.right {
+ animation-timing-function: linear;
+ animation-fill-mode: forwards;
+ animation-duration: 0.3s;
+}
+
+.ListItemMenu.has-options-left.fold-left .hot-corners::before {
+ animation-name: fold-item-left;
+}
+
+.ListItemMenu.has-options-left.fold-left .ListItemMenu-zone.left {
+ animation-name: fold-options-left;
+}
+
+.ListItemMenu.has-options-right.fold-right .hot-corners::after {
+ animation-name: fold-item-right;
+}
+
+.ListItemMenu.has-options-right.fold-right .ListItemMenu-zone.right {
+ animation-name: fold-options-right;
+}
+
+.ListItemMenu.has-options-left.unfold-left .hot-corners::before,
+.ListItemMenu.has-options-right.unfold-right .hot-corners::after {
+ animation-duration: 0.15s;
+}
+
+.ListItemMenu.has-options-right.unfold-right .hot-corners::after {
+ animation-name: unfold-item-right;
+}
+
+.ListItemMenu.has-options-left.unfold-left .hot-corners::before {
+ animation-name: unfold-item-left;
+}
+
+@keyframes fold-options-right {
+ 0% {transform: translate3d(0px, 42px, 0);}
+ 100% {transform: translate3d(-14px, 29px, 0);}
+}
+
+@keyframes fold-options-left {
+ 0% {transform: translate3d(0px, 42px, 0);}
+ 100% {transform: translate3d(14px, 29px, 0);}
+}
+
+@keyframes fold-item-right {
+ 0% {border-width: 0px}
+ 100% {border-width: 15px 15px 0 0;}
+}
+
+@keyframes unfold-item-right {
+ 0% {border-width: 15px 15px 0 0;}
+ 100% {border-width: 0px}
+}
+
+@keyframes fold-item-left {
+ 0% {border-width: 0px}
+ 100% {border-width: 15px 0 0 15px;}
+}
+
+@keyframes unfold-item-left {
+ 0% {border-width: 15px 0 0 15px;}
+ 100% {border-width: 0px}
+}
+
+.ListItemMenu + .ListItemMenu {
+ border-top: none;
+}
+
+.ListItemMenu.selected .ListItem {
+ background-color: #d9d9d9;
+}
+
+.ListItemMenu.active .ListItem {
+ background-color: #e9e9e9;
+}
+
+.ListItemMenu .ListItemMenu-wrapper {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+}
+
+.ListItemMenu .ListItemMenu-zone {
+ -webkit-box-flex: 0;
+ -ms-flex: 0 0 auto;
+ flex: 0 0 auto;
+ width: 100%;
+ height: 100%;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ visibility: visible;
+ position: relative;
+ z-index: 1;
+}
+
+.ListItemMenu .ListItemMenu-zone.hide {
+ visibility: hidden;
+}
+
+.ListItemMenu .ListItemMenu-options,
+.ListItemMenu .ListItemMenu-content {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+.ListItemMenu .ListItemMenu-content .ListItem {
+ border: none;
+}
+
+.ListItemMenu .ListItemMenu-zone.left .ListItemMenu-options {
+ -webkit-box-pack: end;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+}
+
+.ListItemMenu .ListItemMenu-zone.right .ListItemMenu-options {
+ position: relative;
+ -webkit-box-pack: start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+}
+
+.ListItemMenu .ListItemMenu-options button {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ border: none;
+ color: white;
+ outline: none;
+ text-decoration: none;
+ font-weight: bold;
+ white-space: nowrap;
+}
+
+.ListItemMenu .ListItemMenu-zone.right .ListItemMenu-options button {
+ text-align: left;
+}
+
+.ListItemMenu .ListItemMenu-zone.left .ListItemMenu-options button {
+ text-align: right;
+}
+
+.ListItemMenu .ListItemMenu-options button > span {
+ transform: translate3d(0, 0, 0);
+ position: relative;
+ display: inline-block;
+}
+
+.ListItemMenu button.delete {
+ background-color: #e74c3c;
+}
diff --git a/ui/list-item-menu.reel/list-item-menu.html b/ui/list-item-menu.reel/list-item-menu.html
new file mode 100644
index 0000000000..345d4b6a42
--- /dev/null
+++ b/ui/list-item-menu.reel/list-item-menu.html
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/list-item-menu.reel/list-item-menu.js b/ui/list-item-menu.reel/list-item-menu.js
new file mode 100644
index 0000000000..5d20da6f21
--- /dev/null
+++ b/ui/list-item-menu.reel/list-item-menu.js
@@ -0,0 +1,1171 @@
+/**
+ * @module "ui/list-item-menu.reel"
+ */
+var Component = require("../component").Component,
+ TranslateComposer = require("../../composer/translate-composer").TranslateComposer,
+ PressComposer = require("../../composer/press-composer").PressComposer;
+
+/**
+ * @class ListItemMenu
+ * @extends Component
+ */
+var ListItemMenu = exports.ListItemMenu = Component.specialize(/** @lends ListItemMenu.prototype */{
+
+ constructor: {
+ value: function () {
+ this.defineBindings({
+ "classList.has('montage--disabled')": {
+ "<-": "disabled"
+ },
+ "classList.has('is-opened')": {
+ "<-": "__isOpened"
+ },
+ "classList.has('is-translating')": {
+ "<-": "_isTranslating"
+ },
+ "classList.has('has-options-left')": {
+ "<-": "_leftButtons.defined() && _leftButtons.length > 0"
+ },
+ "classList.has('has-options-right')": {
+ "<-": "_rightButtons.defined() && _rightButtons.length > 0"
+ },
+ "_deleteLabel": {
+ "<-": "data.defined() && userInterfaceDescriptor.defined() ? " +
+ "(data.path(userInterfaceDescriptor.listItemMenuDeleteNameExpression || \"''\") || " +
+ "path(userInterfaceDescriptor.listItemMenuDeleteNameExpression || \"''\") || deleteLabel)" +
+ " : deleteLabel"
+ }
+ });
+ }
+ },
+
+ /**
+ * @private
+ * @type {Number}
+ * @default 0
+ * @description Represents the distance traveled by the list item
+ * from the start position.
+ */
+ _distance: {
+ value: null
+ },
+
+ __shouldOpen: {
+ value: false
+ },
+
+ __shouldClose: {
+ value: false
+ },
+
+ /**
+ * @private
+ * @type {boolean}
+ * @default false
+ * @description Indicates if the list item menu should open itself
+ */
+ _shouldOpen: {
+ set: function (should) {
+ should = !!should;
+ this.__shouldOpen = should;
+ this.__shouldClose = !should;
+ },
+ get: function () {
+ return this.__shouldOpen;
+ }
+ },
+
+ /**
+ * @private
+ * @type {boolean}
+ * @default false
+ * @description Indicates if the list item menu should close itself
+ */
+ _shouldClose: {
+ set: function (should) {
+ should = !!should;
+ this.__shouldClose = should;
+ this.__shouldOpen = !should;
+ },
+ get: function () {
+ return this.__shouldClose;
+ }
+ },
+
+ /**
+ * @private
+ * @typedef {string} ListItemMenu.DIRECTION
+ * @default null
+ * @description Represents the current translating direction
+ */
+ _direction: {
+ value: null
+ },
+
+ __translateComposer: {
+ value: null
+ },
+
+ /**
+ * @private
+ * @typedef {Object} TranslateComposer
+ * @readOnly
+ * @default null
+ * @description List item menu's translate composer
+ */
+ _translateComposer: {
+ get: function () {
+ if (!this.__translateComposer) {
+ this.__translateComposer = new TranslateComposer();
+ this.__translateComposer.hasMomentum = false;
+ this.__translateComposer.allowFloats = false;
+ this.__translateComposer.axis = "horizontal";
+ this.__translateComposer.translateX = - this._dragElementRect.width;
+ this.addComposer(this.__translateComposer);
+ }
+
+ return this.__translateComposer;
+ }
+ },
+
+ __pressComposer: {
+ value: null
+ },
+
+ /**
+ * @private
+ * @typedef {Object} PressComposer
+ * @readOnly
+ * @default null
+ * @description List item menu's press composer
+ */
+ _pressComposer: {
+ get: function () {
+ if (!this.__pressComposer) {
+ this.__pressComposer = new PressComposer();
+ this.addComposerForElement(this.__pressComposer, document);
+ }
+
+ return this.__pressComposer;
+ }
+ },
+
+ _isTranslating: {
+ value: false
+ },
+
+ /**
+ * @public
+ * @type {boolean}
+ * @readOnly
+ * @default false
+ * @description Indicates if the list item is currently slidding
+ */
+ isTranslating: {
+ get: function () {
+ return this._isTranslating;
+ }
+ },
+
+ _openedSide: {
+ value: null
+ },
+
+ /**
+ * @public
+ * @typedef {string} ListItemMenu.DIRECTION
+ * @readOnly
+ * @default null
+ * @description Represents the current opened side.
+ */
+ openedSide: {
+ get: function () {
+ return this._openedSide;
+ }
+ },
+
+ __isOpened: {
+ value: false
+ },
+
+ _isOpened: {
+ set: function (opened) {
+ if (opened !== this._opened) {
+ this.__isOpened = opened;
+
+ if (opened) {
+ this.application.addEventListener('press', this);
+ this._pressComposer.addEventListener('pressStart', this);
+ this._pressComposer.load();
+ } else {
+ this.application.removeEventListener('press', this);
+ this.application.removeEventListener('translateEnd', this);
+ this._pressComposer.removeEventListener('pressStart', this);
+ this._pressComposer.unload();
+ }
+ }
+ },
+ get: function () {
+ return this.__isOpened;
+ }
+ },
+
+ /**
+ * @public
+ * @type {boolean}
+ * @default false
+ * @readonly
+ * @description Indicates if the list item menu is opened
+ */
+ isOpened: {
+ get: function () {
+ return this.__isOpened;
+ }
+ },
+
+ _minDistanceBeforeOpen: {
+ value: null
+ },
+
+ /**
+ * @public
+ * @type {Number}
+ * @default 15% of the list item menu width.
+ * @description Represents the minimum distance before
+ * automatically open a list item once a user end
+ * to translate the list item menu.
+ */
+ minDistanceBeforeOpen: {
+ set: function (minDistanceBeforeOpen) {
+ this._minDistanceBeforeOpen = +minDistanceBeforeOpen;
+ },
+ get: function () {
+ if (this._minDistanceBeforeOpen === null && this._dragElementRect) {
+ this._minDistanceBeforeOpen = this._dragElementRect.width * 0.15;
+ }
+
+ return this._minDistanceBeforeOpen;
+ }
+ },
+
+ _minDistanceBeforeClose: {
+ value: null
+ },
+
+ /**
+ * @public
+ * @type {Number}
+ * @default 85
+ * @default 85% of the list item menu width.
+ * @description Represents the minimum distance before
+ * automatically open a list item once a user end
+ * to translate the list item menu.
+ */
+ minDistanceBeforeClose: {
+ set: function (minDistanceBeforeClose) {
+ this._minDistanceBeforeClose = +minDistanceBeforeClose;
+ },
+ get: function () {
+ if (this._minDistanceBeforeClose === null && this._dragElementRect) {
+ this._minDistanceBeforeClose = this._dragElementRect.width * 0.85;
+ }
+
+ return this._minDistanceBeforeClose;
+ }
+ },
+
+ _data: {
+ value: null
+ },
+
+ /**
+ * @public
+ * @type {Object}
+ * @default null
+ * @description Represents the list item menu data
+ */
+ data: {
+ get: function () {
+ return this._data;
+ },
+ set: function (data) {
+ if (this._data !== data) {
+ this._data = data;
+ this._loadDataUserInterfaceDescriptorIfNeeded();
+ }
+ }
+ },
+
+ /**
+ * @public
+ * @typedef {Object} List
+ * @default null
+ * @description Represents the list item menu
+ * parent's list component
+ */
+ list: {
+ value: null
+ },
+
+ /**
+ * @public
+ * @type {boolean}
+ * @default false
+ * @description Indicates if the list item menu is selected
+ */
+ selected: {
+ value: false
+ },
+
+ /**
+ * @public
+ * @type {Number}
+ * @default -1
+ * @description Represents the list item menu position within
+ * its parent's list component
+ */
+ rowIndex: {
+ value: -1
+ },
+
+ /**
+ * @public
+ * @typedef {Object} UserInterfaceDescriptor
+ * @default null
+ * @description Represents the list item menu
+ * user interface descriptor
+ */
+ userInterfaceDescriptor: {
+ value: null
+ },
+
+ /**
+ * @public
+ * @type {string}
+ * @default 'Button'
+ * @description Default value for the label of delete button.
+ */
+ deleteLabel: {
+ value: null
+ },
+
+ /**
+ * @public
+ * @function openLeft
+ * @description Open the left side
+ */
+ openLeft: {
+ value: function () {
+ this._open(ListItemMenu.DIRECTION.LEFT);
+ }
+ },
+
+ /**
+ * @public
+ * @function openRight
+ * @description Open the right side
+ */
+ openRight: {
+ value: function () {
+ this._open(ListItemMenu.DIRECTION.RIGHT);
+ }
+ },
+
+ /**
+ * @public
+ * @function close
+ * @description Close the current opened side
+ */
+ close: {
+ value: function () {
+ if (this.isOpened) {
+ this._shouldClose = true;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ /**
+ * @private
+ * @function _open
+ * @param {string} ListItemMenu.DIRECTION
+ * @description Open the given side
+ */
+ _open: {
+ value: function (side) {
+ if (!this.isOpened) {
+ if (side === ListItemMenu.DIRECTION.RIGHT ||
+ side === ListItemMenu.DIRECTION.LEFT
+ ) {
+ this._openedSide = side;
+ this._shouldOpen = true;
+ this.needsDraw = true;
+ }
+ }
+ }
+ },
+
+ _shouldUpdateButtonPositions: {
+ value: false
+ },
+
+ /**
+ * @private
+ * @function _loadDataUserInterfaceDescriptorIfNeeded
+ * @description Gets the user interface descriptor
+ * related to the `data` property
+ */
+ _loadDataUserInterfaceDescriptorIfNeeded: {
+ value: function () {
+ if (this.data && this._templateDidLoad) {
+ var self = this,
+ infoDelegate;
+
+ this.loadUserInterfaceDescriptor(this.data).then(function (UIDescriptor) {
+ self.userInterfaceDescriptor = UIDescriptor || self.userInterfaceDescriptor; // trigger biddings.
+
+ self._deleteLabel = self.callDelegateMethod(
+ "listItemMenuWillUseDeleteLabelForObjectAtRowIndex",
+ self,
+ self._deleteLabel,
+ self.data,
+ self.rowIndex,
+ self.list
+ ) || self._deleteLabel; // defined by a bidding expression
+ });
+ }
+ }
+ },
+
+ /**
+ * @private
+ * @function _closeIfNeeded
+ * @description Close the current opened side if not translating.
+ */
+ _closeIfNeeded: {
+ value: function () {
+ if (!this._isTranslating) {
+ this.close();
+ }
+ }
+ },
+
+ /**
+ * @private
+ * @function _hasReachMinDistance
+ * @description Cheks if the minimum distance has been reach
+ * in order to automatically open a list item menu
+ * @return boolean
+ */
+ _hasReachMinDistance: {
+ value: function () {
+ return this._distance >= this.minDistanceBeforeOpen;
+ }
+ },
+
+ /**
+ * @private
+ * @function _hasReachMaxDistance
+ * @description Cheks if the minimum distance has been reach
+ * in order to automatically close a list item menu and disptach
+ * an action event.
+ * @return boolean
+ */
+ _hasReachMaxDistance: {
+ value: function () {
+ return this._distance >= this.minDistanceBeforeClose;
+ }
+ },
+
+ /**
+ * @private
+ * @function _findVelocity
+ * @description Find the velocity of a swipe gesture
+ * @returns Number
+ */
+ _findVelocity: {
+ value: function (deltaTime) {
+ if (deltaTime > 300) {
+ return 0;
+ }
+
+ return Math.sqrt(this._deltaX * this._deltaX) / deltaTime;
+ }
+ },
+
+ /**
+ *
+ * Events cycle management
+ *
+ */
+
+ enterDocument: {
+ value: function (firstTime) {
+ if (!ListItemMenu.cssTransform) {
+ if ("webkitTransform" in this._element.style) {
+ ListItemMenu.cssTransform = "webkitTransform";
+ ListItemMenu.cssTransition = "webkitTransition";
+ } else if ("MozTransform" in this._element.style) {
+ ListItemMenu.cssTransform = "MozTransform";
+ ListItemMenu.cssTransition = "MozTransition";
+ } else if ("oTransform" in this._element.style) {
+ ListItemMenu.cssTransform = "oTransform";
+ ListItemMenu.cssTransition = "oTransition";
+ } else {
+ ListItemMenu.cssTransform = "transform";
+ ListItemMenu.cssTransition = "transition";
+ }
+ }
+
+ this._startListeningToInitialInteractionsIfNeeded();
+ }
+ },
+
+ prepareForActivationEvents: {
+ value: function () {
+ this._startListeningToInitialInteractions();
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ this._stopListeningToInitialInteractions();
+ }
+ },
+
+ _startListeningToInitialInteractionsIfNeeded: {
+ value: function () {
+ if (this.preparedForActivationEvents) {
+ this._startListeningToInitialInteractions();
+ }
+ }
+ },
+
+ _startListeningToInitialInteractions: {
+ value: function () {
+ this._translateComposer.addEventListener('translateStart', this);
+ this.element.addEventListener("transitionend", this);
+ window.addEventListener("resize", this);
+
+ if (window.PointerEvent) {
+ this.element.addEventListener('pointerenter', this);
+ } else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ this._element.removeEventListener("MSPointerEnter", this);
+ } else {
+ this.element.addEventListener('mouseenter', this);
+ }
+ }
+ },
+
+ _stopListeningToInitialInteractions: {
+ value: function () {
+ if (this.preparedForActivationEvents) {
+ this._translateComposer.removeEventListener('translateStart', this);
+ this.element.removeEventListener("transitionend", this);
+ window.removeEventListener("resize", this);
+
+ if (window.PointerEvent) {
+ this.element.removeEventListener('pointerenter', this);
+ } else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ this._element.removeEventListener("MSPointerEnter", this);
+ } else {
+ this.element.removeEventListener('mouseenter', this);
+ }
+ }
+ }
+ },
+
+ handleResize: {
+ value: function () {
+ this._forceComputingBoundaries = true;
+ this.needsDraw = true;
+ }
+ },
+
+ handleTransitionend: {
+ value: function (event) {
+ if (event.target === this.dragElement) {
+ if (this._isTranslating) {
+ this._isTranslating = false;
+ }
+
+ if (this._shouldClose) {
+ this.__shouldClose = false;
+ this._isOpened = false;
+ this._openedSide = null;
+
+ } else if (this._shouldOpen) {
+ this.__shouldOpen = false;
+ this._isOpened = true;
+ }
+
+ this._direction = null;
+ }
+ }
+ },
+
+ handlePointerenter: {
+ value: function (event) {
+ if (window.PointerEvent) {
+ if (event.pointerType === "mouse") {
+ this.element.addEventListener('pointermove', this);
+ this.element.addEventListener('pointerleave', this);
+ }
+ } else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ if (event.pointerType === window.MSPointerEvent.MSPOINTER_TYPE_MOUSE) {
+ this.element.addEventListener('MSPointerMove', this);
+ this.element.addEventListener('MSPointerLeave', this);
+ }
+ } else {
+ this.element.addEventListener('mousemove', this);
+ this.element.addEventListener('mouseleave', this);
+ }
+
+ this._handlePointerOver(event);
+ }
+ },
+
+ _handlePointerOver: {
+ value: function (event) {
+ if (!this.isOpened && !this._isTranslating) {
+ this._overPositionX = event.clientX;
+ this.needsDraw = true;
+ } else {
+ this._overPositionX = null;
+ this._shouldFoldItem = false;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ handlePointerleave: {
+ value: function () {
+ if (window.PointerEvent) {
+ this.element.removeEventListener('pointermove', this);
+ this.element.removeEventListener('pointerleave', this);
+ } else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ this.element.removeEventListener('MSPointerMove', this);
+ this.element.removeEventListener('MSPointerLeave', this);
+ } else {
+ this.element.removeEventListener('mousemove', this);
+ this.element.removeEventListener('mouseleave', this);
+ }
+
+ if (!this.isOpened && !this._isTranslating &&
+ this._shouldFoldItem !== false
+ ) {
+ this._shouldFoldItem = false;
+ this._shouldUnfoldItem = true;
+ this.needsDraw = true;
+ }
+ this._overPositionX = null;
+ }
+ },
+
+ handleTranslateStart: {
+ value: function (event) {
+ this._startPositionX = this.__translateComposer.translateX;
+ this._isTranslating = false;
+ this.__shouldClose = false;
+ this.__shouldOpen = false;
+ this._direction = null;
+ this._startTimestamp = event.timeStamp;
+ this.application.addEventListener('translateEnd', this);
+ this._addDragEventListeners();
+ }
+ },
+
+ handleTranslate: {
+ value: function (event) {
+ var translateX = event.translateX,
+ deltaX = translateX - this._startPositionX;
+
+ if (!this._direction) {
+ this._direction = deltaX > 2 ?
+ ListItemMenu.DIRECTION.RIGHT : deltaX < - 2 ?
+ ListItemMenu.DIRECTION.LEFT : null;
+ }
+
+ var direction = this._direction,
+ distance;
+
+ if (!direction && !this._isTranslating) {
+ // wait for a "real" translate.
+ return void 0;
+ }
+
+ if (!this._openedSide &&
+ ((direction === ListItemMenu.DIRECTION.LEFT &&
+ (!this._rightButtons || !this._rightButtons.length)) ||
+ (direction === ListItemMenu.DIRECTION.RIGHT &&
+ (!this._leftButtons || !this._leftButtons.length)))
+ ) {
+ // Cancel translating if there are no options to show
+ this._translateComposer._cancel();
+ return void 0;
+ }
+
+ // Defines the opened side at the first "real" translate.
+ if (!this._openedSide) {
+ this._openedSide = direction === ListItemMenu.DIRECTION.RIGHT ?
+ ListItemMenu.DIRECTION.LEFT : ListItemMenu.DIRECTION.RIGHT;
+ }
+
+ if (this._distance === null) {
+ // Define initial distance.
+ if (this._openedSide === ListItemMenu.DIRECTION.LEFT) {
+ distance = (
+ this.leftOptionsElement.getBoundingClientRect().right -
+ this._hotCornersElementRect.left
+ );
+ } else {
+ distance = (
+ this._hotCornersElementRect.right -
+ this.rightOptionsElement.getBoundingClientRect().left
+ );
+ }
+ } else {
+ var deltaTranslateX = Math.abs(this._translateX) - Math.abs(translateX);
+ direction = deltaTranslateX > 0 ? ListItemMenu.DIRECTION.RIGHT :
+ deltaTranslateX < 0 ? ListItemMenu.DIRECTION.LEFT : this._direction;
+
+ if (this._openedSide === ListItemMenu.DIRECTION.RIGHT) {
+ distance = this._distance - deltaTranslateX;
+ } else {
+ distance = this._distance + deltaTranslateX;
+ }
+ }
+
+ if (this._openedSide === ListItemMenu.DIRECTION.LEFT) {
+ // block distance if the left options reach the right side
+ if (translateX > 0) {
+ distance = this._hotCornersElementRect.width;
+ } else if (
+ this._hotCornersElementRect.width + translateX <= 0
+ ) {
+ // Reset the distance to 0 when a list item menu
+ // is translating above it's edges.
+ distance = 0;
+ }
+ } else {
+ // block distance if the right options reach the left side
+ if (
+ translateX < - this._hotCornersElementRect.width &&
+ Math.abs(translateX) / 2 > this._hotCornersElementRect.width
+ ) {
+ distance = this._hotCornersElementRect.width;
+ } else if (
+ this._hotCornersElementRect.width + translateX >= 0
+ ) {
+ // Reset the distance to 0 when a list item menu
+ // is translating above it's edges.
+ distance = 0;
+ }
+ }
+
+ if (distance < 0) {
+ distance = 0;
+ }
+
+ var buttonList = this._openedSide === ListItemMenu.DIRECTION.RIGHT ?
+ this._rightButtons : this._leftButtons;
+
+ this._hasReachEnd = !!(
+ buttonList &&
+ buttonList.length === 1 &&
+ this._hasReachMaxDistance()
+ );
+
+ this._direction = direction;
+ this._translateX = translateX;
+ this._deltaX = translateX - this._startPositionX;
+ this._isTranslating = true;
+ this._distance = distance;
+ this.needsDraw = true;
+ }
+ },
+
+ handleTranslateEnd: {
+ value: function (event) {
+ var target = event.targetElement || event.target;
+
+ if (target === this.element || this.element.contains(target)) {
+ var direction = this._direction;
+
+ if (direction) {
+ if (this._hasReachEnd) {
+ // Dispatches an action event and close the list item menu
+ // when a user reached the maximum distance
+ var actionEvent = document.createEvent("CustomEvent");
+
+ actionEvent.initCustomEvent("action", true, true, {
+ side: direction === ListItemMenu.DIRECTION.LEFT ?
+ ListItemMenu.DIRECTION.RIGHT :
+ ListItemMenu.DIRECTION.LEFT
+ });
+
+ this.dispatchEvent(actionEvent);
+ this._shouldClose = true;
+ } else {
+ var velocity = this._findVelocity(
+ event.timeStamp - this._startTimestamp
+ ),
+ hasReachMinDistance = this._hasReachMinDistance();
+
+ if (hasReachMinDistance && velocity > 0.15 &&
+ Math.abs(this._deltaX) > this._dragElementRect.width * 0.05
+ ) { // should open a side if we detect a good swipe
+
+ if (this._deltaX > 0) {
+ // should open right side if not already opened
+ this._shouldOpen = this.isOpened &&
+ this._openedSide === ListItemMenu.DIRECTION.RIGHT ?
+ false : true;
+ } else {
+ // should open left side if not already opened
+ this._shouldOpen = this.isOpened &&
+ this._openedSide === ListItemMenu.DIRECTION.LEFT ?
+ false : true;
+ }
+ } else if (hasReachMinDistance) {
+ // should open a side if the minimum distance has been reached.
+ this._shouldOpen = true;
+ } else {
+ // should close a side if the minimum distance has not been reached.
+ this._shouldClose = true;
+ }
+ }
+ }
+
+ this._resetTranslateContext();
+ } else {
+ this._closeIfNeeded();
+ }
+ }
+ },
+
+ handleTranslateCancel: {
+ value: function () {
+ this._resetTranslateContext();
+ this._isTranslating = false;
+ this._direction = null;
+ }
+ },
+
+ handlePressStart: {
+ value: function (event) {
+ var target = event.targetElement;
+
+ if (this.element !== target && !this.element.contains(target)) {
+ this.close();
+ }
+ }
+ },
+
+ handlePress: {
+ value: function () {
+ this._closeIfNeeded();
+ }
+ },
+
+ _addDragEventListeners: {
+ value: function () {
+ this._translateComposer.addEventListener('translate', this);
+ this._translateComposer.addEventListener('translateCancel', this);
+ }
+ },
+
+ _removeDragEventListeners: {
+ value: function () {
+ this._translateComposer.removeEventListener('translate', this);
+ this._translateComposer.removeEventListener('translateCancel', this);
+ }
+ },
+
+ _resetTranslateContext: {
+ value: function () {
+ this._removeDragEventListeners();
+ this._startTimestamp = 0;
+ this._distance = null;
+ this._hasReachEnd = false;
+ this.needsDraw = true;
+ }
+ },
+
+ /**
+ *
+ * Draw cycle management
+ *
+ */
+
+ willDraw: {
+ value: function () {
+ if (
+ !this._dragElementRect ||
+ this._dragElementRect.width === 0 ||
+ this._forceComputingBoundaries
+ ) {
+ this._dragElementRect = this.dragElement.getBoundingClientRect();
+ this._hotCornersElementRect = this.hotCornersElement.getBoundingClientRect();
+ this._leftButtons = this.leftOptionsElement.querySelectorAll('button');
+ this._rightButtons = this.rightOptionsElement.querySelectorAll('button');
+
+ if ((this._rightButtons && this._rightButtons.length > 3) ||
+ (this._leftButtons && this._leftButtons.length > 3)
+ ) {
+ throw new Error(
+ 'the list item menu component doesn\'t support' +
+ 'more than 3 buttons per slidding side'
+ );
+ }
+
+ var hasLeftButtons = this._leftButtons && this._leftButtons.length > 0,
+ hasRightButtons = this._rightButtons && this._rightButtons.length > 0;
+
+ this._shouldUpdateButtonPositions = true;
+ this.disabled = !hasLeftButtons && !hasRightButtons;
+ }
+ }
+ },
+
+ _setButtonBoundaries: {
+ value: function (buttonList, marginSide) {
+ var i, length, button, label, labelRect, buttonWidth;
+
+ if (buttonList && (length = buttonList.length)) {
+ buttonWidth = this._dragElementRect.width / 2 / length;
+
+ for (i = 0; i < length; i++) {
+ button = buttonList[i];
+
+ if ((label = button.firstElementChild)) {
+ labelRect = label.getBoundingClientRect();
+ label.style[marginSide] =
+ (buttonWidth - labelRect.width) / 2 + 'px';
+ }
+ }
+ }
+ }
+ },
+
+ draw: {
+ value: function () {
+ if (this._shouldUpdateButtonPositions) {
+ this._shouldUpdateButtonPositions = false;
+ this._updateButtonPositions();
+ }
+
+ this._setButtonBoundaries(this._rightButtons, 'marginLeft');
+ this._setButtonBoundaries(this._leftButtons, 'marginRight');
+
+ if (this.__translateComposer && !this.disabled) {
+ var dragElementWidth = this._dragElementRect.width,
+ dragElementStyle = this.dragElement.style,
+ elementClassList = this.element.classList,
+ leftOptionsElementClassList = this.leftOptionsElement.classList,
+ rightOptionsElementClassList = this.rightOptionsElement.classList,
+ direction = this._direction, openedSide = this._openedSide,
+ buttonList = openedSide === ListItemMenu.DIRECTION.RIGHT ?
+ this._rightButtons : this._leftButtons,
+ isLeftSideOpened = this._openedSide === ListItemMenu.DIRECTION.LEFT,
+ length, translateX;
+
+ if (this._isTranslating && !this._shouldOpen && !this._shouldClose) {
+ // logic when a user is translating the list item
+ translateX = this._translateX;
+ dragElementStyle[ListItemMenu.cssTransition] = 'none';
+
+ // Hide not sliding options.
+ if (isLeftSideOpened) {
+ rightOptionsElementClassList.add('hide');
+ leftOptionsElementClassList.remove('hide');
+ } else {
+ rightOptionsElementClassList.remove('hide');
+ leftOptionsElementClassList.add('hide');
+ }
+
+ if (isLeftSideOpened) {
+ // block translate if the left options reach the right side
+ if (translateX > 0) {
+ translateX = 0;
+ }
+ } else {
+ // block translate if the right options reach the left side
+ if (
+ translateX < -dragElementWidth &&
+ Math.abs(translateX) / 2 > dragElementWidth
+ ) {
+ translateX = dragElementWidth * -2;
+ }
+ }
+
+ if (buttonList && (length = buttonList.length)) {
+ this._translateButtons(
+ buttonList,
+ (Math.abs(
+ Math.abs(translateX) - dragElementWidth) / length
+ ),
+ 'none',
+ isLeftSideOpened
+ );
+ }
+ } else if (this._shouldOpen || this._shouldClose) {
+ if (this._shouldOpen) {
+ translateX = this.__translateComposer.translateX = (
+ dragElementWidth * (isLeftSideOpened ? -0.5 : -1.5)
+ );
+ } else if (this._shouldClose) {
+ translateX = this.__translateComposer.translateX = (
+ - dragElementWidth
+ );
+ }
+
+ if (buttonList && (length = buttonList.length)) {
+ this._translateButtons(
+ buttonList,
+ this._shouldClose ? 0 : dragElementWidth / 2 / length,
+ ListItemMenu.DEFAULT_TRANSITION,
+ isLeftSideOpened
+ );
+ }
+
+ dragElementStyle[ListItemMenu.cssTransition] = (
+ ListItemMenu.DEFAULT_TRANSITION
+ );
+ } else {
+ if (!this.isOpened) {
+ rightOptionsElementClassList.remove('hide');
+ leftOptionsElementClassList.remove('hide');
+ }
+ }
+
+ if (translateX !== void 0) {
+ dragElementStyle[ListItemMenu.cssTransform] = (
+ "translate3d(" + translateX + "px,0,0)"
+ );
+ }
+
+ if (this._openedSide) {
+ elementClassList.add(this._openedSide.toLowerCase() + '-side');
+ } else {
+ elementClassList.remove('left-side');
+ elementClassList.remove('right-side');
+ }
+
+ if (this._hasReachEnd) {
+ if (this._openedSide === ListItemMenu.DIRECTION.LEFT) {
+ leftOptionsElementClassList.add('has-reach-end');
+ } else {
+ rightOptionsElementClassList.add('has-reach-end');
+ }
+ } else {
+ leftOptionsElementClassList.remove('has-reach-end');
+ rightOptionsElementClassList.remove('has-reach-end');
+ }
+
+ if (this._overPositionX !== null) {
+ var threshold = dragElementWidth * 0.25;
+
+ if (
+ this._leftButtons.length &&
+ this._overPositionX >= this._hotCornersElementRect.left &&
+ this._overPositionX <= this._hotCornersElementRect.left + threshold
+ ) {
+ this._foldSide = ListItemMenu.DIRECTION.LEFT;
+ this._shouldFoldItem = true;
+ } else if (
+ this._rightButtons.length &&
+ this._overPositionX >= this._hotCornersElementRect.right - threshold &&
+ this._overPositionX <= this._hotCornersElementRect.right
+ ) {
+ this._shouldFoldItem = true;
+ this._foldSide = ListItemMenu.DIRECTION.RIGHT;
+ } else {
+ if (this._shouldFoldItem) {
+ this._shouldUnfoldItem = true;
+ }
+
+ this._shouldFoldItem = false;
+ }
+ }
+
+ if (this._shouldFoldItem) {
+ elementClassList.add('fold-' + this._foldSide.toLowerCase());
+ elementClassList.remove('unfold-right');
+ elementClassList.remove('unfold-left');
+ } else {
+ elementClassList.remove('fold-right');
+ elementClassList.remove('fold-left');
+ }
+
+ if (this._shouldUnfoldItem && this._foldSide) {
+ elementClassList.add('unfold-' + this._foldSide.toLowerCase());
+ this._shouldUnfoldItem = false;
+ this._foldSide = null;
+ }
+
+ if (this._forceComputingBoundaries) {
+ this._updateButtonPositions();
+ this._forceComputingBoundaries = false;
+ }
+ }
+ }
+ },
+
+ _updateButtonPositions: {
+ value: function () {
+ if (this._leftButtons && this._leftButtons.length > 0) {
+ this._translateButtons(this._rightButtons, 0, 'none', false);
+ }
+
+ if (this._rightButtons && this._rightButtons.length > 0) {
+ this._translateButtons(this._leftButtons, 0, 'none', true);
+ }
+ }
+ },
+
+ _translateButtons: {
+ value: function (buttonList, position, transition, isLeftSide) {
+ var button, buttonStyle, translate;
+
+ for (var i = 0, length = buttonList.length; i < length; i++) {
+ button = buttonList[i];
+ buttonStyle = button.style;
+
+ if (isLeftSide) {
+ buttonStyle.zIndex = length - i;
+ translate = -((length - i - 1) * position);
+ } else {
+ buttonStyle.zIndex = i;
+ translate = i * position;
+ }
+
+ buttonStyle[ListItemMenu.cssTransition] = transition;
+ buttonStyle[ListItemMenu.cssTransform] = (
+ "translate3d(" + translate + "px,0,0)"
+ );
+ }
+ }
+ }
+
+}, {
+ DIRECTION: {
+ value: {
+ LEFT: 'LEFT',
+ RIGHT: 'RIGHT'
+ }
+ },
+
+ DEFAULT_TRANSITION: {
+ value: 'transform .3s cubic-bezier(0, 0, 0.58, 1)'
+ }
+ }
+);
+
+ListItemMenu.prototype.handlePointermove = ListItemMenu.prototype._handlePointerOver;
+ListItemMenu.prototype.handleMSPointerEnter = ListItemMenu.prototype.handlePointerenter;
+ListItemMenu.prototype.handleMSPointerMove = ListItemMenu.prototype._handlePointerOver;
+ListItemMenu.prototype.handleMSPointerLeave = ListItemMenu.prototype.handlePointerleave;
+ListItemMenu.prototype.handleMouseenter = ListItemMenu.prototype.handlePointerenter;
+ListItemMenu.prototype.handleMousemove = ListItemMenu.prototype._handlePointerOver;
+ListItemMenu.prototype.handleMouseleave = ListItemMenu.prototype.handlePointerleave;
diff --git a/ui/list-item.info/sample/ui/main.reel/main.html b/ui/list-item.info/sample/ui/main.reel/main.html
index a4e745cf30..eea134ce66 100644
--- a/ui/list-item.info/sample/ui/main.reel/main.html
+++ b/ui/list-item.info/sample/ui/main.reel/main.html
@@ -379,10 +379,6 @@ list items
-
-
-
-
diff --git a/ui/list-item.reel/list-item.css b/ui/list-item.reel/list-item.css
index e8d69aea30..1041e2c443 100755
--- a/ui/list-item.reel/list-item.css
+++ b/ui/list-item.reel/list-item.css
@@ -4,7 +4,6 @@
border-radius: 0;
position: relative;
color: #000;
- background-color: #fff;
min-height: 2.75em;
display: -webkit-box;
display: -ms-flexbox;
@@ -12,6 +11,9 @@
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
+ -webkit-box-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
overflow: hidden;
border: 1px solid #c8c7cc;
box-sizing: border-box;
@@ -19,6 +21,10 @@
transition: background-color .2s linear;
}
+.ListItem + .ListItem {
+ border-top: none;
+}
+
/** States **/
.ListItem.selected {
diff --git a/ui/list.info/sample/index.html b/ui/list.info/sample/index.html
index 21ecb1899f..33350713cb 100644
--- a/ui/list.info/sample/index.html
+++ b/ui/list.info/sample/index.html
@@ -4,9 +4,6 @@
List Samples
-
-