From 99fba14dd02bf34aa0e61637d0448fb08e9caea8 Mon Sep 17 00:00:00 2001 From: q2012 Date: Thu, 26 May 2016 11:59:29 +0300 Subject: [PATCH 1/3] Add files via upload --- Frontend/www/assets/js/main.js | 407 ++++++++++++++- Frontend/www/assets/less/main.less | 264 +++++++++- .../www/assets/less/pizza/pizza-card.less | 13 + Frontend/www/index.html | 493 +++++++++++++++++- 4 files changed, 1139 insertions(+), 38 deletions(-) diff --git a/Frontend/www/assets/js/main.js b/Frontend/www/assets/js/main.js index da110673c..83d6aebe0 100644 --- a/Frontend/www/assets/js/main.js +++ b/Frontend/www/assets/js/main.js @@ -188,7 +188,7 @@ exports.PizzaMenu_OneItem = ejs.compile("<%\n\nfunction getIngredientsArray(pizz exports.PizzaCart_OneItem = ejs.compile("
\n <%= pizza.title %> (<%= size %>)\n
Ціна: <%= pizza[size].price %> грн.
\n
\n \n <%= quantity %>\n \n
\n
"); -},{"ejs":6}],3:[function(require,module,exports){ +},{"ejs":8}],3:[function(require,module,exports){ /** * Created by chaika on 25.01.16. */ @@ -209,7 +209,7 @@ $(function(){ * Created by chaika on 02.02.16. */ var Templates = require('../Templates'); - +var Storage = require('./Storage'); //Перелік розмірів піци var PizzaSize = { Big: "big_size", @@ -248,6 +248,11 @@ function initialiseCart() { //Фукнція віпрацьвуватиме при завантаженні сторінки //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його //TODO: ... +var saved_pizza = Storage.get('cart'); + if(saved_pizza){ + Cart = saved_pizza; + } + updateCart(); } @@ -284,7 +289,7 @@ function updateCart() { Cart.forEach(showOnePizzaInCart); } - +Storage.set("cart",Cart); exports.removeFromCart = removeFromCart; exports.addToCart = addToCart; @@ -292,7 +297,7 @@ exports.getPizzaInCart = getPizzaInCart; exports.initialiseCart = initialiseCart; exports.PizzaSize = PizzaSize; -},{"../Templates":2}],5:[function(require,module,exports){ +},{"../Templates":2,"./Storage":6}],5:[function(require,module,exports){ /** * Created by chaika on 02.02.16. */ @@ -349,6 +354,387 @@ function initialiseMenu() { exports.filterPizza = filterPizza; exports.initialiseMenu = initialiseMenu; },{"../Pizza_List":1,"../Templates":2,"./PizzaCart":4}],6:[function(require,module,exports){ +var basil = require('basil.js'); +basil = new basil(); +exports.get = function(key) { + return basil.get(key); +}; +exports.set = function(key, value) { + return basil.set(key, value); +};/** + * Created by Angelina on 03.02.2016. + */ + +},{"basil.js":7}],7:[function(require,module,exports){ +(function () { + // Basil + var Basil = function (options) { + return Basil.utils.extend({}, Basil.plugins, new Basil.Storage().init(options)); + }; + + // Version + Basil.version = '0.4.2'; + + // Utils + Basil.utils = { + extend: function () { + var destination = typeof arguments[0] === 'object' ? arguments[0] : {}; + for (var i = 1; i < arguments.length; i++) { + if (arguments[i] && typeof arguments[i] === 'object') + for (var property in arguments[i]) + destination[property] = arguments[i][property]; + } + return destination; + }, + each: function (obj, fnIterator, context) { + if (this.isArray(obj)) { + for (var i = 0; i < obj.length; i++) + if (fnIterator.call(context, obj[i], i) === false) return; + } else if (obj) { + for (var key in obj) + if (fnIterator.call(context, obj[key], key) === false) return; + } + }, + tryEach: function (obj, fnIterator, fnError, context) { + this.each(obj, function (value, key) { + try { + return fnIterator.call(context, value, key); + } catch (error) { + if (this.isFunction(fnError)) { + try { + fnError.call(context, value, key, error); + } catch (error) {} + } + } + }, this); + }, + registerPlugin: function (methods) { + Basil.plugins = this.extend(methods, Basil.plugins); + } + }; + // Add some isType methods: isArguments, isBoolean, isFunction, isString, isArray, isNumber, isDate, isRegExp. + var types = ['Arguments', 'Boolean', 'Function', 'String', 'Array', 'Number', 'Date', 'RegExp'] + for (var i = 0; i < types.length; i++) { + Basil.utils['is' + types[i]] = (function (type) { + return function (obj) { + return Object.prototype.toString.call(obj) === '[object ' + type + ']'; + }; + })(types[i]); + } + + // Plugins + Basil.plugins = {}; + + // Options + Basil.options = Basil.utils.extend({ + namespace: 'b45i1', + storages: ['local', 'cookie', 'session', 'memory'], + expireDays: 365 + }, window.Basil ? window.Basil.options : {}); + + // Storage + Basil.Storage = function () { + var _salt = 'b45i1' + (Math.random() + 1) + .toString(36) + .substring(7), + _storages = {}, + _toStoragesArray = function (storages) { + if (Basil.utils.isArray(storages)) + return storages; + return Basil.utils.isString(storages) ? [storages] : []; + }, + _toStoredKey = function (namespace, path) { + var key = ''; + if (Basil.utils.isString(path) && path.length) + path = [path]; + if (Basil.utils.isArray(path) && path.length) + key = path.join('.'); + return key && namespace ? namespace + '.' + key : key; + }, + _toKeyName = function (namespace, key) { + if (!namespace) + return key; + return key.replace(new RegExp('^' + namespace + '.'), ''); + }, + _toStoredValue = function (value) { + return JSON.stringify(value); + }, + _fromStoredValue = function (value) { + return value ? JSON.parse(value) : null; + }; + + // HTML5 web storage interface + var webStorageInterface = { + engine: null, + check: function () { + try { + window[this.engine].setItem(_salt, true); + window[this.engine].removeItem(_salt); + } catch (e) { + return false; + } + return true; + }, + set: function (key, value, options) { + if (!key) + throw Error('invalid key'); + window[this.engine].setItem(key, value); + }, + get: function (key) { + return window[this.engine].getItem(key); + }, + remove: function (key) { + window[this.engine].removeItem(key); + }, + reset: function (namespace) { + for (var i = 0, key; i < window[this.engine].length; i++) { + key = window[this.engine].key(i); + if (!namespace || key.indexOf(namespace) === 0) { + this.remove(key); + i--; + } + } + }, + keys: function (namespace) { + var keys = []; + for (var i = 0, key; i < window[this.engine].length; i++) { + key = window[this.engine].key(i); + if (!namespace || key.indexOf(namespace) === 0) + keys.push(_toKeyName(namespace, key)); + } + return keys; + } + }; + + // local storage + _storages.local = Basil.utils.extend({}, webStorageInterface, { + engine: 'localStorage' + }); + // session storage + _storages.session = Basil.utils.extend({}, webStorageInterface, { + engine: 'sessionStorage' + }); + + // memory storage + _storages.memory = { + _hash: {}, + check: function () { + return true; + }, + set: function (key, value, options) { + if (!key) + throw Error('invalid key'); + this._hash[key] = value; + }, + get: function (key) { + return this._hash[key] || null; + }, + remove: function (key) { + delete this._hash[key]; + }, + reset: function (namespace) { + for (var key in this._hash) { + if (!namespace || key.indexOf(namespace) === 0) + this.remove(key); + } + }, + keys: function (namespace) { + var keys = []; + for (var key in this._hash) + if (!namespace || key.indexOf(namespace) === 0) + keys.push(_toKeyName(namespace, key)); + return keys; + } + }; + + // cookie storage + _storages.cookie = { + check: function () { + return navigator.cookieEnabled; + }, + set: function (key, value, options) { + if (!this.check()) + throw Error('cookies are disabled'); + options = options || {}; + if (!key) + throw Error('invalid key'); + var cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value); + // handle expiration days + if (options.expireDays) { + var date = new Date(); + date.setTime(date.getTime() + (options.expireDays * 24 * 60 * 60 * 1000)); + cookie += '; expires=' + date.toGMTString(); + } + // handle domain + if (options.domain && options.domain !== document.domain) { + var _domain = options.domain.replace(/^\./, ''); + if (document.domain.indexOf(_domain) === -1 || _domain.split('.').length <= 1) + throw Error('invalid domain'); + cookie += '; domain=' + options.domain; + } + // handle secure + if (options.secure === true) { + cookie += '; secure'; + } + document.cookie = cookie + '; path=/'; + }, + get: function (key) { + if (!this.check()) + throw Error('cookies are disabled'); + var encodedKey = encodeURIComponent(key); + var cookies = document.cookie ? document.cookie.split(';') : []; + // retrieve last updated cookie first + for (var i = cookies.length - 1, cookie; i >= 0; i--) { + cookie = cookies[i].replace(/^\s*/, ''); + if (cookie.indexOf(encodedKey + '=') === 0) + return decodeURIComponent(cookie.substring(encodedKey.length + 1, cookie.length)); + } + return null; + }, + remove: function (key) { + // remove cookie from main domain + this.set(key, '', { expireDays: -1 }); + // remove cookie from upper domains + var domainParts = document.domain.split('.'); + for (var i = domainParts.length; i >= 0; i--) { + this.set(key, '', { expireDays: -1, domain: '.' + domainParts.slice(- i).join('.') }); + } + }, + reset: function (namespace) { + var cookies = document.cookie ? document.cookie.split(';') : []; + for (var i = 0, cookie, key; i < cookies.length; i++) { + cookie = cookies[i].replace(/^\s*/, ''); + key = cookie.substr(0, cookie.indexOf('=')); + if (!namespace || key.indexOf(namespace) === 0) + this.remove(key); + } + }, + keys: function (namespace) { + if (!this.check()) + throw Error('cookies are disabled'); + var keys = [], + cookies = document.cookie ? document.cookie.split(';') : []; + for (var i = 0, cookie, key; i < cookies.length; i++) { + cookie = cookies[i].replace(/^\s*/, ''); + key = decodeURIComponent(cookie.substr(0, cookie.indexOf('='))); + if (!namespace || key.indexOf(namespace) === 0) + keys.push(_toKeyName(namespace, key)); + } + return keys; + } + }; + + return { + init: function (options) { + this.setOptions(options); + return this; + }, + setOptions: function (options) { + this.options = Basil.utils.extend({}, this.options || Basil.options, options); + }, + support: function (storage) { + return _storages.hasOwnProperty(storage); + }, + check: function (storage) { + if (this.support(storage)) + return _storages[storage].check(); + return false; + }, + set: function (key, value, options) { + options = Basil.utils.extend({}, this.options, options); + if (!(key = _toStoredKey(options.namespace, key))) + return false; + value = options.raw === true ? value : _toStoredValue(value); + var where = null; + // try to set key/value in first available storage + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { + _storages[storage].set(key, value, options); + where = storage; + return false; // break; + }, null, this); + if (!where) { + // key has not been set anywhere + return false; + } + // remove key from all other storages + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { + if (storage !== where) + _storages[storage].remove(key); + }, null, this); + return true; + }, + get: function (key, options) { + options = Basil.utils.extend({}, this.options, options); + if (!(key = _toStoredKey(options.namespace, key))) + return null; + var value = null; + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { + if (value !== null) + return false; // break if a value has already been found. + value = _storages[storage].get(key, options) || null; + value = options.raw === true ? value : _fromStoredValue(value); + }, function (storage, index, error) { + value = null; + }, this); + return value; + }, + remove: function (key, options) { + options = Basil.utils.extend({}, this.options, options); + if (!(key = _toStoredKey(options.namespace, key))) + return; + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { + _storages[storage].remove(key); + }, null, this); + }, + reset: function (options) { + options = Basil.utils.extend({}, this.options, options); + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { + _storages[storage].reset(options.namespace); + }, null, this); + }, + keys: function (options) { + options = options || {}; + var keys = []; + for (var key in this.keysMap(options)) + keys.push(key); + return keys; + }, + keysMap: function (options) { + options = Basil.utils.extend({}, this.options, options); + var map = {}; + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { + Basil.utils.each(_storages[storage].keys(options.namespace), function (key) { + map[key] = Basil.utils.isArray(map[key]) ? map[key] : []; + map[key].push(storage); + }, this); + }, null, this); + return map; + } + }; + }; + + // Access to native storages, without namespace or basil value decoration + Basil.memory = new Basil.Storage().init({ storages: 'memory', namespace: null, raw: true }); + Basil.cookie = new Basil.Storage().init({ storages: 'cookie', namespace: null, raw: true }); + Basil.localStorage = new Basil.Storage().init({ storages: 'local', namespace: null, raw: true }); + Basil.sessionStorage = new Basil.Storage().init({ storages: 'session', namespace: null, raw: true }); + + // browser export + window.Basil = Basil; + + // AMD export + if (typeof define === 'function' && define.amd) { + define(function() { + return Basil; + }); + // commonjs export + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Basil; + } + +})(); + +},{}],8:[function(require,module,exports){ /* * EJS Embedded JavaScript templates * Copyright 2112 Matthew Eernisse (mde@fleegix.org) @@ -1099,7 +1485,7 @@ if (typeof window != 'undefined') { window.ejs = exports; } -},{"../package.json":8,"./utils":7,"fs":9,"path":10}],7:[function(require,module,exports){ +},{"../package.json":10,"./utils":9,"fs":11,"path":12}],9:[function(require,module,exports){ /* * EJS Embedded JavaScript templates * Copyright 2112 Matthew Eernisse (mde@fleegix.org) @@ -1242,7 +1628,7 @@ exports.cache = { }; -},{}],8:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ module.exports={ "name": "ejs", "description": "Embedded JavaScript templates", @@ -1318,13 +1704,12 @@ module.exports={ "shasum": "82e15b1b2a1f948b18097476ba2bd7c66f4d1566", "tarball": "http://registry.npmjs.org/ejs/-/ejs-2.4.1.tgz" }, - "directories": {}, - "readme": "ERROR: No README data found!" + "directories": {} } -},{}],9:[function(require,module,exports){ +},{}],11:[function(require,module,exports){ -},{}],10:[function(require,module,exports){ +},{}],12:[function(require,module,exports){ (function (process){ // Copyright Joyent, Inc. and other Node contributors. // @@ -1552,7 +1937,7 @@ var substr = 'ab'.substr(-1) === 'b' ; }).call(this,require('_process')) -},{"_process":11}],11:[function(require,module,exports){ +},{"_process":13}],13:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; diff --git a/Frontend/www/assets/less/main.less b/Frontend/www/assets/less/main.less index e49b0b5fa..f8e21fa4d 100644 --- a/Frontend/www/assets/less/main.less +++ b/Frontend/www/assets/less/main.less @@ -1,3 +1,263 @@ -@mainColor: blue; +@mainColor: rgba(232, 151, 51, 0.99); +@footerColor: #f98b17; +@fontSize: 20px; +@import "pizza/pizza-card"; -@import "pizza/pizza-card"; \ No newline at end of file +.row{ +margin: auto; +} + +.main-header-top { + width: 100%; + font-size: @fontSize; + line-height: 11px; + color: white; + opacity: 50%; + margin: 11px 0 14px 0; + border-bottom : 1px solid white; + +}.main-header { + font-size: 0; + position: fixed; + top: 0; + left: 0; + width: 100%; + background: black; + opacity:0.8; + padding: 0 25% 0 130px; + z-index: 10; + } +.main-header-top, .header-box, .main-header-top-item { + display: inline-block; +} +.fs14 { + font-size: @fontSize; + line-height: 20px; + margin-right: 30px; + color:grey; +} + +.fs15 { + font-size: @fontSize; + line-height: 20px; + margin-right: 30px; + color:white; +} +.main, nav{ + display: block; +} +.main-nav-item { + display: inline-block; + vertical-align: top; + font-size: @fontSize; + line-height: 17px; + margin-right: 15px; + padding-bottom: 7px; + color: #fff; +} +.site-icon { + position: fixed; + left: 9px; + top: 0px; + background: orange; + border-left: 1px solid #d16200; + border-right: 1px solid #d16200; + z-index: 99; + width: 100px; + height: 87px; + font-size: @fontSize*1.5; + padding: 10px; + padding-top:15px; + text-transform: uppercase; + text-align: center; + color: #fff; +} +.title-1{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration: none; +} +.pizza-logo{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration:none; +} +.sign-in-button { + float: right; + margin-top: -11px; + } +.left-panel { + +margin-right: 500px; + padding-left: 30px; + padding-right: 360px; + max-width: 1354px; +} +.right-panel { + position: fixed!important; + top: 0; + right: 0; + bottom: 0; + padding-top: 35px; + margin-left: 20px; + padding-right: 0!important; + padding-left: 0!important; + box-orient: vertical; + flex-direction: column; + min-width: 330px; + width: 330px; + height: 100%; + background: #fff; + box-shadow: rgba(0,0,0,.2) -3px 3px 10px; + z-index: 1000; +} +.r1, .r2{ + width: 100%; + box-sizing: content-box; + display: block!important; +} + +.r2{ + background-color: gainsboro; +} +.r1{ + margin-bottom: 10%; +} + +.order-state{ + margin:10%; + margin-top:5%; +} + +.sum-title{ + margin-left:-5%; + font-weight: 400; +} +.sum-number{ + margin-left:30%; + font-size: 20px; + font-weight:400; +} + +.button-order{ + margin-top: 10%; +} + +.right-panel .order-list-title { + font-size: @fontSize; + font-weight: 700; + line-height: 17px; + margin-left: 20px; +} +.right-panel .clear-order-wrap { + padding-right: 15px; + padding-left: 20px; + font-size: 10px; + line-height: 11px; + font-weight: 400; + color: gray; +} +.mainTitle { + margin: 10px; + margin-top: 100px; +} +.pizzaType { + color: @mainColor; + background-color: white; + border: none; + margin-bottom: 20px; +} + +.pizzaType:hover{ + background-color: @mainColor; + color:white; +} + +.pizzaType-active { + color:white; + background-color: @mainColor; +} + +.allPizzas { + font-size: 28px; + display: inline-block; + margin: auto; +} +.allPizzasNumber { + font-size: @fontSize; + color: white; + background-color: @mainColor; + border-radius: 20px; + margin: 5px; + padding-left: 10px; + padding-right: 10px; +} +.discount { + position: fixed; + bottom: 0px; + left: 10px; +} +.buy{ + margin-left: 60px; +} +.order-one { + height: 120px; + padding: 20px 61px 10px 24px; + border-bottom: 1px solid rgba(0,0,0,.1); + position: relative; + overflow: hidden; +} +.order-one .order-title { + line-height: 16px; + font-size: 20px; + color: #ec890e; +} +.img-aside { + position: absolute; + right: -50px; + top: 15px; + border-radius: 50% 0 0 50%; + max-height: 96px; + max-width: 96px; +} +img { + vertical-align: middle; +} +.btn-circle { + width: 30px; + height: 30px; + padding: 6px 0; + font-size: 12px; + border-radius: 15px; +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: 400; + line-height: 1; +} + +.pull-right{ + position: absolute; + font-size: 16px; + margin-right: -15px; + margin-top:-15px; + margin-left:65%; +} +.title-1{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration: none; +} +.pizza-logo{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration:none; +} \ No newline at end of file diff --git a/Frontend/www/assets/less/pizza/pizza-card.less b/Frontend/www/assets/less/pizza/pizza-card.less index a0448e2df..d4766279e 100644 --- a/Frontend/www/assets/less/pizza/pizza-card.less +++ b/Frontend/www/assets/less/pizza/pizza-card.less @@ -7,4 +7,17 @@ color: @mainColor; background-color: lighten(@mainColor, 45%); } + .remark { + color: #bdc4ca; + font-size: 14px; + } + .buy { + margin-left: 60px; + } + + .description { + font-size: @fontSize; + height: 65px; + overflow: hidden; + } } \ No newline at end of file diff --git a/Frontend/www/index.html b/Frontend/www/index.html index 41873db7d..ad62d0477 100644 --- a/Frontend/www/index.html +++ b/Frontend/www/index.html @@ -13,59 +13,502 @@ + - -
+ + +
+
+ + +
+
+

(044)222 3 222

+
+
+
+ 24 години / 7 днів на тиждень +
+
+
+
+
+

Безкоштовна доставка піци

+
+
+ +
+ + +
+ +
+
Усі піци
+ 9 +
+
+ + + + + + +
+ +
-
+
+ -

Thumbnail label

+

Міксовий поло

+

М'ясна

+ +

Куриця копчена, сир моцарелла, ананаси, кукурудза, петрушка, соус томатний

+
+
+ + 30 +
+
+ + 500 +
+

130

грн.
+ +
+
+
+ + 50
+
+ + 850
+

220

грн.
+ +
+
+
+
+ +
+
+ Популярна + -

Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

+

BBQ

+

З грибами

-

- Button 2 - Button 1 -

+

Мисливські ковбаски, ковбаски папероні, сир домашній, печериці, петрушка, оливки

+
+
+ + 30 +
+
+ + 500 +
+

170

грн.
+ +
+
+
+ + 50
+
+ + 850
+

240

грн.
+
+
- + -

Thumbnail label

+

Маргарита

+

Вега

-

Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

+

Базилік, орегано, помідор, соус томатний, сир моцарелла

+
+
+ + 30 +
+
+ + 500 +
+

120

грн.
+ +
+
+
+ + 50
+
+ + 850
+

210

грн.
+ +
+
+
+
+
+
+ Нова + -

- Button 3 - Button 4 -

+

Россо Густо

+

З морепродуктами

+

Ікра червона, лосось копчений, сир моцарелла, оливкова олія, вершки

+
+
+ + 30 +
+
+ + 500 +
+

180

грн.
+ +
+
+
+ + 50
+
+ + 850
+

270

грн.
+ +
+
+
+ + + +

Бамбіно

+

З грибами

+

Базилік, шинка, печериці, ковбаса салямі, перець болгарський, соус томатний, сир моцарелла

+
+
+ + 30 +
+
+ + 500 +
+

140

грн.
+ +
+
+
+ + 50
+
+ + 850
+

210

грн.
+ +
+
+
+
- + -

Thumbnail label

+

Вернісаж

+

З грибами

-

Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

+

Печериці, ковбаски мисливські, куряча грудинка, цибуля, петрушка, соус, сир моцарелла, огірки

+
+
+ + 30 +
+
+ + 500 +
+

140

грн.
+ +
+
+
+ + 50
+
+ + 850
+

230

грн.
+ +
+
+
+
+
+ +
+ + +

Імпреза

+

М'ясна

-

- Button 5 - Button 6 -

+

Балик, салямі, куриця, сир моцарелла, сир рокфорд, ананаси, томатна паста, петрушка

+
+
+ + 30 +
+
+ + 500 +
+

130

грн.
+ +
+
+
+ + 130
+
+ + 850
+

230

грн.
+ +
+ +
+
+ + +

Дольче Маре

+

З морепродуктами

+ +

Ікра червона, креветки тигрові, морський коктейль, сир моцарелла, вершки

+
+
+ + 30 +
+
+ + 500 +
+

180

грн.
+ +
+
+
+ + 50
+
+ + 850
+

270

грн.
+ +
+
+
+
+ +
+
+ + +

Капрічіоза

+

М'ясна

+ +

Шинка, ковбаса салямі, куряча грудинка, петрушка, сир моцарелла, вершки

+
+
+ + 30 +
+
+ + 500 +
+

140

грн.
+ +
+
+
+ + 50
+
+ + 850
+

220

грн.
+ +
+ + +
+
+
+ +
+ +
+
+ + Замовлення + 3 + + + + Очистити замовлення + + +
+ +
+
+ Піца +

+ BBQ (Мала) +

+
+ + 30 + + 500 +
+
+ 170грн + + + + + 1 + + + + + + + + + + +
+
+
+ Піца +

+ Міксовий поло (Велика) +

+
+ + 50 + + 850 +
+
+ 220грн + + + + + 1 + + + + + + + + + + +
+
+
+ Піца +

+ Россо Густо (Мала) +

+
+ + 30 + + 500 +
+
+ 180грн + + + + + 1 + + + + + + + + + + +
+
+ + + +
+ + Сума замовлення: + + 570 грн +
+ + + +
+ +
+
+ + +
+ +

ЦЬОГО

ТИЖНЯ

НА ВСЕ


-20%
+
@@ -75,6 +518,6 @@ - + - + \ No newline at end of file From 2278e1f1d21d82613f6d8a4780fbd998a440a42c Mon Sep 17 00:00:00 2001 From: q2012 Date: Thu, 16 Jun 2016 13:33:15 +0300 Subject: [PATCH 2/3] Add files via upload --- Frontend/www/assets/js/app.js | 1848 ++++++++++++++++++++++++++++ Frontend/www/assets/less/main.less | 50 +- Frontend/www/index.html | 458 +------ 3 files changed, 1915 insertions(+), 441 deletions(-) create mode 100644 Frontend/www/assets/js/app.js diff --git a/Frontend/www/assets/js/app.js b/Frontend/www/assets/js/app.js new file mode 100644 index 000000000..1aa8a3bbf --- /dev/null +++ b/Frontend/www/assets/js/app.js @@ -0,0 +1,1848 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\r\n
\r\n
\r\n <% if(pizza.is_new) { %>\r\n Нова\r\n <% } else if(pizza.is_popular) {%>\r\n Популярна\r\n <% } %>\r\n \" alt=\"Pizza\"> \r\n
\r\n

<%= pizza.title %>

\r\n

<%= pizza.type %>

\r\n

\r\n <%= getIngredientsArray(pizza).join(\", \") %>\r\n

\r\n
\r\n <% if (pizza.small_size){ %>\r\n
\r\n
\r\n <%= pizza.small_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.small_size.weight %>\r\n
\r\n

\r\n <%= pizza.small_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n <% if (pizza.big_size) { %>\r\n
\r\n
\r\n <%= pizza.big_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.big_size.weight %>\r\n
\r\n

\r\n <%= pizza.big_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n
\r\n
"); + +exports.PizzaCart_OneItem = ejs.compile("
\r\n\t\t\t \"Піца\"\r\n\t\t\t

\r\n\t\t\t <%= pizza.title %> (<%=size%><%if(size==pizza.small_size){%>Мала<%}else if(size==pizza.big_size){%>Велика<%} %>) \r\n\t\t\t

\r\n\t\t\t
\r\n\t\t\t \r\n\t\t\t 30\r\n\t\t\t \r\n\t\t\t 160\r\n\t\t\t
\r\n\t\t\t
\r\n\t\t\t Ціна: <%= pizza[size].price %> грн.\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t <%= quantity %>\r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t
\r\n\t\t\t
"); + +},{"ejs":6}],3:[function(require,module,exports){ +/** + * Created by chaika on 25.01.16. + */ + +$(function(){ + //This code will execute when the page is ready + var PizzaMenu = require('./pizza/PizzaMenu'); + var PizzaCart = require('./pizza/PizzaCart'); + var Pizza_List = require('./Pizza_List'); + + PizzaCart.initialiseCart(); + PizzaMenu.initialiseMenu(); + + +}); +},{"./Pizza_List":1,"./pizza/PizzaCart":4,"./pizza/PizzaMenu":5}],4:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); + +//Перелік розмірів піци +var PizzaSize = { + Big: "big_size", + Small: "small_size" +}; + +//Змінна в якій зберігаються перелік піц в кошику +var Cart = []; +var cart_map = []; +var count = 0; +//var totalPrice=0; + +//HTML едемент куди будуть додаватися піци +var $cart = $("#cartList"); + +function addToCart(pizza, size) { + + var cart_id = cart_map[pizza.id]; + + if (cart_id && (cart_id[size] || cart_id[size] === 0)){ + Cart[cart_id[size]].quantity += 1; + + } else { + if (!cart_map[pizza.id]){ + cart_map[pizza.id] = []; + } + cart_map[pizza.id][size] = + Cart.push({ + pizza: pizza, + size: size, + // price: pizza.size.price, + quantity: 1 + }) - 1; + } + + //Оновити вміст кошика на сторінці + updateCart(); +} + +function removeFromCart(cart_item) { + //Видалити піцу з кошика + //TODO: треба зробити + + if (cart_item.cart_id){ + Cart.splice(cart_item.cart_id, 1); + + } + + //Після видалення оновити відображення + updateCart(); +} + +function initialiseCart() { + //Фукнція віпрацьвуватиме при завантаженні сторінки + //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його + //TODO: ... + var cart = localStorage.getItem("cart"); + if (cart) + Cart = JSON.parse(cart); + + $("#clear").click(clearCart); + + updateCart(); +} + +function clearCart(){ + Cart = []; + cart_map = []; + + + updateCart(); + count = 0; + //totalPrice=0; + + $("#count").html(count); + // $("#sumNum").html(totalPrice); +} + +function getPizzaInCart() { + //Повертає піци які зберігаються в кошику + return Cart; +} + +function updateCart() { + //Функція викликається при зміні вмісту кошика + //Тут можна наприклад показати оновлений кошик на екрані та зберегти вміт кошика в Local Storage + + //Очищаємо старі піци в кошику + $cart.html(""); + + //Онволення однієї піци + function showOnePizzaInCart(cart_item, id, arr) { + var html_code = Templates.PizzaCart_OneItem(cart_item); + + cart_item.cart_id = id; + + var $node = $(html_code); + + $node.find(".plus").click(function(){ + //Збільшуємо кількість замовлених піц + cart_item.quantity += 1; + count +=1; + // totalPrice+=cart_item.price; + //Оновлюємо відображення + updateCart(); + }); + + $node.find(".minus").click(function(){ + + if (cart_item.quantity > 1){ + cart_item.quantity -= 1; + // totalPrice-=cart_item.price; + count -=1; + } + + //Оновлюємо відображення + updateCart(); + }); + + + $node.find(".count-clear").click(function(){ + + count -= cart_item.quantity; + // totalPrice-=(cart_item.price*cart_item.quantity); + $("#count").html(count); + // $("#sumNum").html(totalPrice); + arr.splice(id, 1); + + updateCart(); + }); + count = 0; + // totalPrice=0; + if(Cart.length != 0){ + Cart.forEach(function(pizza){ + count += pizza.quantity; + // totalPrice+=(pizza.quantity*pizza.price); + }); + } +// else{ count = 0;totalPrice=0;} + else count=0; + $("#count").html(count); + // $("#sumNum").html(totalPrice); + + $cart.append($node); + } + + Cart.forEach(showOnePizzaInCart); + + localStorage.setItem("cart", JSON.stringify(Cart)); +} + +exports.removeFromCart = removeFromCart; +exports.addToCart = addToCart; + +exports.getPizzaInCart = getPizzaInCart; +exports.initialiseCart = initialiseCart; + +exports.PizzaSize = PizzaSize; +},{"../Templates":2}],5:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); +var PizzaCart = require('./PizzaCart'); +var Pizza_List = require('../Pizza_List'); + +//HTML едемент куди будуть додаватися піци +var $pizza_list = $("#pizza_list"); + +function showPizzaList(list) { + //Очищаємо старі піци в кошику + $pizza_list.html(""); + + //Онволення однієї піци + function showOnePizza(pizza) { + var html_code = Templates.PizzaMenu_OneItem({pizza: pizza}); + + var $node = $(html_code); + + $node.find(".buy-big").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Big); + }); + $node.find(".buy-small").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Small); + }); + + $pizza_list.append($node); + } + + $("#pizzaNum").html(list.length); + + list.forEach(showOnePizza); +} + +function filterPizza(filter) { + //Масив куди потраплять піци які треба показати + var pizza_shown = []; + var filt = filter.split(","); + + + Pizza_List.forEach(function(pizza){ + //Якщо піка відповідає фільтру + //pizza_shown.push(pizza); + //var ingridient = getIngredientsArray(pizza); + var checked = []; + filt.forEach(function(f){ + //if(checked) return; + if(f.charAt(0) == '!'){ + var fil = f.substring(1); + if(!(fil in pizza.content)){ + checked.push(true); + } + else checked.push(false); + } else { + if(f in pizza.content) + checked.push(true); + else checked.push(false); + } + + //TODO: зробити фільтри + }); + function isTrue(element, index, array) { + return element == true; + } + if(checked.every(isTrue)) pizza_shown.push(pizza); +}); + + //Показати відфільтровані піци + showPizzaList(pizza_shown); +} + +function initialiseMenu() { + //Показуємо усі піци + showPizzaList(Pizza_List); + + $("#filter-button-meat").click(function(){ + $(".allPizzas").html("М'ясні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('meat'); + }); + + $("#filter-button-pineapples").click(function(){ + $(".allPizzas").html("Піци з ананасом"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('pineapple'); + }); + + $("#filter-button-mushrooms").click(function(){ + $(".allPizzas").html("Грибні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('mushroom'); + }); + + $("#filter-button-ocean").click(function(){ + $(".allPizzas").html("Піци з морепродуктами"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('ocean'); + }); + + $("#filter-button-vega").click(function(){ + console.log("Vega"); + $(".allPizzas").html("Вегетаріанські піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('!meat,!ocean,!mushroom'); + }); + + $("#filter-button-all").click(function(){ + $(".allPizzas").html("Усі піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + showPizzaList(Pizza_List); + + }); +} + +exports.filterPizza = filterPizza; +exports.initialiseMenu = initialiseMenu; +},{"../Pizza_List":1,"../Templates":2,"./PizzaCart":4}],6:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +'use strict'; + +/** + * @file Embedded JavaScript templating engine. + * @author Matthew Eernisse + * @author Tiancheng "Timothy" Gu + * @project EJS + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0} + */ + +/** + * EJS internal functions. + * + * Technically this "module" lies in the same file as {@link module:ejs}, for + * the sake of organization all the private functions re grouped into this + * module. + * + * @module ejs-internal + * @private + */ + +/** + * Embedded JavaScript templating engine. + * + * @module ejs + * @public + */ + +var fs = require('fs') + , utils = require('./utils') + , scopeOptionWarned = false + , _VERSION_STRING = require('../package.json').version + , _DEFAULT_DELIMITER = '%' + , _DEFAULT_LOCALS_NAME = 'locals' + , _REGEX_STRING = '(<%%|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)' + , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context' + , 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace' + , 'strict', 'localsName' + ] + , _TRAILING_SEMCOL = /;\s*$/ + , _BOM = /^\uFEFF/; + +/** + * EJS template function cache. This can be a LRU object from lru-cache NPM + * module. By default, it is {@link module:utils.cache}, a simple in-process + * cache that grows continuously. + * + * @type {Cache} + */ + +exports.cache = utils.cache; + +/** + * Name of the object containing the locals. + * + * This variable is overriden by {@link Options}`.localsName` if it is not + * `undefined`. + * + * @type {String} + * @public + */ + +exports.localsName = _DEFAULT_LOCALS_NAME; + +/** + * Get the path to the included file from the parent file path and the + * specified path. + * + * @param {String} name specified path + * @param {String} filename parent file path + * @return {String} + */ + +exports.resolveInclude = function(name, filename) { + var path = require('path') + , dirname = path.dirname + , extname = path.extname + , resolve = path.resolve + , includePath = resolve(dirname(filename), name) + , ext = extname(name); + if (!ext) { + includePath += '.ejs'; + } + return includePath; +}; + +/** + * Get the template from a string or a file, either compiled on-the-fly or + * read from cache (if enabled), and cache the template if needed. + * + * If `template` is not set, the file specified in `options.filename` will be + * read. + * + * If `options.cache` is true, this function reads the file from + * `options.filename` so it must be set prior to calling this function. + * + * @memberof module:ejs-internal + * @param {Options} options compilation options + * @param {String} [template] template source + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned. + * @static + */ + +function handleCache(options, template) { + var fn + , path = options.filename + , hasTemplate = arguments.length > 1; + + if (options.cache) { + if (!path) { + throw new Error('cache option requires a filename'); + } + fn = exports.cache.get(path); + if (fn) { + return fn; + } + if (!hasTemplate) { + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + } + else if (!hasTemplate) { + // istanbul ignore if: should not happen at all + if (!path) { + throw new Error('Internal EJS error: no file name or template ' + + 'provided'); + } + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + fn = exports.compile(template, options); + if (options.cache) { + exports.cache.set(path, fn); + } + return fn; +} + +/** + * Get the template function. + * + * If `options.cache` is `true`, then the template is cached. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned + * @static + */ + +function includeFile(path, options) { + var opts = utils.shallowCopy({}, options); + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + opts.filename = exports.resolveInclude(path, opts.filename); + return handleCache(opts); +} + +/** + * Get the JavaScript source of an included file. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {String} + * @static + */ + +function includeSource(path, options) { + var opts = utils.shallowCopy({}, options) + , includePath + , template; + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + includePath = exports.resolveInclude(path, opts.filename); + template = fs.readFileSync(includePath).toString().replace(_BOM, ''); + + opts.filename = includePath; + var templ = new Template(template, opts); + templ.generateSource(); + return templ.source; +} + +/** + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and + * `lineno`. + * + * @implements RethrowCallback + * @memberof module:ejs-internal + * @param {Error} err Error object + * @param {String} str EJS source + * @param {String} filename file name of the EJS file + * @param {String} lineno line number of the error + * @static + */ + +function rethrow(err, str, filename, lineno){ + var lines = str.split('\n') + , start = Math.max(lineno - 3, 0) + , end = Math.min(lines.length, lineno + 3); + + // Error context + var context = lines.slice(start, end).map(function (line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' >> ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'ejs') + ':' + + lineno + '\n' + + context + '\n\n' + + err.message; + + throw err; +} + +/** + * Copy properties in data object that are recognized as options to an + * options object. + * + * This is used for compatibility with earlier versions of EJS and Express.js. + * + * @memberof module:ejs-internal + * @param {Object} data data object + * @param {Options} opts options object + * @static + */ + +function cpOptsInData(data, opts) { + _OPTS.forEach(function (p) { + if (typeof data[p] != 'undefined') { + opts[p] = data[p]; + } + }); +} + +/** + * Compile the given `str` of ejs into a template function. + * + * @param {String} template EJS template + * + * @param {Options} opts compilation options + * + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `opts.client`, either type might be returned. + * @public + */ + +exports.compile = function compile(template, opts) { + var templ; + + // v1 compat + // 'scope' is 'context' + // FIXME: Remove this in a future version + if (opts && opts.scope) { + if (!scopeOptionWarned){ + console.warn('`scope` option is deprecated and will be removed in EJS 3'); + scopeOptionWarned = true; + } + if (!opts.context) { + opts.context = opts.scope; + } + delete opts.scope; + } + templ = new Template(template, opts); + return templ.compile(); +}; + +/** + * Render the given `template` of ejs. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} template EJS template + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @return {String} + * @public + */ + +exports.render = function (template, data, opts) { + data = data || {}; + opts = opts || {}; + var fn; + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 2) { + cpOptsInData(data, opts); + } + + return handleCache(opts, template)(data); +}; + +/** + * Render an EJS file at the given `path` and callback `cb(err, str)`. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} path path to the EJS file + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @param {RenderFileCallback} cb callback + * @public + */ + +exports.renderFile = function () { + var args = Array.prototype.slice.call(arguments) + , path = args.shift() + , cb = args.pop() + , data = args.shift() || {} + , opts = args.pop() || {} + , result; + + // Don't pollute passed in opts obj with new vals + opts = utils.shallowCopy({}, opts); + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 3) { + // Express 4 + if (data.settings && data.settings['view options']) { + cpOptsInData(data.settings['view options'], opts); + } + // Express 3 and lower + else { + cpOptsInData(data, opts); + } + } + opts.filename = path; + + try { + result = handleCache(opts)(data); + } + catch(err) { + return cb(err); + } + return cb(null, result); +}; + +/** + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}. + * @public + */ + +exports.clearCache = function () { + exports.cache.reset(); +}; + +function Template(text, opts) { + opts = opts || {}; + var options = {}; + this.templateText = text; + this.mode = null; + this.truncate = false; + this.currentLine = 1; + this.source = ''; + this.dependencies = []; + options.client = opts.client || false; + options.escapeFunction = opts.escape || utils.escapeXML; + options.compileDebug = opts.compileDebug !== false; + options.debug = !!opts.debug; + options.filename = opts.filename; + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER; + options.strict = opts.strict || false; + options.context = opts.context; + options.cache = opts.cache || false; + options.rmWhitespace = opts.rmWhitespace; + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME; + + if (options.strict) { + options._with = false; + } + else { + options._with = typeof opts._with != 'undefined' ? opts._with : true; + } + + this.opts = options; + + this.regex = this.createRegex(); +} + +Template.modes = { + EVAL: 'eval' +, ESCAPED: 'escaped' +, RAW: 'raw' +, COMMENT: 'comment' +, LITERAL: 'literal' +}; + +Template.prototype = { + createRegex: function () { + var str = _REGEX_STRING + , delim = utils.escapeRegExpChars(this.opts.delimiter); + str = str.replace(/%/g, delim); + return new RegExp(str); + } + +, compile: function () { + var src + , fn + , opts = this.opts + , prepended = '' + , appended = '' + , escape = opts.escapeFunction; + + if (opts.rmWhitespace) { + // Have to use two separate replace here as `^` and `$` operators don't + // work well with `\r`. + this.templateText = + this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, ''); + } + + // Slurp spaces and tabs before <%_ and after _%> + this.templateText = + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>'); + + if (!this.source) { + this.generateSource(); + prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n'; + if (opts._with !== false) { + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n'; + appended += ' }' + '\n'; + } + appended += ' return __output.join("");' + '\n'; + this.source = prepended + this.source + appended; + } + + if (opts.compileDebug) { + src = 'var __line = 1' + '\n' + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n' + + ' , __filename = ' + (opts.filename ? + JSON.stringify(opts.filename) : 'undefined') + ';' + '\n' + + 'try {' + '\n' + + this.source + + '} catch (e) {' + '\n' + + ' rethrow(e, __lines, __filename, __line);' + '\n' + + '}' + '\n'; + } + else { + src = this.source; + } + + if (opts.debug) { + console.log(src); + } + + if (opts.client) { + src = 'escape = escape || ' + escape.toString() + ';' + '\n' + src; + if (opts.compileDebug) { + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src; + } + } + + if (opts.strict) { + src = '"use strict";\n' + src; + } + + try { + fn = new Function(opts.localsName + ', escape, include, rethrow', src); + } + catch(e) { + // istanbul ignore else + if (e instanceof SyntaxError) { + if (opts.filename) { + e.message += ' in ' + opts.filename; + } + e.message += ' while compiling ejs'; + } + throw e; + } + + if (opts.client) { + fn.dependencies = this.dependencies; + return fn; + } + + // Return a callable function which will execute the function + // created by the source-code, with the passed data as locals + // Adds a local `include` function which allows full recursive include + var returnedFn = function (data) { + var include = function (path, includeData) { + var d = utils.shallowCopy({}, data); + if (includeData) { + d = utils.shallowCopy(d, includeData); + } + return includeFile(path, opts)(d); + }; + return fn.apply(opts.context, [data || {}, escape, include, rethrow]); + }; + returnedFn.dependencies = this.dependencies; + return returnedFn; + } + +, generateSource: function () { + var self = this + , matches = this.parseTemplateText() + , d = this.opts.delimiter; + + if (matches && matches.length) { + if (this.opts.compileDebug && this.opts.filename) { + this.source = ' ; __lines = ' + JSON.stringify(this.templateText) + '\n'; + this.source += ' ; __filename = "' + this.opts.filename.replace(/\\/g, '/') + '"\n'; + } + matches.forEach(function (line, index) { + var opening + , closing + , include + , includeOpts + , includeSrc; + // If this is an opening tag, check for closing tags + // FIXME: May end up with some false positives here + // Better to store modes as k/v with '<' + delimiter as key + // Then this can simply check against the map + if ( line.indexOf('<' + d) === 0 // If it is a tag + && line.indexOf('<' + d + d) !== 0) { // and is not escaped + closing = matches[index + 2]; + if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) { + throw new Error('Could not find matching close tag for "' + line + '".'); + } + } + // HACK: backward-compat `include` preprocessor directives + if ((include = line.match(/^\s*include\s+(\S+)/))) { + opening = matches[index - 1]; + // Must be in EVAL or RAW mode + if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) { + includeOpts = utils.shallowCopy({}, self.opts); + includeSrc = includeSource(include[1], includeOpts); + includeSrc = ' ; (function(){' + '\n' + includeSrc + + ' ; })()' + '\n'; + self.source += includeSrc; + self.dependencies.push(exports.resolveInclude(include[1], + includeOpts.filename)); + return; + } + } + self.scanLine(line); + }); + } + + } + +, parseTemplateText: function () { + var str = this.templateText + , pat = this.regex + , result = pat.exec(str) + , arr = [] + , firstPos + , lastPos; + + while (result) { + firstPos = result.index; + lastPos = pat.lastIndex; + + if (firstPos !== 0) { + arr.push(str.substring(0, firstPos)); + str = str.slice(firstPos); + } + + arr.push(result[0]); + str = str.slice(result[0].length); + result = pat.exec(str); + } + + if (str) { + arr.push(str); + } + + return arr; + } + +, scanLine: function (line) { + var self = this + , d = this.opts.delimiter + , newLineCount = 0; + + function _addOutput() { + if (self.truncate) { + // Only replace single leading linebreak in the line after + // -%> tag -- this is the single, trailing linebreak + // after the tag that the truncation mode replaces + // Handle Win / Unix / old Mac linebreaks -- do the \r\n + // combo first in the regex-or + line = line.replace(/^(?:\r\n|\r|\n)/, '') + self.truncate = false; + } + else if (self.opts.rmWhitespace) { + // Gotta be more careful here. + // .replace(/^(\s*)\n/, '$1') might be more appropriate here but as + // rmWhitespace already removes trailing spaces anyway so meh. + line = line.replace(/^\n/, ''); + } + if (!line) { + return; + } + + // Preserve literal slashes + line = line.replace(/\\/g, '\\\\'); + + // Convert linebreaks + line = line.replace(/\n/g, '\\n'); + line = line.replace(/\r/g, '\\r'); + + // Escape double-quotes + // - this will be the delimiter during execution + line = line.replace(/"/g, '\\"'); + self.source += ' ; __append("' + line + '")' + '\n'; + } + + newLineCount = (line.split('\n').length - 1); + + switch (line) { + case '<' + d: + case '<' + d + '_': + this.mode = Template.modes.EVAL; + break; + case '<' + d + '=': + this.mode = Template.modes.ESCAPED; + break; + case '<' + d + '-': + this.mode = Template.modes.RAW; + break; + case '<' + d + '#': + this.mode = Template.modes.COMMENT; + break; + case '<' + d + d: + this.mode = Template.modes.LITERAL; + this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n'; + break; + case d + '>': + case '-' + d + '>': + case '_' + d + '>': + if (this.mode == Template.modes.LITERAL) { + _addOutput(); + } + + this.mode = null; + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0; + break; + default: + // In script mode, depends on type of tag + if (this.mode) { + // If '//' is found without a line break, add a line break. + switch (this.mode) { + case Template.modes.EVAL: + case Template.modes.ESCAPED: + case Template.modes.RAW: + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) { + line += '\n'; + } + } + switch (this.mode) { + // Just executing code + case Template.modes.EVAL: + this.source += ' ; ' + line + '\n'; + break; + // Exec, esc, and output + case Template.modes.ESCAPED: + this.source += ' ; __append(escape(' + + line.replace(_TRAILING_SEMCOL, '').trim() + '))' + '\n'; + break; + // Exec and output + case Template.modes.RAW: + this.source += ' ; __append(' + + line.replace(_TRAILING_SEMCOL, '').trim() + ')' + '\n'; + break; + case Template.modes.COMMENT: + // Do nothing + break; + // Literal <%% mode, append as raw output + case Template.modes.LITERAL: + _addOutput(); + break; + } + } + // In string mode, just add the output + else { + _addOutput(); + } + } + + if (self.opts.compileDebug && newLineCount) { + this.currentLine += newLineCount; + this.source += ' ; __line = ' + this.currentLine + '\n'; + } + } +}; + +/* + * Export the internal function for escaping XML so people + * can use for manual escaping if needed + * */ +exports.escapeXML = utils.escapeXML; + +/** + * Express.js support. + * + * This is an alias for {@link module:ejs.renderFile}, in order to support + * Express.js out-of-the-box. + * + * @func + */ + +exports.__express = exports.renderFile; + +// Add require support +/* istanbul ignore else */ +if (require.extensions) { + require.extensions['.ejs'] = function (module, filename) { + filename = filename || /* istanbul ignore next */ module.filename; + var options = { + filename: filename + , client: true + } + , template = fs.readFileSync(filename).toString() + , fn = exports.compile(template, options); + module._compile('module.exports = ' + fn.toString() + ';', filename); + }; +} + +/** + * Version of EJS. + * + * @readonly + * @type {String} + * @public + */ + +exports.VERSION = _VERSION_STRING; + +/* istanbul ignore if */ +if (typeof window != 'undefined') { + window.ejs = exports; +} + +},{"../package.json":8,"./utils":7,"fs":9,"path":10}],7:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +/** + * Private utility functions + * @module utils + * @private + */ + +'use strict'; + +var regExpChars = /[|\\{}()[\]^$+*?.]/g; + +/** + * Escape characters reserved in regular expressions. + * + * If `string` is `undefined` or `null`, the empty string is returned. + * + * @param {String} string Input string + * @return {String} Escaped string + * @static + * @private + */ +exports.escapeRegExpChars = function (string) { + // istanbul ignore if + if (!string) { + return ''; + } + return String(string).replace(regExpChars, '\\$&'); +}; + +var _ENCODE_HTML_RULES = { + '&': '&' + , '<': '<' + , '>': '>' + , '"': '"' + , "'": ''' + } + , _MATCH_HTML = /[&<>\'"]/g; + +function encode_char(c) { + return _ENCODE_HTML_RULES[c] || c; +}; + +/** + * Stringified version of constants used by {@link module:utils.escapeXML}. + * + * It is used in the process of generating {@link ClientFunction}s. + * + * @readonly + * @type {String} + */ + +var escapeFuncStr = + 'var _ENCODE_HTML_RULES = {\n' ++ ' "&": "&"\n' ++ ' , "<": "<"\n' ++ ' , ">": ">"\n' ++ ' , \'"\': """\n' ++ ' , "\'": "'"\n' ++ ' }\n' ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n' ++ 'function encode_char(c) {\n' ++ ' return _ENCODE_HTML_RULES[c] || c;\n' ++ '};\n'; + +/** + * Escape characters reserved in XML. + * + * If `markup` is `undefined` or `null`, the empty string is returned. + * + * @implements {EscapeCallback} + * @param {String} markup Input string + * @return {String} Escaped string + * @static + * @private + */ + +exports.escapeXML = function (markup) { + return markup == undefined + ? '' + : String(markup) + .replace(_MATCH_HTML, encode_char); +}; +exports.escapeXML.toString = function () { + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr +}; + +/** + * Copy all properties from one object to another, in a shallow fashion. + * + * @param {Object} to Destination object + * @param {Object} from Source object + * @return {Object} Destination object + * @static + * @private + */ +exports.shallowCopy = function (to, from) { + from = from || {}; + for (var p in from) { + to[p] = from[p]; + } + return to; +}; + +/** + * Simple in-process cache implementation. Does not implement limits of any + * sort. + * + * @implements Cache + * @static + * @private + */ +exports.cache = { + _data: {}, + set: function (key, val) { + this._data[key] = val; + }, + get: function (key) { + return this._data[key]; + }, + reset: function () { + this._data = {}; + } +}; + + +},{}],8:[function(require,module,exports){ +module.exports={ + "name": "ejs", + "description": "Embedded JavaScript templates", + "keywords": [ + "template", + "engine", + "ejs" + ], + "version": "2.4.2", + "author": { + "name": "Matthew Eernisse", + "email": "mde@fleegix.org", + "url": "http://fleegix.org" + }, + "contributors": [ + { + "name": "Timothy Gu", + "email": "timothygu99@gmail.com", + "url": "https://timothygu.github.io" + } + ], + "license": "Apache-2.0", + "main": "./lib/ejs.js", + "repository": { + "type": "git", + "url": "git://github.com/mde/ejs.git" + }, + "bugs": { + "url": "https://github.com/mde/ejs/issues" + }, + "homepage": "https://github.com/mde/ejs", + "dependencies": {}, + "devDependencies": { + "browserify": "^8.0.3", + "istanbul": "~0.3.5", + "jake": "^8.0.0", + "jsdoc": "^3.3.0-beta1", + "lru-cache": "^2.5.0", + "mocha": "^2.1.0", + "rimraf": "^2.2.8", + "uglify-js": "^2.4.16" + }, + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha", + "sample": "npm install express && node sample/index.js", + "coverage": "istanbul cover node_modules/mocha/bin/_mocha", + "doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*", + "devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*" + }, + "_id": "ejs@2.4.2", + "_shasum": "7057eb4812958fb731841cd9ca353343efe597b1", + "_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.4.2.tgz", + "_from": "ejs@>=2.4.1 <3.0.0", + "_npmVersion": "2.15.1", + "_nodeVersion": "4.4.4", + "_npmUser": { + "name": "mde", + "email": "mde@fleegix.org" + }, + "maintainers": [ + { + "name": "tjholowaychuk", + "email": "tj@vision-media.ca" + }, + { + "name": "mde", + "email": "mde@fleegix.org" + } + ], + "dist": { + "shasum": "7057eb4812958fb731841cd9ca353343efe597b1", + "tarball": "https://registry.npmjs.org/ejs/-/ejs-2.4.2.tgz" + }, + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/ejs-2.4.2.tgz_1464117640663_0.8193834638223052" + }, + "directories": {} +} + +},{}],9:[function(require,module,exports){ + +},{}],10:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; + +}).call(this,require('_process')) +},{"_process":11}],11:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = setTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + clearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + setTimeout(drainQueue, 0); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}]},{},[3]); + +function getElByClass(name, type) +{ + var r = []; + var re = new RegExp("(^|\\s)" + name + "(\\s|$)"); + var e = (type) ? getElByTag(type) : ((navigator.userAgent.indexOf("MSIE") >= 0) ? document.all : getElByTag("*")); + for ( var j = 0; j < e.length; j++ ) + if (re.test(attr(e[j], "class"))) + r.push( e[j] ) + return r; +} + +function attr(el, at, value) +{ + at = {'for': 'htmlFor', 'class': 'className'}[at] || at; + if(!value) + return el[at] || el.getAttribute(at) || ''; + else + { + el[at] = value; + if (el.setAttribute) + el.setAttribute(at, value); + } +} + +function getElByTag(tag, el) +{ + return (el || document).getElementsByTagName(tag); +} + +function getElByName(name) +{ + return document.getElementsByName(name); +} + +function getElById(id) +{ + return document.getElementById(id); +} \ No newline at end of file diff --git a/Frontend/www/assets/less/main.less b/Frontend/www/assets/less/main.less index f8e21fa4d..0c1811f50 100644 --- a/Frontend/www/assets/less/main.less +++ b/Frontend/www/assets/less/main.less @@ -86,10 +86,11 @@ margin: auto; } .sign-in-button { float: right; - margin-top: -11px; + margin-top: -8px; + margin-right: 11px; } .left-panel { - + display: none; margin-right: 500px; padding-left: 30px; padding-right: 360px; @@ -126,10 +127,7 @@ margin-right: 500px; margin-bottom: 10%; } -.order-state{ - margin:10%; - margin-top:5%; -} + .sum-title{ margin-left:-5%; @@ -154,7 +152,7 @@ margin-right: 500px; .right-panel .clear-order-wrap { padding-right: 15px; padding-left: 20px; - font-size: 10px; + font-size: 14px; line-height: 11px; font-weight: 400; color: gray; @@ -260,4 +258,42 @@ img { margin-top: 15px; color: #fefefe; text-decoration:none; +} + +#cart{ + position: fixed !important; + top: 0; + right: 0; + bottom: 0; + margin-left: 20px; + padding-right: 0 !important; + padding-left: 0 !important; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: box; + -moz-box-orient: vertical; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + box-orient: vertical; + flex-direction: column; + height: 100%; + background: #fff; + box-shadow: rgba(0, 0, 0, 0.2) -3px 3px 10px; + z-index: 10000; +} + +.order-state{ + position: absolute; + margin:0 !important; + padding: 10%; + margin-top:5%; + bottom:0; + width:100%; +} + +#cartSum{ + text-align: right; } \ No newline at end of file diff --git a/Frontend/www/index.html b/Frontend/www/index.html index ad62d0477..df14c6883 100644 --- a/Frontend/www/index.html +++ b/Frontend/www/index.html @@ -56,443 +56,37 @@
Усі піци
- 9 + 9
- - - - - - + + + + + +
-
-
-
-
-
- - +
-

Міксовий поло

-

М'ясна

- -

Куриця копчена, сир моцарелла, ананаси, кукурудза, петрушка, соус томатний

-
-
- - 30 -
-
- - 500 -
-

130

грн.
- -
-
-
- - 50
-
- - 850
-

220

грн.
- -
-
-
-
- -
-
- Популярна - - -

BBQ

-

З грибами

- -

Мисливські ковбаски, ковбаски папероні, сир домашній, печериці, петрушка, оливки

-
-
- - 30 -
-
- - 500 -
-

170

грн.
- -
-
-
- - 50
-
- - 850
-

240

грн.
- -
-
-
-
- -
-
- - -

Маргарита

-

Вега

- -

Базилік, орегано, помідор, соус томатний, сир моцарелла

-
-
- - 30 -
-
- - 500 -
-

120

грн.
- -
-
-
- - 50
-
- - 850
-

210

грн.
- -
-
-
-
-
-
- Нова - - -

Россо Густо

-

З морепродуктами

-

Ікра червона, лосось копчений, сир моцарелла, оливкова олія, вершки

-
-
- - 30 -
-
- - 500 -
-

180

грн.
- -
-
-
- - 50
-
- - 850
-

270

грн.
- -
-
-
-
-
-
- - - -

Бамбіно

-

З грибами

- -

Базилік, шинка, печериці, ковбаса салямі, перець болгарський, соус томатний, сир моцарелла

-
-
- - 30 -
-
- - 500 -
-

140

грн.
- -
-
-
- - 50
-
- - 850
-

210

грн.
- -
-
-
-
-
-
- - -

Вернісаж

-

З грибами

- -

Печериці, ковбаски мисливські, куряча грудинка, цибуля, петрушка, соус, сир моцарелла, огірки

-
-
- - 30 -
-
- - 500 -
-

140

грн.
- -
-
-
- - 50
-
- - 850
-

230

грн.
- -
-
-
-
-
- -
- - -

Імпреза

-

М'ясна

- -

Балик, салямі, куриця, сир моцарелла, сир рокфорд, ананаси, томатна паста, петрушка

-
-
- - 30 -
-
- - 500 -
-

130

грн.
- -
-
-
- - 130
-
- - 850
-

230

грн.
- -
-
-
-
- -
-
- - -

Дольче Маре

-

З морепродуктами

- -

Ікра червона, креветки тигрові, морський коктейль, сир моцарелла, вершки

-
-
- - 30 -
-
- - 500 -
-

180

грн.
- -
-
-
- - 50
-
- - 850
-

270

грн.
- -
-
-
-
- -
-
- - -

Капрічіоза

-

М'ясна

- -

Шинка, ковбаса салямі, куряча грудинка, петрушка, сир моцарелла, вершки

-
-
- - 30 -
-
- - 500 -
-

140

грн.
- -
-
-
- - 50
-
- - 850
-

220

грн.
- -
- - -
-
-
- -
-
-
- - Замовлення - 3 - - - - Очистити замовлення - - -
- -
-
- Піца -

- BBQ (Мала) -

-
- - 30 - - 500 -
-
- 170грн - - - - - 1 - - - - - - - - - - -
-
-
- Піца -

- Міксовий поло (Велика) -

-
- - 50 - - 850 -
-
- 220грн - - - - - 1 - - - - - - - - - - -
-
-
- Піца -

- Россо Густо (Мала) -

-
- - 30 - - 500 -
-
- 180грн - - - - - 1 - - - - - - - - - - -
-
- - - -
+
+ +
+ +
+ +
Сума замовлення: - 570 грн + 0 грн
-
- - -
+

ЦЬОГО

ТИЖНЯ

НА ВСЕ


-20%
-
- @@ -518,6 +107,7 @@

220

грн.
- + + \ No newline at end of file From 6619bb89e5f75a5433a71f20d9bde15b9052268d Mon Sep 17 00:00:00 2001 From: q2012 Date: Wed, 22 Jun 2016 10:55:23 +0300 Subject: [PATCH 3/3] Add files via upload --- Backend/api.js | 18 + Backend/data/Pizza_List.js | 177 + Backend/main.js | 53 + Backend/pages.js | 14 + Backend/views/common/footer.ejs | 12 + Backend/views/common/header.ejs | 56 + Backend/views/less/main.less | 307 ++ Backend/views/less/pizza/pizza-card.less | 23 + Backend/views/mainPage-cpy.ejs | 89 + Backend/views/mainPage.ejs | 48 + Backend/views/orderPage.ejs | 282 ++ Frontend/src/Pizza_List.js | 173 + Frontend/src/Templates.js | 8 +- Frontend/src/main.js | 5 + Frontend/src/pizza/PizzaCart.js | 135 +- Frontend/src/pizza/PizzaMenu.js | 109 +- Frontend/www/assets/js/main-cpy.js | 1848 ++++++++++ Frontend/www/assets/js/main-start.js | 2033 ++++++++++++ Frontend/www/assets/js/main.js | 3881 ++++++++++------------ Frontend/www/assets/less/main.less | 8 + Frontend/www/index.html | 3 +- Gruntfile.js | 124 +- package.json | 5 +- server.js | 2 + 24 files changed, 7310 insertions(+), 2103 deletions(-) create mode 100644 Backend/api.js create mode 100644 Backend/data/Pizza_List.js create mode 100644 Backend/main.js create mode 100644 Backend/pages.js create mode 100644 Backend/views/common/footer.ejs create mode 100644 Backend/views/common/header.ejs create mode 100644 Backend/views/less/main.less create mode 100644 Backend/views/less/pizza/pizza-card.less create mode 100644 Backend/views/mainPage-cpy.ejs create mode 100644 Backend/views/mainPage.ejs create mode 100644 Backend/views/orderPage.ejs create mode 100644 Frontend/www/assets/js/main-cpy.js create mode 100644 Frontend/www/assets/js/main-start.js create mode 100644 server.js diff --git a/Backend/api.js b/Backend/api.js new file mode 100644 index 000000000..1eb94c2cc --- /dev/null +++ b/Backend/api.js @@ -0,0 +1,18 @@ +/** + * Created by chaika on 09.02.16. + */ +var Pizza_List = require('./data/Pizza_List'); + +exports.getPizzaList = function(req, res) { + // console.log(Pizza_List); + res.send(Pizza_List); +}; + +exports.createOrder = function(req, res) { + var order_info = req.body; + console.log("Creating Order", order_info); + + res.send({ + success: true + }); +}; \ No newline at end of file diff --git a/Backend/data/Pizza_List.js b/Backend/data/Pizza_List.js new file mode 100644 index 000000000..134fb6c81 --- /dev/null +++ b/Backend/data/Pizza_List.js @@ -0,0 +1,177 @@ +/** + * Created by diana on 12.01.16. + */ + +var pizza_info = [ + { + id:1, + icon:'assets/images/pizza_7.jpg', + title: "Імпреза", + type: 'М’ясна піца', + content: { + meat: ['балик', 'салямі'], + chicken: ['куриця'], + cheese: ['сир моцарелла', 'сир рокфорд'], + pineapple: ['ананаси'], + additional: ['томатна паста', 'петрушка'] + }, + small_size:{ + weight: 370, + size: 30, + price: 99 + }, + big_size:{ + weight: 660, + size: 40, + price: 169 + }, + is_new:true, + is_popular:true + + }, + { + id:2, + icon:'assets/images/pizza_2.jpg', + title: "BBQ", + type: 'М’ясна піца', + content: { + meat: ['мисливські ковбаски', 'ковбаски папероні', 'шинка'], + cheese: ['сир домашній'], + mushroom: ['шампінйони'], + additional: ['петрушка', 'оливки'] + }, + small_size:{ + weight: 460, + size: 30, + price: 139 + }, + big_size:{ + weight: 840, + size: 40, + price: 199 + }, + is_popular:true + }, + { + id:3, + icon:'assets/images/pizza_1.jpg', + title: "Міксовий поло", + type: 'М’ясна піца', + content: { + meat: ['вітчина', 'куриця копчена'], + cheese: ['сир моцарелла'], + pineapple: ['ананаси'], + additional: ['кукурудза', 'петрушка', 'соус томатний'] + }, + small_size:{ + weight: 430, + size: 30, + price: 115 + }, + big_size:{ + weight: 780, + size: 40, + price: 179 + } + }, + { + id:4, + icon:'assets/images/pizza_5.jpg', + title: "Сициліано", + type: 'М’ясна піца', + content: { + meat: ['вітчина', 'салямі'], + cheese: ['сир моцарелла'], + mushroom: ['шампінйони'], + additional: ['перець болгарський', 'соус томатний'] + }, + small_size:{ + weight: 450, + size: 30, + price: 111 + }, + big_size:{ + weight: 790, + size: 40, + price: 169 + } + }, + { + id:17, + icon:'assets/images/pizza_3.jpg', + title: "Маргарита", + type: 'Вега піца', + content: { + cheese: ['сир моцарелла', 'сир домашній'], + tomato: ['помідори'], + additional: ['базилік', 'оливкова олія', 'соус томатний'] + }, + small_size:{ + weight: 370, + size: 30, + price: 89 + } + }, + { + id:43, + icon:'assets/images/pizza_6.jpg', + title: "Мікс смаків", + type: 'М’ясна піца', + content: { + meat: ['ковбаски'], + cheese: ['сир моцарелла'], + mushroom: ['шампінйони'], + pineapple: ['ананаси'], + additional: ['цибуля кримська', 'огірки квашені', 'соус гірчичний'] + }, + small_size:{ + weight: 470, + size: 30, + price: 115 + }, + big_size:{ + weight: 780, + size: 40, + price: 180 + } + }, + { + id:90, + icon:'assets/images/pizza_8.jpg', + title: "Дольче Маре", + type: 'Морська піца', + content: { + ocean: ['криветки тигрові', 'мідії', 'ікра червона', 'філе червоної риби'], + cheese: ['сир моцарелла'], + additional: ['оливкова олія', 'вершки'] + }, + big_size:{ + weight: 845, + size: 40, + price: 399 + } + }, + { + id:6, + icon:'assets/images/pizza_4.jpg', + title: "Россо Густо", + type: 'Морська піца', + content: { + ocean: ['ікра червона', 'лосось копчений'], + cheese: ['сир моцарелла'], + additional: ['оливкова олія', 'вершки'] + }, + small_size:{ + weight: 400, + size: 30, + price: 189 + }, + big_size:{ + weight: 700, + size: 40, + price: 299 + } + } +]; + +module.exports = pizza_info; \ No newline at end of file diff --git a/Backend/main.js b/Backend/main.js new file mode 100644 index 000000000..a86dbf479 --- /dev/null +++ b/Backend/main.js @@ -0,0 +1,53 @@ +/** + * Created by chaika on 09.02.16. + */ +var express = require('express'); +var path = require('path'); +var morgan = require('morgan'); +var bodyParser = require('body-parser'); + +function configureEndpoints(app) { + var pages = require('./pages'); + var api = require('./api'); + + //Налаштування URL за якими буде відповідати сервер + //Отримання списку піц + app.get('/api/get-pizza-list/', api.getPizzaList); + app.post('/api/create-order/', api.createOrder); + + //Сторінки + //Головна сторінка + app.get('/', pages.mainPage); + + //Сторінка замовлення + app.get('/order.html', pages.orderPage); + + //Якщо не підійшов жоден url, тоді повертаємо файли з папки www + app.use(express.static(path.join(__dirname, '../Frontend/www'))); +} + +function startServer(port) { + //Створюється застосунок + var app = express(); + + //Налаштування директорії з шаблонами + app.set('views', path.join(__dirname, 'views')); + app.set('view engine', 'ejs'); + + //Налаштування виводу в консоль списку запитів до сервера + app.use(morgan('dev')); + + //Розбір POST запитів + app.use(bodyParser.urlencoded({ extended: false })); + app.use(bodyParser.json()); + + //Налаштовуємо сторінки + configureEndpoints(app); + + //Запуск додатка за вказаним портом + app.listen(port, function () { + console.log('My Application Running on http://localhost:'+port+'/'); + }); +} + +exports.startServer = startServer; \ No newline at end of file diff --git a/Backend/pages.js b/Backend/pages.js new file mode 100644 index 000000000..1fe66aafa --- /dev/null +++ b/Backend/pages.js @@ -0,0 +1,14 @@ +/** + * Created by chaika on 09.02.16. + */ +exports.mainPage = function(req, res) { + res.render('mainPage', { + pageTitle: 'Вибір Піци' + }); +}; + +exports.orderPage = function(req, res) { + res.render('orderPage', { + pageTitle: 'Замовлення піци' + }); +}; \ No newline at end of file diff --git a/Backend/views/common/footer.ejs b/Backend/views/common/footer.ejs new file mode 100644 index 000000000..23024d876 --- /dev/null +++ b/Backend/views/common/footer.ejs @@ -0,0 +1,12 @@ +

ЦЬОГО

ТИЖНЯ

НА ВСЕ


-20%
+ + + + + + + + + + + \ No newline at end of file diff --git a/Backend/views/common/header.ejs b/Backend/views/common/header.ejs new file mode 100644 index 000000000..e8aa869fe --- /dev/null +++ b/Backend/views/common/header.ejs @@ -0,0 +1,56 @@ + + + + + Pizza + + + + + + + + + + + + + + + +
+
+ + +
+
+

(044)222 3 222

+
+
+
+ 24 години / 7 днів на тиждень +
+
+
+
+
+

Безкоштовна доставка піци

+
+
+ +
+ + +
diff --git a/Backend/views/less/main.less b/Backend/views/less/main.less new file mode 100644 index 000000000..2aee823b7 --- /dev/null +++ b/Backend/views/less/main.less @@ -0,0 +1,307 @@ +@mainColor: rgba(232, 151, 51, 0.99); +@footerColor: #f98b17; +@fontSize: 20px; +@import "pizza/pizza-card"; + +.row{ +margin: auto; +} + +.main-header-top { + width: 100%; + font-size: @fontSize; + line-height: 11px; + color: white; + opacity: 50%; + margin: 11px 0 14px 0; + border-bottom : 1px solid white; + +}.main-header { + font-size: 0; + position: fixed; + top: 0; + left: 0; + width: 100%; + background: black; + opacity:0.8; + padding: 0 25% 0 130px; + z-index: 10; + } +.main-header-top, .header-box, .main-header-top-item { + display: inline-block; +} +.fs14 { + font-size: @fontSize; + line-height: 20px; + margin-right: 30px; + color:grey; +} + +.fs15 { + font-size: @fontSize; + line-height: 20px; + margin-right: 30px; + color:white; +} +.main, nav{ + display: block; +} +.main-nav-item { + display: inline-block; + vertical-align: top; + font-size: @fontSize; + line-height: 17px; + margin-right: 15px; + padding-bottom: 7px; + color: #fff; +} +.site-icon { + position: fixed; + left: 9px; + top: 0px; + background: orange; + border-left: 1px solid #d16200; + border-right: 1px solid #d16200; + z-index: 99; + width: 100px; + height: 87px; + font-size: @fontSize*1.5; + padding: 10px; + padding-top:15px; + text-transform: uppercase; + text-align: center; + color: #fff; +} +.title-1{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration: none; +} +.pizza-logo{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration:none; +} +.sign-in-button { + float: right; + margin-top: -8px; + margin-right: 11px; + } +.left-panel { + display: none; +margin-right: 500px; + padding-left: 30px; + padding-right: 360px; + max-width: 1354px; +} +.right-panel { + position: fixed!important; + top: 0; + right: 0; + bottom: 0; + padding-top: 35px; + margin-left: 20px; + padding-right: 0!important; + padding-left: 0!important; + box-orient: vertical; + flex-direction: column; + min-width: 330px; + width: 330px; + height: 100%; + background: #fff; + box-shadow: rgba(0,0,0,.2) -3px 3px 10px; + z-index: 1000; +} +.r1, .r2{ + width: 100%; + box-sizing: content-box; + display: block!important; +} + +.r2{ + background-color: gainsboro; +} +.r1{ + margin-bottom: 10%; +} + + + +.sum-title{ + margin-left:-5%; + font-weight: 400; +} +.sum-number{ + margin-left:30%; + font-size: 20px; + font-weight:400; +} + +.button-order{ + margin-top: 10%; +} + +.right-panel .order-list-title { + font-size: @fontSize; + font-weight: 700; + line-height: 17px; + margin-left: 20px; +} +.right-panel .clear-order-wrap { + padding-right: 15px; + padding-left: 20px; + font-size: 14px; + line-height: 11px; + font-weight: 400; + color: gray; +} +.mainTitle { + margin: 10px; + margin-top: 100px; +} +.pizzaType { + color: @mainColor; + background-color: white; + border: none; + margin-bottom: 20px; +} + +.pizzaType:hover{ + background-color: @mainColor; + color:white; +} + +.pizzaType-active { + color:white; + background-color: @mainColor; +} + +.allPizzas { + font-size: 28px; + display: inline-block; + margin: auto; +} +.allPizzasNumber { + font-size: @fontSize; + color: white; + background-color: @mainColor; + border-radius: 20px; + margin: 5px; + padding-left: 10px; + padding-right: 10px; +} +.discount { + position: fixed; + bottom: 0px; + left: 10px; +} +.buy{ + margin-left: 60px; +} +.order-one { + height: 120px; + padding: 20px 61px 10px 24px; + border-bottom: 1px solid rgba(0,0,0,.1); + position: relative; + overflow: hidden; +} +.order-one .order-title { + line-height: 16px; + font-size: 20px; + color: #ec890e; +} +.img-aside { + position: absolute; + right: -50px; + top: 15px; + border-radius: 50% 0 0 50%; + max-height: 96px; + max-width: 96px; +} +img { + vertical-align: middle; +} +.btn-circle { + width: 30px; + height: 30px; + padding: 6px 0; + font-size: 12px; + border-radius: 15px; +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: 400; + line-height: 1; +} + +.pull-right{ + position: absolute; + font-size: 16px; + margin-right: -15px; + margin-top:-15px; + margin-left:65%; +} +.title-1{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration: none; +} +.pizza-logo{ + font-size: @fontSize*1.5; + margin-top: 15px; + color: #fefefe; + text-decoration:none; +} + +#cart{ + position: fixed !important; + top: 0; + right: 0; + bottom: 0; + margin-left: 20px; + padding-right: 0 !important; + padding-left: 0 !important; + display: -webkit-box; + display: -moz-box; + display: -ms-flexbox; + display: box; + -moz-box-orient: vertical; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + box-orient: vertical; + flex-direction: column; + height: 100%; + background: #fff; + box-shadow: rgba(0, 0, 0, 0.2) -3px 3px 10px; + z-index: 10000; +} + +.order-state{ + position: absolute; + margin:0 !important; + padding: 10%; + margin-top:5%; + bottom:0; + width:100%; +} + +#cartSum{ + text-align: right; +} + +#googleMap{ + padding-left: 50px; + width: 100%; + height: 250px; + margin-bottom: 30px; + margin-top: 10px; +} \ No newline at end of file diff --git a/Backend/views/less/pizza/pizza-card.less b/Backend/views/less/pizza/pizza-card.less new file mode 100644 index 000000000..d4766279e --- /dev/null +++ b/Backend/views/less/pizza/pizza-card.less @@ -0,0 +1,23 @@ +.pizza-card { + img { + max-width: 250px; + } + + h3 { + color: @mainColor; + background-color: lighten(@mainColor, 45%); + } + .remark { + color: #bdc4ca; + font-size: 14px; + } + .buy { + margin-left: 60px; + } + + .description { + font-size: @fontSize; + height: 65px; + overflow: hidden; + } +} \ No newline at end of file diff --git a/Backend/views/mainPage-cpy.ejs b/Backend/views/mainPage-cpy.ejs new file mode 100644 index 000000000..4014f7674 --- /dev/null +++ b/Backend/views/mainPage-cpy.ejs @@ -0,0 +1,89 @@ +<% include common/header.ejs %> + +
+

+ + Усі піци + + + 8 + +

+
+ +
+
+
+
+
+ +
+
+
+
+
+ Сума замовлення +
+
+ 0 грн +
+
+
+ +
+
+
+
+
+<% include common/footer.ejs %> diff --git a/Backend/views/mainPage.ejs b/Backend/views/mainPage.ejs new file mode 100644 index 000000000..df21567a2 --- /dev/null +++ b/Backend/views/mainPage.ejs @@ -0,0 +1,48 @@ +<% include common/header.ejs %> + +
+
Усі піци
+ 9 +
+
+ + + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + Сума замовлення: + + 0 грн + + +
+
+<% include common/footer.ejs %> diff --git a/Backend/views/orderPage.ejs b/Backend/views/orderPage.ejs new file mode 100644 index 000000000..10ee6c7b8 --- /dev/null +++ b/Backend/views/orderPage.ejs @@ -0,0 +1,282 @@ +<% include common/header.ejs %> + +
+
+
+ 1. Контактні дані +
+
+
+
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+
+
+
+
+

+ Інформація про замовлення +

+

+ + Приблизний час доставки + + : невідомий +

+

+ + Адреса доставки: + + невідома +

+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + +<% include common/footer.ejs %> + + diff --git a/Frontend/src/Pizza_List.js b/Frontend/src/Pizza_List.js index 134fb6c81..a434d6206 100644 --- a/Frontend/src/Pizza_List.js +++ b/Frontend/src/Pizza_List.js @@ -173,5 +173,178 @@ var pizza_info = [ } } ]; +/* +var pizza_info = [ + { + id:1, + icon:'assets/images/pizza_7.jpg', + title: "Імпреза", + type: 'М’ясна піца', + content: { + meat: ['балик', 'салямі'], + chicken: ['куриця'], + cheese: ['сир моцарелла', 'сир рокфорд'], + pineapple: ['ананаси'], + additional: ['томатна паста', 'петрушка'] + }, + small_size:{ + weight: 370, + size: 30, + price: 99 + }, + big_size:{ + weight: 660, + size: 40, + price: 169 + }, + is_new:true, + is_popular:true + + }, + { + id:2, + icon:'assets/images/pizza_2.jpg', + title: "BBQ", + type: 'М’ясна піца', + content: { + meat: ['мисливські ковбаски', 'ковбаски папероні', 'шинка'], + cheese: ['сир домашній'], + mushroom: ['шампінйони'], + additional: ['петрушка', 'оливки'] + }, + small_size:{ + weight: 460, + size: 30, + price: 139 + }, + big_size:{ + weight: 840, + size: 40, + price: 199 + }, + is_popular:true + }, + { + id:3, + icon:'assets/images/pizza_1.jpg', + title: "Міксовий поло", + type: 'М’ясна піца', + content: { + meat: ['вітчина', 'куриця копчена'], + cheese: ['сир моцарелла'], + pineapple: ['ананаси'], + additional: ['кукурудза', 'петрушка', 'соус томатний'] + }, + small_size:{ + weight: 430, + size: 30, + price: 115 + }, + big_size:{ + weight: 780, + size: 40, + price: 179 + } + }, + { + id:4, + icon:'assets/images/pizza_5.jpg', + title: "Сициліано", + type: 'М’ясна піца', + content: { + meat: ['вітчина', 'салямі'], + cheese: ['сир моцарелла'], + mushroom: ['шампінйони'], + additional: ['перець болгарський', 'соус томатний'] + }, + small_size:{ + weight: 450, + size: 30, + price: 111 + }, + big_size:{ + weight: 790, + size: 40, + price: 169 + } + }, + { + id:17, + icon:'assets/images/pizza_3.jpg', + title: "Маргарита", + type: 'Вега піца', + content: { + cheese: ['сир моцарелла', 'сир домашній'], + tomato: ['помідори'], + additional: ['базилік', 'оливкова олія', 'соус томатний'] + }, + small_size:{ + weight: 370, + size: 30, + price: 89 + } + }, + { + id:43, + icon:'assets/images/pizza_6.jpg', + title: "Мікс смаків", + type: 'М’ясна піца', + content: { + meat: ['ковбаски'], + cheese: ['сир моцарелла'], + mushroom: ['шампінйони'], + pineapple: ['ананаси'], + additional: ['цибуля кримська', 'огірки квашені', 'соус гірчичний'] + }, + small_size:{ + weight: 470, + size: 30, + price: 115 + }, + big_size:{ + weight: 780, + size: 40, + price: 180 + } + }, + { + id:90, + icon:'assets/images/pizza_8.jpg', + title: "Дольче Маре", + type: 'Морська піца', + content: { + ocean: ['криветки тигрові', 'мідії', 'ікра червона', 'філе червоної риби'], + cheese: ['сир моцарелла'], + additional: ['оливкова олія', 'вершки'] + }, + big_size:{ + weight: 845, + size: 40, + price: 399 + } + }, + { + id:6, + icon:'assets/images/pizza_4.jpg', + title: "Россо Густо", + type: 'Морська піца', + content: { + ocean: ['ікра червона', 'лосось копчений'], + cheese: ['сир моцарелла'], + additional: ['оливкова олія', 'вершки'] + }, + small_size:{ + weight: 400, + size: 30, + price: 189 + }, + big_size:{ + weight: 700, + size: 40, + price: 299 + } + } +]; +*/ module.exports = pizza_info; \ No newline at end of file diff --git a/Frontend/src/Templates.js b/Frontend/src/Templates.js index 8729954f9..7608f4d2b 100644 --- a/Frontend/src/Templates.js +++ b/Frontend/src/Templates.js @@ -5,6 +5,10 @@ var fs = require('fs'); var ejs = require('ejs'); -exports.PizzaMenu_OneItem = ejs.compile(fs.readFileSync('./Frontend/templates/PizzaMenu_OneItem.ejs', "utf8")); +//exports.PizzaMenu_OneItem = ejs.compile(fs.readFileSync('./Frontend/templates/PizzaMenu_OneItem.ejs', "utf8")); -exports.PizzaCart_OneItem = ejs.compile(fs.readFileSync('./Frontend/templates/PizzaCart_OneItem.ejs', "utf8")); +exports.PizzaMenu_OneItem = ejs.compile("<%\r\n\r\nfunction getIngredientsArray(pizza) {\r\n var content = pizza.content;\r\n var result = [];\r\n\r\n\r\n Object.keys(content).forEach(function(key){\r\n\r\n result = result.concat(content[key]);\r\n });\r\n return result;\r\n}\r\n\r\n %>\r\n
\r\n
\r\n <% if(pizza.is_new) { %>\r\n Нова\r\n <% } else if(pizza.is_popular) {%>\r\n Популярна\r\n <% } %>\r\n \" alt=\"Pizza\"> \r\n
\r\n

<%= pizza.title %>

\r\n

<%= pizza.type %>

\r\n

\r\n <%= getIngredientsArray(pizza).join(\", \") %>\r\n

\r\n
\r\n <% if (pizza.small_size){ %>\r\n
\r\n
\r\n <%= pizza.small_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.small_size.weight %>\r\n
\r\n

\r\n <%= pizza.small_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n <% if (pizza.big_size) { %>\r\n
\r\n
\r\n <%= pizza.big_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.big_size.weight %>\r\n
\r\n

\r\n <%= pizza.big_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n
\r\n
"); + +//exports.PizzaCart_OneItem = ejs.compile(fs.readFileSync('./Frontend/templates/PizzaCart_OneItem.ejs', "utf8")); + +exports.PizzaCart_OneItem = ejs.compile("
\r\n\t\t\t \"Піца\"\r\n\t\t\t

\r\n\t\t\t <%= pizza.title %> (<%=size%><%if(size==pizza.small_size){%>Мала<%}else if(size==pizza.big_size){%>Велика<%} %>) \r\n\t\t\t

\r\n\t\t\t
\r\n\t\t\t \r\n\t\t\t 30\r\n\t\t\t \r\n\t\t\t 160\r\n\t\t\t
\r\n\t\t\t
\r\n\t\t\t Ціна: <%= pizza[size].price %> грн.\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t <%= quantity %>\r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t
\r\n\t\t\t
"); diff --git a/Frontend/src/main.js b/Frontend/src/main.js index 292a17032..9694ec332 100644 --- a/Frontend/src/main.js +++ b/Frontend/src/main.js @@ -8,6 +8,11 @@ $(function(){ var PizzaCart = require('./pizza/PizzaCart'); var Pizza_List = require('./Pizza_List'); + API.getPizzaList(function(err, pizza){ + if (err){ + return; + } + PizzaCart.initialiseCart(); PizzaMenu.initialiseMenu(); diff --git a/Frontend/src/pizza/PizzaCart.js b/Frontend/src/pizza/PizzaCart.js index 17f30f78c..453803932 100644 --- a/Frontend/src/pizza/PizzaCart.js +++ b/Frontend/src/pizza/PizzaCart.js @@ -9,17 +9,46 @@ var PizzaSize = { Small: "small_size" }; +//Змінна в якій зберігаються перелік піц в кошику +//var Cart = []; + //Змінна в якій зберігаються перелік піц в кошику var Cart = []; +var cart_map = []; +var count = 0; +//var totalPrice=0; + +//HTML едемент куди будуть додаватися піци +var $cart = $("#cartList"); //HTML едемент куди будуть додаватися піци -var $cart = $("#cart"); +//var $cart = $("#cart"); function addToCart(pizza, size) { //Додавання однієї піци в кошик покупок + var cart_id = cart_map[pizza.id]; + + if (cart_id && (cart_id[size] || cart_id[size] === 0)){ + Cart[cart_id[size]].quantity += 1; + + } else { + if (!cart_map[pizza.id]){ + cart_map[pizza.id] = []; + } + cart_map[pizza.id][size] = + Cart.push({ + pizza: pizza, + size: size, + // price: pizza.size.price, + quantity: 1 + }) - 1; + } + //Оновити вміст кошика на сторінці + updateCart(); + //Приклад реалізації, можна робити будь-яким іншим способом - Cart.push({ +/* Cart.push({ pizza: pizza, size: size, quantity: 1 @@ -27,22 +56,41 @@ function addToCart(pizza, size) { //Оновити вміст кошика на сторінці updateCart(); + */ } function removeFromCart(cart_item) { //Видалити піцу з кошика //TODO: треба зробити + if (cart_item.cart_id){ + Cart.splice(cart_item.cart_id, 1); + + } + //Після видалення оновити відображення updateCart(); + + //Після видалення оновити відображення + // updateCart(); } function initialiseCart() { //Фукнція віпрацьвуватиме при завантаженні сторінки //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його //TODO: ... + + //Фукнція віпрацьвуватиме при завантаженні сторінки + //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його + //TODO: ... + var cart = localStorage.getItem("cart"); + if (cart) + Cart = JSON.parse(cart); + + $("#clear").click(clearCart); updateCart(); + // updateCart(); } function getPizzaInCart() { @@ -50,7 +98,22 @@ function getPizzaInCart() { return Cart; } +function clearCart(){ + Cart = []; + cart_map = []; + + + updateCart(); + count = 0; + //totalPrice=0; + + $("#count").html(count); + // $("#sumNum").html(totalPrice); +} + function updateCart() { + + //Функція викликається при зміні вмісту кошика //Тут можна наприклад показати оновлений кошик на екрані та зберегти вміт кошика в Local Storage @@ -58,24 +121,90 @@ function updateCart() { $cart.html(""); //Онволення однієї піци - function showOnePizzaInCart(cart_item) { + function showOnePizzaInCart(cart_item, id, arr) { var html_code = Templates.PizzaCart_OneItem(cart_item); + cart_item.cart_id = id; + var $node = $(html_code); $node.find(".plus").click(function(){ //Збільшуємо кількість замовлених піц cart_item.quantity += 1; + count +=1; + // totalPrice+=cart_item.price; + //Оновлюємо відображення + updateCart(); + }); + $node.find(".minus").click(function(){ + + if (cart_item.quantity > 1){ + cart_item.quantity -= 1; + // totalPrice-=cart_item.price; + count -=1; + } + //Оновлюємо відображення updateCart(); }); + + $node.find(".count-clear").click(function(){ + + count -= cart_item.quantity; + // totalPrice-=(cart_item.price*cart_item.quantity); + $("#count").html(count); + // $("#sumNum").html(totalPrice); + arr.splice(id, 1); + + updateCart(); + }); + count = 0; + // totalPrice=0; + if(Cart.length != 0){ + Cart.forEach(function(pizza){ + count += pizza.quantity; + // totalPrice+=(pizza.quantity*pizza.price); + }); + } +// else{ count = 0;totalPrice=0;} + else count=0; + $("#count").html(count); + // $("#sumNum").html(totalPrice); + $cart.append($node); } Cart.forEach(showOnePizzaInCart); + + localStorage.setItem("cart", JSON.stringify(Cart)); + + + //Функція викликається при зміні вмісту кошика + //Тут можна наприклад показати оновлений кошик на екрані та зберегти вміт кошика в Local Storage + //Очищаємо старі піци в кошику +/* $cart.html(""); + + //Онволення однієї піци + function showOnePizzaInCart(cart_item) { + var html_code = Templates.PizzaCart_OneItem(cart_item); + + var $node = $(html_code); + $node.find(".plus").click(function(){ + //Збільшуємо кількість замовлених піц + cart_item.quantity += 1; + + //Оновлюємо відображення + updateCart(); + }); + + $cart.append($node); + } + + Cart.forEach(showOnePizzaInCart); +*/ } exports.removeFromCart = removeFromCart; diff --git a/Frontend/src/pizza/PizzaMenu.js b/Frontend/src/pizza/PizzaMenu.js index c08ee2d59..6893298d5 100644 --- a/Frontend/src/pizza/PizzaMenu.js +++ b/Frontend/src/pizza/PizzaMenu.js @@ -28,12 +28,71 @@ function showPizzaList(list) { $pizza_list.append($node); } + $("#pizzaNum").html(list.length); + list.forEach(showOnePizza); +/* + //Очищаємо старі піци в кошику + $pizza_list.html(""); + + //Онволення однієї піци + function showOnePizza(pizza) { + var html_code = Templates.PizzaMenu_OneItem({pizza: pizza}); + + var $node = $(html_code); + + $node.find(".buy-big").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Big); + }); + $node.find(".buy-small").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Small); + }); + + $pizza_list.append($node); + } + + list.forEach(showOnePizza); + */ } function filterPizza(filter) { //Масив куди потраплять піци які треба показати var pizza_shown = []; + var filt = filter.split(","); + + + Pizza_List.forEach(function(pizza){ + //Якщо піка відповідає фільтру + //pizza_shown.push(pizza); + //var ingridient = getIngredientsArray(pizza); + var checked = []; + filt.forEach(function(f){ + //if(checked) return; + if(f.charAt(0) == '!'){ + var fil = f.substring(1); + if(!(fil in pizza.content)){ + checked.push(true); + } + else checked.push(false); + } else { + if(f in pizza.content) + checked.push(true); + else checked.push(false); + } + + //TODO: зробити фільтри + }); + function isTrue(element, index, array) { + return element == true; + } + if(checked.every(isTrue)) pizza_shown.push(pizza); +}); + + //Показати відфільтровані піци + showPizzaList(pizza_shown); + /* + //Масив куди потраплять піци які треба показати + var pizza_shown = []; Pizza_List.forEach(function(pizza){ //Якщо піка відповідає фільтру @@ -44,11 +103,59 @@ function filterPizza(filter) { //Показати відфільтровані піци showPizzaList(pizza_shown); + */ } function initialiseMenu() { //Показуємо усі піци - showPizzaList(Pizza_List) + showPizzaList(Pizza_List); + + $("#filter-button-meat").click(function(){ + $(".allPizzas").html("М'ясні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('meat'); + }); + + $("#filter-button-pineapples").click(function(){ + $(".allPizzas").html("Піци з ананасом"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('pineapple'); + }); + + $("#filter-button-mushrooms").click(function(){ + $(".allPizzas").html("Грибні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('mushroom'); + }); + + $("#filter-button-ocean").click(function(){ + $(".allPizzas").html("Піци з морепродуктами"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('ocean'); + }); + + $("#filter-button-vega").click(function(){ + console.log("Vega"); + $(".allPizzas").html("Вегетаріанські піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('!meat,!ocean,!mushroom'); + }); + + $("#filter-button-all").click(function(){ + $(".allPizzas").html("Усі піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + showPizzaList(Pizza_List); + + }); + + //Показуємо усі піци +// showPizzaList(Pizza_List) } exports.filterPizza = filterPizza; diff --git a/Frontend/www/assets/js/main-cpy.js b/Frontend/www/assets/js/main-cpy.js new file mode 100644 index 000000000..1aa8a3bbf --- /dev/null +++ b/Frontend/www/assets/js/main-cpy.js @@ -0,0 +1,1848 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\r\n
\r\n
\r\n <% if(pizza.is_new) { %>\r\n Нова\r\n <% } else if(pizza.is_popular) {%>\r\n Популярна\r\n <% } %>\r\n \" alt=\"Pizza\"> \r\n
\r\n

<%= pizza.title %>

\r\n

<%= pizza.type %>

\r\n

\r\n <%= getIngredientsArray(pizza).join(\", \") %>\r\n

\r\n
\r\n <% if (pizza.small_size){ %>\r\n
\r\n
\r\n <%= pizza.small_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.small_size.weight %>\r\n
\r\n

\r\n <%= pizza.small_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n <% if (pizza.big_size) { %>\r\n
\r\n
\r\n <%= pizza.big_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.big_size.weight %>\r\n
\r\n

\r\n <%= pizza.big_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n
\r\n
"); + +exports.PizzaCart_OneItem = ejs.compile("
\r\n\t\t\t \"Піца\"\r\n\t\t\t

\r\n\t\t\t <%= pizza.title %> (<%=size%><%if(size==pizza.small_size){%>Мала<%}else if(size==pizza.big_size){%>Велика<%} %>) \r\n\t\t\t

\r\n\t\t\t
\r\n\t\t\t \r\n\t\t\t 30\r\n\t\t\t \r\n\t\t\t 160\r\n\t\t\t
\r\n\t\t\t
\r\n\t\t\t Ціна: <%= pizza[size].price %> грн.\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t <%= quantity %>\r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t
\r\n\t\t\t
"); + +},{"ejs":6}],3:[function(require,module,exports){ +/** + * Created by chaika on 25.01.16. + */ + +$(function(){ + //This code will execute when the page is ready + var PizzaMenu = require('./pizza/PizzaMenu'); + var PizzaCart = require('./pizza/PizzaCart'); + var Pizza_List = require('./Pizza_List'); + + PizzaCart.initialiseCart(); + PizzaMenu.initialiseMenu(); + + +}); +},{"./Pizza_List":1,"./pizza/PizzaCart":4,"./pizza/PizzaMenu":5}],4:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); + +//Перелік розмірів піци +var PizzaSize = { + Big: "big_size", + Small: "small_size" +}; + +//Змінна в якій зберігаються перелік піц в кошику +var Cart = []; +var cart_map = []; +var count = 0; +//var totalPrice=0; + +//HTML едемент куди будуть додаватися піци +var $cart = $("#cartList"); + +function addToCart(pizza, size) { + + var cart_id = cart_map[pizza.id]; + + if (cart_id && (cart_id[size] || cart_id[size] === 0)){ + Cart[cart_id[size]].quantity += 1; + + } else { + if (!cart_map[pizza.id]){ + cart_map[pizza.id] = []; + } + cart_map[pizza.id][size] = + Cart.push({ + pizza: pizza, + size: size, + // price: pizza.size.price, + quantity: 1 + }) - 1; + } + + //Оновити вміст кошика на сторінці + updateCart(); +} + +function removeFromCart(cart_item) { + //Видалити піцу з кошика + //TODO: треба зробити + + if (cart_item.cart_id){ + Cart.splice(cart_item.cart_id, 1); + + } + + //Після видалення оновити відображення + updateCart(); +} + +function initialiseCart() { + //Фукнція віпрацьвуватиме при завантаженні сторінки + //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його + //TODO: ... + var cart = localStorage.getItem("cart"); + if (cart) + Cart = JSON.parse(cart); + + $("#clear").click(clearCart); + + updateCart(); +} + +function clearCart(){ + Cart = []; + cart_map = []; + + + updateCart(); + count = 0; + //totalPrice=0; + + $("#count").html(count); + // $("#sumNum").html(totalPrice); +} + +function getPizzaInCart() { + //Повертає піци які зберігаються в кошику + return Cart; +} + +function updateCart() { + //Функція викликається при зміні вмісту кошика + //Тут можна наприклад показати оновлений кошик на екрані та зберегти вміт кошика в Local Storage + + //Очищаємо старі піци в кошику + $cart.html(""); + + //Онволення однієї піци + function showOnePizzaInCart(cart_item, id, arr) { + var html_code = Templates.PizzaCart_OneItem(cart_item); + + cart_item.cart_id = id; + + var $node = $(html_code); + + $node.find(".plus").click(function(){ + //Збільшуємо кількість замовлених піц + cart_item.quantity += 1; + count +=1; + // totalPrice+=cart_item.price; + //Оновлюємо відображення + updateCart(); + }); + + $node.find(".minus").click(function(){ + + if (cart_item.quantity > 1){ + cart_item.quantity -= 1; + // totalPrice-=cart_item.price; + count -=1; + } + + //Оновлюємо відображення + updateCart(); + }); + + + $node.find(".count-clear").click(function(){ + + count -= cart_item.quantity; + // totalPrice-=(cart_item.price*cart_item.quantity); + $("#count").html(count); + // $("#sumNum").html(totalPrice); + arr.splice(id, 1); + + updateCart(); + }); + count = 0; + // totalPrice=0; + if(Cart.length != 0){ + Cart.forEach(function(pizza){ + count += pizza.quantity; + // totalPrice+=(pizza.quantity*pizza.price); + }); + } +// else{ count = 0;totalPrice=0;} + else count=0; + $("#count").html(count); + // $("#sumNum").html(totalPrice); + + $cart.append($node); + } + + Cart.forEach(showOnePizzaInCart); + + localStorage.setItem("cart", JSON.stringify(Cart)); +} + +exports.removeFromCart = removeFromCart; +exports.addToCart = addToCart; + +exports.getPizzaInCart = getPizzaInCart; +exports.initialiseCart = initialiseCart; + +exports.PizzaSize = PizzaSize; +},{"../Templates":2}],5:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); +var PizzaCart = require('./PizzaCart'); +var Pizza_List = require('../Pizza_List'); + +//HTML едемент куди будуть додаватися піци +var $pizza_list = $("#pizza_list"); + +function showPizzaList(list) { + //Очищаємо старі піци в кошику + $pizza_list.html(""); + + //Онволення однієї піци + function showOnePizza(pizza) { + var html_code = Templates.PizzaMenu_OneItem({pizza: pizza}); + + var $node = $(html_code); + + $node.find(".buy-big").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Big); + }); + $node.find(".buy-small").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Small); + }); + + $pizza_list.append($node); + } + + $("#pizzaNum").html(list.length); + + list.forEach(showOnePizza); +} + +function filterPizza(filter) { + //Масив куди потраплять піци які треба показати + var pizza_shown = []; + var filt = filter.split(","); + + + Pizza_List.forEach(function(pizza){ + //Якщо піка відповідає фільтру + //pizza_shown.push(pizza); + //var ingridient = getIngredientsArray(pizza); + var checked = []; + filt.forEach(function(f){ + //if(checked) return; + if(f.charAt(0) == '!'){ + var fil = f.substring(1); + if(!(fil in pizza.content)){ + checked.push(true); + } + else checked.push(false); + } else { + if(f in pizza.content) + checked.push(true); + else checked.push(false); + } + + //TODO: зробити фільтри + }); + function isTrue(element, index, array) { + return element == true; + } + if(checked.every(isTrue)) pizza_shown.push(pizza); +}); + + //Показати відфільтровані піци + showPizzaList(pizza_shown); +} + +function initialiseMenu() { + //Показуємо усі піци + showPizzaList(Pizza_List); + + $("#filter-button-meat").click(function(){ + $(".allPizzas").html("М'ясні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('meat'); + }); + + $("#filter-button-pineapples").click(function(){ + $(".allPizzas").html("Піци з ананасом"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('pineapple'); + }); + + $("#filter-button-mushrooms").click(function(){ + $(".allPizzas").html("Грибні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('mushroom'); + }); + + $("#filter-button-ocean").click(function(){ + $(".allPizzas").html("Піци з морепродуктами"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('ocean'); + }); + + $("#filter-button-vega").click(function(){ + console.log("Vega"); + $(".allPizzas").html("Вегетаріанські піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('!meat,!ocean,!mushroom'); + }); + + $("#filter-button-all").click(function(){ + $(".allPizzas").html("Усі піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + showPizzaList(Pizza_List); + + }); +} + +exports.filterPizza = filterPizza; +exports.initialiseMenu = initialiseMenu; +},{"../Pizza_List":1,"../Templates":2,"./PizzaCart":4}],6:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +'use strict'; + +/** + * @file Embedded JavaScript templating engine. + * @author Matthew Eernisse + * @author Tiancheng "Timothy" Gu + * @project EJS + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0} + */ + +/** + * EJS internal functions. + * + * Technically this "module" lies in the same file as {@link module:ejs}, for + * the sake of organization all the private functions re grouped into this + * module. + * + * @module ejs-internal + * @private + */ + +/** + * Embedded JavaScript templating engine. + * + * @module ejs + * @public + */ + +var fs = require('fs') + , utils = require('./utils') + , scopeOptionWarned = false + , _VERSION_STRING = require('../package.json').version + , _DEFAULT_DELIMITER = '%' + , _DEFAULT_LOCALS_NAME = 'locals' + , _REGEX_STRING = '(<%%|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)' + , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context' + , 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace' + , 'strict', 'localsName' + ] + , _TRAILING_SEMCOL = /;\s*$/ + , _BOM = /^\uFEFF/; + +/** + * EJS template function cache. This can be a LRU object from lru-cache NPM + * module. By default, it is {@link module:utils.cache}, a simple in-process + * cache that grows continuously. + * + * @type {Cache} + */ + +exports.cache = utils.cache; + +/** + * Name of the object containing the locals. + * + * This variable is overriden by {@link Options}`.localsName` if it is not + * `undefined`. + * + * @type {String} + * @public + */ + +exports.localsName = _DEFAULT_LOCALS_NAME; + +/** + * Get the path to the included file from the parent file path and the + * specified path. + * + * @param {String} name specified path + * @param {String} filename parent file path + * @return {String} + */ + +exports.resolveInclude = function(name, filename) { + var path = require('path') + , dirname = path.dirname + , extname = path.extname + , resolve = path.resolve + , includePath = resolve(dirname(filename), name) + , ext = extname(name); + if (!ext) { + includePath += '.ejs'; + } + return includePath; +}; + +/** + * Get the template from a string or a file, either compiled on-the-fly or + * read from cache (if enabled), and cache the template if needed. + * + * If `template` is not set, the file specified in `options.filename` will be + * read. + * + * If `options.cache` is true, this function reads the file from + * `options.filename` so it must be set prior to calling this function. + * + * @memberof module:ejs-internal + * @param {Options} options compilation options + * @param {String} [template] template source + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned. + * @static + */ + +function handleCache(options, template) { + var fn + , path = options.filename + , hasTemplate = arguments.length > 1; + + if (options.cache) { + if (!path) { + throw new Error('cache option requires a filename'); + } + fn = exports.cache.get(path); + if (fn) { + return fn; + } + if (!hasTemplate) { + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + } + else if (!hasTemplate) { + // istanbul ignore if: should not happen at all + if (!path) { + throw new Error('Internal EJS error: no file name or template ' + + 'provided'); + } + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + fn = exports.compile(template, options); + if (options.cache) { + exports.cache.set(path, fn); + } + return fn; +} + +/** + * Get the template function. + * + * If `options.cache` is `true`, then the template is cached. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned + * @static + */ + +function includeFile(path, options) { + var opts = utils.shallowCopy({}, options); + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + opts.filename = exports.resolveInclude(path, opts.filename); + return handleCache(opts); +} + +/** + * Get the JavaScript source of an included file. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {String} + * @static + */ + +function includeSource(path, options) { + var opts = utils.shallowCopy({}, options) + , includePath + , template; + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + includePath = exports.resolveInclude(path, opts.filename); + template = fs.readFileSync(includePath).toString().replace(_BOM, ''); + + opts.filename = includePath; + var templ = new Template(template, opts); + templ.generateSource(); + return templ.source; +} + +/** + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and + * `lineno`. + * + * @implements RethrowCallback + * @memberof module:ejs-internal + * @param {Error} err Error object + * @param {String} str EJS source + * @param {String} filename file name of the EJS file + * @param {String} lineno line number of the error + * @static + */ + +function rethrow(err, str, filename, lineno){ + var lines = str.split('\n') + , start = Math.max(lineno - 3, 0) + , end = Math.min(lines.length, lineno + 3); + + // Error context + var context = lines.slice(start, end).map(function (line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' >> ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'ejs') + ':' + + lineno + '\n' + + context + '\n\n' + + err.message; + + throw err; +} + +/** + * Copy properties in data object that are recognized as options to an + * options object. + * + * This is used for compatibility with earlier versions of EJS and Express.js. + * + * @memberof module:ejs-internal + * @param {Object} data data object + * @param {Options} opts options object + * @static + */ + +function cpOptsInData(data, opts) { + _OPTS.forEach(function (p) { + if (typeof data[p] != 'undefined') { + opts[p] = data[p]; + } + }); +} + +/** + * Compile the given `str` of ejs into a template function. + * + * @param {String} template EJS template + * + * @param {Options} opts compilation options + * + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `opts.client`, either type might be returned. + * @public + */ + +exports.compile = function compile(template, opts) { + var templ; + + // v1 compat + // 'scope' is 'context' + // FIXME: Remove this in a future version + if (opts && opts.scope) { + if (!scopeOptionWarned){ + console.warn('`scope` option is deprecated and will be removed in EJS 3'); + scopeOptionWarned = true; + } + if (!opts.context) { + opts.context = opts.scope; + } + delete opts.scope; + } + templ = new Template(template, opts); + return templ.compile(); +}; + +/** + * Render the given `template` of ejs. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} template EJS template + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @return {String} + * @public + */ + +exports.render = function (template, data, opts) { + data = data || {}; + opts = opts || {}; + var fn; + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 2) { + cpOptsInData(data, opts); + } + + return handleCache(opts, template)(data); +}; + +/** + * Render an EJS file at the given `path` and callback `cb(err, str)`. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} path path to the EJS file + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @param {RenderFileCallback} cb callback + * @public + */ + +exports.renderFile = function () { + var args = Array.prototype.slice.call(arguments) + , path = args.shift() + , cb = args.pop() + , data = args.shift() || {} + , opts = args.pop() || {} + , result; + + // Don't pollute passed in opts obj with new vals + opts = utils.shallowCopy({}, opts); + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 3) { + // Express 4 + if (data.settings && data.settings['view options']) { + cpOptsInData(data.settings['view options'], opts); + } + // Express 3 and lower + else { + cpOptsInData(data, opts); + } + } + opts.filename = path; + + try { + result = handleCache(opts)(data); + } + catch(err) { + return cb(err); + } + return cb(null, result); +}; + +/** + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}. + * @public + */ + +exports.clearCache = function () { + exports.cache.reset(); +}; + +function Template(text, opts) { + opts = opts || {}; + var options = {}; + this.templateText = text; + this.mode = null; + this.truncate = false; + this.currentLine = 1; + this.source = ''; + this.dependencies = []; + options.client = opts.client || false; + options.escapeFunction = opts.escape || utils.escapeXML; + options.compileDebug = opts.compileDebug !== false; + options.debug = !!opts.debug; + options.filename = opts.filename; + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER; + options.strict = opts.strict || false; + options.context = opts.context; + options.cache = opts.cache || false; + options.rmWhitespace = opts.rmWhitespace; + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME; + + if (options.strict) { + options._with = false; + } + else { + options._with = typeof opts._with != 'undefined' ? opts._with : true; + } + + this.opts = options; + + this.regex = this.createRegex(); +} + +Template.modes = { + EVAL: 'eval' +, ESCAPED: 'escaped' +, RAW: 'raw' +, COMMENT: 'comment' +, LITERAL: 'literal' +}; + +Template.prototype = { + createRegex: function () { + var str = _REGEX_STRING + , delim = utils.escapeRegExpChars(this.opts.delimiter); + str = str.replace(/%/g, delim); + return new RegExp(str); + } + +, compile: function () { + var src + , fn + , opts = this.opts + , prepended = '' + , appended = '' + , escape = opts.escapeFunction; + + if (opts.rmWhitespace) { + // Have to use two separate replace here as `^` and `$` operators don't + // work well with `\r`. + this.templateText = + this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, ''); + } + + // Slurp spaces and tabs before <%_ and after _%> + this.templateText = + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>'); + + if (!this.source) { + this.generateSource(); + prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n'; + if (opts._with !== false) { + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n'; + appended += ' }' + '\n'; + } + appended += ' return __output.join("");' + '\n'; + this.source = prepended + this.source + appended; + } + + if (opts.compileDebug) { + src = 'var __line = 1' + '\n' + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n' + + ' , __filename = ' + (opts.filename ? + JSON.stringify(opts.filename) : 'undefined') + ';' + '\n' + + 'try {' + '\n' + + this.source + + '} catch (e) {' + '\n' + + ' rethrow(e, __lines, __filename, __line);' + '\n' + + '}' + '\n'; + } + else { + src = this.source; + } + + if (opts.debug) { + console.log(src); + } + + if (opts.client) { + src = 'escape = escape || ' + escape.toString() + ';' + '\n' + src; + if (opts.compileDebug) { + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src; + } + } + + if (opts.strict) { + src = '"use strict";\n' + src; + } + + try { + fn = new Function(opts.localsName + ', escape, include, rethrow', src); + } + catch(e) { + // istanbul ignore else + if (e instanceof SyntaxError) { + if (opts.filename) { + e.message += ' in ' + opts.filename; + } + e.message += ' while compiling ejs'; + } + throw e; + } + + if (opts.client) { + fn.dependencies = this.dependencies; + return fn; + } + + // Return a callable function which will execute the function + // created by the source-code, with the passed data as locals + // Adds a local `include` function which allows full recursive include + var returnedFn = function (data) { + var include = function (path, includeData) { + var d = utils.shallowCopy({}, data); + if (includeData) { + d = utils.shallowCopy(d, includeData); + } + return includeFile(path, opts)(d); + }; + return fn.apply(opts.context, [data || {}, escape, include, rethrow]); + }; + returnedFn.dependencies = this.dependencies; + return returnedFn; + } + +, generateSource: function () { + var self = this + , matches = this.parseTemplateText() + , d = this.opts.delimiter; + + if (matches && matches.length) { + if (this.opts.compileDebug && this.opts.filename) { + this.source = ' ; __lines = ' + JSON.stringify(this.templateText) + '\n'; + this.source += ' ; __filename = "' + this.opts.filename.replace(/\\/g, '/') + '"\n'; + } + matches.forEach(function (line, index) { + var opening + , closing + , include + , includeOpts + , includeSrc; + // If this is an opening tag, check for closing tags + // FIXME: May end up with some false positives here + // Better to store modes as k/v with '<' + delimiter as key + // Then this can simply check against the map + if ( line.indexOf('<' + d) === 0 // If it is a tag + && line.indexOf('<' + d + d) !== 0) { // and is not escaped + closing = matches[index + 2]; + if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) { + throw new Error('Could not find matching close tag for "' + line + '".'); + } + } + // HACK: backward-compat `include` preprocessor directives + if ((include = line.match(/^\s*include\s+(\S+)/))) { + opening = matches[index - 1]; + // Must be in EVAL or RAW mode + if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) { + includeOpts = utils.shallowCopy({}, self.opts); + includeSrc = includeSource(include[1], includeOpts); + includeSrc = ' ; (function(){' + '\n' + includeSrc + + ' ; })()' + '\n'; + self.source += includeSrc; + self.dependencies.push(exports.resolveInclude(include[1], + includeOpts.filename)); + return; + } + } + self.scanLine(line); + }); + } + + } + +, parseTemplateText: function () { + var str = this.templateText + , pat = this.regex + , result = pat.exec(str) + , arr = [] + , firstPos + , lastPos; + + while (result) { + firstPos = result.index; + lastPos = pat.lastIndex; + + if (firstPos !== 0) { + arr.push(str.substring(0, firstPos)); + str = str.slice(firstPos); + } + + arr.push(result[0]); + str = str.slice(result[0].length); + result = pat.exec(str); + } + + if (str) { + arr.push(str); + } + + return arr; + } + +, scanLine: function (line) { + var self = this + , d = this.opts.delimiter + , newLineCount = 0; + + function _addOutput() { + if (self.truncate) { + // Only replace single leading linebreak in the line after + // -%> tag -- this is the single, trailing linebreak + // after the tag that the truncation mode replaces + // Handle Win / Unix / old Mac linebreaks -- do the \r\n + // combo first in the regex-or + line = line.replace(/^(?:\r\n|\r|\n)/, '') + self.truncate = false; + } + else if (self.opts.rmWhitespace) { + // Gotta be more careful here. + // .replace(/^(\s*)\n/, '$1') might be more appropriate here but as + // rmWhitespace already removes trailing spaces anyway so meh. + line = line.replace(/^\n/, ''); + } + if (!line) { + return; + } + + // Preserve literal slashes + line = line.replace(/\\/g, '\\\\'); + + // Convert linebreaks + line = line.replace(/\n/g, '\\n'); + line = line.replace(/\r/g, '\\r'); + + // Escape double-quotes + // - this will be the delimiter during execution + line = line.replace(/"/g, '\\"'); + self.source += ' ; __append("' + line + '")' + '\n'; + } + + newLineCount = (line.split('\n').length - 1); + + switch (line) { + case '<' + d: + case '<' + d + '_': + this.mode = Template.modes.EVAL; + break; + case '<' + d + '=': + this.mode = Template.modes.ESCAPED; + break; + case '<' + d + '-': + this.mode = Template.modes.RAW; + break; + case '<' + d + '#': + this.mode = Template.modes.COMMENT; + break; + case '<' + d + d: + this.mode = Template.modes.LITERAL; + this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n'; + break; + case d + '>': + case '-' + d + '>': + case '_' + d + '>': + if (this.mode == Template.modes.LITERAL) { + _addOutput(); + } + + this.mode = null; + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0; + break; + default: + // In script mode, depends on type of tag + if (this.mode) { + // If '//' is found without a line break, add a line break. + switch (this.mode) { + case Template.modes.EVAL: + case Template.modes.ESCAPED: + case Template.modes.RAW: + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) { + line += '\n'; + } + } + switch (this.mode) { + // Just executing code + case Template.modes.EVAL: + this.source += ' ; ' + line + '\n'; + break; + // Exec, esc, and output + case Template.modes.ESCAPED: + this.source += ' ; __append(escape(' + + line.replace(_TRAILING_SEMCOL, '').trim() + '))' + '\n'; + break; + // Exec and output + case Template.modes.RAW: + this.source += ' ; __append(' + + line.replace(_TRAILING_SEMCOL, '').trim() + ')' + '\n'; + break; + case Template.modes.COMMENT: + // Do nothing + break; + // Literal <%% mode, append as raw output + case Template.modes.LITERAL: + _addOutput(); + break; + } + } + // In string mode, just add the output + else { + _addOutput(); + } + } + + if (self.opts.compileDebug && newLineCount) { + this.currentLine += newLineCount; + this.source += ' ; __line = ' + this.currentLine + '\n'; + } + } +}; + +/* + * Export the internal function for escaping XML so people + * can use for manual escaping if needed + * */ +exports.escapeXML = utils.escapeXML; + +/** + * Express.js support. + * + * This is an alias for {@link module:ejs.renderFile}, in order to support + * Express.js out-of-the-box. + * + * @func + */ + +exports.__express = exports.renderFile; + +// Add require support +/* istanbul ignore else */ +if (require.extensions) { + require.extensions['.ejs'] = function (module, filename) { + filename = filename || /* istanbul ignore next */ module.filename; + var options = { + filename: filename + , client: true + } + , template = fs.readFileSync(filename).toString() + , fn = exports.compile(template, options); + module._compile('module.exports = ' + fn.toString() + ';', filename); + }; +} + +/** + * Version of EJS. + * + * @readonly + * @type {String} + * @public + */ + +exports.VERSION = _VERSION_STRING; + +/* istanbul ignore if */ +if (typeof window != 'undefined') { + window.ejs = exports; +} + +},{"../package.json":8,"./utils":7,"fs":9,"path":10}],7:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +/** + * Private utility functions + * @module utils + * @private + */ + +'use strict'; + +var regExpChars = /[|\\{}()[\]^$+*?.]/g; + +/** + * Escape characters reserved in regular expressions. + * + * If `string` is `undefined` or `null`, the empty string is returned. + * + * @param {String} string Input string + * @return {String} Escaped string + * @static + * @private + */ +exports.escapeRegExpChars = function (string) { + // istanbul ignore if + if (!string) { + return ''; + } + return String(string).replace(regExpChars, '\\$&'); +}; + +var _ENCODE_HTML_RULES = { + '&': '&' + , '<': '<' + , '>': '>' + , '"': '"' + , "'": ''' + } + , _MATCH_HTML = /[&<>\'"]/g; + +function encode_char(c) { + return _ENCODE_HTML_RULES[c] || c; +}; + +/** + * Stringified version of constants used by {@link module:utils.escapeXML}. + * + * It is used in the process of generating {@link ClientFunction}s. + * + * @readonly + * @type {String} + */ + +var escapeFuncStr = + 'var _ENCODE_HTML_RULES = {\n' ++ ' "&": "&"\n' ++ ' , "<": "<"\n' ++ ' , ">": ">"\n' ++ ' , \'"\': """\n' ++ ' , "\'": "'"\n' ++ ' }\n' ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n' ++ 'function encode_char(c) {\n' ++ ' return _ENCODE_HTML_RULES[c] || c;\n' ++ '};\n'; + +/** + * Escape characters reserved in XML. + * + * If `markup` is `undefined` or `null`, the empty string is returned. + * + * @implements {EscapeCallback} + * @param {String} markup Input string + * @return {String} Escaped string + * @static + * @private + */ + +exports.escapeXML = function (markup) { + return markup == undefined + ? '' + : String(markup) + .replace(_MATCH_HTML, encode_char); +}; +exports.escapeXML.toString = function () { + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr +}; + +/** + * Copy all properties from one object to another, in a shallow fashion. + * + * @param {Object} to Destination object + * @param {Object} from Source object + * @return {Object} Destination object + * @static + * @private + */ +exports.shallowCopy = function (to, from) { + from = from || {}; + for (var p in from) { + to[p] = from[p]; + } + return to; +}; + +/** + * Simple in-process cache implementation. Does not implement limits of any + * sort. + * + * @implements Cache + * @static + * @private + */ +exports.cache = { + _data: {}, + set: function (key, val) { + this._data[key] = val; + }, + get: function (key) { + return this._data[key]; + }, + reset: function () { + this._data = {}; + } +}; + + +},{}],8:[function(require,module,exports){ +module.exports={ + "name": "ejs", + "description": "Embedded JavaScript templates", + "keywords": [ + "template", + "engine", + "ejs" + ], + "version": "2.4.2", + "author": { + "name": "Matthew Eernisse", + "email": "mde@fleegix.org", + "url": "http://fleegix.org" + }, + "contributors": [ + { + "name": "Timothy Gu", + "email": "timothygu99@gmail.com", + "url": "https://timothygu.github.io" + } + ], + "license": "Apache-2.0", + "main": "./lib/ejs.js", + "repository": { + "type": "git", + "url": "git://github.com/mde/ejs.git" + }, + "bugs": { + "url": "https://github.com/mde/ejs/issues" + }, + "homepage": "https://github.com/mde/ejs", + "dependencies": {}, + "devDependencies": { + "browserify": "^8.0.3", + "istanbul": "~0.3.5", + "jake": "^8.0.0", + "jsdoc": "^3.3.0-beta1", + "lru-cache": "^2.5.0", + "mocha": "^2.1.0", + "rimraf": "^2.2.8", + "uglify-js": "^2.4.16" + }, + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha", + "sample": "npm install express && node sample/index.js", + "coverage": "istanbul cover node_modules/mocha/bin/_mocha", + "doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*", + "devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*" + }, + "_id": "ejs@2.4.2", + "_shasum": "7057eb4812958fb731841cd9ca353343efe597b1", + "_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.4.2.tgz", + "_from": "ejs@>=2.4.1 <3.0.0", + "_npmVersion": "2.15.1", + "_nodeVersion": "4.4.4", + "_npmUser": { + "name": "mde", + "email": "mde@fleegix.org" + }, + "maintainers": [ + { + "name": "tjholowaychuk", + "email": "tj@vision-media.ca" + }, + { + "name": "mde", + "email": "mde@fleegix.org" + } + ], + "dist": { + "shasum": "7057eb4812958fb731841cd9ca353343efe597b1", + "tarball": "https://registry.npmjs.org/ejs/-/ejs-2.4.2.tgz" + }, + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/ejs-2.4.2.tgz_1464117640663_0.8193834638223052" + }, + "directories": {} +} + +},{}],9:[function(require,module,exports){ + +},{}],10:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; + +}).call(this,require('_process')) +},{"_process":11}],11:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = setTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + clearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + setTimeout(drainQueue, 0); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}]},{},[3]); + +function getElByClass(name, type) +{ + var r = []; + var re = new RegExp("(^|\\s)" + name + "(\\s|$)"); + var e = (type) ? getElByTag(type) : ((navigator.userAgent.indexOf("MSIE") >= 0) ? document.all : getElByTag("*")); + for ( var j = 0; j < e.length; j++ ) + if (re.test(attr(e[j], "class"))) + r.push( e[j] ) + return r; +} + +function attr(el, at, value) +{ + at = {'for': 'htmlFor', 'class': 'className'}[at] || at; + if(!value) + return el[at] || el.getAttribute(at) || ''; + else + { + el[at] = value; + if (el.setAttribute) + el.setAttribute(at, value); + } +} + +function getElByTag(tag, el) +{ + return (el || document).getElementsByTagName(tag); +} + +function getElByName(name) +{ + return document.getElementsByName(name); +} + +function getElById(id) +{ + return document.getElementById(id); +} \ No newline at end of file diff --git a/Frontend/www/assets/js/main-start.js b/Frontend/www/assets/js/main-start.js new file mode 100644 index 000000000..83d6aebe0 --- /dev/null +++ b/Frontend/www/assets/js/main-start.js @@ -0,0 +1,2033 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\n
\n
\n \" alt=\"Pizza\">\n\n <% if(pizza.is_new) { %>\n Нова\n <% } else if(pizza.is_popular) {%>\n Популярна\n <% } %>\n\n
\n <%= pizza.title %>\n
<%= pizza.type %>
\n
\n <%= getIngredientsArray(pizza).join(\", \") %>\n
\n
\n\n \n \n
\n
"); + +exports.PizzaCart_OneItem = ejs.compile("
\n <%= pizza.title %> (<%= size %>)\n
Ціна: <%= pizza[size].price %> грн.
\n
\n \n <%= quantity %>\n \n
\n
"); + +},{"ejs":8}],3:[function(require,module,exports){ +/** + * Created by chaika on 25.01.16. + */ + +$(function(){ + //This code will execute when the page is ready + var PizzaMenu = require('./pizza/PizzaMenu'); + var PizzaCart = require('./pizza/PizzaCart'); + var Pizza_List = require('./Pizza_List'); + + PizzaCart.initialiseCart(); + PizzaMenu.initialiseMenu(); + + +}); +},{"./Pizza_List":1,"./pizza/PizzaCart":4,"./pizza/PizzaMenu":5}],4:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); +var Storage = require('./Storage'); +//Перелік розмірів піци +var PizzaSize = { + Big: "big_size", + Small: "small_size" +}; + +//Змінна в якій зберігаються перелік піц в кошику +var Cart = []; + +//HTML едемент куди будуть додаватися піци +var $cart = $("#cart"); + +function addToCart(pizza, size) { + //Додавання однієї піци в кошик покупок + + //Приклад реалізації, можна робити будь-яким іншим способом + Cart.push({ + pizza: pizza, + size: size, + quantity: 1 + }); + + //Оновити вміст кошика на сторінці + updateCart(); +} + +function removeFromCart(cart_item) { + //Видалити піцу з кошика + //TODO: треба зробити + + //Після видалення оновити відображення + updateCart(); +} + +function initialiseCart() { + //Фукнція віпрацьвуватиме при завантаженні сторінки + //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його + //TODO: ... +var saved_pizza = Storage.get('cart'); + if(saved_pizza){ + Cart = saved_pizza; + } + + + updateCart(); +} + +function getPizzaInCart() { + //Повертає піци які зберігаються в кошику + return Cart; +} + +function updateCart() { + //Функція викликається при зміні вмісту кошика + //Тут можна наприклад показати оновлений кошик на екрані та зберегти вміт кошика в Local Storage + + //Очищаємо старі піци в кошику + $cart.html(""); + + //Онволення однієї піци + function showOnePizzaInCart(cart_item) { + var html_code = Templates.PizzaCart_OneItem(cart_item); + + var $node = $(html_code); + + $node.find(".plus").click(function(){ + //Збільшуємо кількість замовлених піц + cart_item.quantity += 1; + + //Оновлюємо відображення + updateCart(); + }); + + $cart.append($node); + } + + Cart.forEach(showOnePizzaInCart); + +} +Storage.set("cart",Cart); +exports.removeFromCart = removeFromCart; +exports.addToCart = addToCart; + +exports.getPizzaInCart = getPizzaInCart; +exports.initialiseCart = initialiseCart; + +exports.PizzaSize = PizzaSize; +},{"../Templates":2,"./Storage":6}],5:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); +var PizzaCart = require('./PizzaCart'); +var Pizza_List = require('../Pizza_List'); + +//HTML едемент куди будуть додаватися піци +var $pizza_list = $("#pizza_list"); + +function showPizzaList(list) { + //Очищаємо старі піци в кошику + $pizza_list.html(""); + + //Онволення однієї піци + function showOnePizza(pizza) { + var html_code = Templates.PizzaMenu_OneItem({pizza: pizza}); + + var $node = $(html_code); + + $node.find(".buy-big").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Big); + }); + $node.find(".buy-small").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Small); + }); + + $pizza_list.append($node); + } + + list.forEach(showOnePizza); +} + +function filterPizza(filter) { + //Масив куди потраплять піци які треба показати + var pizza_shown = []; + + Pizza_List.forEach(function(pizza){ + //Якщо піка відповідає фільтру + //pizza_shown.push(pizza); + + //TODO: зробити фільтри + }); + + //Показати відфільтровані піци + showPizzaList(pizza_shown); +} + +function initialiseMenu() { + //Показуємо усі піци + showPizzaList(Pizza_List) +} + +exports.filterPizza = filterPizza; +exports.initialiseMenu = initialiseMenu; +},{"../Pizza_List":1,"../Templates":2,"./PizzaCart":4}],6:[function(require,module,exports){ +var basil = require('basil.js'); +basil = new basil(); +exports.get = function(key) { + return basil.get(key); +}; +exports.set = function(key, value) { + return basil.set(key, value); +};/** + * Created by Angelina on 03.02.2016. + */ + +},{"basil.js":7}],7:[function(require,module,exports){ +(function () { + // Basil + var Basil = function (options) { + return Basil.utils.extend({}, Basil.plugins, new Basil.Storage().init(options)); + }; + + // Version + Basil.version = '0.4.2'; + + // Utils + Basil.utils = { + extend: function () { + var destination = typeof arguments[0] === 'object' ? arguments[0] : {}; + for (var i = 1; i < arguments.length; i++) { + if (arguments[i] && typeof arguments[i] === 'object') + for (var property in arguments[i]) + destination[property] = arguments[i][property]; + } + return destination; + }, + each: function (obj, fnIterator, context) { + if (this.isArray(obj)) { + for (var i = 0; i < obj.length; i++) + if (fnIterator.call(context, obj[i], i) === false) return; + } else if (obj) { + for (var key in obj) + if (fnIterator.call(context, obj[key], key) === false) return; + } + }, + tryEach: function (obj, fnIterator, fnError, context) { + this.each(obj, function (value, key) { + try { + return fnIterator.call(context, value, key); + } catch (error) { + if (this.isFunction(fnError)) { + try { + fnError.call(context, value, key, error); + } catch (error) {} + } + } + }, this); + }, + registerPlugin: function (methods) { + Basil.plugins = this.extend(methods, Basil.plugins); + } + }; + // Add some isType methods: isArguments, isBoolean, isFunction, isString, isArray, isNumber, isDate, isRegExp. + var types = ['Arguments', 'Boolean', 'Function', 'String', 'Array', 'Number', 'Date', 'RegExp'] + for (var i = 0; i < types.length; i++) { + Basil.utils['is' + types[i]] = (function (type) { + return function (obj) { + return Object.prototype.toString.call(obj) === '[object ' + type + ']'; + }; + })(types[i]); + } + + // Plugins + Basil.plugins = {}; + + // Options + Basil.options = Basil.utils.extend({ + namespace: 'b45i1', + storages: ['local', 'cookie', 'session', 'memory'], + expireDays: 365 + }, window.Basil ? window.Basil.options : {}); + + // Storage + Basil.Storage = function () { + var _salt = 'b45i1' + (Math.random() + 1) + .toString(36) + .substring(7), + _storages = {}, + _toStoragesArray = function (storages) { + if (Basil.utils.isArray(storages)) + return storages; + return Basil.utils.isString(storages) ? [storages] : []; + }, + _toStoredKey = function (namespace, path) { + var key = ''; + if (Basil.utils.isString(path) && path.length) + path = [path]; + if (Basil.utils.isArray(path) && path.length) + key = path.join('.'); + return key && namespace ? namespace + '.' + key : key; + }, + _toKeyName = function (namespace, key) { + if (!namespace) + return key; + return key.replace(new RegExp('^' + namespace + '.'), ''); + }, + _toStoredValue = function (value) { + return JSON.stringify(value); + }, + _fromStoredValue = function (value) { + return value ? JSON.parse(value) : null; + }; + + // HTML5 web storage interface + var webStorageInterface = { + engine: null, + check: function () { + try { + window[this.engine].setItem(_salt, true); + window[this.engine].removeItem(_salt); + } catch (e) { + return false; + } + return true; + }, + set: function (key, value, options) { + if (!key) + throw Error('invalid key'); + window[this.engine].setItem(key, value); + }, + get: function (key) { + return window[this.engine].getItem(key); + }, + remove: function (key) { + window[this.engine].removeItem(key); + }, + reset: function (namespace) { + for (var i = 0, key; i < window[this.engine].length; i++) { + key = window[this.engine].key(i); + if (!namespace || key.indexOf(namespace) === 0) { + this.remove(key); + i--; + } + } + }, + keys: function (namespace) { + var keys = []; + for (var i = 0, key; i < window[this.engine].length; i++) { + key = window[this.engine].key(i); + if (!namespace || key.indexOf(namespace) === 0) + keys.push(_toKeyName(namespace, key)); + } + return keys; + } + }; + + // local storage + _storages.local = Basil.utils.extend({}, webStorageInterface, { + engine: 'localStorage' + }); + // session storage + _storages.session = Basil.utils.extend({}, webStorageInterface, { + engine: 'sessionStorage' + }); + + // memory storage + _storages.memory = { + _hash: {}, + check: function () { + return true; + }, + set: function (key, value, options) { + if (!key) + throw Error('invalid key'); + this._hash[key] = value; + }, + get: function (key) { + return this._hash[key] || null; + }, + remove: function (key) { + delete this._hash[key]; + }, + reset: function (namespace) { + for (var key in this._hash) { + if (!namespace || key.indexOf(namespace) === 0) + this.remove(key); + } + }, + keys: function (namespace) { + var keys = []; + for (var key in this._hash) + if (!namespace || key.indexOf(namespace) === 0) + keys.push(_toKeyName(namespace, key)); + return keys; + } + }; + + // cookie storage + _storages.cookie = { + check: function () { + return navigator.cookieEnabled; + }, + set: function (key, value, options) { + if (!this.check()) + throw Error('cookies are disabled'); + options = options || {}; + if (!key) + throw Error('invalid key'); + var cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value); + // handle expiration days + if (options.expireDays) { + var date = new Date(); + date.setTime(date.getTime() + (options.expireDays * 24 * 60 * 60 * 1000)); + cookie += '; expires=' + date.toGMTString(); + } + // handle domain + if (options.domain && options.domain !== document.domain) { + var _domain = options.domain.replace(/^\./, ''); + if (document.domain.indexOf(_domain) === -1 || _domain.split('.').length <= 1) + throw Error('invalid domain'); + cookie += '; domain=' + options.domain; + } + // handle secure + if (options.secure === true) { + cookie += '; secure'; + } + document.cookie = cookie + '; path=/'; + }, + get: function (key) { + if (!this.check()) + throw Error('cookies are disabled'); + var encodedKey = encodeURIComponent(key); + var cookies = document.cookie ? document.cookie.split(';') : []; + // retrieve last updated cookie first + for (var i = cookies.length - 1, cookie; i >= 0; i--) { + cookie = cookies[i].replace(/^\s*/, ''); + if (cookie.indexOf(encodedKey + '=') === 0) + return decodeURIComponent(cookie.substring(encodedKey.length + 1, cookie.length)); + } + return null; + }, + remove: function (key) { + // remove cookie from main domain + this.set(key, '', { expireDays: -1 }); + // remove cookie from upper domains + var domainParts = document.domain.split('.'); + for (var i = domainParts.length; i >= 0; i--) { + this.set(key, '', { expireDays: -1, domain: '.' + domainParts.slice(- i).join('.') }); + } + }, + reset: function (namespace) { + var cookies = document.cookie ? document.cookie.split(';') : []; + for (var i = 0, cookie, key; i < cookies.length; i++) { + cookie = cookies[i].replace(/^\s*/, ''); + key = cookie.substr(0, cookie.indexOf('=')); + if (!namespace || key.indexOf(namespace) === 0) + this.remove(key); + } + }, + keys: function (namespace) { + if (!this.check()) + throw Error('cookies are disabled'); + var keys = [], + cookies = document.cookie ? document.cookie.split(';') : []; + for (var i = 0, cookie, key; i < cookies.length; i++) { + cookie = cookies[i].replace(/^\s*/, ''); + key = decodeURIComponent(cookie.substr(0, cookie.indexOf('='))); + if (!namespace || key.indexOf(namespace) === 0) + keys.push(_toKeyName(namespace, key)); + } + return keys; + } + }; + + return { + init: function (options) { + this.setOptions(options); + return this; + }, + setOptions: function (options) { + this.options = Basil.utils.extend({}, this.options || Basil.options, options); + }, + support: function (storage) { + return _storages.hasOwnProperty(storage); + }, + check: function (storage) { + if (this.support(storage)) + return _storages[storage].check(); + return false; + }, + set: function (key, value, options) { + options = Basil.utils.extend({}, this.options, options); + if (!(key = _toStoredKey(options.namespace, key))) + return false; + value = options.raw === true ? value : _toStoredValue(value); + var where = null; + // try to set key/value in first available storage + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { + _storages[storage].set(key, value, options); + where = storage; + return false; // break; + }, null, this); + if (!where) { + // key has not been set anywhere + return false; + } + // remove key from all other storages + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { + if (storage !== where) + _storages[storage].remove(key); + }, null, this); + return true; + }, + get: function (key, options) { + options = Basil.utils.extend({}, this.options, options); + if (!(key = _toStoredKey(options.namespace, key))) + return null; + var value = null; + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { + if (value !== null) + return false; // break if a value has already been found. + value = _storages[storage].get(key, options) || null; + value = options.raw === true ? value : _fromStoredValue(value); + }, function (storage, index, error) { + value = null; + }, this); + return value; + }, + remove: function (key, options) { + options = Basil.utils.extend({}, this.options, options); + if (!(key = _toStoredKey(options.namespace, key))) + return; + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { + _storages[storage].remove(key); + }, null, this); + }, + reset: function (options) { + options = Basil.utils.extend({}, this.options, options); + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { + _storages[storage].reset(options.namespace); + }, null, this); + }, + keys: function (options) { + options = options || {}; + var keys = []; + for (var key in this.keysMap(options)) + keys.push(key); + return keys; + }, + keysMap: function (options) { + options = Basil.utils.extend({}, this.options, options); + var map = {}; + Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { + Basil.utils.each(_storages[storage].keys(options.namespace), function (key) { + map[key] = Basil.utils.isArray(map[key]) ? map[key] : []; + map[key].push(storage); + }, this); + }, null, this); + return map; + } + }; + }; + + // Access to native storages, without namespace or basil value decoration + Basil.memory = new Basil.Storage().init({ storages: 'memory', namespace: null, raw: true }); + Basil.cookie = new Basil.Storage().init({ storages: 'cookie', namespace: null, raw: true }); + Basil.localStorage = new Basil.Storage().init({ storages: 'local', namespace: null, raw: true }); + Basil.sessionStorage = new Basil.Storage().init({ storages: 'session', namespace: null, raw: true }); + + // browser export + window.Basil = Basil; + + // AMD export + if (typeof define === 'function' && define.amd) { + define(function() { + return Basil; + }); + // commonjs export + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Basil; + } + +})(); + +},{}],8:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +'use strict'; + +/** + * @file Embedded JavaScript templating engine. + * @author Matthew Eernisse + * @author Tiancheng "Timothy" Gu + * @project EJS + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0} + */ + +/** + * EJS internal functions. + * + * Technically this "module" lies in the same file as {@link module:ejs}, for + * the sake of organization all the private functions re grouped into this + * module. + * + * @module ejs-internal + * @private + */ + +/** + * Embedded JavaScript templating engine. + * + * @module ejs + * @public + */ + +var fs = require('fs') + , utils = require('./utils') + , scopeOptionWarned = false + , _VERSION_STRING = require('../package.json').version + , _DEFAULT_DELIMITER = '%' + , _DEFAULT_LOCALS_NAME = 'locals' + , _REGEX_STRING = '(<%%|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)' + , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context' + , 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace' + , 'strict', 'localsName' + ] + , _TRAILING_SEMCOL = /;\s*$/ + , _BOM = /^\uFEFF/; + +/** + * EJS template function cache. This can be a LRU object from lru-cache NPM + * module. By default, it is {@link module:utils.cache}, a simple in-process + * cache that grows continuously. + * + * @type {Cache} + */ + +exports.cache = utils.cache; + +/** + * Name of the object containing the locals. + * + * This variable is overriden by {@link Options}`.localsName` if it is not + * `undefined`. + * + * @type {String} + * @public + */ + +exports.localsName = _DEFAULT_LOCALS_NAME; + +/** + * Get the path to the included file from the parent file path and the + * specified path. + * + * @param {String} name specified path + * @param {String} filename parent file path + * @return {String} + */ + +exports.resolveInclude = function(name, filename) { + var path = require('path') + , dirname = path.dirname + , extname = path.extname + , resolve = path.resolve + , includePath = resolve(dirname(filename), name) + , ext = extname(name); + if (!ext) { + includePath += '.ejs'; + } + return includePath; +}; + +/** + * Get the template from a string or a file, either compiled on-the-fly or + * read from cache (if enabled), and cache the template if needed. + * + * If `template` is not set, the file specified in `options.filename` will be + * read. + * + * If `options.cache` is true, this function reads the file from + * `options.filename` so it must be set prior to calling this function. + * + * @memberof module:ejs-internal + * @param {Options} options compilation options + * @param {String} [template] template source + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned. + * @static + */ + +function handleCache(options, template) { + var fn + , path = options.filename + , hasTemplate = arguments.length > 1; + + if (options.cache) { + if (!path) { + throw new Error('cache option requires a filename'); + } + fn = exports.cache.get(path); + if (fn) { + return fn; + } + if (!hasTemplate) { + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + } + else if (!hasTemplate) { + // istanbul ignore if: should not happen at all + if (!path) { + throw new Error('Internal EJS error: no file name or template ' + + 'provided'); + } + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + fn = exports.compile(template, options); + if (options.cache) { + exports.cache.set(path, fn); + } + return fn; +} + +/** + * Get the template function. + * + * If `options.cache` is `true`, then the template is cached. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned + * @static + */ + +function includeFile(path, options) { + var opts = utils.shallowCopy({}, options); + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + opts.filename = exports.resolveInclude(path, opts.filename); + return handleCache(opts); +} + +/** + * Get the JavaScript source of an included file. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {String} + * @static + */ + +function includeSource(path, options) { + var opts = utils.shallowCopy({}, options) + , includePath + , template; + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + includePath = exports.resolveInclude(path, opts.filename); + template = fs.readFileSync(includePath).toString().replace(_BOM, ''); + + opts.filename = includePath; + var templ = new Template(template, opts); + templ.generateSource(); + return templ.source; +} + +/** + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and + * `lineno`. + * + * @implements RethrowCallback + * @memberof module:ejs-internal + * @param {Error} err Error object + * @param {String} str EJS source + * @param {String} filename file name of the EJS file + * @param {String} lineno line number of the error + * @static + */ + +function rethrow(err, str, filename, lineno){ + var lines = str.split('\n') + , start = Math.max(lineno - 3, 0) + , end = Math.min(lines.length, lineno + 3); + + // Error context + var context = lines.slice(start, end).map(function (line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' >> ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'ejs') + ':' + + lineno + '\n' + + context + '\n\n' + + err.message; + + throw err; +} + +/** + * Copy properties in data object that are recognized as options to an + * options object. + * + * This is used for compatibility with earlier versions of EJS and Express.js. + * + * @memberof module:ejs-internal + * @param {Object} data data object + * @param {Options} opts options object + * @static + */ + +function cpOptsInData(data, opts) { + _OPTS.forEach(function (p) { + if (typeof data[p] != 'undefined') { + opts[p] = data[p]; + } + }); +} + +/** + * Compile the given `str` of ejs into a template function. + * + * @param {String} template EJS template + * + * @param {Options} opts compilation options + * + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `opts.client`, either type might be returned. + * @public + */ + +exports.compile = function compile(template, opts) { + var templ; + + // v1 compat + // 'scope' is 'context' + // FIXME: Remove this in a future version + if (opts && opts.scope) { + if (!scopeOptionWarned){ + console.warn('`scope` option is deprecated and will be removed in EJS 3'); + scopeOptionWarned = true; + } + if (!opts.context) { + opts.context = opts.scope; + } + delete opts.scope; + } + templ = new Template(template, opts); + return templ.compile(); +}; + +/** + * Render the given `template` of ejs. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} template EJS template + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @return {String} + * @public + */ + +exports.render = function (template, data, opts) { + data = data || {}; + opts = opts || {}; + var fn; + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 2) { + cpOptsInData(data, opts); + } + + return handleCache(opts, template)(data); +}; + +/** + * Render an EJS file at the given `path` and callback `cb(err, str)`. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} path path to the EJS file + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @param {RenderFileCallback} cb callback + * @public + */ + +exports.renderFile = function () { + var args = Array.prototype.slice.call(arguments) + , path = args.shift() + , cb = args.pop() + , data = args.shift() || {} + , opts = args.pop() || {} + , result; + + // Don't pollute passed in opts obj with new vals + opts = utils.shallowCopy({}, opts); + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 3) { + // Express 4 + if (data.settings && data.settings['view options']) { + cpOptsInData(data.settings['view options'], opts); + } + // Express 3 and lower + else { + cpOptsInData(data, opts); + } + } + opts.filename = path; + + try { + result = handleCache(opts)(data); + } + catch(err) { + return cb(err); + } + return cb(null, result); +}; + +/** + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}. + * @public + */ + +exports.clearCache = function () { + exports.cache.reset(); +}; + +function Template(text, opts) { + opts = opts || {}; + var options = {}; + this.templateText = text; + this.mode = null; + this.truncate = false; + this.currentLine = 1; + this.source = ''; + this.dependencies = []; + options.client = opts.client || false; + options.escapeFunction = opts.escape || utils.escapeXML; + options.compileDebug = opts.compileDebug !== false; + options.debug = !!opts.debug; + options.filename = opts.filename; + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER; + options.strict = opts.strict || false; + options.context = opts.context; + options.cache = opts.cache || false; + options.rmWhitespace = opts.rmWhitespace; + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME; + + if (options.strict) { + options._with = false; + } + else { + options._with = typeof opts._with != 'undefined' ? opts._with : true; + } + + this.opts = options; + + this.regex = this.createRegex(); +} + +Template.modes = { + EVAL: 'eval' +, ESCAPED: 'escaped' +, RAW: 'raw' +, COMMENT: 'comment' +, LITERAL: 'literal' +}; + +Template.prototype = { + createRegex: function () { + var str = _REGEX_STRING + , delim = utils.escapeRegExpChars(this.opts.delimiter); + str = str.replace(/%/g, delim); + return new RegExp(str); + } + +, compile: function () { + var src + , fn + , opts = this.opts + , prepended = '' + , appended = '' + , escape = opts.escapeFunction; + + if (opts.rmWhitespace) { + // Have to use two separate replace here as `^` and `$` operators don't + // work well with `\r`. + this.templateText = + this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, ''); + } + + // Slurp spaces and tabs before <%_ and after _%> + this.templateText = + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>'); + + if (!this.source) { + this.generateSource(); + prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n'; + if (opts._with !== false) { + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n'; + appended += ' }' + '\n'; + } + appended += ' return __output.join("");' + '\n'; + this.source = prepended + this.source + appended; + } + + if (opts.compileDebug) { + src = 'var __line = 1' + '\n' + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n' + + ' , __filename = ' + (opts.filename ? + JSON.stringify(opts.filename) : 'undefined') + ';' + '\n' + + 'try {' + '\n' + + this.source + + '} catch (e) {' + '\n' + + ' rethrow(e, __lines, __filename, __line);' + '\n' + + '}' + '\n'; + } + else { + src = this.source; + } + + if (opts.debug) { + console.log(src); + } + + if (opts.client) { + src = 'escape = escape || ' + escape.toString() + ';' + '\n' + src; + if (opts.compileDebug) { + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src; + } + } + + if (opts.strict) { + src = '"use strict";\n' + src; + } + + try { + fn = new Function(opts.localsName + ', escape, include, rethrow', src); + } + catch(e) { + // istanbul ignore else + if (e instanceof SyntaxError) { + if (opts.filename) { + e.message += ' in ' + opts.filename; + } + e.message += ' while compiling ejs'; + } + throw e; + } + + if (opts.client) { + fn.dependencies = this.dependencies; + return fn; + } + + // Return a callable function which will execute the function + // created by the source-code, with the passed data as locals + // Adds a local `include` function which allows full recursive include + var returnedFn = function (data) { + var include = function (path, includeData) { + var d = utils.shallowCopy({}, data); + if (includeData) { + d = utils.shallowCopy(d, includeData); + } + return includeFile(path, opts)(d); + }; + return fn.apply(opts.context, [data || {}, escape, include, rethrow]); + }; + returnedFn.dependencies = this.dependencies; + return returnedFn; + } + +, generateSource: function () { + var self = this + , matches = this.parseTemplateText() + , d = this.opts.delimiter; + + if (matches && matches.length) { + matches.forEach(function (line, index) { + var opening + , closing + , include + , includeOpts + , includeSrc; + // If this is an opening tag, check for closing tags + // FIXME: May end up with some false positives here + // Better to store modes as k/v with '<' + delimiter as key + // Then this can simply check against the map + if ( line.indexOf('<' + d) === 0 // If it is a tag + && line.indexOf('<' + d + d) !== 0) { // and is not escaped + closing = matches[index + 2]; + if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) { + throw new Error('Could not find matching close tag for "' + line + '".'); + } + } + // HACK: backward-compat `include` preprocessor directives + if ((include = line.match(/^\s*include\s+(\S+)/))) { + opening = matches[index - 1]; + // Must be in EVAL or RAW mode + if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) { + includeOpts = utils.shallowCopy({}, self.opts); + includeSrc = includeSource(include[1], includeOpts); + includeSrc = ' ; (function(){' + '\n' + includeSrc + + ' ; })()' + '\n'; + self.source += includeSrc; + self.dependencies.push(exports.resolveInclude(include[1], + includeOpts.filename)); + return; + } + } + self.scanLine(line); + }); + } + + } + +, parseTemplateText: function () { + var str = this.templateText + , pat = this.regex + , result = pat.exec(str) + , arr = [] + , firstPos + , lastPos; + + while (result) { + firstPos = result.index; + lastPos = pat.lastIndex; + + if (firstPos !== 0) { + arr.push(str.substring(0, firstPos)); + str = str.slice(firstPos); + } + + arr.push(result[0]); + str = str.slice(result[0].length); + result = pat.exec(str); + } + + if (str) { + arr.push(str); + } + + return arr; + } + +, scanLine: function (line) { + var self = this + , d = this.opts.delimiter + , newLineCount = 0; + + function _addOutput() { + if (self.truncate) { + // Only replace single leading linebreak in the line after + // -%> tag -- this is the single, trailing linebreak + // after the tag that the truncation mode replaces + // Handle Win / Unix / old Mac linebreaks -- do the \r\n + // combo first in the regex-or + line = line.replace(/^(?:\r\n|\r|\n)/, '') + self.truncate = false; + } + else if (self.opts.rmWhitespace) { + // Gotta be more careful here. + // .replace(/^(\s*)\n/, '$1') might be more appropriate here but as + // rmWhitespace already removes trailing spaces anyway so meh. + line = line.replace(/^\n/, ''); + } + if (!line) { + return; + } + + // Preserve literal slashes + line = line.replace(/\\/g, '\\\\'); + + // Convert linebreaks + line = line.replace(/\n/g, '\\n'); + line = line.replace(/\r/g, '\\r'); + + // Escape double-quotes + // - this will be the delimiter during execution + line = line.replace(/"/g, '\\"'); + self.source += ' ; __append("' + line + '")' + '\n'; + } + + newLineCount = (line.split('\n').length - 1); + + switch (line) { + case '<' + d: + case '<' + d + '_': + this.mode = Template.modes.EVAL; + break; + case '<' + d + '=': + this.mode = Template.modes.ESCAPED; + break; + case '<' + d + '-': + this.mode = Template.modes.RAW; + break; + case '<' + d + '#': + this.mode = Template.modes.COMMENT; + break; + case '<' + d + d: + this.mode = Template.modes.LITERAL; + this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n'; + break; + case d + '>': + case '-' + d + '>': + case '_' + d + '>': + if (this.mode == Template.modes.LITERAL) { + _addOutput(); + } + + this.mode = null; + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0; + break; + default: + // In script mode, depends on type of tag + if (this.mode) { + // If '//' is found without a line break, add a line break. + switch (this.mode) { + case Template.modes.EVAL: + case Template.modes.ESCAPED: + case Template.modes.RAW: + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) { + line += '\n'; + } + } + switch (this.mode) { + // Just executing code + case Template.modes.EVAL: + this.source += ' ; ' + line + '\n'; + break; + // Exec, esc, and output + case Template.modes.ESCAPED: + this.source += ' ; __append(escape(' + + line.replace(_TRAILING_SEMCOL, '').trim() + '))' + '\n'; + break; + // Exec and output + case Template.modes.RAW: + this.source += ' ; __append(' + + line.replace(_TRAILING_SEMCOL, '').trim() + ')' + '\n'; + break; + case Template.modes.COMMENT: + // Do nothing + break; + // Literal <%% mode, append as raw output + case Template.modes.LITERAL: + _addOutput(); + break; + } + } + // In string mode, just add the output + else { + _addOutput(); + } + } + + if (self.opts.compileDebug && newLineCount) { + this.currentLine += newLineCount; + this.source += ' ; __line = ' + this.currentLine + '\n'; + } + } +}; + +/** + * Express.js support. + * + * This is an alias for {@link module:ejs.renderFile}, in order to support + * Express.js out-of-the-box. + * + * @func + */ + +exports.__express = exports.renderFile; + +// Add require support +/* istanbul ignore else */ +if (require.extensions) { + require.extensions['.ejs'] = function (module, filename) { + filename = filename || /* istanbul ignore next */ module.filename; + var options = { + filename: filename + , client: true + } + , template = fs.readFileSync(filename).toString() + , fn = exports.compile(template, options); + module._compile('module.exports = ' + fn.toString() + ';', filename); + }; +} + +/** + * Version of EJS. + * + * @readonly + * @type {String} + * @public + */ + +exports.VERSION = _VERSION_STRING; + +/* istanbul ignore if */ +if (typeof window != 'undefined') { + window.ejs = exports; +} + +},{"../package.json":10,"./utils":9,"fs":11,"path":12}],9:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +/** + * Private utility functions + * @module utils + * @private + */ + +'use strict'; + +var regExpChars = /[|\\{}()[\]^$+*?.]/g; + +/** + * Escape characters reserved in regular expressions. + * + * If `string` is `undefined` or `null`, the empty string is returned. + * + * @param {String} string Input string + * @return {String} Escaped string + * @static + * @private + */ +exports.escapeRegExpChars = function (string) { + // istanbul ignore if + if (!string) { + return ''; + } + return String(string).replace(regExpChars, '\\$&'); +}; + +var _ENCODE_HTML_RULES = { + '&': '&' + , '<': '<' + , '>': '>' + , '"': '"' + , "'": ''' + } + , _MATCH_HTML = /[&<>\'"]/g; + +function encode_char(c) { + return _ENCODE_HTML_RULES[c] || c; +}; + +/** + * Stringified version of constants used by {@link module:utils.escapeXML}. + * + * It is used in the process of generating {@link ClientFunction}s. + * + * @readonly + * @type {String} + */ + +var escapeFuncStr = + 'var _ENCODE_HTML_RULES = {\n' ++ ' "&": "&"\n' ++ ' , "<": "<"\n' ++ ' , ">": ">"\n' ++ ' , \'"\': """\n' ++ ' , "\'": "'"\n' ++ ' }\n' ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n' ++ 'function encode_char(c) {\n' ++ ' return _ENCODE_HTML_RULES[c] || c;\n' ++ '};\n'; + +/** + * Escape characters reserved in XML. + * + * If `markup` is `undefined` or `null`, the empty string is returned. + * + * @implements {EscapeCallback} + * @param {String} markup Input string + * @return {String} Escaped string + * @static + * @private + */ + +exports.escapeXML = function (markup) { + return markup == undefined + ? '' + : String(markup) + .replace(_MATCH_HTML, encode_char); +}; +exports.escapeXML.toString = function () { + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr +}; + +/** + * Copy all properties from one object to another, in a shallow fashion. + * + * @param {Object} to Destination object + * @param {Object} from Source object + * @return {Object} Destination object + * @static + * @private + */ +exports.shallowCopy = function (to, from) { + from = from || {}; + for (var p in from) { + to[p] = from[p]; + } + return to; +}; + +/** + * Simple in-process cache implementation. Does not implement limits of any + * sort. + * + * @implements Cache + * @static + * @private + */ +exports.cache = { + _data: {}, + set: function (key, val) { + this._data[key] = val; + }, + get: function (key) { + return this._data[key]; + }, + reset: function () { + this._data = {}; + } +}; + + +},{}],10:[function(require,module,exports){ +module.exports={ + "name": "ejs", + "description": "Embedded JavaScript templates", + "keywords": [ + "template", + "engine", + "ejs" + ], + "version": "2.4.1", + "author": { + "name": "Matthew Eernisse", + "email": "mde@fleegix.org", + "url": "http://fleegix.org" + }, + "contributors": [ + { + "name": "Timothy Gu", + "email": "timothygu99@gmail.com", + "url": "https://timothygu.github.io" + } + ], + "license": "Apache-2.0", + "main": "./lib/ejs.js", + "repository": { + "type": "git", + "url": "git://github.com/mde/ejs.git" + }, + "bugs": { + "url": "https://github.com/mde/ejs/issues" + }, + "homepage": "https://github.com/mde/ejs", + "dependencies": {}, + "devDependencies": { + "browserify": "^8.0.3", + "istanbul": "~0.3.5", + "jake": "^8.0.0", + "jsdoc": "^3.3.0-beta1", + "lru-cache": "^2.5.0", + "mocha": "^2.1.0", + "rimraf": "^2.2.8", + "uglify-js": "^2.4.16" + }, + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha", + "coverage": "istanbul cover node_modules/mocha/bin/_mocha", + "doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*", + "devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*" + }, + "_id": "ejs@2.4.1", + "_shasum": "82e15b1b2a1f948b18097476ba2bd7c66f4d1566", + "_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.4.1.tgz", + "_from": "ejs@>=2.4.1 <3.0.0", + "_npmVersion": "2.10.1", + "_nodeVersion": "0.12.4", + "_npmUser": { + "name": "mde", + "email": "mde@fleegix.org" + }, + "maintainers": [ + { + "name": "tjholowaychuk", + "email": "tj@vision-media.ca" + }, + { + "name": "mde", + "email": "mde@fleegix.org" + } + ], + "dist": { + "shasum": "82e15b1b2a1f948b18097476ba2bd7c66f4d1566", + "tarball": "http://registry.npmjs.org/ejs/-/ejs-2.4.1.tgz" + }, + "directories": {} +} + +},{}],11:[function(require,module,exports){ + +},{}],12:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; + +}).call(this,require('_process')) +},{"_process":13}],13:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = setTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + clearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + setTimeout(drainQueue, 0); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}]},{},[3]); diff --git a/Frontend/www/assets/js/main.js b/Frontend/www/assets/js/main.js index 83d6aebe0..1aa8a3bbf 100644 --- a/Frontend/www/assets/js/main.js +++ b/Frontend/www/assets/js/main.js @@ -1,2033 +1,1848 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\n
\n
\n \" alt=\"Pizza\">\n\n <% if(pizza.is_new) { %>\n Нова\n <% } else if(pizza.is_popular) {%>\n Популярна\n <% } %>\n\n
\n <%= pizza.title %>\n
<%= pizza.type %>
\n
\n <%= getIngredientsArray(pizza).join(\", \") %>\n
\n
\n\n \n \n
\n
"); - -exports.PizzaCart_OneItem = ejs.compile("
\n <%= pizza.title %> (<%= size %>)\n
Ціна: <%= pizza[size].price %> грн.
\n
\n \n <%= quantity %>\n \n
\n
"); - -},{"ejs":8}],3:[function(require,module,exports){ -/** - * Created by chaika on 25.01.16. - */ - -$(function(){ - //This code will execute when the page is ready - var PizzaMenu = require('./pizza/PizzaMenu'); - var PizzaCart = require('./pizza/PizzaCart'); - var Pizza_List = require('./Pizza_List'); - - PizzaCart.initialiseCart(); - PizzaMenu.initialiseMenu(); - - -}); -},{"./Pizza_List":1,"./pizza/PizzaCart":4,"./pizza/PizzaMenu":5}],4:[function(require,module,exports){ -/** - * Created by chaika on 02.02.16. - */ -var Templates = require('../Templates'); -var Storage = require('./Storage'); -//Перелік розмірів піци -var PizzaSize = { - Big: "big_size", - Small: "small_size" -}; - -//Змінна в якій зберігаються перелік піц в кошику -var Cart = []; - -//HTML едемент куди будуть додаватися піци -var $cart = $("#cart"); - -function addToCart(pizza, size) { - //Додавання однієї піци в кошик покупок - - //Приклад реалізації, можна робити будь-яким іншим способом - Cart.push({ - pizza: pizza, - size: size, - quantity: 1 - }); - - //Оновити вміст кошика на сторінці - updateCart(); -} - -function removeFromCart(cart_item) { - //Видалити піцу з кошика - //TODO: треба зробити - - //Після видалення оновити відображення - updateCart(); -} - -function initialiseCart() { - //Фукнція віпрацьвуватиме при завантаженні сторінки - //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його - //TODO: ... -var saved_pizza = Storage.get('cart'); - if(saved_pizza){ - Cart = saved_pizza; - } - - - updateCart(); -} - -function getPizzaInCart() { - //Повертає піци які зберігаються в кошику - return Cart; -} - -function updateCart() { - //Функція викликається при зміні вмісту кошика - //Тут можна наприклад показати оновлений кошик на екрані та зберегти вміт кошика в Local Storage - - //Очищаємо старі піци в кошику - $cart.html(""); - - //Онволення однієї піци - function showOnePizzaInCart(cart_item) { - var html_code = Templates.PizzaCart_OneItem(cart_item); - - var $node = $(html_code); - - $node.find(".plus").click(function(){ - //Збільшуємо кількість замовлених піц - cart_item.quantity += 1; - - //Оновлюємо відображення - updateCart(); - }); - - $cart.append($node); - } - - Cart.forEach(showOnePizzaInCart); - -} -Storage.set("cart",Cart); -exports.removeFromCart = removeFromCart; -exports.addToCart = addToCart; - -exports.getPizzaInCart = getPizzaInCart; -exports.initialiseCart = initialiseCart; - -exports.PizzaSize = PizzaSize; -},{"../Templates":2,"./Storage":6}],5:[function(require,module,exports){ -/** - * Created by chaika on 02.02.16. - */ -var Templates = require('../Templates'); -var PizzaCart = require('./PizzaCart'); -var Pizza_List = require('../Pizza_List'); - -//HTML едемент куди будуть додаватися піци -var $pizza_list = $("#pizza_list"); - -function showPizzaList(list) { - //Очищаємо старі піци в кошику - $pizza_list.html(""); - - //Онволення однієї піци - function showOnePizza(pizza) { - var html_code = Templates.PizzaMenu_OneItem({pizza: pizza}); - - var $node = $(html_code); - - $node.find(".buy-big").click(function(){ - PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Big); - }); - $node.find(".buy-small").click(function(){ - PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Small); - }); - - $pizza_list.append($node); - } - - list.forEach(showOnePizza); -} - -function filterPizza(filter) { - //Масив куди потраплять піци які треба показати - var pizza_shown = []; - - Pizza_List.forEach(function(pizza){ - //Якщо піка відповідає фільтру - //pizza_shown.push(pizza); - - //TODO: зробити фільтри - }); - - //Показати відфільтровані піци - showPizzaList(pizza_shown); -} - -function initialiseMenu() { - //Показуємо усі піци - showPizzaList(Pizza_List) -} - -exports.filterPizza = filterPizza; -exports.initialiseMenu = initialiseMenu; -},{"../Pizza_List":1,"../Templates":2,"./PizzaCart":4}],6:[function(require,module,exports){ -var basil = require('basil.js'); -basil = new basil(); -exports.get = function(key) { - return basil.get(key); -}; -exports.set = function(key, value) { - return basil.set(key, value); -};/** - * Created by Angelina on 03.02.2016. - */ - -},{"basil.js":7}],7:[function(require,module,exports){ -(function () { - // Basil - var Basil = function (options) { - return Basil.utils.extend({}, Basil.plugins, new Basil.Storage().init(options)); - }; - - // Version - Basil.version = '0.4.2'; - - // Utils - Basil.utils = { - extend: function () { - var destination = typeof arguments[0] === 'object' ? arguments[0] : {}; - for (var i = 1; i < arguments.length; i++) { - if (arguments[i] && typeof arguments[i] === 'object') - for (var property in arguments[i]) - destination[property] = arguments[i][property]; - } - return destination; - }, - each: function (obj, fnIterator, context) { - if (this.isArray(obj)) { - for (var i = 0; i < obj.length; i++) - if (fnIterator.call(context, obj[i], i) === false) return; - } else if (obj) { - for (var key in obj) - if (fnIterator.call(context, obj[key], key) === false) return; - } - }, - tryEach: function (obj, fnIterator, fnError, context) { - this.each(obj, function (value, key) { - try { - return fnIterator.call(context, value, key); - } catch (error) { - if (this.isFunction(fnError)) { - try { - fnError.call(context, value, key, error); - } catch (error) {} - } - } - }, this); - }, - registerPlugin: function (methods) { - Basil.plugins = this.extend(methods, Basil.plugins); - } - }; - // Add some isType methods: isArguments, isBoolean, isFunction, isString, isArray, isNumber, isDate, isRegExp. - var types = ['Arguments', 'Boolean', 'Function', 'String', 'Array', 'Number', 'Date', 'RegExp'] - for (var i = 0; i < types.length; i++) { - Basil.utils['is' + types[i]] = (function (type) { - return function (obj) { - return Object.prototype.toString.call(obj) === '[object ' + type + ']'; - }; - })(types[i]); - } - - // Plugins - Basil.plugins = {}; - - // Options - Basil.options = Basil.utils.extend({ - namespace: 'b45i1', - storages: ['local', 'cookie', 'session', 'memory'], - expireDays: 365 - }, window.Basil ? window.Basil.options : {}); - - // Storage - Basil.Storage = function () { - var _salt = 'b45i1' + (Math.random() + 1) - .toString(36) - .substring(7), - _storages = {}, - _toStoragesArray = function (storages) { - if (Basil.utils.isArray(storages)) - return storages; - return Basil.utils.isString(storages) ? [storages] : []; - }, - _toStoredKey = function (namespace, path) { - var key = ''; - if (Basil.utils.isString(path) && path.length) - path = [path]; - if (Basil.utils.isArray(path) && path.length) - key = path.join('.'); - return key && namespace ? namespace + '.' + key : key; - }, - _toKeyName = function (namespace, key) { - if (!namespace) - return key; - return key.replace(new RegExp('^' + namespace + '.'), ''); - }, - _toStoredValue = function (value) { - return JSON.stringify(value); - }, - _fromStoredValue = function (value) { - return value ? JSON.parse(value) : null; - }; - - // HTML5 web storage interface - var webStorageInterface = { - engine: null, - check: function () { - try { - window[this.engine].setItem(_salt, true); - window[this.engine].removeItem(_salt); - } catch (e) { - return false; - } - return true; - }, - set: function (key, value, options) { - if (!key) - throw Error('invalid key'); - window[this.engine].setItem(key, value); - }, - get: function (key) { - return window[this.engine].getItem(key); - }, - remove: function (key) { - window[this.engine].removeItem(key); - }, - reset: function (namespace) { - for (var i = 0, key; i < window[this.engine].length; i++) { - key = window[this.engine].key(i); - if (!namespace || key.indexOf(namespace) === 0) { - this.remove(key); - i--; - } - } - }, - keys: function (namespace) { - var keys = []; - for (var i = 0, key; i < window[this.engine].length; i++) { - key = window[this.engine].key(i); - if (!namespace || key.indexOf(namespace) === 0) - keys.push(_toKeyName(namespace, key)); - } - return keys; - } - }; - - // local storage - _storages.local = Basil.utils.extend({}, webStorageInterface, { - engine: 'localStorage' - }); - // session storage - _storages.session = Basil.utils.extend({}, webStorageInterface, { - engine: 'sessionStorage' - }); - - // memory storage - _storages.memory = { - _hash: {}, - check: function () { - return true; - }, - set: function (key, value, options) { - if (!key) - throw Error('invalid key'); - this._hash[key] = value; - }, - get: function (key) { - return this._hash[key] || null; - }, - remove: function (key) { - delete this._hash[key]; - }, - reset: function (namespace) { - for (var key in this._hash) { - if (!namespace || key.indexOf(namespace) === 0) - this.remove(key); - } - }, - keys: function (namespace) { - var keys = []; - for (var key in this._hash) - if (!namespace || key.indexOf(namespace) === 0) - keys.push(_toKeyName(namespace, key)); - return keys; - } - }; - - // cookie storage - _storages.cookie = { - check: function () { - return navigator.cookieEnabled; - }, - set: function (key, value, options) { - if (!this.check()) - throw Error('cookies are disabled'); - options = options || {}; - if (!key) - throw Error('invalid key'); - var cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value); - // handle expiration days - if (options.expireDays) { - var date = new Date(); - date.setTime(date.getTime() + (options.expireDays * 24 * 60 * 60 * 1000)); - cookie += '; expires=' + date.toGMTString(); - } - // handle domain - if (options.domain && options.domain !== document.domain) { - var _domain = options.domain.replace(/^\./, ''); - if (document.domain.indexOf(_domain) === -1 || _domain.split('.').length <= 1) - throw Error('invalid domain'); - cookie += '; domain=' + options.domain; - } - // handle secure - if (options.secure === true) { - cookie += '; secure'; - } - document.cookie = cookie + '; path=/'; - }, - get: function (key) { - if (!this.check()) - throw Error('cookies are disabled'); - var encodedKey = encodeURIComponent(key); - var cookies = document.cookie ? document.cookie.split(';') : []; - // retrieve last updated cookie first - for (var i = cookies.length - 1, cookie; i >= 0; i--) { - cookie = cookies[i].replace(/^\s*/, ''); - if (cookie.indexOf(encodedKey + '=') === 0) - return decodeURIComponent(cookie.substring(encodedKey.length + 1, cookie.length)); - } - return null; - }, - remove: function (key) { - // remove cookie from main domain - this.set(key, '', { expireDays: -1 }); - // remove cookie from upper domains - var domainParts = document.domain.split('.'); - for (var i = domainParts.length; i >= 0; i--) { - this.set(key, '', { expireDays: -1, domain: '.' + domainParts.slice(- i).join('.') }); - } - }, - reset: function (namespace) { - var cookies = document.cookie ? document.cookie.split(';') : []; - for (var i = 0, cookie, key; i < cookies.length; i++) { - cookie = cookies[i].replace(/^\s*/, ''); - key = cookie.substr(0, cookie.indexOf('=')); - if (!namespace || key.indexOf(namespace) === 0) - this.remove(key); - } - }, - keys: function (namespace) { - if (!this.check()) - throw Error('cookies are disabled'); - var keys = [], - cookies = document.cookie ? document.cookie.split(';') : []; - for (var i = 0, cookie, key; i < cookies.length; i++) { - cookie = cookies[i].replace(/^\s*/, ''); - key = decodeURIComponent(cookie.substr(0, cookie.indexOf('='))); - if (!namespace || key.indexOf(namespace) === 0) - keys.push(_toKeyName(namespace, key)); - } - return keys; - } - }; - - return { - init: function (options) { - this.setOptions(options); - return this; - }, - setOptions: function (options) { - this.options = Basil.utils.extend({}, this.options || Basil.options, options); - }, - support: function (storage) { - return _storages.hasOwnProperty(storage); - }, - check: function (storage) { - if (this.support(storage)) - return _storages[storage].check(); - return false; - }, - set: function (key, value, options) { - options = Basil.utils.extend({}, this.options, options); - if (!(key = _toStoredKey(options.namespace, key))) - return false; - value = options.raw === true ? value : _toStoredValue(value); - var where = null; - // try to set key/value in first available storage - Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { - _storages[storage].set(key, value, options); - where = storage; - return false; // break; - }, null, this); - if (!where) { - // key has not been set anywhere - return false; - } - // remove key from all other storages - Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { - if (storage !== where) - _storages[storage].remove(key); - }, null, this); - return true; - }, - get: function (key, options) { - options = Basil.utils.extend({}, this.options, options); - if (!(key = _toStoredKey(options.namespace, key))) - return null; - var value = null; - Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage, index) { - if (value !== null) - return false; // break if a value has already been found. - value = _storages[storage].get(key, options) || null; - value = options.raw === true ? value : _fromStoredValue(value); - }, function (storage, index, error) { - value = null; - }, this); - return value; - }, - remove: function (key, options) { - options = Basil.utils.extend({}, this.options, options); - if (!(key = _toStoredKey(options.namespace, key))) - return; - Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { - _storages[storage].remove(key); - }, null, this); - }, - reset: function (options) { - options = Basil.utils.extend({}, this.options, options); - Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { - _storages[storage].reset(options.namespace); - }, null, this); - }, - keys: function (options) { - options = options || {}; - var keys = []; - for (var key in this.keysMap(options)) - keys.push(key); - return keys; - }, - keysMap: function (options) { - options = Basil.utils.extend({}, this.options, options); - var map = {}; - Basil.utils.tryEach(_toStoragesArray(options.storages), function (storage) { - Basil.utils.each(_storages[storage].keys(options.namespace), function (key) { - map[key] = Basil.utils.isArray(map[key]) ? map[key] : []; - map[key].push(storage); - }, this); - }, null, this); - return map; - } - }; - }; - - // Access to native storages, without namespace or basil value decoration - Basil.memory = new Basil.Storage().init({ storages: 'memory', namespace: null, raw: true }); - Basil.cookie = new Basil.Storage().init({ storages: 'cookie', namespace: null, raw: true }); - Basil.localStorage = new Basil.Storage().init({ storages: 'local', namespace: null, raw: true }); - Basil.sessionStorage = new Basil.Storage().init({ storages: 'session', namespace: null, raw: true }); - - // browser export - window.Basil = Basil; - - // AMD export - if (typeof define === 'function' && define.amd) { - define(function() { - return Basil; - }); - // commonjs export - } else if (typeof module !== 'undefined' && module.exports) { - module.exports = Basil; - } - -})(); - -},{}],8:[function(require,module,exports){ -/* - * EJS Embedded JavaScript templates - * Copyright 2112 Matthew Eernisse (mde@fleegix.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * -*/ - -'use strict'; - -/** - * @file Embedded JavaScript templating engine. - * @author Matthew Eernisse - * @author Tiancheng "Timothy" Gu - * @project EJS - * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0} - */ - -/** - * EJS internal functions. - * - * Technically this "module" lies in the same file as {@link module:ejs}, for - * the sake of organization all the private functions re grouped into this - * module. - * - * @module ejs-internal - * @private - */ - -/** - * Embedded JavaScript templating engine. - * - * @module ejs - * @public - */ - -var fs = require('fs') - , utils = require('./utils') - , scopeOptionWarned = false - , _VERSION_STRING = require('../package.json').version - , _DEFAULT_DELIMITER = '%' - , _DEFAULT_LOCALS_NAME = 'locals' - , _REGEX_STRING = '(<%%|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)' - , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context' - , 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace' - , 'strict', 'localsName' - ] - , _TRAILING_SEMCOL = /;\s*$/ - , _BOM = /^\uFEFF/; - -/** - * EJS template function cache. This can be a LRU object from lru-cache NPM - * module. By default, it is {@link module:utils.cache}, a simple in-process - * cache that grows continuously. - * - * @type {Cache} - */ - -exports.cache = utils.cache; - -/** - * Name of the object containing the locals. - * - * This variable is overriden by {@link Options}`.localsName` if it is not - * `undefined`. - * - * @type {String} - * @public - */ - -exports.localsName = _DEFAULT_LOCALS_NAME; - -/** - * Get the path to the included file from the parent file path and the - * specified path. - * - * @param {String} name specified path - * @param {String} filename parent file path - * @return {String} - */ - -exports.resolveInclude = function(name, filename) { - var path = require('path') - , dirname = path.dirname - , extname = path.extname - , resolve = path.resolve - , includePath = resolve(dirname(filename), name) - , ext = extname(name); - if (!ext) { - includePath += '.ejs'; - } - return includePath; -}; - -/** - * Get the template from a string or a file, either compiled on-the-fly or - * read from cache (if enabled), and cache the template if needed. - * - * If `template` is not set, the file specified in `options.filename` will be - * read. - * - * If `options.cache` is true, this function reads the file from - * `options.filename` so it must be set prior to calling this function. - * - * @memberof module:ejs-internal - * @param {Options} options compilation options - * @param {String} [template] template source - * @return {(TemplateFunction|ClientFunction)} - * Depending on the value of `options.client`, either type might be returned. - * @static - */ - -function handleCache(options, template) { - var fn - , path = options.filename - , hasTemplate = arguments.length > 1; - - if (options.cache) { - if (!path) { - throw new Error('cache option requires a filename'); - } - fn = exports.cache.get(path); - if (fn) { - return fn; - } - if (!hasTemplate) { - template = fs.readFileSync(path).toString().replace(_BOM, ''); - } - } - else if (!hasTemplate) { - // istanbul ignore if: should not happen at all - if (!path) { - throw new Error('Internal EJS error: no file name or template ' - + 'provided'); - } - template = fs.readFileSync(path).toString().replace(_BOM, ''); - } - fn = exports.compile(template, options); - if (options.cache) { - exports.cache.set(path, fn); - } - return fn; -} - -/** - * Get the template function. - * - * If `options.cache` is `true`, then the template is cached. - * - * @memberof module:ejs-internal - * @param {String} path path for the specified file - * @param {Options} options compilation options - * @return {(TemplateFunction|ClientFunction)} - * Depending on the value of `options.client`, either type might be returned - * @static - */ - -function includeFile(path, options) { - var opts = utils.shallowCopy({}, options); - if (!opts.filename) { - throw new Error('`include` requires the \'filename\' option.'); - } - opts.filename = exports.resolveInclude(path, opts.filename); - return handleCache(opts); -} - -/** - * Get the JavaScript source of an included file. - * - * @memberof module:ejs-internal - * @param {String} path path for the specified file - * @param {Options} options compilation options - * @return {String} - * @static - */ - -function includeSource(path, options) { - var opts = utils.shallowCopy({}, options) - , includePath - , template; - if (!opts.filename) { - throw new Error('`include` requires the \'filename\' option.'); - } - includePath = exports.resolveInclude(path, opts.filename); - template = fs.readFileSync(includePath).toString().replace(_BOM, ''); - - opts.filename = includePath; - var templ = new Template(template, opts); - templ.generateSource(); - return templ.source; -} - -/** - * Re-throw the given `err` in context to the `str` of ejs, `filename`, and - * `lineno`. - * - * @implements RethrowCallback - * @memberof module:ejs-internal - * @param {Error} err Error object - * @param {String} str EJS source - * @param {String} filename file name of the EJS file - * @param {String} lineno line number of the error - * @static - */ - -function rethrow(err, str, filename, lineno){ - var lines = str.split('\n') - , start = Math.max(lineno - 3, 0) - , end = Math.min(lines.length, lineno + 3); - - // Error context - var context = lines.slice(start, end).map(function (line, i){ - var curr = i + start + 1; - return (curr == lineno ? ' >> ' : ' ') - + curr - + '| ' - + line; - }).join('\n'); - - // Alter exception message - err.path = filename; - err.message = (filename || 'ejs') + ':' - + lineno + '\n' - + context + '\n\n' - + err.message; - - throw err; -} - -/** - * Copy properties in data object that are recognized as options to an - * options object. - * - * This is used for compatibility with earlier versions of EJS and Express.js. - * - * @memberof module:ejs-internal - * @param {Object} data data object - * @param {Options} opts options object - * @static - */ - -function cpOptsInData(data, opts) { - _OPTS.forEach(function (p) { - if (typeof data[p] != 'undefined') { - opts[p] = data[p]; - } - }); -} - -/** - * Compile the given `str` of ejs into a template function. - * - * @param {String} template EJS template - * - * @param {Options} opts compilation options - * - * @return {(TemplateFunction|ClientFunction)} - * Depending on the value of `opts.client`, either type might be returned. - * @public - */ - -exports.compile = function compile(template, opts) { - var templ; - - // v1 compat - // 'scope' is 'context' - // FIXME: Remove this in a future version - if (opts && opts.scope) { - if (!scopeOptionWarned){ - console.warn('`scope` option is deprecated and will be removed in EJS 3'); - scopeOptionWarned = true; - } - if (!opts.context) { - opts.context = opts.scope; - } - delete opts.scope; - } - templ = new Template(template, opts); - return templ.compile(); -}; - -/** - * Render the given `template` of ejs. - * - * If you would like to include options but not data, you need to explicitly - * call this function with `data` being an empty object or `null`. - * - * @param {String} template EJS template - * @param {Object} [data={}] template data - * @param {Options} [opts={}] compilation and rendering options - * @return {String} - * @public - */ - -exports.render = function (template, data, opts) { - data = data || {}; - opts = opts || {}; - var fn; - - // No options object -- if there are optiony names - // in the data, copy them to options - if (arguments.length == 2) { - cpOptsInData(data, opts); - } - - return handleCache(opts, template)(data); -}; - -/** - * Render an EJS file at the given `path` and callback `cb(err, str)`. - * - * If you would like to include options but not data, you need to explicitly - * call this function with `data` being an empty object or `null`. - * - * @param {String} path path to the EJS file - * @param {Object} [data={}] template data - * @param {Options} [opts={}] compilation and rendering options - * @param {RenderFileCallback} cb callback - * @public - */ - -exports.renderFile = function () { - var args = Array.prototype.slice.call(arguments) - , path = args.shift() - , cb = args.pop() - , data = args.shift() || {} - , opts = args.pop() || {} - , result; - - // Don't pollute passed in opts obj with new vals - opts = utils.shallowCopy({}, opts); - - // No options object -- if there are optiony names - // in the data, copy them to options - if (arguments.length == 3) { - // Express 4 - if (data.settings && data.settings['view options']) { - cpOptsInData(data.settings['view options'], opts); - } - // Express 3 and lower - else { - cpOptsInData(data, opts); - } - } - opts.filename = path; - - try { - result = handleCache(opts)(data); - } - catch(err) { - return cb(err); - } - return cb(null, result); -}; - -/** - * Clear intermediate JavaScript cache. Calls {@link Cache#reset}. - * @public - */ - -exports.clearCache = function () { - exports.cache.reset(); -}; - -function Template(text, opts) { - opts = opts || {}; - var options = {}; - this.templateText = text; - this.mode = null; - this.truncate = false; - this.currentLine = 1; - this.source = ''; - this.dependencies = []; - options.client = opts.client || false; - options.escapeFunction = opts.escape || utils.escapeXML; - options.compileDebug = opts.compileDebug !== false; - options.debug = !!opts.debug; - options.filename = opts.filename; - options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER; - options.strict = opts.strict || false; - options.context = opts.context; - options.cache = opts.cache || false; - options.rmWhitespace = opts.rmWhitespace; - options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME; - - if (options.strict) { - options._with = false; - } - else { - options._with = typeof opts._with != 'undefined' ? opts._with : true; - } - - this.opts = options; - - this.regex = this.createRegex(); -} - -Template.modes = { - EVAL: 'eval' -, ESCAPED: 'escaped' -, RAW: 'raw' -, COMMENT: 'comment' -, LITERAL: 'literal' -}; - -Template.prototype = { - createRegex: function () { - var str = _REGEX_STRING - , delim = utils.escapeRegExpChars(this.opts.delimiter); - str = str.replace(/%/g, delim); - return new RegExp(str); - } - -, compile: function () { - var src - , fn - , opts = this.opts - , prepended = '' - , appended = '' - , escape = opts.escapeFunction; - - if (opts.rmWhitespace) { - // Have to use two separate replace here as `^` and `$` operators don't - // work well with `\r`. - this.templateText = - this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, ''); - } - - // Slurp spaces and tabs before <%_ and after _%> - this.templateText = - this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>'); - - if (!this.source) { - this.generateSource(); - prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n'; - if (opts._with !== false) { - prepended += ' with (' + opts.localsName + ' || {}) {' + '\n'; - appended += ' }' + '\n'; - } - appended += ' return __output.join("");' + '\n'; - this.source = prepended + this.source + appended; - } - - if (opts.compileDebug) { - src = 'var __line = 1' + '\n' - + ' , __lines = ' + JSON.stringify(this.templateText) + '\n' - + ' , __filename = ' + (opts.filename ? - JSON.stringify(opts.filename) : 'undefined') + ';' + '\n' - + 'try {' + '\n' - + this.source - + '} catch (e) {' + '\n' - + ' rethrow(e, __lines, __filename, __line);' + '\n' - + '}' + '\n'; - } - else { - src = this.source; - } - - if (opts.debug) { - console.log(src); - } - - if (opts.client) { - src = 'escape = escape || ' + escape.toString() + ';' + '\n' + src; - if (opts.compileDebug) { - src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src; - } - } - - if (opts.strict) { - src = '"use strict";\n' + src; - } - - try { - fn = new Function(opts.localsName + ', escape, include, rethrow', src); - } - catch(e) { - // istanbul ignore else - if (e instanceof SyntaxError) { - if (opts.filename) { - e.message += ' in ' + opts.filename; - } - e.message += ' while compiling ejs'; - } - throw e; - } - - if (opts.client) { - fn.dependencies = this.dependencies; - return fn; - } - - // Return a callable function which will execute the function - // created by the source-code, with the passed data as locals - // Adds a local `include` function which allows full recursive include - var returnedFn = function (data) { - var include = function (path, includeData) { - var d = utils.shallowCopy({}, data); - if (includeData) { - d = utils.shallowCopy(d, includeData); - } - return includeFile(path, opts)(d); - }; - return fn.apply(opts.context, [data || {}, escape, include, rethrow]); - }; - returnedFn.dependencies = this.dependencies; - return returnedFn; - } - -, generateSource: function () { - var self = this - , matches = this.parseTemplateText() - , d = this.opts.delimiter; - - if (matches && matches.length) { - matches.forEach(function (line, index) { - var opening - , closing - , include - , includeOpts - , includeSrc; - // If this is an opening tag, check for closing tags - // FIXME: May end up with some false positives here - // Better to store modes as k/v with '<' + delimiter as key - // Then this can simply check against the map - if ( line.indexOf('<' + d) === 0 // If it is a tag - && line.indexOf('<' + d + d) !== 0) { // and is not escaped - closing = matches[index + 2]; - if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) { - throw new Error('Could not find matching close tag for "' + line + '".'); - } - } - // HACK: backward-compat `include` preprocessor directives - if ((include = line.match(/^\s*include\s+(\S+)/))) { - opening = matches[index - 1]; - // Must be in EVAL or RAW mode - if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) { - includeOpts = utils.shallowCopy({}, self.opts); - includeSrc = includeSource(include[1], includeOpts); - includeSrc = ' ; (function(){' + '\n' + includeSrc + - ' ; })()' + '\n'; - self.source += includeSrc; - self.dependencies.push(exports.resolveInclude(include[1], - includeOpts.filename)); - return; - } - } - self.scanLine(line); - }); - } - - } - -, parseTemplateText: function () { - var str = this.templateText - , pat = this.regex - , result = pat.exec(str) - , arr = [] - , firstPos - , lastPos; - - while (result) { - firstPos = result.index; - lastPos = pat.lastIndex; - - if (firstPos !== 0) { - arr.push(str.substring(0, firstPos)); - str = str.slice(firstPos); - } - - arr.push(result[0]); - str = str.slice(result[0].length); - result = pat.exec(str); - } - - if (str) { - arr.push(str); - } - - return arr; - } - -, scanLine: function (line) { - var self = this - , d = this.opts.delimiter - , newLineCount = 0; - - function _addOutput() { - if (self.truncate) { - // Only replace single leading linebreak in the line after - // -%> tag -- this is the single, trailing linebreak - // after the tag that the truncation mode replaces - // Handle Win / Unix / old Mac linebreaks -- do the \r\n - // combo first in the regex-or - line = line.replace(/^(?:\r\n|\r|\n)/, '') - self.truncate = false; - } - else if (self.opts.rmWhitespace) { - // Gotta be more careful here. - // .replace(/^(\s*)\n/, '$1') might be more appropriate here but as - // rmWhitespace already removes trailing spaces anyway so meh. - line = line.replace(/^\n/, ''); - } - if (!line) { - return; - } - - // Preserve literal slashes - line = line.replace(/\\/g, '\\\\'); - - // Convert linebreaks - line = line.replace(/\n/g, '\\n'); - line = line.replace(/\r/g, '\\r'); - - // Escape double-quotes - // - this will be the delimiter during execution - line = line.replace(/"/g, '\\"'); - self.source += ' ; __append("' + line + '")' + '\n'; - } - - newLineCount = (line.split('\n').length - 1); - - switch (line) { - case '<' + d: - case '<' + d + '_': - this.mode = Template.modes.EVAL; - break; - case '<' + d + '=': - this.mode = Template.modes.ESCAPED; - break; - case '<' + d + '-': - this.mode = Template.modes.RAW; - break; - case '<' + d + '#': - this.mode = Template.modes.COMMENT; - break; - case '<' + d + d: - this.mode = Template.modes.LITERAL; - this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n'; - break; - case d + '>': - case '-' + d + '>': - case '_' + d + '>': - if (this.mode == Template.modes.LITERAL) { - _addOutput(); - } - - this.mode = null; - this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0; - break; - default: - // In script mode, depends on type of tag - if (this.mode) { - // If '//' is found without a line break, add a line break. - switch (this.mode) { - case Template.modes.EVAL: - case Template.modes.ESCAPED: - case Template.modes.RAW: - if (line.lastIndexOf('//') > line.lastIndexOf('\n')) { - line += '\n'; - } - } - switch (this.mode) { - // Just executing code - case Template.modes.EVAL: - this.source += ' ; ' + line + '\n'; - break; - // Exec, esc, and output - case Template.modes.ESCAPED: - this.source += ' ; __append(escape(' + - line.replace(_TRAILING_SEMCOL, '').trim() + '))' + '\n'; - break; - // Exec and output - case Template.modes.RAW: - this.source += ' ; __append(' + - line.replace(_TRAILING_SEMCOL, '').trim() + ')' + '\n'; - break; - case Template.modes.COMMENT: - // Do nothing - break; - // Literal <%% mode, append as raw output - case Template.modes.LITERAL: - _addOutput(); - break; - } - } - // In string mode, just add the output - else { - _addOutput(); - } - } - - if (self.opts.compileDebug && newLineCount) { - this.currentLine += newLineCount; - this.source += ' ; __line = ' + this.currentLine + '\n'; - } - } -}; - -/** - * Express.js support. - * - * This is an alias for {@link module:ejs.renderFile}, in order to support - * Express.js out-of-the-box. - * - * @func - */ - -exports.__express = exports.renderFile; - -// Add require support -/* istanbul ignore else */ -if (require.extensions) { - require.extensions['.ejs'] = function (module, filename) { - filename = filename || /* istanbul ignore next */ module.filename; - var options = { - filename: filename - , client: true - } - , template = fs.readFileSync(filename).toString() - , fn = exports.compile(template, options); - module._compile('module.exports = ' + fn.toString() + ';', filename); - }; -} - -/** - * Version of EJS. - * - * @readonly - * @type {String} - * @public - */ - -exports.VERSION = _VERSION_STRING; - -/* istanbul ignore if */ -if (typeof window != 'undefined') { - window.ejs = exports; -} - -},{"../package.json":10,"./utils":9,"fs":11,"path":12}],9:[function(require,module,exports){ -/* - * EJS Embedded JavaScript templates - * Copyright 2112 Matthew Eernisse (mde@fleegix.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * -*/ - -/** - * Private utility functions - * @module utils - * @private - */ - -'use strict'; - -var regExpChars = /[|\\{}()[\]^$+*?.]/g; - -/** - * Escape characters reserved in regular expressions. - * - * If `string` is `undefined` or `null`, the empty string is returned. - * - * @param {String} string Input string - * @return {String} Escaped string - * @static - * @private - */ -exports.escapeRegExpChars = function (string) { - // istanbul ignore if - if (!string) { - return ''; - } - return String(string).replace(regExpChars, '\\$&'); -}; - -var _ENCODE_HTML_RULES = { - '&': '&' - , '<': '<' - , '>': '>' - , '"': '"' - , "'": ''' - } - , _MATCH_HTML = /[&<>\'"]/g; - -function encode_char(c) { - return _ENCODE_HTML_RULES[c] || c; -}; - -/** - * Stringified version of constants used by {@link module:utils.escapeXML}. - * - * It is used in the process of generating {@link ClientFunction}s. - * - * @readonly - * @type {String} - */ - -var escapeFuncStr = - 'var _ENCODE_HTML_RULES = {\n' -+ ' "&": "&"\n' -+ ' , "<": "<"\n' -+ ' , ">": ">"\n' -+ ' , \'"\': """\n' -+ ' , "\'": "'"\n' -+ ' }\n' -+ ' , _MATCH_HTML = /[&<>\'"]/g;\n' -+ 'function encode_char(c) {\n' -+ ' return _ENCODE_HTML_RULES[c] || c;\n' -+ '};\n'; - -/** - * Escape characters reserved in XML. - * - * If `markup` is `undefined` or `null`, the empty string is returned. - * - * @implements {EscapeCallback} - * @param {String} markup Input string - * @return {String} Escaped string - * @static - * @private - */ - -exports.escapeXML = function (markup) { - return markup == undefined - ? '' - : String(markup) - .replace(_MATCH_HTML, encode_char); -}; -exports.escapeXML.toString = function () { - return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr -}; - -/** - * Copy all properties from one object to another, in a shallow fashion. - * - * @param {Object} to Destination object - * @param {Object} from Source object - * @return {Object} Destination object - * @static - * @private - */ -exports.shallowCopy = function (to, from) { - from = from || {}; - for (var p in from) { - to[p] = from[p]; - } - return to; -}; - -/** - * Simple in-process cache implementation. Does not implement limits of any - * sort. - * - * @implements Cache - * @static - * @private - */ -exports.cache = { - _data: {}, - set: function (key, val) { - this._data[key] = val; - }, - get: function (key) { - return this._data[key]; - }, - reset: function () { - this._data = {}; - } -}; - - -},{}],10:[function(require,module,exports){ -module.exports={ - "name": "ejs", - "description": "Embedded JavaScript templates", - "keywords": [ - "template", - "engine", - "ejs" - ], - "version": "2.4.1", - "author": { - "name": "Matthew Eernisse", - "email": "mde@fleegix.org", - "url": "http://fleegix.org" - }, - "contributors": [ - { - "name": "Timothy Gu", - "email": "timothygu99@gmail.com", - "url": "https://timothygu.github.io" - } - ], - "license": "Apache-2.0", - "main": "./lib/ejs.js", - "repository": { - "type": "git", - "url": "git://github.com/mde/ejs.git" - }, - "bugs": { - "url": "https://github.com/mde/ejs/issues" - }, - "homepage": "https://github.com/mde/ejs", - "dependencies": {}, - "devDependencies": { - "browserify": "^8.0.3", - "istanbul": "~0.3.5", - "jake": "^8.0.0", - "jsdoc": "^3.3.0-beta1", - "lru-cache": "^2.5.0", - "mocha": "^2.1.0", - "rimraf": "^2.2.8", - "uglify-js": "^2.4.16" - }, - "engines": { - "node": ">=0.10.0" - }, - "scripts": { - "test": "mocha", - "coverage": "istanbul cover node_modules/mocha/bin/_mocha", - "doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*", - "devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*" - }, - "_id": "ejs@2.4.1", - "_shasum": "82e15b1b2a1f948b18097476ba2bd7c66f4d1566", - "_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.4.1.tgz", - "_from": "ejs@>=2.4.1 <3.0.0", - "_npmVersion": "2.10.1", - "_nodeVersion": "0.12.4", - "_npmUser": { - "name": "mde", - "email": "mde@fleegix.org" - }, - "maintainers": [ - { - "name": "tjholowaychuk", - "email": "tj@vision-media.ca" - }, - { - "name": "mde", - "email": "mde@fleegix.org" - } - ], - "dist": { - "shasum": "82e15b1b2a1f948b18097476ba2bd7c66f4d1566", - "tarball": "http://registry.npmjs.org/ejs/-/ejs-2.4.1.tgz" - }, - "directories": {} -} - -},{}],11:[function(require,module,exports){ - -},{}],12:[function(require,module,exports){ -(function (process){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -}).call(this,require('_process')) -},{"_process":13}],13:[function(require,module,exports){ -// shim for using process in browser - -var process = module.exports = {}; -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = setTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - clearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - setTimeout(drainQueue, 0); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - -},{}]},{},[3]); +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\r\n
\r\n
\r\n <% if(pizza.is_new) { %>\r\n Нова\r\n <% } else if(pizza.is_popular) {%>\r\n Популярна\r\n <% } %>\r\n \" alt=\"Pizza\"> \r\n
\r\n

<%= pizza.title %>

\r\n

<%= pizza.type %>

\r\n

\r\n <%= getIngredientsArray(pizza).join(\", \") %>\r\n

\r\n
\r\n <% if (pizza.small_size){ %>\r\n
\r\n
\r\n <%= pizza.small_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.small_size.weight %>\r\n
\r\n

\r\n <%= pizza.small_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n <% if (pizza.big_size) { %>\r\n
\r\n
\r\n <%= pizza.big_size.size %>\r\n
\r\n
\r\n \r\n <%= pizza.big_size.weight %>\r\n
\r\n

\r\n <%= pizza.big_size.price %><\h2>\r\n

грн.
\r\n \r\n
<% } %>\r\n
\r\n
"); + +exports.PizzaCart_OneItem = ejs.compile("
\r\n\t\t\t \"Піца\"\r\n\t\t\t

\r\n\t\t\t <%= pizza.title %> (<%=size%><%if(size==pizza.small_size){%>Мала<%}else if(size==pizza.big_size){%>Велика<%} %>) \r\n\t\t\t

\r\n\t\t\t
\r\n\t\t\t \r\n\t\t\t 30\r\n\t\t\t \r\n\t\t\t 160\r\n\t\t\t
\r\n\t\t\t
\r\n\t\t\t Ціна: <%= pizza[size].price %> грн.\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t <%= quantity %>\r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\t\t\t \r\n\r\n\t\t\t \r\n\t\t\t \r\n\t\t\t
\r\n\t\t\t
"); + +},{"ejs":6}],3:[function(require,module,exports){ +/** + * Created by chaika on 25.01.16. + */ + +$(function(){ + //This code will execute when the page is ready + var PizzaMenu = require('./pizza/PizzaMenu'); + var PizzaCart = require('./pizza/PizzaCart'); + var Pizza_List = require('./Pizza_List'); + + PizzaCart.initialiseCart(); + PizzaMenu.initialiseMenu(); + + +}); +},{"./Pizza_List":1,"./pizza/PizzaCart":4,"./pizza/PizzaMenu":5}],4:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); + +//Перелік розмірів піци +var PizzaSize = { + Big: "big_size", + Small: "small_size" +}; + +//Змінна в якій зберігаються перелік піц в кошику +var Cart = []; +var cart_map = []; +var count = 0; +//var totalPrice=0; + +//HTML едемент куди будуть додаватися піци +var $cart = $("#cartList"); + +function addToCart(pizza, size) { + + var cart_id = cart_map[pizza.id]; + + if (cart_id && (cart_id[size] || cart_id[size] === 0)){ + Cart[cart_id[size]].quantity += 1; + + } else { + if (!cart_map[pizza.id]){ + cart_map[pizza.id] = []; + } + cart_map[pizza.id][size] = + Cart.push({ + pizza: pizza, + size: size, + // price: pizza.size.price, + quantity: 1 + }) - 1; + } + + //Оновити вміст кошика на сторінці + updateCart(); +} + +function removeFromCart(cart_item) { + //Видалити піцу з кошика + //TODO: треба зробити + + if (cart_item.cart_id){ + Cart.splice(cart_item.cart_id, 1); + + } + + //Після видалення оновити відображення + updateCart(); +} + +function initialiseCart() { + //Фукнція віпрацьвуватиме при завантаженні сторінки + //Тут можна наприклад, зчитати вміст корзини який збережено в Local Storage то показати його + //TODO: ... + var cart = localStorage.getItem("cart"); + if (cart) + Cart = JSON.parse(cart); + + $("#clear").click(clearCart); + + updateCart(); +} + +function clearCart(){ + Cart = []; + cart_map = []; + + + updateCart(); + count = 0; + //totalPrice=0; + + $("#count").html(count); + // $("#sumNum").html(totalPrice); +} + +function getPizzaInCart() { + //Повертає піци які зберігаються в кошику + return Cart; +} + +function updateCart() { + //Функція викликається при зміні вмісту кошика + //Тут можна наприклад показати оновлений кошик на екрані та зберегти вміт кошика в Local Storage + + //Очищаємо старі піци в кошику + $cart.html(""); + + //Онволення однієї піци + function showOnePizzaInCart(cart_item, id, arr) { + var html_code = Templates.PizzaCart_OneItem(cart_item); + + cart_item.cart_id = id; + + var $node = $(html_code); + + $node.find(".plus").click(function(){ + //Збільшуємо кількість замовлених піц + cart_item.quantity += 1; + count +=1; + // totalPrice+=cart_item.price; + //Оновлюємо відображення + updateCart(); + }); + + $node.find(".minus").click(function(){ + + if (cart_item.quantity > 1){ + cart_item.quantity -= 1; + // totalPrice-=cart_item.price; + count -=1; + } + + //Оновлюємо відображення + updateCart(); + }); + + + $node.find(".count-clear").click(function(){ + + count -= cart_item.quantity; + // totalPrice-=(cart_item.price*cart_item.quantity); + $("#count").html(count); + // $("#sumNum").html(totalPrice); + arr.splice(id, 1); + + updateCart(); + }); + count = 0; + // totalPrice=0; + if(Cart.length != 0){ + Cart.forEach(function(pizza){ + count += pizza.quantity; + // totalPrice+=(pizza.quantity*pizza.price); + }); + } +// else{ count = 0;totalPrice=0;} + else count=0; + $("#count").html(count); + // $("#sumNum").html(totalPrice); + + $cart.append($node); + } + + Cart.forEach(showOnePizzaInCart); + + localStorage.setItem("cart", JSON.stringify(Cart)); +} + +exports.removeFromCart = removeFromCart; +exports.addToCart = addToCart; + +exports.getPizzaInCart = getPizzaInCart; +exports.initialiseCart = initialiseCart; + +exports.PizzaSize = PizzaSize; +},{"../Templates":2}],5:[function(require,module,exports){ +/** + * Created by chaika on 02.02.16. + */ +var Templates = require('../Templates'); +var PizzaCart = require('./PizzaCart'); +var Pizza_List = require('../Pizza_List'); + +//HTML едемент куди будуть додаватися піци +var $pizza_list = $("#pizza_list"); + +function showPizzaList(list) { + //Очищаємо старі піци в кошику + $pizza_list.html(""); + + //Онволення однієї піци + function showOnePizza(pizza) { + var html_code = Templates.PizzaMenu_OneItem({pizza: pizza}); + + var $node = $(html_code); + + $node.find(".buy-big").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Big); + }); + $node.find(".buy-small").click(function(){ + PizzaCart.addToCart(pizza, PizzaCart.PizzaSize.Small); + }); + + $pizza_list.append($node); + } + + $("#pizzaNum").html(list.length); + + list.forEach(showOnePizza); +} + +function filterPizza(filter) { + //Масив куди потраплять піци які треба показати + var pizza_shown = []; + var filt = filter.split(","); + + + Pizza_List.forEach(function(pizza){ + //Якщо піка відповідає фільтру + //pizza_shown.push(pizza); + //var ingridient = getIngredientsArray(pizza); + var checked = []; + filt.forEach(function(f){ + //if(checked) return; + if(f.charAt(0) == '!'){ + var fil = f.substring(1); + if(!(fil in pizza.content)){ + checked.push(true); + } + else checked.push(false); + } else { + if(f in pizza.content) + checked.push(true); + else checked.push(false); + } + + //TODO: зробити фільтри + }); + function isTrue(element, index, array) { + return element == true; + } + if(checked.every(isTrue)) pizza_shown.push(pizza); +}); + + //Показати відфільтровані піци + showPizzaList(pizza_shown); +} + +function initialiseMenu() { + //Показуємо усі піци + showPizzaList(Pizza_List); + + $("#filter-button-meat").click(function(){ + $(".allPizzas").html("М'ясні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('meat'); + }); + + $("#filter-button-pineapples").click(function(){ + $(".allPizzas").html("Піци з ананасом"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('pineapple'); + }); + + $("#filter-button-mushrooms").click(function(){ + $(".allPizzas").html("Грибні піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('mushroom'); + }); + + $("#filter-button-ocean").click(function(){ + $(".allPizzas").html("Піци з морепродуктами"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('ocean'); + }); + + $("#filter-button-vega").click(function(){ + console.log("Vega"); + $(".allPizzas").html("Вегетаріанські піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + filterPizza('!meat,!ocean,!mushroom'); + }); + + $("#filter-button-all").click(function(){ + $(".allPizzas").html("Усі піци"); + $(".pizzaType-active").removeClass("pizzaType-active"); + $(this).addClass("pizzaType-active"); + showPizzaList(Pizza_List); + + }); +} + +exports.filterPizza = filterPizza; +exports.initialiseMenu = initialiseMenu; +},{"../Pizza_List":1,"../Templates":2,"./PizzaCart":4}],6:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +'use strict'; + +/** + * @file Embedded JavaScript templating engine. + * @author Matthew Eernisse + * @author Tiancheng "Timothy" Gu + * @project EJS + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0} + */ + +/** + * EJS internal functions. + * + * Technically this "module" lies in the same file as {@link module:ejs}, for + * the sake of organization all the private functions re grouped into this + * module. + * + * @module ejs-internal + * @private + */ + +/** + * Embedded JavaScript templating engine. + * + * @module ejs + * @public + */ + +var fs = require('fs') + , utils = require('./utils') + , scopeOptionWarned = false + , _VERSION_STRING = require('../package.json').version + , _DEFAULT_DELIMITER = '%' + , _DEFAULT_LOCALS_NAME = 'locals' + , _REGEX_STRING = '(<%%|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)' + , _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context' + , 'debug', 'compileDebug', 'client', '_with', 'rmWhitespace' + , 'strict', 'localsName' + ] + , _TRAILING_SEMCOL = /;\s*$/ + , _BOM = /^\uFEFF/; + +/** + * EJS template function cache. This can be a LRU object from lru-cache NPM + * module. By default, it is {@link module:utils.cache}, a simple in-process + * cache that grows continuously. + * + * @type {Cache} + */ + +exports.cache = utils.cache; + +/** + * Name of the object containing the locals. + * + * This variable is overriden by {@link Options}`.localsName` if it is not + * `undefined`. + * + * @type {String} + * @public + */ + +exports.localsName = _DEFAULT_LOCALS_NAME; + +/** + * Get the path to the included file from the parent file path and the + * specified path. + * + * @param {String} name specified path + * @param {String} filename parent file path + * @return {String} + */ + +exports.resolveInclude = function(name, filename) { + var path = require('path') + , dirname = path.dirname + , extname = path.extname + , resolve = path.resolve + , includePath = resolve(dirname(filename), name) + , ext = extname(name); + if (!ext) { + includePath += '.ejs'; + } + return includePath; +}; + +/** + * Get the template from a string or a file, either compiled on-the-fly or + * read from cache (if enabled), and cache the template if needed. + * + * If `template` is not set, the file specified in `options.filename` will be + * read. + * + * If `options.cache` is true, this function reads the file from + * `options.filename` so it must be set prior to calling this function. + * + * @memberof module:ejs-internal + * @param {Options} options compilation options + * @param {String} [template] template source + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned. + * @static + */ + +function handleCache(options, template) { + var fn + , path = options.filename + , hasTemplate = arguments.length > 1; + + if (options.cache) { + if (!path) { + throw new Error('cache option requires a filename'); + } + fn = exports.cache.get(path); + if (fn) { + return fn; + } + if (!hasTemplate) { + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + } + else if (!hasTemplate) { + // istanbul ignore if: should not happen at all + if (!path) { + throw new Error('Internal EJS error: no file name or template ' + + 'provided'); + } + template = fs.readFileSync(path).toString().replace(_BOM, ''); + } + fn = exports.compile(template, options); + if (options.cache) { + exports.cache.set(path, fn); + } + return fn; +} + +/** + * Get the template function. + * + * If `options.cache` is `true`, then the template is cached. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `options.client`, either type might be returned + * @static + */ + +function includeFile(path, options) { + var opts = utils.shallowCopy({}, options); + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + opts.filename = exports.resolveInclude(path, opts.filename); + return handleCache(opts); +} + +/** + * Get the JavaScript source of an included file. + * + * @memberof module:ejs-internal + * @param {String} path path for the specified file + * @param {Options} options compilation options + * @return {String} + * @static + */ + +function includeSource(path, options) { + var opts = utils.shallowCopy({}, options) + , includePath + , template; + if (!opts.filename) { + throw new Error('`include` requires the \'filename\' option.'); + } + includePath = exports.resolveInclude(path, opts.filename); + template = fs.readFileSync(includePath).toString().replace(_BOM, ''); + + opts.filename = includePath; + var templ = new Template(template, opts); + templ.generateSource(); + return templ.source; +} + +/** + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and + * `lineno`. + * + * @implements RethrowCallback + * @memberof module:ejs-internal + * @param {Error} err Error object + * @param {String} str EJS source + * @param {String} filename file name of the EJS file + * @param {String} lineno line number of the error + * @static + */ + +function rethrow(err, str, filename, lineno){ + var lines = str.split('\n') + , start = Math.max(lineno - 3, 0) + , end = Math.min(lines.length, lineno + 3); + + // Error context + var context = lines.slice(start, end).map(function (line, i){ + var curr = i + start + 1; + return (curr == lineno ? ' >> ' : ' ') + + curr + + '| ' + + line; + }).join('\n'); + + // Alter exception message + err.path = filename; + err.message = (filename || 'ejs') + ':' + + lineno + '\n' + + context + '\n\n' + + err.message; + + throw err; +} + +/** + * Copy properties in data object that are recognized as options to an + * options object. + * + * This is used for compatibility with earlier versions of EJS and Express.js. + * + * @memberof module:ejs-internal + * @param {Object} data data object + * @param {Options} opts options object + * @static + */ + +function cpOptsInData(data, opts) { + _OPTS.forEach(function (p) { + if (typeof data[p] != 'undefined') { + opts[p] = data[p]; + } + }); +} + +/** + * Compile the given `str` of ejs into a template function. + * + * @param {String} template EJS template + * + * @param {Options} opts compilation options + * + * @return {(TemplateFunction|ClientFunction)} + * Depending on the value of `opts.client`, either type might be returned. + * @public + */ + +exports.compile = function compile(template, opts) { + var templ; + + // v1 compat + // 'scope' is 'context' + // FIXME: Remove this in a future version + if (opts && opts.scope) { + if (!scopeOptionWarned){ + console.warn('`scope` option is deprecated and will be removed in EJS 3'); + scopeOptionWarned = true; + } + if (!opts.context) { + opts.context = opts.scope; + } + delete opts.scope; + } + templ = new Template(template, opts); + return templ.compile(); +}; + +/** + * Render the given `template` of ejs. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} template EJS template + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @return {String} + * @public + */ + +exports.render = function (template, data, opts) { + data = data || {}; + opts = opts || {}; + var fn; + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 2) { + cpOptsInData(data, opts); + } + + return handleCache(opts, template)(data); +}; + +/** + * Render an EJS file at the given `path` and callback `cb(err, str)`. + * + * If you would like to include options but not data, you need to explicitly + * call this function with `data` being an empty object or `null`. + * + * @param {String} path path to the EJS file + * @param {Object} [data={}] template data + * @param {Options} [opts={}] compilation and rendering options + * @param {RenderFileCallback} cb callback + * @public + */ + +exports.renderFile = function () { + var args = Array.prototype.slice.call(arguments) + , path = args.shift() + , cb = args.pop() + , data = args.shift() || {} + , opts = args.pop() || {} + , result; + + // Don't pollute passed in opts obj with new vals + opts = utils.shallowCopy({}, opts); + + // No options object -- if there are optiony names + // in the data, copy them to options + if (arguments.length == 3) { + // Express 4 + if (data.settings && data.settings['view options']) { + cpOptsInData(data.settings['view options'], opts); + } + // Express 3 and lower + else { + cpOptsInData(data, opts); + } + } + opts.filename = path; + + try { + result = handleCache(opts)(data); + } + catch(err) { + return cb(err); + } + return cb(null, result); +}; + +/** + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}. + * @public + */ + +exports.clearCache = function () { + exports.cache.reset(); +}; + +function Template(text, opts) { + opts = opts || {}; + var options = {}; + this.templateText = text; + this.mode = null; + this.truncate = false; + this.currentLine = 1; + this.source = ''; + this.dependencies = []; + options.client = opts.client || false; + options.escapeFunction = opts.escape || utils.escapeXML; + options.compileDebug = opts.compileDebug !== false; + options.debug = !!opts.debug; + options.filename = opts.filename; + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER; + options.strict = opts.strict || false; + options.context = opts.context; + options.cache = opts.cache || false; + options.rmWhitespace = opts.rmWhitespace; + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME; + + if (options.strict) { + options._with = false; + } + else { + options._with = typeof opts._with != 'undefined' ? opts._with : true; + } + + this.opts = options; + + this.regex = this.createRegex(); +} + +Template.modes = { + EVAL: 'eval' +, ESCAPED: 'escaped' +, RAW: 'raw' +, COMMENT: 'comment' +, LITERAL: 'literal' +}; + +Template.prototype = { + createRegex: function () { + var str = _REGEX_STRING + , delim = utils.escapeRegExpChars(this.opts.delimiter); + str = str.replace(/%/g, delim); + return new RegExp(str); + } + +, compile: function () { + var src + , fn + , opts = this.opts + , prepended = '' + , appended = '' + , escape = opts.escapeFunction; + + if (opts.rmWhitespace) { + // Have to use two separate replace here as `^` and `$` operators don't + // work well with `\r`. + this.templateText = + this.templateText.replace(/\r/g, '').replace(/^\s+|\s+$/gm, ''); + } + + // Slurp spaces and tabs before <%_ and after _%> + this.templateText = + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>'); + + if (!this.source) { + this.generateSource(); + prepended += ' var __output = [], __append = __output.push.bind(__output);' + '\n'; + if (opts._with !== false) { + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n'; + appended += ' }' + '\n'; + } + appended += ' return __output.join("");' + '\n'; + this.source = prepended + this.source + appended; + } + + if (opts.compileDebug) { + src = 'var __line = 1' + '\n' + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n' + + ' , __filename = ' + (opts.filename ? + JSON.stringify(opts.filename) : 'undefined') + ';' + '\n' + + 'try {' + '\n' + + this.source + + '} catch (e) {' + '\n' + + ' rethrow(e, __lines, __filename, __line);' + '\n' + + '}' + '\n'; + } + else { + src = this.source; + } + + if (opts.debug) { + console.log(src); + } + + if (opts.client) { + src = 'escape = escape || ' + escape.toString() + ';' + '\n' + src; + if (opts.compileDebug) { + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src; + } + } + + if (opts.strict) { + src = '"use strict";\n' + src; + } + + try { + fn = new Function(opts.localsName + ', escape, include, rethrow', src); + } + catch(e) { + // istanbul ignore else + if (e instanceof SyntaxError) { + if (opts.filename) { + e.message += ' in ' + opts.filename; + } + e.message += ' while compiling ejs'; + } + throw e; + } + + if (opts.client) { + fn.dependencies = this.dependencies; + return fn; + } + + // Return a callable function which will execute the function + // created by the source-code, with the passed data as locals + // Adds a local `include` function which allows full recursive include + var returnedFn = function (data) { + var include = function (path, includeData) { + var d = utils.shallowCopy({}, data); + if (includeData) { + d = utils.shallowCopy(d, includeData); + } + return includeFile(path, opts)(d); + }; + return fn.apply(opts.context, [data || {}, escape, include, rethrow]); + }; + returnedFn.dependencies = this.dependencies; + return returnedFn; + } + +, generateSource: function () { + var self = this + , matches = this.parseTemplateText() + , d = this.opts.delimiter; + + if (matches && matches.length) { + if (this.opts.compileDebug && this.opts.filename) { + this.source = ' ; __lines = ' + JSON.stringify(this.templateText) + '\n'; + this.source += ' ; __filename = "' + this.opts.filename.replace(/\\/g, '/') + '"\n'; + } + matches.forEach(function (line, index) { + var opening + , closing + , include + , includeOpts + , includeSrc; + // If this is an opening tag, check for closing tags + // FIXME: May end up with some false positives here + // Better to store modes as k/v with '<' + delimiter as key + // Then this can simply check against the map + if ( line.indexOf('<' + d) === 0 // If it is a tag + && line.indexOf('<' + d + d) !== 0) { // and is not escaped + closing = matches[index + 2]; + if (!(closing == d + '>' || closing == '-' + d + '>' || closing == '_' + d + '>')) { + throw new Error('Could not find matching close tag for "' + line + '".'); + } + } + // HACK: backward-compat `include` preprocessor directives + if ((include = line.match(/^\s*include\s+(\S+)/))) { + opening = matches[index - 1]; + // Must be in EVAL or RAW mode + if (opening && (opening == '<' + d || opening == '<' + d + '-' || opening == '<' + d + '_')) { + includeOpts = utils.shallowCopy({}, self.opts); + includeSrc = includeSource(include[1], includeOpts); + includeSrc = ' ; (function(){' + '\n' + includeSrc + + ' ; })()' + '\n'; + self.source += includeSrc; + self.dependencies.push(exports.resolveInclude(include[1], + includeOpts.filename)); + return; + } + } + self.scanLine(line); + }); + } + + } + +, parseTemplateText: function () { + var str = this.templateText + , pat = this.regex + , result = pat.exec(str) + , arr = [] + , firstPos + , lastPos; + + while (result) { + firstPos = result.index; + lastPos = pat.lastIndex; + + if (firstPos !== 0) { + arr.push(str.substring(0, firstPos)); + str = str.slice(firstPos); + } + + arr.push(result[0]); + str = str.slice(result[0].length); + result = pat.exec(str); + } + + if (str) { + arr.push(str); + } + + return arr; + } + +, scanLine: function (line) { + var self = this + , d = this.opts.delimiter + , newLineCount = 0; + + function _addOutput() { + if (self.truncate) { + // Only replace single leading linebreak in the line after + // -%> tag -- this is the single, trailing linebreak + // after the tag that the truncation mode replaces + // Handle Win / Unix / old Mac linebreaks -- do the \r\n + // combo first in the regex-or + line = line.replace(/^(?:\r\n|\r|\n)/, '') + self.truncate = false; + } + else if (self.opts.rmWhitespace) { + // Gotta be more careful here. + // .replace(/^(\s*)\n/, '$1') might be more appropriate here but as + // rmWhitespace already removes trailing spaces anyway so meh. + line = line.replace(/^\n/, ''); + } + if (!line) { + return; + } + + // Preserve literal slashes + line = line.replace(/\\/g, '\\\\'); + + // Convert linebreaks + line = line.replace(/\n/g, '\\n'); + line = line.replace(/\r/g, '\\r'); + + // Escape double-quotes + // - this will be the delimiter during execution + line = line.replace(/"/g, '\\"'); + self.source += ' ; __append("' + line + '")' + '\n'; + } + + newLineCount = (line.split('\n').length - 1); + + switch (line) { + case '<' + d: + case '<' + d + '_': + this.mode = Template.modes.EVAL; + break; + case '<' + d + '=': + this.mode = Template.modes.ESCAPED; + break; + case '<' + d + '-': + this.mode = Template.modes.RAW; + break; + case '<' + d + '#': + this.mode = Template.modes.COMMENT; + break; + case '<' + d + d: + this.mode = Template.modes.LITERAL; + this.source += ' ; __append("' + line.replace('<' + d + d, '<' + d) + '")' + '\n'; + break; + case d + '>': + case '-' + d + '>': + case '_' + d + '>': + if (this.mode == Template.modes.LITERAL) { + _addOutput(); + } + + this.mode = null; + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0; + break; + default: + // In script mode, depends on type of tag + if (this.mode) { + // If '//' is found without a line break, add a line break. + switch (this.mode) { + case Template.modes.EVAL: + case Template.modes.ESCAPED: + case Template.modes.RAW: + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) { + line += '\n'; + } + } + switch (this.mode) { + // Just executing code + case Template.modes.EVAL: + this.source += ' ; ' + line + '\n'; + break; + // Exec, esc, and output + case Template.modes.ESCAPED: + this.source += ' ; __append(escape(' + + line.replace(_TRAILING_SEMCOL, '').trim() + '))' + '\n'; + break; + // Exec and output + case Template.modes.RAW: + this.source += ' ; __append(' + + line.replace(_TRAILING_SEMCOL, '').trim() + ')' + '\n'; + break; + case Template.modes.COMMENT: + // Do nothing + break; + // Literal <%% mode, append as raw output + case Template.modes.LITERAL: + _addOutput(); + break; + } + } + // In string mode, just add the output + else { + _addOutput(); + } + } + + if (self.opts.compileDebug && newLineCount) { + this.currentLine += newLineCount; + this.source += ' ; __line = ' + this.currentLine + '\n'; + } + } +}; + +/* + * Export the internal function for escaping XML so people + * can use for manual escaping if needed + * */ +exports.escapeXML = utils.escapeXML; + +/** + * Express.js support. + * + * This is an alias for {@link module:ejs.renderFile}, in order to support + * Express.js out-of-the-box. + * + * @func + */ + +exports.__express = exports.renderFile; + +// Add require support +/* istanbul ignore else */ +if (require.extensions) { + require.extensions['.ejs'] = function (module, filename) { + filename = filename || /* istanbul ignore next */ module.filename; + var options = { + filename: filename + , client: true + } + , template = fs.readFileSync(filename).toString() + , fn = exports.compile(template, options); + module._compile('module.exports = ' + fn.toString() + ';', filename); + }; +} + +/** + * Version of EJS. + * + * @readonly + * @type {String} + * @public + */ + +exports.VERSION = _VERSION_STRING; + +/* istanbul ignore if */ +if (typeof window != 'undefined') { + window.ejs = exports; +} + +},{"../package.json":8,"./utils":7,"fs":9,"path":10}],7:[function(require,module,exports){ +/* + * EJS Embedded JavaScript templates + * Copyright 2112 Matthew Eernisse (mde@fleegix.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +/** + * Private utility functions + * @module utils + * @private + */ + +'use strict'; + +var regExpChars = /[|\\{}()[\]^$+*?.]/g; + +/** + * Escape characters reserved in regular expressions. + * + * If `string` is `undefined` or `null`, the empty string is returned. + * + * @param {String} string Input string + * @return {String} Escaped string + * @static + * @private + */ +exports.escapeRegExpChars = function (string) { + // istanbul ignore if + if (!string) { + return ''; + } + return String(string).replace(regExpChars, '\\$&'); +}; + +var _ENCODE_HTML_RULES = { + '&': '&' + , '<': '<' + , '>': '>' + , '"': '"' + , "'": ''' + } + , _MATCH_HTML = /[&<>\'"]/g; + +function encode_char(c) { + return _ENCODE_HTML_RULES[c] || c; +}; + +/** + * Stringified version of constants used by {@link module:utils.escapeXML}. + * + * It is used in the process of generating {@link ClientFunction}s. + * + * @readonly + * @type {String} + */ + +var escapeFuncStr = + 'var _ENCODE_HTML_RULES = {\n' ++ ' "&": "&"\n' ++ ' , "<": "<"\n' ++ ' , ">": ">"\n' ++ ' , \'"\': """\n' ++ ' , "\'": "'"\n' ++ ' }\n' ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n' ++ 'function encode_char(c) {\n' ++ ' return _ENCODE_HTML_RULES[c] || c;\n' ++ '};\n'; + +/** + * Escape characters reserved in XML. + * + * If `markup` is `undefined` or `null`, the empty string is returned. + * + * @implements {EscapeCallback} + * @param {String} markup Input string + * @return {String} Escaped string + * @static + * @private + */ + +exports.escapeXML = function (markup) { + return markup == undefined + ? '' + : String(markup) + .replace(_MATCH_HTML, encode_char); +}; +exports.escapeXML.toString = function () { + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr +}; + +/** + * Copy all properties from one object to another, in a shallow fashion. + * + * @param {Object} to Destination object + * @param {Object} from Source object + * @return {Object} Destination object + * @static + * @private + */ +exports.shallowCopy = function (to, from) { + from = from || {}; + for (var p in from) { + to[p] = from[p]; + } + return to; +}; + +/** + * Simple in-process cache implementation. Does not implement limits of any + * sort. + * + * @implements Cache + * @static + * @private + */ +exports.cache = { + _data: {}, + set: function (key, val) { + this._data[key] = val; + }, + get: function (key) { + return this._data[key]; + }, + reset: function () { + this._data = {}; + } +}; + + +},{}],8:[function(require,module,exports){ +module.exports={ + "name": "ejs", + "description": "Embedded JavaScript templates", + "keywords": [ + "template", + "engine", + "ejs" + ], + "version": "2.4.2", + "author": { + "name": "Matthew Eernisse", + "email": "mde@fleegix.org", + "url": "http://fleegix.org" + }, + "contributors": [ + { + "name": "Timothy Gu", + "email": "timothygu99@gmail.com", + "url": "https://timothygu.github.io" + } + ], + "license": "Apache-2.0", + "main": "./lib/ejs.js", + "repository": { + "type": "git", + "url": "git://github.com/mde/ejs.git" + }, + "bugs": { + "url": "https://github.com/mde/ejs/issues" + }, + "homepage": "https://github.com/mde/ejs", + "dependencies": {}, + "devDependencies": { + "browserify": "^8.0.3", + "istanbul": "~0.3.5", + "jake": "^8.0.0", + "jsdoc": "^3.3.0-beta1", + "lru-cache": "^2.5.0", + "mocha": "^2.1.0", + "rimraf": "^2.2.8", + "uglify-js": "^2.4.16" + }, + "engines": { + "node": ">=0.10.0" + }, + "scripts": { + "test": "mocha", + "sample": "npm install express && node sample/index.js", + "coverage": "istanbul cover node_modules/mocha/bin/_mocha", + "doc": "rimraf out && jsdoc -c jsdoc.json lib/* docs/jsdoc/*", + "devdoc": "rimraf out && jsdoc -p -c jsdoc.json lib/* docs/jsdoc/*" + }, + "_id": "ejs@2.4.2", + "_shasum": "7057eb4812958fb731841cd9ca353343efe597b1", + "_resolved": "https://registry.npmjs.org/ejs/-/ejs-2.4.2.tgz", + "_from": "ejs@>=2.4.1 <3.0.0", + "_npmVersion": "2.15.1", + "_nodeVersion": "4.4.4", + "_npmUser": { + "name": "mde", + "email": "mde@fleegix.org" + }, + "maintainers": [ + { + "name": "tjholowaychuk", + "email": "tj@vision-media.ca" + }, + { + "name": "mde", + "email": "mde@fleegix.org" + } + ], + "dist": { + "shasum": "7057eb4812958fb731841cd9ca353343efe597b1", + "tarball": "https://registry.npmjs.org/ejs/-/ejs-2.4.2.tgz" + }, + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/ejs-2.4.2.tgz_1464117640663_0.8193834638223052" + }, + "directories": {} +} + +},{}],9:[function(require,module,exports){ + +},{}],10:[function(require,module,exports){ +(function (process){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// resolves . and .. elements in a path array with directory names there +// must be no slashes, empty elements, or device names (c:\) in the array +// (so also no leading and trailing slashes - it does not distinguish +// relative and absolute paths) +function normalizeArray(parts, allowAboveRoot) { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up--; up) { + parts.unshift('..'); + } + } + + return parts; +} + +// Split a filename into [root, dir, basename, ext], unix version +// 'root' is just a slash, or nothing. +var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; +var splitPath = function(filename) { + return splitPathRe.exec(filename).slice(1); +}; + +// path.resolve([from ...], to) +// posix version +exports.resolve = function() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : process.cwd(); + + // Skip empty and invalid entries + if (typeof path !== 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charAt(0) === '/'; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { + return !!p; + }), !resolvedAbsolute).join('/'); + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; +}; + +// path.normalize(path) +// posix version +exports.normalize = function(path) { + var isAbsolute = exports.isAbsolute(path), + trailingSlash = substr(path, -1) === '/'; + + // Normalize the path + path = normalizeArray(filter(path.split('/'), function(p) { + return !!p; + }), !isAbsolute).join('/'); + + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + + return (isAbsolute ? '/' : '') + path; +}; + +// posix version +exports.isAbsolute = function(path) { + return path.charAt(0) === '/'; +}; + +// posix version +exports.join = function() { + var paths = Array.prototype.slice.call(arguments, 0); + return exports.normalize(filter(paths, function(p, index) { + if (typeof p !== 'string') { + throw new TypeError('Arguments to path.join must be strings'); + } + return p; + }).join('/')); +}; + + +// path.relative(from, to) +// posix version +exports.relative = function(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); +}; + +exports.sep = '/'; +exports.delimiter = ':'; + +exports.dirname = function(path) { + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substr(0, dir.length - 1); + } + + return root + dir; +}; + + +exports.basename = function(path, ext) { + var f = splitPath(path)[2]; + // TODO: make this comparison case-insensitive on windows? + if (ext && f.substr(-1 * ext.length) === ext) { + f = f.substr(0, f.length - ext.length); + } + return f; +}; + + +exports.extname = function(path) { + return splitPath(path)[3]; +}; + +function filter (xs, f) { + if (xs.filter) return xs.filter(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + if (f(xs[i], i, xs)) res.push(xs[i]); + } + return res; +} + +// String.prototype.substr - negative index don't work in IE8 +var substr = 'ab'.substr(-1) === 'b' + ? function (str, start, len) { return str.substr(start, len) } + : function (str, start, len) { + if (start < 0) start = str.length + start; + return str.substr(start, len); + } +; + +}).call(this,require('_process')) +},{"_process":11}],11:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = setTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + clearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + setTimeout(drainQueue, 0); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}]},{},[3]); + +function getElByClass(name, type) +{ + var r = []; + var re = new RegExp("(^|\\s)" + name + "(\\s|$)"); + var e = (type) ? getElByTag(type) : ((navigator.userAgent.indexOf("MSIE") >= 0) ? document.all : getElByTag("*")); + for ( var j = 0; j < e.length; j++ ) + if (re.test(attr(e[j], "class"))) + r.push( e[j] ) + return r; +} + +function attr(el, at, value) +{ + at = {'for': 'htmlFor', 'class': 'className'}[at] || at; + if(!value) + return el[at] || el.getAttribute(at) || ''; + else + { + el[at] = value; + if (el.setAttribute) + el.setAttribute(at, value); + } +} + +function getElByTag(tag, el) +{ + return (el || document).getElementsByTagName(tag); +} + +function getElByName(name) +{ + return document.getElementsByName(name); +} + +function getElById(id) +{ + return document.getElementById(id); +} \ No newline at end of file diff --git a/Frontend/www/assets/less/main.less b/Frontend/www/assets/less/main.less index 0c1811f50..2aee823b7 100644 --- a/Frontend/www/assets/less/main.less +++ b/Frontend/www/assets/less/main.less @@ -296,4 +296,12 @@ img { #cartSum{ text-align: right; +} + +#googleMap{ + padding-left: 50px; + width: 100%; + height: 250px; + margin-bottom: 30px; + margin-top: 10px; } \ No newline at end of file diff --git a/Frontend/www/index.html b/Frontend/www/index.html index df14c6883..a0863ce54 100644 --- a/Frontend/www/index.html +++ b/Frontend/www/index.html @@ -15,6 +15,7 @@ +
@@ -108,6 +109,6 @@ - + \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 91f083c99..7fe2d8fb6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,63 +1,63 @@ -/** - * Created by Andriy on 10.03.2015. - */ -module.exports = function(grunt) { - //Налаштування збірки Grunt - var config = { - //Інформацію про проект з файлу package.json - pkg: grunt.file.readJSON('package.json'), - - //Конфігурація для модуля browserify (перетворює require(..) в код - browserify: { - //Загальні налаштування (grunt-browserify) - options: { - - //brfs замість fs.readFileSync вставляє вміст файлу - transform: [ require('brfs') ], - browserifyOptions: { - //Папка з корнем джерельних кодів javascript - basedir: "Frontend/src/js/" - } - }, - - //Збірка з назвою піца - pizza: { - src: 'Frontend/src/main.js', - dest: 'Frontend/www/assets/js/main.js' - } - } - }; - - //Налаштування відстежування змін в проекті - var watchDebug = { - options: { - 'no-beep': true - }, - //Назва завдання будь-яка - scripts: { - //На зміни в яких файлах реагувати - files: ['Frontend/src/**/*.js', 'Frontend/**/*.ejs'], - //Які завдання виконувати під час зміни в файлах - tasks: ['browserify:pizza'] - } - }; - - - //Ініціалузвати Grunt - config.watch = watchDebug; - grunt.initConfig(config); - - //Сказати які модулі необхідно виокристовувати - grunt.loadNpmTasks('grunt-browserify'); - grunt.loadNpmTasks('grunt-contrib-watch'); - - - //Список завданнь по замовчування - grunt.registerTask('default', - [ - 'browserify:pizza', - //Інші завдання які необхідно виконати - ] - ); - +/** + * Created by Andriy on 10.03.2015. + */ +module.exports = function(grunt) { + //Налаштування збірки Grunt + var config = { + //Інформацію про проект з файлу package.json + pkg: grunt.file.readJSON('package.json'), + + //Конфігурація для модуля browserify (перетворює require(..) в код + browserify: { + //Загальні налаштування (grunt-browserify) + options: { + + //brfs замість fs.readFileSync вставляє вміст файлу + transform: [ require('brfs') ], + browserifyOptions: { + //Папка з корнем джерельних кодів javascript + basedir: "Frontend/src/js/" + } + }, + + //Збірка з назвою піца + pizza: { + src: 'Frontend/src/main.js', + dest: 'Frontend/www/assets/js/main.js' + } + } + }; + + //Налаштування відстежування змін в проекті + var watchDebug = { + options: { + 'no-beep': true + }, + //Назва завдання будь-яка + scripts: { + //На зміни в яких файлах реагувати + files: ['Frontend/src/**/*.js', 'Frontend/**/*.ejs'], + //Які завдання виконувати під час зміни в файлах + tasks: ['browserify:pizza'] + } + }; + + + //Ініціалузвати Grunt + config.watch = watchDebug; + grunt.initConfig(config); + + //Сказати які модулі необхідно виокристовувати + grunt.loadNpmTasks('grunt-browserify'); + grunt.loadNpmTasks('grunt-contrib-watch'); + + + //Список завданнь по замовчування + grunt.registerTask('default', + [ + 'browserify:pizza', + //Інші завдання які необхідно виконати + ] + ); + }; \ No newline at end of file diff --git a/package.json b/package.json index a4e3a9d89..697531a0b 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,13 @@ "license": "ISC", "dependencies": { "basil.js": "^0.4.3", + "body-parser": "^1.14.2", "brfs": "^1.4.3", "ejs": "^2.4.1", + "express": "^4.13.4", "grunt": "^0.4.5", "grunt-browserify": "^4.0.1", - "grunt-contrib-watch": "^0.6.1" + "grunt-contrib-watch": "^0.6.1", + "morgan": "^1.6.1" } } diff --git a/server.js b/server.js new file mode 100644 index 000000000..f30329cde --- /dev/null +++ b/server.js @@ -0,0 +1,2 @@ +var main = require('./Backend/main'); +main.startServer(5050); \ No newline at end of file