3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Total items in cart: {{items.length}}
11 |
12 |
15 |
16 |
17 |
18 |
19 | {{#if items.length}}
20 | {{#each items as |item itemIndex|}}
21 | {{#with item}}
22 |
23 |
24 |
25 |

26 |
27 |
28 |
35 |
36 |
37 |
{{itemName}}
38 |
{{categoryName}}
39 |
{{itemPrice}}
40 |
41 |
42 |
49 |
50 | {{/with}}
51 | {{/each}}
52 | {{/if}}
53 |
54 |
Currently there are no items in cart.
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | {{#loadModule 'viewCartItems'}} {{/loadModule}}
--------------------------------------------------------------------------------
/frontend/app/assets/styles-less/item/itemView.less:
--------------------------------------------------------------------------------
1 | @color-black: #000;
2 | @label-color: #878787;
3 |
4 | .info-label() {
5 | color: @label-color;
6 | }
7 |
8 | .panel-background() {
9 | background-color: #fff;
10 | margin: 10px;
11 | border-radius: 3px;
12 | box-sizing: border-box;
13 | }
14 |
15 | .item-overview-panel {
16 | .panel-background();
17 |
18 | .item-image-box {
19 | min-height: 350px;
20 | border: 1px solid #f0f0f0;
21 | margin: 5px;
22 | }
23 |
24 | .detail-header {
25 | margin: 5px;
26 | font-size: x-large;
27 | font-weight: 500;
28 | color: @color-black;
29 |
30 | .category-info {
31 | font-size: small;
32 | color: @label-color;
33 | margin-left: 5px;
34 |
35 | i {
36 | font-size: 10px;
37 | }
38 | }
39 |
40 | .item-name-title {
41 | line-height: 1.4;
42 | padding-left: 5px;
43 | }
44 | }
45 |
46 | .item-price-detail {
47 | color: @color-black;
48 |
49 | .item-price {
50 | font-weight: 600;
51 | font-size: x-large;
52 | }
53 | }
54 |
55 | .add-to-cart-button {
56 | margin-top: 2px;
57 | margin-bottom: 7px;
58 |
59 | button {
60 | width: 200px;
61 | font-size: medium;
62 | }
63 | }
64 |
65 | .delivery-info {
66 | font-size: medium;
67 | margin-top: 15px;
68 |
69 | .info-detail-wrapper {
70 | margin-bottom: 10px;
71 | }
72 |
73 | .label-delivery-info {
74 | .info-label()
75 | }
76 |
77 | table {
78 | color: #388e3c;
79 | }
80 |
81 | .label {
82 | color: #212121;
83 | font-weight: 500;
84 | font-size: medium;
85 | }
86 |
87 | }
88 |
89 | .item-features {
90 | margin-top: 10px;
91 | font-size: medium;
92 |
93 | .label-item-features {
94 | .info-label()
95 | }
96 |
97 | .feature-list {
98 | li {
99 | list-style: none;
100 | position: relative;
101 | padding: 0 0 8px 16px;
102 |
103 | &:after {
104 | content: "";
105 | height: 6px;
106 | width: 6px;
107 | position: absolute;
108 | top: 6px;
109 | left: 0;
110 | border-radius: 50%;
111 | background: #c2c2c2;
112 | }
113 | }
114 | }
115 | }
116 |
117 | .seller-info {
118 | font-size: medium;
119 |
120 | .label-seller-info {
121 | .info-label()
122 | }
123 | }
124 | }
125 |
126 | .item-description-panel {
127 | .panel-background();
128 |
129 | .item-description-area {
130 | margin: 10px;
131 | padding: 5px;
132 | }
133 |
134 | .divider {
135 | border: 0.1px solid #878787;
136 | height: 1px;
137 | width: 98%;
138 | margin-left: 1%;
139 | opacity: 0.2;
140 | }
141 |
142 | .description-title {
143 | padding: 5px;
144 | color: #212121;
145 | font-size: x-large;
146 | font-weight: 600;
147 | }
148 |
149 | .details {
150 | margin: 10px 0px 10px 15px;
151 | font-size: medium;
152 | color: #332;
153 | }
154 | }
--------------------------------------------------------------------------------
/frontend/app/assets/styles/item/itemView.css:
--------------------------------------------------------------------------------
1 | .item-overview-panel {
2 | background-color: #fff;
3 | margin: 10px;
4 | border-radius: 3px;
5 | box-sizing: border-box;
6 | }
7 | .item-overview-panel .item-image-box {
8 | min-height: 350px;
9 | border: 1px solid #f0f0f0;
10 | margin: 5px;
11 | }
12 | .item-overview-panel .detail-header {
13 | margin: 5px;
14 | font-size: x-large;
15 | font-weight: 500;
16 | color: #000;
17 | }
18 | .item-overview-panel .detail-header .category-info {
19 | font-size: small;
20 | color: #878787;
21 | margin-left: 5px;
22 | }
23 | .item-overview-panel .detail-header .category-info i {
24 | font-size: 10px;
25 | }
26 | .item-overview-panel .detail-header .item-name-title {
27 | line-height: 1.4;
28 | padding-left: 5px;
29 | }
30 | .item-overview-panel .item-price-detail {
31 | color: #000;
32 | }
33 | .item-overview-panel .item-price-detail .item-price {
34 | font-weight: 600;
35 | font-size: x-large;
36 | }
37 | .item-overview-panel .add-to-cart-button {
38 | margin-top: 2px;
39 | margin-bottom: 7px;
40 | }
41 | .item-overview-panel .add-to-cart-button button {
42 | width: 200px;
43 | font-size: medium;
44 | }
45 | .item-overview-panel .delivery-info {
46 | font-size: medium;
47 | margin-top: 15px;
48 | }
49 | .item-overview-panel .delivery-info .info-detail-wrapper {
50 | margin-bottom: 10px;
51 | }
52 | .item-overview-panel .delivery-info .label-delivery-info {
53 | color: #878787;
54 | }
55 | .item-overview-panel .delivery-info table {
56 | color: #388e3c;
57 | }
58 | .item-overview-panel .delivery-info .label {
59 | color: #212121;
60 | font-weight: 500;
61 | font-size: medium;
62 | }
63 | .item-overview-panel .item-features {
64 | margin-top: 10px;
65 | font-size: medium;
66 | }
67 | .item-overview-panel .item-features .label-item-features {
68 | color: #878787;
69 | }
70 | .item-overview-panel .item-features .feature-list li {
71 | list-style: none;
72 | position: relative;
73 | padding: 0 0 8px 16px;
74 | }
75 | .item-overview-panel .item-features .feature-list li:after {
76 | content: "";
77 | height: 6px;
78 | width: 6px;
79 | position: absolute;
80 | top: 6px;
81 | left: 0;
82 | border-radius: 50%;
83 | background: #c2c2c2;
84 | }
85 | .item-overview-panel .seller-info {
86 | font-size: medium;
87 | }
88 | .item-overview-panel .seller-info .label-seller-info {
89 | color: #878787;
90 | }
91 | .item-description-panel {
92 | background-color: #fff;
93 | margin: 10px;
94 | border-radius: 3px;
95 | box-sizing: border-box;
96 | }
97 | .item-description-panel .item-description-area {
98 | margin: 10px;
99 | padding: 5px;
100 | }
101 | .item-description-panel .divider {
102 | border: 0.1px solid #878787;
103 | height: 1px;
104 | width: 98%;
105 | margin-left: 1%;
106 | opacity: 0.2;
107 | }
108 | .item-description-panel .description-title {
109 | padding: 5px;
110 | color: #212121;
111 | font-size: x-large;
112 | font-weight: 600;
113 | }
114 | .item-description-panel .details {
115 | margin: 10px 0px 10px 15px;
116 | font-size: medium;
117 | color: #332;
118 | }
119 |
--------------------------------------------------------------------------------
/frontend/app/templates/toppage/widgets/homeAppliances.hbs:
--------------------------------------------------------------------------------
1 |
2 |
44 | {{#loadModule "homeAppliancesWidget"}} {{/loadModule}}
--------------------------------------------------------------------------------
/frontend/app/js/toppage/modules/homepage.js:
--------------------------------------------------------------------------------
1 | define(['jquery', 'handlebars', 'toppage', 'mainHeader', 'hbdivide', 'jscf'],
2 | function homepage($, Handlebars, toppage, mainHeader, divide) {
3 | 'use strict';
4 |
5 | return function callback() {
6 | var categories = [
7 | {
8 | categoryId : 1,
9 | categoryName : 'Electronics',
10 | level : 1,
11 | subCategories: [
12 | {
13 | categoryId : 3,
14 | categoryName : 'Mobile',
15 | isCategoryHead: true,
16 | level : 2,
17 | subCategories : [
18 | {
19 | categoryId : 5,
20 | categoryName: 'LG',
21 | level : 3,
22 | },
23 | {
24 | categoryId : 6,
25 | categoryName: 'Motorola',
26 | level : 3,
27 | },
28 | {
29 | categoryId : 7,
30 | categoryName: 'Samsung',
31 | level : 3,
32 | },
33 | ],
34 | },
35 | {
36 | categoryId : 4,
37 | categoryName : 'Laptop',
38 | level : 2,
39 | isCategoryHead: true,
40 | subCategories : [
41 | {
42 | categoryId : 8,
43 | categoryName: 'Apple',
44 | level : 3,
45 | },
46 | {
47 | categoryId : 9,
48 | categoryName: 'Toshiba',
49 | level : 3,
50 | },
51 | {
52 | categoryId : 10,
53 | categoryName: 'Lenovo',
54 | level : 3,
55 | },
56 | ],
57 | },
58 | {
59 | categoryId : 11,
60 | categoryName : 'Desktop PCs',
61 | level : 2,
62 | isCategoryHead: true,
63 | },
64 | ],
65 | },
66 | {
67 | categoryId : 2,
68 | categoryName: 'Appliances',
69 | level : 1,
70 | },
71 | ];
72 |
73 | /**
74 | * This helper will work to recursively iterate over categories and make nested menu for XS devices.
75 | * Similar like tree structure:
76 | * A
77 | * |
78 | * ---- B
79 | * |
80 | * ---- C
81 | * ---- D
82 | * ---- E
83 | * |
84 | * ---- F
85 | * |
86 | * ---- G
87 | * .
88 | * .
89 | * .
90 | */
91 | Handlebars.registerHelper('generateSubCategories', function generateSubCategoriesPartial(mwrapper, mcategory, block) {
92 | return (function getCategories(category, wrapper) {
93 | var $wrapper = $(wrapper);
94 | var lis = '';
95 | var subCategories = category.subCategories;
96 | if (subCategories && subCategories.length) {
97 | $.each(subCategories, function callbackForEachSubCat(key, cat) {
98 | lis += block.fn({ subCat: cat, moreSubCategories: getCategories(cat, wrapper) });
99 | });
100 | $wrapper.append(lis);
101 | return $wrapper[0].outerHTML;
102 | }
103 | return '';
104 | }(mcategory, mwrapper));
105 | });
106 |
107 | // Register partials
108 | Handlebars.registerPartial('header', toppage.header({ categories: categories, userMenu: toppage.userMenu() }));
109 | Handlebars.registerPartial('footer', toppage.footer());
110 |
111 | $('#homepage').html(toppage.homepage());
112 | };
113 | });
114 |
--------------------------------------------------------------------------------
/frontend/app/templates/toppage/widgets/newArrivals.hbs:
--------------------------------------------------------------------------------
1 |
2 |
47 | {{#loadModule "newArrivalsWidget"}} {{/loadModule}}
--------------------------------------------------------------------------------
/frontend/app/templates/toppage/widgets/laptopsAndDesktops.hbs:
--------------------------------------------------------------------------------
1 |
2 |
44 | {{#loadModule "laptopsAndDesktopsWidget"}} {{/loadModule}}
--------------------------------------------------------------------------------
/frontend/app/templates/user/signup.hbs:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/frontend/app/templates/item/itemView.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
![]()
9 |
10 |
11 |
12 |
20 |
21 |
22 |
23 | {{item.itemPrice}}
24 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | |
44 | Burden of delivery:
45 | |
46 |
47 |
48 | {{item.deliveryBurden}}
49 | |
50 |
51 |
52 | |
53 | Item is from:
54 | |
55 |
56 |
57 | {{item.itemSource}}
58 | |
59 |
60 |
61 | |
62 | Can ship within:
63 | |
64 |
65 |
66 | {{item.shipTime}}
67 | |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | - abc
80 | - sfjs
81 | - sehwr
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
Details
103 |
104 |
105 | {{item.description}}
106 |
107 |
108 |
109 |
110 | {{#loadModule 'itemView' item}} {{/loadModule}}
--------------------------------------------------------------------------------
/frontend/app/js/toppage/modules/widgets/homeAppliancesWidget.js:
--------------------------------------------------------------------------------
1 | if (typeof define === 'function' && define.amd) {
2 | define(['jquery', 'jscf', 'lightslider'], function homeAppliancesWidgetModule($, jscf) {
3 | 'use strict';
4 |
5 | return function homeAppliancesWidget() {
6 | var settings = {
7 | css: {
8 | sliderTpl : '#homeAppliancesSliderTpl',
9 | widget : '#homeAppliancesSlider',
10 | sliderItem : '.item',
11 | widgetSettings : '.widget-settings',
12 | widgetSettingsMock: '.widget-settings-mock',
13 | itemImage : '.item-image',
14 | },
15 |
16 | widget: {
17 | enabled : [true, 'bool'],
18 | image_width : [110, 'int'],
19 | image_height: [110, 'int'],
20 | },
21 | };
22 |
23 | var $elems = {
24 | widget : $(settings.css.widget),
25 | sliderTplHtml: $(settings.css.sliderTpl).remove().html(),
26 | };
27 |
28 | var options;
29 |
30 | /**
31 | * Initialize slider element using lightSlider plugin.
32 | * Set necessary options for slider
33 | */
34 | function initializeSlideshow($contentSlider) {
35 | var sliderOptions = {
36 | loop : true,
37 | keyPress : true,
38 | enableDrag: false,
39 | autoWidth : true,
40 | prevHtml : '
',
41 | nextHtml : '
',
42 | };
43 |
44 | if (jscf.browser.isSp) {
45 | sliderOptions.controls = false;
46 | sliderOptions.enableDrag = true;
47 | }
48 | $elems.widget.append($contentSlider);
49 |
50 | $contentSlider.lightSlider(sliderOptions);
51 |
52 | $elems.widget.show();
53 | }
54 |
55 | /**
56 | * Prepare for rendering slideshow after calling api
57 | * @name prepareSlider
58 | *
59 | * @param {Object} data Data retrieved from api
60 | */
61 | function prepareSlider(data) {
62 | var $sliderTpl = $($elems.sliderTplHtml);
63 | var css = settings.css;
64 | var $liItem = $sliderTpl.find(css.sliderItem).remove();
65 | var items = data.items;
66 | var n = items.length;
67 | var sliderData = {};
68 | var i;
69 | var $sliderItem;
70 | var item;
71 |
72 | for (i = 0; i < n; i++) {
73 | item = items[i];
74 | sliderData['#ITEM_NAME#'] = item.itemName;
75 | sliderData['#ITEM_IMAGE_URL#'] = item.itemImageUrl;
76 | sliderData['#ITEM_URL#'] = item.itemUrl;
77 | sliderData['#ITEM_PRICE#'] = item.itemPrice;
78 |
79 | $sliderItem = $liItem.clone();
80 | $sliderItem.html(jscf.commonUtils.replacePlaceholders($sliderItem.html(), sliderData));
81 | $sliderTpl.append($sliderItem);
82 |
83 | // set css
84 | $sliderItem.find(css.itemImage).css({ width: options.widget.image_width + 'px', height: options.widget.image_height + 'px' });
85 | }
86 |
87 | initializeSlideshow($sliderTpl);
88 | }
89 |
90 | /**
91 | * Execution starts after validating settings and if this widget is enabled.
92 | * @name run
93 | */
94 | function run() {
95 | var apiOptions = {
96 | apiUril: '',
97 | data : {
98 | something: '',
99 | },
100 | };
101 | // call api to get items
102 | jscf.apiUtils.callApi($.extend({}, apiOptions, options.mock))
103 | .done(prepareSlider);
104 | }
105 |
106 | /**
107 | * Initialize things and then run if this widget is enabled.
108 | */
109 | function init() {
110 | var $widget = $elems.widget;
111 | var css = settings.css;
112 |
113 | $.extend($elems, {
114 | widgetSettings: $widget.find(css.widgetSettings),
115 | mockElem : $widget.find(css.widgetSettingsMock, css.widgetSettings),
116 | });
117 |
118 | options = (function readSettings() {
119 | return {
120 | widget: jscf.commonUtils.readSettingsFromElem(settings.widget, $elems.widgetSettings),
121 | mock : jscf.apiUtils.readApiSettings($elems.mockElem),
122 | };
123 | }());
124 |
125 | if (!options || !(options.widget && options.widget.enabled)) {
126 | return;
127 | }
128 |
129 | run();
130 | }
131 |
132 | // start execution by initing
133 | init();
134 | }; // /homeAppliancesWidget
135 | }); // define
136 | } // /if
137 |
--------------------------------------------------------------------------------
/frontend/app/js/toppage/modules/widgets/newArrivalsWidget.js:
--------------------------------------------------------------------------------
1 | if (typeof define === 'function' && define.amd) {
2 | define(['jquery', 'jscf', 'lightslider'], function newArrivalsWidgetModule($, jscf) {
3 | 'use strict';
4 |
5 | return function newArrivalsWidget() {
6 | var settings = {
7 | css: {
8 | sliderTpl : '#newArrivalsSliderTpl',
9 | widget : '#newArrivalsSlider',
10 | sliderItem : '.item',
11 | widgetSettings : '.widget-settings',
12 | widgetSettingsMock: '.widget-settings-mock',
13 | itemImage : '.item-image',
14 | },
15 |
16 | widget: {
17 | enabled : [true, 'bool'],
18 | image_width : [110, 'int'],
19 | image_height: [110, 'int'],
20 | },
21 | };
22 |
23 | var $elems = {
24 | widget : $(settings.css.widget),
25 | sliderTplHtml: $(settings.css.sliderTpl).remove().html(),
26 | };
27 |
28 | var options;
29 |
30 | /**
31 | * Initialize slider element using lightSlider plugin.
32 | * Set necessary options for slider
33 | */
34 | function initializeSlideshow($contentSlider) {
35 | var sliderOptions = {
36 | loop : true,
37 | keyPress : true,
38 | enableDrag: false,
39 | autoWidth : true,
40 | prevHtml : '
',
41 | nextHtml : '
',
42 | };
43 |
44 | if (jscf.browser.isSp) {
45 | sliderOptions.controls = false;
46 | sliderOptions.enableDrag = true;
47 | }
48 | $elems.widget.append($contentSlider);
49 |
50 | $contentSlider.lightSlider(sliderOptions);
51 |
52 | $elems.widget.show();
53 | }
54 |
55 | /**
56 | * Prepare for rendering slideshow after calling api
57 | * @name prepareSlider
58 | *
59 | * @param {Object} data Data retrieved from api
60 | */
61 | function prepareSlider(data) {
62 | var $sliderTpl = $($elems.sliderTplHtml);
63 | var css = settings.css;
64 | var $liItem = $sliderTpl.find(css.sliderItem).remove();
65 | var items = data.items;
66 | var n = items.length;
67 | var sliderData = {};
68 | var i;
69 | var $sliderItem;
70 | var item;
71 |
72 | for (i = 0; i < n; i++) {
73 | item = items[i];
74 | sliderData['#ITEM_NAME#'] = item.itemName;
75 | sliderData['#ITEM_IMAGE_URL#'] = item.itemImageUrl;
76 | sliderData['#ITEM_URL#'] = item.itemUrl;
77 | sliderData['#ITEM_PRICE#'] = item.itemPrice;
78 | sliderData['#ITEM_CATEGORY#'] = item.categoryName;
79 |
80 | $sliderItem = $liItem.clone();
81 | $sliderItem.html(jscf.commonUtils.replacePlaceholders($sliderItem.html(), sliderData));
82 | $sliderTpl.append($sliderItem);
83 |
84 | // set css
85 | $sliderItem.find(css.itemImage).css({ width: options.widget.image_width + 'px', height: options.widget.image_height + 'px' });
86 | }
87 |
88 | initializeSlideshow($sliderTpl);
89 | }
90 |
91 | /**
92 | * Execution starts after validating settings and if this widget is enabled.
93 | * @name run
94 | */
95 | function run() {
96 | var apiOptions = {
97 | apiUril: '',
98 | data : {
99 | something: '',
100 | },
101 | };
102 | // call api to get items
103 | jscf.apiUtils.callApi($.extend({}, apiOptions, options.mock))
104 | .done(prepareSlider);
105 | }
106 |
107 | /**
108 | * Initialize things and then run if this widget is enabled.
109 | */
110 | function init() {
111 | var $widget = $elems.widget;
112 | var css = settings.css;
113 |
114 | $.extend($elems, {
115 | widgetSettings: $widget.find(css.widgetSettings),
116 | mockElem : $widget.find(css.widgetSettingsMock, css.widgetSettings),
117 | });
118 |
119 | options = (function readSettings() {
120 | return {
121 | widget: jscf.commonUtils.readSettingsFromElem(settings.widget, $elems.widgetSettings),
122 | mock : jscf.apiUtils.readApiSettings($elems.mockElem),
123 | };
124 | }());
125 |
126 | if (!options || !(options.widget && options.widget.enabled)) {
127 | return;
128 | }
129 |
130 | run();
131 | }
132 |
133 | // start execution by initing
134 | init();
135 | }; // /newArrivalsWidget
136 | }); // define
137 | } // /if
138 |
--------------------------------------------------------------------------------
/frontend/app/jslib/utils/common.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Provides some common utility methods
3 | */
4 | if (typeof define === 'function' && define.amd) {
5 | define(['jquery'], function commons($) {
6 | 'use strict';
7 |
8 | var commonUtils = {};
9 | var htmlEntityMap = {
10 | '&': '&',
11 | '<': '<',
12 | '>': '>',
13 | '"': '"',
14 | "'": ''',
15 | '/': '/',
16 | };
17 |
18 | commonUtils.prototype = {};
19 |
20 | function escapeHtml(str) {
21 | return String(str).replace(/&<>"'\//g, function replaceCallback(s) {
22 | return htmlEntityMap[s];
23 | });
24 | }
25 |
26 | function normalizeAttr(attrName) {
27 | var normalizedAttr;
28 |
29 | if (attrName) {
30 | attrName = attrName.replace(/^data-/, '');
31 | normalizedAttr = (function findDash(attr) {
32 | var index;
33 | index = attr.indexOf('-');
34 | if (index > 0) {
35 | attr = findDash(attr.substring(0, index) + attr.charAt(index + 1).toUpperCase() + attr.substring(index + 2));
36 | }
37 | return attr;
38 | }(attrName));
39 | }
40 |
41 | return normalizedAttr;
42 | }
43 |
44 | /**
45 | * This utility method can be used to replace placeholders with given data
46 | * @name commonUtils.replacePlaceholders
47 | *
48 | * @param {String} txt text containing placeholders
49 | * @param {Object} data object containing data to replace with each placeholder
50 | * @param {bool} escapeDataHtml whether to escape html or not
51 | *
52 | * @return {String} replaced placeholder string
53 | */
54 | commonUtils.replacePlaceholders = function replacePlaceholders(txt, data, escapeDataHtml) {
55 | var i;
56 | var d;
57 |
58 | for (i in data) {
59 | d = escapeDataHtml === false ? data[i] : escapeHtml(data[i]);
60 | txt = txt.replace(new RegExp(i, 'g'), d);
61 | }
62 |
63 | return txt;
64 | };
65 |
66 | /**
67 | * This function will read settings from given html element and return all attrs with respective values as plain object
68 | *
69 | * @name readSettingsFromElem
70 | *
71 | * @param {Object} settings Object of needed settings with value and type
72 | * @param {String|Object} elem Name of element with it's id/class prefix or jquery elemet itself
73 | *
74 | * @return {Object} attr:value pairs as of settings param
75 | */
76 | commonUtils.readSettingsFromElem = function readSettingsFromElem(settings, elem) {
77 | var $elem = typeof elem === 'string' ? $(elem) : elem;
78 | var nAttrs = {};
79 | var retAttrs = {};
80 |
81 | function validateAttr(attr, attrVal) {
82 | var val = nAttrs[attr];
83 | var type = attrVal[1];
84 |
85 | if (val) {
86 | try {
87 | switch (type) {
88 | case 'bool':
89 | if (!(val === 'true' || val === 'yes' || val === '1' || val === '0' || val === 'false')) {
90 | throw 'invalid bool value for attr: ' + attr;
91 | }
92 | val = val === 'true' || val === 'yes' || val === '1';
93 | break;
94 | case 'int':
95 | val = parseInt(val, 10);
96 | break;
97 | case 'float':
98 | val = parseFloat(val);
99 | break;
100 | default:
101 | val = String(val);
102 | }
103 | } catch (e) {
104 | if (attrVal[0] !== undefined) {
105 | val = attrVal[0];
106 | } else {
107 | throw e;
108 | }
109 | }
110 | } else {
111 | val = attrVal[0];
112 | }
113 |
114 | return val;
115 | }
116 |
117 | if ($elem.length) {
118 | $.each($elem[0].attributes, function eachAttrs() {
119 | if (this.specified) {
120 | nAttrs[normalizeAttr(this.name)] = this.value;
121 | }
122 | });
123 | $.each(settings, function eachSettings(key, val) {
124 | retAttrs[key] = validateAttr(key, val);
125 | });
126 | }
127 |
128 | return retAttrs;
129 | };
130 |
131 | /**
132 | * Works as ES6 spread operator
133 | */
134 | commonUtils.spread = function spread(obj) {
135 | var len;
136 | var key;
137 | var k;
138 |
139 | if (!obj.length) {
140 | return obj;
141 | }
142 |
143 | len = obj.length;
144 | key = Array(len);
145 | k = 0;
146 |
147 | for (; k < len; k++) {
148 | key[k] = obj[k];
149 | }
150 | return key;
151 | };
152 |
153 | return commonUtils;
154 | });
155 | }
156 |
--------------------------------------------------------------------------------
/frontend/app/js/toppage/modules/widgets/laptopsAndDesktopsWidget.js:
--------------------------------------------------------------------------------
1 | if (typeof define === 'function' && define.amd) {
2 | define(['jquery', 'jscf', 'lightslider'], function laptopsAndDesktopsWidgetModule($, jscf) {
3 | 'use strict';
4 |
5 | return function laptopsAndDesktopsWidget(block) {
6 | var settings = {
7 | css: {
8 | sliderTpl : '#laptopsAndDesktopsSliderTpl',
9 | widget : '#laptopsAndDesktopsSlider',
10 | sliderItem : '.item',
11 | widgetSettings : '.widget-settings',
12 | widgetSettingsMock: '.widget-settings-mock',
13 | itemImage : '.item-image',
14 | },
15 |
16 | widget: {
17 | enabled : [true, 'bool'],
18 | image_width : [110, 'int'],
19 | image_height: [110, 'int'],
20 | },
21 | };
22 |
23 | var $elems = {
24 | widget : $(settings.css.widget),
25 | sliderTplHtml: $(settings.css.sliderTpl).remove().html(),
26 | };
27 |
28 | var options;
29 |
30 | /**
31 | * Initialize slider element using lightSlider plugin.
32 | * Set necessary options for slider
33 | */
34 | function initializeSlideshow($contentSlider) {
35 | var sliderOptions = {
36 | loop : true,
37 | keyPress : true,
38 | enableDrag: false,
39 | autoWidth : true,
40 | prevHtml : '
',
41 | nextHtml : '
',
42 | };
43 |
44 | if (jscf.browser.isSp) {
45 | sliderOptions.controls = false;
46 | sliderOptions.enableDrag = true;
47 | }
48 | $elems.widget.append($contentSlider);
49 |
50 | $contentSlider.lightSlider(sliderOptions);
51 |
52 | $elems.widget.show();
53 | }
54 |
55 | /**
56 | * Prepare for rendering slideshow after calling api
57 | * @name prepareSlider
58 | *
59 | * @param {Object} data Data retrieved from api
60 | */
61 | function prepareSlider(data) {
62 | var $sliderTpl = $($elems.sliderTplHtml);
63 | var css = settings.css;
64 | var $liItem = $sliderTpl.find(css.sliderItem).remove();
65 | var items = data.items;
66 | var n = items.length;
67 | var sliderData = {};
68 | var i;
69 | var $sliderItem;
70 | var item;
71 |
72 | for (i = 0; i < n; i++) {
73 | item = items[i];
74 | sliderData['#ITEM_ID#'] = item.itemId;
75 | sliderData['#ITEM_NAME#'] = item.itemName;
76 | sliderData['#ITEM_IMAGE_URL#'] = item.itemImageUrl;
77 | sliderData['#ITEM_URL#'] = item.itemUrl;
78 | sliderData['#ITEM_PRICE#'] = item.itemPrice;
79 |
80 | $sliderItem = $liItem.clone();
81 | $sliderItem.html(jscf.commonUtils.replacePlaceholders($sliderItem.html(), sliderData));
82 | $sliderTpl.append($sliderItem);
83 |
84 | // set css
85 | $sliderItem.find(css.itemImage).css({ width: options.widget.image_width + 'px', height: options.widget.image_height + 'px' });
86 | }
87 |
88 | initializeSlideshow($sliderTpl);
89 | }
90 |
91 | /**
92 | * Execution starts after validating settings and if this widget is enabled.
93 | * @name run
94 | */
95 | function run() {
96 | var apiOptions = {
97 | apiUril: '',
98 | data : {
99 | something: '',
100 | },
101 | };
102 | // call api to get items
103 | jscf.apiUtils.callApi($.extend({}, apiOptions, options.mock))
104 | .done(prepareSlider);
105 | }
106 |
107 | /**
108 | * Initialize things and then run if this widget is enabled.
109 | */
110 | function init() {
111 | var $widget = $elems.widget;
112 | var css = settings.css;
113 |
114 | $.extend($elems, {
115 | widgetSettings: $widget.find(css.widgetSettings),
116 | mockElem : $widget.find(css.widgetSettingsMock, css.widgetSettings),
117 | });
118 |
119 | options = (function readSettings() {
120 | return {
121 | widget: jscf.commonUtils.readSettingsFromElem(settings.widget, $elems.widgetSettings),
122 | mock : jscf.apiUtils.readApiSettings($elems.mockElem),
123 | };
124 | }());
125 |
126 | if (!options || !(options.widget && options.widget.enabled)) {
127 | return;
128 | }
129 |
130 | run();
131 | }
132 |
133 | // start execution by initing
134 | init();
135 | }; // /laptopsAndDesktopsWidget()
136 | }); // /define ()
137 | } // /if
138 |
--------------------------------------------------------------------------------
/frontend/app/assets/styles/toppage/homepage.css:
--------------------------------------------------------------------------------
1 | /*
*/
2 | .main-header {
3 | background-color: #337ab7;
4 | padding-top: 10px;
5 | }
6 | .main-header .logo {
7 | background: url(../../img/logo.jpg) no-repeat;
8 | background-size: contain;
9 | width: 100%;
10 | height: 38px;
11 | }
12 | .main-header .navbar {
13 | min-height: 0px;
14 | margin-bottom: 0px;
15 | }
16 | .main-header .main-header-searchbar .search-text {
17 | width: 100%;
18 | }
19 | .main-header .navbar-top-links .cart-icon.btn-lg .cart-items-number {
20 | display: none;
21 | width: 22px;
22 | height: 21px;
23 | font-size: 15px;
24 | }
25 | @media (max-width: 1030px) {
26 | .main-header .navbar-right {
27 | margin-right: -5px;
28 | }
29 | .main-header .navbar-top-links {
30 | padding-left: 0px;
31 | padding-right: 0px;
32 | }
33 | }
34 | @media only screen and (min-device-width: 768px) and (max-device-width: 992px) {
35 | .main-header .navbar-right {
36 | margin-right: -12px;
37 | }
38 | .main-header .navbar-top-links {
39 | margin-left: -11px;
40 | }
41 | }
42 | @media only screen and (min-device-width: 972px) and (max-device-width: 1024px) {
43 | .main-header .navbar-top-links {
44 | padding-left: 0px;
45 | padding-right: 20px;
46 | }
47 | }
48 | @media (max-width: 375px) {
49 | .main-header .main-header-searchbar {
50 | padding-left: 0px;
51 | padding-right: 0px;
52 | }
53 | .main-header .navbar-top-links {
54 | padding-left: 0px;
55 | padding-right: 0px;
56 | }
57 | .main-header .navbar-top-links .navbar-right {
58 | margin-right: -6px;
59 | }
60 | .main-header .navbar-top-links .navbar-right .dropdown {
61 | margin-left: -3px;
62 | }
63 | }
64 | .main-header .navbar-top-links .navbar-right li {
65 | display: inline-block;
66 | }
67 | .main-header .xs-user-dropdown {
68 | float: right;
69 | }
70 | .main-header .xs-header .icons-right {
71 | float: right;
72 | }
73 | .main-header .xs-header .icons-right .cart-icon {
74 | margin-right: 5px;
75 | position: relative;
76 | }
77 | .main-header .cart-items-number {
78 | display: none;
79 | width: 23px;
80 | height: 20px;
81 | background: #d32f2f;
82 | border-radius: 50%;
83 | -moz-border-radius: 50%;
84 | -webkit-border-radius: 50%;
85 | color: #fff;
86 | top: 2px;
87 | position: absolute;
88 | right: 2px;
89 | font-size: 14px;
90 | font-weight: 900;
91 | border: 1px solid #fff;
92 | }
93 | .main-header .xs-searchbar .xs-searchbar-form {
94 | margin-bottom: 10px;
95 | margin-top: 5px;
96 | }
97 | .main-header .xs-searchbar .xs-searchbar-form #searchBtn {
98 | margin-top: -1px;
99 | padding-bottom: 8px;
100 | }
101 | .main-header .xs-searchbar .xs-searchbar-form #searchBtn .glyphicon {
102 | top: 3px;
103 | }
104 | /* header styles> */
105 | /* */
106 | .main-header-menubar .navbar-nav > li > a {
107 | color: white;
108 | }
109 | .main-header-menubar .navbar-nav li a:hover,
110 | .main-header-menubar .navbar-nav li a:focus {
111 | background-color: transparent;
112 | color: yellow;
113 | }
114 | .main-header-menubar .nav .open > a {
115 | background-color: transparent;
116 | }
117 | .main-header-menubar .nav .open > a:focus,
118 | .main-header-menubar .nav .open > a:hover {
119 | background-color: transparent;
120 | }
121 | .main-header-menubar .nav,
122 | .main-header-menubar .collapse,
123 | .main-header-menubar .dropup,
124 | .main-header-menubar .dropdown {
125 | position: static;
126 | }
127 | .main-header-menubar .container {
128 | position: relative;
129 | }
130 | .main-header-menubar .dropdown-menu {
131 | left: auto;
132 | }
133 | .main-header-menubar .dropdown-menu li a {
134 | color: black;
135 | text-decoration: none;
136 | }
137 | .main-header-menubar .dropdown-menu li a:hover {
138 | color: blue;
139 | }
140 | .main-header-menubar .navbar-nav .dropdown .dropdown-menu.top-category {
141 | left: 0;
142 | right: 0;
143 | }
144 | .main-header-menubar .navbar-nav .dropdown li {
145 | list-style: none;
146 | }
147 | .main-header-menubar .navbar-nav .dropdown li .category-head .caret {
148 | transform: rotate(270deg);
149 | }
150 | /* categories styles> */
151 | /* */
152 | .main-header .usermenu-dropdown ul {
153 | padding-left: 5px;
154 | }
155 | .main-header .usermenu-dropdown li {
156 | width: 100%;
157 | list-style: none;
158 | }
159 | .main-header .usermenu-dropdown li a {
160 | text-decoration: none;
161 | font-size: 16px;
162 | padding-top: 3px;
163 | padding-bottom: 3px;
164 | color: black;
165 | }
166 | .main-header .usermenu-dropdown li a:hover {
167 | color: blue;
168 | }
169 | .main-header .usermenu-dropdown .sign-in {
170 | padding-left: 5px;
171 | }
172 | .main-header .usermenu-dropdown .sign-in button {
173 | width: 95%;
174 | }
175 | /* */
176 | /*