diff --git a/order.js b/order.js deleted file mode 100644 index a49d42e..0000000 --- a/order.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * @license RequireJS order 1.0.5 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. - * Available via the MIT or new BSD license. - * see: http://github.com/jrburke/requirejs for details - */ -/*jslint nomen: false, plusplus: false, strict: false */ -/*global require: false, define: false, window: false, document: false, - setTimeout: false */ - -//Specify that requirejs optimizer should wrap this code in a closure that -//maps the namespaced requirejs API to non-namespaced local variables. -/*requirejs namespace: true */ - -(function () { - - //Sadly necessary browser inference due to differences in the way - //that browsers load and execute dynamically inserted javascript - //and whether the script/cache method works when ordered execution is - //desired. Currently, Gecko and Opera do not load/fire onload for scripts with - //type="script/cache" but they execute injected scripts in order - //unless the 'async' flag is present. - //However, this is all changing in latest browsers implementing HTML5 - //spec. With compliant browsers .async true by default, and - //if false, then it will execute in order. Favor that test first for forward - //compatibility. - ohImBadVar3 = 'fuuuu'; - var testScript = typeof document !== "undefined" && - typeof window !== "undefined" && - document.createElement("script"), - - supportsInOrderExecution = testScript && (testScript.async || - ((window.opera && - Object.prototype.toString.call(window.opera) === "[object Opera]") || - //If Firefox 2 does not have to be supported, then - //a better check may be: - //('mozIsLocallyAvailable' in window.navigator) - ("MozAppearance" in document.documentElement.style))), - - //This test is true for IE browsers, which will load scripts but only - //execute them once the script is added to the DOM. - supportsLoadSeparateFromExecute = testScript && - testScript.readyState === 'uninitialized', - - readyRegExp = /^(complete|loaded)$/, - cacheWaiting = [], - cached = {}, - scriptNodes = {}, - scriptWaiting = []; - - //Done with the test script. - testScript = null; - - //Callback used by the type="script/cache" callback that indicates a script - //has finished downloading. - function scriptCacheCallback(evt) { - var node = evt.currentTarget || evt.srcElement, i, - moduleName, resource; - - if (evt.type === "load" || readyRegExp.test(node.readyState)) { - //Pull out the name of the module and the context. - moduleName = node.getAttribute("data-requiremodule"); - - //Mark this cache request as loaded - cached[moduleName] = true; - - //Find out how many ordered modules have loaded - for (i = 0; (resource = cacheWaiting[i]); i++) { - if (cached[resource.name]) { - resource.req([resource.name], resource.onLoad); - } else { - //Something in the ordered list is not loaded, - //so wait. - break; - } - } - - //If just loaded some items, remove them from cacheWaiting. - if (i > 0) { - cacheWaiting.splice(0, i); - } - - //Remove this script tag from the DOM - //Use a setTimeout for cleanup because some older IE versions vomit - //if removing a script node while it is being evaluated. - setTimeout(function () { - node.parentNode.removeChild(node); - }, 15); - } - } - - /** - * Used for the IE case, where fetching is done by creating script element - * but not attaching it to the DOM. This function will be called when that - * happens so it can be determined when the node can be attached to the - * DOM to trigger its execution. - */ - function onFetchOnly(node) { - var i, loadedNode, resourceName; - - //Mark this script as loaded. - node.setAttribute('data-orderloaded', 'loaded'); - - //Cycle through waiting scripts. If the matching node for them - //is loaded, and is in the right order, add it to the DOM - //to execute the script. - for (i = 0; (resourceName = scriptWaiting[i]); i++) { - loadedNode = scriptNodes[resourceName]; - if (loadedNode && - loadedNode.getAttribute('data-orderloaded') === 'loaded') { - delete scriptNodes[resourceName]; - require.addScriptToDom(loadedNode); - } else { - break; - } - } - - //If just loaded some items, remove them from waiting. - if (i > 0) { - scriptWaiting.splice(0, i); - } - } - - define({ - version: '1.0.5', - - load: function (name, req, onLoad, config) { - var hasToUrl = !!req.nameToUrl, - url, node, context; - - //If no nameToUrl, then probably a build with a loader that - //does not support it, and all modules are inlined. - if (!hasToUrl) { - req([name], onLoad); - return; - } - - url = req.nameToUrl(name, null); - - //Make sure the async attribute is not set for any pathway involving - //this script. - require.s.skipAsync[url] = true; - if (supportsInOrderExecution || config.isBuild) { - //Just a normal script tag append, but without async attribute - //on the script. - req([name], onLoad); - } else if (supportsLoadSeparateFromExecute) { - //Just fetch the URL, but do not execute it yet. The - //non-standards IE case. Really not so nice because it is - //assuming and touching requrejs internals. OK though since - //ordered execution should go away after a long while. - context = require.s.contexts._; - - if (!context.urlFetched[url] && !context.loaded[name]) { - //Indicate the script is being fetched. - context.urlFetched[url] = true; - - //Stuff from require.load - require.resourcesReady(false); - context.scriptCount += 1; - - //Fetch the script now, remember it. - node = require.attach(url, context, name, null, null, onFetchOnly); - scriptNodes[name] = node; - scriptWaiting.push(name); - } - - //Do a normal require for it, once it loads, use it as return - //value. - req([name], onLoad); - } else { - //Credit to LABjs author Kyle Simpson for finding that scripts - //with type="script/cache" allow scripts to be downloaded into - //browser cache but not executed. Use that - //so that subsequent addition of a real type="text/javascript" - //tag will cause the scripts to be executed immediately in the - //correct order. - if (req.specified(name)) { - req([name], onLoad); - } else { - cacheWaiting.push({ - name: name, - req: req, - onLoad: onLoad - }); - require.attach(url, null, name, scriptCacheCallback, "script/cache"); - } - } - } - }); -}()); \ No newline at end of file diff --git a/utilitybelt/__init__.py b/utilitybelt/__init__.py new file mode 100644 index 0000000..3bfbec1 --- /dev/null +++ b/utilitybelt/__init__.py @@ -0,0 +1,6 @@ +try: + import pkg_resources + pkg_resources.declare_namespace(__name__) +except ImportError: + import pkgutil + __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/utilitybelt/apps/Frontend_AU/config.js b/utilitybelt/apps/Frontend_AU/config.js new file mode 100644 index 0000000..479b8ec --- /dev/null +++ b/utilitybelt/apps/Frontend_AU/config.js @@ -0,0 +1,45 @@ +/* + * Config file + * We use RequireJS as a module loader http://requirejs.org/docs/api.html + */ +var requireBaseUrl = '/utilitybelt/utilitybelt'; + +require.config({ + baseUrl: requireBaseUrl, + waitSeconds: 30 +}); + +require(['core/config'], function(config) { + + require(config.coreLibs, function() { + + config.coreInit.apply(core, arguments); + + require([ + /* Inlcude application files */ + 'order!apps/Frontend_AU/namespaces', + 'order!apps/Frontend_AU/config/messages', + 'order!apps/Frontend_AU/pages/Page', + 'order!apps/Frontend_AU/pages/Menu', + 'order!apps/Frontend_AU/pages/Checkout', + 'order!apps/Frontend_AU/pages/RestaurantList', + 'order!apps/Frontend_AU/pages/RestaurantListOpen', + 'order!apps/Frontend_AU/pages/LoggedIn', + 'order!apps/Frontend_AU/pages/Confirm', + 'order!apps/Frontend_AU/pages/LandingPage', + 'order!core/tests/fixtures/Locations' + ], function() { + core.messages.au = _.extend(core.messages.en, core.messages.au); + if (typeof(lh_data) == 'undefined') { + lh_data = {}; + } + if (!lh_data.current_page) { + lh_data.current_page = 'app.Home'; + } + core.Router(lh_data.current_page, lh_data); + }); + }); + +}); + +var APP_LANGUAGE = 'au'; diff --git a/utilitybelt/apps/Frontend_AU/config/messages.js b/utilitybelt/apps/Frontend_AU/config/messages.js new file mode 100644 index 0000000..ebd0383 --- /dev/null +++ b/utilitybelt/apps/Frontend_AU/config/messages.js @@ -0,0 +1,5 @@ + +/** AU application messages */ + +core.messages.au = { +}; diff --git a/utilitybelt/apps/Frontend_AU/menu_page.html b/utilitybelt/apps/Frontend_AU/menu_page.html new file mode 100644 index 0000000..c6a9f70 --- /dev/null +++ b/utilitybelt/apps/Frontend_AU/menu_page.html @@ -0,0 +1,323 @@ + + +
+ +Basic core View, all views (widgets) should extend it
", + "summary": "Basic core View, all views (widgets) should extend it
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "core.define('core.View', {\r\n\r\n extend: 'Backbone.View'," + }, + { + "tags": [], + "description": { + "full": "Runs on widget's render, triggers 'render' event
", + "summary": "Runs on widget's render, triggers 'render' event
", + "body": "" + }, + "ignore": false, + "code": "render: function(arg1, arg2) {\r\n\r\n var me = this;\r\n setTimeout( function() {\r\n me.trigger('render');\r\n }, 1);\r\n\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "jQuery" + ], + "name": "ct", + "description": "Jquery container to render to" + } + ], + "description": { + "full": "Renders widget to specified cotainer
", + "summary": "Renders widget to specified cotainer
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "renderTo: function(ct) {\r\n var me = this;\r\n this.on('render', function() {\r\n ct.empty().append(me.$el);\r\n });\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Class" + ], + "name": "type", + "description": "Class name which should be added\r" + }, + { + "type": "param", + "types": [ + "Object" + ], + "name": "config", + "description": "Class config options\r" + }, + { + "type": "returns", + "string": "added element" + } + ], + "description": { + "full": "Adds an instance of the \"type\" widget into the body (container returned by the getBody() method)
", + "summary": "Adds an instance of the \"type\" widget into the body (container returned by the getBody() method)
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "addItem: function(type, config) {\r\n if (this.getBody) {\r\n var $body = this.getBody();\r\n var new_el = new type(config);\r\n $body.append(new_el.$el); \r\n return new_el;\r\n }\r\n },\r\n\r\n demo: function() {\r\n return $('')\r\n }\r\n\r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.Box.json b/utilitybelt/apps/UB_docs/data/core.views.Box.json new file mode 100644 index 0000000..b744c6f --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.Box.json @@ -0,0 +1,150 @@ +[ + { + "tags": [ + { + "type": "title", + "string": "Basic Box" + }, + { + "type": "param", + "types": [ + "String" + ], + "name": "title", + "description": "Title" + }, + { + "type": "param", + "types": [ + "String" + ], + "name": "content", + "description": "Content" + }, + { + "type": "param", + "types": [ + "String" + ], + "name": "tempate", + "description": "Path to template" + } + ], + "description": { + "full": "Basic Box with the configurable header, footer, and content
\n\nvar bb = new core.views.Box({ title: 'Some awesome title', content: 'Awesomest content', el: $('#box-container') });\nbb.show();\n",
+ "summary": "Basic Box with the configurable header, footer, and content
", + "body": "var bb = new core.views.Box({ title: 'Some awesome title', content: 'Awesomest content', el: $('#box-container') });\nbb.show();\n"
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.Box', {\n\n extend: 'core.View',\n\n className: \"Box\",\n\n template: 'Box/base.html',"
+ },
+ {
+ "tags": [
+ {
+ "type": "constructor",
+ "string": ""
+ }
+ ],
+ "description": {
+ "full": "Initialize the widget
", + "summary": "Initialize the widget
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function() {\n\n var template = this.options.template || this.template;\n\n var me = this;\n core.utils.getTemplate(template, function(tpl) {\n me.template = tpl;\n me.render(tpl);\n });\n },\n\n render: function(tpl) {\n tpl = tpl || this.template;\n this.el = _.template(tpl, { some: 'here' });\n this.appendElement(this.el);\n\n var title = this.title || this.options.title || this.$el.attr('header');\n if (title" + }, + { + "tags": [], + "description": { + "full": "& $('.title-container', this.$el).length < 1
", + "summary": "& $('.title-container', this.$el).length < 1
", + "body": "" + }, + "ignore": false, + "code": "{\n this.setTitle(title);\n }\n\n var content = this.options.content;\n if (content) {\n this.setContent(content);\n }\n\n core.views.Box.__super__.render.call(this);\n }," + }, + { + "tags": [], + "description": { + "full": "Method for appending the final mark-up to DOM. By default, adds it to the this.el
Should be overriden for Lightbox-alike widgets (which render themself to the
Method for appending the final mark-up to DOM. By default, adds it to the this.el
Should be overriden for Lightbox-alike widgets (which render themself to the
Set title for the Lightbox
", + "summary": "Set title for the Lightbox
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "setTitle: function(title) {\n this.$('.title-container').html(title);\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "String" + ], + "name": "content", + "description": "Lightbox Content" + } + ], + "description": { + "full": "Set content for the Lightbox
", + "summary": "Set content for the Lightbox
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "setContent: function(content) {\n this.getBody().html(content);\n }," + }, + { + "tags": [ + { + "type": "returns", + "string": "jQuery" + } + ], + "description": { + "full": "Returns body element
", + "summary": "Returns body element
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "getBody: function() {\n return this.$('.body-box');\n }," + }, + { + "tags": [ + { + "type": "returns", + "string": "jQuery" + } + ], + "description": { + "full": "Adds link to title container and return its element
", + "summary": "Adds link to title container and return its element
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "addTitleLink: function(html) {\n var $title_link = this.$('.top-box .title-link');\n return $title_link.append(html);\n },\n\n demo: function() {\n var bb = new core.views.Box({ title: 'Box title' });\n return bb;\n }\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.Cart.json b/utilitybelt/apps/UB_docs/data/core.views.Cart.json new file mode 100644 index 0000000..cd1c19c --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.Cart.json @@ -0,0 +1,137 @@ +[ + { + "tags": [ + { + "type": "param", + "types": [ + "Cart" + ], + "name": "cart", + "description": "The linked Cart item" + } + ], + "description": { + "full": "View for displaying a cart
\n\nvar cart = new core.views.Cart();\ncart.renderTo($('#some_element'));\n",
+ "summary": "View for displaying a cart
", + "body": "var cart = new core.views.Cart();\ncart.renderTo($('#some_element'));\n"
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.Cart', {\n extend: 'core.View',\n className: 'Cart',\n template: [],\n events: {'change select': 'sumUpdate'},\n plugins: {\n 'select': ['spinner', {cycle: false}]\n },"
+ },
+ {
+ "tags": [],
+ "description": {
+ "full": "Constructor, sets collection and templates
", + "summary": "Constructor, sets collection and templates
", + "body": "" + }, + "ignore": false, + "code": "initialize: function() {\n this.collection = this.options.collection || new core.collections.Cart();\n this.collection.bindTo(this);\n var me = this;\n core.utils.getTemplate('Cart/Cart.html', function(tplMain) {\n me.template = [_.template(tplMain)];\n core.utils.getTemplate('Cart/CartItem.html', function(tplSub) {\n me.template.push(_.template(tplSub));\n core.utils.getTemplate('Cart/CartSum.html', function(tplSum) {\n me.template.push(_.template(tplSum));\n // TODO use a proper load to trigger change (and rendering)\n me.collection.trigger('change');\n });\n });\n });\n this.collection.on('quantity:increase quantity:decrease item:add', function(item, delta) {\n me.renderItem(item.toJSON());\n me._renderSum();\n });\n this.collection.on('item:remove', function(item, delta) {\n if (this.length) {\n me.unRenderItem(item.get('id'));\n me._renderSum();\n }\n });\n this.collection.on('empty', function() { me.onCartEmpty(); });\n }," + }, + { + "tags": [], + "description": { + "full": "Renders widget using the collection and the templates
", + "summary": "Renders widget using the collection and the templates
", + "body": "" + }, + "ignore": false, + "code": "render: function() {\n var me = this,\n collection = me.collection,\n template = me.template;\n // cancel view autorefresh on collection change event\n // TODO make this part optional in the parent class\n collection.off('reset change');\n var records = collection.toJSON();\n me.$el.empty().append(template[0]());\n if (collection.length) {\n this._renderSum();\n _.each(records, function(item) {\n me.renderItem(item);\n });\n } else {\n me.onCartEmpty();\n }\n return core.views.Cart.__super__.render.call(this);\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "item", + "description": "A hash (produced by CartItem.toJSON())" + }, + { + "type": "return", + "types": [ + "core.views.Cart" + ], + "description": "this" + } + ], + "description": { + "full": "Refreshes or adds a new item to the cart.
", + "summary": "Refreshes or adds a new item to the cart.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "renderItem: function(item) {\n var markup = this.template[1]({\n cartItem: item,\n currency: this.collection.currencySymbol\n });\n var current = this.$('.' + item.id);\n if (current.length) {\n current.find('select').nextAll().replaceWith(\n $(markup).find('select').nextAll()\n );\n } else {\n this.$('ul li.sum').before(markup);\n }\n return this;\n }," + }, + { + "tags": [ + { + "type": "return", + "types": [ + "core.views.Cart" + ], + "description": "this" + } + ], + "description": { + "full": "Refreshes or adds a sum row to the cart.
", + "summary": "Refreshes or adds a sum row to the cart.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "_renderSum: function() {\n var markup = this.template[2]({\n sum: this.collection.sum,\n currency: this.collection.currencySymbol\n });\n var current = this.$('ul li.sum');\n if (current.length)\n current.replaceWith(markup);\n else\n this.$('ul li:last').before(markup);\n return this;\n },\n\n unRenderItem: function(id) {\n this.$('ul li.' + id).remove();\n if (!this.collection.length) {\n this.onCartEmpty();\n }\n }," + }, + { + "tags": [], + "description": { + "full": "Runs when cart is empty.
", + "summary": "Runs when cart is empty.
", + "body": "" + }, + "ignore": false, + "code": "onCartEmpty: function() {\n this.$('ul li').not(':last').remove();\n var cartItems = this.$('ul');\n $('Cart item change handler.
Its only business is to identify the modified element
and ask the collection to update occordingly.
Everything else is done by the handlers bound to the collection.
Cart item change handler.
Its only business is to identify the modified element
and ask the collection to update occordingly.
Everything else is done by the handlers bound to the collection.
This demo code uses some fixtures to render a cart containing some
items.
This demo code uses some fixtures to render a cart containing some
items.
Shopping Cart container, for inline display.
", + "body": "" + }, + "ignore": false, + "code": "core.define('core.views.CartBox', {\n extend: 'core.views.Box',\n className: \"CartBox\",\n\n initialize: function() {\n core.views.CartBox.__super__.initialize.call(this);\n var me = this;\n this.on('render', function() {\n me.addClearAllButton();\n me.addPaymentIcons(this.options.paymentIcons);\n me.addItem(core.views.Cart, this.options.cart || {});\n });\n }," + }, + { + "tags": [ + { + "type": "returns", + "string": "jQuery" + } + ], + "description": { + "full": "Adds 'clear cart' button
", + "summary": "Adds 'clear cart' button
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "addClearAllButton: function(el) {\n var html = '';\n var $btn = $(html);\n var $title = $('.top-box', this.$el);\n $btn.on('click', _.bind(this.onClearBtnClick, this));\n return $btn.appendTo($title);\n }," + }, + { + "tags": [], + "description": { + "full": "Adds payment icons
", + "summary": "Adds payment icons
", + "body": "" + }, + "ignore": false, + "code": "addPaymentIcons: function(icons) {\n var $footer = this.$('section > div:last');\n _.each(icons, function(icon) {\n $('Handler for the 'clear cart' button
", + "summary": "Handler for the 'clear cart' button
", + "body": "" + }, + "ignore": false, + "code": "onClearBtnClick: function() {\n this.getItem().collection.empty();\n },\n\n demo: function() {\n var items = [\n {\n \"description\": \"inkl. 0,15\\u20ac Pfand\",\n \"sizes\": [{\"price\": 5, \"name\": \"L\"}],\n \"pic\": \"\",\n \"main_item\": true,\n \"sub_item\": false,\n \"id\": \"mp1\",\n \"name\": \"Fanta*1,3,5,7 0,5L \"\n }, {\n \"description\": \"inkl. 0,15\\u20ac Pfand\",\n \"sizes\": [{\"price\": 20, \"name\": \"XL\"}],\n \"pic\": \"\",\n \"main_item\": true,\n \"sub_item\": false,\n \"id\": \"mp2\",\n \"name\": \"Pain saucisse\"\n }\n ];\n var cart = new core.collections.Cart();\n for (var i=0, bound=items.length; ivar lb = new core.views.FlavorsLightbox();\nlb.show(item);\n",
+ "summary": "Lightbox which displays a list of flavors for a menu item
", + "body": "var lb = new core.views.FlavorsLightbox();\nlb.show(item);\n"
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.FlavorsLightbox', {\n\n extend: 'core.views.Lightbox',\n\n templateFlavor: \"Flavors/flavors.html\",\n\n events: {\n \"click .top-box .close-icon\": \"hide\",\n \"click .button\": \"chooseFlavors\",\n \"click input[data-flavor-id]\": 'recalculatePrice'\n },\n\n className: 'FlavorsLightbox',\n\n plugins: {\n 'section': 'jqTransform'\n },\n\n validate: function() {\n //TODO check first of all the Model Validation and also the data validation inside the model ???\n //and display the error on the DOM\n var forms = this.$el.find(\"form\");\n for(var i = 0, len = forms.length; i < len; i++) {\n console.log(forms[i]);\n }\n },"
+ },
+ {
+ "tags": [
+ {
+ "type": "constructor",
+ "string": ""
+ },
+ {
+ "type": "param",
+ "types": [
+ "Object"
+ ],
+ "name": "options",
+ "description": "Options"
+ }
+ ],
+ "description": {
+ "full": "Constructor
", + "summary": "Constructor
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function(options) {\n var me = this;\n core.utils.getTemplate(me.templateFlavor, function(tpl) {\n me.templateFlavor = tpl;\n });\n core.views.FlavorsLightbox.__super__.initialize.call(this, options);\n },\n addItem: function(type, config, place) {\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "item", + "description": "The data structure (with flavors information) for the menu item" + } + ], + "description": { + "full": "Display the flavors lightbox for a menu item
", + "summary": "Display the flavors lightbox for a menu item
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "show: function(item) {\n this.item = item;\n //TODO: has to be fixed when using backbone again\n //this.basePrice = this.item.get('sizes').at(0).get('price');\n this.basePrice = item.sizes[0].price;\n\n //add all flavors to a view-wide colleciton so they can easily be retrieved by ID\n this.flvUtils = new core.utils.flavorUtils(item);\n this.allFlavors = this.flvUtils.getFlavorsForItem(item.id);\n\n this.itemJSON = item;\n this.title = this.itemJSON.name;\n this.options.content = _.template(this.templateFlavor)(this.itemJSON);\n core.views.FlavorsLightbox.__super__.show.call(this);\n\n this.setDisplayedPrice(core.utils.formatPrice(this.basePrice));\n }," + }, + { + "tags": [], + "description": { + "full": "Validates the flavors chosen for the item. If the validation is successful, the item is added to the cart.
Otherwise, the invalid sections are highlighted.
Validates the flavors chosen for the item. If the validation is successful, the item is added to the cart.
Otherwise, the invalid sections are highlighted.
Creates a core.models.Item model for an item object. The resulting model contains only the flavors specified in flavorsArray.
", + "summary": "Creates a core.models.Item model for an item object. The resulting model contains only the flavors specified in flavorsArray.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "createCartItem: function(flavorsArray, selectedItem) {\n //TODO support arbitrary depth flavor nesting !!\n for(var i = 0, subItems = selectedItem.flavors.items; i < subItems.length; i++) {\n var subItem = subItems[i];\n for(var j = 0, subSubItems = subItem.flavors.items; j < subSubItems.length; j++) {\n var subSubItem = subSubItems[j];\n var subSubId = subSubItem.id;\n if(!_.include(flavorsArray, subSubId)) {\n subItem.flavors.items = _.difference(subItem.flavors.items, [subSubItem])\n }\n }\n }\n //all unselected flavors have been removed from the selectedItem.\n var selectedItemModel = new core.models.Item(selectedItem);\n return selectedItemModel;\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "evt", + "description": "The event object" + } + ], + "description": { + "full": "Schedule this.calculateTotalPrice() for asynchronous execution, allowing the UI to update state
", + "summary": "Schedule this.calculateTotalPrice() for asynchronous execution, allowing the UI to update state
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "recalculatePrice: function(evt) {\n var me = this;\n setTimeout(function() {\n me.calculateTotalPrice();\n }, 1);\n\n }," + }, + { + "tags": [ + { + "type": "return", + "types": [ + "Array" + ], + "description": "An array of stirng, one for each ID" + } + ], + "description": { + "full": "Returns the ID's of flavors that have been selected
", + "summary": "Returns the ID's of flavors that have been selected
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "getSelectedFlavors: function() {\n var checkedInputs = this.$el.find(\"form input:checked\");\n var flavorIds = _.map(checkedInputs, function(input) {\n return $(input).data('flavor-id') + '';\n });\n return flavorIds;\n }," + }, + { + "tags": [], + "description": { + "full": "Updates the total price displayed in the view.
", + "summary": "Updates the total price displayed in the view.
", + "body": "" + }, + "ignore": false, + "code": "calculateTotalPrice: function() {\n var selectedFlavors = this.$el.find(\"form input:checked\");\n var me = this;\n var newPrice = this.basePrice;\n\n var flvUtils = new core.utils.flavorUtils();\n\n _.each(selectedFlavors, function(elem) {\n var id = $(elem).data('flavor-id') + '';\n var selectedFlavor = this.flvUtils.getItem(id);\n if(selectedFlavor != null && selectedFlavor.sizes != null && selectedFlavor.sizes.length != null && selectedFlavor.sizes.length > 0) {\n var flavorPrice = selectedFlavor.sizes[0].price;\n newPrice += flavorPrice;\n }\n }, me);\n this.setDisplayedPrice(core.utils.formatPrice(newPrice));\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "String" + ], + "name": "price", + "description": "The price to be set" + } + ], + "description": { + "full": "Sets the displayed price to a specific value
", + "summary": "Sets the displayed price to a specific value
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "setDisplayedPrice: function(price) {\n this.$el.find(\".total_price h3.right\").text(price);\n },\n\n demo: function() {\n var demoItem = {\n \"flavors\": {\n \"items\": [{\n \"flavors\": {\n \"items\": [{\n \"description\": \"\",\n \"sizes\": [{\n \"price\": 0.60,\n \"name\": \"normal\"\n }],\n \"pic\": \"\",\n \"main_item\": false,\n \"sub_item\": true,\n \"id\": \"1131061\",\n \"name\": \"Balsamico\"\n }, {\n \"description\": \"\",\n \"sizes\": [{\n \"price\": 0.60,\n \"name\": \"normal\"\n }],\n \"pic\": \"\",\n \"main_item\": false,\n \"sub_item\": true,\n \"id\": \"1131062\",\n \"name\": \"Caesar*1\"\n }],\n \"id\": \"76666\",\n \"structure\": \"0\"\n },\n \"description\": \"\",\n \"sizes\": [],\n \"pic\": \"\",\n \"main_item\": false,\n \"sub_item\": false,\n \"id\": \"76666\",\n \"name\": \"Extra Dressing\"\n }, {\n \"flavors\": {\n \"items\": [{\n \"description\": \"\",\n \"sizes\": [{\n \"price\": 0.00,\n \"name\": \"normal\"\n }],\n \"pic\": \"\",\n \"main_item\": false,\n \"sub_item\": true,\n \"id\": \"1131059\",\n \"name\": \"Balsamico\"\n }, {\n \"description\": \"\",\n \"sizes\": [{\n \"price\": 0.00,\n \"name\": \"normal\"\n }],\n \"pic\": \"\",\n \"main_item\": false,\n \"sub_item\": true,\n \"id\": \"1131060\",\n \"name\": \"Caesar*1 \"\n }, {\n \"description\": \"\",\n \"sizes\": [{\n \"price\": 0.00,\n \"name\": \"normal\"\n }],\n \"pic\": \"\",\n \"main_item\": false,\n \"sub_item\": true,\n \"id\": \"1131057\",\n \"name\": \"ohne Dressing\"\n }],\n \"id\": \"76665\",\n \"structure\": \"1\"\n },\n \"description\": \"\",\n \"sizes\": [],\n \"pic\": \"\",\n \"main_item\": false,\n \"sub_item\": false,\n \"id\": \"76665\",\n \"name\": \"Dressing\"\n }],\n \"id\": \"1633809\",\n \"structure\": \"-1\"\n },\n \"description\": \"und Parmesan (inkl. 1 Dressing) \",\n \"sizes\": [{\n \"price\": 4.50,\n \"name\": \"normal\"\n }],\n \"pic\": \"\",\n \"main_item\": true,\n \"sub_item\": false,\n \"id\": \"1633809\",\n \"name\": \"Gemischter Salat mit H\\u00e4hnchenbrustfilet \"\n }\n\n var flb = new core.views.FlavorsLightbox();\n var $result = $('Have a Gemischter Salat!').click( function() {\n flb.show(demoItem);\n flb.on(\"flavorsChosen\", function(flavorsObj) {\n //me.cartCollection.add(flavorsObj.selectedItemModel); //just a demo!\n });\n });\n return $result;\n }\n});\n\n//TODO: Temporarily Solution as long as backbone does not work with the current data structure\ncore.utils.flavorUtils = function(jsonData) {\n this.jsonData = jsonData;\n this.getItem = function(searchId) {\n return this.getItemRecursive(this.jsonData, searchId);\n }" + }, + { + "tags": [], + "description": { + "full": "returns the searched element or null
", + "summary": "returns the searched element or null
", + "body": "" + }, + "ignore": false, + "code": "this.getItemRecursive = function(curItem, searchId) {\n if(!!curItem.items && curItem.items.length > 0) {\n for(var i = 0, ii = curItem.items.length; i < ii; ++i) {\n var returnValue = this.getItemRecursive(curItem.items[i], searchId);\n if(returnValue != null) {\n return returnValue;\n }\n }\n } else if(curItem.flavors != null && curItem.flavors.id != null && curItem.flavors.id == searchId) {\n return curItem;\n } else if(curItem.flavors != null && curItem.flavors.items != null && curItem.flavors.items.length > 0) {\n var elems = curItem.flavors.items;\n for(var i = 0, ii = elems.length; i < ii; ++i) {\n var returnValue = this.getItemRecursive(elems[i], searchId);\n if(returnValue != null) {\n return returnValue;\n }\n }\n } else if(curItem.length != null && curItem.length > 0) {\n for(var i = 0, ii = curItem.length; i < ii; ++i) {\n var returnValue = this.getItemRecursive(curItem[i], searchId);\n if(returnValue != null) {\n return returnValue;\n }\n }\n } else {\n if(curItem.id == searchId) {\n return curItem;\n } else {\n return null;\n }\n }\n };", + "ctx": { + "type": "method", + "receiver": "this", + "name": "getItemRecursive", + "string": "this.getItemRecursive()" + } + }, + { + "tags": [], + "description": { + "full": "returns an array of items
", + "summary": "returns an array of items
", + "body": "" + }, + "ignore": false, + "code": "this.getFlavorsForItem = function(id) {\n var item = this.getItem(id);\n if(item != null && item.flavors != null && item.flavors.items != null && item.flavors.items.length > 0) {\n return item.flavors.items;\n }\n return null;\n };\n};", + "ctx": { + "type": "method", + "receiver": "this", + "name": "getFlavorsForItem", + "string": "this.getFlavorsForItem()" + } + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.Form.json b/utilitybelt/apps/UB_docs/data/core.views.Form.json new file mode 100644 index 0000000..9e67e25 --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.Form.json @@ -0,0 +1,278 @@ +[ + { + "tags": [], + "description": { + "full": "Basic Form widget
", + "summary": "Basic Form widget
", + "body": "" + }, + "ignore": false, + "code": "core.define('core.views.Form', {\r\n\r\n extend: 'core.View',\r\n\r\n className: \"Form\"," + }, + { + "tags": [], + "description": { + "full": "Define events mapping
", + "summary": "Define events mapping
", + "body": "" + }, + "ignore": false, + "code": "events: {\r\n \"click input.submit\": \"submit\",\r\n \"submit form\": \"submit\",\r\n \"keypress input[type=text],textarea\": \"keypress\"\r\n }," + }, + { + "tags": [ + { + "type": "returns", + "string": "core.views.Form\r" + }, + { + "type": "constructor", + "string": "" + } + ], + "description": { + "full": "Constructor
", + "summary": "Constructor
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function() {\r\n this.validations = this.options.validations;\r\n }," + }, + { + "tags": [], + "description": { + "full": "Focus on the first field and select its content
", + "summary": "Focus on the first field and select its content
", + "body": "" + }, + "ignore": false, + "code": "selectFirstField: function() {\r\n\r\n var fields = $('input:visible', this.el);\r\n if (fields && fields[0]) {\r\n var field = $(fields[0]);\r\n if (field && field.focus && field.val) {\r\n field.focus();\r\n if (field.val()!='' && field.val()!=field.attr('placeholder'))\r\n field.select();\r\n }\r\n }\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "ArrayOfObject" + ], + "name": "errors", + "description": "Array of errors" + } + ], + "description": { + "full": "Mark fields via flashing in this form invalid in bulk.
", + "summary": "Mark fields via flashing in this form invalid in bulk.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "markInvalid: function(errors) { // TODO: rewrite completely, animation is terrible \r\n\r\n for (var i=0,ii=errors.length; iSave placeholder value before flashing
", + "body": "" + }, + "ignore": false, + "code": "if (input.val) {\r\n input.attr('save_val', input.attr('placeholder'));\r\n input.attr('placeholder', '');\r\n }\r\n \r\n //-- Saving background --\r\n input.attr('save_background', input.css('background-color')); \r\n \r\n //adding error message if defined and put in html pwojcieszuk\r\n if(input.parent().children('.error_message').size() > 0)\r\n \tinput.parent().children('.error_message').text(errors[i].message);\r\n \r\n if (input.animate) {\r\n input.animate({backgroundColor: '#fffcb7'}, 300, function(){ // todo: convert to animation function\r\n $(this).animate({backgroundColor: '#fff'}, 200, function(){\r\n $(this).animate({backgroundColor: '#fffcb7'}, 300, function(){\r\n $(this).animate({backgroundColor: '#fff'}, 200, function(){\r\n $(this).animate({backgroundColor: '#fffcb7'}, 300, function(){\r\n $(this).animate({backgroundColor: '#fff'}, 200, function(){\r\n $(this).attr('placeholder', $(this).attr('save_val'));\r\n \r\n //-- Fix to avoid wide background in some fields --\r\n \t\t\t\t\t $(this).css('background-color', $(this).attr('save_background'));\r\n });\r\n });\r\n });\r\n });\r\n });\r\n }); \r\n }\r\n }\r\n \r\n return false;\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "ArrayOfObjects" + ], + "name": "errors", + "description": "Array of errors" + } + ], + "description": { + "full": "Mark invalid via simple label color change
", + "summary": "Mark invalid via simple label color change
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "markInvalidSimple: function(errors) {\r\n var form = this.$el;\r\n this.clearInvalidSimple();\r\n for (var i=0,ii=errors.length; iClear invalid simple
", + "body": "" + }, + "ignore": false, + "code": "clearInvalidSimple: function() {\r\n var form = this.$el;\r\n $('input', form).parent('div').removeClass('input-error');\r\n }," + }, + { + "tags": [], + "description": { + "full": "Show inline loading spinner
", + "summary": "Show inline loading spinner
", + "body": "" + }, + "ignore": false, + "code": "showSpinner: function() {\r\n $('.spinner', this.el).show();\r\n }," + }, + { + "tags": [], + "description": { + "full": "Hide inline loading spinner
", + "summary": "Hide inline loading spinner
", + "body": "" + }, + "ignore": false, + "code": "hideSpinner: function() {\r\n $('.spinner', this.el).hide();\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "ArrayOfObjects" + ], + "name": "values", + "description": "Array of values" + } + ], + "description": { + "full": "Set form values
", + "summary": "Set form values
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "setValues: function(mdl) {\r\n\r\n var values = mdl.attributes || mdl;\r\n\r\n if (values) {\r\n for (var field in values) {\r\n var field_el = $('input[name=\"' + field + '\"]', this.el);\r\n if (field_el.length)\r\n field_el.val(values[field]);\r\n }\r\n }\r\n }," + }, + { + "tags": [], + "description": { + "full": "On key press handler
", + "summary": "On key press handler
", + "body": "" + }, + "ignore": false, + "code": "keypress: function(ev) {" + }, + { + "tags": [], + "description": { + "full": "f there was an error message and the input is being filled again, remove error message
", + "summary": "f there was an error message and the input is being filled again, remove error message
", + "body": "" + }, + "ignore": false, + "code": "var changedInput = $(\"input[name='\" + ev.target.name +\"']\");\r\n \tif(changedInput.parent().children('.error_message').size() > 0)\r\n \t\tchangedInput.parent().children('.error_message').text('');\r\n },", + "ctx": { + "type": "declaration", + "name": "changedInput", + "value": "$(\"input[name='\" + ev.target.name +\"']\")", + "string": "changedInput" + } + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "data", + "description": "Form data \r" + }, + { + "type": "returns", + "string": "{ArrayOfObjects} errors Array of errors" + } + ], + "description": { + "full": "Validate form data against validations defined on Model [DEPRECATED] Use Model.validate
", + "summary": "Validate form data against validations defined on Model [DEPRECATED] Use Model.validate
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "validate: function(data) {\r\n var errors = []; // basic validations, afterwards we'll use more solid library for this\r\n var validations = this.model.validations;\r\n for (var i in validations) {\r\n var validation = validations[i],\r\n field = validation.field,\r\n field_el = $('input:visible[name=\"' + field + '\"]', this.el),\r\n visible = (field_el.size() > 0),\r\n field_empty = ($.trim(data[field])+''=='' || field_el.attr('placeholder') == field_el.val());\r\n\r\n if (visible && field_empty && validation['type'] == 'required') {\r\n \terrorMessage = (validation['message_key'])? jsGetText(validation['message_key']): 'Field is required';\r\n \terrors.push({ field: field, type: 'required', message: errorMessage });\r\n }\r\n }\r\n return errors;\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "data", + "description": "Form data \r" + }, + { + "type": "param", + "types": [ + "Object" + ], + "name": "options", + "description": "Ajax call options ('url', 'type' and 'success' for success callback)" + } + ], + "description": { + "full": "Send form data via jQuery's Ajax call
Use inline spinner as a loading indicator
Send form data via jQuery's Ajax call
Use inline spinner as a loading indicator
Submit form handler
Serialize form data and validate it. If validation succeeds, send it, if failed -- use markInvalid to mark errors
Submit form handler
Serialize form data and validate it. If validation succeeds, send it, if failed -- use markInvalid to mark errors
Serialize and returns Form data as a JSON
", + "body": "" + }, + "ignore": false, + "code": "getFormValues: function(){\r\n var data = {}, data_arr = $('input:visible', this.form).serializeArray();\r\n\r\n for (var i=0,ii=data_arr.length; iValidate the form data and save the Model if validated successfully, mark errors otherwise
", + "body": "" + }, + "ignore": false, + "code": "formValidate: function() { \r\n var data = this.getFormValues();\r\n this.model.set(data, { silent: true });\r\n \r\n if (this.model.isValid()) {\r\n this.model.save( {}, { success: this.options.onSuccess } ); \r\n } else {\r\n var errors = this.model.getValidationErrors();\r\n this.markInvalidSimple(errors);\r\n }\r\n },\r\n\r\n demo: function() {\r\n return $('')\r\n } \r\n\r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.Lightbox.json b/utilitybelt/apps/UB_docs/data/core.views.Lightbox.json new file mode 100644 index 0000000..db8cdc9 --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.Lightbox.json @@ -0,0 +1,278 @@ +[ + { + "tags": [ + { + "type": "title", + "string": "Basic Lightbox\r" + }, + { + "type": "param", + "types": [ + "String" + ], + "name": "title", + "description": "Title\r" + }, + { + "type": "param", + "types": [ + "String" + ], + "name": "content", + "description": "Content\r" + }, + { + "type": "param", + "types": [ + "Number" + ], + "name": "x", + "description": "X coordinate on the screen\r" + }, + { + "type": "param", + "types": [ + "Number" + ], + "name": "y", + "description": "Y coordinate on the screen\r" + }, + { + "type": "param", + "types": [ + "String" + ], + "name": "tempate", + "description": "Path to template" + } + ], + "description": { + "full": "Basic Lightbox with the title, close icon, and content
\n\nvar lb = new core.views.Lightbox({ title: 'Some awesome title', content: 'Awesomest content' });\nlb.show();\n",
+ "summary": "Basic Lightbox with the title, close icon, and content
\n\nvar lb = new core.views.Lightbox({ title: 'Some awesome title', content: 'Awesomest content' });\nlb.show();\n",
+ "body": ""
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.Lightbox', {\r\n\r\n extend: 'core.View',\r\n\r\n className: \"Lightbox\",\r\n\r\n template: 'Lightbox/base.html',\r\n\r\n events: {\r\n \"click .top-box .close-icon\": \"hide\"\r\n },"
+ },
+ {
+ "tags": [],
+ "description": {
+ "full": "Init blanket layer which cover the page to prevent interaction when Lightbox is modal.
Click on blanket close the Lightbox.
Init blanket layer which cover the page to prevent interaction when Lightbox is modal.
Click on blanket close the Lightbox.
Hide Lightbox, destroy its DOM structure, hide blanket
", + "summary": "Hide Lightbox, destroy its DOM structure, hide blanket
", + "body": "" + }, + "ignore": false, + "code": "hide: function() {\r\n this.$el.trigger('hide');\r\n this.remove(); // remove from DOM, to prevent flooding\r\n if (this.isModal() && this.blanket) {\r\n this.blanket.hide();\r\n }\r\n }," + }, + { + "tags": [], + "description": { + "full": "Init Lightbox position and layout properties
", + "summary": "Init Lightbox position and layout properties
", + "body": "" + }, + "ignore": false, + "code": "initPosition: function() {\r\n this.$el.css({ position:' fixed', 'margin': '0px' });\r\n\r\n this.body = this.getBody();\r\n\r\n if (this.options.height) {\r\n this.body.height(this.options.height);\r\n this.body.css({ 'overflow-x': 'hidden', 'overflow-y': 'auto' });\r\n }\r\n \r\n if (this.options.x && this.options.y) {\r\n this.$el.css({ top: this.options.x + 'px', left: this.options.y + 'px' })\r\n }\r\n else {\r\n this.center();\r\n }\r\n\r\n }," + }, + { + "tags": [ + { + "type": "constructor", + "string": "" + } + ], + "description": { + "full": "Initialize the widget
", + "summary": "Initialize the widget
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function() {\r\n\r\n var template = this.options.template || this.template;\r\n\r\n var me = this;\r\n core.utils.getTemplate(template, function(tpl) {\r\n me.render(tpl);\r\n });\r\n\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "String" + ], + "name": "tpl", + "description": "Widget template" + } + ], + "description": { + "full": "Render Lightbox
", + "summary": "Render Lightbox
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "render: function(tpl) {\r\n\r\n this.el = $(tpl);\r\n this.$el = this.el.appendTo($('body')).hide();\r\n this.delegateEvents();" + }, + { + "tags": [], + "description": { + "full": "Assign user-defined events TODO: put in our core View wrapper
", + "summary": "Assign user-defined events TODO: put in our core View wrapper
", + "body": "" + }, + "ignore": false, + "code": "if (this.options.events) {\r\n this.delegateEvents(_.extend(this.events, this.options.events));\r\n }\r\n\r\n this.initPosition();\r\n\r\n var title = this.title || this.options.title || this.$el.attr('header');\r\n if (title" + }, + { + "tags": [], + "description": { + "full": "& $('.title-container', this.$el).length < 1
", + "summary": "& $('.title-container', this.$el).length < 1
", + "body": "" + }, + "ignore": false, + "code": "{\r\n this.setTitle(title);\r\n }\r\n\r\n var content = this.options.content;\r\n if (content) {\r\n this.setContent(content);\r\n }\r\n\r\n core.views.Lightbox.__super__.render.call(this);\r\n\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "String" + ], + "name": "title", + "description": "Lightbox Title" + } + ], + "description": { + "full": "Set title for the Lightbox
", + "summary": "Set title for the Lightbox
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "setTitle: function(title) {\r\n $('.title-container', this.$el).html(title);\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "String" + ], + "name": "content", + "description": "Lightbox Content" + } + ], + "description": { + "full": "Set content for the Lightbox
", + "summary": "Set content for the Lightbox
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "setContent: function(content) {\r\n this.getBody().html(content);\r\n }," + }, + { + "tags": [ + { + "type": "returns", + "string": "Boolean" + } + ], + "description": { + "full": "Check if Lightbox is modal
", + "summary": "Check if Lightbox is modal
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "isModal: function() {\r\n return this.options.modal == undefined || this.options.modal === true;\r\n }," + }, + { + "tags": [ + { + "type": "method", + "string": "showError" + } + ], + "description": { + "full": "Show inline error via .message element
", + "summary": "Show inline error via .message element
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "showError: function(text) {\r\n $('.message', this.$el).html(text);\r\n }," + }, + { + "tags": [], + "description": { + "full": "Clear error from the .message element
", + "summary": "Clear error from the .message element
", + "body": "" + }, + "ignore": false, + "code": "clearError: function() {\r\n $('.message', this.$el).html('');\r\n }," + }, + { + "tags": [], + "description": { + "full": "Show Lightbox
", + "summary": "Show Lightbox
", + "body": "" + }, + "ignore": false, + "code": "show: function() {\r\n var me = this;\r\n me.on('render', function() {\r\n me.clearError();\r\n me.$el.show();\r\n if (me.isModal()) {\r\n me.initBlanket();\r\n me.blanket.show();\r\n }\r\n });\r\n }," + }, + { + "tags": [], + "description": { + "full": "Center Lightbox
", + "summary": "Center Lightbox
", + "body": "" + }, + "ignore": false, + "code": "center: function () {\r\n this.$el.css(\"position\", \"fixed\");\r\n var visualFix = parseInt($(window).height()/15);\r\n this.$el.css(\"top\", '130px');\r\n this.$el.css(\"left\", (($(window).width() - this.$el.outerWidth()) / 2) + $(window).scrollLeft() + \"px\");\r\n return this;\r\n }," + }, + { + "tags": [ + { + "type": "returns", + "string": "jQuery" + } + ], + "description": { + "full": "Returns body element
", + "summary": "Returns body element
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "getBody: function() {\r\n return $('.body-box', this.$el);\r\n }," + }, + { + "tags": [ + { + "type": "returns", + "string": "jQuery" + } + ], + "description": { + "full": "Adds link to title container and return its element
", + "summary": "Adds link to title container and return its element
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "addTitleLink: function(html) {\r\n var $title_link = $('.top-box .title-link', this.$el);\r\n return $title_link.append(html);\r\n },\r\n\r\n demo: function() {\r\n var $result = $('Click Me')\r\n .click( function() {\r\n var lb = new core.views.Lightbox({ title: 'Some awesome title', content: 'Awesomest content' });\r\n lb.show();\r\n });\r\n return $result;\r\n }\r\n\r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.LoginForm.json b/utilitybelt/apps/UB_docs/data/core.views.LoginForm.json new file mode 100644 index 0000000..217f081 --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.LoginForm.json @@ -0,0 +1,122 @@ +[ + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "model", + "description": "An instance of a user model" + } + ], + "description": { + "full": "Form for User login
\n\nvar form = new core.views.LoginForm({ model: theUser });\nform.renderTo($('#my_container'));\n",
+ "summary": "Form for User login
", + "body": "var form = new core.views.LoginForm({ model: theUser });\nform.renderTo($('#my_container'));\n"
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.LoginForm', {\n extend: 'core.views.Form',\n className: 'LoginForm',\n template: '',\n \n events: {\n 'submit form': 'authorize',\n 'click .submit': 'authorize'\n },"
+ },
+ {
+ "tags": [
+ {
+ "type": "param",
+ "types": [
+ "Object"
+ ],
+ "name": "options",
+ "description": "A hash containing the view options"
+ }
+ ],
+ "description": {
+ "full": "Constructor.
Instantiates an empty User model if none provided.
Renders the form with the provided template (defaults to Login/LoginForm.html).
Sets up authorize callbacks.
Constructor.
Instantiates an empty User model if none provided.
Renders the form with the provided template (defaults to Login/LoginForm.html).
Sets up authorize callbacks.
Renders the widget using the given template.
", + "summary": "Renders the widget using the given template.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "render: function(tpl) {\n this.template = _.template(tpl);\n this.$el.append(this.template);\n this.form = this.$el.find('form');\n this.clearInvalidSimple();\n core.views.UserAddressForm.__super__.render.call(this);\n }," + }, + { + "tags": [], + "description": { + "full": "Validates login inputs and forward authorization query to the User model.
", + "summary": "Validates login inputs and forward authorization query to the User model.
", + "body": "" + }, + "ignore": false, + "code": "authorize: function() {\n var data = this.getFormValues();\n this.model.set(data, { silent: true });\n if (!this.model.isValid()) {\n var errors = this.model.getValidationErrors();\n this.markInvalid(errors);\n } else {\n this.model.authorize(data.pwd);\n }\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "core.models.User" + ], + "name": "user", + "description": "The freshly authorized user" + } + ], + "description": { + "full": "Authorization success handler.
", + "summary": "Authorization success handler.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "authorizeSuccess: function(user) {\n var bits = ['Hi,', user.get('name'), user.get('last_name'), '!'];\n this.$el.text(bits.join(' '));\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "core.models.User" + ], + "name": "user", + "description": "The unauthorized user" + } + ], + "description": { + "full": "Authorization error handler.
", + "summary": "Authorization error handler.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "authorizeError: function(user) {\n this.markInvalidSimple([{field: 'email'}, {field: 'pwd'}])\n }," + }, + { + "tags": [], + "description": { + "full": "Demo code
", + "summary": "Demo code
", + "body": "" + }, + "ignore": false, + "code": "demo: function() {\n var form = new core.views.LoginForm();\n return form;\n }\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.LoginLightbox.json b/utilitybelt/apps/UB_docs/data/core.views.LoginLightbox.json new file mode 100644 index 0000000..a87feae --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.LoginLightbox.json @@ -0,0 +1,56 @@ +[ + { + "tags": [ + { + "type": "extends", + "string": "core.views.Lightbox" + } + ], + "description": { + "full": "Lightbox with the Login Form inside
\n\nvar lb = new core.views.LoginLightbox({ title: jsGetText('login') });\nlb.show();\n",
+ "summary": "Lightbox with the Login Form inside
", + "body": "var lb = new core.views.LoginLightbox({ title: jsGetText('login') });\nlb.show();\n"
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.LoginLightbox', {\n\n extend: 'core.views.Lightbox',"
+ },
+ {
+ "tags": [
+ {
+ "type": "method",
+ "string": "initialize"
+ },
+ {
+ "type": "constructor",
+ "string": ""
+ },
+ {
+ "type": "param",
+ "types": [
+ "Object"
+ ],
+ "name": "options",
+ "description": "Options passed to the login form view"
+ }
+ ],
+ "description": {
+ "full": "Constructor.
", + "summary": "Constructor.
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function(options) {\n this.on('render', function() {\n var lb = this;\n this.addItem(core.views.LoginForm, this.options);\n });\n core.views.LoginLightbox.__super__.initialize.call(this);\n }," + }, + { + "tags": [], + "description": { + "full": "Demo code.
", + "summary": "Demo code.
", + "body": "" + }, + "ignore": false, + "code": "demo: function() {\n var $result = $('Click Me')\n .click(function() {\n var lb = new core.views.LoginLightbox({ title: jsGetText('login_title') });\n lb.show();\n });\n return $result;\n }\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.MultipleAddressLightbox.json b/utilitybelt/apps/UB_docs/data/core.views.MultipleAddressLightbox.json new file mode 100644 index 0000000..97973ce --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.MultipleAddressLightbox.json @@ -0,0 +1,112 @@ +[ + { + "tags": [ + { + "type": "extends", + "string": "core.views.Lightbox" + } + ], + "description": { + "full": "Lightbox with the User Addresses List inside
\n\nvar lb = new core.views.MultipleAddressLightbox();\nlb.show();\n",
+ "summary": "Lightbox with the User Addresses List inside
\n\nvar lb = new core.views.MultipleAddressLightbox();\nlb.show();\n",
+ "body": ""
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.MultipleAddressLightbox', {\r\n\r\n extend: 'core.views.Lightbox',\r\n\r\n template: [\"MultipleAddress/MultipleAddress.html\"],\r\n\r\n events: {\r\n \"click .top-box .close-icon\": \"hide\"\r\n // ,\"click li\": \"addressSelectHandler\"\r\n },\r\n\r\n __shown: false,\r\n\r\n className: 'MultipleAddressLightbox',"
+ },
+ {
+ "tags": [
+ {
+ "type": "constructor\r",
+ "string": ""
+ },
+ {
+ "type": "param",
+ "types": [
+ "Object"
+ ],
+ "name": "options",
+ "description": "Options"
+ }
+ ],
+ "description": {
+ "full": "Constructor
", + "summary": "Constructor
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function(options) {\r\n this.locations = this.options.locations;\r\n var me = this;\r\n this.title = jsGetText(\"multiple_addresses\");\r\n\r\n core.utils.getTemplate(me.template, function(tpl) {\r\n me.template = _.template(tpl)();\r\n });\r\n\r\n this.on('render', function() {\r\n //adding the map and the list\r\n me.initPosition();\r\n me.map = me.addItem(core.views.Map, me.locations, \".maps\");\r\n me.map.on(\"markerClick\", function(elem) {\r\n me.addressMapSelectHandler.call(me, elem)\r\n });\r\n var listOptions = {\r\n addresses: me.locations,\r\n getBackgroundCSS: me.getBackgroundCSS\r\n };\r\n me.map.render();\r\n me.list = me.addItem(core.views.MultipleAddressList, me.options, \".streets\");\r\n me.list.on(\"locationSelected\", function(elem) {\r\n me.addressSelectHandler.call(me, elem);\r\n });\r\n me.list.render();\r\n });\r\n },\r\n addItem: function(type, config, place) {\r\n if(place != null) {\r\n var positionElement = $('.body-box', this.$el).find(place);\r\n var new_el = new type(config);\r\n $(positionElement).html(new_el.$el);\r\n return new_el;\r\n } else if(this.getBody) {\r\n core.views.MultipleAddressLightbox.__super__.addItem.call(this, type, config);\r\n }\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "list", + "description": "" + } + ], + "description": { + "full": "setAddressList
", + "summary": "setAddressList
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "setAddressList: function(list) {\r\n this.addressList = list;\r\n }," + }, + { + "tags": [], + "description": { + "full": "", + "summary": "", + "body": "" + }, + "ignore": false, + "code": "getAddressList: function() {\r\n return this.addressList;\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "elem", + "description": "" + } + ], + "description": { + "full": "addressSelectHandler
", + "summary": "addressSelectHandler
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "addressSelectHandler: function(elem) {\r\n //TODO do something here\r\n this.trigger(\"locationSelected\", elem);\r\n }," + }, + { + "tags": [ + { + "type": "param", + "types": [ + "Object" + ], + "name": "elem", + "description": "" + } + ], + "description": { + "full": "addressMapSelectHandler
", + "summary": "addressMapSelectHandler
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "addressMapSelectHandler: function(elem) {\r\n //TODO do something here\r\n this.trigger(\"locationSelected\", elem);\r\n },\r\n hide: function() {\r\n //TODO as soon as we have a container object which keeps children we can add them here\r\n this.map.hide();\r\n this.list.remove();\r\n this.$el.remove();\r\n this.__shown = false;\r\n },\r\n demo: function() {\r\n\r\n var locations = {\r\n \"pagination\": {\r\n \"total_items\": 2,\r\n \"limit\": 10,\r\n \"total_pages\": 1,\r\n \"page\": 1,\r\n \"offset\": 0\r\n },\r\n \"data\": [{\r\n \"uri_search\": \"http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=45.23234&long=37.77234\",\r\n \"address\": {\r\n \"city_slug\": \"berlin\",\r\n \"city\": \"Berlin\",\r\n \"street_number\": \"60\",\r\n \"latitude\": 45.232340000000001,\r\n \"country\": \"DE\",\r\n \"street_name\": \"Mohrenstrasse\",\r\n \"zipcode\": \"10117\",\r\n \"longitude\": 37.77234\r\n }\r\n }, {\r\n \"uri_search\": \"http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=46.2004&long=37.88774\",\r\n \"address\": {\r\n \"city_slug\": \"berlin\",\r\n \"city\": \"Berlin\",\r\n \"street_number\": \"59\",\r\n \"latitude\": 46.40000000000002,\r\n \"country\": \"DE\",\r\n \"street_name\": \"Mohrenstrasse\",\r\n \"zipcode\": \"10117\",\r\n \"longitude\": 37.887740000000001\r\n }\r\n }, {\r\n \"uri_search\": \"http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=46.2004&long=37.88774\",\r\n \"address\": {\r\n \"city_slug\": \"berlin\",\r\n \"city\": \"Berlin\",\r\n \"street_number\": \"59\",\r\n \"latitude\": 46.200400000000002,\r\n \"country\": \"DE\",\r\n \"street_name\": \"Mohrenstrasse\",\r\n \"zipcode\": \"10117\",\r\n \"longitude\": 37.987740000000001\r\n }\r\n }, {\r\n \"uri_search\": \"http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=46.2004&long=37.88774\",\r\n \"address\": {\r\n \"city_slug\": \"berlin\",\r\n \"city\": \"Berlin\",\r\n \"street_number\": \"59\",\r\n \"latitude\": 46.400400000000002,\r\n \"country\": \"DE\",\r\n \"street_name\": \"Mohrenstrasse\",\r\n \"zipcode\": \"10117\",\r\n \"longitude\": 37.987740000000001\r\n }\r\n }]\r\n };\r\n\r\n var $result = $('Click Me')\r\n .click( function() {\r\n var lb = new core.views.MultipleAddressLightbox({\r\n locations: locations.data\r\n });\r\n lb.show();\r\n });\r\n return $result;\r\n }\r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.ReadOnlyCartBox.json b/utilitybelt/apps/UB_docs/data/core.views.ReadOnlyCartBox.json new file mode 100644 index 0000000..94f2c5a --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.ReadOnlyCartBox.json @@ -0,0 +1,12 @@ +[ + { + "tags": [], + "description": { + "full": "Shopping Cart container (read only mode), for inline display.
", + "summary": "Shopping Cart container (read only mode), for inline display.
", + "body": "" + }, + "ignore": false, + "code": "core.define('core.views.ReadOnlyCartBox', {\n extend: 'core.views.CartBox',\n\n demo: function() {\n var items = [\n {\n \"description\": \"inkl. 0,15\\u20ac Pfand\",\n \"sizes\": [{\"price\": 5, \"name\": \"L\"}],\n \"pic\": \"\",\n \"main_item\": true,\n \"sub_item\": false,\n \"id\": \"mp1\",\n \"name\": \"Fanta*1,3,5,7 0,5L \"\n }, {\n \"description\": \"inkl. 0,15\\u20ac Pfand\",\n \"sizes\": [{\"price\": 20, \"name\": \"XL\"}],\n \"pic\": \"\",\n \"main_item\": true,\n \"sub_item\": false,\n \"id\": \"mp2\",\n \"name\": \"Pain saucisse\"\n }\n ];\n var cart = new core.collections.Cart();\n for (var i=0, bound=items.length; ivar form = new core.views.UserAddressForm({ id: 'a2', user_id: 'a1' });\nform.renderTo($('my_container'));\n",
+ "summary": "Form for editing User Address
\n\nvar form = new core.views.UserAddressForm({ id: 'a2', user_id: 'a1' });\nform.renderTo($('my_container'));\n",
+ "body": ""
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.UserAddressForm', {\r\n extend: 'core.views.Form',\r\n className: 'UserAddressForm',\r\n template: '',\r\n user_id: null,\r\n model: null,\r\n \r\n events: {\r\n \"submit form\": \"formValidate\",\r\n \"click .submit\": \"formValidate\",\r\n \"click a.back\": \"onBackLinkClick\"\r\n },"
+ },
+ {
+ "tags": [],
+ "description": {
+ "full": "Constructor
", + "summary": "Constructor
", + "body": "" + }, + "ignore": false, + "code": "initialize: function(){\r\n\r\n var me = this;\r\n this.user_id = this.options.user_id;\r\n this.id = this.options.id;\r\n\r\n this.record = this.options.record;\r\n\r\n this.model = new core.models.Address({ user_id: this.user_id, id: this.id });\r\n\r\n core.utils.getTemplate('UserAddress/UserAddressForm.html', function(tpl) {\r\n me.render(tpl);\r\n });\r\n \r\n }," + }, + { + "tags": [], + "description": { + "full": "Render the widget using the template
", + "summary": "Render the widget using the template
", + "body": "" + }, + "ignore": false, + "code": "render: function(tpl){\r\n var me = this;\r\n me.template = _.template(tpl);\r\n me.$el.append(me.template);\r\n me.form = me.$el.find('form');\r\n me.clearInvalidSimple();\r\n me.loadAddressData();\r\n core.views.UserAddressForm.__super__.render.call(this);\r\n }," + }, + { + "tags": [], + "description": { + "full": "Populate with the address data
", + "summary": "Populate with the address data
", + "body": "" + }, + "ignore": false, + "code": "loadAddressData: function(){\r\n var me = this;\r\n if (this.record) {\r\n me.model = this.record;\r\n me.setValues(this.record);\r\n }\r\n else if (this.options.id) {\r\n this.model.fetch({ success: function(mdl) {\r\n me.setValues(mdl)\r\n } });\r\n }\r\n }," + }, + { + "tags": [], + "description": { + "full": "Runs when user clicks on a \"Back\" link
", + "summary": "Runs when user clicks on a \"Back\" link
", + "body": "" + }, + "ignore": false, + "code": "onBackLinkClick: function() {\r\n if (this.options && this.options.onBackLinkClick)\r\n this.options.onBackLinkClick();\r\n }," + }, + { + "tags": [], + "description": { + "full": "Demo code
", + "summary": "Demo code
", + "body": "" + }, + "ignore": false, + "code": "demo: function() {\r\n var form = new core.views.UserAddressForm({ id: 1 });\r\n return form;\r\n }\r\n\r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.UserAddressLightbox.json b/utilitybelt/apps/UB_docs/data/core.views.UserAddressLightbox.json new file mode 100644 index 0000000..fbfee0d --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.UserAddressLightbox.json @@ -0,0 +1,46 @@ +[ + { + "tags": [ + { + "type": "extends", + "string": "core.views.Lightbox" + } + ], + "description": { + "full": "Lightbox with the User Address Form inside
\n\nvar lb = new core.views.UserAddressLightbox({ id: 1, title: jsGetText('save_address') }); // fetch the record from the back-end\nlb.show();\n\nvar lb2 = new core.views.UserAddressLightbox({ record: { ... } }); // use the predefined record\n\nvar lb3 = new core.views.UserAddressLightbox({ title: jsGetText('new_address') }); // open empty form\nlb3.on('render', function(lightbox) { // populate with data\n lightbox.getForm().populate( { ... } ) \n});\n",
+ "summary": "Lightbox with the User Address Form inside
\n\nvar lb = new core.views.UserAddressLightbox({ id: 1, title: jsGetText('save_address') }); // fetch the record from the back-end\nlb.show();\n\nvar lb2 = new core.views.UserAddressLightbox({ record: { ... } }); // use the predefined record\n\nvar lb3 = new core.views.UserAddressLightbox({ title: jsGetText('new_address') }); // open empty form\nlb3.on('render', function(lightbox) { // populate with data\n lightbox.getForm().populate( { ... } ) \n});\n",
+ "body": ""
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.UserAddressLightbox', {\r\n\r\n extend: 'core.views.Lightbox',"
+ },
+ {
+ "tags": [
+ {
+ "type": "method",
+ "string": "initialize\r"
+ },
+ {
+ "type": "constructor\r",
+ "string": ""
+ },
+ {
+ "type": "param",
+ "types": [
+ "Object"
+ ],
+ "name": "options",
+ "description": "Options"
+ }
+ ],
+ "description": {
+ "full": "Initialize
", + "summary": "Initialize
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function(options){\r\n \r\n this.on('render', function() { \r\n var lb = this;\r\n this.options.onSuccess = function() { \r\n lb.hide(); \r\n \tnew core.views.UserAddressListLightbox().show();\r\n };\r\n this.options.onBackLinkClick = function() { \r\n lb.hide(); \r\n \tnew core.views.UserAddressListLightbox().show();\r\n };\r\n this.addItem(core.views.UserAddressForm, this.options);\r\n });\r\n\r\n core.views.UserAddressLightbox.__super__.initialize.call(this);\r\n\r\n },\r\n\r\n demo: function() {\r\n var $result = $('Click Me')\r\n .click( function() {\r\n var lb = new core.views.UserAddressLightbox({ id: 1, title: jsGetText('save_address') });\r\n lb.show();\r\n });\r\n return $result;\r\n }\r\n\r\n \r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.UserAddressList.json b/utilitybelt/apps/UB_docs/data/core.views.UserAddressList.json new file mode 100644 index 0000000..a5fd1c5 --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.UserAddressList.json @@ -0,0 +1,106 @@ +[ + { + "tags": [ + { + "type": "param", + "types": [ + "Collection" + ], + "name": "collection", + "description": "Collection of core.models.Address \r" + }, + { + "type": "param", + "types": [ + "Function" + ], + "name": "openEditWidget", + "description": "Handler to open the widget for model editing" + } + ], + "description": { + "full": "View with the list of User Addresses
\n\nvar list = new core.views.UserAddressList();\nlist.renderTo($('#some_element'));\n",
+ "summary": "View with the list of User Addresses
\n\nvar list = new core.views.UserAddressList();\nlist.renderTo($('#some_element'));\n",
+ "body": ""
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.UserAddressList', {\r\n\r\n extend: 'core.View',\r\n className: 'UserAddressList',\r\n template: '',\r\n// user_id: null,\r\n \r\n events: {\r\n \"click .edit-icon\": \"editAddress\",\r\n \"click .delete-icon\": \"deleteAddressConfirm\"\r\n },"
+ },
+ {
+ "tags": [],
+ "description": {
+ "full": "Constructor, set collection and template
", + "summary": "Constructor, set collection and template
", + "body": "" + }, + "ignore": false, + "code": "initialize: function(){\r\n this.collection = this.options.collection || new core.collections.Address();\r\n this.collection.bindTo(this);" + }, + { + "tags": [], + "description": { + "full": "this.defaults = this.options.defaults || this.collection.defaults;
\n\n this.user_id = this.options.user_id;\n this.collection.user_id = this.user_id;\n",
+ "summary": "this.defaults = this.options.defaults || this.collection.defaults;
\n\n this.user_id = this.options.user_id;\n this.collection.user_id = this.user_id;\n",
+ "body": ""
+ },
+ "ignore": false,
+ "code": "var me = this;\r\n core.utils.getTemplate(['UserAddress/UserAddresses.html'], function(tpl) {\r\n me.template = tpl;\r\n me.collection.fetch(); // should change url first...\r\n }); \r\n \r\n },",
+ "ctx": {
+ "type": "declaration",
+ "name": "me",
+ "value": "this",
+ "string": "me"
+ }
+ },
+ {
+ "tags": [],
+ "description": {
+ "full": "Render widget using the collection and the template
", + "summary": "Render widget using the collection and the template
", + "body": "" + }, + "ignore": false, + "code": "render: function() {\r\n\r\n var collection = this.collection;\r\n\r\n if (collection.length == 0) {\r\n this.onUserListEmpty();\r\n }\r\n else {\r\n\r\n var col = collection.getRecords();\r\n\r\n var tpl = _.template(this.template);\r\n var data = { addresses: col };\r\n data.get_full_address = function(address) { // TODO: create set of global renderers and process them in generic way\r\n return address.city + ' ' + address.street_name + ' ' + address.street_number;\r\n }\r\n\r\n this.$el.empty().append(tpl(data));\r\n\r\n }\r\n\r\n core.views.UserAddressList.__super__.render.call(this);\r\n\r\n }," + }, + { + "tags": [], + "description": { + "full": "Run when addresses collection is empty
", + "summary": "Run when addresses collection is empty
", + "body": "" + }, + "ignore": false, + "code": "onUserListEmpty: function() {\r\n this.$el.empty().append(jsGetText(\"no_addresses\"));\r\n }," + }, + { + "tags": [], + "description": { + "full": "Run when click on \"edit user\" icon
", + "summary": "Run when click on \"edit user\" icon
", + "body": "" + }, + "ignore": false, + "code": "editAddress: function(e) { \r\n var id = e.target.id;\r\n var rec = this.collection.get(id);\r\n if (rec && rec.id) {\r\n this.options.openEditWidget({ record: rec, title: jsGetText('edit_address') });\r\n }\r\n }," + }, + { + "tags": [], + "description": { + "full": "Remove the address from collection and re-render the widget
", + "summary": "Remove the address from collection and re-render the widget
", + "body": "" + }, + "ignore": false, + "code": "deleteAddress: function(id) {\r\n var rec = this.collection.get(id);\r\n var me = this;\r\n rec.destroy({ success: function() {\r\n me.collection.remove();\r\n me.render();\r\n } });\r\n }," + }, + { + "tags": [], + "description": { + "full": "Run when click on \"delete user\" icon, show small inline \"confirmation\" dialog
", + "summary": "Run when click on \"delete user\" icon, show small inline \"confirmation\" dialog
", + "body": "" + }, + "ignore": false, + "code": "deleteAddressConfirm: function(e){\r\n var id = e.target.id, me = this;\r\n core.utils.getTemplate(['UserAddress/DeleteConfirm.html'], function(tpl) {\r\n var html = _.template(tpl);\r\n var ct = $(e.target).parents('li');\r\n var confirm_message = ct.hide().after(html).next();\r\n confirm_message.height(ct.height());\r\n $('.yes', confirm_message).click( function() { \r\n ct.show();\r\n confirm_message.hide();\r\n me.deleteAddress(id); \r\n } );\r\n $('.no', confirm_message).click( function() { \r\n ct.show();\r\n confirm_message.hide() \r\n } );\r\n }); \r\n },\r\n\r\n demo: function() {\r\n var list = new core.views.UserAddressList();\r\n return list; \r\n }\r\n\r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/data/core.views.UserAddressListLightbox.json b/utilitybelt/apps/UB_docs/data/core.views.UserAddressListLightbox.json new file mode 100644 index 0000000..c1faf01 --- /dev/null +++ b/utilitybelt/apps/UB_docs/data/core.views.UserAddressListLightbox.json @@ -0,0 +1,46 @@ +[ + { + "tags": [ + { + "type": "extends", + "string": "core.views.Lightbox" + } + ], + "description": { + "full": "Lightbox with the User Addresses List inside
\n\nvar lb = new core.views.UserAddressListLightbox();\nlb.show();\n",
+ "summary": "Lightbox with the User Addresses List inside
\n\nvar lb = new core.views.UserAddressListLightbox();\nlb.show();\n",
+ "body": ""
+ },
+ "isPrivate": false,
+ "ignore": false,
+ "code": "core.define('core.views.UserAddressListLightbox', {\r\n\r\n extend: 'core.views.Lightbox',\r\n\r\n className: 'UserAddressListLightbox',"
+ },
+ {
+ "tags": [
+ {
+ "type": "method",
+ "string": "initialize\r"
+ },
+ {
+ "type": "constructor\r",
+ "string": ""
+ },
+ {
+ "type": "param",
+ "types": [
+ "Object"
+ ],
+ "name": "options",
+ "description": "Options"
+ }
+ ],
+ "description": {
+ "full": "Initialize
", + "summary": "Initialize
", + "body": "" + }, + "isPrivate": false, + "ignore": false, + "code": "initialize: function(options){\r\n\r\n this.title = jsGetText('address_list');\r\n \r\n this.on('render', function() { \r\n var lb = this;\r\n lb.addTitleLink(jsGetText('new_address')).addClass('new-address').click(function() {\r\n var form = new core.views.UserAddressLightbox({ title: jsGetText('new_address') });\r\n form.show();\r\n lb.hide();\r\n });\r\n this.options.openEditWidget = function(options) {\r\n var form = new core.views.UserAddressLightbox(options);\r\n form.show();\r\n lb.hide();\r\n };\r\n\r\n var list = this.addItem(core.views.UserAddressList, this.options);\r\n this.setAddressList(list);\r\n\r\n });\r\n\r\n core.views.UserAddressListLightbox.__super__.initialize.call(this);\r\n\r\n },\r\n\r\n setAddressList: function(list) {\r\n this.addressList = list;\r\n },\r\n\r\n getAddressList: function() {\r\n return this.addressList;\r\n },\r\n\r\n demo: function() {\r\n var $result = $('Click Me')\r\n .click( function() {\r\n var lb = new core.views.UserAddressListLightbox({ user_id: 1 });\r\n lb.show();\r\n });\r\n return $result;\r\n }\r\n\r\n});" + } +] \ No newline at end of file diff --git a/utilitybelt/apps/UB_docs/images/common/arrow_filter.png b/utilitybelt/apps/UB_docs/images/common/arrow_filter.png new file mode 100644 index 0000000..998e6b9 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/arrow_filter.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/arrows_menu.png b/utilitybelt/apps/UB_docs/images/common/arrows_menu.png new file mode 100644 index 0000000..29fe949 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/arrows_menu.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/back_other_pages.jpg b/utilitybelt/apps/UB_docs/images/common/back_other_pages.jpg new file mode 100644 index 0000000..be7170d Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/back_other_pages.jpg differ diff --git a/utilitybelt/apps/UB_docs/images/common/back_pizza.jpg b/utilitybelt/apps/UB_docs/images/common/back_pizza.jpg new file mode 100644 index 0000000..2031538 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/back_pizza.jpg differ diff --git a/utilitybelt/apps/UB_docs/images/common/bar_brown.jpg b/utilitybelt/apps/UB_docs/images/common/bar_brown.jpg new file mode 100644 index 0000000..fed3033 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bar_brown.jpg differ diff --git a/utilitybelt/apps/UB_docs/images/common/baseline-20.png b/utilitybelt/apps/UB_docs/images/common/baseline-20.png new file mode 100644 index 0000000..726e2d6 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/baseline-20.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/big_logo.png b/utilitybelt/apps/UB_docs/images/common/big_logo.png new file mode 100644 index 0000000..b52b8a4 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/big_logo.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-bl.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-bl.png new file mode 100644 index 0000000..47c61f1 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-bl.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-br.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-br.png new file mode 100644 index 0000000..7111e7c Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-br.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-tl.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-tl.png new file mode 100644 index 0000000..27e1b88 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-tl.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-tr.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-tr.png new file mode 100644 index 0000000..20c5df3 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/STYLE-tr.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/big_logo.jpg b/utilitybelt/apps/UB_docs/images/common/bloomsburys/big_logo.jpg new file mode 100644 index 0000000..5575cad Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/big_logo.jpg differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_green_center.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_green_center.png new file mode 100644 index 0000000..d3c26f3 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_green_center.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_green_left_right.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_green_left_right.png new file mode 100644 index 0000000..a2e5567 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_green_left_right.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_vorbestellen_2.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_vorbestellen_2.png new file mode 100644 index 0000000..3ddcf0a Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_vorbestellen_2.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_zummenue.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_zummenue.png new file mode 100644 index 0000000..daa60ef Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/button_zummenue.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/cart_delete.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/cart_delete.png new file mode 100644 index 0000000..c96b6ec Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/cart_delete.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/cucine.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/cucine.png new file mode 100644 index 0000000..ba278e2 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/cucine.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/hat.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/hat.png new file mode 100644 index 0000000..7704cc1 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/hat.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo.gif b/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo.gif new file mode 100644 index 0000000..fd8dea1 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo.gif differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo_blooms.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo_blooms.png new file mode 100644 index 0000000..4b0618b Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo_blooms.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo_widget.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo_widget.png new file mode 100644 index 0000000..2429b4a Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/logo_widget.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/menu_arrow_2.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/menu_arrow_2.png new file mode 100644 index 0000000..b1599de Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/menu_arrow_2.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/pattern.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/pattern.png new file mode 100644 index 0000000..6e61827 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/pattern.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/tab_active.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/tab_active.png new file mode 100644 index 0000000..7cdeab2 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/tab_active.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/bloomsburys/top_tooltip_description.png b/utilitybelt/apps/UB_docs/images/common/bloomsburys/top_tooltip_description.png new file mode 100644 index 0000000..70f9fe6 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/bloomsburys/top_tooltip_description.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/brown_pattern.png b/utilitybelt/apps/UB_docs/images/common/brown_pattern.png new file mode 100644 index 0000000..5fe3be2 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/brown_pattern.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/coup_yes.png b/utilitybelt/apps/UB_docs/images/common/coup_yes.png new file mode 100644 index 0000000..c21dda9 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/coup_yes.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/ekomi_rating.png b/utilitybelt/apps/UB_docs/images/common/ekomi_rating.png new file mode 100644 index 0000000..98fba96 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/ekomi_rating.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/express_icon.png b/utilitybelt/apps/UB_docs/images/common/express_icon.png new file mode 100644 index 0000000..ea5c931 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/express_icon.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/facebook-plugin.png b/utilitybelt/apps/UB_docs/images/common/facebook-plugin.png new file mode 100644 index 0000000..4052e1b Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/facebook-plugin.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/facebook_plugin_big.png b/utilitybelt/apps/UB_docs/images/common/facebook_plugin_big.png new file mode 100644 index 0000000..d1b3bac Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/facebook_plugin_big.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/gastrologic/button_zummenue.png b/utilitybelt/apps/UB_docs/images/common/gastrologic/button_zummenue.png new file mode 100644 index 0000000..cdf9a04 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/gastrologic/button_zummenue.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/gastrologic/pattern.gif b/utilitybelt/apps/UB_docs/images/common/gastrologic/pattern.gif new file mode 100644 index 0000000..cec74ac Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/gastrologic/pattern.gif differ diff --git a/utilitybelt/apps/UB_docs/images/common/gastrologic/taxi_icon.jpg b/utilitybelt/apps/UB_docs/images/common/gastrologic/taxi_icon.jpg new file mode 100644 index 0000000..713c57f Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/gastrologic/taxi_icon.jpg differ diff --git a/utilitybelt/apps/UB_docs/images/common/gastrologic_pattern.gif b/utilitybelt/apps/UB_docs/images/common/gastrologic_pattern.gif new file mode 100644 index 0000000..cec74ac Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/gastrologic_pattern.gif differ diff --git a/utilitybelt/apps/UB_docs/images/common/goldPattern.png b/utilitybelt/apps/UB_docs/images/common/goldPattern.png new file mode 100644 index 0000000..5700953 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/goldPattern.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/gplus-plugin.png b/utilitybelt/apps/UB_docs/images/common/gplus-plugin.png new file mode 100644 index 0000000..227166e Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/gplus-plugin.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/icon_cuisine.png b/utilitybelt/apps/UB_docs/images/common/icon_cuisine.png new file mode 100644 index 0000000..5bac930 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/icon_cuisine.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/icon_time_green.png b/utilitybelt/apps/UB_docs/images/common/icon_time_green.png new file mode 100644 index 0000000..7e62490 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/icon_time_green.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/icons.png b/utilitybelt/apps/UB_docs/images/common/icons.png new file mode 100644 index 0000000..4350324 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/icons.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/logo.png b/utilitybelt/apps/UB_docs/images/common/logo.png new file mode 100644 index 0000000..1d8f4d5 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/logo.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/logo125.png b/utilitybelt/apps/UB_docs/images/common/logo125.png new file mode 100644 index 0000000..c6d6534 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/logo125.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/logo57x57.png b/utilitybelt/apps/UB_docs/images/common/logo57x57.png new file mode 100644 index 0000000..06a0e33 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/logo57x57.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/logo70.png b/utilitybelt/apps/UB_docs/images/common/logo70.png new file mode 100644 index 0000000..30d3ca4 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/logo70.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/logo_small.png b/utilitybelt/apps/UB_docs/images/common/logo_small.png new file mode 100644 index 0000000..db721d6 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/logo_small.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/pattern-yellow.png b/utilitybelt/apps/UB_docs/images/common/pattern-yellow.png new file mode 100644 index 0000000..ad181cd Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/pattern-yellow.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/pattern.png b/utilitybelt/apps/UB_docs/images/common/pattern.png new file mode 100644 index 0000000..4adcfa3 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/pattern.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/pattern_blooms.png b/utilitybelt/apps/UB_docs/images/common/pattern_blooms.png new file mode 100644 index 0000000..6e61827 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/pattern_blooms.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/payment_icons.png b/utilitybelt/apps/UB_docs/images/common/payment_icons.png new file mode 100644 index 0000000..7ab26f3 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/payment_icons.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/restaurantlist_logoborder_hover.png b/utilitybelt/apps/UB_docs/images/common/restaurantlist_logoborder_hover.png new file mode 100644 index 0000000..21891df Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/restaurantlist_logoborder_hover.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/restaurantlist_logoborder_sprite.png b/utilitybelt/apps/UB_docs/images/common/restaurantlist_logoborder_sprite.png new file mode 100644 index 0000000..e69f3c1 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/restaurantlist_logoborder_sprite.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/search_lupe_klein.png b/utilitybelt/apps/UB_docs/images/common/search_lupe_klein.png new file mode 100644 index 0000000..e096d96 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/search_lupe_klein.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/sprite_nav.png b/utilitybelt/apps/UB_docs/images/common/sprite_nav.png new file mode 100644 index 0000000..b53a7f3 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/sprite_nav.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/stars_empty-ekomi-big.png b/utilitybelt/apps/UB_docs/images/common/stars_empty-ekomi-big.png new file mode 100644 index 0000000..29b7c0e Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/stars_empty-ekomi-big.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/temp_restaurantlogo.jpeg b/utilitybelt/apps/UB_docs/images/common/temp_restaurantlogo.jpeg new file mode 100644 index 0000000..94cb68e Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/temp_restaurantlogo.jpeg differ diff --git a/utilitybelt/apps/UB_docs/images/common/testimonials_closing_quotation.png b/utilitybelt/apps/UB_docs/images/common/testimonials_closing_quotation.png new file mode 100644 index 0000000..c8f176b Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/testimonials_closing_quotation.png differ diff --git a/utilitybelt/apps/UB_docs/images/common/testimonials_opening_quotation.png b/utilitybelt/apps/UB_docs/images/common/testimonials_opening_quotation.png new file mode 100644 index 0000000..f607777 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/common/testimonials_opening_quotation.png differ diff --git a/utilitybelt/apps/UB_docs/images/jqtransform/button_checkbox.png b/utilitybelt/apps/UB_docs/images/jqtransform/button_checkbox.png new file mode 100644 index 0000000..380fd52 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/jqtransform/button_checkbox.png differ diff --git a/utilitybelt/apps/UB_docs/images/jqtransform/button_radio.png b/utilitybelt/apps/UB_docs/images/jqtransform/button_radio.png new file mode 100644 index 0000000..8b6d3b1 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/jqtransform/button_radio.png differ diff --git a/utilitybelt/apps/UB_docs/images/jqtransform/cart_delete.png b/utilitybelt/apps/UB_docs/images/jqtransform/cart_delete.png new file mode 100644 index 0000000..597b0fc Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/jqtransform/cart_delete.png differ diff --git a/utilitybelt/apps/UB_docs/images/jqtransform/cart_plus_minus_bg.png b/utilitybelt/apps/UB_docs/images/jqtransform/cart_plus_minus_bg.png new file mode 100644 index 0000000..511805a Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/jqtransform/cart_plus_minus_bg.png differ diff --git a/utilitybelt/apps/UB_docs/images/jqtransform/select_left.png b/utilitybelt/apps/UB_docs/images/jqtransform/select_left.png new file mode 100644 index 0000000..6448beb Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/jqtransform/select_left.png differ diff --git a/utilitybelt/apps/UB_docs/images/jqtransform/select_right.png b/utilitybelt/apps/UB_docs/images/jqtransform/select_right.png new file mode 100644 index 0000000..64731aa Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/jqtransform/select_right.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_animation/background_slide.png b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/background_slide.png new file mode 100644 index 0000000..c6b467c Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/background_slide.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_animation/hero.png b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/hero.png new file mode 100644 index 0000000..91afa88 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/hero.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_1.png b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_1.png new file mode 100644 index 0000000..05895e8 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_1.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_2_1.png b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_2_1.png new file mode 100644 index 0000000..21ba601 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_2_1.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_2_2.png b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_2_2.png new file mode 100644 index 0000000..21aecd8 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_2_2.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_3_1.png b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_3_1.png new file mode 100644 index 0000000..ad701ec Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_3_1.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_3_2.png b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_3_2.png new file mode 100644 index 0000000..764e55c Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_animation/speech_3_2.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/1_order_brown.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/1_order_brown.png new file mode 100644 index 0000000..5cbe9d7 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/1_order_brown.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/2_order_grey.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/2_order_grey.png new file mode 100644 index 0000000..a3cf758 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/2_order_grey.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/3_order_grey.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/3_order_grey.png new file mode 100644 index 0000000..7afbff5 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/3_order_grey.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/baloon_order.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/baloon_order.png new file mode 100644 index 0000000..6bcc20c Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/baloon_order.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_no_order.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_no_order.png new file mode 100644 index 0000000..3bb4cfe Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_no_order.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_wait_order.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_wait_order.png new file mode 100644 index 0000000..bb00bb9 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_wait_order.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_yes_order.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_yes_order.png new file mode 100644 index 0000000..80509b9 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/hero_yes_order.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/hero_order/ok_icon_order.png b/utilitybelt/apps/UB_docs/images/widgets/hero_order/ok_icon_order.png new file mode 100644 index 0000000..af0bba0 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/hero_order/ok_icon_order.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/input_lc_plz.png b/utilitybelt/apps/UB_docs/images/widgets/input_lc_plz.png new file mode 100644 index 0000000..e98b2f6 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/input_lc_plz.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/lightbox_border.png b/utilitybelt/apps/UB_docs/images/widgets/lightbox_border.png new file mode 100644 index 0000000..0d0a764 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/lightbox_border.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/spinner.gif b/utilitybelt/apps/UB_docs/images/widgets/spinner.gif new file mode 100644 index 0000000..e158443 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/spinner.gif differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/tooltips/body_address.png b/utilitybelt/apps/UB_docs/images/widgets/tooltips/body_address.png new file mode 100644 index 0000000..ce2276d Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/tooltips/body_address.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/tooltips/ekomi-tooltip-body.png b/utilitybelt/apps/UB_docs/images/widgets/tooltips/ekomi-tooltip-body.png new file mode 100644 index 0000000..fee74fe Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/tooltips/ekomi-tooltip-body.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/tooltips/lieferheld_express.jpg b/utilitybelt/apps/UB_docs/images/widgets/tooltips/lieferheld_express.jpg new file mode 100644 index 0000000..a1ce89c Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/tooltips/lieferheld_express.jpg differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/tooltips/middle-box-express.png b/utilitybelt/apps/UB_docs/images/widgets/tooltips/middle-box-express.png new file mode 100644 index 0000000..9deeda1 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/tooltips/middle-box-express.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/tooltips/stars_full-ekomi-big.png b/utilitybelt/apps/UB_docs/images/widgets/tooltips/stars_full-ekomi-big.png new file mode 100644 index 0000000..5ac84d8 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/tooltips/stars_full-ekomi-big.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/tooltips/stars_full-ekomi.png b/utilitybelt/apps/UB_docs/images/widgets/tooltips/stars_full-ekomi.png new file mode 100644 index 0000000..f935867 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/tooltips/stars_full-ekomi.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/tooltips/tooltips.png b/utilitybelt/apps/UB_docs/images/widgets/tooltips/tooltips.png new file mode 100644 index 0000000..888fe1b Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/tooltips/tooltips.png differ diff --git a/utilitybelt/apps/UB_docs/images/widgets/wrong_icon_order.png b/utilitybelt/apps/UB_docs/images/widgets/wrong_icon_order.png new file mode 100644 index 0000000..d7a2297 Binary files /dev/null and b/utilitybelt/apps/UB_docs/images/widgets/wrong_icon_order.png differ diff --git a/utilitybelt/apps/UB_docs/index.html b/utilitybelt/apps/UB_docs/index.html new file mode 100644 index 0000000..0010b77 --- /dev/null +++ b/utilitybelt/apps/UB_docs/index.html @@ -0,0 +1,106 @@ + + + + +{{ method.method.trim() }}(' + + '{% _.each(method.params, function(param) { %}' + + '{{ param.types[0] }} {{ param.name }}' + + '{% }); %}' + + ') {% if (method.returns) { %}: {{ method.returns }}{% } %}
' + + '{{ method.description }}
' + + '{% }); %}'; + if (!methods.length) { + tpl += 'See {{ extend }}
'; + } + + $('#documentation').html(_.template(tpl)({ methods: methods, klass: klass, extend: extend })); + } + }); + } +}); diff --git a/utilitybelt/apps/example/config.js b/utilitybelt/apps/example/config.js new file mode 100644 index 0000000..4d2eda2 --- /dev/null +++ b/utilitybelt/apps/example/config.js @@ -0,0 +1,33 @@ + +/* + * Sample config file + * We use RequireJS as a module loader http://requirejs.org/docs/api.html + */ + +require.config({ + baseUrl: '/utilitybelt' +}); + +require([ + +/* Include Web UI library */ + + 'webui/config' + , 'tests/namespaces' +], function(webui) { + require([ + +/* Inlcude application files */ + + 'order!apps/example/pages/Page' + , 'order!apps/example/pages/Home' + + ], function() { + +/* Call router, which will create the instance of the relevant page */ + webui.Router('example.Home'); + + }) +}); + +var APP_LANGUAGE = 'de'; diff --git a/utilitybelt/apps/example/namespaces.js b/utilitybelt/apps/example/namespaces.js new file mode 100644 index 0000000..a1d9aad --- /dev/null +++ b/utilitybelt/apps/example/namespaces.js @@ -0,0 +1,4 @@ +/** Example application namespaces */ + +var example = {}; + diff --git a/utilitybelt/apps/example/pages/Home.js b/utilitybelt/apps/example/pages/Home.js new file mode 100644 index 0000000..85e9212 --- /dev/null +++ b/utilitybelt/apps/example/pages/Home.js @@ -0,0 +1,17 @@ + +/** Home page */ + +example.Home = example.Page.extend({ + + initialize: function() { + + example.Home.__super__.initialize.call(this); + + $(document).ready(function() { + + console.log('Home page ready'); + + }); + + } +}); \ No newline at end of file diff --git a/utilitybelt/apps/example/pages/Page.js b/utilitybelt/apps/example/pages/Page.js new file mode 100644 index 0000000..5053b7a --- /dev/null +++ b/utilitybelt/apps/example/pages/Page.js @@ -0,0 +1,12 @@ + +/** Basic application page class, contains features which should be on every page */ + +example.Page = webui.Page.extend({ + + initialize: function() { + + console.log('Common page ready'); + + } + +}); diff --git a/utilitybelt/bootstrap.js b/utilitybelt/bootstrap.js new file mode 100644 index 0000000..0862a9a --- /dev/null +++ b/utilitybelt/bootstrap.js @@ -0,0 +1,212 @@ + +/** utilitybelt.js bootstrap script + * Example usage: + * + * + * Configuragion options: + * @param {String} path Path to utilitybelt.js + * @param {String} mode 'DEV' or 'PROD', to swicth between development or production modes + * @param {Array} html5shims List of libraries enabling HTML5 features on old browsers + * @param {String} requirejs_path Path to RequireJs library (used as a UB widgets packager) + * @param {String} requirejs_mode If set to 'auto', requirejs will be included on set-up, and not when the widget is added + * @param {String} jquery_path Path to jQuery + * @param {String} jqueryui_path Path to jQueryUI + * @param {String} development_config Path to requirejs config used in development + * @param {String} production_bundle Path to single minified js bundle used in production + */ + +var ub_loader = function() { + + return { + + /** Public configuration */ + conf: { + 'paths': { + 'global': '/static/utilitybelt/utilitybelt/', + 'requirejs': 'lib/require/require.js', + 'jquery': 'lib/jquery/1.7.1/jquery.min.js', + 'jqueryui': 'lib/jqueryui/1.8.17/jquery-ui.min.js' + }, + 'html5shims': [ /*'lib/html5shiv/html5shiv.js'*/ 'lib/modernizr/2.6.2/modernizr.js', 'lib/selectivizr/1.0.2/selectivizr.js' ], + 'development_config': 'apps/Frontend_AU/config.js', + 'production_bundle': 'main-built' + }, + + /** UB widgets registry */ + widgets_registry: [], + + /** Libraries registry */ + libs_registry: {}, + + /** Setup config and enable shims */ + setup: function(conf) { + for (var field in conf) { + this.conf[field] = conf[field]; + } + if (this.conf.requirejs_mode == 'auto') { + this.add_requirejs(); + } + if (isOld()) { + this.inject_js(this.conf.html5shims); + } + }, + + /** Add library's '; + document.write(script_str); + this.libs_registry[url.src] = url; + } + } + } + } + + /** + * Wait until the test condition is true or a timeout occurs. Useful for waiting + * on a server response or for a ui change (fadeIn, etc.) to occur. + * + * @param check javascript condition that evaluates to a boolean. + * @param onTestPass what to do when 'check' condition is fulfilled. + * @param onTimeout what to do when 'check' condition is not fulfilled and 'timeoutMs' has passed + * @param timeoutMs the max amount of time to wait. Default value is 3 seconds + * @param freqMs how frequently to repeat 'check'. Default value is 250 milliseconds + */ + function waitFor(check, onTestPass, onTimeout, timeoutMs, freqMs) { + var timeoutMs = timeoutMs || 6000, + freqMs = freqMs || 100, + start = Date.now(), + condition = false, + timer = setTimeout(function() { + var elapsedMs = Date.now() - start; + if ((elapsedMs < timeoutMs) && !condition) { + condition = check(elapsedMs); + timer = setTimeout(arguments.callee, freqMs); + } else { + clearTimeout(timer); + if (!condition) { + onTimeout(elapsedMs); + } else { + onTestPass(elapsedMs); + } + } + }, freqMs); + } + + /** + * @return True if browser does not support major HTML5 and CSS3 features and needs shims + */ + function isOld() { // IE8 or worse + var docMode = document.documentMode; + return (/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 8)); + } + +} diff --git a/utilitybelt/core/build-plain.js b/utilitybelt/core/build-plain.js new file mode 100644 index 0000000..190a4f3 --- /dev/null +++ b/utilitybelt/core/build-plain.js @@ -0,0 +1,155 @@ +require([ +/* 'order!lib/jquery/1.7.1/jquery.min' // JQuery http://jquery.com/ + // 'order!lib/jquery/1.7.1/jquery' // JQuery http://jquery.com/ + ,*/ 'order!lib/jqueryui/1.8.17/jquery-ui.min' // JQuery UI http://jqueryui.com/ + , 'order!lib/underscore/1.3.3/underscore' // Underscore.js http://documentcloud.github.com/underscore/ + , 'order!lib/backbone/0.9.2/backbone' // Backbone.js http://documentcloud.github.com/backbone/ + , 'order!lib/backbone-relational/0.5.0/backbone-relational' // Backbone-relational.js https://github.com/PaulUithol/Backbone-relational + , 'order!lib/underscore-plugins/string/underscore.string' // Underscore String plugin http://epeli.github.com/underscore.string/ + , 'order!lib/modernizr/1.7/modernizr.min' // http://www.modernizr.com/ + , 'order!lib/sinon/1.3.2/sinon' + // , 'order!lib/&log/&log' + , 'order!lib/jquery-plugins/placeholder/2.0.7/placeholder' + , 'order!lib/jquery-plugins/cookie/jquery.cookie' + // , 'order!lib/jquery-plugins/jqTransform/1.0/jquery.jqtransform' + , 'order!lib/jquery-plugins/jqTransform/1.0.1dh/jquery.jqtransform.dh' + , 'order!lib/jquery-plugins/vtabs/vtabs' + + /* List of UB core files */ + + , 'order!core/namespaces' + , 'order!core/config/messages' + , 'order!core/config/locales' + , 'order!core/config/MapConfig' + , 'order!core/utils/Class' + , 'order!core/utils/Object' + , 'order!core/utils/getText' + , 'order!core/utils/getLocale' + , 'order!core/utils/Router' + , 'order!core/utils/getTemplate' + , 'order!core/utils/LS' + , 'order!core/utils/Proxy' + , 'order!core/utils/formatPrice' + , 'order!core/utils/formatItem' + , 'order!core/utils/formatAddress' + , 'order!core/utils/formatURL' + , 'order!core/utils/getUrlParams' + , 'order!core/utils/getUrlHash' + , 'order!core/utils/getIcon' + , 'order!core/utils/buildUrl' + , 'order!core/utils/Dom' + , 'order!core/utils/redirectLocation' + , 'order!core/utils/trackingLogger' + + , 'order!core/views/View' + , 'order!core/views/Box' + , 'order!core/views/Lightbox' + , 'order!core/views/Form' + , 'order!core/views/Form/ExitPoll' + , 'order!core/views/MapInterface' + , 'order!core/views/Page' + , 'order!core/views/Tooltip' + + , 'order!core/mixins/Validate' + , 'order!core/mixins/AutosuggestLocations' + + , 'order!core/collections/Collection' + , 'order!core/models/Model' + // , 'order!core/tests/namespaces' //temporary to build list view + // , 'order!core/tests/fixtures/UserAddress' //temporary to build list view + , 'order!core/models/Location' + , 'order!core/models/Address' + , 'order!core/models/DeliveryAddress' + , 'order!core/models/CartItem' + , 'order!core/models/ItemFlavor' + , 'order!core/models/Flavor' + , 'order!core/models/Item' + , 'order!core/models/ItemSize' + , 'order!core/models/Order' + , 'order!core/models/OrderGeneral' + , 'order!core/models/OrderPriceDetails' + , 'order!core/models/Restaurant' + , 'order!core/models/Section' + , 'order!core/models/Coupon' + , 'order!core/models/Payment' + , 'order!core/models/User' + , 'order!core/models/Authorization' + , 'order!core/models/Restaurant' + , 'order!core/models/Category' + , 'order!core/models/Option' + , 'order!core/models/ExitPoll' + , 'order!core/collections/Locations' + , 'order!core/collections/Address' + , 'order!core/collections/DeliveryAddress' + , 'order!core/collections/Cart' + , 'order!core/collections/DeliveryFee' + , 'order!core/collections/Order' + , 'order!core/collections/Category' + , 'order!core/collections/Option' + , 'order!core/collections/GeoLocations' + , 'order!core/views/Lightbox/Throbber' + , 'order!core/views/Form/Login' + , 'order!core/views/Form/Password' + , 'order!core/views/View/UserAccountTrigger' + , 'order!core/views/Form/UserAddress' + , 'order!core/views/Form/Checkout' + , 'order!core/views/Form/Filter' + , 'order!core/views/Maps/GoogleMaps' + , 'order!core/views/View/Cart' + , 'order!core/views/Lightbox/Flavors' + , 'order!core/views/View/LocationSearch' + , 'order!core/views/View/MultipleLocationList' + , 'order!core/views/View/UserAddressList' + , 'order!core/views/View/ActiveAddress' + , 'order!core/views/Lightbox/Login' + , 'order!core/views/Lightbox/Password' + , 'order!core/views/Lightbox/MultipleLocation' + , 'order!core/views/Lightbox/UserAddress' + , 'order!core/views/Lightbox/UserAddressList' + , 'order!core/views/Lightbox/PasswordForgotten' + , 'order!core/views/Lightbox/ZipCodeBox' + , 'order!core/views/Lightbox/ChooseBox' + , 'order!core/views/Lightbox/Error' + , 'order!core/views/Lightbox/ExitPoll' + , 'order!core/views/View/Payment' + , 'order!core/views/View/Confirmation' + , 'order!core/views/Box/Cart' + , 'order!core/views/Box/ReadOnlyCart' + + //, 'template!core/templates/Lightbox/base.html' + , 'template!core/templates/Throbber/Throbber.html' + , 'template!core/templates/Flavors/flavors.html' + , 'template!core/templates/UserAddress/UserAddresses.html' + , 'template!core/templates/UserAddress/UserAddressForm.html' + , 'template!core/templates/UserAddress/DeleteConfirm.html' + , 'template!core/templates/MultipleLocation/MultipleLocation.html' + , 'template!core/templates/MultipleLocation/MultipleLocationList.html' + , 'template!core/templates/Search/LocationSearchSingle.html' + , 'template!core/templates/Cart/Cart.html' + , 'template!core/templates/Cart/Item.html' + , 'template!core/templates/Cart/Details.html' + , 'template!core/templates/Form/ValidationErrors.html' + , 'template!core/templates/Lightbox/small.html' + , 'template!core/templates/Lightbox/base.html' + , 'template!core/templates/Lightbox/close.html' + , 'template!core/templates/Box/base.html' + , 'template!core/templates/Payment/payment.html' + , 'template!core/templates/User/PasswordForgotten.html' + , 'template!core/templates/PLZ/zip_code_lightbox.html' + , 'template!core/templates/PLZ/choose_lightbox.html' + , 'template!core/templates/Filter/FilterForm.html' + + , 'order!apps/Frontend_AU/namespaces' + , 'order!apps/Frontend_AU/config/messages' + , 'order!apps/Frontend_AU/pages/Page' + , 'order!apps/Frontend_AU/pages/Menu' + , 'order!apps/Frontend_AU/pages/Checkout' + , 'order!apps/Frontend_AU/pages/RestaurantList' + , 'order!apps/Frontend_AU/pages/RestaurantListOpen' + , 'order!apps/Frontend_AU/pages/Confirm' + , 'order!apps/Frontend_AU/pages/LandingPage' + , 'order!apps/Frontend_AU/pages/LoggedIn' + , 'order!core/tests/fixtures/Locations' + , 'order!apps/Frontend_AU/config' + , 'order!core/config' +]); diff --git a/utilitybelt/core/collections/Address.js b/utilitybelt/core/collections/Address.js new file mode 100644 index 0000000..6fcd209 --- /dev/null +++ b/utilitybelt/core/collections/Address.js @@ -0,0 +1,46 @@ +core.define('core.collections.Address', { + + extend: 'core.Collection', + + model: core.models.Address, + + initialize: function() { +// _.bindAll(this, 'change') +// this.on('add', function() { console.log(this, 'add') }) +/* + if (arguments[1] && arguments[1].hasOwnProperty('user_id')) { + this.user_id = arguments[1].user_id; + }; +*/ + }, + + url: function() { + +/* + try { + this._assertRequiredParams(); + } catch(error) { + // Error handling... cover this this block with tests as well + console.log('Error constructing collection url!', error); + }; +*/ + + return '/api/users/' + this.getUrlParams().user_id + '/addresses/?fields=address'; + }, + + parse: function(resp, xhr) { + var parsed = core.collections.Address.__super__.parse.call(this, resp, xhr); + parsed = _.map(parsed, function(rec) { + return rec.address || rec; + }); + return parsed; + } + +/* + _assertRequiredParams: function() { + if (!this.user_id) { + throw new Error('Required parameter user_id is missing!'); + }; + }, +*/ +}); diff --git a/utilitybelt/core/collections/Cart.js b/utilitybelt/core/collections/Cart.js new file mode 100644 index 0000000..2ecdc09 --- /dev/null +++ b/utilitybelt/core/collections/Cart.js @@ -0,0 +1,257 @@ +/** + * Collection of cart items that represents a shopping cart. + * Add and remove methods understand an additional option: quantity. + * This allows to update a cart item quantity. Those methods also synchronize + * a global sum. + * + * @property {string} currency The name of the currency used by the cart + * @property {string} currencySymbol The symbol of the currency used by the cart + */ +core.define('core.collections.Cart', { + extend: 'core.Collection', + model: core.models.CartItem, + order: false, + autosave: true, + + /** + * Constructor method. Reads static properties for currency + * and configures the new instance. + */ + initialize: function() { + this.sum = 0; + + // Not every single update for the cart should trigger a call to .save right away, + // so debounce this method. + this.save = _.debounce(_.bind(this.save, this), 1000); + }, + + /** + * Helper function to wrap an item in a cart item. + * @param {core.models.Item} product The Product to wrap and add to the cart + * @param {int} quantity The quantity of the product to add + * @return {core.models.CartItem} A CartItem instance holding the given quantity of the given product + */ + pack: function(product, quantity) { + return new core.models.CartItem(product, quantity); + }, + + /** + * Helper function to update the number of product in a cart item and sync the total price. + * The change event from the cart item is delayed until the cart sum is updated. + * @param {core.models.CartItem} cartItem The CartItem to update + * @param {int} quantity The new quantity of cart item product + * @return {int} The difference between the previous and the new quantity + */ + _updateCartItem: function(cartItem, quantity) { + var oldPrice = cartItem.price(); + var delta = cartItem.update(cartItem.get('quantity') + quantity, {silent: true}); + this.sum += cartItem.price() - oldPrice; + if (this.order) { + this.order.setSubTotal(this.sum); + if (this.autosave) { + // Set order.idle flag to false right away since .save() is debounced. + this.order.idle = false; + this.save(); + } + } + this.trigger('change', cartItem); + return delta; + }, + + /** + * Overwrites the add method to add an item or update its quantity if already + * present and sync the total price of the collection. + * + * @param {Object} models A model or an array of model to add to the collection + * @param {Object} options The options + * + * @trigger item:add (CartItem, delta) when an item is added to the cart + * @trigger quantity:increase (CartItem, delta) when an item has its quantity + * increased (i.e. The item was already in the cart) + */ + add: function(models, options) { + models = _.isArray(models) ? models : [models]; + var opts = _.extend({quantity: 1, silent: false}, options); + if (opts.quantity < 0) + throw 'illegal-quantity'; + for (var i=0, bound=models.length; i{{ jsFormatPrice(coupon_fee) }}
{{ cartItem.price }}
+ {{ description }} +
+{% _.each(flavors.items, function(flavorContainer) { %} ++ {{ address.zipcode + " " + address.city }} +
+{{ jsGetText("address_form_comment") }}
+ + diff --git a/utilitybelt/core/templates/UserAddress/UserAddresses.html b/utilitybelt/core/templates/UserAddress/UserAddresses.html new file mode 100644 index 0000000..f482768 --- /dev/null +++ b/utilitybelt/core/templates/UserAddress/UserAddresses.html @@ -0,0 +1,19 @@ +Delivery address Berlin change
+').text(jsGetText('global_ajax_error')).html(), + $('
').html($('').attr('href', window.location.href).text(jsGetText('page_reload'))).html() + ].join(' ')); + }, + + reload: function() { + window.location.reload(); + return false; + } +}); diff --git a/utilitybelt/core/views/Lightbox/ExitPoll.js b/utilitybelt/core/views/Lightbox/ExitPoll.js new file mode 100644 index 0000000..911994a --- /dev/null +++ b/utilitybelt/core/views/Lightbox/ExitPoll.js @@ -0,0 +1,23 @@ +/** + * Lightbox for Exit Poll + * + * var cb = new core.views.ExitPollLightbox(); + * cb.show(); + * + * @extends core.views.Lightbox + */ + +core.define('core.views.ExitPollLightbox', { + + extend : 'core.views.Lightbox', + template: 'Lightbox/small.html', + + initialize: function(options) { + this.on('render', function() { + this.options['hide'] = _.bind(this.hide, this); + this.addItem(core.views.ExitPollForm, this.options); + this.setTitle(jsGetText('poll_title')); + }); + core.views.ExitPollLightbox.__super__.initialize.call(this); + } +}); diff --git a/utilitybelt/core/views/Lightbox/Flavors.js b/utilitybelt/core/views/Lightbox/Flavors.js new file mode 100644 index 0000000..eebfd2d --- /dev/null +++ b/utilitybelt/core/views/Lightbox/Flavors.js @@ -0,0 +1,300 @@ +/** + * Lightbox which displays a list of flavors for a menu item + * + * Examples: + * + * var lb = new core.views.FlavorsLightbox(); + * lb.show(item); + * + * @extends core.views.Lightbox + */ + +core.define('core.views.FlavorsLightbox', { + + extend: 'core.views.Lightbox', + + templateFlavor: "Flavors/flavors.html", + + events: { + "click .top-box .close-icon": "hide", + "click .button": "chooseFlavors", + "click input[data-flavor-id]": 'recalculatePrice' + }, + + className: 'FlavorsLightbox', + + plugins: { + 'section': 'jqTransform' + }, + + /** + * Constructor + * @constructor + * @param {Object} options Options + */ + initialize: function(options) { + var me = this; + core.utils.getTemplate(me.templateFlavor, function(tpl) { + me.templateFlavor = tpl; + }); + core.views.FlavorsLightbox.__super__.initialize.call(this, options); + }, + + /** + * Display the flavors lightbox for a menu item + * @param {core.models.Item} item The backbone model (with flavors information) for the menu item + */ + show: function(item) { + this.item = item; + this.itemJSON = item.viewJSON(); + this.basePrice = this.itemJSON.sizes[0].price; + + //add all flavors to a view-wide collection so they can easily be retrieved by ID + this.allFlavors = item.getAllSubItems(); + + + this.title = this.itemJSON.name; + this.options.content = _.template(this.templateFlavor)( _.extend(this.itemJSON, { + getType: function(flavorContainer){ + if (flavorContainer.flavors.structure == null){ + throw new Error("Invalid flavor structure"); + } + var type = "radio"; + if (flavorContainer.flavors.structure == "0" || flavorContainer.flavors.structure == "2"){ + type = "checkbox"; + } + return type; + } + })); + core.views.FlavorsLightbox.__super__.show.call(this); + + this.setDisplayedPrice(core.utils.formatPriceWithoutCurrency(this.basePrice)); + }, + + /** + * Validates the flavors chosen for the item. If the validation is successful, the item is added to the cart. + * Otherwise, the invalid sections are highlighted. + */ + chooseFlavors: function() { + var clonedItem = {}; + jQuery.extend(true, clonedItem, this.itemJSON); + var itemModel = this.createItemWithSelectedFlavors(this.getSelectedFlavors(), clonedItem); + + var errorDiv = this.$(".flavors_error_message") + //VALIDATION + var errors = itemModel.validate(); + var me = this; + if(errors) { + errorDiv.html(""); + this.$(".flavors-section-header").removeClass("invalidSection"); + var scrolled = false; + _.each(errors, function(formId) { + var form = this.$("#" + formId); + if(form.length) { + if(!scrolled && me.isOverflowing()){ + core.utils.Dom.scrollTop(form[0]); //scroll to the *first* invalid form + scrolled = true; + } + form.find(".flavors-section-header").addClass("invalidSection"); + } + }, me); + errorDiv.html(jsGetText("flavors_message_choose")); + this.trigger("flavorsInvalid"); + } else { + this.trigger("flavorsChosen", { + selectedItemModel: itemModel + }); + this.hide(); + } + }, + + /** + * Creates a core.models.Item model for an item object. The resulting model contains only the flavors specified in flavorsArray. + * @param {Array} flavorsArray An array of ID strings of flavors to be included in the returned Item model + * @param {Object} selectedItem The object data structure for the menu item + */ + createItemWithSelectedFlavors: function(flavorsArray, selectedItem) { + + //TODO support arbitrary depth flavor nesting !! ditto for flavors.js + //FIXME selectedItem is not a backbone model anymore + for(var i = 0, subItems = selectedItem.flavors.items; i < subItems.length; i++) { + var subItem = subItems[i]; + for(var j = 0, subSubItems = subItem.flavors.items; j < subSubItems.length; j++) { + var subSubItem = subSubItems[j]; + var subSubId = subSubItem.id; + if(!_.include(flavorsArray, subSubId)) { + subItem.flavors.items = _.difference(subItem.flavors.items, [subSubItem]) + } + } + } + //all unselected flavors have been removed from the selectedItem. + var selectedItemModel = new core.models.Item(selectedItem); + return selectedItemModel; + }, + + /** + * Schedule this.calculateTotalPrice() for asynchronous execution, allowing the UI to update state + * @param {Object} evt The event object + */ + recalculatePrice: function(evt) { + var me = this; + setTimeout(function() { + me.calculateTotalPrice(); + }, 1); + + }, + + /** + * Returns the ID's of flavors that have been selected + * @return {Array} An array of stirng, one for each ID + */ + getSelectedFlavors: function() { + var checkedInputs = this.$el.find("form input:checked"); + var flavorIds = _.map(checkedInputs, function(input) { + return $(input).data('flavor-id') + ''; + }); + return flavorIds; + }, + + /** + * Updates the total price displayed in the view. + */ + calculateTotalPrice: function() { + var selectedFlavors = this.$el.find("form input:checked"); + var me = this; + var newPrice = this.basePrice; + + + _.each(selectedFlavors, function(elem) { + var id = $(elem).data('flavor-id') + ''; + var selectedFlavor = this.allFlavors.find(function(el){ + return el.get('id') == id; + }); + if(selectedFlavor && selectedFlavor.get('sizes')) { + var flavorPrice = selectedFlavor.get('sizes').at(0).get('price'); + newPrice += flavorPrice; + } + }, me); + this.setDisplayedPrice(core.utils.formatPriceWithoutCurrency(newPrice)); + }, + + /** + * Sets the displayed price to a specific value + * @param {String} price The price to be set + */ + setDisplayedPrice: function(price) { + this.$el.find(".total_price h3.right").text(price); + }, + + demo: function() { + var demoItem = { + "flavors": { + "items": [{ + "flavors": { + "items": [{ + "description": "", + "sizes": [{ + "price": 0.60, + "name": "normal" + }], + "pic": "", + "main_item": false, + "sub_item": true, + "id": "1131061", + "name": "Balsamico" + }, { + "description": "", + "sizes": [{ + "price": 0.60, + "name": "normal" + }], + "pic": "", + "main_item": false, + "sub_item": true, + "id": "1131062", + "name": "Caesar*1" + }], + "id": "76666", + "structure": "0" + }, + "description": "", + "sizes": [], + "pic": "", + "main_item": false, + "sub_item": false, + "id": "76666", + "name": "Extra Dressing" + }, { + "flavors": { + "items": [{ + "description": "", + "sizes": [{ + "price": 0.00, + "name": "normal" + }], + "pic": "", + "main_item": false, + "sub_item": true, + "id": "1131059", + "name": "Balsamico" + }, { + "description": "", + "sizes": [{ + "price": 0.00, + "name": "normal" + }], + "pic": "", + "main_item": false, + "sub_item": true, + "id": "1131060", + "name": "Caesar*1 " + }, { + "description": "", + "sizes": [{ + "price": 0.00, + "name": "normal" + }], + "pic": "", + "main_item": false, + "sub_item": true, + "id": "1131057", + "name": "ohne Dressing" + }], + "id": "76665", + "structure": "1" + }, + "description": "", + "sizes": [], + "pic": "", + "main_item": false, + "sub_item": false, + "id": "76665", + "name": "Dressing" + }], + "id": "1633809", + "structure": "-1" + }, + "description": "und Parmesan (inkl. 1 Dressing) ", + "sizes": [{ + "price": 4.50, + "name": "normal" + }], + "pic": "", + "main_item": true, + "sub_item": false, + "id": "1633809", + "name": "Gemischter Salat mit H\u00e4hnchenbrustfilet " + } + + var demoItemModel = new core.models.Item(demoItem); + + var flb = new core.views.FlavorsLightbox(); + var $result = $('Have a Gemischter Salat!').click( function() { + flb.show(demoItemModel); + flb.on("flavorsChosen", function(flavorsObj) { + //me.cartCollection.add(flavorsObj.selectedItemModel); //just a demo! + }); + }); + return $result; + } +}); \ No newline at end of file diff --git a/utilitybelt/core/views/Lightbox/Login.js b/utilitybelt/core/views/Lightbox/Login.js new file mode 100644 index 0000000..dcc0c54 --- /dev/null +++ b/utilitybelt/core/views/Lightbox/Login.js @@ -0,0 +1,43 @@ +/** + * Lightbox with the Login Form inside + * + * Examples: + * + * var lb = new core.views.LoginLightbox({ title: jsGetText('login') }); + * lb.show(); + * + * @extends core.views.Lightbox + */ +core.define('core.views.LoginLightbox', { + extend: 'core.views.Lightbox', + template: 'Lightbox/small.html', + + /** + * Constructor. + * @method initialize + * @constructor + * @param {Object} options Options passed to the login form view + */ + initialize: function(options) { + this.model = options.user || new core.models.User(); + this.options.model = this.model; + this.model.on('authorize:grant', _.bind(this.hide, this)); + this.on('render', function() { + var lb = this; + this.addItem(core.views.LoginForm, this.options); + }); + core.views.LoginLightbox.__super__.initialize.call(this); + }, + + /** + * Demo code. + */ + demo: function() { + var $result = $('Click Me') + .click(function() { + var lb = new core.views.LoginLightbox({ title: jsGetText('login_title') }); + lb.show(); + }); + return $result; + } +}); diff --git a/utilitybelt/core/views/Lightbox/MultipleLocation.js b/utilitybelt/core/views/Lightbox/MultipleLocation.js new file mode 100644 index 0000000..2914e19 --- /dev/null +++ b/utilitybelt/core/views/Lightbox/MultipleLocation.js @@ -0,0 +1,181 @@ +/** + * Lightbox with the User Location List inside + * + * Examples: + * + * var lb = new core.views.MultipleLocationLightbox(); + * lb.show(); + * + * @extends core.views.Lightbox + */ + +core.define('core.views.MultipleLocationLightbox', { + + extend : 'core.views.Lightbox', + + template : ["MultipleLocation/MultipleLocation.html"], + + events : { + "click .top-box .close-icon" : "hide", + "click .closeLB.button" : "hide" + }, + + options: { + closeButton: true, + blanketId: 'dark_blanket' + }, + + __shown : false, + + className : 'MultipleLocationLightbox', + + /** + * Constructor + * @constructor + * @param {Object} options Options + */ + initialize : function(options) { + this.locations = this.options.locations; + var me = this; + this.title = jsGetText("multiple_location_found"); + + this.searchTerm = this.options.searchTerm; + this.on('render', function() { + //adding the map and the list + me.map = me.addItem(core.views.Map, { + locations : me.locations + }, ".maps"); + me.map.on("markerClick", me.locationSelectHandler, me); + + var listOptions = { + locations : me.locations, + getBackgroundCSS : me.getBackgroundCSS + }; + me.map.render(); + me.list = me.addItem(core.views.MultipleLocationList, me.options, ".streets"); + me.list.on("location:selected", me.locationSelectHandler, me); + me.list.render(); + + core.utils.trackingLogger.log('search', 'search_event_popup_suggestions_display', this.searchTerm, me.locations.length); + }); + core.views.MultipleLocationLightbox.__super__.initialize.call(this); + }, + addItem : function(type, config, place) { + if (place != null) { + var positionElement = $('.body-box', this.$el).find(place); + var new_el = new type(config); + $(positionElement).html(new_el.$el); + return new_el; + } else if (this.getBody) { + core.views.MultipleLocationLightbox.__super__.addItem.call(this, type, config); + } + }, + /** + * setLocationList + * @param {Object} list + */ + setLocationList : function(list) { + this.locationList = list; + }, + /** + * + */ + getLocationList : function() { + return this.locationList; + }, + /** + * locationSelectHandler + * @param {Object} elem + */ + locationSelectHandler : function(elem) { + core.utils.trackingLogger.log('search', 'search_event_popup_suggestions_select', this.searchTerm, this.locations.length); + this.trigger("location:selected", elem); + }, + hide : function() { + //TODO as soon as we have a container object which keeps children we can add them here + if (this.map) { + this.map.hide(); + } + if (this.list) { + this.list.remove(); + } + this.__shown = false; + core.views.MultipleLocationLightbox.__super__.hide.call(this); + }, + show : function() { + this.__shown = true; + core.views.MultipleLocationLightbox.__super__.show.call(this); + }, + isShown : function() { + return this.__shown; + }, + demo : function() { + + var locations = { + "pagination" : { + "total_items" : 2, + "limit" : 10, + "total_pages" : 1, + "page" : 1, + "offset" : 0 + }, + "data" : [{ + "uri_search" : "http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=45.23234&long=37.77234", + "address" : { + "city_slug" : "berlin", + "city" : "Berlin", + "street_number" : "60", + "latitude" : 45.232340000000001, + "country" : "DE", + "street_name" : "Mohrenstrasse", + "zipcode" : "10117", + "longitude" : 37.77234 + } + }, { + "uri_search" : "http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=46.2004&long=37.88774", + "address" : { + "city_slug" : "berlin", + "city" : "Berlin", + "street_number" : "59", + "latitude" : 46.40000000000002, + "country" : "DE", + "street_name" : "Mohrenstrasse", + "zipcode" : "10117", + "longitude" : 37.887740000000001 + } + }, { + "uri_search" : "http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=46.2004&long=37.88774", + "address" : { + "city_slug" : "berlin", + "city" : "Berlin", + "street_number" : "59", + "latitude" : 46.200400000000002, + "country" : "DE", + "street_name" : "Mohrenstrasse", + "zipcode" : "10117", + "longitude" : 37.987740000000001 + } + }, { + "uri_search" : "http://mockapi.lieferheld.de/restaurants/?city=berlin&lat=46.2004&long=37.88774", + "address" : { + "city_slug" : "berlin", + "city" : "Berlin", + "street_number" : "59", + "latitude" : 46.400400000000002, + "country" : "DE", + "street_name" : "Mohrenstrasse", + "zipcode" : "10117", + "longitude" : 37.987740000000001 + } + }] + }; + + var $result = $('Click Me').click(function() { + var lb = new core.views.MultipleLocationLightbox({ + locations : locations.data + }); + lb.show(); + }); + return $result; + } +}); diff --git a/utilitybelt/core/views/Lightbox/Password.js b/utilitybelt/core/views/Lightbox/Password.js new file mode 100644 index 0000000..2f10416 --- /dev/null +++ b/utilitybelt/core/views/Lightbox/Password.js @@ -0,0 +1,46 @@ +/** + * Lightbox with the "password forgotten" form + * + * Examples: + * + * var lb = new core.views.PasswordLightbox(); + * lb.show(); + * + * @extends core.views.Lightbox + */ +core.define('core.views.PasswordLightbox', { + extend: 'core.views.Lightbox', + template: 'Lightbox/base.html', + + + /** + * Constructor. + * @method initialize + * @constructor + * @param {Object} options Options passed to the login form view + */ + initialize: function(options) { + this.model = options.user; + var lb = this; + this.on('render', function() { + this.addItem(core.views.PasswordForm, this.options); + this.formView = this.getItem(); + this.formView.on("hide",function(){ + lb.hide(); + }); + }); + core.views.LoginLightbox.__super__.initialize.call(this); + }, + + /** + * Demo code. + */ + demo: function() { + var $result = $('Click Me') + .click(function() { + var lb = new core.views.PasswordLightbox({ title: jsGetText('change_details') }); + lb.show(); + }); + return $result; + } +}); diff --git a/utilitybelt/core/views/Lightbox/PasswordForgotten.js b/utilitybelt/core/views/Lightbox/PasswordForgotten.js new file mode 100644 index 0000000..336e37e --- /dev/null +++ b/utilitybelt/core/views/Lightbox/PasswordForgotten.js @@ -0,0 +1,61 @@ +core.define('core.views.PasswordForgotten', { + + extend: 'core.views.Lightbox', + + template: ["User/PasswordForgotten.html"], + + events: { + 'click .button': 'resetPassword', + 'submit .passwordForgottenForm': 'resetPassword', + 'click .top-box .close-icon': 'hide' + }, + + hide: function(){ + delete this.options.errorMessage; + core.views.PasswordForgotten.__super__.hide.call(this); + }, + + resetPassword: function(event){ + event.preventDefault(); + var val = this.$("input.input-default").val(); + this.hide(); + this.reset(val); + }, + + /** + * resets the password via backbone model by the given email address + * @param {Object} email + */ + reset: function(email){ + var me = this; + var model = this.options.Authorization || new core.models.Authorization(); + model.save({ + "email": email, "op": "reset" + },{ + success: function(model, response){ + if (response != null && response.errors != null){ + _.each(response.errors, function(e){ + if (e.error_code != null){ + var errorCode = parseInt(e.error_code); + switch(errorCode){ + case 617: + case 616: + me.show(); + me.options.errorMessage = jsGetText("password_forgotten_not_found"); + break; + default: + me.show(); + me.options.errorMessage = jsGetText("error_happened_try_again"); + } + return; + } + }); + } + //TODO show the login box, was not in the master right now + }, error: function(){ + me.show(); + } + } + ); + } +}); diff --git a/utilitybelt/core/views/Lightbox/Throbber.js b/utilitybelt/core/views/Lightbox/Throbber.js new file mode 100644 index 0000000..a290eea --- /dev/null +++ b/utilitybelt/core/views/Lightbox/Throbber.js @@ -0,0 +1,166 @@ +/** + * Lightbox for showing the Loading Animation with or without blanket + * + * Examples: + * + * @extends core.views.Lightbox + */ + +core.define('core.views.Throbber', { + + extend: 'core.views.Lightbox', + + template: ["Throbber/Throbber.html"], + + events: { + }, + /** + * fadeInTime: fading in time[ms] for the animated image + * fadeOutTime: fading out time[ms] for the animated image + * delay: the delay time[ms] for starting the fading in of the animated image + * the blanket is not affected by this settng, it will be shown immediately + */ + options: { + fadeInTime: 250, + fadeOutTime: 150, + fadeDelay: 2000, + blanketId: "dark_blanket", + auto: true, + position: "fixed" + }, + + // timer for user callback + __timerCallback: null, + + initialize: function() { + var me = this, + timeout = this.options.fadeDelay; + this.timer = false; + if (this.options.auto) { + $(document).ajaxStop(function(event, xhr, error) { + clearTimeout(me.timer); + me.timer = false; + _.defer(function() { + me.hide(); + }); + }).ajaxStart(function(event, xhr, error) { + me.timer = _.delay(_.bind(me.show, me), timeout); + }); + } + core.views.Throbber.__super__.initialize.call(this); + }, + + /** + * handles the event when the window is resized + * calls center + * @param {Object} event includes the me object + */ + onResize: function(event) { + event.data.me.center.call(event.data.me); + }, + + initPosition: function() { + this.center(); + }, + /** + * calculates the center of the screen for the given image + */ + center: function() { + //center the animation picture + var image = this.getAnimImg(); + image.css({ + left: Math.round(($(window).innerWidth() - image.width() ) / 2) + "px", + top: Math.round(($(window).innerHeight() - image.height() ) / 2) + "px" + }); + }, + /** + * removes the blanket and the animated image + */ + hide: function() { + var me = this; + if (me.__timerCallback) { + clearTimeout(me.__timerCallback); + } + if (!this.isVisible()) { + return; + } + var img = me.getAnimImg(); + img.fadeOut(me.options.fadeOutTime, function() { + core.views.Throbber.__super__.hide.call(me); + $(window).off("resize", me.onResize); + }); + }, + /** + * fetches the img node inside the template + */ + getAnimImg: function() { + return this.$(".throbber"); + }, + /** + * setting the fading in duration + */ + setFadeInTime: function(value) { + if ( typeof value == 'number' && value >= 0) { + this.options.fadeInTime = value; + } + }, + /** + * setting the fading out duration + */ + setFadeOutTime: function(value) { + if ( typeof value == 'number' && value >= 0) { + this.options.fadeOutTime = value; + } + }, + /** + * setting the delay time to start fading in + */ + setDelay: function(value) { + if ( typeof value == 'number' && value >= 0) { + this.options.delay = value; + } + }, + /** + * setting the url of the image + */ + setImage: function(url) { + var image = this.getAnimImg(); + image.attr("src", url); + }, + /** + * setting the blanket id + * currently supported: + * - dark_blanket + * - light_blanket + */ + setBlanketId: function(blanketId) { + if (blanketId) { + this.options.blanketId = blanketId; + } + }, + + /** + * shows the blanket and starts the timeout using options.delay + * @see options.delay + */ + show: function(time, callback) { + var me = this; + if (this.isVisible()) { + return; + } + core.views.Throbber.__super__.show.call(me); + var img = me.getAnimImg(); + $(window).on("resize", { + "me": me + }, this.onResize); + img.fadeIn(me.options.fadeInTime); + me.center(); + //calling the callback function after a while + if (_.isFunction(callback) && _.isNumber(time) && time > 0) { + this.__timerCallback = setTimeout(function() { + callback(); + me.hide(); + }, time); + } + } +}); diff --git a/utilitybelt/core/views/Lightbox/UserAddress.js b/utilitybelt/core/views/Lightbox/UserAddress.js new file mode 100644 index 0000000..722c23c --- /dev/null +++ b/utilitybelt/core/views/Lightbox/UserAddress.js @@ -0,0 +1,61 @@ + /** + * Lightbox with the User Address Form inside + * + * Examples: + * + * var lb = new core.views.UserAddressLightbox({ id: 1, title: jsGetText('save_address') }); // fetch the record from the back-end + * lb.show(); + * + * var lb2 = new core.views.UserAddressLightbox({ record: { ... } }); // use the predefined record + * + * var lb3 = new core.views.UserAddressLightbox({ title: jsGetText('new_address') }); // open empty form + * lb3.on('render', function(lightbox) { // populate with data + * lightbox.getForm().populate( { ... } ) + * }); + * + * @extends core.views.Lightbox + */ + +core.define('core.views.UserAddressLightbox', { + + extend: 'core.views.Lightbox', + +/** + * Initialize + * @method initialize + * @constructor + * @param {Object} options Options + */ + + initialize: function(options){ + + var options = this.options; + + this.on('render', function() { + var lb = this; + this.options.onSuccess = function() { + lb.hide(); + new core.views.UserAddressListLightbox(options).show(); + }; + this.options.onBackLinkClick = function() { + lb.hide(); + new core.views.UserAddressListLightbox(options).show(); + }; + this.addItem(core.views.UserAddressForm, this.options); + }); + + core.views.UserAddressLightbox.__super__.initialize.call(this); + + }, + + demo: function() { + var $result = $('Click Me') + .click( function() { + var lb = new core.views.UserAddressLightbox({ id: 1, title: jsGetText('save_address') }); + lb.show(); + }); + return $result; + } + + +}); \ No newline at end of file diff --git a/utilitybelt/core/views/Lightbox/UserAddressList.js b/utilitybelt/core/views/Lightbox/UserAddressList.js new file mode 100644 index 0000000..3f7586a --- /dev/null +++ b/utilitybelt/core/views/Lightbox/UserAddressList.js @@ -0,0 +1,71 @@ +/** +* Lightbox with the User Addresses List inside +* +* Examples: +* +* var lb = new core.views.UserAddressListLightbox(); +* lb.show(); +* +* @extends core.views.Lightbox + */ + +core.define('core.views.UserAddressListLightbox', { + + extend: 'core.views.Lightbox', + + className: 'UserAddressListLightbox', + +/** + * Initialize + * @method initialize + * @constructor + * @param {Object} options Options + */ + + initialize: function(options){ + + this.title = jsGetText('address_list'); + + var user_id = this.options.user_id; + + this.on('render', function() { + var lb = this; + lb.addTitleLink(jsGetText('new_address')).addClass('new-address').click(function() { + var form = new core.views.UserAddressLightbox({ title: jsGetText('new_address'), user_id: user_id }); + form.show(); + lb.hide(); + }); + this.options.openEditWidget = function(options) { + options.user_id = user_id; + var form = new core.views.UserAddressLightbox(options); + form.show(); + lb.hide(); + }; + + var list = this.addItem(core.views.UserAddressList, this.options); + this.setAddressList(list); + + }); + + core.views.UserAddressListLightbox.__super__.initialize.call(this); + + }, + + setAddressList: function(list) { + this.addressList = list; + }, + + getAddressList: function() { + return this.addressList; + }, + + demo: function() { + var $result = $('Click Me') + .click( function() { + var lb = new core.views.UserAddressListLightbox({ user_id: 1 }); + lb.show(); + }); + return $result; + } + +}); \ No newline at end of file diff --git a/utilitybelt/core/views/Lightbox/ZipCodeBox.js b/utilitybelt/core/views/Lightbox/ZipCodeBox.js new file mode 100644 index 0000000..d5cb1af --- /dev/null +++ b/utilitybelt/core/views/Lightbox/ZipCodeBox.js @@ -0,0 +1,60 @@ +/** + * Lightbox showing the search location input + * + * Examples: + * + * var zb = new core.views.ZipCodeLightbox(); + * zb.show(); + * + * @extends core.views.Lightbox + */ + +core.define('core.views.ZipCodeLightbox', { + + extend : 'core.views.Lightbox', + + template: 'PLZ/zip_code_lightbox.html', + + plugins: { + 'form *': 'placeholder', + '.zip-input input': [ 'autocomplete', { + 'source': 'suggestLocation', + 'select': 'onSelectSuggestedLocation', + 'minLength': 2, + 'position': { offset: '0 -3' }, + 'delay': 300 + } ] + }, + + events : { + "submit .zip-input": "suggestOnEnter", + "click .button.big": "suggestOnEnter" + }, + + mixins: ['core.mixins.AutosuggestLocations'], + + options: { + blanketId: "light_blanket", + blanketClickToClose: true + }, + + __disabled: false, + + className : 'ZipCodeLightbox', + + getSearchInputField: function() { + if (!this.searchInputField) + this.searchInputField = $('.zip-input input'); + return this.searchInputField; + }, + + show: function(restaurantName){ + this.options.renderData = { + "restaurantName": restaurantName + }; + + core.views.ZipCodeLightbox.__super__.show.call(this); + //this.setTitle(jsGetText("location_box_title", restaurantName)); + } + +}); diff --git a/utilitybelt/core/views/MapInterface.js b/utilitybelt/core/views/MapInterface.js new file mode 100644 index 0000000..482eb67 --- /dev/null +++ b/utilitybelt/core/views/MapInterface.js @@ -0,0 +1,56 @@ +/* + * Map Interface + */ +core.define('core.views.MapInterface', { + + extend: 'core.View', + + template: '', + + className: "MapInterface", + + /* + * Constructor + * @returns core.views.Form + * @constructor + */ + initialize: function(options) { + //do the require here... + //throw new Error("this is just an interface and has to be implemented"); + }, + + /** + * + * @param {Object} markers + */ + addMarkers: function(markers) { + // throw new Error("this is just an interface and has to be implemented"); + }, + + /** + * + */ + removeAllMarkers: function() { + // throw new Error("this is just an interface and has to be implemented"); + }, + /** + * + */ + removeMarkers: function() { + // throw new Error("this is just an interface and has to be implemented"); + }, + /** + * @returns + */ + getServiceName: function() { + + }, + + addListener: function(){ + + }, + + demo: function() { + + } +}); diff --git a/utilitybelt/core/views/Maps/GoogleMaps.js b/utilitybelt/core/views/Maps/GoogleMaps.js new file mode 100644 index 0000000..01d7de6 --- /dev/null +++ b/utilitybelt/core/views/Maps/GoogleMaps.js @@ -0,0 +1,151 @@ +/* + * Google map wrapper + */ +core.define('core.views.Map', { + + extend: 'core.views.MapInterface', + + className: "Map", + __loaded: false, + + markers: [], + + /* + * Constructor + * @returns core.views.Form + * @constructor + */ + initialize: function(options) { + var me = this; + this.options = options; + this.__loaded = (window.google != null && window.google.maps != null && window.google.maps.Map != null); + this.on("render", function() { + if(me.__loaded) { + me.showMap(); + } + }); + //do the require here + if(!this.__loaded) { + if(window.mapLoadedObserver == null) { + window.mapLoadedObserver = { + mapLoaded: function() { + $(window.mapLoadedObserver).trigger("loaded"); + delete (window.mapLoadedObserver); + }, + addMapLoadedHandler: function(func, context){ + $(window.mapLoadedObserver).bind("loaded", _.bind(func, context)); + } + }; + var url = 'http://maps.google.com/maps/api/js?sensor=false&callback=window.mapLoadedObserver.mapLoaded'; + if(core.MapConfig != null && core.MapConfig.GOOGLE_MAP_KEY != null && core.MapConfig.GOOGLE_MAP_KEY.length > 0) { + url += '&key=' + core.MapConfig.GOOGLE_MAP_KEY; + } + require([url], function() { + }); + + } + // window.mapCallback = _.bind(function() { + // this.mapLoaded(); + // delete (window.mapCallback); + // }, this); + window.mapLoadedObserver.addMapLoadedHandler(me.mapLoaded, me); + }; + + }, + /** + * needed as a callback function to listen to + */ + mapLoaded: function() { + this.__loaded = true; + this.showMap(); + }, + /** + * shows the map in the dom, because of the internal asynhronous loading of google maps + */ + showMap: function() { + var mapDiv = null; + if(this.options.domNode != null) { + mapDiv = $(this.options.domNode); + } else { + mapDiv = $('.maps'); + } + + if(mapDiv.length != null && mapDiv.length > 0) { + mapDiv = mapDiv[0]; + } + else { + mapDiv = $('
')[0]; + } + + // create the map + this.map = new google.maps.Map(mapDiv, { + // center: new google.maps.LatLng(0, 0), + zoom: 13, + mapTypeId: google.maps.MapTypeId.ROADMAP, + navigationControl: true, + navigationControlOptions: { + style: google.maps.NavigationControlStyle.SMALL + } + }); + //adding the markers on the map + this.markers = []; + this.latLngBounds = new google.maps.LatLngBounds(); + var me = this; + this.options.locations.each( function(elem, index) { + var singleMarker = this.createMapMarker(elem.get('address'), index); + google.maps.event.addListener(singleMarker, 'click', function() { + me.handleMarkerClick.call(me, elem); + }); + this.markers.push(singleMarker); + this.latLngBounds.extend(singleMarker.position); + }, this); + //setting the center and the correct zoom level + this.map.setCenter(this.latLngBounds.getCenter()); + this.map.fitBounds(this.latLngBounds); + }, + /** + * handler for the marker clicking on the map + * @param {google.maps.Marker} elem which has been clicked on the map + */ + handleMarkerClick: function(elem) { + this.trigger("markerClick", elem); + }, + /** + * + * @param {Object} address the address object with street, latitude, longitude, etc... + * @param {Number} the index number for knowing which element has been clicked later on + */ + createMapMarker: function(addressObject, index) { + return new google.maps.Marker({ + map: this.map, + title: addressObject.street, + icon: core.utils.getIcon('mapMarker', index), + addressObject: addressObject, + index: index, + position: new google.maps.LatLng(addressObject.latitude, addressObject.longitude) + }); + }, + /** + * removes all markers from the map + */ + removeAllMarkers: function() { + _.each(this.markers, function(marker) { + // for (var marker in this.markers){ + marker.setMap(null); + }); + this.markers = []; + }, + /** + * @return {String} which service is being used + */ + getServiceName: function() { + return "Google Maps"; + }, + /** + * removes all markers and also the element itself from the DOM + */ + hide: function() { + this.removeAllMarkers(); + this.remove(); // TODO: make sure we're remove all Google Map's events as well + } +}); diff --git a/utilitybelt/core/views/Page.js b/utilitybelt/core/views/Page.js new file mode 100644 index 0000000..dc5f815 --- /dev/null +++ b/utilitybelt/core/views/Page.js @@ -0,0 +1,65 @@ +/** + * Basic Page class, every app page should extend it. + */ +core.define('core.Page', { + extend: 'core.View', + + /** + * Constructor. + * Sets up login or user actions for all pages. + */ + initialize: function() { + var user = this.options.user; + + // take over the whole page + this.setElement($('body')); + + // always provide a login lightbox, in case of error 401 + var authorizeTool = new core.views.LoginLightbox({ + user: user, + title: jsGetText('login_title') + }); + + this.on('render', function() { + // set up user action trigger (either login or actions) + var uat = { + model: user, + el: $('.button.login').parent(), + authorizeTool: user.isAuthorized() ? false : authorizeTool + }; + var userAccountTrigger = new core.views.UserAccountTrigger(uat); + + var knownAtLoading = user.isAuthorized(); + user.on('authorize:expire', function(user) { + if (knownAtLoading) { + authorizeTool.show(); + } + else { + user.makeAnonym(); + } + }); + + // set up a lightbox to display for ajax request errors + var errorBox = new core.views.ErrorLightbox(); + + this.$el.ajaxError(function(event, xhr, settings, error) { + if (_.indexOf([500, 502], xhr.status) > -1 && !settings.silent) { + errorBox.show(); + } + else if (401 === xhr.status) { + user.authorizeExpire(); + } + }); + + if (_.has(this.options, 'throbberDelay')) { + var throbber = new core.views.Throbber({ + fadeDelay: this.options.throbberDelay + }); + } + + }); + this.render(); + + core.Page.__super__.initialize.call(this); + } +}); diff --git a/utilitybelt/core/views/Tooltip.js b/utilitybelt/core/views/Tooltip.js new file mode 100644 index 0000000..0aa379a --- /dev/null +++ b/utilitybelt/core/views/Tooltip.js @@ -0,0 +1,62 @@ +/** + * Tooltip + * @requires core.View + */ +core.define('core.views.Tooltip', { + + extend: 'core.View', + + className: "Tooltip", + + /** + * Define handlers for mouse interactions (click, mouseenter, mouseleave) + */ + setHandlers: function() { + var out; + this.options.anchor.mouseleave( function() { + out = setTimeout( function() { + $el.fadeOut(600); + }, 300); + }); + + $(document).click( function() { + $el.fadeOut(600); + }); + + $el.mouseenter( function(event) { + clearTimeout(out); + event.stopPropagation(); + $el.mouseleave( function(event) { + $el.fadeOut(600); + }); + }); + + }, + + /* + * Adjust Tooltip position according to the anchor + * @param {Object} anchor Anchor element (for example, link which should be clicked to display the tooltip) + */ + adjustPosition: function(anchor) { + var pos = anchor.position(), // offset doesn't calculate position correctly + height = anchor.height(), + width = anchor.width(); + $el.css({ "left": (pos.left) - (width/2 - 50) + "px", "top": pos.top + height - 5 + "px", position: 'absolute', 'z-index': 999999 }); + }, + + /* + * @constructor + */ + initialize: function() { + $el = this.el; + + this.adjustPosition(this.options.anchor); + + this.setHandlers(); + + $el.fadeToggle(600); + + if (this.options.click_event) + this.options.click_event.stopPropagation(); + } +}); diff --git a/utilitybelt/core/views/View.js b/utilitybelt/core/views/View.js new file mode 100644 index 0000000..59b3914 --- /dev/null +++ b/utilitybelt/core/views/View.js @@ -0,0 +1,123 @@ +/** + * Basic core View, all views (widgets) should extend it + * @param {String} template Template code + */ +core.define('core.View', { + + extend: 'Backbone.View', + + /* + * Plugins to be bound to the view after rendering. + * Describe plugins like this: + * selector: [plugin name, opt1, opt2, ...] + * Options will be passed to the plugin function with apply(). + */ + plugins: {}, + children: [], + + /** + * Runs on widget's render, triggers 'render' event + */ + render: function() { + + this.delegateEvents(); + + if (this.options && this.options.events) { + this.delegateEvents(_.extend(this.events, this.options.events)); + } + + var me = this; + me.rendered = true; + setTimeout( function() { + me.trigger('render'); + me.bindPlugins(); + }, 1); + return this; + }, + + /* + * Renders widget to specified cotainer + * @param {jQuery} ct Jquery container to render to + */ + renderTo: function(ct) { + var me = this; + this.on('render', function() { + ct.empty().append(me.$el); + }); + }, + + + /** + * Binds the plugins to the view using the plugins property. + * The property has to describe which element, which plugin and how to attach it: + * selector1: [plugin1, opt1, opt2, ...], + * selector2: [plugin2, opt3, opt4, ...] + * + * Option can be both primitive types and callbacks: + * + * 'input': [ 'autocomplete', { + * 'source': 'suggestLocation', // will be bind to suggestLocation method of the View + * 'minLength': 2 + * } ] + * + * With no options, the array can be omitted: + * selector1: plugin1 + * + * The plugin is first looked up in the view itself, then in $.fn, + * enabling overwritting for complex config. + */ + bindPlugins: function() { + var me = this; + for (var s in me.plugins) { + var plugin = me.plugins[s], + opts = []; + if (typeof plugin == 'object') { + opts = plugin.slice(1); + _.each(opts, function(opt) { + for (var key in opt) { + var fn = opt[key]; + if (me[fn]) + opt[key] = _.bind(me[fn], me); + }; + }) + plugin = plugin[0]; + } + var fn = plugin in me ? me[plugin] : $.fn[plugin]; + fn.apply(me.$el.find(s), opts); + } + }, + + /** + * Adds an instance of the "type" widget into the body (container returned by the getBody() method) + * Keeps a reference to the added item in the children property. + * @param {Class} type Class name which should be added + * @param {Object} config Class config options + * @returns added element + */ + addItem: function(type, config) { + if (this.getBody) { + var $body = this.getBody(); + var el = 'cid' in config ? config : new type(config); + this.children.push(el); + $body.append(el.$el); + return el; + } + }, + + /** + * Returns the last of the view children. + * TODO handle multiple children. + * + * FIXME somehow, in the UB_docs, a view is added twice for a box. + * Apparently, the good reference (which has its markup in the DOM) is the last one. + * + * @return {Object} The last added child + */ + getItem: function() { + return this.children[this.children.length - 1]; + }, + + demo: function() { + return $(''); + } +}); diff --git a/utilitybelt/core/views/View/ActiveAddress.js b/utilitybelt/core/views/View/ActiveAddress.js new file mode 100644 index 0000000..9117e02 --- /dev/null +++ b/utilitybelt/core/views/View/ActiveAddress.js @@ -0,0 +1,134 @@ +/** + * Example: + */ +core.define('core.views.ActiveAddress', { + extend: 'core.View', + + events: { + 'click a.change' : 'showSearchWidget' + }, + + options: { + el: 'section.filter', + searchPlaceholder: '.search_placeholder', + marginTarget: '.restaurant-count, .landing_page', + marginClass: 'margin-top-filter', + changeSelector: 'a.change', + cookieName: 'active_address', + closeable: true + }, + + /** + * Constructor + */ + initialize: function() { + var me = this; + this.initLocationSearchWidget(); + this.hideSearchWidget(true); + if (!this.options.activeAddress) { + me.showSearchWidget(); + } + }, + + /** + * Initialise Location Search widget and register event listeners + */ + initLocationSearchWidget: function() { + var me = this, + ls = { + renderToEl : $(me.options.searchPlaceholder), + showCloseButton: this.options.closeable + }; + me.locationSearchWidget = new core.views.LocationSearch(ls); + me.locationSearchWidget.on("locationFound", this.locationFound); + me.locationSearchWidget.on("locationNotFound", function(params){ + core.utils.trackingLogger.logError('search_error_nomatch_rlist', params.searchValue); + me.showError.call(me); + }); + me.locationSearchWidget.on("locationFetchError", function(){ + me.showError.call(me); + }); + + me.locationSearchWidget.on('toggle:hide', function(searchWidget) { + searchWidget.$el.fadeOut(300, function() { + me.trigger('toggle:hide:complete'); + $(me.options.marginTarget).removeClass(me.options.marginClass, 300); + me.$(me.options.changeSelector).fadeIn(); + }); + }); + + me.locationSearchWidget.on('toggle:show', function(searchWidget) { + $(me.options.marginTarget).addClass(me.options.marginClass, 300, function() { + searchWidget.$el.fadeIn(300, function() { + me.trigger('toggle:show:complete'); + me.$(me.options.changeSelector).fadeOut(); + }); + }); + }); + }, + + /** + * Location Found event handler + */ + locationFound: function(ev) { + var me = this; + if (ev && ev.collection) { + if (ev.collection.length > 1) { + if (me.multiLocationLB && me.multiLocationLB.isShown()) { + return; + } + me.multiLocationLB = new core.views.MultipleLocationLightbox({ + locations : ev.collection, + position : "absolute", + searchTerm: ev.searchTerm + }); + me.multiLocationLB.on('location:selected', function(item) { + me.multiLocationLB.hide(); + core.utils.redirectLocation(item); + }); + me.multiLocationLB.show(); + } else if (ev.collection.length == 1) { + core.utils.redirectLocation(ev.collection.first()); + } + } + }, + + /** + * Show Location Search Widget Wrapper + */ + showSearchWidget: function(ev) { + if (ev) { + ev.preventDefault(); + } + this.locationSearchWidget.show(); + }, + + /** + * Hide Location Search Widget Wrapper + */ + hideSearchWidget: function(bypass) { + if (bypass) { + this.locationSearchWidget.$el.hide(); + this.trigger('toggle:hide:complete'); + } else { + this.locationSearchWidget.hide(); + } + }, + + /** + * Show errors + */ + showError : function() { + var messageLightbox = new core.views.Lightbox({ + title : jsGetText("search_not_found_title"), + content : jsGetText("search_not_found_message"), + template : "Lightbox/small.html" + }); + var me = this; + messageLightbox.on("hide", function(){ + me.locationSearchWidget.__disabled = false; + }); + this.locationSearchWidget.__disabled = true; + messageLightbox.show(); + } +}); \ No newline at end of file diff --git a/utilitybelt/core/views/View/Cart.js b/utilitybelt/core/views/View/Cart.js new file mode 100644 index 0000000..f40eefd --- /dev/null +++ b/utilitybelt/core/views/View/Cart.js @@ -0,0 +1,229 @@ +/** + * View for displaying a cart + * + * Example: + * + * var cart = new core.views.Cart(); + * cart.renderTo($('#some_element')); + * + * @param {Cart} cart The linked Cart item + */ +core.define('core.views.Cart', { + extend: 'core.View', + className: 'Cart', + events: {}, + options: { + readOnly: false, + preorder: false, + collection: false, + mainTpl: 'Cart/Cart.html', + itemTpl: 'Cart/Item.html', + detailsTpl: 'Cart/Details.html' + }, + + /** + * Constructor, sets collection and templates. + * Builds partials to provide shortcuts for modifying item quantities. + */ + initialize: function() { + // partials for incrementing and decrementing quantities + this.quantityInc = _.bind(this.quantityUpdate, this, 1); + this.quantityDec = _.bind(this.quantityUpdate, this, -1); + this.collection = this.options.collection || new core.collections.Cart(); + var me = this; + // copied from parent class to avoid unbinding relevant events + this.collection.on('reset change', function() { + me.render(); + }, this.collection); + // let's bind and trigger stuff when template is finally loaded + core.utils.getTemplate([me.options.mainTpl, me.options.itemTpl, me.options.detailsTpl], function(main, item, details) { + me.mainRender = _.template(main); + me.itemRender = _.template(item); + me.detailsRender = _.template(details); + me.collection.on('change sync reset', _.bind(me.onItemsChange, me)); + me.collection.order.on('order:changeAddress', _.bind(me.onItemsChange, me)); + // (re)render item row for each addition or quantity modification + me.collection.on('quantity:increase quantity:decrease item:add', function(item, delta) { + me.unRenderItem('.empty'); + me._renderDetails(); + me.renderItem(item.toJSON()); + }); + // remove cart row for item removals + me.collection.on('item:remove', function(item, delta) { + if (this.length) { + me.unRenderItem(item.get('id')); + me._renderDetails(); + } + }); + // display empty cart if emptied + me.collection.on('reset', function() { me.renderEmpty(); }); + if (!me.options.readOnly) { + _.extend(me.events, { + 'click .cart-plus': 'quantityInc', + 'click .cart-minus': 'quantityDec', + 'click a.checkout': '_checkout' + }); + } + // trigger change and rendering + me.collection.trigger('change'); + }); + }, + + /** + * Runs when cart items change (add, remove, empty, save state) + */ + onItemsChange: function() { + this.collection.order.get('price_details').updatePriceDetails(); + this.render(); + this.toggleCheckoutButton(this.collection.isReadyForSync()); + }, + + /** + * Toggles checkout button state. + * @param {Boolean} enabled Boolean tellin wether the button must be enabled or not + */ + toggleCheckoutButton: function(enabled) { + var btn = this.$('.checkout'), cls = 'disabled'; + if (enabled) + btn.removeClass(cls); + else + btn.addClass(cls); + }, + + /** + * Renders widget using the collection and the templates + * @return {core.views.Cart} this + */ + render: function() { + var me = this, + collection = me.collection; + var records = collection.toJSON(); + me.$el.empty().append(me.mainRender({cart: this.options})); + if (collection.length) { + this._renderDetails(); + _.each(records, function(item) { + me.renderItem(item); + }); + } else { + me.renderEmpty(); + } + return core.views.Cart.__super__.render.call(this); + }, + + /** + * Refreshes or adds a new item to the cart. + * @param {Object} item A hash (produced by CartItem.toJSON()) + * @return {core.views.Cart} this + */ + renderItem: function(item) { + item.price = core.utils.formatPrice(item.price); + var markup = this.itemRender({ + cartItem: item, + cart: { + readOnly: this.options.readOnly + } + }); + var current = this.$('.' + item.id); + if (current.length) { + current.replaceWith($(markup)); + } else { + this.$('ul .meta:first').before(markup); + } + return this; + }, + + /** + * Refreshes or adds a detail rows to the cart. + * @return {core.views.Cart} this + */ + _renderDetails: function() { + var priceDetails = this.collection.order.get('price_details').viewJSON(); + var markup = this.detailsRender(priceDetails); + this.$('ul .meta').remove(); + this.$('ul').append(markup); + return this; + }, + + unRenderItem: function(id) { + this.$('ul li.' + id).remove(); + if (!this.collection.length) { + this.renderEmpty(); + } + }, + + /** + * Runs when cart is empty. + * Note that fees should still be displayed: + */ + renderEmpty: function() { + var cartItems = this.$('ul').empty(); + $('
+ Die beste Pizza, die ich jemals bei einem Lieferanten gegessen habe! Der extra ... weiterlesen +
+