Skip to content

Commit

Permalink
Merge pull request #102 from it3s/disable_list_buttons
Browse files Browse the repository at this point in the history
Disable bulk action buttons if there is no selected item
  • Loading branch information
LuizArmesto committed Nov 29, 2014
2 parents 60f901a + eab4649 commit 59c184e
Show file tree
Hide file tree
Showing 15 changed files with 137 additions and 41 deletions.
46 changes: 42 additions & 4 deletions app/assets/javascripts/components/list.js.coffee
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
App.components.list = ->
attributes: ->
list: @container.find("ul.list")
scroll: @attr.scroll || {}
list: @container.find("ul.list")
itemSelector: ".list-item"
itemsChecked: '.list-item input[type=checkbox]:checked'
scroll: @attr.scroll || {}
count: @container.find('.selected-count')

infiniteScrollDefaults:
navSelector: @container.find("nav.pagination")
Expand All @@ -14,8 +17,18 @@ App.components.list = ->
initialize: ->
options = @handleOptions()
@startInfiniteScroll(options)
App.mediator.subscribe "listItem:remove", (evt, data) =>
@bindEvents()

bindEvents: ->
App.mediator.subscribe "list:selectAll", (evt, data) =>
@selectAll()

App.mediator.subscribe "list:unselectAll", (evt, data) =>
@unselectAll()

App.mediator.subscribe "list:remove", (evt, data) =>
@removeItemByInternalId(data.id)
@bindItemsEvents(@container)

handleOptions: ->
options = _.defaults(@attr.scroll, @attr.infiniteScrollDefaults)
Expand All @@ -29,9 +42,34 @@ App.components.list = ->
item = @getItemByInternalId id
item.remove()

selectAll: ->
@container.find("#{@attr.itemSelector} input[type=checkbox]").prop 'checked', true
@updateSelectCount()
App.mediator.publish "list:selectedAll", {count: $(@attr.itemsChecked).length}

unselectAll: ->
@container.find("#{@attr.itemSelector} input[type=checkbox]").prop 'checked', false
@updateSelectCount()
App.mediator.publish "list:unselectedAll"

startInfiniteScroll: (opts) ->
_this = this
@attr.list.infinitescroll opts, -> _this.startComponents.bind(_this)(this)
@attr.list.infinitescroll opts, ->
_this.bindItemsEvents.bind(_this)(this)
_this.startComponents.bind(_this)(this)

bindItemsEvents: (container) ->
_this = this
$(container).find("#{@attr.itemSelector} input[type=checkbox]").change ->
_this.updateSelectCount()
parent = $(this).parents("li:first")
isChecked = $(this).is(":checked")
App.mediator.publish "listItem:#{ ( if isChecked then "selected" else "unselected") }",
{el: parent, identifier: _this.identifier, listItemId: parent.data("listItem-id")}

startComponents: (container) ->
App.mediator.publish('components:start', $(container))

updateSelectCount: ->
count = $(@attr.itemsChecked).length
@attr.count.text if count > 0 then I18n.pluralize(I18n.lists.selected, count) else ""
28 changes: 28 additions & 0 deletions app/assets/javascripts/components/listActions.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
App.components.listActions = ->
attributes: ->
bulkButtons: @container.find('.bulkActions button')

initialize: ->
@count = 0
@updateBulkButtons()
@bindEvents()

bindEvents: ->
App.mediator.subscribe "listItem:selected", (evt, data) =>
@count++
@updateBulkButtons()

App.mediator.subscribe "listItem:unselected", (evt, data) =>
@count--
@updateBulkButtons()

App.mediator.subscribe "list:unselectedAll", (evt, data) =>
@count = 0
@updateBulkButtons()

App.mediator.subscribe "list:selectedAll", (evt, data) =>
@count = data.count
@updateBulkButtons()

updateBulkButtons: ->
@attr.bulkButtons.prop "disabled", (@count is 0)
3 changes: 2 additions & 1 deletion app/assets/javascripts/components/modal.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ App.components.modal = ->
if @attr.remote || @attr.autoload then @container else @referedElement()

referedElement: ->
$("#{ @container.attr('href') }")
# try "data-href" to allow another elements
$("#{ @container.attr('href') || @container.attr('data-href') }")

open: ->
if @shouldOpen()
Expand Down
2 changes: 1 addition & 1 deletion app/assets/javascripts/components/removeButton.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ App.components.removeButton = ->
dataType: "json"
data: @requestData()
success: (data) =>
App.mediator.publish "listItem:remove", _.extend(data, {id: @attr.id})
App.mediator.publish "list:remove", _.extend(data, {id: @attr.id})
false

requestData: ->
Expand Down
16 changes: 4 additions & 12 deletions app/assets/javascripts/components/selectAll.js.coffee
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
App.components.selectAll = ->
attributes: ->
checkbox: @container.find('input[type=checkbox]')
listItems: $('.list-item input[type=checkbox]')
itemsChecked: '.list-item input[type=checkbox]:checked'
count: $('.selected-count')

initialize: ->
@on 'click', @toggle
@on @attr.listItems, 'change', @updateSelectCount

App.mediator.subscribe "listItem:unselected", (evt, data) =>
@uncheck() if @checked()

toggle: ->
if @checked() then @uncheck() else @check()
@updateSelectCount()
App.mediator.publish "list:#{ if @checked() then "selectAll" else "unselectAll" }"

checked: ->
@attr.checkbox.is(':checked')
Expand All @@ -24,10 +23,3 @@ App.components.selectAll = ->

setCheck: (val) ->
@attr.checkbox.prop('checked', val)
@attr.listItems.prop('checked', val)

updateSelectCount: (evt, el) ->
count = $(@attr.itemsChecked).length
@attr.count.text if count > 0 then I18n.pluralize(I18n.lists.selected, count) else ""


8 changes: 8 additions & 0 deletions app/assets/stylesheets/core/_mixins.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@
background: $bg-hover;
color: $fg-hover;
}

&[disabled], &[disabled]:hover {
text-decoration: none;
background: $bg;
color: $fg;
opacity: 0.6;
cursor: default;
}
}

@mixin green-button {
Expand Down
5 changes: 5 additions & 0 deletions app/assets/stylesheets/shared/_lists.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ nav.pagination { display: none; } // We are using infinite scroll
margin-left: 0;
}

.upload-btn {
float: right;
margin-left: 3px;
}

.select-all-btn {
padding-top: 5px;
input[type=checkbox] { position: relative; top: 3px; }
Expand Down
8 changes: 8 additions & 0 deletions app/helpers/concerns/components_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ def link_to_tooltip(body, selector)
"<a href=\"#{selector}\" data-components=\"tooltip\" data-tooltip-options='#{ {template: selector}.to_json }'>#{body}</a>".html_safe
end

def button_to_modal(body, url, options={})
html_attrs = hash_to_attributes(options[:html]) if options[:html]
modal_attrs = options.except(:html).to_json
components = ["modal"] + (options[:login_required] ? ["loginRequired"] : [])

"<button data-href=\"#{url}\" #{html_attrs} data-components=\"#{ components.join(' ') }\" data-modal-options='#{ modal_attrs }'>#{body}</button>".html_safe
end

def remote_form_for(record, options={}, &block)
options.deep_merge!(:remote => true, :html => {'data-components' => 'remoteForm', 'multipart' => true})
simple_form_for(record, options, &block)
Expand Down
13 changes: 6 additions & 7 deletions app/views/geo_data/_list_actions.html.erb
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
<div class="list-actions" data-components="stick" data-stick-options='{ "get_width_from": ".site-page" }'>
<div class="list-actions" data-components="stick listActions" data-stick-options='{ "get_width_from": ".site-page" }'>
<button class="select-all-btn" data-components='selectAll'>
<input type="checkbox" name="all" /><%= t 'lists.select_all' %>
</button>

<%= link_to_modal icon("globe", t("geo_data.add_map.title")), "#bulk-add-to-map-modal",
login_required: true, html: {class: "add-to-map", id: "bulk-add-to-map"} %>
<span class="bulkActions">
<%= button_to_modal icon("globe", t("geo_data.add_map.title")), "#bulk-add-to-map-modal",
login_required: true, html: {class: "add-to-map", id: "bulk-add-to-map"} %>
<%= render 'shared/export/export_object', object: nil %>
</span>
<%= render "geo_data/bulk_add_map_modal" %>
<%= render 'imports/modal' %>
<%= render 'shared/export/export_object', object: nil %>
<%= link_to icon('map-marker', t('geo_data.list.add_new')), new_geo_data_path, class: 'add-new-btn' , "data-components" => "loginRequired" %>
</div>
2 changes: 1 addition & 1 deletion app/views/imports/_modal.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= link_to_modal icon('upload'), '#import-modal', login_required: true, html: {class: 'upload-btn', title: 'Upload content in batch'} %>
<%= button_to_modal icon('upload'), '#import-modal', login_required: true, html: {class: 'upload-btn', title: t('import.button.title')} %>

<div id="import-modal" class="import-modal" >
<header><h2><%= t 'import.title' %></h2></header>
Expand Down
8 changes: 5 additions & 3 deletions app/views/maps/_list_actions.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<div class="list-actions" data-components="stick" data-stick-options='{ "get_width_from": ".site-page" }'>
<div class="list-actions" data-components="stick listActions" data-stick-options='{ "get_width_from": ".site-page" }'>
<button class="select-all-btn" data-components='selectAll'>
<input type="checkbox" name="all" /><%= t 'lists.select_all' %>
</button>

<%= render 'imports/modal' %>
<%= render 'shared/export/export_object', object: nil %>
<span class="bulkActions">
<%= render 'shared/export/export_object', object: nil %>
</span>

<%= render 'imports/modal' %>
<%= link_to icon('globe', t('maps.list.add_new')), new_map_path, class: 'add-new-btn' , "data-components" => "loginRequired" %>
</div>
2 changes: 1 addition & 1 deletion app/views/shared/export/_export_object.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= link_to_modal icon("download"), "#export-object", html: {class: "download", title: t('export.link_title')} %>
<%= button_to_modal icon("download"), "#export-object", html: {class: "download", title: t('export.link_title')} %>

<div id="export-object" class="export-modal modal" data-components="exporter">
<header><h2><%= t 'export.download' %></h2></header>
Expand Down
5 changes: 3 additions & 2 deletions config/locales/en/import.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ en:

warn_notice: '<b>Warning</b>: On the CSV use a semicolon (<b>;</b>) as separator. Also use quotes (<b>"</b>) to enclose values.'

button:
title: "Upload content in batch"

example_value:
'name': "content name"
'description': "content description"
Expand Down Expand Up @@ -43,5 +46,3 @@ en:
empty: 'There are no importations for %{name}'
imported: 'Already imported'
not_imported: 'Not imported yet'


12 changes: 3 additions & 9 deletions config/locales/pt-BR/import.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pt-BR:

warn_notice: '<b>Aviso</b>: No CSV use ponto-e-vírgula (<b>;</b>) como separador. Também use aspas (<b>"</b>) para incluir valores.'

button:
title: "Enviar conteúdo em lote"

example_value:
'name': "nome do conteúdo name"
'description': "descrição do conteúdo"
Expand Down Expand Up @@ -43,12 +46,3 @@ pt-BR:
empty: 'Não há importações para %{name}'
imported: 'Já foi importado'
not_imported: 'Não importado ainda'









20 changes: 20 additions & 0 deletions spec/helpers/application_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,26 @@
end
end

describe "#button_to_modal" do
context "regular modal" do
let(:anchor) { '<button data-href="#some-id" class="button" data-components="modal" data-modal-options=\'{}\'>Open Modal</button>' }
it "renders modal component" do
expect(helper.button_to_modal 'Open Modal', '#some-id', :html => { :class => 'button'} ).to eq anchor
end
end

context "remote modal" do
let(:link) { helper.link_to_modal 'Open Modal', '#some-id', :remote => true }
it { expect(link).to include 'data-modal-options=\'{"remote":true}\'' }
end

context "autoload and prevent_close" do
let(:link) { helper.link_to_modal 'Open Modal', '#some-id', :autoload => true, :prevent_close => true }
it { expect(link).to include 'data-modal-options=\'{"autoload":true,"prevent_close":true}\'' }
end

end

describe "#remote_form_for" do
let(:user) { FactoryGirl.build(:user) }

Expand Down

0 comments on commit 59c184e

Please sign in to comment.