diff --git a/front-ui/app/actions/itemDetailsActions.js b/front-ui/app/actions/itemDetailsActions.js
new file mode 100644
index 0000000..8fa3430
--- /dev/null
+++ b/front-ui/app/actions/itemDetailsActions.js
@@ -0,0 +1,36 @@
+var AppDispatcher = require('../dispatcher/appDispatcher');
+var ItemDetailsConstants = require('../constants/itemDetailsConstants');
+
+// Define action methods
+var ItemDetailsActions = {
+
+
+ loadItemWithDetails: function() {
+ AppDispatcher.handleAction({
+ actionType: ItemDetailsConstants.LOAD_ITEM_WITH_DETAILS
+ })
+ },
+
+ nextCarouselImage: function() {
+ AppDispatcher.handleAction({
+ actionType: ItemDetailsConstants.NEXT_CAROUSEL_IMAGE
+ })
+ },
+
+ previousCarouselImage: function() {
+ AppDispatcher.handleAction({
+ actionType: ItemDetailsConstants.PREVIOUS_CAROUSEL_IMAGE
+ })
+ },
+
+ selectCarouselImage: function(index) {
+ AppDispatcher.handleAction({
+ actionType: ItemDetailsConstants.SELECT_CAROUSEL_IMAGE,
+ index: index
+ })
+ }
+
+
+};
+
+module.exports = ItemDetailsActions;
\ No newline at end of file
diff --git a/front-ui/app/components/items/itemMultiMediaDescriptions.js b/front-ui/app/components/items/itemMultiMediaDescriptions.js
index 1f4fb12..5b5b75b 100644
--- a/front-ui/app/components/items/itemMultiMediaDescriptions.js
+++ b/front-ui/app/components/items/itemMultiMediaDescriptions.js
@@ -15,9 +15,6 @@ var ItemMultimediaDescriptions = React.createClass({
);
}
- //getInitialState: function () {
- //return { descriptions: [] };
- //}
});
diff --git a/front-ui/app/components/items/itemWithDetailsPage.js b/front-ui/app/components/items/itemWithDetailsPage.js
index e76b653..295457b 100644
--- a/front-ui/app/components/items/itemWithDetailsPage.js
+++ b/front-ui/app/components/items/itemWithDetailsPage.js
@@ -1,8 +1,8 @@
var React = require('react'),
- ItemMultiMediaDescriptions = require('./itemMultiMediaDescriptions'),
- ItemActions = require('../../actions/itemActions'),
- NavigationStore = require('../../stores/NavigationStore'),
- ItemStore = require('../../stores/itemStore');
+ Carousel = require('../shared/carousel'),
+ ItemDetailsActions = require('../../actions/itemDetailsActions'),
+ NavigationStore = require('../../stores/navigationStore'),
+ ItemDetailsStore = require('../../stores/itemDetailsStore');
var Router = require('react-router');
@@ -13,47 +13,59 @@ var ItemWithDetailsPage = React.createClass({
return (
-
-
-
-
+
+
+
{this.state.item.get('name')}
-
-
{this.state.item.get('list_price')} KM
-
{this.state.item.get('description')}
+
{this.state.item.get('list_price')} KM
+
{this.state.item.get('description')}
-
-
-
+
+
+
quantitative descriptions
-
- ) ;
+
+ );
},
// Add change listeners to stores
componentDidMount: function() {
- ItemStore.addChangeListener(this._onChange);
+ ItemDetailsStore.addChangeListener(this._onChange);
NavigationStore.addChangeListener(this._onChange);
- ItemActions.loadItemWithDetails();
+ ItemDetailsActions.loadItemWithDetails();
},
+
+ onClickLeft: function() {
+ ItemDetailsActions.previousCarouselImage();
+
+ },
+
+ onClickRight: function() {
+ ItemDetailsActions.nextCarouselImage();
+ },
+
+ onSelectImage: function(i) {
+ ItemDetailsActions.selectCarouselImage(i);
+ },
+
_onChange: function () {
if (this.isMounted()) {
- this.setState({
- item: ItemStore.getLoadedItemWithDetails()
- });
+ this.setState(ItemDetailsStore.getState());
}
},
getInitialState: function () {
- return {
- item : ItemStore.getLoadedItemWithDetails()
- };
+ return ItemDetailsStore.getState();
}
});
diff --git a/front-ui/app/components/shared/carousel.js b/front-ui/app/components/shared/carousel.js
new file mode 100644
index 0000000..69a5278
--- /dev/null
+++ b/front-ui/app/components/shared/carousel.js
@@ -0,0 +1,51 @@
+var React = require("react");
+
+var Carousel = React.createClass({
+ propTypes: {
+ images: React.PropTypes.array.isRequired,
+ selected: React.PropTypes.number.isRequired,
+ onClickLeft: React.PropTypes.func.isRequired,
+ onClickRight: React.PropTypes.func.isRequired,
+ onSelectImage: React.PropTypes.func.isRequired
+ },
+
+ render: function() {
+ var left = this.props.selected * 300 * -1,
+ ulStyle = {
+ width: this.props.images.length * 300,
+ "-ms-transform": "translate(" + left + "px,0px)",
+ "-webkit-transform": "translate(" + left + "px,0px)",
+ transform: "translate(" + left + "px,0px)"
+ };
+
+ return (
+
+
◄
+
+
+ {this.props.images.map(function(image, i) {
+ return 
;
+ })}
+
+
+ {this.props.images.map(function(image, i) {
+ var activeClass = i === this.props.selected ? "active" : "";
+ return ;
+ }.bind(this))}
+
+
+
►
+
+ )
+ },
+
+ onClickDot: function(index) {
+ this.props.onSelectImage(index);
+ }
+});
+
+module.exports = Carousel;
\ No newline at end of file
diff --git a/front-ui/app/constants/itemDetailsConstants.js b/front-ui/app/constants/itemDetailsConstants.js
new file mode 100644
index 0000000..af68f91
--- /dev/null
+++ b/front-ui/app/constants/itemDetailsConstants.js
@@ -0,0 +1,9 @@
+var keyMirror = require('react/lib/keyMirror');
+
+// Define action constants
+module.exports = keyMirror({
+ LOAD_ITEM_WITH_DETAILS: null,
+ NEXT_CAROUSEL_IMAGE: null,
+ PREVIOUS_CAROUSEL_IMAGE: null,
+ SELECT_CAROUSEL_IMAGE: null
+});
\ No newline at end of file
diff --git a/front-ui/app/css/carousel.css b/front-ui/app/css/carousel.css
new file mode 100644
index 0000000..1e1cebd
--- /dev/null
+++ b/front-ui/app/css/carousel.css
@@ -0,0 +1,72 @@
+* {
+ box-sizing: border-box;
+}
+.application-container {
+ width: 400px;
+ margin: 0 auto;
+}
+.arrow,
+.circle {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.arrow {
+ position: relative;
+ top: -100px;
+ padding: 10px;
+}
+.carousel-stage {
+ width: 300px;
+ height: 200px;
+ border: 1px solid black;
+ overflow: hidden;
+ display: inline-block;
+ position: relative;
+}
+.carousel-stage ul.carousel-list {
+ display: inline-block;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ position: relative;
+ transition: 300ms ease-in-out;
+}
+.carousel-stage ul.carousel-list li {
+ display: inline-block;
+ width: 300px;
+ height: 200px;
+ float: left;
+}
+.carousel-stage ul.carousel-list li img {
+ object-fit: cover;
+ object-position: center center;
+ width: 300px;
+ height: 200px;
+}
+.carousel-stage ul.dots {
+ width: 300px;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ position: absolute;
+ bottom: 0;
+ text-align: center;
+}
+.carousel-stage ul.dots li {
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ background-color: white;
+ margin: 2px;
+ border-radius: 50%;
+ line-height: 5px;
+ border: 2px solid black;
+}
+.carousel-stage ul.dots li.active {
+ background-color: #ccc;
+}
\ No newline at end of file
diff --git a/front-ui/app/stores/itemDetailsStore.js b/front-ui/app/stores/itemDetailsStore.js
new file mode 100644
index 0000000..f377208
--- /dev/null
+++ b/front-ui/app/stores/itemDetailsStore.js
@@ -0,0 +1,147 @@
+var AppDispatcher = require('../dispatcher/appDispatcher');
+var EventEmitter = require('events').EventEmitter;
+var ItemDetailsConstants = require('../constants/itemDetailsConstants');
+var ItemWithDetails = require('../models/itemWithDetails');
+var _ = require('underscore');
+
+
+var _itemWithDetails = new ItemWithDetails();
+var _images = [];
+var _currentImage = 0;
+var _animating = false;
+var _count;
+
+
+var getItemIdFromUrl = function() {
+ // ugly but it seems to me that
+ // router does not want to expose its
+ // state (for phylosophical reasons)
+ var url = document.URL;
+ var itemIdRegex = /artikal\/(\d+)\//g;
+ var match = itemIdRegex.exec(url);
+ console.log(match);
+ return match[1];
+};
+
+var fetchItemWithDetails = function() {
+ var id = getItemIdFromUrl();
+ if (id !== undefined && _itemWithDetails.id !== id) {
+ var item = new ItemWithDetails({
+ id: id
+ });
+ item.fetch({
+ success: function() {
+ _itemWithDetails = item;
+ _images = (_itemWithDetails.get("multi_media_descriptions") || []).map(function(mmd) {
+ return mmd.url;
+ });
+ _count = _images.length;
+ _currentImage = 0;
+ _animating = false;
+ ItemWithDetailsStore.emitChange();
+ }
+ });
+ }
+};
+
+var handlNextImage = function() {
+ if (_animating) return;
+ var next = _currentImage + 1;
+ if (next >= _count) next = 0;
+ handleSelectImage(next);
+};
+
+var handlePrevImage = function() {
+ if (_animating) return;
+ var next = _currentImage - 1;
+ if (next < 0) next = _count - 1;
+ handleSelectImage(next);
+};
+
+
+var handleSelectImage = function(index) {
+ if (_animating) return;
+ _animating = true;
+ _currentImage = index;
+ setTimeout(function() {
+ _animating = false;
+ }, 300);
+};
+
+
+
+// Extend ItemWithDetailsStore with EventEmitter to add eventing capabilities
+var ItemWithDetailsStore = _.extend({}, EventEmitter.prototype, {
+
+ getState: function() {
+
+
+
+ return {
+ item: _itemWithDetails,
+ images: _images,
+ currentImage: _currentImage,
+ count: _count
+ }
+
+ },
+
+
+ // item with details
+ getLoadedItemWithDetails: function() {
+ return _itemWithDetails;
+ },
+
+ // Emit Change event
+ emitChange: function() {
+ console.log("Emitting change!");
+ this.emit('change');
+ },
+
+ // Add change listener
+ addChangeListener: function(callback) {
+ this.on('change', callback);
+ },
+
+ // Remove change listener
+ removeChangeListener: function(callback) {
+ this.removeListener('change', callback);
+ }
+
+});
+
+
+// Register callback with AppDispatcher
+AppDispatcher.register(function(payload) {
+ var action = payload.action;
+ var text;
+
+ switch (action.actionType) {
+
+ case ItemDetailsConstants.LOAD_ITEM_WITH_DETAILS:
+ fetchItemWithDetails();
+ break;
+
+ case ItemDetailsConstants.NEXT_CAROUSEL_IMAGE:
+ handlNextImage();
+ break;
+
+ case ItemDetailsConstants.PREVIOUS_CAROUSEL_IMAGE:
+ handlePrevImage();
+ break;
+
+ case ItemDetailsConstants.SELECT_CAROUSEL_IMAGE:
+ handleSelectImage(action.index);
+ break;
+
+ default:
+ return true;
+ }
+
+ // If action was responded to, emit change event
+ ItemWithDetailsStore.emitChange();
+ return true;
+
+});
+
+module.exports = ItemWithDetailsStore;
\ No newline at end of file
diff --git a/front-ui/app/stores/navigationStore.js b/front-ui/app/stores/navigationStore.js
index 2264eda..c9ec59b 100644
--- a/front-ui/app/stores/navigationStore.js
+++ b/front-ui/app/stores/navigationStore.js
@@ -8,16 +8,7 @@ var _ = require('underscore');
// Extend ItemStore with EventEmitter to add eventing capabilities
var NavigationStore = _.extend({}, EventEmitter.prototype, {
- getItemIdFromUrl: function () {
- // ugly but it seems to me that
- // router does not want to expose its
- // state
- var url = document.URL;
- var itemIdRegex = /artikal\/(\d+)\//;
- var match = itemIdRegex.exec(url);
- console.log(match);
- return match[0];
- },
+
// Emit Change event
emitChange: function() {