activeadmin_sortable_table 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +20 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +245 -0
- data/LICENSE.txt +22 -0
- data/README.md +97 -0
- data/Rakefile +27 -0
- data/activeadmin_sortable_table.gemspec +28 -0
- data/app/assets/javascripts/activeadmin_sortable_table.js +35 -0
- data/app/assets/stylesheets/activeadmin_sortable_table.css +11 -0
- data/lib/active_admin/sortable_table/engine.rb +9 -0
- data/lib/active_admin/sortable_table/handle_column.rb +46 -0
- data/lib/active_admin/sortable_table/version.rb +6 -0
- data/lib/activeadmin_sortable_table.rb +38 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/admin/categories.rb +12 -0
- data/spec/dummy/app/admin/dashboard.rb +32 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/active_admin.js.coffee +3 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/javascripts/jquery.simulate.js +314 -0
- data/spec/dummy/app/assets/stylesheets/active_admin.scss +17 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/category.rb +3 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +28 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/active_admin.rb +262 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20150910072150_create_active_admin_comments.rb +19 -0
- data/spec/dummy/db/migrate/20150910072505_create_categories.rb +8 -0
- data/spec/dummy/db/schema.rb +36 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/features/activeadmin_sortable_table_spec.rb +31 -0
- data/spec/rails_helper.rb +62 -0
- data/spec/spec_helper.rb +92 -0
- data/spec/support/wait_for_ajax.rb +20 -0
- metadata +288 -0
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
task default: ['dummy:prepare', :spec]
|
6
|
+
|
7
|
+
require 'rake/clean'
|
8
|
+
CLEAN.include 'spec/dummy/db/*sqlite3', 'spec/dummy/log/*', 'spec/dummy/public/assets/*', 'spec/dummy/tmp/**/*'
|
9
|
+
|
10
|
+
namespace :dummy do
|
11
|
+
desc 'Setup dummy app database'
|
12
|
+
task :prepare do
|
13
|
+
# File.expand_path is executed directory of generated Rails app
|
14
|
+
rakefile = File.expand_path('Rakefile', dummy_path)
|
15
|
+
command = format("rake -f '%s' db:schema:load RAILS_ENV=test", rakefile)
|
16
|
+
sh(command) unless ENV['DISABLE_CREATE']
|
17
|
+
end
|
18
|
+
|
19
|
+
def dummy_path
|
20
|
+
rel_path = ENV['DUMMY_APP_PATH'] || 'spec/dummy'
|
21
|
+
if @current_path.to_s.include?(rel_path)
|
22
|
+
@current_path
|
23
|
+
else
|
24
|
+
@current_path = File.expand_path(rel_path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'active_admin/sortable_table/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'activeadmin_sortable_table'
|
8
|
+
gem.version = ActiveAdmin::SortableTable::VERSION
|
9
|
+
gem.authors = ['Adam McCrea', 'Jonathan Gertig', 'Artyom Bolshakov']
|
10
|
+
gem.email = ['adam@adamlogic.com', 'jcgertig@gmail.com', 'abolshakov@spbtv.com']
|
11
|
+
gem.description = 'Drag and drop reordering interface for ActiveAdmin tables'
|
12
|
+
gem.summary = 'Drag and drop reordering interface for ActiveAdmin tables'
|
13
|
+
gem.homepage = 'https://github.com/bolshakov/activeadmin_sortable_table'
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_dependency 'activeadmin', '>= 1.0.0.pre1'
|
21
|
+
gem.add_development_dependency 'rails', '~> 4.2'
|
22
|
+
gem.add_development_dependency 'capybara'
|
23
|
+
gem.add_development_dependency 'rspec-rails', '~> 3.3'
|
24
|
+
gem.add_development_dependency 'phantomjs'
|
25
|
+
gem.add_development_dependency 'poltergeist'
|
26
|
+
gem.add_development_dependency 'database_cleaner'
|
27
|
+
gem.add_development_dependency 'launchy'
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
(function($) {
|
2
|
+
$(document).ready(function() {
|
3
|
+
$('.handle').closest('tbody').activeAdminSortableTable();
|
4
|
+
});
|
5
|
+
|
6
|
+
$.fn.activeAdminSortableTable = function() {
|
7
|
+
this.sortable({
|
8
|
+
update: function(event, ui) {
|
9
|
+
var item = ui.item.find('[data-sort-url]');
|
10
|
+
var url = item.data('sort-url');
|
11
|
+
var actionOnSuccess = item.data('sort-success-action');
|
12
|
+
var customParams = {};
|
13
|
+
if (typeof item.data('sort-custom-params') === 'object') {
|
14
|
+
customParams = item.data('sort-custom-params');
|
15
|
+
}
|
16
|
+
|
17
|
+
$.ajax({
|
18
|
+
url: url,
|
19
|
+
type: 'post',
|
20
|
+
data: $.extend(customParams, { position: ui.item.index() + 1 }),
|
21
|
+
error: function() { console.error('Saving sortable error'); },
|
22
|
+
success: function() {
|
23
|
+
if (actionOnSuccess === 'noting') { return; }
|
24
|
+
|
25
|
+
$("tr", $('.handle').closest('tbody')).removeClass('even odd');
|
26
|
+
$("tr", $('.handle').closest('tbody')).filter(":even").addClass('odd');
|
27
|
+
$("tr", $('.handle').closest('tbody')).filter(":odd").addClass('even');
|
28
|
+
}
|
29
|
+
});
|
30
|
+
}
|
31
|
+
});
|
32
|
+
|
33
|
+
this.disableSelection();
|
34
|
+
}
|
35
|
+
})(jQuery);
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
#
|
3
|
+
module SortableTable
|
4
|
+
# Adds `handle_column` method to `TableFor` dsl.
|
5
|
+
# @example on index page
|
6
|
+
# index do
|
7
|
+
# handle_column
|
8
|
+
# id_column
|
9
|
+
# # other columns...
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# @example table_for
|
13
|
+
# table_for c.collection_memberships do
|
14
|
+
# handle_column
|
15
|
+
# # other columns...
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
module HandleColumn
|
19
|
+
# @param [Hash] options
|
20
|
+
# @option options [Symbol, Proc, String] :url
|
21
|
+
#
|
22
|
+
def handle_column(options = {})
|
23
|
+
column '', class: 'activeadmin_sortable_table' do |resource|
|
24
|
+
content_tag :span, '', class: 'handle', 'data-sort-url' => sort_url(options[:url], resource)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def sort_url(url, resource)
|
31
|
+
if url.is_a?(Symbol)
|
32
|
+
send(url, resource)
|
33
|
+
elsif url.respond_to?(:call)
|
34
|
+
url.call(resource)
|
35
|
+
else
|
36
|
+
sort_url, query_params = resource_path(resource).split('?', 2)
|
37
|
+
sort_url += '/sort'
|
38
|
+
sort_url += '?' + query_params if query_params
|
39
|
+
sort_url
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
::ActiveAdmin::Views::TableFor.send(:include, HandleColumn)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'activeadmin'
|
2
|
+
|
3
|
+
module ActiveAdmin
|
4
|
+
# Include this module to registered page to enable
|
5
|
+
# ActiveAdmin Sortable Table extension
|
6
|
+
# @example
|
7
|
+
#
|
8
|
+
# ActiveAdmin.register Category do
|
9
|
+
# include ActiveAdmin::SortableTable
|
10
|
+
# config.sort_order = 'position_asc'
|
11
|
+
# permit_params :position
|
12
|
+
#
|
13
|
+
# index do
|
14
|
+
# handle_column
|
15
|
+
# id_column
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
module SortableTable
|
20
|
+
require 'active_admin/sortable_table/version'
|
21
|
+
require 'active_admin/sortable_table/engine'
|
22
|
+
require 'active_admin/sortable_table/handle_column'
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# @param [ActiveAdmin::DSL] dsl
|
26
|
+
# @return [void]
|
27
|
+
#
|
28
|
+
def included(dsl)
|
29
|
+
dsl.instance_eval do
|
30
|
+
member_action :sort, method: :post do
|
31
|
+
resource.insert_at params[:position].to_i
|
32
|
+
head 200
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
ActiveAdmin.register_page 'Dashboard' do
|
2
|
+
menu priority: 1, label: proc { I18n.t('active_admin.dashboard') }
|
3
|
+
|
4
|
+
content title: proc { I18n.t('active_admin.dashboard') } do
|
5
|
+
div class: 'blank_slate_container', id: 'dashboard_default_message' do
|
6
|
+
span class: 'blank_slate' do
|
7
|
+
span I18n.t('active_admin.dashboard_welcome.welcome')
|
8
|
+
small I18n.t('active_admin.dashboard_welcome.call_to_action')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Here is an example of a simple dashboard with columns and panels.
|
13
|
+
#
|
14
|
+
# columns do
|
15
|
+
# column do
|
16
|
+
# panel "Recent Posts" do
|
17
|
+
# ul do
|
18
|
+
# Post.recent(5).map do |post|
|
19
|
+
# li link_to(post.title, admin_post_path(post))
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
|
25
|
+
# column do
|
26
|
+
# panel "Info" do
|
27
|
+
# para "Welcome to ActiveAdmin."
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
end # content
|
32
|
+
end
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,314 @@
|
|
1
|
+
/*!
|
2
|
+
* jQuery Simulate v@VERSION - simulate browser mouse and keyboard events
|
3
|
+
* https://github.com/jquery/jquery-simulate
|
4
|
+
*
|
5
|
+
* Copyright 2012 jQuery Foundation and other contributors
|
6
|
+
* Released under the MIT license.
|
7
|
+
* http://jquery.org/license
|
8
|
+
*
|
9
|
+
* Date: @DATE
|
10
|
+
*/
|
11
|
+
|
12
|
+
;(function( $, undefined ) {
|
13
|
+
|
14
|
+
var rkeyEvent = /^key/,
|
15
|
+
rmouseEvent = /^(?:mouse|contextmenu)|click/;
|
16
|
+
|
17
|
+
$.fn.simulate = function( type, options ) {
|
18
|
+
return this.each(function() {
|
19
|
+
new $.simulate( this, type, options );
|
20
|
+
});
|
21
|
+
};
|
22
|
+
|
23
|
+
$.simulate = function( elem, type, options ) {
|
24
|
+
var method = $.camelCase( "simulate-" + type );
|
25
|
+
|
26
|
+
this.target = elem;
|
27
|
+
this.options = options;
|
28
|
+
|
29
|
+
if ( this[ method ] ) {
|
30
|
+
this[ method ]();
|
31
|
+
} else {
|
32
|
+
this.simulateEvent( elem, type, options );
|
33
|
+
}
|
34
|
+
};
|
35
|
+
|
36
|
+
$.extend( $.simulate, {
|
37
|
+
|
38
|
+
keyCode: {
|
39
|
+
BACKSPACE: 8,
|
40
|
+
COMMA: 188,
|
41
|
+
DELETE: 46,
|
42
|
+
DOWN: 40,
|
43
|
+
END: 35,
|
44
|
+
ENTER: 13,
|
45
|
+
ESCAPE: 27,
|
46
|
+
HOME: 36,
|
47
|
+
LEFT: 37,
|
48
|
+
NUMPAD_ADD: 107,
|
49
|
+
NUMPAD_DECIMAL: 110,
|
50
|
+
NUMPAD_DIVIDE: 111,
|
51
|
+
NUMPAD_ENTER: 108,
|
52
|
+
NUMPAD_MULTIPLY: 106,
|
53
|
+
NUMPAD_SUBTRACT: 109,
|
54
|
+
PAGE_DOWN: 34,
|
55
|
+
PAGE_UP: 33,
|
56
|
+
PERIOD: 190,
|
57
|
+
RIGHT: 39,
|
58
|
+
SPACE: 32,
|
59
|
+
TAB: 9,
|
60
|
+
UP: 38
|
61
|
+
},
|
62
|
+
|
63
|
+
buttonCode: {
|
64
|
+
LEFT: 0,
|
65
|
+
MIDDLE: 1,
|
66
|
+
RIGHT: 2
|
67
|
+
}
|
68
|
+
});
|
69
|
+
|
70
|
+
$.extend( $.simulate.prototype, {
|
71
|
+
|
72
|
+
simulateEvent: function( elem, type, options ) {
|
73
|
+
var event = this.createEvent( type, options );
|
74
|
+
this.dispatchEvent( elem, type, event, options );
|
75
|
+
},
|
76
|
+
|
77
|
+
createEvent: function( type, options ) {
|
78
|
+
if ( rkeyEvent.test( type ) ) {
|
79
|
+
return this.keyEvent( type, options );
|
80
|
+
}
|
81
|
+
|
82
|
+
if ( rmouseEvent.test( type ) ) {
|
83
|
+
return this.mouseEvent( type, options );
|
84
|
+
}
|
85
|
+
},
|
86
|
+
|
87
|
+
mouseEvent: function( type, options ) {
|
88
|
+
var event, eventDoc, doc, body;
|
89
|
+
options = $.extend({
|
90
|
+
bubbles: true,
|
91
|
+
cancelable: (type !== "mousemove"),
|
92
|
+
view: window,
|
93
|
+
detail: 0,
|
94
|
+
screenX: 0,
|
95
|
+
screenY: 0,
|
96
|
+
clientX: 1,
|
97
|
+
clientY: 1,
|
98
|
+
ctrlKey: false,
|
99
|
+
altKey: false,
|
100
|
+
shiftKey: false,
|
101
|
+
metaKey: false,
|
102
|
+
button: 0,
|
103
|
+
relatedTarget: undefined
|
104
|
+
}, options );
|
105
|
+
|
106
|
+
if ( document.createEvent ) {
|
107
|
+
event = document.createEvent( "MouseEvents" );
|
108
|
+
event.initMouseEvent( type, options.bubbles, options.cancelable,
|
109
|
+
options.view, options.detail,
|
110
|
+
options.screenX, options.screenY, options.clientX, options.clientY,
|
111
|
+
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
|
112
|
+
options.button, options.relatedTarget || document.body.parentNode );
|
113
|
+
|
114
|
+
// IE 9+ creates events with pageX and pageY set to 0.
|
115
|
+
// Trying to modify the properties throws an error,
|
116
|
+
// so we define getters to return the correct values.
|
117
|
+
if ( event.pageX === 0 && event.pageY === 0 && Object.defineProperty ) {
|
118
|
+
eventDoc = event.relatedTarget.ownerDocument || document;
|
119
|
+
doc = eventDoc.documentElement;
|
120
|
+
body = eventDoc.body;
|
121
|
+
|
122
|
+
Object.defineProperty( event, "pageX", {
|
123
|
+
get: function() {
|
124
|
+
return options.clientX +
|
125
|
+
( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
|
126
|
+
( doc && doc.clientLeft || body && body.clientLeft || 0 );
|
127
|
+
}
|
128
|
+
});
|
129
|
+
Object.defineProperty( event, "pageY", {
|
130
|
+
get: function() {
|
131
|
+
return options.clientY +
|
132
|
+
( doc && doc.scrollTop || body && body.scrollTop || 0 ) -
|
133
|
+
( doc && doc.clientTop || body && body.clientTop || 0 );
|
134
|
+
}
|
135
|
+
});
|
136
|
+
}
|
137
|
+
} else if ( document.createEventObject ) {
|
138
|
+
event = document.createEventObject();
|
139
|
+
$.extend( event, options );
|
140
|
+
// standards event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ff974877(v=vs.85).aspx
|
141
|
+
// old IE event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ms533544(v=vs.85).aspx
|
142
|
+
// so we actually need to map the standard back to oldIE
|
143
|
+
event.button = {
|
144
|
+
0: 1,
|
145
|
+
1: 4,
|
146
|
+
2: 2
|
147
|
+
}[ event.button ] || event.button;
|
148
|
+
}
|
149
|
+
|
150
|
+
return event;
|
151
|
+
},
|
152
|
+
|
153
|
+
keyEvent: function( type, options ) {
|
154
|
+
var event;
|
155
|
+
options = $.extend({
|
156
|
+
bubbles: true,
|
157
|
+
cancelable: true,
|
158
|
+
view: window,
|
159
|
+
ctrlKey: false,
|
160
|
+
altKey: false,
|
161
|
+
shiftKey: false,
|
162
|
+
metaKey: false,
|
163
|
+
keyCode: 0,
|
164
|
+
charCode: undefined
|
165
|
+
}, options );
|
166
|
+
|
167
|
+
if ( document.createEvent ) {
|
168
|
+
try {
|
169
|
+
event = document.createEvent( "KeyEvents" );
|
170
|
+
event.initKeyEvent( type, options.bubbles, options.cancelable, options.view,
|
171
|
+
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
|
172
|
+
options.keyCode, options.charCode );
|
173
|
+
// initKeyEvent throws an exception in WebKit
|
174
|
+
// see: http://stackoverflow.com/questions/6406784/initkeyevent-keypress-only-works-in-firefox-need-a-cross-browser-solution
|
175
|
+
// and also https://bugs.webkit.org/show_bug.cgi?id=13368
|
176
|
+
// fall back to a generic event until we decide to implement initKeyboardEvent
|
177
|
+
} catch( err ) {
|
178
|
+
event = document.createEvent( "Events" );
|
179
|
+
event.initEvent( type, options.bubbles, options.cancelable );
|
180
|
+
$.extend( event, {
|
181
|
+
view: options.view,
|
182
|
+
ctrlKey: options.ctrlKey,
|
183
|
+
altKey: options.altKey,
|
184
|
+
shiftKey: options.shiftKey,
|
185
|
+
metaKey: options.metaKey,
|
186
|
+
keyCode: options.keyCode,
|
187
|
+
charCode: options.charCode
|
188
|
+
});
|
189
|
+
}
|
190
|
+
} else if ( document.createEventObject ) {
|
191
|
+
event = document.createEventObject();
|
192
|
+
$.extend( event, options );
|
193
|
+
}
|
194
|
+
|
195
|
+
if ( !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ) || (({}).toString.call( window.opera ) === "[object Opera]") ) {
|
196
|
+
event.keyCode = (options.charCode > 0) ? options.charCode : options.keyCode;
|
197
|
+
event.charCode = undefined;
|
198
|
+
}
|
199
|
+
|
200
|
+
return event;
|
201
|
+
},
|
202
|
+
|
203
|
+
dispatchEvent: function( elem, type, event ) {
|
204
|
+
if ( elem[ type ] ) {
|
205
|
+
elem[ type ]();
|
206
|
+
} else if ( elem.dispatchEvent ) {
|
207
|
+
elem.dispatchEvent( event );
|
208
|
+
} else if ( elem.fireEvent ) {
|
209
|
+
elem.fireEvent( "on" + type, event );
|
210
|
+
}
|
211
|
+
},
|
212
|
+
|
213
|
+
simulateFocus: function() {
|
214
|
+
var focusinEvent,
|
215
|
+
triggered = false,
|
216
|
+
element = $( this.target );
|
217
|
+
|
218
|
+
function trigger() {
|
219
|
+
triggered = true;
|
220
|
+
}
|
221
|
+
|
222
|
+
element.bind( "focus", trigger );
|
223
|
+
element[ 0 ].focus();
|
224
|
+
|
225
|
+
if ( !triggered ) {
|
226
|
+
focusinEvent = $.Event( "focusin" );
|
227
|
+
focusinEvent.preventDefault();
|
228
|
+
element.trigger( focusinEvent );
|
229
|
+
element.triggerHandler( "focus" );
|
230
|
+
}
|
231
|
+
element.unbind( "focus", trigger );
|
232
|
+
},
|
233
|
+
|
234
|
+
simulateBlur: function() {
|
235
|
+
var focusoutEvent,
|
236
|
+
triggered = false,
|
237
|
+
element = $( this.target );
|
238
|
+
|
239
|
+
function trigger() {
|
240
|
+
triggered = true;
|
241
|
+
}
|
242
|
+
|
243
|
+
element.bind( "blur", trigger );
|
244
|
+
element[ 0 ].blur();
|
245
|
+
|
246
|
+
// blur events are async in IE
|
247
|
+
setTimeout(function() {
|
248
|
+
// IE won't let the blur occur if the window is inactive
|
249
|
+
if ( element[ 0 ].ownerDocument.activeElement === element[ 0 ] ) {
|
250
|
+
element[ 0 ].ownerDocument.body.focus();
|
251
|
+
}
|
252
|
+
|
253
|
+
// Firefox won't trigger events if the window is inactive
|
254
|
+
// IE doesn't trigger events if we had to manually focus the body
|
255
|
+
if ( !triggered ) {
|
256
|
+
focusoutEvent = $.Event( "focusout" );
|
257
|
+
focusoutEvent.preventDefault();
|
258
|
+
element.trigger( focusoutEvent );
|
259
|
+
element.triggerHandler( "blur" );
|
260
|
+
}
|
261
|
+
element.unbind( "blur", trigger );
|
262
|
+
}, 1 );
|
263
|
+
}
|
264
|
+
});
|
265
|
+
|
266
|
+
|
267
|
+
|
268
|
+
/** complex events **/
|
269
|
+
|
270
|
+
function findCenter( elem ) {
|
271
|
+
var offset,
|
272
|
+
document = $( elem.ownerDocument );
|
273
|
+
elem = $( elem );
|
274
|
+
offset = elem.offset();
|
275
|
+
|
276
|
+
return {
|
277
|
+
x: offset.left + elem.outerWidth() / 2 - document.scrollLeft(),
|
278
|
+
y: offset.top + elem.outerHeight() / 2 - document.scrollTop()
|
279
|
+
};
|
280
|
+
}
|
281
|
+
|
282
|
+
$.extend( $.simulate.prototype, {
|
283
|
+
simulateDrag: function() {
|
284
|
+
var i = 0,
|
285
|
+
target = this.target,
|
286
|
+
options = this.options,
|
287
|
+
center = findCenter( target ),
|
288
|
+
x = Math.floor( center.x ),
|
289
|
+
y = Math.floor( center.y ),
|
290
|
+
dx = options.dx || 0,
|
291
|
+
dy = options.dy || 0,
|
292
|
+
moves = options.moves || 3,
|
293
|
+
coord = { clientX: x, clientY: y };
|
294
|
+
|
295
|
+
this.simulateEvent( target, "mousedown", coord );
|
296
|
+
|
297
|
+
for ( ; i < moves ; i++ ) {
|
298
|
+
x += dx / moves;
|
299
|
+
y += dy / moves;
|
300
|
+
|
301
|
+
coord = {
|
302
|
+
clientX: Math.round( x ),
|
303
|
+
clientY: Math.round( y )
|
304
|
+
};
|
305
|
+
|
306
|
+
this.simulateEvent( document, "mousemove", coord );
|
307
|
+
}
|
308
|
+
|
309
|
+
this.simulateEvent( target, "mouseup", coord );
|
310
|
+
this.simulateEvent( target, "click", coord );
|
311
|
+
}
|
312
|
+
});
|
313
|
+
|
314
|
+
})( jQuery );
|