├── Rakefile ├── lib ├── active_admin_date_range_preset │ └── version.rb └── active_admin_date_range_preset.rb ├── screen ├── step_1.jpg ├── step_2.jpg ├── step_2_1.png └── step_2_2.png ├── Gemfile ├── .idea └── vcs.xml ├── vendor └── assets │ ├── stylesheets │ └── active_admin_date_range_preset.scss │ └── javascripts │ └── active_admin_date_range_preset.js ├── LICENSE.txt ├── active_admin_date_range_preset.gemspec ├── package.json └── README.md /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /lib/active_admin_date_range_preset/version.rb: -------------------------------------------------------------------------------- 1 | module ActiveAdminDateRangePreset 2 | VERSION = "0.3.1" 3 | end 4 | -------------------------------------------------------------------------------- /screen/step_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activeadmin-plugins/active_admin_date_range_preset/HEAD/screen/step_1.jpg -------------------------------------------------------------------------------- /screen/step_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activeadmin-plugins/active_admin_date_range_preset/HEAD/screen/step_2.jpg -------------------------------------------------------------------------------- /screen/step_2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activeadmin-plugins/active_admin_date_range_preset/HEAD/screen/step_2_1.png -------------------------------------------------------------------------------- /screen/step_2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activeadmin-plugins/active_admin_date_range_preset/HEAD/screen/step_2_2.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in active_admin_date_range_preset.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /lib/active_admin_date_range_preset.rb: -------------------------------------------------------------------------------- 1 | require "activeadmin" 2 | require "active_admin_date_range_preset/version" 3 | 4 | module ActiveAdminDateRangePreset 5 | module Rails 6 | class Engine < ::Rails::Engine 7 | 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/active_admin_date_range_preset.scss: -------------------------------------------------------------------------------- 1 | form label.datetime_preset_filter_label .btn_timerange { 2 | float: right; 3 | margin: -2px 8px 0 0; 4 | text-decoration: none; 5 | border-bottom: 1px dashed; 6 | line-height: 1.4em; 7 | &:hover { 8 | border-bottom: 0 none; 9 | } 10 | } 11 | 12 | .block_timerange { 13 | position: absolute; 14 | display: block; 15 | border: 1px solid #000; 16 | padding: 5px 10px 5px 10px; 17 | text-align: center; 18 | background-color: #f4f4f4; 19 | >div { 20 | margin-top: 10px; 21 | &:last-child { 22 | margin-bottom: 10px; 23 | } 24 | span { 25 | color: #2e86cc; 26 | cursor: pointer; 27 | text-decoration: none; 28 | font-size: 14px; 29 | border-bottom: 1px dashed; 30 | &:hover { 31 | border-bottom: 0 none; 32 | } 33 | } 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Igor Fedoronchuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /active_admin_date_range_preset.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'active_admin_date_range_preset/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "active_admin_date_range_preset" 8 | spec.version = ActiveAdminDateRangePreset::VERSION 9 | spec.authors = ["Gena M."] 10 | spec.email = ["workgena@gmail.com"] 11 | 12 | spec.summary = %q{date_range_preset extension for ActiveAdmin} 13 | spec.description = %q{Integrate useful fast links to set date ranges in to ActiveAdmin, for example today range, week range, month range} 14 | spec.homepage = "https://github.com/workgena/active_admin_date_range_preset" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 18 | spec.bindir = "bin" 19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_development_dependency "bundler", "~> 1.8" 23 | spec.add_development_dependency "rake", "~> 10.0" 24 | end 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@activeadmin-plugins/active_admin_date_range_preset", 3 | "version": "0.3.1", 4 | "description": "Integrate useful fast links to set date ranges in to ActiveAdmin, for example today range, week range, month range", 5 | "main": "src/active_admin_date_range_preset.js", 6 | "style": "src/active_admin_date_range_preset.scss", 7 | "repository": "git@github.com:activeadmin-plugins/active_admin_date_range_preset.git", 8 | "author": "Gena M. ", 9 | "license": "MIT", 10 | "private": false, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/activeadmin-plugins/active_admin_date_range_preset.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/activeadmin-plugins/active_admin_date_range_preset/issues" 17 | }, 18 | "homepage": "https://github.com/activeadmin-plugins/active_admin_date_range_preset#readme", 19 | "keywords": [ 20 | "active", 21 | "admin", 22 | "date", 23 | "range", 24 | "preset" 25 | ], 26 | "files": [ 27 | "src/**/*" 28 | ], 29 | "scripts": { 30 | "prepublishOnly": "rm -rf src && cp -R vendor/assets/javascripts/ src && cp -R vendor/assets/stylesheets/ src" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gem Version](https://badge.fury.io/rb/active_admin_date_range_preset.svg)](https://badge.fury.io/rb/active_admin_date_range_preset) 2 | [![NPM Version](https://badge.fury.io/js/@activeadmin-plugins%2Factive_admin_date_range_preset.svg)](https://badge.fury.io/js/@activeadmin-plugins%2Factive_admin_date_range_preset) 3 | ![npm](https://img.shields.io/npm/dm/@activeadmin-plugins/active_admin_date_range_preset) 4 | 5 | # active_admin_date_range_preset 6 | 7 | Preset links for ActiveAdmin date_range inputs in sidebar filters in forms 8 | 9 | This is how it looks like 10 | 11 | ![Step 1](/screen/step_1.jpg) 12 | 13 | ![Step 2](/screen/step_2.jpg) 14 | 15 | ![Form 1](/screen/step_2_1.png) 16 | 17 | ![Form 2](/screen/step_2_2.png) 18 | 19 | ## Installation 20 | 21 | Add this line to your application's Gemfile: 22 | 23 | ```ruby 24 | gem 'active_admin_date_range_preset' 25 | ``` 26 | 27 | And then execute: 28 | 29 | $ bundle install 30 | 31 | Or install it yourself as: 32 | 33 | $ gem install active_admin_date_range_preset 34 | 35 | ##### Using assets via Sprockets 36 | 37 | JS asset 38 | ```//= require active_admin_date_range_preset``` 39 | 40 | CSS 41 | ```@import "active_admin_date_range_preset";``` 42 | 43 | ##### Using assets via Webpacker (or any other assets bundler) as a NPM module (Yarn package) 44 | 45 | Execute: 46 | 47 | $ npm i @activeadmin-plugins/active_admin_date_range_preset 48 | 49 | Or 50 | 51 | $ yarn add @activeadmin-plugins/active_admin_date_range_preset 52 | 53 | Or add manually to `package.json`: 54 | 55 | ```json 56 | "dependencies": { 57 | "@activeadmin-plugins/active_admin_date_range_preset": "0.3.1" 58 | } 59 | ``` 60 | and execute: 61 | 62 | $ yarn 63 | 64 | Add the following line into `app/assets/javascripts/active_admin.js`: 65 | 66 | ```javascript 67 | import '@activeadmin-plugins/active_admin_date_range_preset'; 68 | ``` 69 | 70 | Add the following line into `app/assets/stylesheets/active_admin.scss`: 71 | 72 | ```css 73 | @import '@activeadmin-plugins/active_admin_date_range_preset'; 74 | ``` 75 | 76 | Your sidebar filters should now have link "Set Range" 77 | 78 | ## Usage 79 | 80 | in New/Edit formtastic forms: 81 | 82 | ```ruby 83 | f.input :date_from, as: :date_time_picker, wrapper_html: { class: 'datetime_preset_pair', data: { show_time: 'true' } } 84 | f.input :date_to, as: :date_time_picker 85 | ``` 86 | 87 | Input can be "as :string" or any other type compatible with "input type=text" 88 | Main point is to set for first input-pair wrapper-class 89 | 90 | ```wrapper_html: { class: 'datetime_preset_pair' }``` 91 | 92 | input name('date_from' and 'date_to') can be named whatever your need 93 | 94 | By default inputs are filled with date("yyyy-mm-dd"). If you need time add 95 | 96 | ```data: { show_time: 'true' }``` 97 | 98 | 99 | ## Using with ActiveAdminDatetimepicker 100 | 101 | If you use GEM https://github.com/activeadmin-plugins/active_admin_datetimepicker 102 | and want apply this plugin to filter-inputs for this gem you need: 103 | 104 | First apply ActiveAdminDatetimepicker to any filters your need 105 | 106 | ```ruby 107 | filter :time_start, as: :date_time_range 108 | ``` 109 | 110 | In active_admin.js 111 | 112 | Add following lines to JavaScript 113 | 114 | ```javascript 115 | $(document).on('ready', function(){ 116 | $('form.filter_form div.filter_date_time_range').date_range_ext_preset(); 117 | }); 118 | ``` 119 | 120 | Now all you "date_time_range" inputs has button "Set range" 121 | 122 | 123 | ## Custom usage 124 | 125 | You can assign "Set range" almost to any input-text-pair filters/forms. 126 | For example, you have complex form where input-pairs are not close to each other and not standard. 127 | 128 | ```javascript 129 | $(document).on('ready', function(){ 130 | $('.any_jquery_selector').date_range_ext_preset({ 131 | lteq_input: '.jquery_selector_to_first_input', 132 | gteq_input: '.jquery_selector_to_second_input' 133 | }); 134 | }); 135 | ``` 136 | ".any_jquery_selector" is pointed to place where button "Set range" will appear. 137 | Set lteq_input and gteq_input to point to inputs if they not near main selector. 138 | 139 | 140 | ## Global and local settings 141 | 142 | There are several settings, which can be set globally or locally. 143 | 144 | Example how to set settings for only specific inputs 145 | 146 | ```javascript 147 | $('.any_jquery_selector').date_range_ext_preset({ 148 | setting_name: "setting_value" 149 | }); 150 | ``` 151 | Example how to set global settings. Write it before $(document).on('ready') 152 | 153 | ```javascript 154 | $.fn.date_range_ext_preset.defaults.setting_name = "setting_value" 155 | ``` 156 | 157 | You can set global defaults in your active_admin.js like this: 158 | 159 | ```javascript 160 | # End date will be full-day, not next. 161 | # Today true : 2015-06-12 - 2015-06-12 162 | # Today false: 2015-06-12 - 2015-06-13 163 | $.fn.date_range_ext_preset.defaults.date_to_human_readable = true 164 | 165 | # Display time 166 | # Today: 2015-06-12 00:00:00 - 2015-06-13 00:00:00 167 | # Today with human_readable=true: 2015-06-12 00:00:00 - 2015-16-12 23:59:59 168 | $.fn.date_range_ext_preset.defaults.show_time = true 169 | ``` 170 | 171 | ### date_to_human_readable 172 | 173 | value: true/false 174 | 175 | default: false 176 | 177 | This options changes second date to include full date-time of the day, like normal human thinks about time ranges. 178 | Today true : 2015-06-12 - 2015-06-12 179 | Today false: 2015-06-12 - 2015-06-13 180 | 181 | When normal human say "2015-06-12" hi means "2015-06-12 23:59:59" 182 | But default behavior in programming is "2015-06-12" = "2015-06-12 00:00:00" 183 | Be careful with this options. Cause if you change it to "true" you will also need to change your server-side scripts to search "humanize-way". 184 | 185 | ### show_time 186 | 187 | value: true/false 188 | 189 | default: false 190 | 191 | If true then will show date and time, usually it will be 00:00:00 192 | 193 | ### hours_offset 194 | 195 | values: positive or negative integer 196 | 197 | default: 0 198 | 199 | To work correctly this plugin needs to detect current date-time. And it uses UTC. But if you need your local timezone or some other time-shift, your can set this option: 200 | 201 | Example: 202 | ```javascript 203 | $.fn.date_range_ext_preset.defaults.hours_offset = +3 204 | // or 205 | $.fn.date_range_ext_preset.defaults.hours_offset = -3 206 | ``` 207 | 208 | ### Addition ranges 209 | 210 | ```javascript 211 | $(document).on('ready', function(){ 212 | 213 | $('.filter_form .filter_date_range').date_range_ext_preset({ 214 | date_to_human_readable: true, # affects last day 215 | add_range: [ 216 | { 217 | title: 'Last 30 days', 218 | // date_to_human_readable affects end-date, sow must do this: 219 | start: new Date(new Date().setDate(new Date().getDate() - 29)), 220 | end: new Date(new Date().setDate(new Date().getDate() + 1)) 221 | } 222 | ] 223 | }); 224 | 225 | }); 226 | ``` 227 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/active_admin_date_range_preset.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | // options: 3 | // gteq_input: jQuery-selecotr for input date_from 4 | // lteq_input: jQuery-selecotr for input date_to 5 | // hours_offset: Int number - hours +/- to correct time 6 | $.fn.date_range_ext_preset = function(options) { 7 | // settings 8 | options = options || {}; 9 | let opts = $.extend({}, $.fn.date_range_ext_preset.defaults, options); 10 | 11 | // aditional functions 12 | function num_with_leading_zero(num, digitsCount = 2) { 13 | let s = num + ''; 14 | while (s.length < digitsCount) { 15 | s = '0' + s; 16 | } 17 | return s; 18 | } 19 | 20 | // formated date YYYY-MM-DD, with converting to UTC 21 | // note: getMonth Returns the month (from 0-11), so we do +1 22 | function formatDate(date) { 23 | let str = date.getFullYear() + '-' + num_with_leading_zero(date.getMonth()+1) + '-' + num_with_leading_zero(date.getDate()); 24 | if (opts.show_time) { 25 | str += (' ' + num_with_leading_zero(date.getHours()) + ':' + num_with_leading_zero(date.getMinutes()) + ':' + num_with_leading_zero(date.getSeconds())); 26 | } 27 | return str; 28 | } 29 | 30 | function unbindClickEventBlockTimerange() { 31 | $('.block_timerange').remove(); 32 | $('body').off('click.CalendarRangeSet'); 33 | } 34 | 35 | // local datetime now 36 | let now = new Date(); 37 | // UTC datetime now 38 | let now_utc = new Date( 39 | now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 40 | now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds(), 41 | now.getUTCMilliseconds() 42 | ); 43 | // datetime object, UTC with hours offset 44 | let datetime = new Date(now_utc.getTime() + opts.hours_offset * 60 * 60 * 1000); 45 | 46 | // PLUGIN BEGIN 47 | return this.each(function(i, el) { 48 | let $this = $(el); 49 | 50 | if (typeof $this.data('show-time') != 'undefined' && $this.data('show-time').toString() == 'true') { 51 | opts.show_time = true; 52 | } 53 | 54 | // detect inputs 55 | let lteq_input = $this.find('input:last'); 56 | if (options.lteq_input) { 57 | lteq_input = $(options.lteq_input); 58 | } else if ($this.hasClass('datetime_preset_pair')) { 59 | lteq_input = $this.next().find('input'); 60 | } 61 | 62 | let gteq_input = $this.find('input:first'); 63 | if (options.gteq_input) { 64 | gteq_input = $(options.gteq_input); 65 | } else if ($this.hasClass('datetime_preset_pair')) { 66 | gteq_input = $this.find('input'); 67 | } 68 | 69 | // filter modifying 70 | let main_btn_html = 'Set range'; 71 | $this.find('label').addClass('datetime_preset_filter_label').append(main_btn_html); 72 | 73 | // helper 74 | function fillInputs(start, end) { 75 | gteq_input.val(formatDate(start)); 76 | if (opts.date_to_human_readable) { 77 | end.setTime(end.getTime() - 1000); 78 | } 79 | 80 | lteq_input.val(formatDate(end)); 81 | } 82 | 83 | $this.on('click', '.btn_timerange', function(e) { 84 | unbindClickEventBlockTimerange(); 85 | e.stopPropagation(); 86 | e.preventDefault(); 87 | 88 | let additional_items_html = ''; 89 | opts.add_range.forEach(function(el, i) { 90 | return additional_items_html += '
' + el['title'] + '
'; 91 | }); 92 | 93 | $('body').append('
' + 94 | '
Today
' + 95 | '
Yesterday
' + 96 | '
This Week
' + 97 | '
This Month
' + 98 | '
Last Week
' + 99 | '
Last Month
' + 100 | additional_items_html + 101 | '
' 102 | ).ready(function() { 103 | let container = $(this).find('.block_timerange'); 104 | 105 | // additional ranges 106 | opts.add_range.forEach(function(el, i) { 107 | $(container).on('click.CalendarRangeSet', '.btn_date_range_' + i, function(e) { 108 | unbindClickEventBlockTimerange(); 109 | let start = new Date(el['start'].getFullYear(), el['start'].getMonth(), el['start'].getDate()); 110 | let end = new Date(el['end'].getFullYear(), el['end'].getMonth(), el['end'].getDate()); 111 | fillInputs(start, end) 112 | }); 113 | }); 114 | 115 | // Today 116 | $(container).on('click.CalendarRangeSet', '.btn_today', function(e) { 117 | unbindClickEventBlockTimerange(); 118 | let start = new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate()); 119 | let end = new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate() + 1); 120 | fillInputs(start, end); 121 | }); 122 | 123 | // Yesterday 124 | $(container).on('click.CalendarRangeSet', '.btn_yesterday', function(e) { 125 | unbindClickEventBlockTimerange(); 126 | let start = new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate() - 1); 127 | let end = new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate()); 128 | fillInputs(start, end); 129 | }); 130 | 131 | // Week 132 | $(container).on('click.CalendarRangeSet', '.btn_week', function(e) { 133 | unbindClickEventBlockTimerange(); 134 | let start = new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate() - datetime.getDay() + 1); 135 | let end = new Date(start.getFullYear(), start.getMonth(), start.getDate() + 7); 136 | fillInputs(start, end); 137 | }); 138 | 139 | // Month 140 | $(container).on('click.CalendarRangeSet', '.btn_month', function(e) { 141 | unbindClickEventBlockTimerange(); 142 | let start = new Date(datetime.getFullYear(), datetime.getMonth(), 1); 143 | let end = new Date(datetime.getFullYear(), datetime.getMonth() + 1, 1); 144 | fillInputs(start, end); 145 | }); 146 | 147 | // Last Week 148 | $(container).on('click.CalendarRangeSet', '.btn_last_week', function(e) { 149 | unbindClickEventBlockTimerange(); 150 | let end = new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate() - datetime.getDay() + 1); 151 | let start = new Date(end.getFullYear(), end.getMonth(), end.getDate() - 7); 152 | fillInputs(start, end); 153 | }); 154 | 155 | // Last Month 156 | $(container).on('click.CalendarRangeSet', '.btn_last_month', function(e) { 157 | unbindClickEventBlockTimerange(); 158 | let end = new Date(datetime.getFullYear(), datetime.getMonth(), 1); 159 | let start = new Date(end.getFullYear(), end.getMonth() - 1, 1); 160 | fillInputs(start, end); 161 | }); 162 | 163 | // Outer 164 | $('body').on('click.CalendarRangeSet', function(e) { 165 | e.stopPropagation(); 166 | if ($(e.target).closest('.block_timerange').length == 0) { 167 | unbindClickEventBlockTimerange(); 168 | } 169 | }); 170 | }); 171 | }); 172 | }); 173 | } 174 | 175 | $.fn.date_range_ext_preset.defaults = { 176 | // Manual global time shift, from UTC can be +/- number 177 | hours_offset: 0, 178 | 179 | // date_to_human_readable = true, then "date_to" consider as including full day without last second 180 | // For example Today will be: 181 | // true 182 | // 2015-06-10 - 2015-06-10 183 | // 2015-06-10 00:00:00 - 2015-06-10 23:59:59 184 | // false 185 | // 2015-06-10 - 2015-06-11 186 | // 2015-06-10 00:00:00 - 2015-06-11 00:00:00 187 | date_to_human_readable: false, 188 | 189 | // Display time or not: 2015-06-10 vs 2015-06-10 00:00:00 190 | show_time: false, 191 | 192 | // Array of addition ranges 193 | // example: 194 | // { 195 | // title: 'Last 30 days', 196 | // start: new Date().setDate((new Date()).getDate() - 30) 197 | // end: new Date() 198 | // } 199 | add_range: [] 200 | } 201 | }); 202 | 203 | $(document).on('ready', function() { 204 | // Init in forms 205 | $('.datetime_preset_pair').date_range_ext_preset(); 206 | }); 207 | --------------------------------------------------------------------------------