diff --git a/app/assets/javascripts/qwaiter.js.coffee b/app/assets/javascripts/qwaiter.js.coffee index 9d4d6c26..1fe8cde7 100644 --- a/app/assets/javascripts/qwaiter.js.coffee +++ b/app/assets/javascripts/qwaiter.js.coffee @@ -1,5 +1,6 @@ window.Qwaiter= alert: (msg) -> + $('.modal').modal('hide') template = @mustache('#alert-template', {title: 'Alert', message: msg, close: 'OK'}) $(template).modal() false diff --git a/app/assets/javascripts/supplier/qsupplier.js.coffee b/app/assets/javascripts/supplier/qsupplier.js.coffee index d9fde4b1..292f5ba5 100644 --- a/app/assets/javascripts/supplier/qsupplier.js.coffee +++ b/app/assets/javascripts/supplier/qsupplier.js.coffee @@ -134,10 +134,8 @@ root.Qsupplier= Qsupplier.build_list_table(body, foot, res) ) build_list_table: (body, foot, res) -> - if !res.orders && !res.orders.length - alert('No orders in list') - return body.html('') + return unless res.orders for order in res.orders body.append @mustache('#list-order-template', new Order(order)) foot.find('.list-total').html(currency(res.total_amount)) @@ -160,10 +158,11 @@ root.Qsupplier= by_row_count = parseInt($('#arrange-tables-by-row-count').val()) by_column_count = parseInt($('#arrange-tables-by-column-count').val()) if(option == "by_row") - return alert('Please fill in a positive number representing the number of tables per row') unless by_row_count && by_row_count > 0 + return @alert(t('section.arrange_tables.by_row_no_row_count')) unless by_row_count && by_row_count > 0 if(option == "by_column") - return alert('Please fill in a positive number representing the number of tables per column') unless by_column_count && by_column_count > 0 - $.post('/supplier/sections/'+current_section_id+'/arrange_tables', {option: option, row_count: by_row_count, column_count: by_column_count}, -> window.location.reload()) + return @alert(t('section.arrange_tables.by_column_no_column_count')) unless by_column_count && by_column_count > 0 + $.post '/supplier/sections/'+current_section_id+'/arrange_tables', {option: option, row_count: by_row_count, column_count: by_column_count}, (response)=> + if response.ok then window.location.reload() else @alert(t(response.message)) false mustache: (selector, locals)-> locs = $.extend(locals, @@ -172,3 +171,4 @@ root.Qsupplier= currency(Mustache.render(val, this)) ) Mustache.to_html($(selector).html(), locs) + alert: Qwaiter.alert diff --git a/app/assets/javascripts/supplier/translations.js.erb b/app/assets/javascripts/supplier/translations.js.erb index a057ccba..a9d2d020 100644 --- a/app/assets/javascripts/supplier/translations.js.erb +++ b/app/assets/javascripts/supplier/translations.js.erb @@ -1,13 +1,14 @@ var $translations = { en: { - messages: <%= I18n.t('messages', locale: :en).to_json %>, models: <%= I18n.t('activemodel.models', locale: :en).to_json %>, attributes: <%= I18n.t('activemodel.attributes', locale: :en).to_json %>, + helpers: <%= I18n.t('helpers', locale: :en).to_json %>, <%= I18n.t('supplier', locale: :en).to_json[1..-2] %> }, nl: { models: <%= I18n.t('activemodel.models', locale: :nl).to_json %>, attributes: <%= I18n.t('activemodel.attributes', locale: :nl).to_json %>, + helpers: <%= I18n.t('helpers', locale: :nl).to_json %>, <%= I18n.t('supplier', locale: :nl).to_json[1..-2] %> } } @@ -15,6 +16,7 @@ $transformation_mappings = { downcase: 'toLowerCase', upcase: 'toUpperCase' } + function t(path, vars){ vars || (vars = {}); var result, m, translatable, isafety,replacable; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 829c0df2..b14c45a9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -49,11 +49,13 @@ private message = args.first || '' {ok: false, message: message}.merge(options).to_json end + alias json_alert js_alert def js_notice(*args) options = args.extract_options! message = args.first || '' {ok: true, message: message}.merge(options).to_json end + alias json_notice js_notice # Return the hostname of the event server def event_host diff --git a/app/controllers/suppliers/sections_controller.rb b/app/controllers/suppliers/sections_controller.rb index 6dd8bb28..ed702e3b 100644 --- a/app/controllers/suppliers/sections_controller.rb +++ b/app/controllers/suppliers/sections_controller.rb @@ -132,11 +132,11 @@ module Suppliers def arrange_tables @section = Section.find_by_supplier_id_and_id!(current_supplier.id, params[:id]) case params[:option] - when 'distributed' then @section.arrange_tables_in_grid - when 'by_row' then @section.arrange_tables_in_rows_of(params[:row_count].to_i) - when 'by_column' then @section.arrange_tables_in_columns_of(params[:column_count].to_i) + when 'distributed' then render(json: (@section.arrange_tables_in_grid ? {ok: true} : json_alert('messages.could_not_arrange_tables_distributed'))) + when 'by_row' then render(json: (@section.arrange_tables_in_rows_of(params[:row_count].to_i) ? {ok: true} : json_alert('messages.could_not_arrange_tables_by_row'))) + when 'by_column' then render(json: (@section.arrange_tables_in_columns_of(params[:column_count].to_i) ? {ok: true} : json_alert('messages.could_not_arrange_tables_by_column'))) + else render(json: json_alert('messages.could_not_arrange_tables')) end - render json: {ok: true} end end end diff --git a/app/models/section.rb b/app/models/section.rb index b93984af..1ea80e0a 100644 --- a/app/models/section.rb +++ b/app/models/section.rb @@ -1,5 +1,6 @@ class Section include SimplyStored::Couch + include Qwaiter::Distribution property :title property :path, type: Array, default: [] @@ -77,50 +78,45 @@ class Section w = width h = height n = tables.size - return unless w > 0 && h > 0 && n > 0 - l = Math.sqrt((w*h).to_f/n) - epsilon = (10 ** -(Float::DIG - 1)).to_f - while (w/l).floor * (h/l).floor < n # find a fitting combination - l = if w.remainder(l) < epsilon then (h/l).ceil - elsif h.remainder(l) < epsilon then (w/l).ceil - elsif w.remainder(l) < epsilon && h.remainder(l) < epsilon then [w / (w/l).ceil.succ, h / (h/l).ceil.succ].max # Failsafe for when both are valid and it still does not fit - else [w / (w/l).ceil, h / (h/l).ceil].max end - end - x0 = w.remainder(l - epsilon)/2 # Start with half a remainder space, will end with the other halve + return false unless w > 0 && h > 0 && n > 0 + lx, ly = distribute_lattice(w, h, n) + x0 = lx/2 x = x0 - y = h.remainder(l - epsilon)/2 + y = ly/2 saves = [] for table in tables.sort_by(&:number) - if x + l > w + (1e4*epsilon) # New row, error = epsilon times possible tables + if x > w + (1e4*epsilon) # New row, error = epsilon times possible tables in a row x = x0 - y += l + y += ly end - table.position_x = x + (l/2) - (table_width/2) # Starting point of square + half the square (center) minus half the table size - table.position_y = y + (l/2) - (table_height/2) + table.position_x = x - (table.width/2) # Starting point of square + half the square (center) minus half the table size + table.position_y = y - (table.height/2) saves << table.save - x += l + x += lx end - [l, saves.all?] + saves.all? end def arrange_tables_in_rows_of(n) - return unless n.present? + return false unless n.present? n = n.to_i - return unless n > 0 + return false unless n > 0 dx = width / n dy = height / (tables.size.to_f/n).ceil x = 0.0 y = 0.0 + saves = [] tables.sort_by(&:number).each.with_index do |table, i| - table.position_x = x + (dx/2) - (table_width/2) - table.position_y = y + (dy/2) - (table_height/2) + table.position_x = x + (dx/2) - (table.width/2) + table.position_y = y + (dy/2) - (table.height/2) x += dx if (i + 1).multiple_of?( n ) x = 0.0 y += dy end - table.save + saves << table.save end + return saves.all? end def arrange_tables_in_columns_of(n) return unless n.present? @@ -131,8 +127,8 @@ class Section x = 0.0 y = 0.0 tables.sort_by(&:number).each.with_index do |table, i| - table.position_x = x + (dx/2) - (table_width/2) - table.position_y = y + (dy/2) - (table_height/2) + table.position_x = x + (dx/2) - (table.width/2) + table.position_y = y + (dy/2) - (table.height/2) y += dy if (i + 1).multiple_of?( n ) y = 0.0 @@ -142,13 +138,4 @@ class Section end end - # Method returning the sections table width - def table_width - 2.0 - end - - # Method returning the sections table height - def table_height - 2.0 - end end diff --git a/app/models/table.rb b/app/models/table.rb index 13e43b01..3f3f13fc 100644 --- a/app/models/table.rb +++ b/app/models/table.rb @@ -36,4 +36,13 @@ class Table number end + # Method returning the sections table width + def width + 2.0 + end + + # Method returning the sections table height + def height + 2.0 + end end diff --git a/app/templates/supplier/_alert.mustache b/app/templates/supplier/_alert.mustache new file mode 100644 index 00000000..b078499a --- /dev/null +++ b/app/templates/supplier/_alert.mustache @@ -0,0 +1,12 @@ +
diff --git a/app/views/layouts/tablet.html.slim b/app/views/layouts/tablet.html.slim index 0e37438e..cc60f64f 100644 --- a/app/views/layouts/tablet.html.slim +++ b/app/views/layouts/tablet.html.slim @@ -77,9 +77,6 @@ html lang="en" = content_for?(:content) ? yield(:content) : yield - if content_for?(:row) .row= yield :row - /! - Javascripts - \================================================== - /! Placed at the end of the document so the pages load faster = javascript_include_tag "supplier/application" + script#alert-template[type="text/html"]= mustache_template 'supplier/alert' = yield :footer diff --git a/app/views/suppliers/sections/index.html.slim b/app/views/suppliers/sections/index.html.slim index d45bdd9e..af6e222c 100644 --- a/app/views/suppliers/sections/index.html.slim +++ b/app/views/suppliers/sections/index.html.slim @@ -5,12 +5,12 @@ table.table thead tr - th.link= model_class.human_attribute_name(:title) - th.table-info= Table.model_name.human_plural - th.numeric= model_class.human_attribute_name(:width) - th.numeric= model_class.human_attribute_name(:height) - th.timestamp= model_class.human_attribute_name(:created_at) - th.actions=t 'helpers.actions' + th.link data-t='attributes.section.title' = model_class.human_attribute_name(:title) + th.table-info data-t='models.plural.table' = Table.model_name.human_plural + th.numeric data-t='attributes.section.width' = model_class.human_attribute_name(:width) + th.numeric data-t='attributes.section.height' = model_class.human_attribute_name(:height) + th.timestamp data-t='attributes.section.created_at' = model_class.human_attribute_name(:created_at) + th.actions data-t='helpers.actions' = t 'helpers.actions' tbody - @sections.each do |section| tr @@ -22,12 +22,14 @@ td.numeric= section.height td.timestamp=l section.created_at, format: :short td.actions - = link_to t('supplier.section.tables_view'), [:tables_view, :suppliers, section], class: [:btn, 'btn-mini btn-info'] + = link_to t('supplier.section.tables_view.link'), [:tables_view, :suppliers, section], class: 'btn btn-mini btn-info', data: {t: 'section.tables_view.link'} ' - = link_to t('helpers.links.edit'), [:edit, :suppliers, section], class: 'btn btn-mini' + = link_to t('supplier.section.manage_tables.link'), [:manage_tables, :suppliers, section], class: 'btn btn-mini btn-warning', data: {t: 'section.manage_tables.link'} ' - = link_to t("helpers.links.destroy"), [:suppliers, section], method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-mini btn-danger' + = link_to t('helpers.links.edit'), [:edit, :suppliers, section], class: 'btn btn-mini', data: {t: 'helpers.links.edit'} + ' + = link_to t("helpers.links.destroy"), [:suppliers, section], method: :delete, data: {confirm: are_you_sure?, t: 'helpers.links.destroy'}, class: 'btn btn-mini btn-danger' - else = no_content_given model_class .form-actions - = link_to t("helpers.links.new"), new_suppliers_section_path, class: 'btn btn-primary' + = link_to t("helpers.links.new"), new_suppliers_section_path, class: 'btn btn-primary', data: {t: 'helpers.links.new'} diff --git a/app/views/suppliers/sections/manage_tables.html.slim b/app/views/suppliers/sections/manage_tables.html.slim index 333d4993..3eaa2702 100644 --- a/app/views/suppliers/sections/manage_tables.html.slim +++ b/app/views/suppliers/sections/manage_tables.html.slim @@ -1,5 +1,6 @@ - model_class = Section -.page-header data-t='section.manage_tables.title' data-t-attributes=%|{"title":"#{@section.title}"}| +.page-header + h1 data-t='section.manage_tables.title' data-t-attributes=%|{"title":"#{@section.title}"}| - content_for :row do ul.nav.nav-tabs - for section in @section.supplier.sections @@ -22,17 +23,17 @@ .table-number = table.number .clearfix .form-actions - = link_to t("helpers.links.back"), suppliers_sections_path, class: 'btn' + = link_to t("helpers.links.back"), suppliers_sections_path, class: 'btn', data: {t: 'helpers.links.back'} ' - = link_to t('helpers.links.edit'), [:edit, :suppliers, @section], class: 'btn' + = link_to t('helpers.links.edit'), [:edit, :suppliers, @section], class: 'btn', data: {t: 'helpers.links.edit'} ' - = link_to t('supplier.section.tables_view'), [:tables_view, :suppliers, @section], class: [:btn, 'btn-info'] + = link_to t('supplier.section.tables_view.link'), [:tables_view, :suppliers, @section], class: 'btn btn-info', data: {t: 'section.tables_view.link'} ' - a.btn href='#add-tables-modal' role='button' data-toggle='modal'= t('supplier.section.add_tables.button_label') + a.btn href='#add-tables-modal' role='button' data-toggle='modal' data-t='section.add_tables.button_label' = t('supplier.section.add_tables.button_label') ' - a.btn href='#arrange-tables-modal' role='button' data-toggle='modal'= t('supplier.section.arrange_tables.button_label') + a.btn href='#arrange-tables-modal' role='button' data-toggle='modal' data-t='section.arrange_tables.button_label' = t('supplier.section.arrange_tables.button_label') ' - = link_to t("helpers.links.destroy"), [:suppliers, @section], method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-danger' + = link_to t("helpers.links.destroy"), [:suppliers, @section], method: :delete, data: {confirm: are_you_sure?, t: 'helpers.links.destroy' }, class: 'btn btn-danger' - content_for :footer do javascript: var current_section_id = '#{@section.id}'; diff --git a/app/views/suppliers/sections/show.html.slim b/app/views/suppliers/sections/show.html.slim index 6f97a119..da279844 100644 --- a/app/views/suppliers/sections/show.html.slim +++ b/app/views/suppliers/sections/show.html.slim @@ -1,21 +1,22 @@ - model_class = Section -.page-header= title :show, @section +.page-header + h1 data-t='section.show.title' dl.dl-horizontal.show-list - dt= model_class.human_attribute_name(:title) + dt data-t='attributes.section.title' = model_class.human_attribute_name(:title) dd= @section.title dl.dl-horizontal.show-list - dt= model_class.human_attribute_name(:width) + dt data-t='attributes.section.width' = model_class.human_attribute_name(:width) dd= @section.width dl.dl-horizontal.show-list - dt= model_class.human_attribute_name(:height) + dt data-t='attributes.section.height' = model_class.human_attribute_name(:height) dd= @section.height .form-actions - = link_to t("helpers.links.back"), suppliers_sections_path, class: 'btn' + = link_to t("helpers.links.back"), suppliers_sections_path, class: 'btn', data: {t: 'helpers.links.back'} ' - = link_to t('helpers.links.edit'), [:edit, :suppliers, @section], class: 'btn' + = link_to t('helpers.links.edit'), [:edit, :suppliers, @section], class: 'btn', data: {t: 'helpers.links.edit'} ' - = link_to t('supplier.section.manage_tables'), [:manage_tables, :suppliers, @section], class: [:btn, 'btn-warning'] + = link_to t('supplier.section.manage_tables.link'), [:manage_tables, :suppliers, @section], class: 'btn btn-warning', data: {t: 'section.manage_tables.link'} ' - = link_to t('supplier.section.tables_view'), [:tables_view, :suppliers, @section], class: [:btn, 'btn-info'] + = link_to t('supplier.section.tables_view.link'), [:tables_view, :suppliers, @section], class: 'btn btn-info', data: {t: 'section.tables_view.link'} ' - = link_to t("helpers.links.destroy"), [:suppliers, @section], method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-danger' + = link_to t("helpers.links.destroy"), [:suppliers, @section], method: :delete, data: {confirm: are_you_sure?, t: 'helpers.links.destroy'}, class: 'btn btn-danger' diff --git a/config/application.rb b/config/application.rb index 9a8dd25e..2586a3bd 100644 --- a/config/application.rb +++ b/config/application.rb @@ -86,4 +86,5 @@ module Qwaiter config.assets.version = '1.0' end end +require 'qwaiter' require 'rqrcode-rails3' diff --git a/config/locales/en.yml b/config/locales/en.yml index 68f5143d..811429bd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -91,6 +91,11 @@ en: needs_payment: Wants to pay closed_at: Closed at supplier: + messages: + could_not_arrange_tables: 'The tables could not be arranged' + could_not_arrange_tables_distributed: 'The tables could not be arranged. Does the ${models.section|downcase} have a width and a height?' + could_not_arrange_tables_by_row: 'The tables could not be arranged. Does the ${models.section|downcase} have a width and a height?' + could_not_arrange_tables_by_column: 'The tables could not be arranged. Does the ${models.section|downcase} have a width and a height?' menu: active_lists: Active lists active_lists: @@ -111,9 +116,13 @@ en: title: Show %{list} section: first_section_title: Room + show: + title: 'Show ${models.section|downcase}' manage_tables: + link: 'Manage tables' title: "Manage tables for ${models.section|downcase}: %{title}" - tables_view: Tables view + tables_view: + link: 'Tables view' add_tables: button_label: Add tables modal: @@ -125,6 +134,8 @@ en: add_button: Add arrange_tables: button_label: Arrange tables + by_row_no_row_count: 'Please fill in a positive number representing the number of ${models.plural.table|downcase} per row' + by_column_no_column_count: 'Please fill in a positive number representing the number of ${models.plural.table|downcase} per column' modal: title: Arrange tables body_header: "" diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 4389b065..49253e21 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -100,6 +100,11 @@ nl: password: 'Wachtwoord' password_confirmation: 'Bevestiging' supplier: + messages: + could_not_arrange_tables: 'De ${models.plural.table} konden niet worden gepositioneerd' + could_not_arrange_tables_distributed: 'De ${models.plural.table} konden niet worden gepositioneerd. Heeft de ${models.section|downcase} een hoogte en breedte?' + could_not_arrange_tables_by_row: 'De ${models.plural.table} konden niet worden gepositioneerd. Heeft de ${models.section|downcase} een hoogte en breedte?' + could_not_arrange_tables_by_column: 'De ${models.plural.table} konden niet worden gepositioneerd. Heeft de ${models.section|downcase} een hoogte en breedte?' menu: active_lists: Actieve %{lists} active_lists: @@ -120,9 +125,13 @@ nl: title: "%{list} tonen" section: first_section_title: Ruimte + show: + title: 'Toon ${models.section|downcase}' manage_tables: + link: 'Tafels beheren' title: "Tafels beheren voor ${models.section|downcase}: %{title}" - tables_view: Tafel overzicht + tables_view: + link: Tafel overzicht add_tables: button_label: Voeg tafels toe modal: @@ -134,6 +143,8 @@ nl: add_button: Voeg toe arrange_tables: button_label: Positioneer tafels + by_row_no_row_count: 'Geef een positief getal voor het aantal ${models.plural.table|downcase} per rij' + by_column_no_column_count: 'Geef een positief getal voor het aantal ${models.plural.table|downcase} per kolom' modal: title: Positioneer tafels body_header: "" diff --git a/lib/qwaiter.rb b/lib/qwaiter.rb new file mode 100644 index 00000000..dd167bbc --- /dev/null +++ b/lib/qwaiter.rb @@ -0,0 +1,4 @@ +module Qwaiter + extend ActiveSupport::Autoload + autoload :Distribution +end diff --git a/lib/qwaiter/distribution.rb b/lib/qwaiter/distribution.rb new file mode 100644 index 00000000..5502c217 --- /dev/null +++ b/lib/qwaiter/distribution.rb @@ -0,0 +1,47 @@ +module Qwaiter + module Distribution + module DistributionMethods + def epsilon + @@epsilon ||= (10 ** -(Float::DIG - 1)).to_f + end + + ## + # Distribute a section of width w and height h in a length and a width scale + # that makes n tables fit. + # distribute_lattice 10, 10, 3 #=> [5.0, 5.0] + # distribute_lattice 10, 10, 4 #=> [5.0, 5.0] + ## + def distribute_lattice(w, h, n) + w, h = w.to_f, h.to_f + area = w*h + l = Math.sqrt(area.to_f/n) + nx = w/l + ny = h/l + while (w/l + epsilon).floor * (h/l + epsilon).floor < n + tx = w/l + ty = h/l + # The biggest remainder is closest to a fitting option + # Just add one if no remainder wins and it still is not enough + if tx.remainder(1) < epsilon && ty.remainder(1) < epsilon + # Both divide, but there is no solution yet. Just add one + l = [w/(tx + 1).round, h/(ty + 1).round].max + nx = tx.ceil + ny = ny.ceil + elsif tx.remainder(1) > ty.remainder(1) + nx = tx.ceil + ny = (n.to_f/nx).ceil + l = w/nx + else + ny = ty.ceil + nx = (n.to_f/ny).ceil + l = h/ny + end + + end + [w/nx, h/ny] + end + end + include DistributionMethods + extend DistributionMethods + end +end