diff --git a/index.html b/index.html
index d8ed569d0d..638b3f2402 100644
--- a/index.html
+++ b/index.html
@@ -30,6 +30,7 @@
-
+
diff --git a/ui/cascading-list.reel/cascading-list-item.reel/cascading-list-item.js b/ui/cascading-list.reel/cascading-list-item.reel/cascading-list-item.js
index 9aa9867eb5..3992d2c6e8 100755
--- a/ui/cascading-list.reel/cascading-list-item.reel/cascading-list-item.js
+++ b/ui/cascading-list.reel/cascading-list-item.reel/cascading-list-item.js
@@ -155,18 +155,72 @@ var CascadingListItem = exports.CascadingListItem = Component.specialize({
value: null
},
- selection: {
+ _selection: {
value: null
},
+ _ignoreSelectionChange: {
+ value: false
+ },
+
+ selection: {
+ get: function () {
+ return this._selection;
+ },
+ set: function (selection) {
+ if (selection !== this._selection) {
+ this._selection = selection;
+
+ if (
+ this.isCollection && selection &&
+ this.context.columnIndex < this.cascadingList.currentColumnIndex &&
+ !selection.length
+ ) {
+ var nextCascadingListItem = this.cascadingList.cascadingListItemAtIndex(this.context.columnIndex + 1);
+ this._ignoreSelectionChange = true;
+ this.selection.push(nextCascadingListItem.context.object);
+ }
+ }
+ }
+ },
+
+ enterDocument: {
+ value: function () {
+ this.context.cascadingList.registerComponentForBackRoute(this.backButton);
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ if (this.context) {
+ this.context.cascadingList.unregisterComponentForBackRoute(this.backButton);
+ }
+ }
+ },
+
_handleSelectionChange: {
value: function (plus, minus, index) {
- if (plus && plus.length === 1) {
+ if (
+ plus && plus.length === 1 &&
+ !this._ignoreSelectionChange
+ ) {
this.cascadingList.expand(
plus[0],
this.context.columnIndex + 1
);
}
+
+ this._ignoreSelectionChange = false;
+ }
+ },
+
+ didDraw: {
+ value: function () {
+ if (this.context && this.content.component) {
+ // FIXME: Should be dispatched from the content placeholder.
+ // and then we dispatch a cascadingListItemLoaded event
+ this.dispatchEventNamed('cascadingListItemLoaded', true, true);
+ }
}
}
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.css b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.css
new file mode 100644
index 0000000000..d02e534f89
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.css
@@ -0,0 +1,36 @@
+.CascadingListShelfItem {
+ font-weight: 400;
+ color: #858585;
+ height: 18px;
+ display: flex;
+ align-items: center;
+}
+
+.CascadingListShelfItem-label {
+ font-size: 16px;
+ padding: 0 8px;
+ padding-right: 8px;
+ margin: 0;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ -ms-flex: 1;
+ flex: 1;
+}
+
+.CascadingListShelfItem-delete {
+ padding-left: 8px;
+ width: 14px;
+ height: 14px;
+ background-position: center;
+ background-image: url("trash.svg");
+ background-repeat: no-repeat;
+}
+
+.CascadingListShelfItem-delete:hover {
+ cursor: pointer;
+}
+
+.CascadingListShelfItem.montage-ghostImage .CascadingListShelfItem-delete {
+ visibility: hidden;
+}
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.html b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.html
new file mode 100644
index 0000000000..a584ae1318
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.js b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.js
new file mode 100644
index 0000000000..2c36206485
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/cascading-list-shelf-item.js
@@ -0,0 +1,80 @@
+/**
+ * @module "ui/cascading-list-shelf-item.reel"
+ */
+var Component = require("../../../component").Component;
+
+/**
+ * @class CascadingListShelfItem
+ * @extends Component
+ */
+exports.CascadingListShelfItem = Component.specialize(/** @lends CascadingListShelfItem.prototype */{
+
+ _templateDidLoad: {
+ value: false
+ },
+
+ templateDidLoad: {
+ value: function () {
+ this.defineBindings({
+ "_label": {
+ "<-": "data.defined() && userInterfaceDescriptor.defined() ? " +
+ "(data.path(userInterfaceDescriptor.nameExpression) || " +
+ "data) : null"
+ }
+
+ });
+ // FIXME: not safe!
+ // https://github.com/montagejs/montage/issues/1977
+ this._templateDidLoad = true;
+ this._loadDataUserInterfaceDescriptorIfNeeded();
+ }
+ },
+
+ _label: {
+ value: null
+ },
+
+ enterDocument: {
+ value: function () {
+ this.addEventListener("action", this);
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ this.removeEventListener("action", this);
+ }
+ },
+
+ userInterfaceDescriptor: {
+ value: null
+ },
+
+ handleDeleteAction: {
+ value: function () {
+ this.cascadingList.removeObjectFromShelf(this.data);
+ }
+ },
+
+ _loadDataUserInterfaceDescriptorIfNeeded: {
+ value: function () {
+ if (this.data && this._templateDidLoad) {
+ var self = this;
+
+ return this.loadUserInterfaceDescriptor(this.data).then(function (UIDescriptor) {
+ self.userInterfaceDescriptor = UIDescriptor || self.userInterfaceDescriptor; // trigger biddings.
+
+ self._label = self.callDelegateMethod(
+ "cascadingListShelfItemWillUseLabelForObject",
+ self,
+ self._label,
+ self.data,
+ self.rowIndex,
+ self.list
+ ) || self._label; // defined by a bidding expression
+ });
+ }
+ }
+ }
+
+});
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/trash.svg b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/trash.svg
new file mode 100644
index 0000000000..b01d643cea
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf-item.reel/trash.svg
@@ -0,0 +1 @@
+
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.css b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.css
new file mode 100644
index 0000000000..de54bf5f5d
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.css
@@ -0,0 +1,116 @@
+.CascadingListShelf {
+ position: absolute;
+ left: 0;
+ right: 0;
+ z-index: 10;
+ background-color: #E8E8E8;
+ height: 0px;
+ overflow: hidden;
+ font-family: 'lato';
+ box-sizing: border-box;
+}
+
+.CascadingListShelf.is-open,
+.CascadingListShelf.open-transition {
+ border-bottom: 1px solid #c8c7cc;
+ height: 64px;
+}
+
+.CascadingListShelf.open-transition {
+ transition: .3s height ease-in-out;
+}
+
+.CascadingListShelf.close-transition {
+ height: 0px;
+ transition: .3s height ease-in-out;
+}
+
+.CascadingListShelf .CascadingListShelf-background {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: absolute;
+ z-index: 10;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.CascadingListShelf .CascadingListShelf-background > svg {
+ display: none;
+}
+
+.CascadingListShelf.is-empty .CascadingListShelf-background > svg,
+.CascadingListShelf.accept-drop.will-drop .CascadingListShelf-background > svg {
+ display: block;
+}
+
+.CascadingListShelf .CascadingListShelf-background .drop {
+ stroke: #858585;
+}
+
+.CascadingList.is-dragging-item .CascadingListShelf.accept-drop .CascadingListShelf-background {
+ border: 2px dashed #0076FF;
+}
+
+.CascadingList.is-dragging-item .CascadingListShelf.accept-drop.will-drop .CascadingListShelf-background {
+ display: flex;
+ border: 2px solid #0076FF;
+}
+
+.CascadingListShelf.accept-drop.will-drop .CascadingListShelf-background .drop {
+ stroke: #0076FF;
+}
+
+.CascadingListShelf.accept-drop.will-drop .CascadingListShelf-options,
+.CascadingListShelf.accept-drop.will-drop .CascadingListShelf-items {
+ display: none;
+}
+
+.CascadingListShelf-options {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 16px;
+ padding: 4px;
+ display: flex;
+ z-index: 11;
+}
+
+.CascadingListShelf-title {
+ padding-right: 8px;
+ color: #0076FF;
+ font-weight: 600;
+}
+
+.CascadingListShelf-close {
+ display: inline-block;
+ height: 16px;
+ width: 16px;
+ background-image: url("times.svg");
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: contain;
+ outline: none;
+ margin-left: auto;
+}
+
+.CascadingListShelf-close:hover {
+ cursor: pointer;
+}
+
+.CascadingListShelf-items {
+ position: absolute;
+ top: 24px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 11;
+}
+
+.CascadingListShelf-repetition {
+ max-height: 100%;
+ overflow: auto;
+}
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.html b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.html
new file mode 100644
index 0000000000..be78392a91
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.js b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.js
new file mode 100644
index 0000000000..efc28b2acf
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/cascading-list-shelf.js
@@ -0,0 +1,160 @@
+/**
+ * @module "ui/cascading-list-dropzone.reel"
+ */
+var Component = require("../../component").Component;
+
+/**
+ * @class CascadingListShelf
+ * @extends Component
+ *
+ * TODO:
+ *
+ * - Add a visible drawer or not
+ * - swipe up to close it or down if there is a visible drawer
+ */
+exports.CascadingListShelf = Component.specialize({
+
+ enterDocument: {
+ value: function () {
+ this.element.addEventListener("transitionend", this);
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ this.element.removeEventListener("transitionend", this);
+ }
+ },
+
+ isOpened: {
+ value: false
+ },
+
+ acceptDrop: {
+ value: false
+ },
+
+ willDrop: {
+ value: false
+ },
+
+ open: {
+ value: function (noTransition) {
+ if (!this.isOpened) {
+ this._noTransition = !!noTransition;
+ this._shouldOpen = true;
+ this._shouldClose = false;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ close: {
+ value: function (noTransition) {
+ if (this.isOpened) {
+ this._noTransition = !!noTransition;
+ this._shouldClose = true;
+ this._shouldOpen = false;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ handleCloseAction: {
+ value: function () {
+ this.close();
+ }
+ },
+
+ handleTransitionend: {
+ value: function (event) {
+ if (event.target === this.element) {
+ var currentCascadingListItem ;
+
+ if (this._shouldClose) {
+ this.removeEventListener("action", this);
+ this._noTransition = false;
+ this._shouldClose = false;
+ this.isOpened = false;
+ this.cascadingList.clearShelfContent();
+ this.dispatchEventNamed("cascadingListShelfClose", true, true, this);
+ currentCascadingListItem = this.cascadingList.getCurrentCascadingListItem();
+ currentCascadingListItem.content.classList.remove('close-transition');
+ this.needsDraw = true;
+
+ } else if (this._shouldOpen) {
+ this.addEventListener("action", this);
+ this._noTransition = false;
+ this._shouldOpen = false;
+ this.isOpened = true;
+ this.dispatchEventNamed("cascadingListShelfOpen", true, true, this);
+ currentCascadingListItem = this.cascadingList.getCurrentCascadingListItem();
+ currentCascadingListItem.content.classList.remove('open-transition');
+ this.needsDraw = true;
+ }
+ }
+ }
+ },
+
+ willDraw: {
+ value: function () {
+ if (!this._anchorBoundingRect && this._shouldOpen) {
+ this._cascadingListHeaderElement = this.parentComponent.element.querySelector(
+ '[data-montage-id="cascading-list-header"]'
+ );
+
+ if (this._cascadingListHeaderElement) {
+ this._anchorBoundingRect = this._cascadingListHeaderElement.getBoundingClientRect();
+ this.element.style.top = this._cascadingListHeaderElement.offsetHeight + "px";
+ }
+ }
+ }
+ },
+
+ draw: {
+ value: function () {
+ var currentCascadingListItem;
+
+ if (!this._noTransition) {
+ if (this._shouldOpen) {
+ this.classList.add('open-transition');
+ currentCascadingListItem = this.cascadingList.getCurrentCascadingListItem();
+ currentCascadingListItem.content.classList.add('open-transition');
+
+ } else {
+ this.classList.remove('open-transition');
+ }
+
+ if (this._shouldClose) {
+ this.classList.add('close-transition');
+ currentCascadingListItem = this.cascadingList.getCurrentCascadingListItem();
+ currentCascadingListItem.content.classList.add('close-transition');
+ } else {
+ this.classList.remove('close-transition');
+ }
+ } else {
+ this.classList.remove('open-transition');
+ this.classList.remove('close-transition');
+
+ if (this._shouldOpen) {
+ this._shouldOpen = false;
+ this.isOpened = true;
+ this.addEventListener("action", this);
+ currentCascadingListItem = this.cascadingList.getCurrentCascadingListItem();
+ currentCascadingListItem.content.classList.remove('close-transition');
+ this.dispatchEventNamed("cascadingListShelfOpen", true, true, this);
+
+ } else if (this._shouldClose) {
+ this.isOpened = false;
+ this._shouldClose = false;
+ currentCascadingListItem = this.cascadingList.getCurrentCascadingListItem();
+ currentCascadingListItem.content.classList.remove('open-transition');
+ this.cascadingList.clearShelfContent();
+ this.removeEventListener("action", this);
+ this.dispatchEventNamed("cascadingListShelfClose", true, true, this);
+ }
+ }
+ }
+ }
+
+});
diff --git a/ui/cascading-list.reel/cascading-list-shelf.reel/times.svg b/ui/cascading-list.reel/cascading-list-shelf.reel/times.svg
new file mode 100644
index 0000000000..f5b45d0df9
--- /dev/null
+++ b/ui/cascading-list.reel/cascading-list-shelf.reel/times.svg
@@ -0,0 +1 @@
+
diff --git a/ui/cascading-list.reel/cascading-list.css b/ui/cascading-list.reel/cascading-list.css
index 334739759f..70511d89ea 100644
--- a/ui/cascading-list.reel/cascading-list.css
+++ b/ui/cascading-list.reel/cascading-list.css
@@ -2,19 +2,19 @@
display: -webkit-box;
display: -ms-flexbox;
display: flex;
- -webkit-box-flex: 1;
- -ms-flex: 1;
- flex: 1;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
+ position: relative;
+ overflow: hidden;
+ border: 1px solid #c8c7cc;
+ min-width: 256px;
+ max-width: 256px;
overflow: hidden;
- box-sizing: border-box;
- border-left: 1px solid #c8c7cc;
}
-.CascadingList-repetition {
+.CascadingList-succession {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
@@ -23,4 +23,57 @@
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
+ width: 200%;
+}
+
+.CascadingList.isFlat {
+ overflow: visible;
+ min-width: inherit;
+ max-width: inherit;
+}
+
+.CascadingList.isFlat .CascadingListItem {
+ border-left: 1px solid #c8c7cc;
+}
+
+.CascadingList.isFlat .CascadingListItem:first-of-type {
+ border-left: none;
+}
+
+.CascadingList.isFlat .CascadingList-succession {
+ width: 100%;
+}
+
+.CascadingList.animated .CascadingList-succession .buildInFrom {
+ transform: translateX(0%);
+}
+
+.CascadingList.animated .CascadingList-succession .buildIn {
+ transition: transform .25s ease-in-out;
+ transform: translateX(-100%);
+}
+
+.CascadingList.animated .CascadingList-succession .buildOut {
+ transition: transform .25s ease-in-out;
+}
+
+.CascadingList.animated .CascadingList-succession .buildOutTo {
+ transform: translateX(-100%);
+}
+
+.CascadingList.animated .CascadingList-succession.back-transition .buildInFrom {
+ transform: translateX(-200%);
+}
+
+.CascadingList.animated .CascadingList-succession.back-transition .buildIn {
+ transition: transform .25s ease-in-out;
+ transform: translateX(-100%);
+}
+
+.CascadingList.animated .CascadingList-succession.back-transition .buildOut {
+ transition: transform .25s ease-in-out;
+}
+
+.CascadingList.animated .CascadingList-succession.back-transition .buildOutTo {
+ transform: translateX(100%);
}
diff --git a/ui/cascading-list.reel/cascading-list.html b/ui/cascading-list.reel/cascading-list.html
index 88b85be9c1..9641d9f4cf 100644
--- a/ui/cascading-list.reel/cascading-list.html
+++ b/ui/cascading-list.reel/cascading-list.html
@@ -1,5 +1,6 @@
+
+
+
diff --git a/ui/cascading-list.reel/cascading-list.js b/ui/cascading-list.reel/cascading-list.js
index c1d06d280b..a2468d2b9e 100644
--- a/ui/cascading-list.reel/cascading-list.js
+++ b/ui/cascading-list.reel/cascading-list.js
@@ -1,6 +1,12 @@
-var Component = require("../component").Component,
- Montage = require("../../core/core").Montage,
- Promise = require('../../core/promise').Promise;
+var CascadingListShelfItem = require("./cascading-list-shelf.reel/cascading-list-shelf-item.reel").CascadingListShelfItem,
+ TranslateComposer = require("../../composer/translate-composer").TranslateComposer,
+ CascadingListItem = require("./cascading-list-item.reel").CascadingListItem,
+ PressComposer = require("../../composer/press-composer").PressComposer,
+ ListItem = require("../list-item.reel").ListItem,
+ Promise = require('../../core/promise').Promise,
+ Component = require("../component").Component,
+ Montage = require("../../core/core").Montage;
+
var CascadingListContext = exports.CascadingListContext = Montage.specialize({
@@ -30,11 +36,60 @@ var CascadingListContext = exports.CascadingListContext = Montage.specialize({
});
-exports.CascadingList = Component.specialize({
+var CascadingList = exports.CascadingList = Component.specialize({
- constructor: {
- value: function () {
- this.history = [];
+ __pressComposer: {
+ value: null
+ },
+
+ _pressComposer: {
+ get: function () {
+ if (!this.__pressComposer) {
+ this.__pressComposer = new PressComposer();
+ this.__pressComposer.delegate = this;
+
+ this.addComposerForElement(
+ this.__pressComposer,
+ this.element.ownerDocument
+ );
+ }
+
+ return this.__pressComposer;
+ }
+ },
+
+ __translateComposer: {
+ value: null
+ },
+
+ _translateComposer: {
+ get: function () {
+ if (!this.__translateComposer) {
+ this.__translateComposer = new TranslateComposer();
+ this.__translateComposer.hasMomentum = false;
+ this.__translateComposer.shouldCancelOnSroll = false;
+ this.__translateComposer.translateX = 0;
+ this.__translateComposer.translateY = 0;
+ this.addComposer(this.__translateComposer);
+ }
+
+ return this.__translateComposer;
+ }
+ },
+
+ __registeredRoutesComponents: {
+ value: null
+ },
+
+ _registeredRoutesComponents: {
+ get: function () {
+ if (!this.__registeredRoutesComponents) {
+ this.__registeredRoutesComponents = new Map();
+ this._registeredRoutesComponents.set("back", []);
+ this._registeredRoutesComponents.set("next", []);
+ }
+
+ return this.__registeredRoutesComponents;
}
},
@@ -42,8 +97,43 @@ exports.CascadingList = Component.specialize({
value: 0
},
+ currentColumnIndex: {
+ get: function () {
+ return this._currentColumnIndex;
+ }
+ },
+
history: {
- value: null
+ get: function () {
+ return this.succession ?
+ this.succession.history : [];
+ }
+ },
+
+ isFlat: {
+ value: false
+ },
+
+ isResponsive: {
+ value: true
+ },
+
+ shrinkForWidth: {
+ value: 768 // px
+ },
+
+ _contentBuildOutAnimation: {
+ value: {
+ cssClass: "buildOut",
+ toCssClass: "buildOutTo"
+ }
+ },
+
+ _contentBuildInAnimation: {
+ value: {
+ fromCssClass: "buildInFrom",
+ cssClass: "buildIn"
+ }
},
_root: {
@@ -58,7 +148,7 @@ exports.CascadingList = Component.specialize({
if (this._root !== root) {
this._root = root;
- if (root) {
+ if (root && !this.isDeserializing) {
this.expand(root);
}
}
@@ -69,12 +159,60 @@ exports.CascadingList = Component.specialize({
value: false
},
+ isShelfOpened: {
+ value: false
+ },
+
+ _shelfContent: {
+ value: null
+ },
+
+ shelfContent: {
+ get: function () {
+ return this._shelfContent || (this._shelfContent = []);
+ }
+ },
+
+ enterDocument: {
+ value: function () {
+ if (!CascadingList.cssTransform) {
+ if ("webkitTransform" in this._element.style) {
+ CascadingList.cssTransform = "webkitTransform";
+ } else if ("MozTransform" in this._element.style) {
+ CascadingList.cssTransform = "MozTransform";
+ } else if ("oTransform" in this._element.style) {
+ CascadingList.cssTransform = "oTransform";
+ } else {
+ CascadingList.cssTransform = "transform";
+ }
+ }
+
+ window.addEventListener("resize", this);
+ this.addEventListener("cascadingListItemLoaded", this);
+ this.addEventListener("cascadingListShelfOpen", this);
+ this.addEventListener("cascadingListShelfClose", this);
+ this.addEventListener("listIterationLongPress", this);
+
+ if (this._root) {
+ this.expand(this._root);
+ }
+ }
+ },
+
exitDocument: {
value: function () {
+ window.removeEventListener("resize", this);
+ this.removeEventListener("cascadingListItemLoaded", this);
+ this.removeEventListener("cascadingListShelfOpen", this);
+ this.removeEventListener("cascadingListShelfClose", this);
+ this.removeEventListener("listIterationLongPress", this);
+
+ this.classList.remove('animated');
+
this.popAll();
}
},
-
+
_delegate: {
value: null
},
@@ -179,6 +317,8 @@ exports.CascadingList = Component.specialize({
this._currentColumnIndex = columnIndex;
+ this._closeShelfIfNeeded();
+
return this._populateColumnWithObjectAndIndex(
object, columnIndex, isEditing
);
@@ -188,15 +328,21 @@ exports.CascadingList = Component.specialize({
cascadingListItemAtIndex: {
value: function (index) {
if (this.history[index]) {
- return this.history[index].cascadingListItem;
+ return this.history[index];
}
}
},
+ getCurrentCascadingListItem: {
+ value: function () {
+ return this.cascadingListItemAtIndex(this._currentColumnIndex);
+ }
+ },
+
findIndexForObject: {
value: function (object) {
for (var i = this.history.length - 1; i > -1; i--) {
- if (this.history[i] === object) {
+ if (this.history[i].context === object) {
return i;
}
}
@@ -205,31 +351,284 @@ exports.CascadingList = Component.specialize({
}
},
+ openShelf: {
+ value: function (noTransition) {
+ if (!this.shelf.isOpened && !this.isFlat) {
+ this.shelf.open(noTransition);
+ }
+ }
+ },
+
+ closeShelf: {
+ value: function (noTransition) {
+ if (this.shelf.isOpened && !this.isFlat) {
+ this.shelf.close(noTransition);
+ }
+ }
+ },
+
+ removeObjectFromShelf: {
+ value: function (object) {
+ var index;
+
+ if ((index = this.shelfContent.indexOf(object)) !== -1) {
+ this.shelfContent.splice(index, 1);
+ }
+ }
+ },
+
+ addObjectToShelf: {
+ value: function (object) {
+ if (!this.shelfHasDataObject(object)) {
+ this.shelfContent.push(object);
+ }
+ }
+ },
+
+ clearShelfContent: {
+ value: function () {
+ this.shelfContent.clear();
+ }
+ },
+
+ shelfHasDataObject: {
+ value: function (object) {
+ return this.shelfContent.indexOf(object) > -1;
+ }
+ },
+
+ registerComponentForBackRoute: {
+ value: function (component) {
+ if (component) {
+ var backRoutes = this._registeredRoutesComponents.get("back");
+
+ if (backRoutes.indexOf(component) === -1) {
+ backRoutes.push(component);
+ }
+ }
+ }
+ },
+
+ unregisterComponentForBackRoute: {
+ value: function (component) {
+ if (component) {
+ var backRoutes = this._registeredRoutesComponents.get("back"),
+ index;
+
+ if ((index = backRoutes.indexOf(component)) > -1) {
+ backRoutes.splice(index, 1);
+ }
+ }
+ }
+ },
+
+ /**
+ * Event Handlers
+ */
+
+ handlePress: {
+ value: function (event) {
+ if (!this.element.contains(event.targetElement)) {
+ this.closeShelf();
+ }
+ }
+ },
+
+ handleListIterationLongPress: {
+ value: function (event) {
+ if (!this.isFlat) {
+ this.openShelf();
+ }
+ }
+ },
+
+ handleTranslateStart: {
+ value: function (event) {
+ var startPosition = this._translateComposer.pointerStartEventPosition,
+ dataObject = this._findDataObjectFromElement(startPosition.target);
+
+ this._resetTranslateContext();
+
+ if (dataObject) {
+ var delegateResponse = this.callDelegateMethod(
+ 'cascadingListCanDragObject', this, dataObject, true
+ ),
+ canDrag = delegateResponse === void 0 ?
+ true : delegateResponse;
+
+ if (canDrag) {
+ var shouldCascadingListShelfAcceptDrop = !this.shelfHasDataObject(dataObject);
+ delegateResponse = this.callDelegateMethod(
+ 'cascadingListShelfShouldAcceptDataObject',
+ this,
+ dataObject,
+ shouldCascadingListShelfAcceptDrop
+ );
+
+ this._startPositionX = startPosition.pageX;
+ this._startPositionY = startPosition.pageY;
+
+ // Add delegate method
+ this._draggingComponent = this._findDraggingComponentFromElement(startPosition.target);
+ this._draggingDataObject = dataObject;
+ this._isDragging = true;
+ this._shouldShelfAcceptDrop = delegateResponse === void 0 ?
+ shouldCascadingListShelfAcceptDrop : delegateResponse;
+
+ this._addDragEventListeners();
+ }
+ }
+ }
+ },
+
+ handleTranslate: {
+ value: function (event) {
+ this._translateX = event.translateX;
+ this._translateY = event.translateY;
+
+ var positionX = this._startPositionX + this._translateX,
+ positionY = this._startPositionY + this._translateY;
+
+ this._isShelfWillAcceptDrop = this._isDraggingComponentOverShelf();
+
+ //FIXME: need to used a radius before canceling the back navigation
+ clearTimeout(this._timeout);
+
+ if (!this._isShelfWillAcceptDrop && !this._isBackTransition) {
+ this._shouldNaviguateBack = this._isDraggingComponentOverBackRoute(positionX, positionY);
+
+ if (this._shouldNaviguateBack) {
+ var self = this;
+
+ this._timeout = setTimeout(function () {
+ self._navigateBack();
+ }, 50);
+ }
+ }
+
+
+ this.needsDraw = true;
+ }
+ },
+
+ handleTranslateEnd: {
+ value: function () {
+ if (this._isShelfWillAcceptDrop) {
+ this.addObjectToShelf(this._draggingDataObject);
+ }
+
+ this._resetTranslateContext();
+ }
+ },
+
+
+ handleTranslateCancel: {
+ value: function () {
+ this._resetTranslateContext();
+ }
+ },
+
+ handleCascadingListShelfOpen: {
+ value: function (event) {
+ this.isShelfOpened = true;
+ this._pressComposer.addEventListener("press", this);
+ this._translateComposer.addEventListener("translateStart", this);
+ }
+ },
+
+ handleCascadingListShelfClose: {
+ value: function (event) {
+ this.isShelfOpened = false;
+ this._pressComposer.removeEventListener("press", this);
+ this._translateComposer.removeEventListener("translateStart", this);
+ }
+ },
+
+ handleBackAction: {
+ value: function () {
+ this._navigateBack();
+ }
+ },
+
+ handleBuildOutEnd: {
+ value: function (event) {
+ this._isBackTransition = false;
+ }
+ },
+
+ handleCascadingListItemLoaded: {
+ value: function () {
+ this.classList.add('animated');
+ this.removeEventListener('cascadingListItemLoaded', this);
+ }
+ },
+
+ handleResize: {
+ value: function () {
+ this.needsDraw = true;
+ }
+ },
+
+ /**
+ * Private Method
+ */
+
+ _navigateBack: {
+ value: function () {
+ this._pop();
+ this._closeShelfIfNeeded();
+ this._isBackTransition = true;
+ }
+ },
+
+ _closeShelfIfNeeded: {
+ value: function () {
+ if (this.shelf.isOpened && !this.shelfContent.length) {
+ this.closeShelf(true);
+ }
+ }
+ },
+
_push: {
value: function (context) {
- this.history.splice(context.columnIndex, 1, context);
- this.needsDraw = true;
+ var cascadingListItem = new CascadingListItem();
+ cascadingListItem.element = document.createElement("div");
+ cascadingListItem.cascadingList = this;
+ cascadingListItem.delegate = this.delegate;
+ cascadingListItem.context = context;
+ cascadingListItem.isFlat = this.isFlat;
+ cascadingListItem.needsDraw = true;
+ this.history.splice(context.columnIndex, 1, cascadingListItem);
if (this.shouldDispatchCascadingListEvents) {
- this.dispatchEventNamed('cascadingListPush', true, true, context);
+ this.dispatchEventNamed(
+ 'cascadingListPush',
+ true,
+ true,
+ cascadingListItem
+ );
}
}
},
_pop: {
value: function () {
- var cascadingListItem,
- context = this.history.pop();
-
+ var cascadingListItem = this.history.pop();
+
this._currentColumnIndex--;
- context.isEditing = false;
+ cascadingListItem.context.isEditing = false;
this.needsDraw = true;
if (this.shouldDispatchCascadingListEvents) {
- this.dispatchEventNamed('cascadingListPop', true, true, context);
+ this.dispatchEventNamed(
+ 'cascadingListPop',
+ true,
+ true,
+ cascadingListItem
+ );
}
- return context;
+ return cascadingListItem;
}
},
@@ -237,7 +636,7 @@ exports.CascadingList = Component.specialize({
value: function (object, columnIndex, isEditing) {
if (!this._populatePromise && object) {
var self = this;
-
+
this._populatePromise = this.loadUserInterfaceDescriptor(object).then(function (UIDescriptor) {
var context = self._createCascadingListContextWithObjectAndColumnIndex(
object,
@@ -268,6 +667,180 @@ exports.CascadingList = Component.specialize({
return context;
}
+ },
+
+ _findDraggingComponentFromElement: {
+ value: function (element) {
+ var component;
+
+ while (element && !(component = element.component)) {
+ element = element.parentElement;
+ }
+
+ while (component && !(
+ component instanceof ListItem ||
+ component instanceof CascadingListShelfItem
+ )) {
+ component = component.parentComponent;
+ }
+
+ return component;
+ }
+ },
+
+ _addDragEventListeners: {
+ value: function () {
+ this._translateComposer.addEventListener('translate', this, false);
+ this._translateComposer.addEventListener('translateEnd', this, false);
+ this._translateComposer.addEventListener('translateCancel', this, false);
+ }
+ },
+
+ _removeDragEventListeners: {
+ value: function () {
+ this._translateComposer.removeEventListener('translate', this, false);
+ this._translateComposer.removeEventListener('translateEnd', this, false);
+ this._translateComposer.removeEventListener('translateCancel', this, false);
+ }
+ },
+
+
+ _resetTranslateContext: {
+ value: function () {
+ this._removeDragEventListeners();
+ this._startPositionX = 0;
+ this._startPositionY = 0;
+ this._translateX = 0;
+ this._translateY = 0;
+ this._isDragging = false;
+ this.__translateComposer.translateX = 0;
+ this.__translateComposer.translateY = 0;
+ this._draggingElementBoundingRect = null;
+ this._isShelfWillAcceptDrop = false;
+ this._shouldShelfAcceptDrop = false;
+ this.needsDraw = true;
+ }
+ },
+
+ _findDataObjectFromElement: {
+ value: function (element) {
+ var component, dataObject;
+
+ while (element && !(component = element.component)) {
+ element = element.parentElement;
+ }
+
+ while (component && !(dataObject = component.data)) {
+ component = component.parentComponent;
+ }
+
+ return dataObject;
+ }
+ },
+
+ _isDraggingComponentOverShelf: {
+ value: function () {
+ if (this._shelfBoundingRect && this.shelf.isOpened) {
+ var x = this._startPositionX + this._translateX,
+ y = this._startPositionY + this._translateY;
+
+ if (x >= this._shelfBoundingRect.left && x <= this._shelfBoundingRect.right &&
+ y >= this._shelfBoundingRect.top && y <= this._shelfBoundingRect.bottom
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ },
+
+ _isDraggingComponentOverBackRoute: {
+ value: function (positionX, positionY) {
+ var backRoutes = this._registeredRoutesComponents.get("back"),
+ component,
+ rect;
+
+ for (var i = 0, length = backRoutes.length; i < length; i++) {
+ component = backRoutes[i];
+ //FIXME: need to be optimized
+ rect = component.element.getBoundingClientRect();
+
+ if (positionX > rect.x && positionX < (rect.x + rect.width) &&
+ positionY > rect.y && positionY < (rect.y + rect.height)
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ },
+
+ /**
+ * Draw Methods
+ */
+
+ willDraw: {
+ value: function () {
+ if (this.isResponsive) {
+ this.isFlat = window.innerWidth >= this.shrinkForWidth;
+
+ for (var i = 0; i < this.history.length; i++) {
+ var item = this.history[i];
+ item.isFlat = this.isFlat;
+ }
+ }
+
+ if (this._isDragging) {
+ if (!this._shelfBoundingRect) {
+ this._shelfBoundingRect = this.shelf.element.getBoundingClientRect();
+ }
+
+ if (this._draggingComponent && !this._draggingElementBoundingRect) {
+ this._draggingElementBoundingRect = this._draggingComponent.element.getBoundingClientRect();
+ }
+ }
+ }
+ },
+
+ draw: {
+ value: function () {
+ if (this._isDragging) {
+ this.element.classList.add('is-dragging-item');
+
+ if (!this._ghostElement) {
+ this._ghostElement = this._draggingComponent.element.cloneNode(true);
+ this._ghostElement.classList.add("montage-ghostImage");
+ this._ghostElement.style.visibility = "hidden";
+ this._ghostElement.style.position = "absolute";
+ this._ghostElement.style.zIndex = 999999;
+ this._ghostElement.style.top = this._draggingElementBoundingRect.top + "px";
+ this._ghostElement.style.left = this._draggingElementBoundingRect.left + "px";
+ this._ghostElement.style.width = this._draggingElementBoundingRect.width + "px";
+ document.body.appendChild(this._ghostElement);
+ this._needsToWaitforGhostElementBoundaries = true;
+ this.needsDraw = true;
+ }
+
+ if (!this._needsToWaitforGhostElementBoundaries) {
+ // Delegate Method for ghost element positioning?
+ this._ghostElement.style.visibility = "visible";
+ } else {
+ this._needsToWaitforGhostElementBoundaries = false;
+ }
+
+ this._ghostElement.style[CascadingList.cssTransform] = "translate3d(" +
+ this._translateX + "px," + this._translateY + "px,0)";
+ } else {
+ this.element.classList.remove('is-dragging-item');
+
+ if (this._ghostElement) {
+ document.body.removeChild(this._ghostElement);
+ this._ghostElement = null;
+ }
+ }
+ }
}
});
diff --git a/ui/component.js b/ui/component.js
index 713877f54f..c36c32b614 100644
--- a/ui/component.js
+++ b/ui/component.js
@@ -1368,56 +1368,75 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
}
},
set: function (value) {
- var components,
- componentsToAdd = [],
- i,
- component;
+ var componentsToAdd = [],
+ elementsToAppend =
+ this._elementsToAppend = [],
+ elementsToAppendBefore =
+ this._elementsToAppendBefore = [],
+ componentsPendingBuildOut =
+ this._componentsPendingBuildOut = [],
+ currentDomContent = this.domContent,
+ childComponents = this.childComponents,
+ isArray = false, index = -1,
+ i, length, childComponent,
+ component, element;
- if (!this._elementsToAppend) {
- this._elementsToAppend = [];
- }
- this._newDomContent = value;
- this.needsDraw = true;
+ if (value) {
+ if (value instanceof Element) {
+ if (currentDomContent.length <= 1) {
+ if (currentDomContent.indexOf(value) === -1) {
+ elementsToAppend.push(value);
+ }
+ } else {
+ elementsToAppend.push(value);
+ }
+ } else if ((isArray =
+ (Array.isArray(value) || value instanceof NodeList)
+ )) {
+ if (currentDomContent.length === 1) {
+ index = Array.prototype.indexOf.call(value, currentDomContent[0]);
+ }
- if (this._newDomContent === null) {
- this._shouldClearDomContentOnNextDraw = true;
- }
+ for (i = 0; i < value.length; i++) {
+ element = value[i];
- if (typeof this.contentWillChange === "function") {
- this.contentWillChange(value);
- }
+ if (currentDomContent.indexOf(element) === -1) {
+ if (i > index) {
+ elementsToAppend.push(element);
+ } else {
+ elementsToAppendBefore.push(element);
+ }
- // cleanup current content
- components = this.childComponents;
- if (value) {
- if (!this._componentsPendingBuildOut) {
- this._componentsPendingBuildOut = [];
+ if ( // Clean up possible transplanted components
+ (component = element.component) &&
+ component._addedToDrawList &&
+ component.parentComponent
+ ) {
+ component.parentComponent._removeToDrawList(component);
+ }
+ }
+ }
}
- for (i = components.length - 1; i >= 0; i--) {
- if (this._componentsPendingBuildOut.indexOf(components[i]) === -1) {
- this._componentsPendingBuildOut.push(components[i]);
+
+ for (i = childComponents.length - 1; i >= 0; i--) {
+ childComponent = childComponents[i];
+
+ if (
+ (isArray && Array.prototype.indexOf.call(value, childComponent.element) === -1) ||
+ (!isArray && elementsToAppend.length && elementsToAppend.indexOf(childComponent.element) === -1)
+ ) {
+ componentsPendingBuildOut.push(childComponent);
}
}
} else {
- this._componentsPendingBuildOut = [];
- for (i = components.length - 1; i >= 0; i--) {
- components[i]._shouldBuildOut = true;
- }
- }
- if (value instanceof Element) {
- this._elementsToAppend.push(value);
- this._findAndDetachComponents(value, componentsToAdd);
- } else if (value && value[0]) {
- for (i = 0; i < value.length; i++) {
- this._elementsToAppend.push(value[i]);
- this._findAndDetachComponents(value[i], componentsToAdd);
+ for (i = childComponents.length - 1; i >= 0; i--) {
+ componentsPendingBuildOut.push(childComponents[i]);
}
}
- // not sure if I can rely on _parentComponent to detach the nodes instead of doing one loop for dettach and another to attach...
- for (i = 0; (component = componentsToAdd[i]); i++) {
- this.addChildComponent(component);
- }
+ this._newDomContent = value;
+ this._shouldClearDomContentOnNextDraw = this._newDomContent === null;
+ this.needsDraw = true;
}
},
@@ -1616,6 +1635,7 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
}
self.canDrawGate.setField("componentTreeLoaded", true);
+ return self;
}).catch(function (error) {
console.error(error);
});
@@ -1818,6 +1838,9 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
}
instances.owner = self;
+
+ // FIXME: should be set after the instantiateWithInstances call...
+ // https://github.com/montagejs/montage/issues/1977
self._isTemplateInstantiated = true;
return template.instantiateWithInstances(instances, _document).then(function (documentPart) {
@@ -2098,10 +2121,18 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
childComponent = oldDrawList[i];
childComponent._addedToDrawList = false;
if (childComponent.canDraw()) { // TODO if canDraw is false when does needsDraw get reset?
- childComponent._drawIfNeeded(level+1);
+ childComponent._drawIfNeeded(level + 1);
} else if (drawLogger.isDebug) {
drawLogger.debug(loggerToString(childComponent) + " can't draw.");
}
+
+ var componentsPendingBuildOut = childComponent._componentsPendingBuildOut;
+
+ if (componentsPendingBuildOut) {
+ while (componentsPendingBuildOut.length) {
+ componentsPendingBuildOut.pop()._shouldBuildOut = true;
+ }
+ }
}
this._disposeArray(oldDrawList);
}
@@ -2465,13 +2496,16 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
_performDomContentChanges: {
value: function () {
var contents = this._newDomContent,
- element,
- elementToAppend,
- i;
+ componentsToAdd, component, referenceNode,
+ element, elementToAppend, i;
if (contents || this._shouldClearDomContentOnNextDraw) {
element = this._element;
+ if (typeof this.contentWillChange === "function") {
+ this.contentWillChange(contents);
+ }
+
// Setting the innerHTML to clear the children will not work on
// IE because it modifies the underlying child nodes. Here's the
// test case that shows this issue: http://jsfiddle.net/89X6F/
@@ -2481,19 +2515,52 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
}
}
- if (this._elementsToAppend) {
+ if (this._elementsToAppendBefore && this._elementsToAppendBefore.length) {
+ componentsToAdd = [];
+ referenceNode = element.firstElementChild;
+
+ while (this._elementsToAppendBefore.length) {
+ elementToAppend = this._elementsToAppendBefore.shift();
+
+ if (!element.contains(elementToAppend)) {
+ this._findAndDetachComponents(elementToAppend, componentsToAdd);
+
+ if (referenceNode) {
+ element.insertBefore(elementToAppend, referenceNode);
+ } else {
+ element.appendChild(elementToAppend);
+ }
+ }
+ }
+
+ for (i = 0; (component = componentsToAdd[i]); i++) {
+ this.addChildComponent(component);
+ }
+ }
+
+ if (this._elementsToAppend && this._elementsToAppend.length) {
+ componentsToAdd = [];
+
while (this._elementsToAppend.length) {
elementToAppend = this._elementsToAppend.shift();
+
if (!element.contains(elementToAppend)) {
+ this._findAndDetachComponents(elementToAppend, componentsToAdd);
element.appendChild(elementToAppend);
}
}
+
+ for (i = 0; (component = componentsToAdd[i]); i++) {
+ this.addChildComponent(component);
+ }
}
this._newDomContent = null;
+
if (typeof this.contentDidChange === "function") {
this.contentDidChange();
}
+
this._shouldClearDomContentOnNextDraw = false;
}
}
@@ -2587,6 +2654,50 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
}
},
+ _removeToParentsDrawList: {
+ enumerable: false,
+ value: function () {
+ if (this._addedToDrawList) {
+ var parentComponent = this._parentComponent;
+
+ if (parentComponent) {
+ parentComponent._removeToDrawList(this);
+ }
+ }
+ }
+ },
+
+ __removeToDrawList: {
+ enumerable: false,
+ value: function (childComponent) {
+ var index;
+
+ if (
+ this._drawList &&
+ (index = this._drawList.indexOf(childComponent)) > -1
+ ) {
+ this._drawList.splice(index, 1);
+ childComponent._addedToDrawList = false;
+ }
+ }
+ },
+
+ /**
+ * Adds the passed in child component to the drawList
+ * If the current instance isn't added to the drawList of its parentComponent, then it adds itself.
+ * @private
+ */
+ _removeToDrawList: {
+ enumerable: false,
+ value: function (childComponent) {
+ this.__removeToDrawList(childComponent);
+
+ if (this._drawList && !this._drawList.length) {
+ this._removeToParentsDrawList();
+ }
+ }
+ },
+
_needsDraw: {
value: false
},
@@ -3586,11 +3697,21 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto
false
);
- if (typeof object === "object" &&
- (constructor = object.constructor) &&
- constructor.objectDescriptorModuleId
- ) {
- objectDescriptorModuleId = constructor.objectDescriptorModuleId;
+ if (object && typeof object === "object") {
+ if (
+ (constructor = object.constructor) &&
+ constructor.objectDescriptorModuleId
+ ) {
+ objectDescriptorModuleId = constructor.objectDescriptorModuleId;
+ }
+
+ if (!objectDescriptorModuleId && Array.isArray(object) &&
+ object.length && object[0] && typeof object[0] === "object" &&
+ !Array.isArray(object[0]) && (constructor = object[0].constructor) &&
+ constructor.objectDescriptorModuleId
+ ) { // Try with the first object of the array.
+ objectDescriptorModuleId = constructor.objectDescriptorModuleId;
+ }
}
objectDescriptorModuleIdCandidate = this.callDelegateMethod(
diff --git a/ui/condiction.info/sample/index.html b/ui/condiction.info/sample/index.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/ui/condition.info/index.html b/ui/condition.info/index.html
deleted file mode 100644
index 4a6fa9f7ab..0000000000
--- a/ui/condition.info/index.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
condition.info
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ui/condition.info/package.json b/ui/condition.info/package.json
deleted file mode 100644
index 08a0a62625..0000000000
--- a/ui/condition.info/package.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "condition.info",
- "private": true,
- "dependencies": {
- "montage": "../.."
- }
-}
\ No newline at end of file
diff --git a/ui/condition.info/sample/index.html b/ui/condition.info/sample/index.html
new file mode 100644
index 0000000000..3feec77724
--- /dev/null
+++ b/ui/condition.info/sample/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
Condition Sample
+
+
+
+
+
+
+
diff --git a/ui/condition.info/sample/package.json b/ui/condition.info/sample/package.json
new file mode 100644
index 0000000000..442aef85d7
--- /dev/null
+++ b/ui/condition.info/sample/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "condition-sample",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../"
+ }
+}
diff --git a/ui/condition.info/sample/ui/main.reel/main.css b/ui/condition.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..21372df317
--- /dev/null
+++ b/ui/condition.info/sample/ui/main.reel/main.css
@@ -0,0 +1,62 @@
+html, body, .Main {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ width: 100%;
+ font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.Main {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+header {
+ padding: 60px 0 20px 0;
+ font-size: 2rem;
+ text-align: center;
+ color: #33495d;
+ height: 40px;
+}
+
+.content {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+ -webkit-box-orient: vertical;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ font-size: 0;
+}
+
+h4 {
+ font-size: 1rem;
+ text-align: center;
+ color: #33495d;
+ margin: 40px;
+}
+
+span {
+ display: inline-block;
+ font-size: 1rem;
+ padding: 0 8px;
+}
+
+.montage-invisible {
+ visibility: hidden;
+}
+
+.Condition {
+ text-align: center;
+}
diff --git a/ui/condition.info/sample/ui/main.reel/main.html b/ui/condition.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..d3c4ffb0e5
--- /dev/null
+++ b/ui/condition.info/sample/ui/main.reel/main.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
Condition 2: [removalStrategy:remove] [condition=true]
+
+ Hello Montage
+
+
Condition 2: [removalStrategy:remove] [condition=false]
+
+ Hello Montage
+
+
Condition 3: [removalStrategy:hide] [condition=true]
+
+ Hello Montage
+
+
Condition 4: [removalStrategy:hide] [condition=false]
+
+ Hello Montage
+
+
+
+
+
diff --git a/ui/condition.info/sample/ui/main.reel/main.js b/ui/condition.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..18c7c32c6a
--- /dev/null
+++ b/ui/condition.info/sample/ui/main.reel/main.js
@@ -0,0 +1,16 @@
+var Component = require("montage/ui/component").Component,
+ Promise = require('montage/core/promise').Promise;
+
+exports.Main = Component.specialize(/** @lends Main# */{
+
+ enterDocument: {
+ value: function () {
+ this.content = [];
+
+ for (var i = 0; i < 10; i++) {
+ this.content.push('item ' + (i + 1));
+ }
+ }
+ }
+
+});
diff --git a/ui/condition.reel/condition.js b/ui/condition.reel/condition.js
index b6bf0639d1..3cf53eb56f 100644
--- a/ui/condition.reel/condition.js
+++ b/ui/condition.reel/condition.js
@@ -29,25 +29,17 @@ exports.Condition = Component.specialize( /** @lends Condition.prototype # */ {
value: true
},
- _contents: {
+ __content: {
value: null
},
- _needsClearDomContent: {
- value: false
- },
-
- __contentDocumentFragment: {
- value: null
- },
-
- _contentDocumentFragment: {
+ _content: {
get: function () {
- if (!this.__contentDocumentFragment && this.element) {
- this.__contentDocumentFragment = document.createDocumentFragment();
+ if (!this.__content && this.element) {
+ this.__content = Array.from(this.element.childNodes);
}
- return this.__contentDocumentFragment;
+ return this.__content;
}
},
@@ -61,22 +53,24 @@ exports.Condition = Component.specialize( /** @lends Condition.prototype # */ {
*/
condition: {
set: function (value) {
-
+ value = !!value;
+
if (value === this._condition) {
return;
}
this._condition = value;
- this.needsDraw = true;
+
// If it is being deserialized element might not been set yet
if (!this.isDeserializing && this.removalStrategy === "remove") {
if (value) {
- this.domContent = this._contentDocumentFragment.childNodes;
-
+ this.domContent = this._content;
} else {
- this._needsDraw = this._needsClearDomContent = true;
+ this._clearDomContent();
}
}
+
+ this.needsDraw = true;
},
get: function () {
return this._condition;
@@ -85,19 +79,13 @@ exports.Condition = Component.specialize( /** @lends Condition.prototype # */ {
_clearDomContent: {
value: function () {
- if (this.removalStrategy === "remove" && !this._condition) {
- var childNodes = this.element.childNodes;
-
- while (childNodes.length) {
- this._contentDocumentFragment.appendChild(childNodes[0]);
- }
-
+ if (
+ this.removalStrategy === "remove" &&
+ !this._condition &&
+ this._content
+ ) {
this.domContent = null;
- this._shouldClearDomContentOnNextDraw = false;
- this.needsDraw = false;
}
-
- this._needsClearDomContent = false;
}
},
@@ -161,10 +149,6 @@ exports.Condition = Component.specialize( /** @lends Condition.prototype # */ {
} else {
this.element.classList.add("montage-invisible");
}
-
- if (this._needsClearDomContent) {
- this._clearDomContent();
- }
}
}
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..784e33f0b6 100644
--- a/ui/list-item.info/sample/ui/main.reel/main.html
+++ b/ui/list-item.info/sample/ui/main.reel/main.html
@@ -352,6 +352,15 @@
"data": {"<-": "@owner.check"},
"delegate": {"=": "@owner"}
}
+ },
+
+ "listItem41": {
+ "prototype": "montage/ui/list-item.reel",
+ "values": {
+ "element": {"#": "listItem41"},
+ "label": "Item 28",
+ "showHandle": true
+ }
}
}
@@ -388,6 +397,7 @@
list items
+
list items with object descriptor
diff --git a/ui/list-item.reel/list-item.css b/ui/list-item.reel/list-item.css
index e8d69aea30..ac567c3699 100755
--- a/ui/list-item.reel/list-item.css
+++ b/ui/list-item.reel/list-item.css
@@ -59,6 +59,24 @@
margin-right: 35px;
}
+.ListItem.show-handle .ListItem-handle {
+ padding-top: 5px;
+}
+
+.ListItem.show-handle .ListItem-handle:hover {
+ cursor: crosshair;
+ cursor: -webkit-grab;
+}
+
+.ListItem.show-handle .ListItem-handle span {
+ display: block;
+ width: 18px;
+ height: 1px;
+ margin-bottom: 4px;
+ position: relative;
+ background: #C7C7CC;
+}
+
/** Icon **/
.ListItem .ListItem-icon > * {
diff --git a/ui/list-item.reel/list-item.html b/ui/list-item.reel/list-item.html
index aa40439655..88132daf00 100755
--- a/ui/list-item.reel/list-item.html
+++ b/ui/list-item.reel/list-item.html
@@ -14,6 +14,7 @@
"classList.has('active')": {"<-": "@owner.active"},
"classList.has('selected')": {"<-": "@owner.selected"},
"classList.has('is-expandable')": {"<-": "@owner._isExpandable"},
+ "classList.has('show-handle')": {"<-": "@owner.showHandle"},
"classList.has('description-bottom')": {"<-": "@owner._descriptionPosition == 'bottom'"}
}
},
@@ -57,6 +58,11 @@
+
+
+
+
+
diff --git a/ui/list-item.reel/list-item.js b/ui/list-item.reel/list-item.js
index 24ab2579ad..784f0df346 100755
--- a/ui/list-item.reel/list-item.js
+++ b/ui/list-item.reel/list-item.js
@@ -62,7 +62,8 @@ exports.ListItem = Component.specialize({
"isExpandable) : isExpandable"
}
});
- //FIXME: not safe!
+ // FIXME: not safe!
+ // https://github.com/montagejs/montage/issues/1977
this._templateDidLoad = true;
this._loadDataUserInterfaceDescriptorIfNeeded();
}
@@ -163,6 +164,10 @@ exports.ListItem = Component.specialize({
userInterfaceDescriptor: {
value: null
},
+
+ showHandle: {
+ value: false
+ },
__pressComposer: {
value: null
diff --git a/ui/list.info/sample/ui/main.reel/main.html b/ui/list.info/sample/ui/main.reel/main.html
index fc533daed5..8f516bc48f 100644
--- a/ui/list.info/sample/ui/main.reel/main.html
+++ b/ui/list.info/sample/ui/main.reel/main.html
@@ -31,12 +31,20 @@
}
},
- "list1": {
+ "isReorderable": {
+ "prototype": "montage/ui/checkbox.reel",
+ "values": {
+ "element": {"#": "isReorderable"}
+ }
+ },
+
+ "list1": {
"prototype": "montage/ui/list.reel",
"values": {
"element": {"#": "list1"},
"data": {"<-": "@owner.strings"},
"allowsMultipleSelection": {"<-": "!!@allowMultipeSelection.checked"},
+ "enableReorderModeAfterLongPress": {"<-": "!!@isReorderable.checked"},
"isSelectionEnabled": {"<-": "!!@isSelectionEnabled.checked"},
"isExpandable": {"<-": "!!@isExpandable.checked"}
}
@@ -48,6 +56,7 @@
"element": {"#": "list2"},
"data": {"<-": "@owner.employees"},
"allowsMultipleSelection": {"<-": "!!@allowMultipeSelection.checked"},
+ "enableReorderModeAfterLongPress": {"<-": "!!@isReorderable.checked"},
"isSelectionEnabled": {"<-": "!!@isSelectionEnabled.checked"},
"isExpandable": {"<-": "!!@isExpandable.checked"}
}
@@ -69,6 +78,7 @@
"element": {"#": "list3"},
"data": {"<-": "@owner.employees"},
"allowsMultipleSelection": {"<-": "!!@allowMultipeSelection.checked"},
+ "enableReorderModeAfterLongPress": {"<-": "!!@isReorderable.checked"},
"isSelectionEnabled": {"<-": "!!@isSelectionEnabled.checked"},
"isExpandable": {"<-": "!!@isExpandable.checked"}
}
@@ -106,6 +116,10 @@
Options:
Allow Navigation:
+
+ Reorder after long press:
+
+
List with default list item
diff --git a/ui/list.reel/list.html b/ui/list.reel/list.html
index 10d88621c5..bb7af84cd4 100755
--- a/ui/list.reel/list.html
+++ b/ui/list.reel/list.html
@@ -8,6 +8,7 @@
"owner": {
"values": {
"element": {"#": "list"},
+ "repetition": {"@": "repetition"},
"selection": {"<->": "@repetition.selection"},
"montageListItemModule": { "%": "../list-item.reel"}
}
@@ -17,8 +18,9 @@
"prototype": "../repetition.reel",
"values": {
"element": {"#": "repetition"},
- "isSelectionEnabled": {"<-": "@owner.isSelectionEnabled"},
- "allowsMultipleSelection": {"<-": "@owner.allowsMultipleSelection"},
+ "isSelectionEnabled": {"<-": "@owner._isSelectionEnabled"},
+ "ignoreSelectionAfterLongPress": {"<-": "@owner._ignoreSelectionAfterLongPress"},
+ "allowsMultipleSelection": {"<-": "@owner._allowsMultipleSelection"},
"content": {"<-": "@owner.data"}
}
},
@@ -36,10 +38,11 @@
"component.list": {"<-": "@owner"},
"component.delegate": {"<-": "@owner.delegate"},
"component.rowIndex": {"<-": "@repetition:iteration.index"},
- "component.isExpandable": {"<-": "@owner.isExpandable"},
+ "component.isExpandable": {"<-": "@owner._isExpandable"},
"component.userInterfaceDescriptor": {"<-": "@owner.userInterfaceDescriptor"},
"component.selected": {"<-": "@repetition:iteration.selected"},
"component.active": {"<-": "@repetition:iteration.active"},
+ "component.showHandle": {"<-": "@owner.isReorderModeEnabled"},
"component.classList.has('ListItem')": {"<-": "true"}
}
}
diff --git a/ui/list.reel/list.js b/ui/list.reel/list.js
index 920d6cb166..313f14bdec 100755
--- a/ui/list.reel/list.js
+++ b/ui/list.reel/list.js
@@ -2,53 +2,71 @@ var Component = require("../component").Component;
exports.List = Component.specialize({
+ _templateDidLoad: {
+ value: false
+ },
+
templateDidLoad: {
value: function () {
- this.isExpandable = this.callDelegateMethod(
- "shouldListBeExpandable",
- this,
- this.isExpandable,
- this.data
- ) || this.isExpandable;
-
- this.isSelectionEnabled = this.callDelegateMethod(
- "shouldListEnableSelection",
- this,
- this.isSelectionEnabled,
- this.data
- ) || this.isSelectionEnabled;
-
- this.allowsMultipleSelection = this.callDelegateMethod(
- "shouldListAllowMultipleSelectionn",
- this,
- this.allowsMultipleSelection,
- this.data
- ) || this.allowsMultipleSelection;
+ this._definesBindings();
+
+ // FIXME: not safe!
+ // https://github.com/montagejs/montage/issues/1977
+ this._templateDidLoad = true;
+ this._loadDataUserInterfaceDescriptorIfNeeded();
+ }
+ },
+
+ enterDocument: {
+ value: function () {
+ this.repetition._pressComposer.addEventListener("longPress", this);
}
},
+ exitDocument: {
+ value: function () {
+ this.repetition._pressComposer.removeEventListener("longPress", this);
+ }
+ },
+
+ _data: {
+ value: null
+ },
+
/**
* Description TODO
* @public
*/
- userInterfaceDescriptor: {
- value: null
+ data: {
+ get: function () {
+ return this._data;
+ },
+ set: function (data) {
+ if (this._data !== data) {
+ this._data = data;
+ this._loadDataUserInterfaceDescriptorIfNeeded();
+ }
+ }
+ },
+
+ _isSelectionEnabled: {
+ value: false
},
/**
* Description TODO
* @public
*/
- data: {
- value: null
+ ignoreSelectionAfterLongPress: {
+ value: false
},
/**
* Description TODO
* @public
*/
- isNavigationEnabled: {
- value: false
+ userInterfaceDescriptor: {
+ value: null
},
/**
@@ -73,6 +91,132 @@ exports.List = Component.specialize({
*/
delegate: {
value: null
+ },
+
+ dispatchLongPress: {
+ value: false
+ },
+
+ handleLongPress: {
+ value: function (event) {
+ if (this.enableReorderModeAfterLongPress) {
+ this.isReorderModeEnabled = !this.isReorderModeEnabled;
+ }
+
+ if (this._dispatchLongPress) {
+ var iteration = this.repetition._findIterationContainingElement(event.targetElement);
+
+ if (iteration) {
+ this.dispatchEventNamed(
+ "listIterationLongPress",
+ true,
+ true,
+ iteration
+ );
+ }
+ }
+ }
+ },
+
+ isReorderModeEnabled: {
+ value: false
+ },
+
+ _enableReorderModeAfterLongPress: {
+ value: false
+ },
+
+ enableReorderModeAfterLongPress: {
+ set: function (enableReorderModeAfterLongPress) {
+ enableReorderModeAfterLongPress = !!enableReorderModeAfterLongPress;
+
+ if (this._enableReorderModeAfterLongPress !== enableReorderModeAfterLongPress) {
+ this._enableReorderModeAfterLongPress = enableReorderModeAfterLongPress;
+ this.repetition.ignoreSelectionAfterLongPress = enableReorderModeAfterLongPress;
+ }
+ },
+ get: function () {
+ return this._enableReorderModeAfterLongPress;
+ }
+ },
+
+ _loadDataUserInterfaceDescriptorIfNeeded: {
+ value: function () {
+ if (this.data && this._templateDidLoad) {
+ var self = this;
+
+ return this.loadUserInterfaceDescriptor(this.data).then(function (UIDescriptor) {
+ self.userInterfaceDescriptor = UIDescriptor || self.userInterfaceDescriptor; // trigger biddings.
+
+ self._isExpandable = self.callDelegateMethod(
+ "shouldListBeExpandable",
+ self,
+ self._isExpandable,
+ self.data
+ ) || self._isExpandable;
+
+ self._isSelectionEnabled = self.callDelegateMethod(
+ "shouldListEnableSelection",
+ self,
+ self._isSelectionEnabled,
+ self.data
+ ) || self._isSelectionEnabled;
+
+ self._allowsMultipleSelection = self.callDelegateMethod(
+ "shouldListAllowMultipleSelection",
+ self,
+ self._allowsMultipleSelection,
+ self.data
+ ) || self._allowsMultipleSelection;
+
+ self._ignoreSelectionAfterLongPress = self.callDelegateMethod(
+ "shouldListIgnoreSelectionAfterLongPress",
+ self,
+ self._ignoreSelectionAfterLongPress,
+ self.data
+ ) || self._ignoreSelectionAfterLongPress;
+
+ self._dispatchLongPress = self.callDelegateMethod(
+ "shouldListDispatchLongPress",
+ self,
+ self._dispatchLongPress,
+ self.data
+ ) || self._dispatchLongPress;
+ });
+ }
+ }
+ },
+
+ _definesBindings: {
+ value: function () {
+ this.defineBindings({
+ "_ignoreSelectionAfterLongPress": {
+ "<-": "userInterfaceDescriptor.defined() ? " +
+ "(userInterfaceDescriptor.listIgnoreSelectionAfterLongPress || " +
+ "ignoreSelectionAfterLongPress) : ignoreSelectionAfterLongPress"
+ },
+ "_isExpandable": {
+ "<-": "userInterfaceDescriptor.defined() ? " +
+ "(userInterfaceDescriptor.listIsExpandable || " +
+ "isExpandable) : isExpandable"
+ },
+ "_isSelectionEnabled": {
+ "<-": "userInterfaceDescriptor.defined() ? " +
+ "(userInterfaceDescriptor.listIsSelectionEnabled ?? " +
+ "isSelectionEnabled) : isSelectionEnabled"
+ },
+ "_allowsMultipleSelection": {
+ "<-": "userInterfaceDescriptor.defined() ? " +
+ "(userInterfaceDescriptor.listAllowsMultipleSelection || " +
+ "allowsMultipleSelection) : allowsMultipleSelection"
+ },
+ "_dispatchLongPress": {
+ "<-": "userInterfaceDescriptor.defined() ? " +
+ "(userInterfaceDescriptor.listDispatchLongPress || " +
+ "dispatchLongPress) : dispatchLongPress"
+ }
+ });
+ }
}
});
diff --git a/ui/repetition.reel/repetition.js b/ui/repetition.reel/repetition.js
index debc101b2b..c6104bf87d 100644
--- a/ui/repetition.reel/repetition.js
+++ b/ui/repetition.reel/repetition.js
@@ -1879,6 +1879,10 @@ var Repetition = exports.Repetition = Component.specialize(/** @lends Repetition
this._initialContentDrawn = true;
}
+ if (!this.isSelectionEnabled && this.selection.length) {
+ this.selection.clear();
+ }
+
// Synchronize iterations and _drawnIterations
// Retract iterations that should no longer be visible
@@ -2004,9 +2008,60 @@ var Repetition = exports.Repetition = Component.specialize(/** @lends Repetition
if (selectionTracking) {
this._enableSelectionTracking();
} else {
- this.selection.clear();
this._disableSelectionTracking();
}
+
+ if (!this.isDeserializing) {
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _ignoreSelectionAfterLongPress: {
+ value: false
+ },
+
+ ignoreSelectionAfterLongPress: {
+ set: function (ignoreSelectionAfterLongPress) {
+ ignoreSelectionAfterLongPress = !!ignoreSelectionAfterLongPress;
+
+ if (this._ignoreSelectionAfterLongPress !== ignoreSelectionAfterLongPress) {
+ this._ignoreSelectionAfterLongPress = ignoreSelectionAfterLongPress;
+
+ if (!this.listenToLongPress && ignoreSelectionAfterLongPress) {
+ this.listenToLongPress = true;
+ }
+ }
+ },
+ get: function () {
+ return this._ignoreSelectionAfterLongPress;
+ }
+ },
+
+ _listenToLongPress: {
+ value: false
+ },
+
+ listenToLongPress: {
+ set: function (listenToLongPress) {
+ listenToLongPress = !!listenToLongPress;
+
+ if (this._listenToLongPress !== listenToLongPress) {
+ this._listenToLongPress = listenToLongPress;
+
+ if (listenToLongPress) {
+ this._pressComposer.addEventListener(
+ "longPress", this, false
+ );
+ } else if (!this.ignoreSelectionAfterLongPress) {
+ this._pressComposer.removeEventListener(
+ "longPress", this, false
+ );
+ }
+ }
+ },
+ get: function () {
+ return this._listenToLongPress;
}
},
@@ -2018,6 +2073,10 @@ var Repetition = exports.Repetition = Component.specialize(/** @lends Repetition
_enableSelectionTracking: {
value: function () {
this._pressComposer.addEventListener("pressStart", this, false);
+
+ if (this.listenToLongPress) {
+ this._pressComposer.addEventListener("longPress", this, false);
+ }
}
},
@@ -2029,6 +2088,10 @@ var Repetition = exports.Repetition = Component.specialize(/** @lends Repetition
_disableSelectionTracking: {
value: function () {
this._pressComposer.removeEventListener("pressStart", this, false);
+
+ if (this.listenToLongPress) {
+ this._pressComposer.removeEventListener("longPress", this, false);
+ }
}
},
@@ -2049,6 +2112,14 @@ var Repetition = exports.Repetition = Component.specialize(/** @lends Repetition
}
},
+ handleLongPress: {
+ value: function () {
+ if (this.ignoreSelectionAfterLongPress) {
+ this._ignoreSelection();
+ this.selection.clear();
+ }
+ }
+ },
/**
* @private
diff --git a/ui/substitution.reel/substitution.js b/ui/substitution.reel/substitution.js
index 5b0def25ef..46c1ddd470 100644
--- a/ui/substitution.reel/substitution.js
+++ b/ui/substitution.reel/substitution.js
@@ -137,10 +137,6 @@ exports.Substitution = Slot.specialize( /** @lends Substitution.prototype # */ {
}
},
- _drawnSwitchValue: {
- value: null
- },
-
_switchValue: {
value: null
},
@@ -193,6 +189,7 @@ exports.Substitution = Slot.specialize( /** @lends Substitution.prototype # */ {
// In the future the DrawManager will handle adding and
// removing nodes from the DOM at any time before draw().
this._updateComponentDom();
+ this.addEventListener("firstDraw", this);
}
}
},
@@ -208,19 +205,6 @@ exports.Substitution = Slot.specialize( /** @lends Substitution.prototype # */ {
}
},
- contentDidChange: {
- value: function (newContent, oldContent) {
- Slot.prototype.contentDidChange.call(this, newContent, oldContent);
-
- if (this._drawnSwitchValue) {
- if (this._switchComponents[this._drawnSwitchValue]) {
- this._switchElements[this._drawnSwitchValue] = this._switchComponents[this._drawnSwitchValue].element;
- }
- }
- this._drawnSwitchValue = this._switchValue;
- }
- },
-
_loadSwitchComponentTree: {
value: function (value) {
var self = this,
@@ -258,7 +242,7 @@ exports.Substitution = Slot.specialize( /** @lends Substitution.prototype # */ {
if (promises.length > 0) {
canDrawGate.setField(value + "ComponentTreeLoaded", false);
- Promise.all(promises).then(function () {
+ Promise.all(promises).then(function (components) {
self._switchComponentTreeLoaded[value] = true;
canDrawGate.setField(value + "ComponentTreeLoaded", true);
self._canDraw = true;
@@ -336,5 +320,22 @@ exports.Substitution = Slot.specialize( /** @lends Substitution.prototype # */ {
transition: {
value: null
+ },
+
+ handleFirstDraw: {
+ value: function (event) {
+ if (
+ this._allChildComponents.indexOf(event.target) > -1 &&
+ this._switchValue &&
+ this._switchComponents[this._switchValue]
+ ) {
+ this._switchElements[this._switchValue] =
+ this._switchComponents[this._switchValue].element;
+
+ if (this._content !== this._switchElements[this._switchValue]) {
+ this.content = this._switchElements[this._switchValue];
+ }
+ }
+ }
}
});
diff --git a/ui/succession.info/sample/ui/main.reel/main.js b/ui/succession.info/sample/ui/main.reel/main.js
index 30c38c30a0..948f20704a 100644
--- a/ui/succession.info/sample/ui/main.reel/main.js
+++ b/ui/succession.info/sample/ui/main.reel/main.js
@@ -165,7 +165,7 @@ exports.Main = Component.specialize({
handlePushx5Action: {
value: function () {
- var numberOfPushes = 10,
+ var numberOfPushes = 5,
self = this;
var pushInterval = setInterval(function () {
@@ -176,7 +176,7 @@ exports.Main = Component.specialize({
if (numberOfPushes === 0) {
clearInterval(pushInterval);
}
- }, 50);
+ }, 750);
}
},
diff --git a/ui/succession.reel/succession.js b/ui/succession.reel/succession.js
index 57e28368f7..c3406ecf03 100644
--- a/ui/succession.reel/succession.js
+++ b/ui/succession.reel/succession.js
@@ -1,7 +1,7 @@
/**
* @module "montage/ui/succession.reel"
*/
-var Component = require("ui/component").Component;
+var Component = require("../component").Component;
/**
* Subclasses Component for its `domContent` behavior.
@@ -103,6 +103,30 @@ exports.Succession = Component.specialize(/** @lends Succession.prototype */{
}
},
+ _isFlat: {
+ value: false
+ },
+
+ isFlat: {
+ get: function () {
+ return this._isFlat;
+ },
+ set: function (isFlat) {
+ isFlat = !!isFlat;
+
+ if (this._isFlat !== isFlat) {
+ this._isFlat = isFlat;
+
+ if (!this.isDeserializing) {
+ this._updateDomContentWith(
+ isFlat ?
+ this.history : this.history[this.history.length - 1]
+ );
+ }
+ }
+ }
+ },
+
/**
* Ensure components generated by instantiating in JavaScript instead of
* declaring in template serialization has an element.
@@ -113,19 +137,53 @@ exports.Succession = Component.specialize(/** @lends Succession.prototype */{
*/
_updateDomContentWith: {
value: function (content) {
- if (content) {
- var element;
- if (!content.element) {
- element = document.createElement("div");
- element.id = content.identifier || "appendDiv";
- content.element = element;
+ var element;
+
+ if (!this.isFlat) {
+ if (content) {
+ if (!content.element) {
+ element = document.createElement("div");
+ element.id = content.identifier || "appendDiv";
+ content.element = element;
+ } else {
+ element = content.element;
+ }
+ this.domContent = element;
+ content.needsDraw = true;
} else {
- element = content.element;
+ this.domContent = null;
}
- this.domContent = element;
- content.needsDraw = true;
} else {
- this.domContent = null;
+ if (content) {
+ var isArray = Array.isArray(content),
+ domContent = [], i, index, component;
+
+ if (isArray) {
+ for (i = 0; i < content.length; i++) {
+ component = content[i];
+
+ if (!component.element) {
+ element = document.createElement("div");
+ element.id = content.identifier;
+ content.element = element;
+ }
+ }
+ } else {
+ if (!content.element) {
+ element = document.createElement("div");
+ element.id = content.identifier;
+ content.element = element;
+ }
+ }
+
+ for (i = 0; i < this.history.length; i++) {
+ domContent.push(this.history[i].element);
+ }
+
+ this.domContent = domContent;
+ } else {
+ this.domContent = null;
+ }
}
}
},
@@ -155,20 +213,29 @@ exports.Succession = Component.specialize(/** @lends Succession.prototype */{
var length = this.history ? this.history.length : 0,
isChanged = plus.length || minus.length,
isChangeVisible = isChanged && index + plus.length === length,
- isPush = isChangeVisible && !minus.length && index,
+ isPush = isChangeVisible && !minus.length && index >= 0,
isPop = isChangeVisible && !plus.length && length,
isReplace = isChangeVisible && !isPush && !isPop && length,
isClear = isChangeVisible && !length;
- // Set appropriate classes and update the succession if necessary.
- if (isChangeVisible) {
- this.classList[isPush ? "add" : "remove"]("montage-Succession--push");
- this.classList[isPop ? "add" : "remove"]("montage-Succession--pop");
- this.classList[isReplace ? "add" : "remove"]("montage-Succession--replace");
- this.classList[isClear ? "add" : "remove"]("montage-Succession--clear");
- this._prepareForBuild(this.content);
- this.dispatchBeforeOwnPropertyChange("content", this.content);
- this._updateDomContentWith(this.content);
- this.dispatchOwnPropertyChange("content", this.content);
+
+ if (!this.isFlat) {
+ // Set appropriate classes and update the succession if necessary.
+ if (isChangeVisible) {
+ this.classList[isPush ? "add" : "remove"]("montage-Succession--push");
+ this.classList[isPop ? "add" : "remove"]("montage-Succession--pop");
+ this.classList[isReplace ? "add" : "remove"]("montage-Succession--replace");
+ this.classList[isClear ? "add" : "remove"]("montage-Succession--clear");
+ this._prepareForBuild(this.content);
+ this.dispatchBeforeOwnPropertyChange("content", this.content);
+ this._updateDomContentWith(this.content);
+ this.dispatchOwnPropertyChange("content", this.content);
+ }
+ } else {
+ if (isChangeVisible) {
+ this.dispatchBeforeOwnPropertyChange("content", this.content);
+ this._updateDomContentWith(!!isPush ? plus : minus);
+ this.dispatchOwnPropertyChange("content", this.content);
+ }
}
}
},
diff --git a/ui/virtual-list.reel/virtual-list.html b/ui/virtual-list.reel/virtual-list.html
index 7af8fb38ab..7c6603f505 100755
--- a/ui/virtual-list.reel/virtual-list.html
+++ b/ui/virtual-list.reel/virtual-list.html
@@ -8,6 +8,7 @@
"values": {
"element": {"#": "virtual-list"},
"flow": {"@": "flow"},
+ "repetition": {"<-": "@flow._repetition"},
"selection": {"<->": "@flow.selection"},
"montageListItemModule": { "%": "../list-item.reel"},
"_scrollBars": {"@": "scrollbars"},