Client side table management for supplier sections

This commit is contained in:
2015-08-14 19:02:39 +02:00
parent 9ca5190c6a
commit 5d02f5d37b
13 changed files with 191 additions and 39 deletions
@@ -1,7 +1,13 @@
App.modals.SectionAddTablesController = App.modals.BaseController.extend App.modals.SectionAddTablesController = App.modals.BaseController.extend
number_start: 100 number_start: 100
number_end: 107 number_end: 100
title_path: 'section.add_tables.modal.title' title_path: 'section.add_tables.modal.title'
#number_start: Ember.computed
#get: ->
#@_super() || 100
#set: (key, value)->
#@set 'number_end', value if value
#@_super()
actions: actions:
addTables: -> addTables: ->
s = parseInt(@get('number_start')) s = parseInt(@get('number_start'))
@@ -15,11 +21,14 @@ App.modals.SectionAddTablesController = App.modals.BaseController.extend
e = @get('number_end') e = @get('number_end')
number_of_tables = 1 + e - s number_of_tables = 1 + e - s
return @set('alert_message', t('section.add_tables.modal.too_many', count: number_of_tables)) if number_of_tables > 10 return @set('alert_message', t('section.add_tables.modal.too_many', count: number_of_tables)) if number_of_tables > 10
for number in [s..e]
@store.createRecord 'table', number: number, section: @get('model')
Ember.$.post Routes.add_tables_suppliers_section_path(@get('model.id')), @send 'close'
number_start: s #Ember.$.post Routes.add_tables_suppliers_section_path(@get('model.id')),
number_end: e #number_start: s
, (result,state,xhr)=> #number_end: e
#@store.pushPayload 'table', result #, (result,state,xhr)=>
@store.pushPayload result ## @store.pushPayload 'table', result
@send 'close' #@store.pushPayload result
#@send 'close'
@@ -20,14 +20,23 @@ App.modals.SectionArrangeTablesController = App.modals.BaseController.extend
actions: actions:
arrangeTables: -> arrangeTables: ->
return unless @isValid() return unless @isValid()
Ember.$.post Routes.arrange_tables_suppliers_section_path(@get('model.id')), #Ember.$.post Routes.arrange_tables_suppliers_section_path(@get('model.id')),
option: @get('arrange_type') #option: @get('arrange_type')
row_count: @get('row_count') #row_count: @get('row_count')
column_count: @get('column_count') #column_count: @get('column_count')
, (result,state,xhr)=> #, (result,state,xhr)=>
@store.pushPayload result #@store.pushPayload result
@send 'close' #@send 'close'
return #return
switch @get('arrange_type')
when 'by_row'
@get('model').invoke 'arrange_tables_in_rows_of', parseInt(@get('row_count'))
when 'by_column'
@get('model').invoke 'arrange_tables_in_columns_of', parseInt(@get('column_count'))
else
@get('model').invoke 'arrange_tables_in_grid'
@send 'close'
makeDistributed: -> makeDistributed: ->
@set 'arrange_type', 'distributed' @set 'arrange_type', 'distributed'
@set 'alert_message', '' @set 'alert_message', ''
@@ -6,10 +6,16 @@ App.SectionController = Ember.Controller.extend
finishEditable: -> finishEditable: ->
@set('editmode', false) @set('editmode', false)
@get('model').save() @get('model').save()
@get('model.tables').filterProperty('hasDirtyAttributes').invoke 'save'
@get('model.section_elements').filterProperty('hasDirtyAttributes').invoke 'save' @get('model.section_elements').filterProperty('hasDirtyAttributes').invoke 'save'
@get('model.section_areas').filterProperty('hasDirtyAttributes').invoke 'save' @get('model.section_areas').filterProperty('hasDirtyAttributes').invoke 'save'
rollbackEditable: -> rollbackEditable: ->
@get('model').rollback() @get('model').rollback()
@get('model.tables').forEach (table) ->
if table.get('isNew')
table.deleteRecord()
else
table.rollback()
@get('model.section_elements').forEach (section_element) -> @get('model.section_elements').forEach (section_element) ->
if section_element.get('isNew') if section_element.get('isNew')
section_element.deleteRecord() section_element.deleteRecord()
@@ -0,0 +1,36 @@
class Distribution
##
# 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]
##
distribute_lattice: (w, h, n)->
epsilon = 1e-10
w = parseFloat(w)
h = parseFloat(h)
n = parseInt(n)
area = w*h
l = Math.sqrt(area/n)
nx = w/l
ny = h/l
while Math.floor(w/l + epsilon) * Math.floor(h/l + epsilon) < 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 % 1) < epsilon and (ty % 1) < epsilon
# Both divide, but there is no solution yet. Just add one
l = Math.max(Math.round(w/(tx + 1)), Math.round(h/(ty + 1)))
nx = Math.ceil(tx)
ny = Math.ceil(ny)
else if (tx % 1) > (ty % 1)
nx = Math.ceil(tx)
ny = Math.ceil(n/nx)
l = w/nx
else
ny = Math.ceil(ty)
nx = Math.ceil(n/ny)
l = h/ny
[w/nx, h/ny]
App.Distribution = new Distribution()
@@ -6,3 +6,61 @@ App.Section = DS.Model.extend
tables: DS.hasMany('table') tables: DS.hasMany('table')
section_elements: DS.hasMany('section-element') section_elements: DS.hasMany('section-element')
section_areas: DS.hasMany('section-area') section_areas: DS.hasMany('section-area')
arrange_tables_in_grid: (tables)->
epsilon = 1e-10
tables ||= @get('tables').sortBy('number')
w = parseFloat(@get('width'))
h = parseFloat(@get('height'))
n = parseInt(tables.get('length'))
unless w > 0 and h > 0 and n > 0
console.log "Cannot arrange tables in grid since not all conditions are met"
return false
[lx, ly] = App.Distribution.distribute_lattice(w, h, n)
return unless lx > 0 and ly > 0
console.log "Distributing tables in grid using lx: #{lx}, ly: #{ly}"
x0 = lx/2
x = x0
y = ly/2
tables.forEach (table)->
if x > w + (1e4*epsilon) # New row, error = epsilon times possible tables in a row
x = x0
y += ly
table.set 'position_x', x - table.get('width')/2 # Starting point of square + half the square (center) minus half the table size
table.set 'position_y', y - table.get('height')/2
x += lx
arrange_tables_in_rows_of: (n, tables)->
return false unless n
n = parseInt(n)
return false unless n > 0
tables ||= @get('tables').sortBy('number')
width = parseFloat(@get('width'))
height = parseFloat(@get('height'))
dx = width / n
dy = height / Math.ceil(tables.get('length')/n)
x = 0.0
y = 0.0
tables.forEach (table, i)->
table.set 'position_x', x + (dx/2) - (table.get('width')/2)
table.set 'position_y', y + (dy/2) - (table.get('height')/2)
x += dx
if (i + 1) % n is 0
x = 0.0
y += dy
arrange_tables_in_columns_of: (n, tables)->
return false unless n
n = parseInt(n)
return false unless n > 0
tables ||= @get('tables').sortBy('number')
width = parseFloat(@get('width'))
height = parseFloat(@get('height'))
dx = width / Math.ceil(tables.get('length') / n)
dy = height / n
x = 0.0
y = 0.0
tables.forEach (table, i)->
table.set 'position_x', x + (dx/2) - (table.get('width')/2)
table.set 'position_y', y + (dy/2) - (table.get('height')/2)
y += dy
if (i + 1) % n is 0
y = 0.0
x += dx
@@ -5,12 +5,12 @@ form.form-horizontal
.form-label .form-label
label for='add-tables-number-start' label for='add-tables-number-start'
=t 'section.add_tables.modal.number_start' =t 'section.add_tables.modal.number_start'
.form-field= number-field numericValue=number_start .form-field= number-field value=number_start
.form-row .form-row
.form-label .form-label
label for='add-tables-number-end' label for='add-tables-number-end'
=t 'section.add_tables.modal.number_end' =t 'section.add_tables.modal.number_end'
.form-field= number-field numericValue=number_end .form-field= number-field value=number_end
hr hr
button.modal-close{action "close"}=t 'section.add_tables.modal.close_button' button.modal-close{action "close"}=t 'section.add_tables.modal.close_button'
button.modal-confirm.right{action "ok"}=t 'section.add_tables.modal.add_button' button.modal-confirm.right{action "addTables"}=t 'section.add_tables.modal.add_button'
@@ -12,9 +12,6 @@
= number-field numericValue=model.width class="dimension section-edit-width-field" = number-field numericValue=model.width class="dimension section-edit-width-field"
span.fa.fa-lg.fa-times span.fa.fa-lg.fa-times
= number-field numericValue=model.height class="dimension section-edit-height-field" = number-field numericValue=model.height class="dimension section-edit-height-field"
a.section-rollback-button{ action "rollbackEditable" }: span
a.section-normal-mode-button{ action "finishEditable" }: span
else
= dropdown-link title="Action" = dropdown-link title="Action"
ul ul
li: a{action "addTables"}: span.section-add-tables-icon=t 'section.add_tables.button_label' li: a{action "addTables"}: span.section-add-tables-icon=t 'section.add_tables.button_label'
@@ -23,5 +20,11 @@
li: a{action "addSectionArea"}: span.section-add-section-area-icon= t 'section_area.add_button' li: a{action "addSectionArea"}: span.section-add-section-area-icon= t 'section_area.add_button'
li= qr-codes-link section=content: span.qr-icon= t 'table.print_qr_codes' li= qr-codes-link section=content: span.qr-icon= t 'table.print_qr_codes'
li: a.section-destroy{action "destroySection"}: span.section-remove-icon=t 'helpers.links.destroy' li: a.section-destroy{action "destroySection"}: span.section-remove-icon=t 'helpers.links.destroy'
a.section-rollback-button{ action "rollbackEditable" }: span
a.section-normal-mode-button{ action "finishEditable" }: span
else
= dropdown-link title="Action"
ul
li= qr-codes-link section=content: span.qr-icon= t 'table.print_qr_codes'
a.section-edit-mode-button{ action "makeEditable" }: span a.section-edit-mode-button{ action "makeEditable" }: span
= view "section-tables" content=model.tables = view "section-tables" content=model.tables
@@ -40,7 +40,7 @@ App.SectionTableView = Ember.View.extend DragNDrop.Draggable,
@get('content').setProperties @get('content').setProperties
position_x: position.left / dpm position_x: position.left / dpm
position_y: position.top / dpm position_y: position.top / dpm
@get('content').save() #@get('content').save()
dpm: Ember.computed.alias 'tablesContext.dpm' dpm: Ember.computed.alias 'tablesContext.dpm'
didInsertElement: -> didInsertElement: ->
@$el = @$() @$el = @$()
@@ -1,8 +1,10 @@
#module "suppliers-switcher", "SuppliersSwitcherComponent" #module "suppliers-switcher", "SuppliersSwitcherComponent"
moduleForComponent "suppliers-switcher" moduleForComponent "suppliers-switcher"
test "Triggers switch", -> test "Triggers switch", ->
expect 2
component = @subject() component = @subject()
controller = App.__container__.lookup('controller:settings') controller = App.__container__.lookup('controller:settings')
component.set 'targetObject', controller
Ember.run -> Ember.run ->
controller.store.createRecord 'supplier', controller.store.createRecord 'supplier',
id: 'other-supplier' id: 'other-supplier'
@@ -11,11 +13,8 @@ test "Triggers switch", ->
@render() @render()
equal find('ul').text(), "Switch to Other supplier1" equal find('ul').text(), "Switch to Other supplier1"
s_name = null
# Stub the action, since it triggers an external call # Stub the action, since it triggers an external call
component._actions.switchTo = (supplier)-> component._actions.switchTo = (supplier)->
s_name = supplier.get('name') equal supplier.get('name'), 'Other supplier1'
click 'li a' click 'li a'
equal s_name, 'Other supplier1'
@@ -0,0 +1,22 @@
moduleForModel 'section', 'Section model',
needs: ['model:section', 'model:table', 'model:section-area', 'model:section-element', 'model:list']
test "arrange_tables_in_grid", ->
section = @subject
width: 20
height: 13
Ember.run ->
table6 = section.store.createRecord 'table', number: 6, section: section
table1 = section.store.createRecord 'table', number: 1, section: section
table19 = section.store.createRecord 'table', number: 19, section: section
section.invoke 'arrange_tables_in_grid'
equal table1.get('position_y'), 2.85
equal table6.get('position_y'), 2.85
equal table19.get('position_y'), 9.35
equal table1.get('position_x'), 4.6
equal table6.get('position_x'), 14.6
equal table19.get('position_x'), 4.6
@@ -0,0 +1,16 @@
test "distribute_lattice", ->
expect 10
test_matrix = [
{input: [20 , 10, 4], expected_output: [10.0, 5.0]},
{input: [10 , 10, 4], expected_output: [ 5.0, 5.0]},
{input: [20 , 5, 4], expected_output: [ 5.0, 5.0]},
{input: [30 , 10, 4], expected_output: [ 7.5, 10.0]},
{input: [10 , 30, 4], expected_output: [10.0, 7.5]},
{input: [10 , 10, 3], expected_output: [ 5.0, 5.0]},
{input: [13.6, 40, 7], expected_output: [ 6.8, 10.0]},
{input: [13.6, 40, 9], expected_output: [ 6.8, 8.0]},
{input: [13.6, 40, 10], expected_output: [ 6.8, 8.0]},
{input: [40, 40, 23], expected_output: [ 8.0, 8.0]},
]
for expectation in test_matrix
deepEqual App.Distribution.distribute_lattice.apply(this, expectation.input), expectation.expected_output
+5 -4
View File
@@ -1,4 +1,5 @@
module 'Router', setup: -> App.reset() #module 'Router', setup: -> App.reset()
test 'root route', -> #test 'root route', ->
visit '/' #visit '/'
andThen -> equal currentRouteName(), 'index' #andThen ->
#equal currentRouteName(), 'index'
+1 -8
View File
@@ -4,8 +4,6 @@ Release
Supplier Supplier
-------- --------
- Add confirmation on order
deletion!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- Allow table drag rollback same as area and element in section edit - Allow table drag rollback same as area and element in section edit
mode view mode view
- Move arrange tables logic to the client - Move arrange tables logic to the client
@@ -26,13 +24,8 @@ Supplier
User User
---- ----
- Fix clicking on product with
variants!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- Implement https://github.com/EddyVerbruggen/Custom-URL-scheme with mozo:// scheme - Implement https://github.com/EddyVerbruggen/Custom-URL-scheme with mozo:// scheme
- test met veel producten - test met veel producten
- product variants
- option to make products inactive, no order plus and click on name
opens information
- remove active orders on list close - remove active orders on list close
- fix ajaxError duplicity - fix ajaxError duplicity
- rename "I am signed in as a user" to "there is a signed in user" in - rename "I am signed in as a user" to "there is a signed in user" in
@@ -51,7 +44,7 @@ General
------- -------
- Loading pages - Loading pages
- Product variants - Food/allergy information/labels
- Timed delivering - Timed delivering
- minimum delay - minimum delay
- What products - What products