diff --git a/.gitignore b/.gitignore index 49b2a2210e8..432698c4bfe 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,16 @@ public .rspec .rails-version .rbenv-version +*.rbc +*.sassc +.sass-cache +/vendor/bundle +/log/* +/tmp/* +/db/*.sqlite3 +/public/system/* +/coverage/ +/spec/tmp/* +**.orig +rerun.txt +pickle-email-*.html diff --git a/.travis.yml b/.travis.yml index 4b2080a1e37..6edc2c533a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,11 @@ script: bundle exec rake rvm: - ree - 1.9.2 + - 1.9.3 before_install: - gem update --system - gem --version +env: + - RAILS=3.0.12 + - RAILS=3.1.4 + - RAILS=3.2.3 diff --git a/CHANGELOG.md b/CHANGELOG.md index c24972f639c..191cb058e4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ * Created new view components (Footer, TitleBar, Header, UtilityNav) to more easily customize the views in Active Admin and per namespace. (@gregbell) +* All CSS is now encapsulated under the `body.active_admin` class. This may + change the precedence of styles that you created to override or use in + other areas of your application. ### Deprecations @@ -15,6 +18,13 @@ creating custom menu items, the builder syntax has changed to. Menu#add now accepts a MenuItem, instead of building the menu item for you. +## 0.4.4 + +### Dependencies + +* Use `formtastic` ~> 2.1.1 until AA 0.5.0 is released +* Use `inherited_resources` >= 1.3.1 (ensure flash messages work) + ## 0.4.3 ### Bug Fixes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 552d4b33fbe..d4917487c8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,10 +10,8 @@ The first step to contributing to Active Admin is creating a ticket in our The community has been hard at work already, so please take a second to search for the issue or feature before creating a new one. -All features or bug fixes should have a ticket. This makes it easy for everyone -to discuss the code and know if a fix is already in progress for an issue. If -it's a feature, the team can prioritize what it should work on based on these -tickets. +All bug fixes should have a ticket. This makes it easy for everyone +to discuss the code and know if a fix is already in progress for an issue. ### 2. Fork & Create a Feature Branch diff --git a/Gemfile b/Gemfile index 92315d0c15b..70122322ebc 100644 --- a/Gemfile +++ b/Gemfile @@ -26,13 +26,12 @@ group :development, :test do gem 'haml', '~> 3.1.1', :require => false gem 'yard' gem 'rdiscount' # For yard - gem "guard-sprockets" + gem "sprockets" gem 'rails-i18n' # Gives us default i18n for many languages end group :test do - gem 'rspec-rails', '~> 2.8.1' - gem 'cucumber', '1.1.4' + gem 'rspec-rails', '~> 2.9.0' gem 'cucumber-rails', '1.2.1', :require => false gem 'capybara', '1.1.2' gem 'database_cleaner' diff --git a/Guardfile b/Guardfile index 67ec7a0cbe8..882515b251f 100644 --- a/Guardfile +++ b/Guardfile @@ -5,11 +5,3 @@ guard 'rspec', :all_on_start => false, :version => 2 do watch(%r{^lib/active_admin/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { "spec/" } end - -guard 'coffeescript', :output => 'spec/javascripts/compiled', :all_on_start => true do - watch(%r{spec/javascripts/coffeescripts/(.*)\.coffee}) -end - -guard 'sprockets', :destination => "app/assets/javascripts/active_admin/", :asset_paths => ['app/assets/javascripts/active_admin/coffeescripts/'] do - watch(%r{^app/assets/javascripts/active_admin/coffeescripts/.+$}) -end diff --git a/README.rdoc b/README.rdoc index 57f17455ead..7a923f1a9cc 100644 --- a/README.rdoc +++ b/README.rdoc @@ -4,22 +4,17 @@ Active Admin is a framework for creating administration style interfaces. It abstracts common business application patterns to make it simple for developers to implement beautiful and elegant interfaces with very little effort. -{}[http://travis-ci.org/gregbell/active_admin] +{}[http://travis-ci.org/gregbell/active_admin] == Documentation & Support * Documentation & Guides: http://activeadmin.info/documentation.html * Wiki: https://github.com/gregbell/active_admin/wiki -* RDoc: http://rubydoc.info/github/gregbell/active_admin/master/frames +* RDoc: http://rubydoc.info/gems/activeadmin/frames * Live demo: http://demo.activeadmin.info/admin * Website: http://www.activeadmin.info * Need Support? Ask the Mailing list: http://groups.google.com/group/activeadmin -== Bugs & Feature Requests - -* Bug Reports & Feature Requests: https://github.com/gregbell/active_admin/issues -* Want to Contribute? Read the Guide: https://github.com/gregbell/active_admin/blob/master/CONTRIBUTING.md - == Goals 1. Allow developers to quickly create gorgeous administration interfaces @@ -28,6 +23,22 @@ to implement beautiful and elegant interfaces with very little effort. 3. Ensure that developers can easily customize every nook and cranny of the interface. 4. Build common interfaces as shareable gems so that the entire community benefits. +== Bugs Reports & Contributing + +* Bug Reports: https://github.com/gregbell/active_admin/issues +* Want to Contribute? Read the Guide: https://github.com/gregbell/active_admin/blob/master/CONTRIBUTING.md + +== Feature Requests + +Please don't put feature requests in Github Issues. They will be closed as soon as they +are reviewed by one of the core team members. If you would like a feature in Active Admin, +please submit a well tested pull request with the desired changes. If you're not a coder, +then the mailing list may be a good place to try to convince someone to help you out +with your cause. + +If you are going to submit a pull request, please read the contributing guide: +https://github.com/gregbell/active_admin/blob/master/CONTRIBUTING.md + == Getting Started diff --git a/activeadmin.gemspec b/activeadmin.gemspec index a2586a6793a..6f6272a179d 100644 --- a/activeadmin.gemspec +++ b/activeadmin.gemspec @@ -23,7 +23,7 @@ Gem::Specification.new do |s| s.add_dependency("meta_search", ">= 0.9.2") s.add_dependency("devise", ">= 1.1.2") s.add_dependency("formtastic", "~> 2.1.1") - s.add_dependency("inherited_resources", "<= 1.3.0") + s.add_dependency("inherited_resources", ">= 1.3.1") s.add_dependency("kaminari", ">= 0.13.0") s.add_dependency("sass", ">= 3.1.0") s.add_dependency("fastercsv", ">= 0") diff --git a/app/assets/javascripts/active_admin/application.js b/app/assets/javascripts/active_admin/application.js index 7e882f7c5f7..7860adf1cc2 100644 --- a/app/assets/javascripts/active_admin/application.js +++ b/app/assets/javascripts/active_admin/application.js @@ -1,292 +1,3 @@ -(function() { - - window.AA = {}; - -}).call(this); -(function() { - - window.AA.CheckboxToggler = AA.CheckboxToggler = (function() { - - function CheckboxToggler(options, container) { - var defaults; - this.options = options; - this.container = container; - defaults = {}; - this.options = $.extend({}, defaults, options); - this._init(); - this._bind(); - } - - CheckboxToggler.prototype._init = function() { - if (!this.container) { - throw new Error("Container element not found"); - } else { - this.$container = $(this.container); - } - if (!this.$container.find(".toggle_all").length) { - throw new Error("'toggle all' checkbox not found"); - } else { - this.toggle_all_checkbox = this.$container.find(".toggle_all"); - } - return this.checkboxes = this.$container.find(":checkbox").not(this.toggle_all_checkbox); - }; - - CheckboxToggler.prototype._bind = function() { - var _this = this; - this.checkboxes.bind("change", function(e) { - return _this._didChangeCheckbox(e.target); - }); - return this.toggle_all_checkbox.bind("change", function(e) { - return _this._didChangeToggleAllCheckbox(); - }); - }; - - CheckboxToggler.prototype._didChangeCheckbox = function(checkbox) { - if (this.checkboxes.filter(":checked").length === this.checkboxes.length - 1) { - return this._uncheckToggleAllCheckbox(); - } else if (this.checkboxes.filter(":checked").length === this.checkboxes.length) { - return this._checkToggleAllCheckbox(); - } - }; - - CheckboxToggler.prototype._didChangeToggleAllCheckbox = function() { - if (this.toggle_all_checkbox.attr("checked") === "checked") { - return this._checkAllCheckboxes(); - } else { - return this._uncheckAllCheckboxes(); - } - }; - - CheckboxToggler.prototype._uncheckToggleAllCheckbox = function() { - return this.toggle_all_checkbox.removeAttr("checked"); - }; - - CheckboxToggler.prototype._checkToggleAllCheckbox = function() { - return this.toggle_all_checkbox.attr("checked", "checked"); - }; - - CheckboxToggler.prototype._uncheckAllCheckboxes = function() { - var _this = this; - return this.checkboxes.each(function(index, el) { - $(el).removeAttr("checked"); - return _this._didChangeCheckbox(el); - }); - }; - - CheckboxToggler.prototype._checkAllCheckboxes = function() { - var _this = this; - return this.checkboxes.each(function(index, el) { - $(el).attr("checked", "checked"); - return _this._didChangeCheckbox(el); - }); - }; - - return CheckboxToggler; - - })(); - - (function($) { - return $.widget.bridge('checkboxToggler', AA.CheckboxToggler); - })(jQuery); - -}).call(this); -(function() { - - window.AA.Popover = AA.Popover = (function() { - - function Popover(options, element) { - var defaults; - this.options = options; - this.element = element; - this.$element = $(this.element); - defaults = { - fadeInDuration: 20, - fadeOutDuration: 100, - autoOpen: true, - pageWrapperElement: "#wrapper", - onClickActionItemCallback: null - }; - this.options = $.extend({}, defaults, options); - this.$popover = null; - this.isOpen = false; - if ($(this.$element.attr("href")).length > 0) { - this.$popover = $(this.$element.attr("href")); - } - this._buildPopover(); - this._bind(); - return this; - } - - Popover.prototype.open = function() { - this.isOpen = true; - this.$popover.fadeIn(this.options.fadeInDuration); - this._positionPopover(); - this._positionNipple(); - return this; - }; - - Popover.prototype.close = function() { - this.isOpen = false; - this.$popover.fadeOut(this.options.fadeOutDuration); - return this; - }; - - Popover.prototype.destroy = function() { - this.$element.removeData('popover'); - this.$element.unbind(); - this.$element = null; - return this; - }; - - Popover.prototype.option = function() {}; - - Popover.prototype._buildPopover = function() { - this.$popover.prepend("
"); - this.$popover.hide(); - return this.$popover.addClass("popover"); - }; - - Popover.prototype._bind = function() { - var _this = this; - $(this.options.pageWrapperElement).bind('click', function(e) { - if (_this.isOpen === true) return _this.close(); - }); - if (this.options.autoOpen === true) { - return this.$element.bind('click', function() { - _this.open(); - return false; - }); - } - }; - - Popover.prototype._positionPopover = function() { - var centerOfButtonFromLeft, centerOfPopoverFromLeft, popoverLeftPos; - centerOfButtonFromLeft = this.$element.offset().left + this.$element.outerWidth() / 2; - centerOfPopoverFromLeft = this.$popover.outerWidth() / 2; - popoverLeftPos = centerOfButtonFromLeft - centerOfPopoverFromLeft; - return this.$popover.css("left", popoverLeftPos); - }; - - Popover.prototype._positionNipple = function() { - var $nipple, bottomOfButtonFromTop, centerOfPopoverFromLeft, centerOfnippleFromLeft, nippleLeftPos; - centerOfPopoverFromLeft = this.$popover.outerWidth() / 2; - bottomOfButtonFromTop = this.$element.offset().top + this.$element.outerHeight() + 10; - this.$popover.css("top", bottomOfButtonFromTop); - $nipple = this.$popover.find(".popover_nipple"); - centerOfnippleFromLeft = $nipple.outerWidth() / 2; - nippleLeftPos = centerOfPopoverFromLeft - centerOfnippleFromLeft; - return $nipple.css("left", nippleLeftPos); - }; - - return Popover; - - })(); - - (function($) { - return $.widget.bridge('popover', AA.Popover); - })(jQuery); - -}).call(this); -(function() { - var __hasProp = Object.prototype.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }; - - window.AA.TableCheckboxToggler = AA.TableCheckboxToggler = (function(_super) { - - __extends(TableCheckboxToggler, _super); - - function TableCheckboxToggler() { - TableCheckboxToggler.__super__.constructor.apply(this, arguments); - } - - TableCheckboxToggler.prototype._init = function() { - return TableCheckboxToggler.__super__._init.apply(this, arguments); - }; - - TableCheckboxToggler.prototype._bind = function() { - var _this = this; - TableCheckboxToggler.__super__._bind.apply(this, arguments); - return this.$container.find("tbody").find("td").bind("click", function(e) { - if (e.target.type !== 'checkbox') return _this._didClickCell(e.target); - }); - }; - - TableCheckboxToggler.prototype._didChangeCheckbox = function(checkbox) { - var $row; - TableCheckboxToggler.__super__._didChangeCheckbox.apply(this, arguments); - $row = $(checkbox).parents("tr"); - if (checkbox.checked) { - return $row.addClass("selected"); - } else { - return $row.removeClass("selected"); - } - }; - - TableCheckboxToggler.prototype._didClickCell = function(cell) { - return $(cell).parent("tr").find(':checkbox').click(); - }; - - return TableCheckboxToggler; - - })(AA.CheckboxToggler); - - (function($) { - return $.widget.bridge('tableCheckboxToggler', AA.TableCheckboxToggler); - })(jQuery); - -}).call(this); -(function() { - - $(function() { - $(".datepicker").datepicker({ - dateFormat: "yy-mm-dd" - }); - return $(".clear_filters_btn").click(function() { - window.location.search = ""; - return false; - }); - }); - -}).call(this); -(function() { - - jQuery(function($) { - $("#batch_actions_button").popover({ - autoOpen: false - }); - $(document).delegate("#batch_actions_popover li a", "click.rails", function() { - $("#batch_action").val($(this).attr("data-action")); - return $("#collection_selection").submit(); - }); - $("#batch_actions_button").click(function() { - if (!$(this).hasClass("disabled")) { - if ($("#batch_actions_popover").is(":hidden")) { - $(this).popover("open"); - return false; - } else { - $(this).popover("close"); - return false; - } - } - }); - if ($("#batch_actions_button").length && $(":checkbox.toggle_all").length) { - if ($(".paginated_collection").find("table").length) { - $(".paginated_collection table").tableCheckboxToggler(); - } else { - $(".paginated_collection").checkboxToggler(); - } - return $(".paginated_collection").find(":checkbox").bind("change", function() { - if ($(".paginated_collection").find(":checkbox").filter(":checked").length > 0) { - return $("#batch_actions_button").removeClass("disabled"); - } else { - return $("#batch_actions_button").addClass("disabled"); - } - }); - } - }); - -}).call(this); - - - - +//= require_tree ./lib/ +//= require_tree ./components/ +//= require_tree ./pages/ diff --git a/app/assets/javascripts/active_admin/base.js b/app/assets/javascripts/active_admin/base.js index 0dea74c80d3..f88ab6c237f 100644 --- a/app/assets/javascripts/active_admin/base.js +++ b/app/assets/javascripts/active_admin/base.js @@ -1,5 +1,5 @@ //= require jquery //= require jquery-ui //= require jquery_ujs -//= require active_admin/application +//= require active_admin/application diff --git a/app/assets/javascripts/active_admin/coffeescripts/application.js b/app/assets/javascripts/active_admin/coffeescripts/application.js deleted file mode 100644 index 2a9112b2251..00000000000 --- a/app/assets/javascripts/active_admin/coffeescripts/application.js +++ /dev/null @@ -1,4 +0,0 @@ -//= require_tree ./lib/ -//= require_tree ./components/ -//= require_tree ./pages/ -//= require_directory ./ diff --git a/app/assets/javascripts/active_admin/coffeescripts/pages/batch_actions.js.coffee b/app/assets/javascripts/active_admin/coffeescripts/pages/batch_actions.js.coffee deleted file mode 100644 index b533bb59342..00000000000 --- a/app/assets/javascripts/active_admin/coffeescripts/pages/batch_actions.js.coffee +++ /dev/null @@ -1,45 +0,0 @@ -jQuery ($) -> - - # - # Init batch action popover - # - - $("#batch_actions_button").popover autoOpen: false - - # - # Use Rails.js click handler to allow for Rails' confirm dialogs - # - - $(document).delegate "#batch_actions_popover li a", "click.rails", -> - $("#batch_action").val $(this).attr("data-action") - $("#collection_selection").submit() - - # - # Toggle showing / hiding the batch actions popover - # - - $("#batch_actions_button").click -> - unless $(this).hasClass("disabled") - if $("#batch_actions_popover").is(":hidden") - $(this).popover "open" - return false - else - $(this).popover "close" - return false - - # - # Add checkbox selection to resource tables and lists if batch actions are enabled - # - - if $("#batch_actions_button").length && $(":checkbox.toggle_all").length - - if $(".paginated_collection").find("table").length - $(".paginated_collection table").tableCheckboxToggler() - else - $(".paginated_collection").checkboxToggler() - - $(".paginated_collection").find(":checkbox").bind "change", -> - if $(".paginated_collection").find(":checkbox").filter(":checked").length > 0 - $("#batch_actions_button").removeClass("disabled") - else - $("#batch_actions_button").addClass("disabled") diff --git a/app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.checkbox-toggler.js.coffee b/app/assets/javascripts/active_admin/components/jquery.aa.checkbox-toggler.js.coffee similarity index 100% rename from app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.checkbox-toggler.js.coffee rename to app/assets/javascripts/active_admin/components/jquery.aa.checkbox-toggler.js.coffee diff --git a/app/assets/javascripts/active_admin/components/jquery.aa.dropdown-menu.js.coffee b/app/assets/javascripts/active_admin/components/jquery.aa.dropdown-menu.js.coffee new file mode 100644 index 00000000000..70714c4301a --- /dev/null +++ b/app/assets/javascripts/active_admin/components/jquery.aa.dropdown-menu.js.coffee @@ -0,0 +1,107 @@ +window.AA.DropdownMenu = class AA.DropdownMenu + + constructor: (@options, @element) -> + + @$element = $(@element) + + defaults = { + fadeInDuration: 20, + fadeOutDuration: 100, + onClickActionItemCallback: null + } + + @options = $.extend({}, defaults, options) + + @$menuButton = @$element.find(".dropdown_menu_button") + @$menuList = @$element.find(".dropdown_menu_list_wrapper") + + @isOpen = false + + @_buildMenuList() + @_bind() + + return @ + + open: -> + @isOpen = true + @$menuList.fadeIn @options.fadeInDuration + + @_positionMenuList() + @_positionNipple() + + return @ + + + close: -> + @isOpen = false + @$menuList.fadeOut this.options.fadeOutDuration + + return @ + + destroy: -> + @$element.unbind() + @$element = null + + return @ + + isDisabled: -> + @$menuButton.hasClass("disabled") + + disable: -> + @$menuButton.addClass("disabled") + + enable: -> + @$menuButton.removeClass("disabled") + + option: (key, value) -> + if $.isPlainObject(key) + return @options = $.extend(true, @options, key) + + else if key? + return @options[key] + + else + return @options[key] = value + + # Private + + _buildMenuList: -> + @$menuList.prepend("
") + @$menuList.hide() + + _bind: -> + $("body").bind 'click', () => + if @isOpen is true + @close() + + @$menuButton.bind 'click', () => + unless @isDisabled() + if @isOpen is true + @close() + else + @open() + + # Return false so that the event is stopped + false + + _positionMenuList: -> + centerOfButtonFromLeft = @$menuButton.offset().left + @$menuButton.outerWidth() / 2 + centerOfmenuListFromLeft = @$menuList.outerWidth() / 2 + menuListLeftPos = centerOfButtonFromLeft - centerOfmenuListFromLeft + @$menuList.css "left", menuListLeftPos + + _positionNipple: -> + centerOfmenuListFromLeft = @$menuList.outerWidth() / 2 + bottomOfButtonFromTop = @$menuButton.offset().top + @$menuButton.outerHeight() + 10 + @$menuList.css "top", bottomOfButtonFromTop + $nipple = @$menuList.find(".dropdown_menu_nipple") + centerOfnippleFromLeft = $nipple.outerWidth() / 2 + nippleLeftPos = centerOfmenuListFromLeft - centerOfnippleFromLeft + $nipple.css "left", nippleLeftPos + +(($) -> + $.widget.bridge 'aaDropdownMenu', AA.DropdownMenu + + $ -> + $(".dropdown_menu").aaDropdownMenu() +)(jQuery) diff --git a/app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.popover.js.coffee b/app/assets/javascripts/active_admin/components/jquery.aa.popover.js.coffee similarity index 90% rename from app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.popover.js.coffee rename to app/assets/javascripts/active_admin/components/jquery.aa.popover.js.coffee index b5885b506b9..7465c8da31e 100644 --- a/app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.popover.js.coffee +++ b/app/assets/javascripts/active_admin/components/jquery.aa.popover.js.coffee @@ -13,13 +13,16 @@ window.AA.Popover = class AA.Popover onClickActionItemCallback: null } - @options = $.extend( {}, defaults, options ); + @options = $.extend({}, defaults, options) @$popover = null @isOpen = false - + if $(@$element.attr("href")).length > 0 @$popover = $(@$element.attr("href")) + else + @$popover = @$element.next(".popover") + @_buildPopover() @_bind() @@ -40,39 +43,41 @@ window.AA.Popover = class AA.Popover close: -> @isOpen = false; @$popover.fadeOut this.options.fadeOutDuration; - + return @ destroy: -> @$element.removeData('popover'); @$element.unbind(); @$element = null; - + return @ option: -> # ?? # Private - + _buildPopover: -> @$popover.prepend("
") - + @$popover.hide() @$popover.addClass "popover" _bind: -> - - $(@options.pageWrapperElement).bind 'click', (e) => if @isOpen is true @close() - + if @options.autoOpen is true @$element.bind 'click', () => - @open() + if @isOpen is true + @close() + else + @open() + false _positionPopover: -> @@ -90,6 +95,6 @@ window.AA.Popover = class AA.Popover nippleLeftPos = centerOfPopoverFromLeft - centerOfnippleFromLeft $nipple.css "left", nippleLeftPos -( ( $ ) -> +(($) -> $.widget.bridge 'popover', AA.Popover -)( jQuery ) +)(jQuery) diff --git a/app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.table-checkbox-toggler.js.coffee b/app/assets/javascripts/active_admin/components/jquery.aa.table-checkbox-toggler.js.coffee similarity index 99% rename from app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.table-checkbox-toggler.js.coffee rename to app/assets/javascripts/active_admin/components/jquery.aa.table-checkbox-toggler.js.coffee index 6a6b14542e9..8cd51614e28 100644 --- a/app/assets/javascripts/active_admin/coffeescripts/components/jquery.aa.table-checkbox-toggler.js.coffee +++ b/app/assets/javascripts/active_admin/components/jquery.aa.table-checkbox-toggler.js.coffee @@ -25,5 +25,3 @@ window.AA.TableCheckboxToggler = class AA.TableCheckboxToggler extends AA.Checkb ( ( $ ) -> $.widget.bridge 'tableCheckboxToggler', AA.TableCheckboxToggler )( jQuery ) - - diff --git a/app/assets/javascripts/active_admin/coffeescripts/lib/namespace.js.coffee b/app/assets/javascripts/active_admin/lib/namespace.js.coffee similarity index 100% rename from app/assets/javascripts/active_admin/coffeescripts/lib/namespace.js.coffee rename to app/assets/javascripts/active_admin/lib/namespace.js.coffee diff --git a/app/assets/javascripts/active_admin/coffeescripts/pages/application.js.coffee b/app/assets/javascripts/active_admin/pages/application.js.coffee similarity index 76% rename from app/assets/javascripts/active_admin/coffeescripts/pages/application.js.coffee rename to app/assets/javascripts/active_admin/pages/application.js.coffee index c1a9b9bc7f4..94439d1e1b8 100644 --- a/app/assets/javascripts/active_admin/coffeescripts/pages/application.js.coffee +++ b/app/assets/javascripts/active_admin/pages/application.js.coffee @@ -2,11 +2,12 @@ # Active Admin JS # -# Date picker $ -> + # Date picker $(".datepicker").datepicker dateFormat: "yy-mm-dd" $(".clear_filters_btn").click -> window.location.search = "" false + $(".dropdown_button").popover() diff --git a/app/assets/javascripts/active_admin/pages/batch_actions.js.coffee b/app/assets/javascripts/active_admin/pages/batch_actions.js.coffee new file mode 100644 index 00000000000..124dce1c3df --- /dev/null +++ b/app/assets/javascripts/active_admin/pages/batch_actions.js.coffee @@ -0,0 +1,26 @@ +jQuery ($) -> + + # + # Use Rails.js click handler to allow for Rails' confirm dialogs + # + + $(document).delegate "#batch_actions_selector li a", "click.rails", -> + $("#batch_action").val $(this).attr("data-action") + $("#collection_selection").submit() + + # + # Add checkbox selection to resource tables and lists if batch actions are enabled + # + + if $("#batch_actions_selector").length && $(":checkbox.toggle_all").length + + if $(".paginated_collection").find("table.index_table").length + $(".paginated_collection table").tableCheckboxToggler() + else + $(".paginated_collection").checkboxToggler() + + $(".paginated_collection").find(":checkbox").bind "change", -> + if $(".paginated_collection").find(":checkbox").filter(":checked").length > 0 + $("#batch_actions_selector").aaDropdownMenu("enable") + else + $("#batch_actions_selector").aaDropdownMenu("disable") diff --git a/app/assets/stylesheets/active_admin/_base.css.scss b/app/assets/stylesheets/active_admin/_base.css.scss index 8dab465393a..fce38245f7a 100644 --- a/app/assets/stylesheets/active_admin/_base.css.scss +++ b/app/assets/stylesheets/active_admin/_base.css.scss @@ -1,35 +1,40 @@ /* Active Admin CSS */ // Reset Away! -@include global-reset; +body.active_admin { + @include global-reset; +} // Partials -@import "active_admin/typography"; -@import "active_admin/header"; -@import "active_admin/forms"; -@import "active_admin/components/comments"; -@import "active_admin/components/flash_messages"; -@import "active_admin/components/date_picker"; -@import "active_admin/components/popovers"; -@import "active_admin/components/tables"; -@import "active_admin/components/batch_actions"; -@import "active_admin/components/blank_slates"; -@import "active_admin/components/breadcrumbs"; -@import "active_admin/components/buttons"; -@import "active_admin/components/grid"; -@import "active_admin/components/links"; -@import "active_admin/components/pagination"; -@import "active_admin/components/panels"; -@import "active_admin/components/columns"; -@import "active_admin/components/scopes"; -@import "active_admin/components/status_tags"; -@import "active_admin/components/table_tools"; -@import "active_admin/pages/dashboard"; -@import "active_admin/pages/logged_out"; -@import "active_admin/structure/footer"; -@import "active_admin/structure/main_structure"; -@import "active_admin/structure/title_bar"; +body.active_admin { + @import "active_admin/typography"; + @import "active_admin/header"; + @import "active_admin/forms"; + @import "active_admin/components/comments"; + @import "active_admin/components/flash_messages"; + @import "active_admin/components/date_picker"; + @import "active_admin/components/popovers"; + @import "active_admin/components/tables"; + @import "active_admin/components/batch_actions"; + @import "active_admin/components/blank_slates"; + @import "active_admin/components/breadcrumbs"; + @import "active_admin/components/dropdown_menu"; + @import "active_admin/components/buttons"; + @import "active_admin/components/grid"; + @import "active_admin/components/links"; + @import "active_admin/components/pagination"; + @import "active_admin/components/panels"; + @import "active_admin/components/columns"; + @import "active_admin/components/scopes"; + @import "active_admin/components/status_tags"; + @import "active_admin/components/table_tools"; + @import "active_admin/pages/dashboard"; + @import "active_admin/pages/logged_out"; + @import "active_admin/structure/footer"; + @import "active_admin/structure/main_structure"; + @import "active_admin/structure/title_bar"; +} -body { +body.active_admin { @include sans-family; line-height: 150%; font-size: 72%; diff --git a/app/assets/stylesheets/active_admin/_forms.css.scss b/app/assets/stylesheets/active_admin/_forms.css.scss index feefb55cc15..bd68505d60b 100644 --- a/app/assets/stylesheets/active_admin/_forms.css.scss +++ b/app/assets/stylesheets/active_admin/_forms.css.scss @@ -29,6 +29,13 @@ form { } } + ol > div.has_many { + padding: 20px 10px; + h3 { + font-size: 12px; + font-weight: bold; + } + } ol > li > li label { line-height:100%; @@ -67,14 +74,14 @@ form { li { padding:0; - border:0; + border:0; } } } } /* Text Fields */ - input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], textarea { + input[type=text], input[type=password], input[type=email], input[type=number], input[type=url], input[type=tel], textarea { width: 76%; border: 1px solid #c9d0d6; @include rounded; @@ -127,7 +134,7 @@ form { &.boolean { height: 1.1em; label { - width: 100%; + width: 80%; padding-left:20%; padding-right: 10px; text-transform: none !important; @@ -165,12 +172,12 @@ form { } - .buttons, .actions { + .buttons, .actions { margin-top: 15px; input[type=submit] { margin-right: 10px; } } - fieldset.buttons li, fieldset.actions li { + fieldset.buttons li, fieldset.actions li { float:left; padding: 0; diff --git a/app/assets/stylesheets/active_admin/_header.css.scss b/app/assets/stylesheets/active_admin/_header.css.scss index 9dabe4e0de2..342a108f3cd 100644 --- a/app/assets/stylesheets/active_admin/_header.css.scss +++ b/app/assets/stylesheets/active_admin/_header.css.scss @@ -5,9 +5,8 @@ @include text-shadow(#000); height: 20px; overflow: visible; - position: relative; + position: inherit; padding: 9px $horizontal-page-margin; - position: relative; z-index: 900; h1 { diff --git a/app/assets/stylesheets/active_admin/_typography.css.scss b/app/assets/stylesheets/active_admin/_typography.css.scss index f12389f4761..3044b4bc533 100644 --- a/app/assets/stylesheets/active_admin/_typography.css.scss +++ b/app/assets/stylesheets/active_admin/_typography.css.scss @@ -25,7 +25,7 @@ // Default font settings. The font-size percentage is of 16px. (0.75 * 16px = 12px) */ html { font-size:100.01%; } -body { font-size: 75%; font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; } +& { font-size: 75%; font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; } // Headings h1,h2,h3,h4,h5,h6 { diff --git a/app/assets/stylesheets/active_admin/components/_buttons.scss b/app/assets/stylesheets/active_admin/components/_buttons.scss index e95e848ae18..f7e416465fe 100644 --- a/app/assets/stylesheets/active_admin/components/_buttons.scss +++ b/app/assets/stylesheets/active_admin/components/_buttons.scss @@ -1,4 +1,3 @@ - td, p { @include icon(#B3BCC1, 0.8em); span.icon { margin: 0 3px; } @@ -9,4 +8,4 @@ a.member_link { white-space: nowrap; } -a.button, a:link.button, a:visited.button, input[type=submit] { @include dark-button; } \ No newline at end of file +a.button, a:link.button, a:visited.button, input[type=submit] { @include dark-button; } diff --git a/app/assets/stylesheets/active_admin/components/_dropdown_menu.scss b/app/assets/stylesheets/active_admin/components/_dropdown_menu.scss new file mode 100644 index 00000000000..2f22bac2c08 --- /dev/null +++ b/app/assets/stylesheets/active_admin/components/_dropdown_menu.scss @@ -0,0 +1,151 @@ +.dropdown_menu { + display: inline; + + .dropdown_menu_button { + @include light-button; + position: relative; + padding-right: 22px !important; + cursor: pointer; + + &:before { + content: ' '; + position: absolute; + width: 0; + height: 0; + border-width: 3px 3px 0; + border-style: solid; + border-color: #FFF transparent; + right: 12px; + top: 45%; + } + + &:after { + content: ' '; + position: absolute; + width: 0; + height: 0; + border-width: 3px 3px 0; + border-style: solid; + border-color: #777 transparent; + right: 12px; + top: 45%; + } + } + + .dropdown_menu_nipple { + + // The nipple's border + content: ""; + position: absolute; + top: -6px; + display: block; + width: 0; + height: 0; + border-width: 0 6px 6px; + border-style: solid; + border-color: darken($primary-color, 4%) transparent; + z-index: 100; + + // The nipple's inner shadow + + &:before { + content: ' '; + position: absolute; + width: 0; + height: 0; + border-width: 0 5px 5px; + border-style: solid; + border-color: lighten($primary-color, 15%) transparent; + left: -5px; + top: 1px; + } + + // The nipple's background color + + &:after { + content: ' '; + position: absolute; + width: 0; + height: 0; + border-width: 0 5px 5px; + border-style: solid; + border-color: lighten($primary-color, 4%) transparent; + left: -5px; + top: 2px; + } + } + + .dropdown_menu_list_wrapper { + display: inline-block; + position: absolute; + background-color: white; + padding: 2px; + @include box-shadow(rgba(0,0,0,0.4) 0 1px 3px, lighten($primary-color, 15%) 0px 1px 0px 0px inset); + background-color: $primary-color; + @include gradient(lighten($primary-color, 4%), darken($primary-color, 5%)); + border: solid 1px darken($primary-color, 10%); + border-top-color: darken($primary-color, 4%); + border-bottom-color: darken($primary-color, 17%); + + border-radius: 4px; + + .dropdown_menu_list { + display: block; + background-color: #FFF; + border: solid 1px darken($primary-color, 10%); + @include box-shadow(lighten($primary-color, 5%) 0px 1px 0px 0px); + border-radius: 3px; + margin: 0; + overflow: hidden; + padding: 8px; + + list-style-type: none; + padding: 0; + + li { + display: block; + border-bottom: solid 1px #ebebeb; + @include box-sizing(border-box); + + a { + display: block; + @include box-sizing(padding-box); + font-size: 0.95em; + font-weight: bold; + padding: 7px 16px 5px; + text-decoration: none; + text-align: center; + -webkit-font-smoothing: antialiased; + + &:hover { + @include highlight-gradient; + @include text-shadow(#5a83aa); + color: #FFF; + } + + &:active { + @include reverse-highlight-gradient; + color: #FFF; + } + + } + + &:first-child { + a { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } + + } + + &:last-child { + a { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + border: none; + } + } + } + } +} diff --git a/app/assets/stylesheets/active_admin/components/_flash_messages.css.scss b/app/assets/stylesheets/active_admin/components/_flash_messages.css.scss index f2e319981eb..d3c85f2bdbd 100644 --- a/app/assets/stylesheets/active_admin/components/_flash_messages.css.scss +++ b/app/assets/stylesheets/active_admin/components/_flash_messages.css.scss @@ -1,4 +1,4 @@ -body.logged_in { +&.logged_in { .flash { @include gradient(#f7f1d3, #f5edc5); @include text-shadow(#fafafa); @@ -25,7 +25,7 @@ body.logged_in { } } -body.logged_out { +&.logged_out { .flash { @include no-shadow; @include text-shadow(#fff); @@ -36,4 +36,4 @@ body.logged_out { margin-bottom: 10px; padding: 0; } -} \ No newline at end of file +} diff --git a/app/assets/stylesheets/active_admin/components/_table_tools.css.scss b/app/assets/stylesheets/active_admin/components/_table_tools.css.scss index 3be4f378f8c..b531c4b76a0 100644 --- a/app/assets/stylesheets/active_admin/components/_table_tools.css.scss +++ b/app/assets/stylesheets/active_admin/components/_table_tools.css.scss @@ -16,9 +16,11 @@ .table_tools_segmented_control + .table_tools_button { margin-left: 6px; } + } -a.table_tools_button { + +a.table_tools_button, .table_tools .dropdown_menu_button { @include light-button; @include gradient(#FFF, #F0F0F0); @include border-colors(#d9d9d9, #d0d0d0, #c5c5c5); @@ -39,36 +41,6 @@ a.table_tools_button { @include gradient(#FFF, #E8E8E8); } } - - &.dropdown_button { - padding-right: 22px; - - &:before { - content: ' '; - position: absolute; - width: 0; - height: 0; - border-width: 3px 3px 0; - border-style: solid; - border-color: #FFF transparent; - right: 9px; - top: 10px; - } - - &:after { - content: ' '; - position: absolute; - width: 0; - height: 0; - border-width: 3px 3px 0; - border-style: solid; - border-color: #777 transparent; - right: 9px; - top: 9px; - } - - } - } .table_tools_segmented_control { diff --git a/app/assets/stylesheets/active_admin/mixins/_gradients.css.scss b/app/assets/stylesheets/active_admin/mixins/_gradients.css.scss index 3f78fee7022..60f0dcb0c0e 100644 --- a/app/assets/stylesheets/active_admin/mixins/_gradients.css.scss +++ b/app/assets/stylesheets/active_admin/mixins/_gradients.css.scss @@ -1,14 +1,14 @@ -$secondary-gradient-start: #efefef; -$secondary-gradient-stop: #dfe1e2; +$secondary-gradient-start: #efefef !default; +$secondary-gradient-stop: #dfe1e2 !default; @mixin gradient($start, $end){ background: $start; background: -webkit-gradient(linear, left top, left bottom, from($start), to($end)); background: -moz-linear-gradient(-90deg, $start, $end); // IE 6 & 7 - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$start}, endColorstr=#{$end}); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$start}', endColorstr='#{$end}'); // IE 8 - -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$start}, endColorstr=#{$end}); + -ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{$start}', endColorstr='#{$end}'); } @mixin primary-gradient { @@ -34,4 +34,4 @@ $secondary-gradient-stop: #dfe1e2; filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); // IE 8 -ms-filter: "progid:DXImageTransform.Microsoft.gradient(enabled=false)"; -} \ No newline at end of file +} diff --git a/app/assets/stylesheets/active_admin/mixins/_icons.css.scss b/app/assets/stylesheets/active_admin/mixins/_icons.css.scss index 58aa5c0defc..69fdf9b7fe1 100644 --- a/app/assets/stylesheets/active_admin/mixins/_icons.css.scss +++ b/app/assets/stylesheets/active_admin/mixins/_icons.css.scss @@ -1,5 +1,7 @@ -span.icon { vertical-align: middle; display: inline-block; } -span.icon svg { vertical-align: baseline; } +body.active_admin { + span.icon { vertical-align: middle; display: inline-block; } + span.icon svg { vertical-align: baseline; } +} @mixin icon-color ($color) { span.icon svg { @@ -17,4 +19,6 @@ span.icon svg { vertical-align: baseline; } @include icon-size($size); } -@include icon-size(0.8em); +body.active_admin { + @include icon-size(0.8em); +} diff --git a/app/assets/stylesheets/active_admin/mixins/_variables.css.scss b/app/assets/stylesheets/active_admin/mixins/_variables.css.scss index 52def4f868f..caa631c6ea5 100644 --- a/app/assets/stylesheets/active_admin/mixins/_variables.css.scss +++ b/app/assets/stylesheets/active_admin/mixins/_variables.css.scss @@ -1,22 +1,24 @@ -// Variables used throughout Active Admin +// Variables used throughout Active Admin. +// They can be overridden by prepending your own +// to 'app/assets/stylesheets/active_admin.css.scss'. // Colors -$primary-color: #5E6469; -$secondary-color: #f0f0f0; -$text-color: #323537; -$link-color: #38678b; -$section-header-text-color: $primary-color; -$current-menu-item-background: lighten($primary-color, 12%); -$hover-menu-item-background: lighten($primary-color, 12%); -$table-stripe-color: lighten($primary-color, 57%); -$table-selected-color: #d9e4ec; -$error-color: #932419; +$primary-color: #5E6469 !default; +$secondary-color: #f0f0f0 !default; +$text-color: #323537 !default; +$link-color: #38678b !default; +$section-header-text-color: $primary-color !default; +$current-menu-item-background: lighten($primary-color, 12%) !default; +$hover-menu-item-background: lighten($primary-color, 12%) !default; +$table-stripe-color: lighten($primary-color, 57%) !default; +$table-selected-color: #d9e4ec !default; +$error-color: #932419 !default; // Sizes -$horizontal-page-margin: 30px; -$sidebar-width: 270px; -$cell-padding: 5px 10px 3px 10px; -$cell-horizontal-padding: 12px; -$section-padding: 15px; -$text-input-horizontal-padding: 10px; +$horizontal-page-margin: 30px !default; +$sidebar-width: 270px !default; +$cell-padding: 5px 10px 3px 10px !default; +$cell-horizontal-padding: 12px !default; +$section-padding: 15px !default; +$text-input-horizontal-padding: 10px !default; diff --git a/app/assets/stylesheets/active_admin/pages/_logged_out.scss b/app/assets/stylesheets/active_admin/pages/_logged_out.scss index a45c9861084..f9e73efb737 100644 --- a/app/assets/stylesheets/active_admin/pages/_logged_out.scss +++ b/app/assets/stylesheets/active_admin/pages/_logged_out.scss @@ -1,4 +1,4 @@ -body.logged_out { +&.logged_out { background: #e8e9ea; #content_wrapper{ @@ -41,4 +41,4 @@ body.logged_out { a { float: right; margin-top: -32px; } } -} \ No newline at end of file +} diff --git a/app/assets/stylesheets/active_admin/print.css.scss b/app/assets/stylesheets/active_admin/print.css.scss index 5b59698d51a..d0825f3b4bc 100644 --- a/app/assets/stylesheets/active_admin/print.css.scss +++ b/app/assets/stylesheets/active_admin/print.css.scss @@ -9,9 +9,11 @@ $text-color: black; @include global-reset; // Partials -@import "active_admin/typography"; +body.active_admin { + @import "active_admin/typography"; +} -body { +body.active_admin { font-family: Helvetica, Arial, sans-serif; line-height: 150%; font-size: 72%; @@ -22,6 +24,8 @@ body { color: $text-color; } +body.active_admin { + a { color: $text-color; text-decoration: none; @@ -281,4 +285,6 @@ form { } } -} \ No newline at end of file +} + +} diff --git a/app/views/active_admin/devise/passwords/edit.html.erb b/app/views/active_admin/devise/passwords/edit.html.erb index 4431c583c8f..33e38798f66 100644 --- a/app/views/active_admin/devise/passwords/edit.html.erb +++ b/app/views/active_admin/devise/passwords/edit.html.erb @@ -1,16 +1,16 @@ -

Change your password

+
+ <%= content_tag :h2, t('active_admin.devise.change_password.title') %> -<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %> - <%= devise_error_messages! %> - <%= f.hidden_field :reset_password_token %> + <%= active_admin_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| + f.inputs do + f.input :password + f.input :password_confirmation + end + f.actions do + f.action :submit, :label => t('active_admin.devise.change_password.submit'), :button_html => { :value => "Change my password" } + f.input :reset_password_token, :as => :hidden, :value => resource.reset_password_token + end + end %> -

<%= f.label :password %>
- <%= f.password_field :password %>

- -

<%= f.label :password_confirmation %>
- <%= f.password_field :password_confirmation %>

- -

<%= f.submit "Change my password" %>

-<% end %> - -<%= render :partial => "active_admin/devise/shared/links" %> \ No newline at end of file + <%= render :partial => "active_admin/devise/shared/links" %> +
\ No newline at end of file diff --git a/app/views/active_admin/devise/passwords/new.html.erb b/app/views/active_admin/devise/passwords/new.html.erb index 1d772577351..03dd24dd330 100644 --- a/app/views/active_admin/devise/passwords/new.html.erb +++ b/app/views/active_admin/devise/passwords/new.html.erb @@ -1,14 +1,12 @@
-

Forgot your password?

+ <%= content_tag :h2, t('active_admin.devise.reset_password.title') %> <%= active_admin_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post }) do |f| f.inputs do f.input :email end -# f.buttons do - # f.commit_button "Reset My Password" f.actions do - f.action :submit, :label => "Reset My Password", :button_html => { :value => "Reset My Password" } + f.action :submit, :label => t('active_admin.devise.reset_password.submit'), :button_html => { :value => "Reset My Password" } end end %> diff --git a/app/views/active_admin/devise/sessions/new.html.erb b/app/views/active_admin/devise/sessions/new.html.erb index 24639f469d1..93ed2c4328c 100644 --- a/app/views/active_admin/devise/sessions/new.html.erb +++ b/app/views/active_admin/devise/sessions/new.html.erb @@ -1,17 +1,15 @@
-

<%= title "#{active_admin_application.site_title} Login" %>

+

<%= title "#{active_admin_application.site_title} #{t('active_admin.devise.login.title')}" %>

<% scope = Devise::Mapping.find_scope!(resource_name) %> <%= active_admin_form_for(resource, :as => resource_name, :url => send(:"#{scope}_session_path"), :html => { :id => "session_new" }) do |f| f.inputs do Devise.authentication_keys.each { |key| f.input key, :input_html => {:autofocus => true}} f.input :password - f.input :remember_me, :as => :boolean, :if => false #devise_mapping.rememberable? } + f.input :remember_me, :label => t('active_admin.devise.login.remember_me'), :as => :boolean, :if => false #devise_mapping.rememberable? } end -# f.buttons do -# f.commit_button "Login" f.actions do - f.action :submit, :label => "Login", :button_html => { :value => "Login" } + f.action :submit, :label => t('active_admin.devise.login.submit'), :button_html => { :value => "Login" } end end %> diff --git a/app/views/active_admin/devise/shared/_links.erb b/app/views/active_admin/devise/shared/_links.erb index 4a7d769f1a5..f49846a58ad 100644 --- a/app/views/active_admin/devise/shared/_links.erb +++ b/app/views/active_admin/devise/shared/_links.erb @@ -1,20 +1,20 @@ <%- if controller_name != 'sessions' %> <% scope = Devise::Mapping.find_scope!(resource_name) %> - <%= link_to "Sign in", send(:"new_#{scope}_session_path") %>
+ <%= link_to t('active_admin.devise.links.sign_in'), send(:"new_#{scope}_session_path") %>
<% end -%> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> - <%= link_to "Sign up", new_registration_path(resource_name) %>
+ <%= link_to t('active_admin.devise.links.sign_up'), new_registration_path(resource_name) %>
<% end -%> <%- if devise_mapping.recoverable? && controller_name != 'passwords' %> - <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+ <%= link_to t('active_admin.devise.links.forgot_your_password'), new_password_path(resource_name) %>
<% end -%> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> - <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+ <%= link_to t('active_admin.devise.links.resend_confirmation_instructions'), new_confirmation_path(resource_name) %>
<% end -%> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> - <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
-<% end -%> + <%= link_to t('active_admin.devise.links.resend_unlock_instructions'), new_unlock_path(resource_name) %>
+<% end -%> \ No newline at end of file diff --git a/app/views/active_admin/resource/index.csv.erb b/app/views/active_admin/resource/index.csv.erb index 83737a4bad3..f124881fd34 100644 --- a/app/views/active_admin/resource/index.csv.erb +++ b/app/views/active_admin/resource/index.csv.erb @@ -7,7 +7,7 @@ CSV end - csv_output = csv_lib.generate do |csv| + csv_output = csv_lib.generate(:col_sep => active_admin_config.csv_builder.column_separator || ',') do |csv| columns = active_admin_config.csv_builder.columns csv << columns.map(&:name) collection.each do |resource| diff --git a/app/views/layouts/active_admin_logged_out.html.erb b/app/views/layouts/active_admin_logged_out.html.erb index 3a15238fa85..273a154353e 100644 --- a/app/views/layouts/active_admin_logged_out.html.erb +++ b/app/views/layouts/active_admin_logged_out.html.erb @@ -14,7 +14,7 @@ <%= csrf_meta_tag %> - +
diff --git a/docs/4-csv-format.md b/docs/4-csv-format.md index 44d08d1eb32..408ecf59401 100644 --- a/docs/4-csv-format.md +++ b/docs/4-csv-format.md @@ -12,3 +12,12 @@ Customizing the CSV format is as simple as customizing the index page. column("Author") { |post| post.author.full_name } end end + +You can choose custom separator + + ActiveAdmin.register Post do + csv :separator => ';' do + column :title + column("Author") { |post| post.author.full_name } + end + end diff --git a/docs/9-batch-actions.md b/docs/9-batch-actions.md index e7d6bd0a80d..b756a9033c3 100644 --- a/docs/9-batch-actions.md +++ b/docs/9-batch-actions.md @@ -22,6 +22,30 @@ to operate on. The array should contain at least one ID. end end +### Disabling Batch Actions + +You can disable batch actions at the application or namespace level in +`config/initializers/active_admin.rb`: + + ActiveAdmin.setup do |config| + + # Disable all batch actions + config.batch_actions = false + + + # Or disable for a given namespace + config.namespace :admin do |admin| + admin.batch_actions = false + end + end + +You can disable batch actions on any given resource using: + + ActiveAdmin.register Post do + config.batch_actions = false + end + + ### Modifying a Previously Registered Batch Action If you wanted to modify the behavior of the provided "Delete" batch action, you can override by: diff --git a/features/i18n.feature b/features/i18n.feature index 8f564315097..beeb2c25ea0 100644 --- a/features/i18n.feature +++ b/features/i18n.feature @@ -11,7 +11,7 @@ Feature: Internationalization Then I should see "Hello words" When I follow "View" Then I should see "Bookstore Details" - And I should see "Bookstore #" + And I should see "Hello words" And I should see a link to "Delete Bookstore" When I follow "Edit Bookstore" Then I should see "Edit Bookstore" diff --git a/features/index/batch_actions.feature b/features/index/batch_actions.feature index b7e8d8d88f3..a2f504b009c 100644 --- a/features/index/batch_actions.feature +++ b/features/index/batch_actions.feature @@ -26,33 +26,45 @@ Feature: Batch Actions And an index configuration of: """ ActiveAdmin.register Post do - batch_action( :flag ) do - redirect_to collection_path, :notice => "Successfully flagged 10 posts" - end + batch_action(:flag) do + redirect_to collection_path, :notice => "Successfully flagged 10 posts" + end end """ When I check the 1st record Given I submit the batch action form with "flag" Then I should see a flash with "Successfully flagged 10 posts" - - Scenario: Disabling batch actions + + Scenario: Disabling batch actions for a resource Given 10 posts exist And an index configuration of: """ ActiveAdmin.register Post do - batch_action :destroy, false + config.batch_actions = false end """ - Then I should not see the batch action :destroy "Delete Selected" + Then I should not see the batch actions selector And I should not see checkboxes in the table + Scenario: Disabling the default destroy batch action + Given 10 posts exist + And an index configuration of: + """ + ActiveAdmin.register Post do + batch_action :destroy, false + batch_action(:flag) {} + end + """ + Then I should see the batch action "Flag Selected" + And I should not see the batch action "Delete Selected" + Scenario: Optional display of batch actions Given 10 posts exist And an index configuration of: """ ActiveAdmin.register Post do - batch_action( :flag, :if => proc { true } ) {} - batch_action( :unflag, :if => proc { false } ) {} + batch_action(:flag, :if => proc { true }) {} + batch_action(:unflag, :if => proc { false }) {} end """ Then I should see the batch action "Flag Selected" @@ -63,9 +75,9 @@ Feature: Batch Actions And an index configuration of: """ ActiveAdmin.register Post do - batch_action( :test, :priority => 3 ) {} - batch_action( :flag, :priority => 2 ) {} - batch_action( :unflag, :priority => 1 ) {} + batch_action(:test, :priority => 3) {} + batch_action(:flag, :priority => 2) {} + batch_action(:unflag, :priority => 1) {} end """ Then the 4th batch action should be "Delete Selected" @@ -78,8 +90,8 @@ Feature: Batch Actions And an index configuration of: """ ActiveAdmin.register Post do - batch_action( "Very Complex and Time Consuming" ) {} - batch_action( :passing_a_symbol ) {} + batch_action("Very Complex and Time Consuming") {} + batch_action(:passing_a_symbol) {} end """ Then I should see the batch action :very_complex_and_time_consuming "Very Complex and Time Consuming Selected" diff --git a/features/index/format_as_csv.feature b/features/index/format_as_csv.feature index 70be1936ab8..bc725777de0 100644 --- a/features/index/format_as_csv.feature +++ b/features/index/format_as_csv.feature @@ -44,3 +44,20 @@ Feature: Format as CSV | Title | Last update | Copyright | | Hello, World | (.*) | Greg Bell | + Scenario: With CSV format customization + Given a configuration of: + """ + ActiveAdmin.register Post do + csv :separator => ';' do + column :title + column :body + end + end + """ + And a post with the title "Hello, World" exists + When I am on the index page for posts + And I follow "CSV" + And I should download a CSV file with ";" separator for "posts" containing: + | Title | Body | + | Hello, World | (.*) | + diff --git a/features/index/page_title.feature b/features/index/page_title.feature new file mode 100644 index 00000000000..7952fdb4e3d --- /dev/null +++ b/features/index/page_title.feature @@ -0,0 +1,12 @@ +Feature: Index - Page Title + + Modifying the page title on the index screen + + Scenario: Set a string as the title + Given an index configuration of: + """ + ActiveAdmin.register Post do + index :title => "Awesome Title" + end + """ + Then I should see the page title "Awesome Title" diff --git a/features/show/default_content.feature b/features/show/default_content.feature index 807ad11a5eb..8df18de5fe9 100644 --- a/features/show/default_content.feature +++ b/features/show/default_content.feature @@ -20,8 +20,8 @@ Feature: Show - Default Content Scenario: Attributes should link when linked resource is registered Given a show configuration of: """ - ActiveAdmin.register User ActiveAdmin.register Post + ActiveAdmin.register User """ Then I should see the attribute "Author" with "jane_doe" And I should see a link to "jane_doe" diff --git a/features/show/page_title.feature b/features/show/page_title.feature index 35247e3271b..20f3c889d32 100644 --- a/features/show/page_title.feature +++ b/features/show/page_title.feature @@ -31,3 +31,17 @@ Feature: Show - Page Title end """ Then I should see the page title "Title: Hello World" + + Scenario: Default title + Given a show configuration of: + """ + ActiveAdmin.register Post + """ + Then I should see the page title "Hello World" + + Scenario: Default title with no display name method candidate + Given a show configuration of: + """ + ActiveAdmin.register Tag + """ + Then I should see the page title "Tag #" diff --git a/features/step_definitions/additional_web_steps.rb b/features/step_definitions/additional_web_steps.rb index d152e0dedba..e4bf0a7d469 100644 --- a/features/step_definitions/additional_web_steps.rb +++ b/features/step_definitions/additional_web_steps.rb @@ -64,7 +64,9 @@ end Then /^I should see the page title "([^"]*)"$/ do |title| - page.should have_css('h2#page_title', :text => title) + within('h2#page_title') do + page.should have_content(title) + end end Then /^I should see a fieldset titled "([^"]*)"$/ do |title| diff --git a/features/step_definitions/batch_action_steps.rb b/features/step_definitions/batch_action_steps.rb index e5a1b6c05ae..157df835f26 100644 --- a/features/step_definitions/batch_action_steps.rb +++ b/features/step_definitions/batch_action_steps.rb @@ -14,7 +14,7 @@ end Then /^I (should|should not) see the batch action :([^\s]*) "([^"]*)"$/ do |maybe, sym, title| - within "#batch_actions_popover" do + within "#batch_actions_selector" do unless maybe == "should not" link = page.find "a.batch_action", :text => title link["data-action"].should match( sym ) @@ -26,7 +26,7 @@ end Then /^the (\d+)(?:st|nd|rd|th) batch action should be "([^"]*)"$/ do |index, title| - within "#batch_actions_popover" do + within "#batch_actions_selector" do page.all( "a.batch_action" )[index.to_i - 1].text.should match( title ) end end @@ -55,19 +55,23 @@ end Then /^I should see that the batch action button is disabled$/ do - page.should have_css("#batch_actions_button.disabled") + page.should have_css("#batch_actions_selector .dropdown_menu_button.disabled") end Then /^I (should|should not) see the batch action button$/ do |maybe| if maybe == "should not" - page.should_not have_css("div.table_tools #batch_actions_button") + page.should_not have_css("div.table_tools #batch_actions_selector .dropdown_menu_button") else - page.should have_css("div.table_tools #batch_actions_button") + page.should have_css("div.table_tools #batch_actions_selector .dropdown_menu_button") end end +Then "I should not see the batch actions selector" do + page.should_not have_css("div.table_tools #batch_actions_selector") +end + Then /^I should see the batch action popover exists$/ do - page.should have_css("#batch_actions_popover") + page.should have_css("#batch_actions_selector") end Given /^I submit the batch action form with "([^"]*)"$/ do |action| diff --git a/features/step_definitions/configuration_steps.rb b/features/step_definitions/configuration_steps.rb index 86bfc56d12c..7fa4b5abaf7 100644 --- a/features/step_definitions/configuration_steps.rb +++ b/features/step_definitions/configuration_steps.rb @@ -57,11 +57,21 @@ def self.rollback! end Given /^a show configuration of:$/ do |configuration_content| + resource = configuration_content.match(/ActiveAdmin\.register (\w+)/)[1] load_active_admin_configuration(configuration_content) - step 'I am logged in' - step "I am on the index page for posts" - step 'I follow "View"' + case resource + when "Post" + step 'I am logged in' + step "I am on the index page for posts" + step 'I follow "View"' + when "Tag" + step 'I am logged in' + Tag.create! + visit admin_tag_path(Tag.last) + else + raise "#{resource} is not supported" + end end Given /^"([^"]*)" contains:$/ do |filename, contents| diff --git a/features/step_definitions/format_steps.rb b/features/step_definitions/format_steps.rb index 24c99d2dbcf..4fa0fea17d6 100644 --- a/features/step_definitions/format_steps.rb +++ b/features/step_definitions/format_steps.rb @@ -19,14 +19,14 @@ end # Check first rows of the displayed CSV. -Then /^I should download a CSV file for "([^"]*)" containing:$/ do |resource_name, table| +Then /^I should download a CSV file with "([^"]*)" separator for "([^"]*)" containing:$/ do |sep, resource_name, table| page.response_headers['Content-Type'].should == 'text/csv; charset=utf-8' csv_filename = "#{resource_name}-#{Time.now.strftime("%Y-%m-%d")}.csv" page.response_headers['Content-Disposition'].should == %{attachment; filename="#{csv_filename}"} body = page.driver.response.body begin - csv = CSVLib.parse(body) + csv = CSVLib.parse(body, :col_sep => sep) table.raw.each_with_index do |expected_row, row_index| expected_row.each_with_index do |expected_cell, col_index| cell = csv.try(:[], row_index).try(:[], col_index) @@ -45,3 +45,7 @@ raise $! end end + +Then /^I should download a CSV file for "([^"]*)" containing:$/ do |resource_name, table| + step "I should download a CSV file with \",\" separator for \"#{resource_name}\" containing:", table +end \ No newline at end of file diff --git a/lib/active_admin/application.rb b/lib/active_admin/application.rb index 80a32ae555c..a46997ca029 100644 --- a/lib/active_admin/application.rb +++ b/lib/active_admin/application.rb @@ -57,6 +57,9 @@ def self.inheritable_setting(name, default) # The method to use when generating the link for user logout inheritable_setting :logout_link_method, :get + # Whether the batch actions are enabled or not + inheritable_setting :batch_actions, true + # Active Admin makes educated guesses when displaying objects, this is # the list of methods it tries calling in order setting :display_name_methods, [ :display_name, diff --git a/lib/active_admin/batch_actions.rb b/lib/active_admin/batch_actions.rb index 236e764b67c..a6864da1097 100644 --- a/lib/active_admin/batch_actions.rb +++ b/lib/active_admin/batch_actions.rb @@ -10,7 +10,8 @@ require "active_admin/batch_actions/views/batch_action_form" require "active_admin/batch_actions/views/batch_action_popover" require "active_admin/batch_actions/views/selection_cells" + require "active_admin/batch_actions/views/batch_action_selector" # Register the views with the view factory - app.view_factory.register :batch_action_popover => ActiveAdmin::BatchActions::BatchActionPopover + app.view_factory.register :batch_action_selector => ActiveAdmin::BatchActions::BatchActionSelector end diff --git a/lib/active_admin/batch_actions/resource_extension.rb b/lib/active_admin/batch_actions/resource_extension.rb index c799b263348..c2cc2999a46 100644 --- a/lib/active_admin/batch_actions/resource_extension.rb +++ b/lib/active_admin/batch_actions/resource_extension.rb @@ -2,7 +2,6 @@ module ActiveAdmin module BatchActions module ResourceExtension - def initialize(*) super @batch_actions = {} @@ -11,7 +10,20 @@ def initialize(*) # @return [Array] The set of batch actions for this resource def batch_actions - @batch_actions.values.sort + batch_actions_enabled? ? @batch_actions.values.sort : [] + end + + # @return [Boolean] If batch actions are enabled for this resource + def batch_actions_enabled? + # If the resource config has been set, use it. Otherwise + # return the namespace setting + @batch_actions_enabled.nil? ? namespace.batch_actions : @batch_actions_enabled + end + + # Disable or Enable batch actions for this resource + # Set to `nil` to inherit the setting from the namespace + def batch_actions=(bool) + @batch_actions_enabled = bool end # Add a new batch item to a resource diff --git a/lib/active_admin/batch_actions/views/batch_action_form.rb b/lib/active_admin/batch_actions/views/batch_action_form.rb index ed1e152b410..3fd2b82123d 100644 --- a/lib/active_admin/batch_actions/views/batch_action_form.rb +++ b/lib/active_admin/batch_actions/views/batch_action_form.rb @@ -11,22 +11,23 @@ class BatchActionForm < ActiveAdmin::Component def build(options = {}, &block) options[:id] ||= "collection_selection" - @contents = input(:name => :batch_action, :id => :batch_action, :type => :hidden) - @prefix_html = text_node(form_tag send(active_admin_config.batch_action_path), :id => options[:id]) + + # Open a form + text_node form_tag(send(active_admin_config.batch_action_path), :id => options[:id]) + input(:name => :batch_action, :id => :batch_action, :type => :hidden) + super(options) end - # Override to_html to wrap the custom form stuff + # Override the default to_s to include a closing form tag def to_s - @prefix_html + content + text_node(''.html_safe) + content + closing_form_tag end - def add_child(child) - if @contents - @contents << child - else - super - end + private + + def closing_form_tag + ''.html_safe end end diff --git a/lib/active_admin/batch_actions/views/batch_action_selector.rb b/lib/active_admin/batch_actions/views/batch_action_selector.rb new file mode 100644 index 00000000000..69ae00b8eda --- /dev/null +++ b/lib/active_admin/batch_actions/views/batch_action_selector.rb @@ -0,0 +1,63 @@ +require 'active_admin/component' + +module ActiveAdmin + module BatchActions + + class BatchActionSelector < ActiveAdmin::Component + builder_method :batch_action_selector + + # Build a new batch actions selector + # + # @param [Array] batch_actions An array of batch actions + def build(batch_actions) + @batch_actions = Array(batch_actions) + @drop_down = build_drop_down + end + + # We don't want to wrap the action list (or any other children) in + # an unecessary div, so instead we just return the children + def to_s + children.to_s + end + + private + + def build_drop_down + dropdown_menu I18n.t("active_admin.batch_actions.button_label"), + :id => "batch_actions_selector", + :button => { :class => "disabled" } do + batch_actions_to_display.each do |batch_action| + options = { + :class => "batch_action", + "data-action" => batch_action.sym, + "data-confirm" => batch_action.confirm + } + + title = I18n.t("active_admin.batch_actions.labels.#{batch_action.sym}", :default => batch_action.title) + label = I18n.t("active_admin.batch_actions.action_label", :title => title) + + item label, "#", options + end + end + end + + # Return the set of batch actions that should be displayed + def batch_actions_to_display + @batch_actions.select do |batch_action| + call_method_or_proc_on(self, batch_action.display_if_block) + end + end + + # def build_batch_action_button + # a :class => 'table_tools_button dropdown_button disabled', :href => "#batch_actions_popover", :id => "batch_actions_button" do + # text_node I18n.t("active_admin.batch_actions.button_label") + # end + # end + + # def build_batch_action_popover + # end + + end + + end +end diff --git a/lib/active_admin/comments/views/active_admin_comments.rb b/lib/active_admin/comments/views/active_admin_comments.rb index cb345879619..a75a0b7845b 100644 --- a/lib/active_admin/comments/views/active_admin_comments.rb +++ b/lib/active_admin/comments/views/active_admin_comments.rb @@ -70,9 +70,7 @@ def build_comment_form form.input :resource_id, :value => @record.id, :as => :hidden form.input :body, :input_html => {:size => "80x8"}, :label => false end - #form.buttons do form.actions do - #form.commit_button I18n.t('active_admin.comments.add') form.action :submit, :label => I18n.t('active_admin.comments.add'), :button_html => { :value => I18n.t('active_admin.comments.add') } end end diff --git a/lib/active_admin/csv_builder.rb b/lib/active_admin/csv_builder.rb index da1801e6f9d..550661de36f 100644 --- a/lib/active_admin/csv_builder.rb +++ b/lib/active_admin/csv_builder.rb @@ -7,6 +7,10 @@ module ActiveAdmin # csv_builder.column :id # csv_builder.column("Name") { |resource| resource.full_name } # + # csv_builder = CSVBuilder.new :separator => ";" + # csv_builder.column :id + # + # class CSVBuilder # Return a default CSVBuilder for a resource @@ -21,10 +25,11 @@ def self.default_for_resource(resource) end end - attr_reader :columns + attr_reader :columns, :column_separator - def initialize(&block) - @columns = [] + def initialize(options={}, &block) + @columns = [] + @column_separator = options.delete(:separator) instance_eval &block if block_given? end diff --git a/lib/active_admin/form_builder.rb b/lib/active_admin/form_builder.rb index 510df445476..321f4d8eac0 100644 --- a/lib/active_admin/form_builder.rb +++ b/lib/active_admin/form_builder.rb @@ -24,28 +24,32 @@ def input(method, *args) form_buffers.last << content.html_safe end - # The buttons method always needs to be wrapped in a new buffer - def buttons(*args, &block) + def cancel_link(url = nil, html_options = {}, li_attributes = {}) + li_attributes[:class] ||= "cancel" + url ||= {:action => "index"} + form_buffers.last << template.content_tag(:li, (template.link_to I18n.t('active_admin.cancel'), url, html_options), li_attributes) + end + + def commit_action_with_cancel_link + content = action(:submit) + content << cancel_link + end + + def actions(*args, &block) content = with_new_form_buffer do - block_given? ? super : super { commit_button_with_cancel_link } + block_given? ? super : super { commit_action_with_cancel_link } end form_buffers.last << content.html_safe end - def commit_button(*args) - content = with_new_form_buffer{ super } + def action(*args) + content = with_new_form_buffer { super } form_buffers.last << content.html_safe end - def cancel_link(url = nil, html_options = {}, li_attributes = {}) - li_attributes[:class] ||= "cancel" - url ||= {:action => "index"} - template.content_tag(:li, (template.link_to I18n.t('active_admin.cancel'), url, html_options), li_attributes) - end - - def commit_button_with_cancel_link - content = commit_button - content << cancel_link + def commit_action_with_cancel_link + action(:submit) + cancel_link end def actions(*args, &block) @@ -103,6 +107,40 @@ def has_many(association, options = {}, &block) form_buffers.last << content.html_safe end + # These methods are deprecated and removed from Formtastic, however are + # supported here to help with transition. + module DeprecatedMethods + + # Formtastic has depreciated #commit_button in favor of #action(:submit) + def commit_button(*args) + ::ActiveSupport::Deprecation.warn("f.commit_button is deprecated in favour of f.action(:submit)") + + options = args.extract_options! + if String === args.first + options[:label] = args.first unless options.has_key?(:label) + end + + action(:submit, options) + end + + def commit_button_with_cancel_link + # Formtastic has depreciated #buttons in favor of #actions + ::ActiveSupport::Deprecation.warn("f.commit_button_with_cancel_link is deprecated in favour of f.commit_action_with_cancel_link") + + commit_action_with_cancel_link + end + + # The buttons method always needs to be wrapped in a new buffer + def buttons(*args, &block) + # Formtastic has depreciated #buttons in favor of #actions + ::ActiveSupport::Deprecation.warn("f.buttons is deprecated in favour of f.actions") + + actions args, &block + end + + end + include DeprecatedMethods + protected def active_admin_input_class_name(as) diff --git a/lib/active_admin/locales/en.yml b/lib/active_admin/locales/en.yml index c3ae6a22037..d8cb9917e72 100644 --- a/lib/active_admin/locales/en.yml +++ b/lib/active_admin/locales/en.yml @@ -64,3 +64,17 @@ en: title_content: "Comments (%{count})" errors: empty_text: "Comment wasn't saved, text was empty." + devise: + login: + title: "Login" + remember_me: "Remember me" + submit: "Login" + reset_password: + title: "Forgot your password?" + submit: "Reset My Password" + change_password: + title: "Change your password" + submit: "Change my password" + links: + sign_in: "Sign in" + forgot_your_password: "Forgot your password?" diff --git a/lib/active_admin/locales/es.yml b/lib/active_admin/locales/es.yml index d38a0f10aeb..4f6fca5b14a 100644 --- a/lib/active_admin/locales/es.yml +++ b/lib/active_admin/locales/es.yml @@ -9,7 +9,9 @@ es: delete: "Eliminar" delete_confirmation: "¿Está seguro que quiere eliminar esto?" new_model: "Nuevo(a) %{model}" + create_model: "Nuevo(a) %{model}" edit_model: "Editar %{model}" + update_model: "Editar %{model}" delete_model: "Eliminar %{model}" details: "Detalles de %{model}" cancel: "Cancelar" diff --git a/lib/active_admin/locales/he_il.yml b/lib/active_admin/locales/he.yml similarity index 55% rename from lib/active_admin/locales/he_il.yml rename to lib/active_admin/locales/he.yml index a9de0b87f7c..5e3193bde0f 100644 --- a/lib/active_admin/locales/he_il.yml +++ b/lib/active_admin/locales/he.yml @@ -1,4 +1,4 @@ -he_il: +he: active_admin: dashboard: פנל ניהול dashboard_welcome: @@ -42,4 +42,39 @@ he_il: any: "Any" blank_slate: content: "כרגע אין עוד אף %{resource_name}." - link: "צור אחד" \ No newline at end of file + link: "צור אחד" + batch_actions: + button_label: "פעולות מרובות" + delete_confirmation: "האם הנך בטוח שאתה רוצה למרוח את %{plural_model}? לא תוכל לבטל את המחיקה." + succesfully_destroyed: + one: "1 %{model} נמחק בהצלחה" + other: "%{count} %{plural_model} נמחק בהצלחה" + selection_toggle_explanation: "(שינוי בחירה)" + link: "צור" + action_label: "%{title} נבחר" + labels: + destroy: "מחק" + comments: + body: "תוכן" + author: 'נוצר ע"י' + title: "תגובה" + add: "הוסף תגובה" + resource: "Resource" + no_comments_yet: "אין עדיין תגובות." + title_content: "תגובות (%{count})" + errors: + empty_text: "התגובה לא נשמרה, שדה התוכן ריק." + devise: + login: + title: "כניסה" + remember_me: "זכור אותי" + submit: "הכנס" + reset_password: + title: "שכחת סיסמא?" + submit: "אפס את הסיסמא שלי" + change_password: + title: "שנה את הסיסמא שלך" + submit: "שנה את הסיסמא שלי" + links: + sign_in: "כניסה" + forgot_your_password: "שכחת את הסיסמא שלך?" diff --git a/lib/active_admin/locales/it.yml b/lib/active_admin/locales/it.yml index 3755abd3eb5..49d95e29b42 100644 --- a/lib/active_admin/locales/it.yml +++ b/lib/active_admin/locales/it.yml @@ -42,4 +42,25 @@ it: any: "Qualsiasi" blank_slate: content: "Non sono presenti %{resource_name}" - link: "Crea nuovo/a" \ No newline at end of file + link: "Crea nuovo/a" + batch_actions: + button_label: "Azioni Batch" + delete_confirmation: "Sei sicuro di volere cancellare %{plural_model}? Non sarà possibile annulare questa modifica." + succesfully_destroyed: + one: "Eliminato con successo 1 %{model}" + other: "Eliminati con successo %{count} %{plural_model}" + selection_toggle_explanation: "(Toggle Selection)" + link: "Crea uno" + action_label: "%{title} Selezionati" + labels: + destroy: "Elimina" + comments: + body: "Corpo" + author: "Autore" + title: "Commento" + add: "Aggiungi Commento" + resource: "Risorsa" + no_comments_yet: "Nessun commento." + title_content: "Commenti (%{count})" + errors: + empty_text: "Il commento non può essere salvato, il testo è vuoto." \ No newline at end of file diff --git a/lib/active_admin/locales/nl.yml b/lib/active_admin/locales/nl.yml index 1045c60023f..6e17b0efdf8 100644 --- a/lib/active_admin/locales/nl.yml +++ b/lib/active_admin/locales/nl.yml @@ -9,7 +9,9 @@ nl: delete: "Verwijder" delete_confirmation: "Weet je zeker dat je dit item wilt verwijderen?" new_model: "Nieuwe %{model}" + create_model: "Nieuwe %{model}" edit_model: "Wijzig %{model}" + update_model: "Wijzig %{model}" delete_model: "Verwijder %{model}" details: "%{model} details" cancel: "Annuleren" @@ -34,7 +36,31 @@ nl: one: "Geeft 1 %{model} weer" one_page: "Geeft %{n} %{model} weer" multiple: "Geeft %{model} %{from} - %{to} van de %{total} weer" + entry: + one: "entry" + other: "entries" any: "Alle" blank_slate: content: "Er zijn geen %{resource_name} gevonden." - link: "Maak aan" \ No newline at end of file + link: "Maak aan" + batch_actions: + button_label: "Batch acties" + delete_confirmation: "Weet je zeker dat je deze %{plural_model} wilt verwijderen? Er is geen undo." + succesfully_destroyed: + one: "1 %{model} verwijderd." + other: "%{count} %{plural_model} verwijderd." + selection_toggle_explanation: "(Toggle selectie)" + link: "Maak aan" + action_label: "%{title} geselecteerde" + labels: + destroy: "Verwijder" + comments: + body: "Tekst" + author: "Auteur" + title: "Reactie" + add: "Voeg commentaar toe" + resource: "Resource" + no_comments_yet: "Nog geen reacties." + title_content: "Reacties (%{count})" + errors: + empty_text: "De reactie is niet opgeslagen, de tekst was leeg." diff --git a/lib/active_admin/locales/pl.yml b/lib/active_admin/locales/pl.yml index 0f6240a207e..da380f8c081 100644 --- a/lib/active_admin/locales/pl.yml +++ b/lib/active_admin/locales/pl.yml @@ -9,7 +9,9 @@ pl: delete: "Usuń" delete_confirmation: "Jesteś pewien, że chcesz to usunąć?" new_model: "Nowy %{model}" + create_model: "Nowy %{model}" edit_model: "Edytuj %{model}" + update_model: "Edytuj %{model}" delete_model: "Usuń %{model}" details: "Detale %{model}" cancel: "Anuluj" @@ -37,4 +39,25 @@ pl: any: "Jakikolwiek" blank_slate: content: "Nie ma jeszcze zasobu %{resource_name}." - link: "Utwórz go" \ No newline at end of file + link: "Utwórz go" + batch_actions: + button_label: "Akcje na partiach" + delete_confirmation: "Czy na pewno chcesz usunąć te %{plural_model}? Nie będziesz miał możliwości cofnięcia tego." + succesfully_destroyed: + one: "Poprawnie usunięto 1 %{model}" + other: "Poprawnie usunięto %{count} %{plural_model}" + selection_toggle_explanation: "(Przełącz zaznaczenie)" + link: "Utwórz jeden" + action_label: "%{title} zaznaczone" + labels: + destroy: "Usuń" + comments: + body: "Treść" + author: "Autor" + title: "Komentarz" + add: "Dodaj komentarz" + resource: "Zasób" + no_comments_yet: "Nie ma jeszcze komentarzy." + title_content: "Komentarze (%{count})" + errors: + empty_text: "Komentarz nie został zapisany, zawartość była pusta." diff --git a/lib/active_admin/locales/sv-SE.yml b/lib/active_admin/locales/sv-SE.yml index e785e7deea1..ddc3fae0a88 100644 --- a/lib/active_admin/locales/sv-SE.yml +++ b/lib/active_admin/locales/sv-SE.yml @@ -9,7 +9,9 @@ delete: "Ta bort" delete_confirmation: "Är du säker att du vill ta bort denna?" new_model: "Ny %{model}" + create_model: "Ny %{model}" edit_model: "Editera %{model}" + update_model: "Editera %{model}" delete_model: "Ta bort %{model}" details: "Detaljvy för %{model}" cancel: "Avbryt" @@ -34,7 +36,31 @@ one: "Visar 1 utav %{model}" one_page: "Visar alla %{n} utav %{model}" multiple: "Visar %{model} %{from} - %{to} av %{total} totalt" + entry: + one: "inlägg" + other: "inlägg" any: "Någon" blank_slate: content: "Finns ingen %{resource_name} än." - link: "Skapa en" \ No newline at end of file + link: "Skapa en" + batch_actions: + button_label: "Batch Behandling" + delete_confirmation: "Är du säker på att du vill radera dessa %{plural_model}? Du kan inte ångra detta." + succesfully_destroyed: + one: "Lyckades radera 1 %{model}" + other: "Lyckades radera %{count} %{plural_model}" + selection_toggle_explanation: "(Toggle Selection)" + link: "Skapa en" + action_label: "%{title} Markerad" + labels: + destroy: "Radera" + comments: + body: "Innehåll" + author: "Författare" + title: "Kommentar" + add: "Lägg till kommentar" + resource: "Resurs" + no_comments_yet: "Inga kommentarer än." + title_content: "Kommentarer (%{count})" + errors: + empty_text: "Kommentaren sparades inte, måste innehålla text." \ No newline at end of file diff --git a/lib/active_admin/locales/vi.yml b/lib/active_admin/locales/vi.yml new file mode 100644 index 00000000000..d67d1acdc21 --- /dev/null +++ b/lib/active_admin/locales/vi.yml @@ -0,0 +1,66 @@ +vi: + active_admin: + dashboard: Dashboard + dashboard_welcome: + welcome: "Chào mừng bạn đến với Active Admin. Đây là trang Dashboard mặc định." + call_to_action: "Để thêm phần phần cho trang Dashboar hãy chỉnh sửa 'app/admin/dashboards.rb'" + view: "Xem" + edit: "Chỉnh sửa" + delete: "Xóa" + delete_confirmation: "Bạn có chắc chắn rằng mình muốn xóa cái này?" + new_model: "Tạo mới %{model}" + create_model: "Tạo mới %{model}" + edit_model: "Chỉnh sửa %{model}" + update_model: "Chỉnh sửa %{model}" + delete_model: "Xóa %{model}" + details: "%{model} Chi tiết" + cancel: "Hủy" + empty: "Trống" + previous: "Trước" + next: "Tiếp" + download: "Download:" + has_many_new: "Thêm mới %{model}" + has_many_delete: "Xóa" + filter: "Lọc" + clear_filters: "Xóa dữ liệu lọc" + search_field: "Tìm kiếm %{field}" + equal_to: "Bằng" + greater_than: "Lớn hơn" + less_than: "Nhỏ hơn" + main_content: "Xin bổ sung %{model}#main_content để hiển thị nội dung." + logout: "Đăng xuất" + sidebars: + filters: "Bộ Lọc" + pagination: + empty: "Không có %{model} nào được tìm thấy" + one: "Đang hiển thị 1 %{model}" + one_page: "Đang hiển thị tất cả %{n} %{model}" + multiple: "Đang hiển thị %{model} %{from} - %{to} of %{total} trong tất cả." + entry: + one: "entry" + other: "entries" + any: "Bất kỳ" + blank_slate: + content: "Chưa có %{resource_name}." + link: "Tạo mới" + batch_actions: + button_label: "Hành động hàng loạt" + delete_confirmation: "Bạn có chắc chắn muốn xóa những %{plural_model}? Bạn sẽ không thể lấy lại được dữ liệu." + succesfully_destroyed: + one: "Đã xóa thành công 1 %{model}" + other: "Đã xóa thành công %{count} %{plural_model}" + selection_toggle_explanation: "(Thay đổi lựa chọn)" + link: "Tạo mới" + action_label: "%{title} được chọn" + labels: + destroy: "Xóa" + comments: + body: "Nội dung" + author: "Tác giả" + title: "Bình luận" + add: "Thêm bình luận" + resource: "Tài nguyên" + no_comments_yet: "Chưa có bình luận." + title_content: "Bình luận (%{count})" + errors: + empty_text: "Lời bình luận chưa được lưu, vì nội dung còn trống." diff --git a/lib/active_admin/resource/naming.rb b/lib/active_admin/resource/naming.rb index 5619f0932de..f975c943987 100644 --- a/lib/active_admin/resource/naming.rb +++ b/lib/active_admin/resource/naming.rb @@ -29,7 +29,7 @@ def plural_resource_label if @options[:as] I18n.t(@options[:as].downcase, :scope => [:activerecord, :models], :count => 3) else - resource_name.human(:count => 3, :default => resource_label.pluralize).titleize + resource_name.human(:count => 1.1, :default => resource_label.pluralize).titleize end end end diff --git a/lib/active_admin/resource_dsl.rb b/lib/active_admin/resource_dsl.rb index fb4fa2af5e5..72e5afb5bc8 100644 --- a/lib/active_admin/resource_dsl.rb +++ b/lib/active_admin/resource_dsl.rb @@ -68,8 +68,12 @@ def form(options = {}, &block) # column("Author") { |post| post.author.full_name } # end # - def csv(&block) - config.csv_builder = CSVBuilder.new(&block) + # csv :separator => ";" do + # column :name + # end + # + def csv(options={}, &block) + config.csv_builder = CSVBuilder.new(options, &block) end # Member Actions give you the functionality of defining both the @@ -93,14 +97,20 @@ def csv(&block) # def member_action(name, options = {}, &block) config.member_actions << ControllerAction.new(name, options) + title = options.delete(:title) + controller do + before_filter(:only => [name]) { @page_title = title } if title define_method(name, &block || Proc.new{}) end end def collection_action(name, options = {}, &block) config.collection_actions << ControllerAction.new(name, options) + title = options.delete(:title) + controller do + before_filter(:only => [name]){ @page_title = title } if title define_method(name, &block || Proc.new{}) end end diff --git a/lib/active_admin/router.rb b/lib/active_admin/router.rb index 0e457351562..4907888a0d9 100644 --- a/lib/active_admin/router.rb +++ b/lib/active_admin/router.rb @@ -76,6 +76,15 @@ def apply(router) resources config.belongs_to_config.target.resource_name.plural, :only => [] do instance_eval &routes_for_belongs_to end + + # Batch action path is not nested. + if config.is_a?(Resource) + resources config.resource_name.route_key do + collection do + post :batch_action + end + end + end end end diff --git a/lib/active_admin/version.rb b/lib/active_admin/version.rb index 2beeea024fd..1264af49e0e 100644 --- a/lib/active_admin/version.rb +++ b/lib/active_admin/version.rb @@ -1,3 +1,3 @@ module ActiveAdmin - VERSION = '0.4.3' + VERSION = '0.4.4' end diff --git a/lib/active_admin/view_helpers/breadcrumb_helper.rb b/lib/active_admin/view_helpers/breadcrumb_helper.rb index 7321c91d33d..710eeb16193 100644 --- a/lib/active_admin/view_helpers/breadcrumb_helper.rb +++ b/lib/active_admin/view_helpers/breadcrumb_helper.rb @@ -2,31 +2,32 @@ module ActiveAdmin module ViewHelpers module BreadcrumbHelper - # Returns an array of links to use in a breadcrumb - def breadcrumb_links(path = nil) - path ||= request.fullpath - parts = path.gsub(/^\//, '').split('/') - parts.pop unless %w{ create update }.include?(params[:action]) - crumbs = [] - parts.each_with_index do |part, index| - name = "" - if part =~ /^\d/ && parent = parts[index - 1] - begin - parent_class = parent.singularize.camelcase.constantize - obj = parent_class.find(part.to_i) - name = obj.display_name if obj.respond_to?(:display_name) - rescue - end - end - name = part.titlecase if name == "" - begin - crumbs << link_to( I18n.translate!("activerecord.models.#{part.singularize}", :count => 2), "/" + parts[0..index].join('/')) - rescue I18n::MissingTranslationData - crumbs << link_to( name, "/" + parts[0..index].join('/')) - end - end - crumbs - end + # Returns an array of links to use in a breadcrumb + def breadcrumb_links(path = nil) + path ||= request.fullpath + parts = path.gsub(/^\//, '').split('/') + parts.pop unless %w{ create update }.include?(params[:action]) + crumbs = [] + parts.each_with_index do |part, index| + name = "" + if part =~ /^\d/ && parent = parts[index - 1] + begin + parent_class = parent.singularize.camelcase.constantize + obj = parent_class.find(part.to_i) + name = obj.display_name if obj.respond_to?(:display_name) + rescue + end + end + + name = part.titlecase if name == "" + begin + crumbs << link_to( I18n.translate!("activerecord.models.#{part.singularize}", :count => 1.1), "/" + parts[0..index].join('/')) + rescue I18n::MissingTranslationData + crumbs << link_to( name, "/" + parts[0..index].join('/')) + end + end + crumbs + end end end diff --git a/lib/active_admin/views/components/dropdown_menu.rb b/lib/active_admin/views/components/dropdown_menu.rb new file mode 100644 index 00000000000..00491e96104 --- /dev/null +++ b/lib/active_admin/views/components/dropdown_menu.rb @@ -0,0 +1,73 @@ +require 'active_admin/views/components/popover' + +module ActiveAdmin + module Views + + # Action List - A button with a drop down menu of links + # + # Creating a new action list: + # + # dropdown_menu "Administration" do + # item "Edit Details", edit_details_path + # item "Edit My Account", edit_my_acccount_path + # end + # + # This will create a button with the label "Administration" and + # a drop down once clicked with 2 options. + # + class DropdownMenu < ActiveAdmin::Component + builder_method :dropdown_menu + + # Build a new action list + # + # @param [String] name The name to display in the button + # + # @param [Hash] options A set of options that get passed along to + # to the parent dom element. + def build(name, options = {}) + options = options.dup + + # Easily set options for the button or menu + button_options = options.delete(:button) || {} + menu_options = options.delete(:menu) || {} + + @button = build_button(name, button_options) + @menu = build_menu(menu_options) + + super(options) + end + + def item(*args) + within @menu do + li link_to(*args) + end + end + + private + + def build_button(name, button_options) + button_options[:class] ||= "" + button_options[:class] << " dropdown_menu_button" + + button_options[:href] = "#" + + a name, button_options + end + + def build_menu(options) + options[:class] ||= "" + options[:class] << " dropdown_menu_list" + + menu_list = nil + + div :class => "dropdown_menu_list_wrapper", :style => "display:none;" do + menu_list = ul(options) + end + + menu_list + end + + end + + end +end diff --git a/lib/active_admin/views/components/paginated_collection.rb b/lib/active_admin/views/components/paginated_collection.rb index 090f0808d74..1c550d9b506 100644 --- a/lib/active_admin/views/components/paginated_collection.rb +++ b/lib/active_admin/views/components/paginated_collection.rb @@ -127,9 +127,11 @@ def page_entries_info(options = {}) else; I18n.t('active_admin.pagination.one_page', :model => entries_name, :n => collection.total_count) end else - offset = collection.current_page * collection.size + size = collection.size + size = size.size if size.kind_of? Hash # when GROUP BY is used, AR returns Hash instead of Fixnum for .size + offset = collection.current_page * size total = collection.total_count - I18n.t('active_admin.pagination.multiple', :model => entries_name, :from => (offset - collection.size + 1), :to => offset > total ? total : offset, :total => total) + I18n.t('active_admin.pagination.multiple', :model => entries_name, :from => (offset - size + 1), :to => offset > total ? total : offset, :total => total) end end diff --git a/lib/active_admin/views/components/popover.rb b/lib/active_admin/views/components/popover.rb index c8858360cad..b0bb147cbac 100644 --- a/lib/active_admin/views/components/popover.rb +++ b/lib/active_admin/views/components/popover.rb @@ -1,34 +1,27 @@ module ActiveAdmin module Views - # Build a Popover + class Popover < ActiveAdmin::Component builder_method :popover - - def default_class_name - 'popover' - end - + def build(options = {}, &block) - - self.id = options[:id] - + options = options.dup + contents_root_tag = options.delete(:contents_root_tag) || :div + options[:style] = "display: none" + super(options) - - @contents ||= div(:class => "popover_contents") - - # Hide the popover by default - - attributes[:style] = "display: none" + + @contents_root = send(contents_root_tag, :class => "popover_contents") end - + def add_child(child) - if @contents - @contents << child + if @contents_root + @contents_root << child else super end end - + end end end diff --git a/lib/active_admin/views/dashboard_section_renderer.rb b/lib/active_admin/views/dashboard_section_renderer.rb index 268ca75878a..95512a5b187 100644 --- a/lib/active_admin/views/dashboard_section_renderer.rb +++ b/lib/active_admin/views/dashboard_section_renderer.rb @@ -11,8 +11,11 @@ def build(section) protected def title - translated_name = I18n.t("active_admin.dashboard_sections.#{@section.name}", :default => @section.name) - translated_name.to_s.titleize + begin + I18n.t!("active_admin.sections.#{@section.name.to_s}") + rescue I18n::MissingTranslationData + @section.name.to_s.titleize + end end end diff --git a/lib/active_admin/views/pages/base.rb b/lib/active_admin/views/pages/base.rb index 323d429fee6..77c85e8a8a3 100644 --- a/lib/active_admin/views/pages/base.rb +++ b/lib/active_admin/views/pages/base.rb @@ -15,6 +15,7 @@ def build(*args) def add_classes_to_body @body.add_class(params[:action]) @body.add_class(params[:controller].gsub('/', '_')) + @body.add_class("active_admin") @body.add_class("logged_in") @body.add_class(active_admin_namespace.name.to_s + "_namespace") end @@ -41,7 +42,6 @@ def build_page build_page_content build_footer end - build_extra_content end end @@ -128,10 +128,6 @@ def build_footer insert_tag view_factory.footer end - def build_extra_content - # Put popovers, etc here - end - end end end diff --git a/lib/active_admin/views/pages/form.rb b/lib/active_admin/views/pages/form.rb index e05fe2b63f2..05c303fc9ec 100644 --- a/lib/active_admin/views/pages/form.rb +++ b/lib/active_admin/views/pages/form.rb @@ -41,7 +41,6 @@ def default_form_path def default_form_config ActiveAdmin::PagePresenter.new do |f| f.inputs - #f.buttons f.actions end end diff --git a/lib/active_admin/views/pages/index.rb b/lib/active_admin/views/pages/index.rb index 121c34d88fb..df635679116 100644 --- a/lib/active_admin/views/pages/index.rb +++ b/lib/active_admin/views/pages/index.rb @@ -5,7 +5,11 @@ module Pages class Index < Base def title - active_admin_config.plural_resource_label + if config[:title].is_a? String + config[:title] + else + active_admin_config.plural_resource_label + end end def config @@ -15,12 +19,7 @@ def config # Render's the index configuration that was set in the # controller. Defaults to rendering the ActiveAdmin::Pages::Index::Table def main_content - if active_admin_config.batch_actions.any? - batch_action_form do - build_table_tools - build_collection - end - else + wrap_with_batch_action_form do build_table_tools build_collection end @@ -28,8 +27,12 @@ def main_content protected - def build_extra_content - build_batch_action_popover + def wrap_with_batch_action_form(&block) + if active_admin_config.batch_actions.any? + batch_action_form(&block) + else + block.call + end end def items_in_collection? @@ -65,22 +68,14 @@ def build_download_format_links(formats = [:csv, :xml, :json]) def build_table_tools div :class => "table_tools" do - - if active_admin_config.batch_actions.any? - a :class => 'table_tools_button dropdown_button disabled', :href => "#batch_actions_popover", :id => "batch_actions_button" do - text_node I18n.t("active_admin.batch_actions.button_label") - end - end - + build_batch_actions_selector build_scopes end end - def build_batch_action_popover - insert_tag view_factory.batch_action_popover do - active_admin_config.batch_actions.each do |the_action| - action the_action if call_method_or_proc_on(self, the_action.display_if_block) - end + def build_batch_actions_selector + if active_admin_config.batch_actions.any? + insert_tag view_factory.batch_action_selector, active_admin_config.batch_actions end end diff --git a/lib/active_admin/views/pages/show.rb b/lib/active_admin/views/pages/show.rb index 8c44fe25473..e6ca456fc98 100644 --- a/lib/active_admin/views/pages/show.rb +++ b/lib/active_admin/views/pages/show.rb @@ -36,7 +36,13 @@ def attributes_table(*args, &block) protected def default_title - "#{active_admin_config.resource_label} ##{resource.id}" + title = display_name(resource) + + if title.nil? || title.empty? || title == resource.to_s + title = "#{active_admin_config.resource_label} ##{resource.id}" + end + + title end module DefaultMainContent diff --git a/lib/generators/active_admin/assets/assets_generator.rb b/lib/generators/active_admin/assets/assets_generator.rb index 2e558cc0a65..1ffcc1579a9 100644 --- a/lib/generators/active_admin/assets/assets_generator.rb +++ b/lib/generators/active_admin/assets/assets_generator.rb @@ -20,7 +20,7 @@ def install_assets template '3.1/active_admin.js', 'app/assets/javascripts/active_admin.js' template '3.1/active_admin.css.scss', 'app/assets/stylesheets/active_admin.css.scss' else - template '../../../../../app/assets/javascripts/active_admin/application.js', 'public/javascripts/active_admin.js' + template '3.0/active_admin.js', 'public/javascripts/active_admin.js' directory '../../../../../app/assets/images/active_admin', 'public/images/active_admin' generate "jquery:install --ui" if options.jquery? install_bourbon if options.bourbon? diff --git a/lib/generators/active_admin/assets/templates/3.0/active_admin.js b/lib/generators/active_admin/assets/templates/3.0/active_admin.js new file mode 100644 index 00000000000..469c7926420 --- /dev/null +++ b/lib/generators/active_admin/assets/templates/3.0/active_admin.js @@ -0,0 +1 @@ +(function(){window.AA={}}).call(this),function(){window.AA.CheckboxToggler=AA.CheckboxToggler=function(){function a(a,b){var c;this.options=a,this.container=b,c={},this.options=$.extend({},c,a),this._init(),this._bind()}return a.name="CheckboxToggler",a.prototype._init=function(){if(!this.container)throw new Error("Container element not found");this.$container=$(this.container);if(!this.$container.find(".toggle_all").length)throw new Error("'toggle all' checkbox not found");return this.toggle_all_checkbox=this.$container.find(".toggle_all"),this.checkboxes=this.$container.find(":checkbox").not(this.toggle_all_checkbox)},a.prototype._bind=function(){var a=this;return this.checkboxes.bind("change",function(b){return a._didChangeCheckbox(b.target)}),this.toggle_all_checkbox.bind("change",function(b){return a._didChangeToggleAllCheckbox()})},a.prototype._didChangeCheckbox=function(a){if(this.checkboxes.filter(":checked").length===this.checkboxes.length-1)return this._uncheckToggleAllCheckbox();if(this.checkboxes.filter(":checked").length===this.checkboxes.length)return this._checkToggleAllCheckbox()},a.prototype._didChangeToggleAllCheckbox=function(){return this.toggle_all_checkbox.attr("checked")==="checked"?this._checkAllCheckboxes():this._uncheckAllCheckboxes()},a.prototype._uncheckToggleAllCheckbox=function(){return this.toggle_all_checkbox.removeAttr("checked")},a.prototype._checkToggleAllCheckbox=function(){return this.toggle_all_checkbox.attr("checked","checked")},a.prototype._uncheckAllCheckboxes=function(){var a=this;return this.checkboxes.each(function(b,c){return $(c).removeAttr("checked"),a._didChangeCheckbox(c)})},a.prototype._checkAllCheckboxes=function(){var a=this;return this.checkboxes.each(function(b,c){return $(c).attr("checked","checked"),a._didChangeCheckbox(c)})},a}(),function(a){return a.widget.bridge("checkboxToggler",AA.CheckboxToggler)}(jQuery)}.call(this),function(){window.AA.DropdownMenu=AA.DropdownMenu=function(){function a(a,b){var c;return this.options=a,this.element=b,this.$element=$(this.element),c={fadeInDuration:20,fadeOutDuration:100,onClickActionItemCallback:null},this.options=$.extend({},c,a),this.$menuButton=this.$element.find(".dropdown_menu_button"),this.$menuList=this.$element.find(".dropdown_menu_list_wrapper"),this.isOpen=!1,this._buildMenuList(),this._bind(),this}return a.name="DropdownMenu",a.prototype.open=function(){return this.isOpen=!0,this.$menuList.fadeIn(this.options.fadeInDuration),this._positionMenuList(),this._positionNipple(),this},a.prototype.close=function(){return this.isOpen=!1,this.$menuList.fadeOut(this.options.fadeOutDuration),this},a.prototype.destroy=function(){return this.$element.unbind(),this.$element=null,this},a.prototype.isDisabled=function(){return this.$menuButton.hasClass("disabled")},a.prototype.disable=function(){return this.$menuButton.addClass("disabled")},a.prototype.enable=function(){return this.$menuButton.removeClass("disabled")},a.prototype.option=function(a,b){return $.isPlainObject(a)?this.options=$.extend(!0,this.options,a):a!=null?this.options[a]:this.options[a]=b},a.prototype._buildMenuList=function(){return this.$menuList.prepend(''),this.$menuList.hide()},a.prototype._bind=function(){var a=this;return $("body").bind("click",function(){if(a.isOpen===!0)return a.close()}),this.$menuButton.bind("click",function(){return a.isDisabled()||(a.isOpen===!0?a.close():a.open()),!1})},a.prototype._positionMenuList=function(){var a,b,c;return a=this.$menuButton.offset().left+this.$menuButton.outerWidth()/2,b=this.$menuList.outerWidth()/2,c=a-b,this.$menuList.css("left",c)},a.prototype._positionNipple=function(){var a,b,c,d,e;return c=this.$menuList.outerWidth()/2,b=this.$menuButton.offset().top+this.$menuButton.outerHeight()+10,this.$menuList.css("top",b),a=this.$menuList.find(".dropdown_menu_nipple"),d=a.outerWidth()/2,e=c-d,a.css("left",e)},a}(),function(a){return a.widget.bridge("aaDropdownMenu",AA.DropdownMenu),a(function(){return a(".dropdown_menu").aaDropdownMenu()})}(jQuery)}.call(this),function(){window.AA.Popover=AA.Popover=function(){function a(a,b){var c;return this.options=a,this.element=b,this.$element=$(this.element),c={fadeInDuration:20,fadeOutDuration:100,autoOpen:!0,pageWrapperElement:"#wrapper",onClickActionItemCallback:null},this.options=$.extend({},c,a),this.$popover=null,this.isOpen=!1,$(this.$element.attr("href")).length>0?this.$popover=$(this.$element.attr("href")):this.$popover=this.$element.next(".popover"),this._buildPopover(),this._bind(),this}return a.name="Popover",a.prototype.open=function(){return this.isOpen=!0,this.$popover.fadeIn(this.options.fadeInDuration),this._positionPopover(),this._positionNipple(),this},a.prototype.close=function(){return this.isOpen=!1,this.$popover.fadeOut(this.options.fadeOutDuration),this},a.prototype.destroy=function(){return this.$element.removeData("popover"),this.$element.unbind(),this.$element=null,this},a.prototype.option=function(){},a.prototype._buildPopover=function(){return this.$popover.prepend('
'),this.$popover.hide(),this.$popover.addClass("popover")},a.prototype._bind=function(){var a=this;$(this.options.pageWrapperElement).bind("click",function(b){if(a.isOpen===!0)return a.close()});if(this.options.autoOpen===!0)return this.$element.bind("click",function(){return a.isOpen===!0?a.close():a.open(),!1})},a.prototype._positionPopover=function(){var a,b,c;return a=this.$element.offset().left+this.$element.outerWidth()/2,b=this.$popover.outerWidth()/2,c=a-b,this.$popover.css("left",c)},a.prototype._positionNipple=function(){var a,b,c,d,e;return c=this.$popover.outerWidth()/2,b=this.$element.offset().top+this.$element.outerHeight()+10,this.$popover.css("top",b),a=this.$popover.find(".popover_nipple"),d=a.outerWidth()/2,e=c-d,a.css("left",e)},a}(),function(a){return a.widget.bridge("popover",AA.Popover)}(jQuery)}.call(this),function(){var a={}.hasOwnProperty,b=function(b,c){function e(){this.constructor=b}for(var d in c)a.call(c,d)&&(b[d]=c[d]);return e.prototype=c.prototype,b.prototype=new e,b.__super__=c.prototype,b};window.AA.TableCheckboxToggler=AA.TableCheckboxToggler=function(a){function c(){return c.__super__.constructor.apply(this,arguments)}return b(c,a),c.name="TableCheckboxToggler",c.prototype._init=function(){return c.__super__._init.apply(this,arguments)},c.prototype._bind=function(){var a=this;return c.__super__._bind.apply(this,arguments),this.$container.find("tbody").find("td").bind("click",function(b){if(b.target.type!=="checkbox")return a._didClickCell(b.target)})},c.prototype._didChangeCheckbox=function(a){var b;return c.__super__._didChangeCheckbox.apply(this,arguments),b=$(a).parents("tr"),a.checked?b.addClass("selected"):b.removeClass("selected")},c.prototype._didClickCell=function(a){return $(a).parent("tr").find(":checkbox").click()},c}(AA.CheckboxToggler),function(a){return a.widget.bridge("tableCheckboxToggler",AA.TableCheckboxToggler)}(jQuery)}.call(this),function(){$(function(){return $(".datepicker").datepicker({dateFormat:"yy-mm-dd"}),$(".clear_filters_btn").click(function(){return window.location.search="",!1}),$(".dropdown_button").popover()})}.call(this),function(){jQuery(function(a){a(document).delegate("#batch_actions_selector li a","click.rails",function(){return a("#batch_action").val(a(this).attr("data-action")),a("#collection_selection").submit()});if(a("#batch_actions_selector").length&&a(":checkbox.toggle_all").length)return a(".paginated_collection").find("table.index_table").length?a(".paginated_collection table").tableCheckboxToggler():a(".paginated_collection").checkboxToggler(),a(".paginated_collection").find(":checkbox").bind("change",function(){return a(".paginated_collection").find(":checkbox").filter(":checked").length>0?a("#batch_actions_selector").aaDropdownMenu("enable"):a("#batch_actions_selector").aaDropdownMenu("disable")})})}.call(this); \ No newline at end of file diff --git a/lib/generators/active_admin/assets/templates/3.1/active_admin.css.scss b/lib/generators/active_admin/assets/templates/3.1/active_admin.css.scss index 9b2dc9d7f53..80d4710799b 100644 --- a/lib/generators/active_admin/assets/templates/3.1/active_admin.css.scss +++ b/lib/generators/active_admin/assets/templates/3.1/active_admin.css.scss @@ -1,6 +1,29 @@ -// Active Admin CSS Styles +// SASS variable overrides must be declared before loading up Active Admin's styles. +// +// To view the variables that Active Admin provides, take a look at +// `app/assets/stylesheets/active_admin/mixins/_variables.css.scss` in the +// Active Admin source. +// +// For example, to change the sidebar width: +// $sidebar-width: 242px; + +// Active Admin's got SASS! @import "active_admin/mixins"; @import "active_admin/base"; -// To customize the Active Admin interfaces, add your -// styles here: +// Overriding any non-variable SASS must be done after the fact. +// For example, to change the default status-tag color: +// +// body.active_admin { +// .status { background: #6090DB; } +// } +// +// Notice that Active Admin CSS rules are nested within a +// 'body.active_admin' selector to prevent conflicts with +// other pages in the app. It is best to wrap your changes in a +// namespace so they are properly recognized. You have options +// if you e.g. want different styles for different namespaces: +// +// .active_admin applies to any Active Admin namespace +// .admin_namespace applies to the admin namespace (eg: /admin) +// .other_namespace applies to a custom namespace named other (eg: /other) diff --git a/lib/generators/active_admin/install/templates/active_admin.rb.erb b/lib/generators/active_admin/install/templates/active_admin.rb.erb index 075b7a50b96..45906edb000 100644 --- a/lib/generators/active_admin/install/templates/active_admin.rb.erb +++ b/lib/generators/active_admin/install/templates/active_admin.rb.erb @@ -104,6 +104,14 @@ ActiveAdmin.setup do |config| # end + # == Batch Actions + # + # Enable and disable Batch Actions + # + # Default: + # config.batch_actions = true + + # == Controller Filters # # You can add before, after and around filters to all of your diff --git a/spec/javascripts/coffeescripts/jquery.aa.checkbox-toggler-spec.js.coffee b/spec/javascripts/coffeescripts/jquery.aa.checkbox-toggler-spec.js.coffee index dd4106582cf..755761caba1 100644 --- a/spec/javascripts/coffeescripts/jquery.aa.checkbox-toggler-spec.js.coffee +++ b/spec/javascripts/coffeescripts/jquery.aa.checkbox-toggler-spec.js.coffee @@ -1,7 +1,7 @@ describe "AA.CheckboxToggler", -> beforeEach -> - loadFixtures('checkboxes.html'); + loadFixtures('checkboxes.html') @collection = $("#collection") @toggle_all = @collection.find(".toggle_all") diff --git a/spec/support/detect_rails_version.rb b/spec/support/detect_rails_version.rb index 5e894b95c9f..6146bb3129f 100644 --- a/spec/support/detect_rails_version.rb +++ b/spec/support/detect_rails_version.rb @@ -1,8 +1,6 @@ # Detects the current version of Rails that is being used # -# You can pass it in as an ENV variable or it will use -# the current Gemfile.lock to find it - +# unless defined?(RAILS_VERSION_FILE) RAILS_VERSION_FILE = File.expand_path("../../../.rails-version", __FILE__) end @@ -12,16 +10,24 @@ end def detect_rails_version - detected_version = if File.exists?(RAILS_VERSION_FILE) + version = version_from_file || version_from_env || DEFAULT_RAILS_VERSION + + puts "Detected Rails: #{version}" if ENV['DEBUG'] + + version +end + +def version_from_file + if File.exists?(RAILS_VERSION_FILE) version = File.read(RAILS_VERSION_FILE).chomp.strip - version != "" ? version : DEFAULT_RAILS_VERSION - else - DEFAULT_RAILS_VERSION - end + version = nil if version == "" - puts "Detected Rails: #{detected_version}" if ENV['DEBUG'] + version + end +end - detected_version +def version_from_env + ENV['RAILS'] end def write_rails_version(version) diff --git a/spec/support/rails_template.rb b/spec/support/rails_template.rb index 0ce46b60161..952bc783d4b 100644 --- a/spec/support/rails_template.rb +++ b/spec/support/rails_template.rb @@ -11,6 +11,8 @@ # Generate some test models generate :model, "post title:string body:text published_at:datetime author_id:integer category_id:integer" inject_into_file 'app/models/post.rb', " belongs_to :author, :class_name => 'User'\n belongs_to :category\n accepts_nested_attributes_for :author\n", :after => "class Post < ActiveRecord::Base\n" +# Rails 3.2.3 model generator declare attr_accessible +inject_into_file 'app/models/post.rb', " attr_accessible :author\n", :before => "end" if Rails::VERSION::STRING >= '3.2.3' generate :model, "user type:string first_name:string last_name:string username:string age:integer" inject_into_file 'app/models/user.rb', " has_many :posts, :foreign_key => 'author_id'\n", :after => "class User < ActiveRecord::Base\n" generate :model, "publisher --migration=false --parent=User" diff --git a/spec/unit/action_builder_spec.rb b/spec/unit/action_builder_spec.rb index f72ebf06689..25fcaecad74 100644 --- a/spec/unit/action_builder_spec.rb +++ b/spec/unit/action_builder_spec.rb @@ -44,6 +44,18 @@ controller.public_instance_methods.collect(&:to_s).should include("comment") end end + + context "with :title" do + let(:action!) do + ActiveAdmin.register Post do + member_action :comment, :title => "My Awesome Comment" + end + end + + subject { find_before_filter controller, :comment } + + it { should set_page_title_to "My Awesome Comment" } + end end describe "generate a new collection action" do @@ -83,6 +95,32 @@ controller.public_instance_methods.collect(&:to_s).should include("comments") end end + context "with :title" do + let(:action!) do + ActiveAdmin.register Post do + collection_action :comments, :title => "My Awesome Comments" + end + end + + subject { find_before_filter controller, :comments } + + it { should set_page_title_to "My Awesome Comments" } + end + end + + def find_before_filter(controller, action) + controller._process_action_callbacks.detect { |f| f.kind == :before && f.options[:only] == [action] } end + RSpec::Matchers.define :set_page_title_to do |expected| + match do |filter| + filter.raw_filter.call + @actual = filter.klass.instance_variable_get(:@page_title) + @actual == expected + end + + failure_message_for_should do |filter| + message = "expected before_filter to set the @page_title to '#{expected}', but was '#{@actual}'" + end + end end diff --git a/spec/unit/batch_actions/settings_spec.rb b/spec/unit/batch_actions/settings_spec.rb new file mode 100644 index 00000000000..fcc992b16c3 --- /dev/null +++ b/spec/unit/batch_actions/settings_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe "Batch Actions Settings" do + let(:app) { ActiveAdmin::Application.new } + let(:ns) { ActiveAdmin::Namespace.new(app, "Admin") } + let(:post_resource) { ns.register Post } + + it "should be enabled globally by default" do + app.batch_actions.should be_true + ns.batch_actions.should be_true + post_resource.batch_actions.should be_true + end + + it "should be settable to false" do + app.batch_actions = false + app.batch_actions.should == false + end + + it "should be an inheritable_setting" do + app.batch_actions = false + ns.batch_actions.should == false + end + + it "should be settable at the namespace level" do + app.batch_actions = false + ns.batch_actions = true + + app.batch_actions.should == false + ns.batch_actions.should == true + end + + it "should be settable at the resource level" do + post_resource.batch_actions_enabled?.should == true + post_resource.batch_actions = false + post_resource.batch_actions_enabled?.should == false + end + + it "should inherit the setting on the resource from the namespace" do + ns.batch_actions = false + post_resource.batch_actions_enabled?.should == false + post_resource.batch_actions.should be_empty + + post_resource.batch_actions = true + post_resource.batch_actions_enabled?.should == true + post_resource.batch_actions.should_not be_empty + end + + it "should inherit the setting from the namespace when set to nil" do + post_resource.batch_actions = false + post_resource.batch_actions_enabled?.should == false + post_resource.batch_actions.should be_empty + + post_resource.batch_actions = nil + post_resource.batch_actions_enabled?.should == true # inherited from namespace + post_resource.batch_actions.should_not be_empty + end +end diff --git a/spec/unit/comments_spec.rb b/spec/unit/comments_spec.rb index 9f05d708650..babdc9d9d98 100644 --- a/spec/unit/comments_spec.rb +++ b/spec/unit/comments_spec.rb @@ -4,7 +4,13 @@ let(:application){ ActiveAdmin::Application.new } describe ActiveAdmin::Comment do + subject { ActiveAdmin::Comment } + describe "Associations and Validations" do + before do + pending "This is not passing on Travis-CI. See Issue #1273." + end + it { should belong_to :resource } it { should belong_to :author } diff --git a/spec/unit/csv_builder_spec.rb b/spec/unit/csv_builder_spec.rb index aca35ef7555..5a964788cb6 100644 --- a/spec/unit/csv_builder_spec.rb +++ b/spec/unit/csv_builder_spec.rb @@ -37,7 +37,7 @@ end end - it "should have one colum" do + it "should have one column" do builder.columns.size.should == 1 end @@ -63,7 +63,7 @@ end end - it "should have one colum" do + it "should have one column" do builder.columns.size.should == 1 end @@ -80,4 +80,14 @@ end end + context "with a separator" do + let(:builder) do + ActiveAdmin::CSVBuilder.new :separator => ";" + end + + it "should have proper separator" do + builder.column_separator.should == ";" + end + end + end diff --git a/spec/unit/resource_controller_spec.rb b/spec/unit/resource_controller_spec.rb index b268e3917cd..666a38a2ad2 100644 --- a/spec/unit/resource_controller_spec.rb +++ b/spec/unit/resource_controller_spec.rb @@ -3,6 +3,8 @@ describe ActiveAdmin::ResourceController do + before(:all) { load_defaults! } + let(:controller) { ActiveAdmin::ResourceController.new } it_should_behave_like "BaseController" diff --git a/spec/unit/views/components/paginated_collection_spec.rb b/spec/unit/views/components/paginated_collection_spec.rb index 944baf6e7d3..6e90d1e731d 100644 --- a/spec/unit/views/components/paginated_collection_spec.rb +++ b/spec/unit/views/components/paginated_collection_spec.rb @@ -150,7 +150,7 @@ context "when collection comes from find with GROUP BY" do let(:collection) do %w{Foo Foo Bar}.each {|title| Post.create(:title => title) } - Post.group(:title).page(1).per(5) + Post.select(:title).group(:title).page(1).per(5) end let(:pagination) { paginated_collection(collection) } @@ -159,5 +159,21 @@ pagination.find_by_class('pagination_information').first.content.should == "Displaying all 2 posts" end end + + context "when collection with many pages comes from find with GROUP BY" do + let(:collection) do + %w{Foo Foo Bar Baz}.each {|title| Post.create(:title => title) } + Post.select(:title).group(:title).page(1).per(2) + end + + let(:pagination) { paginated_collection(collection) } + + it "should display proper message (including number and not hash)" do + pagination.find_by_class('pagination_information').first.content. + gsub(' ',' ').should == "Displaying posts 1 - 2 of 3 in total" + end + end + + end end diff --git a/spec/unit/views/pages/layout_spec.rb b/spec/unit/views/pages/layout_spec.rb index 2c8027b523c..f8188abb22e 100644 --- a/spec/unit/views/pages/layout_spec.rb +++ b/spec/unit/views/pages/layout_spec.rb @@ -19,4 +19,44 @@ end + describe "the body" do + + let(:active_admin_namespace){ ActiveAdmin::Namespace.new(ActiveAdmin::Application.new, :myspace) } + let(:active_admin_application){ ActiveAdmin.application } + let(:view_factory) { ActiveAdmin::ViewFactory.new } + + before(:each) do + @assigns = {} + @helpers = mock('Helpers', + :active_admin_application => active_admin_application, + :active_admin_config => mock('Config', :action_items? => nil, :sidebar_sections? => nil), + :active_admin_namespace => active_admin_namespace, + :breadcrumb_links => [], + :content_for => "", + :csrf_meta_tag => "", + :current_active_admin_user => nil, + :current_active_admin_user? => false, + :current_menu => mock('Menu', :items => []), + :flash => {}, + :javascript_path => "/dummy/", + :link_to => "", + :render_or_call_method_or_proc_on => "", + :stylesheet_link_tag => mock(:html_safe => ""), + :view_factory => view_factory, + :params => {:controller => 'UsersController', :action => 'edit'}) + end + + + it "should have class 'active_admin'" do + layout = ActiveAdmin::Views::Pages::Layout.new(@assigns, @helpers) + layout.build.class_list.should include 'active_admin' + end + + it "should have namespace class" do + layout = ActiveAdmin::Views::Pages::Layout.new(@assigns, @helpers) + layout.build.class_list.should include "#{active_admin_namespace.name}_namespace" + end + + end + end diff --git a/tasks/js.rake b/tasks/js.rake new file mode 100644 index 00000000000..e292d7f373b --- /dev/null +++ b/tasks/js.rake @@ -0,0 +1,32 @@ +namespace :js do + + desc "Compile the JS for Rails apps without Asset Pipeline" + task :compile do + require 'sprockets' + require 'uglifier' + require 'fileutils' + + root_dir = File.expand_path(File.join("..", ".."), __FILE__) + js_dir = File.join(root_dir, "app", "assets", "javascripts", "active_admin") + generated_file = File.join(root_dir, 'lib', 'generators', 'active_admin', 'assets', 'templates', '3.0', 'active_admin.js') + + # The base.js file requires jquery. We don't need jquery to + # compile the assets, however Sprockets will try to look it up + # and raise an exception. Insteaad, we move the file out of the directory + # then put it back after we compile. + base_js = File.join(js_dir, "base.js") + tmp_base_js = File.join(root_dir, "base.js") + FileUtils.mv base_js, tmp_base_js + + env = Sprockets::Environment.new + env.js_compressor = ::Uglifier.new + env.append_path js_dir + + File.open generated_file, "w+" do |f| + f << env["application"] + end + + FileUtils.mv tmp_base_js, base_js + end + +end diff --git a/tasks/test.rake b/tasks/test.rake index 96d16845cd2..ff30d775952 100644 --- a/tasks/test.rake +++ b/tasks/test.rake @@ -29,7 +29,7 @@ namespace :test do desc "Run the full suite against the important versions of rails" task :major_supported_rails do - run_tests_against "3.0.11", "3.1.3", "3.2.0" + run_tests_against "3.0.12", "3.1.4", "3.2.3" end desc "Alias for major_supported_rails"