on xenial help sign in
Add CardTool to determine category-wide card properties based on the category template.

Clean up test configurations, too.

commitd7e5175d2940a5b0c250f18cebdaf15bcb0bb7a2 authorMichał Sawicz <michal.sawicz@canonical.com> dateTue 4 Feb 2014, 14:08 (13 years ago) parentbeb705a4a28a9e
7 files changed+514−77
qml/Dash/Card.qml+3−12 qml/Dash/CardTool.qml+136 qml/Dash/graphics/checkers.png tests/qmltests/CMakeLists.txt+1 tests/qmltests/Dash/CardHelpers.js+45 tests/qmltests/Dash/tst_Card.qml+29−65 tests/qmltests/Dash/tst_CardTool.qml+300
qml/Dash/Card.qml+3−12
@@ -23,17 +23,8 @@ Item {
2323 property var components
2424 property var cardData
2525
26− width: {
27− if (template !== undefined) {
28− if (template["card-layout"] === "horizontal") return units.gu(38);
29− switch (template['card-size']) {
30− case "small": return units.gu(12);
31− case "large": return units.gu(38);
32− }
33− }
34− return units.gu(18.5);
35− }
36− height: childrenRect.height
26+ implicitWidth: childrenRect.width
27+ implicitHeight: childrenRect.height
3728
3829 UbuntuShape {
3930 id: artShape
@@ -61,7 +52,7 @@ Item {
6152 // FIXME uncomment when having investigated / fixed the crash
6253 //sourceSize.width: width > height ? width : 0
6354 //sourceSize.height: height > width ? height : 0
64− fillMode: components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop
55+ fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop
6556
6657 property real aspect: implicitWidth / implicitHeight
6758 }
qml/Dash/CardTool.qmlnew file+136
@@ -0,0 +1,136 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+
19+/*!
20+ \brief Tool for introspecting Card properties.
21+
22+ Some properties of Cards we need to determine category-wide (like card sizes in grid),
23+ so we should not do them per-Card but in the category renderer.
24+
25+ This component creates an invisible card filled with maximum mapped data and calculates
26+ or measures card properties for this configuration.
27+ */
28+
29+Item {
30+ id: cardTool
31+ /*!
32+ \brief Template supplied for the category.
33+ */
34+ property var template
35+
36+ /*!
37+ \brief Component mapping supplied for the category.
38+ */
39+ property var components
40+
41+ /*!
42+ \brief Width of the view, based on which carousel width is calculated.
43+ */
44+ property var viewWidth
45+
46+ // FIXME: Saviq
47+ // Only way for the card below to actually be laid out completely.
48+ // If invisible or in "data" array, some components are not taken into account.
49+ width: 0
50+ height: 0
51+ clip: true
52+
53+ /*!
54+ type:real \brief Width to be enforced on the card in this configuration.
55+
56+ If undefined, should use implicit width of the actual card.
57+ */
58+ readonly property var cardWidth: {
59+ switch (template !== undefined && template["category-layout"]) {
60+ case "grid":
61+ case "vertical-journal":
62+ if (template["card-layout"] === "horizontal") return units.gu(38);
63+ switch (template["card-size"]) {
64+ case "small": return units.gu(12);
65+ case "large": return units.gu(38);
66+ }
67+ return units.gu(18.5);
68+ case "carousel":
69+ if (viewWidth === undefined) return undefined
70+ if (viewWidth <= units.gu(40)) return units.gu(18)
71+ if (viewWidth >= units.gu(128)) return units.gu(26)
72+ return units.gu(18 + Math.round((viewWidth - units.gu(40))/ units.gu(11)))
73+ case undefined:
74+ case "organic-grid":
75+ case "journal":
76+ default:
77+ return undefined;
78+ }
79+ }
80+
81+ /*!
82+ type:real \brief Height to be enforced on the card in this configuration.
83+
84+ If undefined, should use implicit height of the actual card.
85+ */
86+ readonly property var cardHeight: {
87+ switch (template !== undefined && template["category-layout"]) {
88+ case "journal":
89+ if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
90+ return units.gu(18.5);
91+ case "grid":
92+ return card.implicitHeight
93+ case "carousel":
94+ return cardWidth / (components ? components["art"]["aspect-ratio"] : 1)
95+ case undefined:
96+ case "organic-grid":
97+ case "vertical-journal":
98+ default:
99+ return undefined;
100+ }
101+ }
102+
103+ readonly property QtObject priv: card
104+
105+ Card {
106+ id: card
107+ template: cardTool.template
108+ components: cardTool.components
109+
110+ width: cardTool.cardWidth || implicitWidth
111+ height: cardTool.cardHeight || implicitHeight
112+
113+ property var fields: ["art", "mascot", "title", "subtitle", "summary"]
114+ property var maxData: {
115+ "art": Qt.resolvedUrl("graphics/checkers.png"),
116+ "mascot": Qt.resolvedUrl("graphics/checkers.png"),
117+ "title": "—\n—",
118+ "subtitle": "—",
119+ "summary": "—\n—\n—\n—\n—"
120+ }
121+
122+ onComponentsChanged: {
123+ var data = {};
124+ for (var k in fields) {
125+ var component = components[fields[k]];
126+ var key = fields[k];
127+ if ((typeof component === "string" && component.length > 0) ||
128+ (typeof component === "object" && component !== null
129+ && typeof component["field"] === "string" && component["field"].length > 0)) {
130+ data[key] = maxData[key];
131+ }
132+ }
133+ cardData = data;
134+ }
135+ }
136+}
qml/Dash/graphics/checkers.pngnew file

Binary file not shown.

tests/qmltests/CMakeLists.txt+1
@@ -44,6 +44,7 @@ add_qml_test(Dash DashPreview)
4444add_qml_test(Dash GenericPreview)
4545add_qml_test(Dash Card)
4646add_qml_test(Dash CardHeader)
47+add_qml_test(Dash CardTool)
4748add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4849add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins
4950 ${CMAKE_BINARY_DIR}/tests/mocks)
tests/qmltests/Dash/CardHelpers.js+45
@@ -18,6 +18,51 @@
1818
1919var components = ["title", "art", "subtitle", "mascot", "emblem", "old-price", "price", "alt-price", "rating", "alt-rating", "summary"]
2020
21+var defaultLayout = ' \
22+{ \
23+ "schema-version": 1, \
24+ "template": { \
25+ "category-layout": "grid", \
26+ "card-layout": "vertical", \
27+ "card-size": "medium", \
28+ "overlay-mode": null, \
29+ "collapsed-rows": 2 \
30+ }, \
31+ "components": { \
32+ "title": null, \
33+ "art": { \
34+ "aspect-ratio": 1.0, \
35+ "fill-mode": "crop" \
36+ }, \
37+ "subtitle": null, \
38+ "mascot": null, \
39+ "emblem": null, \
40+ "old-price": null, \
41+ "price": null, \
42+ "alt-price": null, \
43+ "rating": { \
44+ "type": "stars", \
45+ "range": [0, 5], \
46+ "full": "image://theme/rating-star-full", \
47+ "half": "image://theme/rating-star-half", \
48+ "empty": "image://theme/rating-star-empty" \
49+ }, \
50+ "alt-rating": null, \
51+ "summary": null \
52+ }, \
53+ "resources": {} \
54+}'
55+
56+var fullMapping = ' \
57+{ \
58+ "title": "title", \
59+ "art": "art", \
60+ "subtitle": "subtitle", \
61+ "mascot": "mascot", \
62+ "summary": "summary" \
63+}'
64+
65+
2166function tryParse(json, errorLabel) {
2267 var o = undefined;
2368 if (errorLabel !== undefined) {
tests/qmltests/Dash/tst_Card.qml+29−65
@@ -27,41 +27,6 @@ Rectangle {
2727 height: units.gu(72)
2828 color: "#88FFFFFF"
2929
30− property string defaultLayout: '
31− {
32− "schema-version": 1,
33− "template": {
34− "category-layout": "grid",
35− "card-layout": "vertical",
36− "card-size": "medium",
37− "overlay-mode": null,
38− "collapsed-rows": 2
39− },
40− "components": {
41− "title": null,
42− "art": {
43− "aspect-ratio": 1.0,
44− "fill-mode": "crop"
45− },
46− "subtitle": null,
47− "mascot": null,
48− "emblem": null,
49− "old-price": null,
50− "price": null,
51− "alt-price": null,
52− "rating": {
53− "type": "stars",
54− "range": [0, 5],
55− "full": "image://theme/rating-star-full",
56− "half": "image://theme/rating-star-half",
57− "empty": "image://theme/rating-star-empty"
58− },
59− "alt-rating": null,
60− "summary": null
61− },
62− "resources": {}
63− }'
64−
6530 property string cardData: '
6631 {
6732 "art": "../../tests/qmltests/Dash/artwork/music-player-design.png",
@@ -71,62 +36,61 @@ Rectangle {
7136 "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
7237 }'
7338
74− property string fullMapping: '
75− {
76− "title": "title",
77− "art": "art",
78− "subtitle": "subtitle",
79− "mascot": "mascot",
80− "summary": "summary"
81− }'
82−
8339 property var cardsModel: [
8440 {
85− "name": "Art, header, summary - vertical",
86− "layout": { "components": JSON.parse(fullMapping) }
41+ "name": "Art, header, summary",
42+ "layout": { "components": JSON.parse(Helpers.fullMapping) }
8743 },
8844 {
89− "name": "Art, header, summary - vertical, small",
90− "layout": { "template": { "card-size": "small" }, "components": JSON.parse(fullMapping) }
45+ "name": "Art, header, summary - small",
46+ "layout": { "template": { "card-size": "small" }, "components": JSON.parse(Helpers.fullMapping) }
9147 },
9248 {
93− "name": "Art, header, summary - vertical, large",
94− "layout": { "template": { "card-size": "large" }, "components": JSON.parse(fullMapping) }
49+ "name": "Art, header, summary - large",
50+ "layout": { "template": { "card-size": "large" }, "components": JSON.parse(Helpers.fullMapping) }
9551 },
9652 {
97− "name": "Art, header, summary - vertical, wide",
98− "layout": { "components": Helpers.update(JSON.parse(root.fullMapping), { "art": { "aspect-ratio": 2 } }) }
53+ "name": "Art, header, summary - wide",
54+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "aspect-ratio": 2 } }) }
9955 },
10056 {
101− "name": "Art, title - vertical, fitted",
102− "layout": { "components": Helpers.update(JSON.parse(root.fullMapping), { "art": { "fill-mode": "fit" } }) }
57+ "name": "Art, title - fitted",
58+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": { "fill-mode": "fit" } }) }
10359 },
10460 {
10561 "name": "Art, header, summary - horizontal",
10662 "layout": { "template": { "card-layout": "horizontal" },
107− "components": JSON.parse(fullMapping) }
63+ "components": JSON.parse(Helpers.fullMapping) }
10864 },
10965 {
110− "name": "Art, header - vertical",
111− "layout": { "components": Helpers.update(JSON.parse(root.fullMapping), { "summary": undefined }) }
66+ "name": "Art, header",
67+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "summary": undefined }) }
11268 },
11369 {
114− "name": "Art, summary - vertical",
70+ "name": "Art, summary",
11571 "layout": { "components": { "art": "art", "summary": "summary" } }
11672 },
11773 {
118− "name": "Header title only - horizontal",
119− "layout": { "template": { "card-layout": "horizontal" },
120− "components": { "title": "title" } }
74+ "name": "Header title only",
75+ "layout": { "components": { "title": "title" } }
12176 },
12277 ]
12378
79+ CardTool {
80+ id: cardTool
81+ template: card.template
82+ components: card.components
83+ }
84+
12485 Card {
12586 id: card
12687 anchors { top: parent.top; left: parent.left; margins: units.gu(1) }
12788
128− template: Helpers.update(JSON.parse(root.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template'];
129− components: Helpers.update(JSON.parse(root.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components'];
89+ width: cardTool.cardWidth || implicitWidth
90+ height: cardTool.cardHeight || implicitHeight
91+
92+ template: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template'];
93+ components: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components'];
13094 cardData: Helpers.mapData(dataArea.text, components, dataError)
13195 }
13296
@@ -249,8 +213,8 @@ Rectangle {
249213 function test_card_size_data() {
250214 return [
251215 { tag: "Medium", width: units.gu(18.5), index: 0 },
252− { tag: "Small", width: units.gu(12), size: "small", index: 0 },
253− { tag: "Large", width: units.gu(38), size: "large", index: 0 },
216+ { tag: "Small", width: units.gu(12), index: 1 },
217+ { tag: "Large", width: units.gu(38), index: 2 },
254218 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
255219 { tag: "Horizontal", width: units.gu(38), index: 5 },
256220 // Make sure card ends with header when there's no summary
tests/qmltests/Dash/tst_CardTool.qmlnew file+300
@@ -0,0 +1,300 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 0.1
20+import Unity.Test 0.1 as UT
21+import "../../../qml/Dash"
22+import "CardHelpers.js" as Helpers
23+
24+Rectangle {
25+ id: root
26+ width: units.gu(80)
27+ height: units.gu(72)
28+ color: "#88FFFFFF"
29+
30+ property var cardsModel: [
31+ {
32+ "name": "Art, header, summary",
33+ "layout": { "components": JSON.parse(Helpers.fullMapping) }
34+ },
35+ {
36+ "name": "Header, summary",
37+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": undefined }) }
38+ },
39+ {
40+ "name": "Art, header",
41+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "summary": undefined }) }
42+ },
43+ {
44+ "name": "Header only",
45+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": undefined, "summary": undefined }) }
46+ },
47+ {
48+ "name": "Header title only",
49+ "layout": { "components": { "title": "title" } }
50+ },
51+ {
52+ "name": "Header title and subtitle",
53+ "layout": { "components": { "title": "title", "subtitle": "subtitle" } }
54+ },
55+ {
56+ "name": "Header title and mascot",
57+ "layout": { "components": { "title": "title", "mascot": "mascot" } }
58+ },
59+ {
60+ "name": "Art, header, summary - small",
61+ "layout": { "template": { "card-size": "small" }, "components": JSON.parse(Helpers.fullMapping) }
62+ },
63+ {
64+ "name": "Art, header, summary - large",
65+ "layout": { "template": { "card-size": "large" }, "components": JSON.parse(Helpers.fullMapping) }
66+ },
67+ {
68+ "name": "Art, header, summary - horizontal",
69+ "layout": { "template": { "card-layout": "horizontal" }, "components": JSON.parse(Helpers.fullMapping) }
70+ },
71+ {
72+ "name": "Art, header - portrait",
73+ "layout": { "components": Helpers.update(JSON.parse(Helpers.fullMapping), { "art": {"aspect-ratio": 0.5, "summary": undefined }}) }
74+ },
75+ ]
76+
77+ CardTool {
78+ id: cardTool
79+
80+ template: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template'];
81+ components: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components'];
82+ viewWidth: units.gu(Math.round(widthSlider.value))
83+ }
84+
85+ Column {
86+ width: units.gu(38)
87+ anchors { left: parent.left; top: parent.top; margins: units.gu(1) }
88+
89+ Repeater {
90+ model: [
91+ { label: "View width", value: cardTool.viewWidth && cardTool.viewWidth / units.gu(1) },
92+ { label: "Card width", value: cardTool.cardWidth && cardTool.cardWidth / units.gu(1) },
93+ { label: "Card height", value: cardTool.cardHeight && cardTool.cardHeight / units.gu(1) },
94+ ]
95+
96+ delegate: Row {
97+ anchors { left: parent.left; right: parent.right; margins: units.gu(3) }
98+
99+ Label {
100+ height: units.gu(5)
101+ width: units.gu(25)
102+ text: modelData.label
103+ verticalAlignment: Text.AlignVCenter
104+ }
105+
106+ Label {
107+ height: units.gu(5)
108+ text: modelData.value || "undefined"
109+ verticalAlignment: Text.AlignVCenter
110+ }
111+ }
112+ }
113+
114+ Card {
115+ id: card
116+ template: cardTool.template;
117+ components: cardTool.components;
118+ cardData: Helpers.mapData(dataArea.text, components, dataError)
119+
120+ width: cardTool.cardWidth || implicitWidth
121+ height: cardTool.cardHeight || implicitHeight
122+
123+ clip: true
124+
125+ Rectangle {
126+ anchors.fill: parent
127+ color: "transparent"
128+ border.width: 1
129+ border.color: "green"
130+ }
131+ }
132+ }
133+
134+ Rectangle {
135+ anchors { top: parent.top; bottom: parent.bottom; right: parent.right}
136+ width: units.gu(40)
137+ color: "lightgrey"
138+
139+ Column {
140+ anchors { fill: parent; margins: units.gu(1) }
141+ spacing: units.gu(1)
142+
143+ OptionSelector {
144+ id: selector
145+ model: cardsModel
146+ delegate: OptionSelectorDelegate { text: modelData.name }
147+ onSelectedIndexChanged: updateAreas()
148+ Component.onCompleted: updateAreas()
149+
150+ function updateAreas() {
151+ var element = cardsModel[selectedIndex];
152+ if (element) {
153+ layoutArea.text = JSON.stringify(element.layout, undefined, 2) || "{}";
154+ } else {
155+ layoutArea.text = "";
156+ }
157+ }
158+ }
159+
160+ OptionSelector {
161+ id: layoutSelector
162+ model: [
163+ { label: "Grid", layout: "grid" },
164+ { label: "Organic Grid", layout: "organic-grid" },
165+ { label: "Horizontal Journal", layout: "journal" },
166+ { label: "Vertical Journal", layout: "vertical-journal" },
167+ { label: "Carousel", layout: "carousel" },
168+ ]
169+ delegate: OptionSelectorDelegate { text: modelData.label }
170+ onSelectedIndexChanged: {
171+ var element = model[selectedIndex];
172+ if (element && cardTool.template["category-layout"] !== element.layout) {
173+ var current = JSON.parse(layoutArea.text);
174+ var update = { "template": { "category-layout": element.layout }}
175+ layoutArea.text = JSON.stringify(Helpers.update(current, update), undefined, 2) || "{}";
176+ }
177+ }
178+ }
179+
180+ Label {
181+ anchors { left: parent.left; right: parent.right }
182+ height: units.gu(3)
183+ verticalAlignment: Text.AlignBottom
184+ text: "View width:"
185+ }
186+
187+ Slider {
188+ id: widthSlider
189+ minimumValue: 30
190+ maximumValue: 140
191+ live: true
192+ value: 40
193+ }
194+
195+ TextArea {
196+ id: layoutArea
197+ anchors { left: parent.left; right: parent.right }
198+ height: units.gu(25)
199+ }
200+
201+ Label {
202+ id: layoutError
203+ anchors { left: parent.left; right: parent.right }
204+ height: units.gu(4)
205+ color: "orange"
206+ }
207+
208+ TextArea {
209+ id: dataArea
210+ anchors { left: parent.left; right: parent.right }
211+ height: units.gu(25)
212+ text: JSON.stringify(cardTool.priv.cardData, undefined, 2)
213+ }
214+
215+ Label {
216+ id: dataError
217+ anchors { left: parent.left; right: parent.right }
218+ height: units.gu(4)
219+ color: "orange"
220+ }
221+ }
222+
223+ Connections {
224+ target: cardTool
225+ onTemplateChanged: {
226+ switch(cardTool.template["category-layout"]) {
227+ case "organic-grid": layoutSelector.selectedIndex = 1; break;
228+ case "journal": layoutSelector.selectedIndex = 2; break;
229+ case "vertical-journal": layoutSelector.selectedIndex = 3; break;
230+ case "carousel": layoutSelector.selectedIndex = 4; break;
231+ case "grid":
232+ default: layoutSelector.selectedIndex = 0; break;
233+ }
234+ }
235+ }
236+ }
237+
238+ UT.UnityTestCase {
239+ id: testCase
240+ name: "Card"
241+
242+ when: windowShown
243+
244+ function cleanup() {
245+ selector.selectedIndex = -1;
246+ layoutSelector.selectedIndex = -1;
247+ }
248+
249+ function test_card_size_data() {
250+ return [
251+ { tag: "Medium", width: units.gu(18.5), height: function() { return card.height }, index: 0 },
252+ { tag: "No art", width: units.gu(18.5), height: function() { return card.height }, index: 1 },
253+ { tag: "No summary", width: units.gu(18.5), height: function() { return card.height }, index: 2 },
254+ { tag: "Just header", width: units.gu(18.5), height: function() { return card.height }, index: 3 },
255+ { tag: "Just title", width: units.gu(18.5), height: function() { return card.height }, index: 4 },
256+ { tag: "Title and subtitle", width: units.gu(18.5), height: function() { return card.height }, index: 5 },
257+ { tag: "Title and mascot", width: units.gu(18.5), height: function() { return card.height }, index: 6 },
258+ { tag: "Small", width: units.gu(12), height: function() { return card.height }, index: 7 },
259+ { tag: "Large", width: units.gu(38), height: function() { return card.height }, index: 8 },
260+ { tag: "Horizontal", width: units.gu(38), height: function() { return card.height }, index: 9 },
261+ { tag: "OrganicGrid", width: undefined, height: undefined, index: 0, layout_index: 1},
262+ { tag: "Journal", width: undefined, height: units.gu(20), size: 20, index: 0, layout_index: 2 },
263+ { tag: "OversizedJournal", width: undefined, height: units.gu(18.5), size: 40, index: 0, layout_index: 2 },
264+ { tag: "VerticalJournal", width: units.gu(18.5), height: undefined, index: 0, layout_index: 3 },
265+ { tag: "SmallCarousel", width: units.gu(18), height: units.gu(18), viewWidth: 30, index: 0, layout_index: 4},
266+ { tag: "MediumCarousel", width: units.gu(22), height: units.gu(22), viewWidth: 84, index: 0, layout_index: 4},
267+ { tag: "LargeCarousel", width: units.gu(26), height: units.gu(26), viewWidth: 140, index: 0, layout_index: 4},
268+ { tag: "PortraitCarousel", width: units.gu(22), height: units.gu(44), viewWidth: 84, index: 10, layout_index: 4},
269+ ]
270+ }
271+
272+ function test_card_size(data) {
273+ selector.selectedIndex = data.index;
274+ if (data.hasOwnProperty("layout_index")) {
275+ layoutSelector.selectedIndex = data.layout_index;
276+ }
277+
278+ if (data.hasOwnProperty("viewWidth")) {
279+ widthSlider.value = data.viewWidth;
280+ }
281+
282+ if (data.hasOwnProperty("size")) {
283+ cardTool.template['card-size'] = data.size;
284+ cardTool.templateChanged();
285+ }
286+
287+ if (data.hasOwnProperty("width")) {
288+ if (typeof data.width === "function") {
289+ tryCompareFunction(function() { return cardTool.cardWidth === data.width() }, true);
290+ } else tryCompare(cardTool, "cardWidth", data.width);
291+ }
292+
293+ if (data.hasOwnProperty("height")) {
294+ if (typeof data.height === "function") {
295+ tryCompareFunction(function() { return cardTool.cardHeight === data.height() }, true);
296+ } else tryCompare(cardTool, "cardHeight", data.height);
297+ }
298+ }
299+ }
300+}