Skip to content

Instantly share code, notes, and snippets.

@jamiehodge
Created June 3, 2013 14:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamiehodge/5698709 to your computer and use it in GitHub Desktop.
Save jamiehodge/5698709 to your computer and use it in GitHub Desktop.
Drag and drop ordered list
require 'sequel'
DB = Sequel.sqlite
DB.create_table :collections do
primary_key :id
end
DB.create_table :items do
primary_key :id
foreign_key :collection_id, :collections
text :name
integer :position
end
class Collection < Sequel::Model
one_to_many :items
end
class Item < Sequel::Model
plugin :list, scope: :collection_id
many_to_one :collection
end
parent = Collection.create
('a'..'g').to_a.each {|name| parent.add_item(name: name) }
require 'sinatra'
require 'slim'
require 'coffee-script'
require 'sass'
def indexes
Collection.first.items_dataset.select_map(:id)
end
get '/' do
slim :list, locals: { items: Item }, layout: !request.xhr?
end
put '/:id' do
item = Item[ params[:id] ]
position = params.delete('position')
item.move_to(position.to_i) if position
p indexes
redirect to '/'
end
__END__
@@layout
doctype html
head
body
main == yield
@@list
ul.list
- items.each_with_index do |item,index|
li
a href=url(item.id) data-position=item.position item #{item.name}
scss:
li {
list-style: none;
}
li a {
text-decoration: none;
color: #000;
margin: 10px;
width: 150px;
border: 3px dashed #999;
background: #eee;
padding: 10px;
display: block;
}
*[draggable] {
-webkit-user-select: none;
-webkit-user-drag: element;
cursor: move;
}
*:-webkit-drag {
background-color: rgba(238, 238, 238, 0.5);
}
li a:hover:after {
content: ' (drag me)';
}
ul {
margin-left: 200px;
min-height: 300px;
}
li a.over {
border-color: #333;
background: #ccc;
}
coffee:
class List
constructor: (@element) ->
document.addEventListener 'dragstart', @started, false
document.addEventListener 'dragenter', @entered, false
document.addEventListener 'dragover', @over, false
document.addEventListener 'dragleave', @left, false
document.addEventListener 'drop', @dropped, false
document.addEventListener 'dragend', @ended, false
move: (position) =>
data = new FormData
data.append 'position', position
request = new XMLHttpRequest
request.onerror = -> alert 'error'
request.onload = @moved
request.open 'put', @selection.href, true
request.setRequestHeader 'X-Requested-With', 'XMLHttpRequest'
request.responseType = 'document'
request.send data
moved: (e) =>
@element.innerHTML = e.currentTarget.responseXML.querySelector('.list').innerHTML
started: (e) =>
@selection = e.target
e.dataTransfer.effectAllowed = 'move'
e.dataTransfer.setData 'text/html', @selection.innerHTML
entered: (e) =>
@focus e.target
over: (e) ->
e.preventDefault()
e.dataTransfer.dropEffect = 'move'
false
left: (e) =>
@blur e.target
dropped: (e) =>
e.stopPropagation()
if @selection isnt e.target
@move e.target.dataset.position
@blur @element.querySelectorAll('.over')...
ended: (e) =>
@blur @element.querySelectorAll('.over')...
focus: (element) ->
element.classList.add 'over'
blur: (elements...) ->
for element in elements
element.classList.remove 'over'
new List(document.querySelector('.list'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment