Skip to content

Commit

Permalink
Merge 1b4036b into 0b06e7d
Browse files Browse the repository at this point in the history
  • Loading branch information
aishek committed May 16, 2016
2 parents 0b06e7d + 1b4036b commit 6a9623b
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 65 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ $(document).ready(function(){

Before send ajax request to server jQuery UI Sortable disabled, after receive response enable.

`activerecord_sortable()` accetps [JQuery UI Sortable](http://api.jqueryui.com/sortable/)-style options. By default `axis` uses `y` value (to prevent horizontal dragging), and `update` overwrites by internal handler and is unavailabe to set.
`activerecord_sortable()` accepts [JQuery UI Sortable](http://api.jqueryui.com/sortable/)-style options. By default `axis` uses `y` value (to prevent horizontal dragging), and `update` overwrites by internal handler and is unavailabe to set.

`$('*[data-role=activerecord_sortable]')` node may have `start-position` data-attribute (`<div data-start-position="10">...</div>`) in this case first element position will be equal to data-attribute value. If `start-position` not set, then first child node data-attribute `position` will be taken, `0` otherwise.


## How to add activerecord-sortable into existing model
Expand Down
2 changes: 2 additions & 0 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ $(document).ready(function(){

`activerecord_sortable()` принимает аргумент-объект с опциями, аналогичными [виджету JQuery UI Sortable](http://api.jqueryui.com/sortable/). По-умолчанию поле `axis` у аргумента-объекта принимает значение `y` (разрешается только перетаскивание по вертикали), а поле `update` перезаписывается внутренним обработчиком – его переопределить нельзя.

У узла `$('*[data-role=activerecord_sortable]')` можно указать data-атрибут `start-position``<div data-start-position="10">...</div>` – в этом случае позиция первого элемента будет равна значению этого атрибута. Если значение `start-position` не задавать, то будет взято значение data-атрибута `position` первого узла-ребёнка, если и его нет – то `0`.

## Как добавить функциональность activerecord-sortable в существующую модель

```ruby
Expand Down
4 changes: 3 additions & 1 deletion activerecord-sortable.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Gem::Specification.new do |gem|
gem.test_files = Dir["spec/**/*"]

gem.add_development_dependency 'capybara'
gem.add_development_dependency 'poltergeist'
gem.add_development_dependency 'poltergeist', '1.7.0'
gem.add_development_dependency 'phantomjs', '2.1.1.0'

gem.add_development_dependency 'coveralls'
gem.add_development_dependency 'rubocop'
end
3 changes: 2 additions & 1 deletion lib/assets/javascripts/sortable.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@

function Sortable(node, options) {
this.node = node;
this.start_position = this.node.data('start-position') || this.node.children().eq(0).data('position') || 0;

if (!options) options = {};
options['update'] = $.proxy(this.sortable_stop_handler, this);
Expand All @@ -107,7 +108,7 @@
this.node.sortable('disable').trigger('sortable:start');

var node = ui.item;
var new_position = node.index();
var new_position = this.start_position + node.index();
var old_position = parseInt(node.data('position'));

var positions_updater = new PositionsUpdater(this.node, node, new_position, old_position);
Expand Down
1 change: 1 addition & 0 deletions spec/dummy-3.2/app/controllers/things_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class ThingsController < ApplicationController
def index
@things = Thing.ordered_by_position_asc
@things = @things.where('position >= ?', params[:min_position]) if params[:min_position]
end

def move
Expand Down
1 change: 1 addition & 0 deletions spec/dummy-4.0/app/controllers/things_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class ThingsController < ApplicationController
def index
@things = Thing.ordered_by_position_asc
@things = @things.where('position >= ?', params[:min_position]) if params[:min_position]
end

def move
Expand Down
1 change: 1 addition & 0 deletions spec/dummy-4.1/app/controllers/things_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class ThingsController < ApplicationController
def index
@things = Thing.ordered_by_position_asc
@things = @things.where('position >= ?', params[:min_position]) if params[:min_position]
end

def move
Expand Down
1 change: 1 addition & 0 deletions spec/dummy-4.2/app/controllers/things_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class ThingsController < ApplicationController
def index
@things = Thing.ordered_by_position_asc
@things = @things.where('position >= ?', params[:min_position]) if params[:min_position]
end

def move
Expand Down
195 changes: 133 additions & 62 deletions spec/features/drag_and_drop_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,78 +4,154 @@
context 'existing things' do
before(:each) { Thing.delete_all }

let!(:thing1) { Thing.create }
let!(:thing2) { Thing.create }
context 'all things at one page' do
let!(:thing1) { Thing.create! }
let!(:thing2) { Thing.create! }

describe 'drag up' do
let(:thing1_selector) { "li[data-role=thing#{thing1.id}]" }
let(:thing2_selector) { "li[data-role=thing#{thing2.id}]" }

subject do
visit '/'
page.execute_script "
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $('#{thing1_selector}');
var droppable = $('#{thing2_selector}');
var dy = droppable.offset().top - draggable.offset().top - 1;
draggable.simulate('drag', {dx:0, dy: dy});
});
"
sleep 3

click_button 'Refresh'
end

it 'change first thing position to 0' do
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing1.id}' and @data-position='0']")
end

it 'change second thing position to 1' do
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing2.id}' and @data-position='1']")
end
end

describe 'drag up' do
let(:thing1_selector) { "li[data-role=thing#{thing1.id}]" }
let(:thing2_selector) { "li[data-role=thing#{thing2.id}]" }
describe 'drag down' do
let!(:thing1) { Thing.create! }
let!(:thing2) { Thing.create! }

subject do
sleep 3
page.execute_script "
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $('#{thing1_selector}');
var droppable = $('#{thing2_selector}');
var dy = droppable.offset().top - draggable.offset().top - 1;
let(:thing1_selector) { "li[data-role=thing#{thing1.id}]" }
let(:thing2_selector) { "li[data-role=thing#{thing2.id}]" }

draggable.simulate('drag', {dx:0, dy: dy});
});
"
sleep 3
subject do
sleep 3

click_button 'Refresh'
end
delta = thing2.sortable_append ? -1 : 1
page.execute_script "
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $('#{thing2_selector}');
var droppable = $('#{thing1_selector}');
it 'change first thing position to 0' do
visit '/'
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing1.id}' and @data-position='0']")
end
var dy = droppable.offset().top - draggable.offset().top + #{delta};
it 'change second thing position to 1' do
visit '/'
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing2.id}' and @data-position='1']")
draggable.simulate('drag', {dx:0, dy: dy});
});
"
sleep 3

click_button 'Refresh'
end

it 'change first thing position to 0' do
visit '/'
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing1.id}' and @data-position='#{thing1.sortable_append ? 1 : 0}']")
end

it 'change second thing position to 1' do
visit '/'
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing2.id}' and @data-position='#{thing2.sortable_append ? 0 : 1}']")
end
end
end

describe 'drag down' do
let!(:thing1) { Thing.create }
let!(:thing2) { Thing.create }
# In some cases first thing position may be greater than 0 (pagination, for example)
context 'second page' do
describe 'drag up' do
let!(:thing0) { Thing.create! }
let!(:thing1) { Thing.create! }
let!(:thing2) { Thing.create! }

let(:thing1_selector) { "li[data-role=thing#{thing1.id}]" }
let(:thing2_selector) { "li[data-role=thing#{thing2.id}]" }

subject do
visit '/?min_position=1'
page.execute_script "
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $('#{thing1_selector}');
var droppable = $('#{thing2_selector}');
var dy = droppable.offset().top - draggable.offset().top - 1;
draggable.simulate('drag', {dx:0, dy: dy});
});
"
sleep 3

click_button 'Refresh'
end

it 'change first thing position to 1' do
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing1.id}' and @data-position='1']")
end

it 'change second thing position to 2' do
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing2.id}' and @data-position='2']")
end
end

let(:thing1_selector) { "li[data-role=thing#{thing1.id}]" }
let(:thing2_selector) { "li[data-role=thing#{thing2.id}]" }
describe 'drag down' do
let!(:thing0) { Thing.create! }
let!(:thing1) { Thing.create! }
let!(:thing2) { Thing.create! }

subject do
sleep 3
let(:thing1_selector) { "li[data-role=thing#{thing1.id}]" }
let(:thing2_selector) { "li[data-role=thing#{thing2.id}]" }

delta = thing2.sortable_append ? -1 : 1
page.execute_script "
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $('#{thing2_selector}');
var droppable = $('#{thing1_selector}');
subject do
visit '/?min_position=1'

var dy = droppable.offset().top - draggable.offset().top + #{delta};
delta = thing2.sortable_append ? -1 : 1
page.execute_script "
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $('#{thing2_selector}');
var droppable = $('#{thing1_selector}');
draggable.simulate('drag', {dx:0, dy: dy});
});
"
sleep 3
var dy = droppable.offset().top - draggable.offset().top + #{delta};
click_button 'Refresh'
end
draggable.simulate('drag', {dx:0, dy: dy});
});
"
sleep 3

it 'change first thing position to 0' do
visit '/'
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing1.id}' and @data-position='#{thing1.sortable_append ? 1 : 0}']")
end
click_button 'Refresh'
end

it 'change second thing position to 1' do
visit '/'
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing2.id}' and @data-position='#{thing2.sortable_append ? 0 : 1}']")
it 'change first thing position to 1' do
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing1.id}' and @data-position='#{thing1.sortable_append ? 2 : 1}']")
end

it 'change second thing position to 2' do
subject
expect(page).to have_selector(:xpath, "//li[@data-role='thing#{thing2.id}' and @data-position='#{thing2.sortable_append ? 1 : 2}']")
end
end
end
end
Expand All @@ -88,7 +164,7 @@
let(:child2_selector) { "li[data-position='0']" }

subject do
sleep 3
visit new_parent_path
page.execute_script %{
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $("#{child1_selector}");
Expand All @@ -104,13 +180,11 @@
end

it 'change first child position to 2' do
visit new_parent_path
subject
expect(page).to have_selector("li[data-position='1']", text: 'Child 0')
end

it 'change last child position to 0' do
visit new_parent_path
subject
expect(page).to have_selector("li[data-position='0']", text: 'Child 2')
end
Expand All @@ -121,7 +195,7 @@
let(:child2_selector) { "li[data-position='0']" }

subject do
sleep 3
visit new_parent_path
page.execute_script %{
$.getScript('/assets/jquery.simulate.js', function(){
var draggable = $("#{child2_selector}");
Expand All @@ -137,19 +211,16 @@
end

it 'change first child position to 2' do
visit new_parent_path
subject
expect(page).to have_selector("li[data-position='2']", text: 'Child 0')
end

it 'change middle child position to 0' do
visit new_parent_path
subject
expect(page).to have_selector("li[data-position='0']", text: 'Child 1')
end

it 'change last child position to 1' do
visit new_parent_path
subject
expect(page).to have_selector("li[data-position='1']", text: 'Child 2')
end
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
require 'capybara/rspec'
require 'capybara/rails'
require 'capybara/poltergeist'
require 'phantomjs/poltergeist'
Capybara.javascript_driver = :poltergeist
Capybara.app = Dummy::Application

Expand Down

0 comments on commit 6a9623b

Please sign in to comment.