mirror of https://github.com/RubaXa/Sortable.git
RubaXa
11 years ago
commit
6ace554483
7 changed files with 963 additions and 0 deletions
@ -0,0 +1,31 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
module.exports = function (grunt){ |
||||||
|
grunt.initConfig({ |
||||||
|
pkg: grunt.file.readJSON('package.json'), |
||||||
|
|
||||||
|
version: { |
||||||
|
src: '<%= pkg.exportName %>.js' |
||||||
|
}, |
||||||
|
|
||||||
|
uglify: { |
||||||
|
options: { |
||||||
|
banner: '/*! <%= pkg.exportName %> <%= pkg.version %> - <%= pkg.license %> | <%= pkg.repository.url %> */\n' |
||||||
|
}, |
||||||
|
dist: { |
||||||
|
files: { |
||||||
|
'<%= pkg.exportName %>.min.js': ['<%= pkg.exportName %>.js'] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
// These plugins provide necessary tasks.
|
||||||
|
grunt.loadNpmTasks('grunt-version'); |
||||||
|
grunt.loadNpmTasks('grunt-contrib-uglify'); |
||||||
|
|
||||||
|
|
||||||
|
// Default task.
|
||||||
|
grunt.registerTask('default', ['version', 'uglify']); |
||||||
|
}; |
@ -0,0 +1,46 @@ |
|||||||
|
# Sortable |
||||||
|
|
||||||
|
|
||||||
|
## Features |
||||||
|
* Support touch devices |
||||||
|
* Built using native HTML5 drag and drop API |
||||||
|
* Simple API |
||||||
|
* Lightweight, 2KB gzipped |
||||||
|
* No jQuery |
||||||
|
|
||||||
|
|
||||||
|
### Usage |
||||||
|
```html |
||||||
|
<ul id="items"> |
||||||
|
<li>item 1</li> |
||||||
|
<li>item 2</li> |
||||||
|
<li>item 3</li> |
||||||
|
</ul> |
||||||
|
``` |
||||||
|
|
||||||
|
```js |
||||||
|
new Sortable(items); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Options |
||||||
|
```js |
||||||
|
new Sortable(elem, { |
||||||
|
group: "name", |
||||||
|
handle: ".my-handle", // Restricts sort start click/touch to the specified element |
||||||
|
draggable: ".item", // Specifies which items inside the element should be sortable |
||||||
|
ghostClass: "sortable-ghost", |
||||||
|
|
||||||
|
onAdd: function (evt){ |
||||||
|
var itemEl = ui.detail; |
||||||
|
}, |
||||||
|
|
||||||
|
onUpdate: function (evt){ |
||||||
|
var itemEl = ui.detail; // the current dragged HTMLElement |
||||||
|
}, |
||||||
|
|
||||||
|
onRemove: function (evt){ |
||||||
|
var itemEl = ui.detail; |
||||||
|
} |
||||||
|
}); |
||||||
|
``` |
@ -0,0 +1,474 @@ |
|||||||
|
/**! |
||||||
|
* Sortable |
||||||
|
* @author RubaXa <trash@rubaxa.org> |
||||||
|
* @license MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
(function (factory){ |
||||||
|
"use strict"; |
||||||
|
|
||||||
|
if( typeof define === "function" && define.amd ){ |
||||||
|
define("Sortable", [], factory); |
||||||
|
} |
||||||
|
else { |
||||||
|
window["Sortable"] = factory(); |
||||||
|
} |
||||||
|
})(function (){ |
||||||
|
"use strict"; |
||||||
|
|
||||||
|
var |
||||||
|
dragEl |
||||||
|
, ghostEl |
||||||
|
, rootEl |
||||||
|
, nextEl |
||||||
|
|
||||||
|
, lastEl |
||||||
|
, lastCSS |
||||||
|
|
||||||
|
, activeGroup |
||||||
|
|
||||||
|
, tapEvt |
||||||
|
, touchEvt |
||||||
|
|
||||||
|
, expando = 'Sortable' + (new Date).getTime() |
||||||
|
|
||||||
|
, win = window |
||||||
|
, document = win.document |
||||||
|
, parseInt = win.parseInt |
||||||
|
, Event = win.CustomEvent |
||||||
|
|
||||||
|
, noop = function (){} |
||||||
|
, slice = [].slice |
||||||
|
|
||||||
|
, touchDragOverListeners = [] |
||||||
|
; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @class Sortable |
||||||
|
* @param {HTMLElement} el |
||||||
|
* @param {Object} [options] |
||||||
|
* @constructor |
||||||
|
*/ |
||||||
|
function Sortable(el, options){ |
||||||
|
this.el = el; // root element
|
||||||
|
this.options = options = (options || {}); |
||||||
|
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
options.group = options.group || Math.random(); |
||||||
|
options.handle = options.handle || null; |
||||||
|
options.draggable = options.draggable || el.children[0] && el.children[0].nodeName || 'li'; |
||||||
|
options.ghostClass = options.ghostClass || 'sortable-ghost'; |
||||||
|
|
||||||
|
options.onAdd = _bind(this, options.onAdd || noop); |
||||||
|
options.onUpdate = _bind(this, options.onUpdate || noop); |
||||||
|
options.onRemove = _bind(this, options.onRemove || noop); |
||||||
|
|
||||||
|
|
||||||
|
el[expando] = options.group; |
||||||
|
|
||||||
|
|
||||||
|
// Bind all prevate methods
|
||||||
|
for( var fn in this ){ |
||||||
|
if( fn.charAt(0) === '_' ){ |
||||||
|
this[fn] = _bind(this, this[fn]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Bind events
|
||||||
|
_on(el, 'add', options.onAdd); |
||||||
|
_on(el, 'update', options.onUpdate); |
||||||
|
_on(el, 'remove', options.onRemove); |
||||||
|
|
||||||
|
_on(el, 'mousedown', this._onTapStart); |
||||||
|
_on(el, 'touchstart', this._onTapStart); |
||||||
|
|
||||||
|
_on(el, 'dragover', this._onDragOver); |
||||||
|
_on(el, 'dragenter', this._onDragOver); |
||||||
|
|
||||||
|
touchDragOverListeners.push(this._onDragOver); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
Sortable.prototype = { |
||||||
|
constructor: Sortable, |
||||||
|
|
||||||
|
|
||||||
|
_applyEffects: function (){ |
||||||
|
_toggleClass(dragEl, this.options.ghostClass, true); |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
_onTapStart: function (evt/**TouchEvent*/){ |
||||||
|
var |
||||||
|
touch = evt.touches && evt.touches[0] |
||||||
|
, target = (touch || evt).target |
||||||
|
, options = this.options |
||||||
|
; |
||||||
|
|
||||||
|
if( options.handle ){ |
||||||
|
target = _closest(target, options.handle, this.el); |
||||||
|
} |
||||||
|
|
||||||
|
target = _closest(target, options.draggable, this.el); |
||||||
|
|
||||||
|
if( target && !dragEl ){ |
||||||
|
tapEvt = evt; |
||||||
|
target.draggable = true; |
||||||
|
|
||||||
|
// Disable "draggable"
|
||||||
|
_find(target, 'a', _disableDraggable); |
||||||
|
_find(target, 'img', _disableDraggable); |
||||||
|
|
||||||
|
|
||||||
|
if( touch ){ |
||||||
|
// Touch device support
|
||||||
|
tapEvt = { |
||||||
|
target: target |
||||||
|
, clientX: touch.clientX |
||||||
|
, clientY: touch.clientY |
||||||
|
}; |
||||||
|
this._onDragStart(tapEvt, true); |
||||||
|
evt.preventDefault(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
_on(this.el, 'dragstart', this._onDragStart); |
||||||
|
_on(document, 'dragover', _globalDragOver); |
||||||
|
|
||||||
|
|
||||||
|
try { |
||||||
|
if( document.selection ){ |
||||||
|
document.selection.empty(); |
||||||
|
} else { |
||||||
|
window.getSelection().removeAllRanges() |
||||||
|
} |
||||||
|
} catch (err){ } |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
_emulateDragOver: function (){ |
||||||
|
if( touchEvt ){ |
||||||
|
_css(ghostEl, 'display', 'none'); |
||||||
|
|
||||||
|
var |
||||||
|
target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY) |
||||||
|
, parent = target |
||||||
|
, group = this.options.group |
||||||
|
, i = touchDragOverListeners.length |
||||||
|
; |
||||||
|
|
||||||
|
do { |
||||||
|
if( parent[expando] === group ){ |
||||||
|
|
||||||
|
while( i-- ){ |
||||||
|
touchDragOverListeners[i]({ |
||||||
|
clientX: touchEvt.clientX, |
||||||
|
clientY: touchEvt.clientY, |
||||||
|
target: target, |
||||||
|
rootEl: parent |
||||||
|
}); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
while( parent = parent.parentNode ); |
||||||
|
|
||||||
|
_css(ghostEl, 'display', ''); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
_onTouchMove: function (evt){ |
||||||
|
if( tapEvt ){ |
||||||
|
var |
||||||
|
touch = evt.touches[0] |
||||||
|
, dx = touch.clientX - tapEvt.clientX |
||||||
|
, dy = touch.clientY - tapEvt.clientY |
||||||
|
; |
||||||
|
|
||||||
|
touchEvt = touch; |
||||||
|
_css(ghostEl, 'webkitTransform', 'translate3d('+dx+'px,'+dy+'px,0)'); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
_onDragStart: function (evt/**Event*/, isTouch){ |
||||||
|
var |
||||||
|
target = evt.target |
||||||
|
, dataTransfer = evt.dataTransfer |
||||||
|
; |
||||||
|
|
||||||
|
rootEl = this.el; |
||||||
|
dragEl = target; |
||||||
|
nextEl = target.nextSibling; |
||||||
|
activeGroup = this.options.group; |
||||||
|
|
||||||
|
if( isTouch ){ |
||||||
|
var rect = target.getBoundingClientRect(), css = _css(target); |
||||||
|
|
||||||
|
ghostEl = target.cloneNode(true); |
||||||
|
|
||||||
|
_css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10)); |
||||||
|
_css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10)); |
||||||
|
_css(ghostEl, 'width', rect.right - rect.left); |
||||||
|
_css(ghostEl, 'height', rect.bottom - rect.top); |
||||||
|
_css(ghostEl, 'opacity', '0.8'); |
||||||
|
_css(ghostEl, 'position', 'fixed'); |
||||||
|
_css(ghostEl, 'zIndex', '100000'); |
||||||
|
|
||||||
|
target.parentNode.insertBefore(ghostEl, target); |
||||||
|
|
||||||
|
// Bind touch events
|
||||||
|
_on(document, 'touchmove', this._onTouchMove); |
||||||
|
_on(document, 'touchend', this._onDrop); |
||||||
|
|
||||||
|
this._loopId = setInterval(this._emulateDragOver, 100); |
||||||
|
} |
||||||
|
else { |
||||||
|
dataTransfer.effectAllowed = 'move'; |
||||||
|
dataTransfer.setData('Text', target.textContent); |
||||||
|
|
||||||
|
_on(document, 'drop', this._onDrop); |
||||||
|
} |
||||||
|
|
||||||
|
setTimeout(this._applyEffects); |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
_onDragOver: function (evt){ |
||||||
|
if( activeGroup === this.options.group && (evt.rootEl === void 0 || evt.rootEl === this.el) ){ |
||||||
|
var |
||||||
|
el = this.el |
||||||
|
, target = _closest(evt.target, this.options.draggable, el) |
||||||
|
; |
||||||
|
|
||||||
|
|
||||||
|
if( el.children.length === 0 || target == null ){ |
||||||
|
el.appendChild(dragEl); |
||||||
|
} |
||||||
|
else if( target && (target !== dragEl) ){ |
||||||
|
if( lastEl !== target ){ |
||||||
|
lastEl = target; |
||||||
|
lastCSS = _css(target) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var |
||||||
|
rect = target.getBoundingClientRect() |
||||||
|
, width = rect.right - rect.left |
||||||
|
, height = rect.bottom - rect.top |
||||||
|
, floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display) |
||||||
|
, after = !floating && (evt.clientY - rect.top)/height > .5 || floating && (evt.clientX - rect.left)/width > .5 |
||||||
|
, nextSibling = target.nextSibling |
||||||
|
; |
||||||
|
|
||||||
|
|
||||||
|
if( after && !nextSibling ){ |
||||||
|
el.appendChild(dragEl); |
||||||
|
} else { |
||||||
|
target.parentNode.insertBefore(dragEl, after ? nextSibling : target); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
_onDrop: function (evt/**Event*/){ |
||||||
|
clearInterval(this._loopId); |
||||||
|
|
||||||
|
// Unbind events
|
||||||
|
_off(document, 'drop', this._onDrop); |
||||||
|
_off(document, 'dragover', _globalDragOver); |
||||||
|
|
||||||
|
_off(this.el, 'dragstart', this._onDragStart); |
||||||
|
|
||||||
|
_off(document, 'touchmove', this._onTouchMove); |
||||||
|
_off(document, 'touchend', this._onDrop); |
||||||
|
|
||||||
|
|
||||||
|
if( evt ){ |
||||||
|
evt.preventDefault(); |
||||||
|
|
||||||
|
if( dragEl ){ |
||||||
|
var opts = { bubbles: true, cancelable: true, detail: dragEl }; |
||||||
|
|
||||||
|
_toggleClass(dragEl, this.options.ghostClass, false); |
||||||
|
|
||||||
|
if( !rootEl.contains(dragEl) ){ |
||||||
|
// Remove event
|
||||||
|
rootEl.dispatchEvent(new Event('remove', opts)); |
||||||
|
|
||||||
|
// Add event
|
||||||
|
dragEl.dispatchEvent(new Event('add', opts)); |
||||||
|
} |
||||||
|
else if( dragEl.nextSibling !== nextEl ){ |
||||||
|
// Update event
|
||||||
|
dragEl.dispatchEvent(new Event('update', opts)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if( ghostEl ){ |
||||||
|
ghostEl.parentNode.removeChild(ghostEl); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Set NULL
|
||||||
|
rootEl = |
||||||
|
dragEl = |
||||||
|
ghostEl = |
||||||
|
nextEl = |
||||||
|
|
||||||
|
tapEvt = |
||||||
|
touchEvt = |
||||||
|
|
||||||
|
lastEl = |
||||||
|
lastCSS = |
||||||
|
|
||||||
|
activeGroup = null; |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
|
||||||
|
destroy: function (){ |
||||||
|
var el = this.el, options = this.options; |
||||||
|
|
||||||
|
_off(el, 'add', options.onAdd); |
||||||
|
_off(el, 'update', options.onUpdate); |
||||||
|
_off(el, 'remove', options.onRemove); |
||||||
|
|
||||||
|
_off(el, 'mousedown', this._onTapStart); |
||||||
|
_off(el, 'touchstart', this._onTapStart); |
||||||
|
|
||||||
|
_off(el, 'dragover', this._onDragOver); |
||||||
|
_off(el, 'dragenter', this._onDragOver); |
||||||
|
|
||||||
|
touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1); |
||||||
|
|
||||||
|
this._onDrop(); |
||||||
|
|
||||||
|
this.el = null; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
function _bind(ctx, fn){ |
||||||
|
var args = slice.call(arguments, 2); |
||||||
|
return fn.bind ? fn.bind.apply(fn, [ctx].concat(args)) : function (){ |
||||||
|
return fn.apply(ctx, args.concat(slice.call(arguments))); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _closest(el, selector, ctx){ |
||||||
|
if( el && ctx ){ |
||||||
|
ctx = ctx || document; |
||||||
|
selector = selector.split('.'); |
||||||
|
|
||||||
|
var |
||||||
|
tag = selector.shift().toUpperCase() |
||||||
|
, re = new RegExp('\\b('+selector.join('|')+')\\b', 'g') |
||||||
|
; |
||||||
|
|
||||||
|
do { |
||||||
|
if( |
||||||
|
(tag === '' || el.nodeName == tag) |
||||||
|
&& (!selector.length || ((el.className+'').match(re) || []).length == selector.length) |
||||||
|
){ |
||||||
|
return el; |
||||||
|
} |
||||||
|
} |
||||||
|
while( el !== ctx && (el = el.parentNode) ); |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _globalDragOver(evt){ |
||||||
|
evt.dataTransfer.dropEffect = 'move'; |
||||||
|
evt.preventDefault(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _on(el, event, fn){ |
||||||
|
el.addEventListener(event, fn, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _off(el, event, fn){ |
||||||
|
el.removeEventListener(event, fn, false); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _toggleClass(el, name, state){ |
||||||
|
if( el ){ |
||||||
|
if( el.classList ){ |
||||||
|
el.classList[state ? 'add' : 'remove'](name); |
||||||
|
} |
||||||
|
else { |
||||||
|
var className = (' '+el.className+' ').replace(' '+name+' ', '').replace(/\s+/g, ' '); |
||||||
|
el.className = className + (state ? ' '+name : '') |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _css(el, prop, val){ |
||||||
|
if( el && el.style ){ |
||||||
|
if( val === void 0 ){ |
||||||
|
if( document.defaultView && document.defaultView.getComputedStyle ){ |
||||||
|
val = document.defaultView.getComputedStyle(el, ''); |
||||||
|
} |
||||||
|
else if( el.currentStyle ){ |
||||||
|
val = el.currentStyle; |
||||||
|
} |
||||||
|
return prop === void 0 ? val : val[prop]; |
||||||
|
} else { |
||||||
|
el.style[prop] = val + (typeof val === 'string' ? '' : 'px'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _find(ctx, tagName, iterator){ |
||||||
|
if( ctx ){ |
||||||
|
var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length; |
||||||
|
if( iterator ){ |
||||||
|
for( ; i < n; i++ ){ |
||||||
|
iterator(list[i], i); |
||||||
|
} |
||||||
|
} |
||||||
|
return list; |
||||||
|
} |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function _disableDraggable(el){ |
||||||
|
return el.draggable = false; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Export utils
|
||||||
|
Sortable.utils = { |
||||||
|
on: _on, |
||||||
|
off: _off, |
||||||
|
css: _css, |
||||||
|
find: _find, |
||||||
|
bind: _bind, |
||||||
|
closest: _closest, |
||||||
|
toggleClass: _toggleClass |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
Sortable.version = '0.1.0'; |
||||||
|
|
||||||
|
// Export
|
||||||
|
return Sortable; |
||||||
|
}); |
File diff suppressed because one or more lines are too long
@ -0,0 +1,387 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"/> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> |
||||||
|
|
||||||
|
<title>Sortable (No jQuery)</title> |
||||||
|
|
||||||
|
<meta name="keywords" content="sortable, reorder, list, javascript, html5, drag and drop, dnd, rubaxa"/> |
||||||
|
<meta name="description" content="Sortable - is a minimalist JavaScript library for modern browsers and touch devices (No jQuery)."/> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/> |
||||||
|
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"> |
||||||
|
|
||||||
|
<style> |
||||||
|
@import url(http://fonts.googleapis.com/css?family=Roboto:300); |
||||||
|
|
||||||
|
|
||||||
|
html, body { |
||||||
|
color: #333; |
||||||
|
min-height: 100%; |
||||||
|
font-size: 18px; |
||||||
|
font-family: "Arial", Helvetica, Garuda, sans-serif; |
||||||
|
} |
||||||
|
|
||||||
|
h1, h2, h3 { |
||||||
|
font-family: 'Roboto', sans-serif; |
||||||
|
font-weight: 300; |
||||||
|
} |
||||||
|
|
||||||
|
h1 a { |
||||||
|
color: #333; |
||||||
|
text-decoration: underline; |
||||||
|
} |
||||||
|
|
||||||
|
h1 + div { |
||||||
|
opacity: 0.95; |
||||||
|
margin-bottom: 50px; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
ul { |
||||||
|
margin: 0; |
||||||
|
padding: 0; |
||||||
|
list-style: none; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
.sortable-ghost { |
||||||
|
opacity: .2; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
img { vertical-align: middle; } |
||||||
|
|
||||||
|
#contacts { |
||||||
|
border-radius: 3px; |
||||||
|
box-shadow: 0 0 1px rgba(0,0,0,0.4); |
||||||
|
} |
||||||
|
#contacts li:first-child { |
||||||
|
border-radius: 3px 3px 0 0; |
||||||
|
} |
||||||
|
#contacts li:last-child { |
||||||
|
border-radius: 0 0 3px 3px; |
||||||
|
} |
||||||
|
|
||||||
|
#contacts li { |
||||||
|
cursor: move; |
||||||
|
padding: 10px; |
||||||
|
background: rgba(255,255,255,.8); |
||||||
|
border-bottom: 1px solid #ccc; |
||||||
|
} |
||||||
|
|
||||||
|
#contacts img { |
||||||
|
margin-right: 5px; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#tags { |
||||||
|
min-height: 100px; |
||||||
|
box-shadow: 0 1px 1px rgba(0,0,0,0.3); |
||||||
|
border-radius: 5px; |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
|
||||||
|
#tags li { |
||||||
|
cursor: move; |
||||||
|
float: left; |
||||||
|
margin: 10px; |
||||||
|
padding: 6px 15px; |
||||||
|
background: #B7D967; |
||||||
|
border-radius: 3px; |
||||||
|
box-shadow: 0 2px 0 #6d823d; |
||||||
|
text-shadow: 0 1px 1px rgba(255,255,255,0.6); |
||||||
|
} |
||||||
|
|
||||||
|
#tags img { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
.tile { |
||||||
|
width: 280px; |
||||||
|
float: left; |
||||||
|
padding: 2px; |
||||||
|
box-shadow: 0 0 0 3px rgba(0,0,0,0.2); |
||||||
|
background-color: #fff; |
||||||
|
margin-right: 30px; |
||||||
|
margin-bottom: 30px; |
||||||
|
} |
||||||
|
.tile__title { |
||||||
|
cursor: pointer; |
||||||
|
padding: 7px 0 10px; |
||||||
|
text-align: center; |
||||||
|
background-color: #E0E4F2; |
||||||
|
} |
||||||
|
|
||||||
|
.tile__list { |
||||||
|
padding: 15px; |
||||||
|
} |
||||||
|
.tile__list img { |
||||||
|
margin: 10px; |
||||||
|
cursor: move; |
||||||
|
} |
||||||
|
|
||||||
|
.download { |
||||||
|
color: #333; |
||||||
|
margin-left: 10px; |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
.download:hover { |
||||||
|
text-decoration: none; |
||||||
|
} |
||||||
|
</style> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
|
||||||
|
<a href="https://github.com/RubaXa/Sortable"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a> |
||||||
|
|
||||||
|
<div class="container"> |
||||||
|
<h1> |
||||||
|
<a href="https://github.com/RubaXa/Sortable/">Sortable</a> |
||||||
|
<a class="download" title="Download" href="https://github.com/RubaXa/Sortable/archive/master.zip">↓</a> |
||||||
|
</h1> |
||||||
|
<div>— is a minimalist JavaScript library for modern browsers and touch devices (No jQuery).</div> |
||||||
|
|
||||||
|
|
||||||
|
<div class="row"> |
||||||
|
<div class="col-md-6 col-sm-6"> |
||||||
|
<h3>List A</h3> |
||||||
|
|
||||||
|
<ul id="contacts"> |
||||||
|
<li> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-prn1/s32x32/41627_1611219478_5779_q.jpg"/> |
||||||
|
<span>Catherine</span> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash3/s32x32/370175_619386670_43244658_q.jpg"/> |
||||||
|
<span>Polina</span> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash3/s32x32/173108_654249662_698694459_q.jpg"/> |
||||||
|
<span>Duke</span> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-prn2/s32x32/372024_100000330534964_827799899_q.jpg"/> |
||||||
|
<span>Adnrey</span> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash1/s32x32/260934_100000460170867_1741520317_q.jpg"/> |
||||||
|
<span>Maxim</span> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="col-md-6 col-sm-6"> |
||||||
|
<h3>List B</h3> |
||||||
|
|
||||||
|
<ul id="tags"> |
||||||
|
<li> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash2/s32x32/274297_100002088418977_1552918698_q.jpg"/> |
||||||
|
<span>Ilya</span> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash1/s32x32/370664_100003149104712_1050952731_q.jpg"/> |
||||||
|
<span>Anna</span> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p> </p> |
||||||
|
<p> </p> |
||||||
|
|
||||||
|
<div class="container" id="multi"> |
||||||
|
<h2>Multi</h2> |
||||||
|
|
||||||
|
<div class="tile"> |
||||||
|
<div class="tile__title">Group A</div> |
||||||
|
<div class="tile__list"> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-prn1/c9.9.113.113/s100x100/59436_1391411357920_1388516_s.jpg"/><!-- |
||||||
|
--><img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash3/c13.8.104.104/s100x100/941190_10151608397684663_1532692251_s.jpg"/><!-- |
||||||
|
--><img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-frc3/c0.0.103.103/s100x100/382696_10150378364701671_1792621129_a.jpg"/><!-- |
||||||
|
--><img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash3/c44.10.116.116/s100x100/552948_430685950285752_1435082176_a.jpg"/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="tile"> |
||||||
|
<div class="tile__title">Group B</div> |
||||||
|
<div class="tile__list"> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash3/c8.8.105.105/s100x100/558916_4874661741992_448469446_s.jpg"/><!-- |
||||||
|
--><img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-prn1/c29.9.117.117/s100x100/68347_385372304875713_1358705380_a.jpg"/><!-- |
||||||
|
--><img src="https://fbcdn-profile-a.akamaihd.net/hprofile-ak-ash2/c9.9.113.113/s100x100/424349_465457316812937_2106915541_s.jpg"/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="tile"> |
||||||
|
<div class="tile__title">Group C</div> |
||||||
|
<div class="tile__list"> |
||||||
|
<img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-frc3/c12.12.156.156/s100x100/303317_320632284665935_15996162_a.jpg"/><!-- |
||||||
|
--><img src="//fbcdn-profile-a.akamaihd.net/hprofile-ak-ash2/c9.9.109.109/s100x100/484507_4207733265938_1693034881_s.jpg"/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="row"></div> |
||||||
|
<p> </p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="container"> |
||||||
|
<h2>Code example</h2> |
||||||
|
<pre class="javascript"><code>// Simple list |
||||||
|
var list = document.getElementById("my-ui-list"); |
||||||
|
new Sortable(list); // That's all. |
||||||
|
|
||||||
|
|
||||||
|
// Grouping |
||||||
|
var foo = document.getElementById("foo"); |
||||||
|
new Sortable(foo, { group: "omega" }); |
||||||
|
|
||||||
|
var bar = document.getElementById("bar"); |
||||||
|
new Sortable(bar, { group: "omega" }); |
||||||
|
|
||||||
|
|
||||||
|
// Or |
||||||
|
var container = document.getElementById("multi"); |
||||||
|
var sort = new Sortable(container, { |
||||||
|
handle: ".tile__title", // Restricts sort start click/touch to the specified element |
||||||
|
dragabble: ".tile", // Specifies which items inside the element should be sortable |
||||||
|
onUpdate: function (evt/**Event*/){ |
||||||
|
var item = evt.detail; // the current dragged HTMLElement |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// .. |
||||||
|
sort.destroy(); |
||||||
|
</code></pre> |
||||||
|
|
||||||
|
<p> </p> |
||||||
|
<p> </p> |
||||||
|
<p> </p> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
<script src="Sortable.js"></script> |
||||||
|
|
||||||
|
<script> |
||||||
|
(function (){ |
||||||
|
var console = window.console; |
||||||
|
|
||||||
|
if( !console.log ){ |
||||||
|
console.log = function (){ |
||||||
|
alert([].join.apply(arguments, ' ')); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
new Sortable(contacts, { |
||||||
|
group: "contacts", |
||||||
|
onAdd: function (evt){ console.log('onAdd.contacts:', evt.detail); }, |
||||||
|
onUpdate: function (evt){ console.log('onUpdate.contacts:', evt.detail); }, |
||||||
|
onRemove: function (evt){ console.log('onRemove.contacts:', evt.detail); } |
||||||
|
}); |
||||||
|
|
||||||
|
new Sortable(tags, { |
||||||
|
group: "contacts", |
||||||
|
onAdd: function (evt){ console.log('onAdd.tags:', evt.detail); }, |
||||||
|
onUpdate: function (evt){ console.log('onUpdate.tags:', evt.detail); }, |
||||||
|
onRemove: function (evt){ console.log('onRemove.tags:', evt.detail); } |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
new Sortable(multi, { |
||||||
|
draggable: '.tile', |
||||||
|
handle: '.tile__title' |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
[].forEach.call(multi.getElementsByClassName('tile__list'), function (el){ |
||||||
|
new Sortable(el, { group: 'photo' }); |
||||||
|
}); |
||||||
|
})(); |
||||||
|
|
||||||
|
|
||||||
|
function setNoiseBackground(el, color, width, height, opacity){ |
||||||
|
var canvas = document.createElement("canvas"); |
||||||
|
var context = canvas.getContext("2d"); |
||||||
|
|
||||||
|
canvas.width = width; |
||||||
|
canvas.height = height; |
||||||
|
|
||||||
|
for( var i = 0; i < width; i++ ){ |
||||||
|
for( var j = 0; j < height; j++ ){ |
||||||
|
var val = Math.floor(Math.random() * 255); |
||||||
|
context.fillStyle = "rgba(" + val + "," + val + "," + val + "," + opacity + ")"; |
||||||
|
context.fillRect(i, j, 1, 1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
el.style.background = "url(" + canvas.toDataURL("image/png") + "), "+color; |
||||||
|
} |
||||||
|
|
||||||
|
// Usage |
||||||
|
setNoiseBackground(document.getElementsByTagName('body')[0], "linear-gradient(to bottom, #E1E2D1 0%, #5AABA5 100%)", 50, 50, 0.03); |
||||||
|
</script> |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- highlight.js --> |
||||||
|
<style> |
||||||
|
/* Tomorrow Theme */ |
||||||
|
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ |
||||||
|
/* Original theme - https://github.com/chriskempson/tomorrow-theme */ |
||||||
|
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ |
||||||
|
.tomorrow-comment, pre .comment, pre .title { |
||||||
|
color: #8e908c; |
||||||
|
} |
||||||
|
|
||||||
|
.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { |
||||||
|
color: #c82829; |
||||||
|
} |
||||||
|
|
||||||
|
.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { |
||||||
|
color: #f5871f; |
||||||
|
} |
||||||
|
|
||||||
|
.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { |
||||||
|
color: #eab700; |
||||||
|
} |
||||||
|
|
||||||
|
.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { |
||||||
|
color: #718c00; |
||||||
|
} |
||||||
|
|
||||||
|
.tomorrow-aqua, pre .css .hexcolor { |
||||||
|
color: #3e999f; |
||||||
|
} |
||||||
|
|
||||||
|
.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { |
||||||
|
color: #4271ae; |
||||||
|
} |
||||||
|
|
||||||
|
.tomorrow-purple, pre .keyword, pre .javascript .function { |
||||||
|
color: #8959a8; |
||||||
|
} |
||||||
|
|
||||||
|
pre { |
||||||
|
border: 0; |
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,0.4); |
||||||
|
background-color: #fff; |
||||||
|
} |
||||||
|
|
||||||
|
pre code { |
||||||
|
display: block; |
||||||
|
color: #4d4d4c; |
||||||
|
font-family: Menlo, Monaco, Consolas, monospace; |
||||||
|
line-height: 1.5; |
||||||
|
padding: 10px; |
||||||
|
} |
||||||
|
</style> |
||||||
|
|
||||||
|
<script src="//yandex.st/highlightjs/7.5/highlight.min.js"></script> |
||||||
|
<script>hljs.initHighlightingOnLoad();</script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,22 @@ |
|||||||
|
{ |
||||||
|
"name": "sortable", |
||||||
|
"exportName": "Sortable", |
||||||
|
"version": "0.1.0", |
||||||
|
"devDependencies": { |
||||||
|
"grunt": "*", |
||||||
|
"grunt-version": "*", |
||||||
|
"grunt-contrib-uglify": "*" |
||||||
|
}, |
||||||
|
"description": "Sortable - is a minimalist JavaScript library for modern browsers and touch devices (No jQuery).", |
||||||
|
"main": "Sortable.js", |
||||||
|
"scripts": { |
||||||
|
"test": "grunt" |
||||||
|
}, |
||||||
|
"repository": { |
||||||
|
"type": "git", |
||||||
|
"url": "git://github.com/rubaxa/Sortable.git" |
||||||
|
}, |
||||||
|
"keywords": ["sortable", "reorder"], |
||||||
|
"author": "Konstantin Lebedev <ibnRubaXa@gmail.com>", |
||||||
|
"license": "MIT" |
||||||
|
} |
Loading…
Reference in new issue