From 8dff9a653d270e8b27ea42849e4d4958f3b9765c Mon Sep 17 00:00:00 2001 From: Aaron Wiggins Date: Wed, 15 Jul 2015 00:05:41 -0400 Subject: [PATCH] create partial for instructions --- app/views/experiments/_instructions.html.erb | 3 + app/views/experiments/instructions.js | 21 + vendor/assets/javascripts/html.sortable.js | 398 +++++++++++++++++++ 3 files changed, 422 insertions(+) create mode 100644 app/views/experiments/_instructions.html.erb create mode 100644 app/views/experiments/instructions.js create mode 100644 vendor/assets/javascripts/html.sortable.js diff --git a/app/views/experiments/_instructions.html.erb b/app/views/experiments/_instructions.html.erb new file mode 100644 index 0000000..8227fcd --- /dev/null +++ b/app/views/experiments/_instructions.html.erb @@ -0,0 +1,3 @@ +
+ <%= instruction.order_number %> | <%= instruction.information %>
+
diff --git a/app/views/experiments/instructions.js b/app/views/experiments/instructions.js new file mode 100644 index 0000000..5154cce --- /dev/null +++ b/app/views/experiments/instructions.js @@ -0,0 +1,21 @@ +var ready, set_positions; + +set_positions = function(){ + + // loop through and give each task a data-pos + // attribute that holds its position in the DOM + $('.panel.panel-default').each(function(i){ + $(this).attr("data-pos",i+1); + }); +} + +ready = function(){ + + // call set_positions function + set_positions(); + + $('.sortable').sortable(); + +} + +$(document).ready(ready); diff --git a/vendor/assets/javascripts/html.sortable.js b/vendor/assets/javascripts/html.sortable.js new file mode 100644 index 0000000..8a31a86 --- /dev/null +++ b/vendor/assets/javascripts/html.sortable.js @@ -0,0 +1,398 @@ +/* + * HTML5 Sortable jQuery Plugin + * https://github.com/voidberg/html5sortable + * + * Original code copyright 2012 Ali Farhadi. + * This version is mantained by Alexandru Badiu & Lukas Oppermann + * + * + * Released under the MIT license. + */ +'use strict'; +/* + * variables global to the plugin + */ +var dragging; +var draggingHeight; +var placeholders = $(); +var sortables = []; +/* + * remove event handlers from items + * @param [jquery Collection] items + * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event) + */ +var _removeItemEvents = function(items) { + items.off('dragstart.h5s'); + items.off('dragend.h5s'); + items.off('selectstart.h5s'); + items.off('dragover.h5s'); + items.off('dragenter.h5s'); + items.off('drop.h5s'); +}; +/* + * remove event handlers from sortable + * @param [jquery Collection] sortable + * @info event.h5s (jquery way of namespacing events, to bind multiple handlers to the event) + */ +var _removeSortableEvents = function(sortable) { + sortable.off('dragover.h5s'); + sortable.off('dragenter.h5s'); + sortable.off('drop.h5s'); +}; +/* + * attache ghost to dataTransfer object + * @param [event] original event + * @param [object] ghost-object with item, x and y coordinates + */ +var _attachGhost = function(event, ghost) { + // this needs to be set for HTML5 drag & drop to work + event.dataTransfer.effectAllowed = 'move'; + event.dataTransfer.setData('text', ''); + + // check if setDragImage method is available + if (event.dataTransfer.setDragImage) { + event.dataTransfer.setDragImage(ghost.item, ghost.x, ghost.y); + } +}; +/** + * _addGhostPos clones the dragged item and adds it as a Ghost item + * @param [object] event - the event fired when dragstart is triggered + * @param [object] ghost - .item = node, draggedItem = jQuery collection + */ +var _addGhostPos = function(e, ghost) { + if (!ghost.x) { + ghost.x = parseInt(e.pageX - ghost.draggedItem.offset().left); + } + if (!ghost.y) { + ghost.y = parseInt(e.pageY - ghost.draggedItem.offset().top); + } + return ghost; +}; +/** + * _makeGhost decides which way to make a ghost and passes it to attachGhost + * @param [jQuery selection] $draggedItem - the item that the user drags + */ +var _makeGhost = function($draggedItem) { + return { + item: $draggedItem[0], + draggedItem: $draggedItem + }; +}; +/** + * _getGhost constructs ghost and attaches it to dataTransfer + * @param [event] event - the original drag event object + * @param [jQuery selection] $draggedItem - the item that the user drags + * @param [object] ghostOpt - the ghost options + */ +// TODO: could $draggedItem be replaced by event.target in all instances +var _getGhost = function(event, $draggedItem) { + // add ghost item & draggedItem to ghost object + var ghost = _makeGhost($draggedItem); + // attach ghost position + ghost = _addGhostPos(event, ghost); + // attach ghost to dataTransfer + _attachGhost(event, ghost); +}; +/* + * return options if not set on sortable already + * @param [object] soptions + * @param [object] options + */ +var _getOptions = function(soptions, options) { + if (typeof soptions === 'undefined') { + return options; + } + return soptions; +}; +/* + * remove data from sortable + * @param [jquery Collection] a single sortable + */ +var _removeSortableData = function(sortable) { + sortable.removeData('opts'); + sortable.removeData('connectWith'); + sortable.removeData('items'); + sortable.removeAttr('aria-dropeffect'); +}; +/* + * remove data from items + * @param [jquery Collection] items + */ +var _removeItemData = function(items) { + items.removeAttr('aria-grabbed'); + items.removeAttr('draggable'); + items.removeAttr('role'); +}; +/* + * check if two lists are connected + * @param [jquery Collection] items + */ +var _listsConnected = function(curList, destList) { + if (curList[0] === destList[0]) { + return true; + } + if (curList.data('connectWith') !== undefined) { + return curList.data('connectWith') === destList.data('connectWith'); + } + return false; +}; +/* + * destroy the sortable + * @param [jquery Collection] a single sortable + */ +var _destroySortable = function(sortable) { + var opts = sortable.data('opts') || {}; + var items = sortable.children(opts.items); + var handles = opts.handle ? items.find(opts.handle) : items; + // remove event handlers & data from sortable + _removeSortableEvents(sortable); + _removeSortableData(sortable); + // remove event handlers & data from items + handles.off('mousedown.h5s'); + _removeItemEvents(items); + _removeItemData(items); +}; +/* + * enable the sortable + * @param [jquery Collection] a single sortable + */ +var _enableSortable = function(sortable) { + var opts = sortable.data('opts'); + var items = sortable.children(opts.items); + var handles = opts.handle ? items.find(opts.handle) : items; + sortable.attr('aria-dropeffect', 'move'); + handles.attr('draggable', 'true'); + // IE FIX for ghost + if (typeof document.createElement('span').dragDrop === 'function') { + handles.on('mousedown.h5s', function() { + if (items.index(this) !== -1) { + this.dragDrop(); + } else { + $(this).parents(opts.items)[0].dragDrop(); + } + }); + } +}; +/* + * disable the sortable + * @param [jquery Collection] a single sortable + */ +var _disableSortable = function(sortable) { + var opts = sortable.data('opts'); + var items = sortable.children(opts.items); + var handles = opts.handle ? items.find(opts.handle) : items; + sortable.attr('aria-dropeffect', 'none'); + handles.attr('draggable', false); + handles.off('mousedown.h5s'); +}; +/* + * reload the sortable + * @param [jquery Collection] a single sortable + * @description events need to be removed to not be double bound + */ +var _reloadSortable = function(sortable) { + var opts = sortable.data('opts'); + var items = sortable.children(opts.items); + var handles = opts.handle ? items.find(opts.handle) : items; + // remove event handlers from items + _removeItemEvents(items); + handles.off('mousedown.h5s'); + // remove event handlers from sortable + _removeSortableEvents(sortable); +}; +/* + * public sortable object + * @param [object|string] options|method + */ +var sortable = function(selector, options) { + + var $sortables = $(selector); + var method = String(options); + + options = $.extend({ + connectWith: false, + placeholder: null, + // dragImage can be null or a jQuery element + dragImage: null, + placeholderClass: 'sortable-placeholder', + draggingClass: 'sortable-dragging' + }, options); + + /* TODO: maxstatements should be 25, fix and remove line below */ + /*jshint maxstatements:false */ + return $sortables.each(function() { + + var $sortable = $(this); + + if (/enable|disable|destroy/.test(method)) { + sortable[method]($sortable); + return; + } + + // get options & set options on sortable + options = _getOptions($sortable.data('opts'), options); + $sortable.data('opts', options); + // reset sortable + _reloadSortable($sortable); + // initialize + var items = $sortable.children(options.items); + var index; + var startParent; + var newParent; + var placeholder = (options.placeholder === null) ? $('<' + (/^ul|ol$/i.test(this.tagName) ? 'li' : 'div') + ' class="' + options.placeholderClass + '"/>') : $(options.placeholder).addClass(options.placeholderClass); + + // setup sortable ids + if (!$sortable.attr('data-sortable-id')) { + var id = sortables.length; + sortables[id] = $sortable; + $sortable.attr('data-sortable-id', id); + items.attr('data-item-sortable-id', id); + } + + $sortable.data('items', options.items); + placeholders = placeholders.add(placeholder); + if (options.connectWith) { + $sortable.data('connectWith', options.connectWith); + } + + _enableSortable($sortable); + items.attr('role', 'option'); + items.attr('aria-grabbed', 'false'); + + // Handle drag events on draggable items + items.on('dragstart.h5s', function(e) { + e.stopImmediatePropagation(); + + if (options.dragImage) { + _attachGhost(e.originalEvent, { + item: options.dragImage, + x: 0, + y: 0 + }); + console.log('WARNING: dragImage option is deprecated' + + ' and will be removed in the future!'); + } else { + // add transparent clone or other ghost to cursor + _getGhost(e.originalEvent, $(this), options.dragImage); + } + // cache selsection & add attr for dragging + dragging = $(this); + dragging.addClass(options.draggingClass); + dragging.attr('aria-grabbed', 'true'); + // grab values + index = dragging.index(); + draggingHeight = dragging.height(); + startParent = $(this).parent(); + // trigger sortstar update + dragging.parent().triggerHandler('sortstart', { + item: dragging, + startparent: startParent + }); + }); + // Handle drag events on draggable items + items.on('dragend.h5s', function() { + if (!dragging) { + return; + } + // remove dragging attributes and show item + dragging.removeClass(options.draggingClass); + dragging.attr('aria-grabbed', 'false'); + dragging.show(); + + placeholders.detach(); + newParent = $(this).parent(); + dragging.parent().triggerHandler('sortstop', { + item: dragging, + startparent: startParent, + }); + if (index !== dragging.index() || + startParent.get(0) !== newParent.get(0)) { + dragging.parent().triggerHandler('sortupdate', { + item: dragging, + index: newParent.children(newParent.data('items')).index(dragging), + oldindex: items.index(dragging), + elementIndex: dragging.index(), + oldElementIndex: index, + startparent: startParent, + endparent: newParent + }); + } + dragging = null; + draggingHeight = null; + }); + // Handle drop event on sortable & placeholder + // TODO: REMOVE placeholder????? + $(this).add([placeholder]).on('drop.h5s', function(e) { + if (!_listsConnected($sortable, $(dragging).parent())) { + return; + } + + e.stopPropagation(); + placeholders.filter(':visible').after(dragging); + dragging.trigger('dragend.h5s'); + return false; + }); + + // Handle dragover and dragenter events on draggable items + // TODO: REMOVE placeholder????? + items.add([this, placeholder]).on('dragover.h5s dragenter.h5s', function(e) { + if (!_listsConnected($sortable, $(dragging).parent())) { + return; + } + + e.preventDefault(); + e.originalEvent.dataTransfer.dropEffect = 'move'; + if (items.is(this)) { + var thisHeight = $(this).height(); + if (options.forcePlaceholderSize) { + placeholder.height(draggingHeight); + } + + // Check if $(this) is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering + if (thisHeight > draggingHeight) { + // Dead zone? + var deadZone = thisHeight - draggingHeight; + var offsetTop = $(this).offset().top; + if (placeholder.index() < $(this).index() && + e.originalEvent.pageY < offsetTop + deadZone) { + return false; + } + if (placeholder.index() > $(this).index() && + e.originalEvent.pageY > offsetTop + thisHeight - deadZone) { + return false; + } + } + + dragging.hide(); + if (placeholder.index() < $(this).index()) { + $(this).after(placeholder); + } else { + $(this).before(placeholder); + } + placeholders.not(placeholder).detach(); + } else { + if (!placeholders.is(this) && !$(this).children(options.items).length) { + placeholders.detach(); + $(this).append(placeholder); + } + } + return false; + }); + }); +}; + +sortable.destroy = function(sortable) { + _destroySortable(sortable); +}; + +sortable.enable = function(sortable) { + _enableSortable(sortable); +}; + +sortable.disable = function(sortable) { + _disableSortable(sortable); +}; + +$.fn.sortable = function(options) { + return sortable(this, options); +};