diff --git a/Gemfile b/Gemfile index 7cf43305..0f5ca329 100644 --- a/Gemfile +++ b/Gemfile @@ -21,6 +21,7 @@ group :assets do gem 'therubyracer', :platforms => :ruby gem 'uglifier', '>= 1.0.3' + gem 'mustache' #, :require => 'mustache/railtie' end gem 'jquery-rails' @@ -44,7 +45,8 @@ gem 'kaminari-bootstrap' # To use Jbuilder templates for JSON # gem 'jbuilder' group :development do - gem 'pry' + gem 'pry' + gem 'pry-remote' gem 'rspec-rails' gem 'thin' end diff --git a/Gemfile.lock b/Gemfile.lock index 3263f1b0..dd89859c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,7 +50,7 @@ GEM arel (3.0.2) bcrypt-ruby (3.0.1) builder (3.0.4) - capybara (2.0.0) + capybara (2.0.1) mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) @@ -97,7 +97,7 @@ GEM factory_girl_rails (4.1.0) factory_girl (~> 4.1.0) railties (>= 3.0.0) - ffi (1.1.5) + ffi (1.2.0) fssm (0.2.9) haml (3.1.7) haml-rails (0.3.5) @@ -124,7 +124,7 @@ GEM actionpack (>= 3.1) less (~> 2.2.0) libv8 (3.3.10.4) - libwebsocket (0.1.6) + libwebsocket (0.1.6.1) websocket mail (2.4.4) i18n (>= 0.4.0) @@ -135,6 +135,7 @@ GEM mini_magick (3.4) subexec (~> 0.2.1) multi_json (1.3.7) + mustache (0.99.4) nokogiri (1.5.5) orm_adapter (0.0.7) polyglot (0.3.3) @@ -142,6 +143,9 @@ GEM coderay (~> 1.0.5) method_source (~> 0.8) slop (~> 3.3.1) + pry-remote (0.1.6) + pry (~> 0.9) + slop (~> 3.0) rack (1.4.1) rack-cache (1.2) rack (>= 0.4) @@ -233,7 +237,7 @@ GEM multi_json (~> 1.0, >= 1.0.2) warden (1.1.1) rack (>= 1.0) - websocket (1.0.3) + websocket (1.0.4) xpath (1.0.0) nokogiri (~> 1.3) @@ -253,7 +257,9 @@ DEPENDENCIES kaminari-bootstrap less-rails mini_magick + mustache pry + pry-remote rack-cors rails (= 3.2.9) rqrcode diff --git a/app/assets/javascripts/user/application.js.erb b/app/assets/javascripts/user/application.js.erb index 9f38e5ff..0bbcd65e 100644 --- a/app/assets/javascripts/user/application.js.erb +++ b/app/assets/javascripts/user/application.js.erb @@ -27,6 +27,7 @@ //= require twitter/bootstrap/bootstrap-typeahead //= require twitter/bootstrap/bootstrap-affix //= require qwaiter +//= require mustache //= require_directory . //= require_self var path_mapping = { @@ -176,9 +177,20 @@ $(function(){ container.show(); } $('[data-t]').each(function(){$(this).text(t($(this).attr('data-t')))}) + setTranslations(); }); function setLocale(locale){ QMobile.setLocale(locale); $locale = locale; - $('[data-t]').each(function(){$(this).text(t($(this).attr('data-t')))}) + setTranslations(); +} +function Qupdate(selector){ + setTranslations(selector); +} +function setTranslations(selector){ + if(selector){ + $(selector).find('[data-t]').each(function(){$(this).text(t($(this).attr('data-t')))}) + }else{ + $('[data-t]').each(function(){$(this).text(t($(this).attr('data-t')))}) + } } diff --git a/app/assets/javascripts/user/quser.js.coffee b/app/assets/javascripts/user/quser.js.coffee index 83f20d68..c4d29bbc 100644 --- a/app/assets/javascripts/user/quser.js.coffee +++ b/app/assets/javascripts/user/quser.js.coffee @@ -175,31 +175,35 @@ window.Quser= link.attr('href', root_url + src + '?'+authentication_string+'&page='+i) li.append(link) list.append(li) + mustache: (selector, locals)-> + locs = $.extend(locals, + currency: -> + (val)-> + currency(Mustache.render(val, this)) + ) + Mustache.to_html($(selector).html(), locs) build_list_table: (body, foot, res) -> body.find('tr').remove() foot.find('tr').remove() if !res.orders && !res.orders.length alert('No orders in list') return - for order in res.orders + m_obj = res + for order in m_obj.orders order_txts = [] - row = $('').appendTo(body) - row.addClass(order.state) - #if(order.state == 'placed') row.addClass('info'); - #if(order.state == 'delivered') row.addClass('success'); - row.addClass('error') if order.state == 'cancelled' for product in order.products order_txts.push(product.name + ' (' + product['number'] + ')') - row.append($('').text(order_txts.join(', '))) - row.append($('').html(currency(order.total_amount))) - foot.append(''+currency(res.total_amount)+'') + order.products_display = order_txts.join(', ') + body.append @mustache('#active-list-orders-template', m_obj) + foot.append @mustache('#active-list-orders-footer-template', m_obj) + order_selected_products: ()-> return if $.isEmptyObject(window.active_products_list) h = {} match = window.document.URL.toString().match('table_id=([0-9a-zA-Z]+)') h['table_id'] = match[1] if match - for product_id, info of window.active_products_list - h['products['+product_id+']'] = info.number + for product_id, number of window.active_products_list + h['products['+product_id+']'] = number $.post(data_host + '/user/order_selected_products', $.extend(h, authentication_object), ((res) -> Quser.handle_response(res)), 'json') handle_response: (res) -> if(typeof(res) == 'string') @@ -215,21 +219,17 @@ window.Quser= else redirect_to res.location || 'list_products' if res['ok'] build_product_list: -> - table = $('#active-order-table') - tbody = table.find('tbody') - tbody = $('').appendTo(table) unless tbody.length - tbody.find('tr').remove() total = 0.0 - for product_id, info of window.active_products_list - total += info.product.price * info.number - row = $('').attr('id', 'active-order-row-'+product_id).appendTo(tbody) - row.append(''+info.product.name+'') - row.append(''+info.number+'') - row.append(''+currency(info.product.price * info.number)+'') - x_btn = $('').click(-> delete(window.active_products_list[product_id]) && Quser.build_product_list() ) - row.append($('').append(x_btn)) - $('#active-order-total').html(currency(total)) - table.show() + h = {products: []} + for product_id, number of window.active_products_list + product = window.products[product_id] + product.number = number + product.product_total = product.price * number + h.products.push product + total += product.price * number + h.total = total + $('#active-order-container').html @mustache('#active-order-template', h) + Qupdate('#active-order-container') load_active_list_products: -> Quser.populate_products_table('/user/list_products.json?'+authentication_string) @@ -256,40 +256,39 @@ window.Quser= if res.supplier_name $('.supplier-name').text(res.supplier_name) delete(res['supplier_name']) + window.products = {} body.find('tr').remove() + script_id = if include_order_buttons then '#products-category-for-order-template' else '#products-category-template' for category, products of res - body.append('

'+category+'

') + body.append Quser.mustache(script_id, + category: category, + products: products, + include_order_buttons: include_order_buttons + ) for product in products - row = $('') - row.append(''+product.name+'') - if include_order_buttons - button = $('') - callback = ((prod) -> - -> - product_count_holder = $('#order-product-count-'+prod._id) - count = parseInt(product_count_holder.text()) - product_count_holder.text(1) - Quser.add_product(prod, count) - )(product) - button.click(callback) - order_product_count = $('1') - order_count_minus = $('-') - order_count_minus.click(-> - val_holder = $(this).siblings('.order-product-count') - val = parseInt(val_holder.text()) - val_holder.text(val - 1) if val > 1 - ) - order_count_plus = $('+') - order_count_plus.click(-> - val_holder = $(this).siblings('.order-product-count') - val = parseInt(val_holder.text()) - val_holder.text(val + 1) - ) - row.append($('').append(order_count_minus).append(' ').append(order_product_count).append(' ').append(order_count_plus)) - row.append(''+currency(product.price)+'') - row.append($('').append(button)) if include_order_buttons - body.append(row) + window.products[product._id] = product ) + increment_products_counter: (product_id)-> + product_count_holder = $('#order-product-count-'+product_id) + count = parseInt(product_count_holder.text()) + product_count_holder.text(count + 1) + false + lower_products_counter: (product_id)-> + product_count_holder = $('#order-product-count-'+product_id) + count = parseInt(product_count_holder.text()) + product_count_holder.text(count - 1) + false + add_product_to_order: (product_id, context) -> + product_count_holder = $('#order-product-count-'+product_id) + count = parseInt(product_count_holder.text()) + count ||= 1 + product_count_holder.text(1) + window.active_products_list ||= {} + window.active_products_list[product_id] ||= 0 + window.active_products_list[product_id] += count + delete(window.active_products_list[product_id]) if window.active_products_list[product_id] < 1 + Quser.build_product_list() + false actions_for_table: (table)-> table = JSON.parse(table) if typeof(table) == 'string' $.getJSON(data_host + '/user/table_info.json?'+authentication_string+'&table_id='+table.table_id, (res)-> @@ -357,11 +356,11 @@ window.Quser= else redirect_to 'user_root', {message: 'join_request_rejected'} ) - add_product: (product, count) -> + add_product: (product_id, count) -> count ||= 1 - window.active_products_list = {} unless window.active_products_list - window.active_products_list[product._id] = {product: product, number: 0} unless window.active_products_list[product._id] - window.active_products_list[product._id].number += count + window.active_products_list ||= {} + window.active_products_list[product_id] ||= 0 + window.active_products_list[product_id] += count Quser.build_product_list() clear_selected_products: -> window.active_products_list = {} diff --git a/app/templates/user/_active_list_orders.mustache b/app/templates/user/_active_list_orders.mustache new file mode 100644 index 00000000..8e2d7a2a --- /dev/null +++ b/app/templates/user/_active_list_orders.mustache @@ -0,0 +1,6 @@ +{{#orders}} + + {{products_display}} + {{#currency}}{{total_amount}}{{/currency}} + +{{/orders}} diff --git a/app/templates/user/_active_list_orders_footer.mustache b/app/templates/user/_active_list_orders_footer.mustache new file mode 100644 index 00000000..403b0f47 --- /dev/null +++ b/app/templates/user/_active_list_orders_footer.mustache @@ -0,0 +1 @@ +{{#currency}}{{total_amount}}{{/currency}} diff --git a/app/templates/user/_active_order.mustache b/app/templates/user/_active_order.mustache new file mode 100644 index 00000000..5eb0a618 --- /dev/null +++ b/app/templates/user/_active_order.mustache @@ -0,0 +1,29 @@ + + + + + + + + + + + {{#products}} + + + + + + {{/products}} + + + + + + + + +
#
{{name}}{{number}}{{#currency}}{{product_total}}{{/currency}}
+ + + {{#currency}}{{total}}{{/currency}}
diff --git a/app/templates/user/_products_category.mustache b/app/templates/user/_products_category.mustache new file mode 100644 index 00000000..87543de1 --- /dev/null +++ b/app/templates/user/_products_category.mustache @@ -0,0 +1,7 @@ +

{{category}}

+{{#products}} + + {{name}} + {{#currency}}{{price}}{{/currency}} + +{{/products}} diff --git a/app/templates/user/_products_category_for_order.mustache b/app/templates/user/_products_category_for_order.mustache new file mode 100644 index 00000000..eddbf7c6 --- /dev/null +++ b/app/templates/user/_products_category_for_order.mustache @@ -0,0 +1,13 @@ +

{{category}}

+{{#products}} + + {{name}} + + - + 1 + + + + {{#currency}}{{price}}{{/currency}} + + +{{/products}} diff --git a/app/views/layouts/phone.html.slim b/app/views/layouts/phone.html.slim index 0a915209..3f964ad1 100644 --- a/app/views/layouts/phone.html.slim +++ b/app/views/layouts/phone.html.slim @@ -17,7 +17,7 @@ html lang="en" link href="/images/apple-touch-icon.png" rel="apple-touch-icon-precomposed" link href="/favicon.ico" rel="shortcut icon" javascript: - var data_host = '#{Rails.env == 'development' ? 'http://localhost:3000' : 'http://data.qwaiter.com' }'; + var data_host = '#{Rails.env == 'development' ? 'http://qwaiter.dev' : 'http://data.qwaiter.com' }'; //var data_host = 'http://localhost:3000'; //data_host = 'http://192.168.1.148:3000'; var $locale = 'en'; diff --git a/app/views/user/active_list.html.slim b/app/views/user/active_list.html.slim index 9d3a98e3..56972a35 100644 --- a/app/views/user/active_list.html.slim +++ b/app/views/user/active_list.html.slim @@ -16,6 +16,8 @@ tr td colspan=2 = slider_image tfoot +script#active-list-orders-template[type="text/html"]= render 'active_list_orders.mustache' +script#active-list-orders-footer-template[type="text/html"]= render 'active_list_orders_footer.mustache' - content_for :footer do javascript: jQuery(function(){ diff --git a/app/views/user/list_products.html.slim b/app/views/user/list_products.html.slim index 9affe714..dee36534 100644 --- a/app/views/user/list_products.html.slim +++ b/app/views/user/list_products.html.slim @@ -11,23 +11,10 @@ tbody tr td= slider_image - table#active-order-table.table.hide - thead - tr - th data-t="models.product"= Product.model_name.human - th # - th.currency data-t="basket.total"= t('user.basket.total') - th - tbody - tfoot - tr - td colspan=2 - button class="btn btn-primary" onClick="Quser.handle_active_list(function(){Quser.order_selected_products()})" data-t="selected_products.order"= t('selected_products.order') - |  - button class="btn btn btn-warning" onClick="Quser.clear_selected_products()" data-t="selected_products.clear"= t('selected_products.clear') - td.currency - strong#active-order-total - td + #active-order-container +script#products-category-template[type="text/html"]= render 'products_category.mustache' +script#products-category-for-order-template[type="text/html"]= render 'products_category_for_order.mustache' +script#active-order-template[type="text/html"]= render 'active_order.mustache' - content_for :footer do javascript: jQuery(function(){ diff --git a/app/views/user/list_products_for_table.html.slim b/app/views/user/list_products_for_table.html.slim index 57ead7e0..ceb3852b 100644 --- a/app/views/user/list_products_for_table.html.slim +++ b/app/views/user/list_products_for_table.html.slim @@ -24,6 +24,8 @@ td.currency strong#active-order-total td +script#products-category-template[type="text/html"]= render 'products_category.mustache' +script#products-category-for-order-template[type="text/html"]= render 'products_category_for_order.mustache' - content_for :footer do javascript: jQuery(function(){ diff --git a/config/initializers/mustache_template_handler.rb b/config/initializers/mustache_template_handler.rb new file mode 100644 index 00000000..2eb3f77f --- /dev/null +++ b/config/initializers/mustache_template_handler.rb @@ -0,0 +1,11 @@ +module MustacheTemplateHandler + def self.call(template) + if template.locals.include? :locals + "Mustache.render(#{template.source.inspect}, locals).html_safe" + else + "#{template.source.inspect}.html_safe" + end + end +end +ActionView::Template.register_template_handler(:mustache, MustacheTemplateHandler) +ActionController::Base.view_paths << Rails.root.join('app', 'templates') diff --git a/vendor/assets/javascripts/mustache.js b/vendor/assets/javascripts/mustache.js new file mode 100644 index 00000000..0148d29d --- /dev/null +++ b/vendor/assets/javascripts/mustache.js @@ -0,0 +1,625 @@ +/*! + * mustache.js - Logic-less {{mustache}} templates with JavaScript + * http://github.com/janl/mustache.js + */ + +/*global define: false*/ + +var Mustache; + +(function (exports) { + if (typeof module !== "undefined" && module.exports) { + module.exports = exports; // CommonJS + } else if (typeof define === "function") { + define(exports); // AMD + } else { + Mustache = exports; //