mirror of
https://github.com/wahyd4/cdnjs.git
synced 2026-08-11 22:06:36 +10:00
Added jQuery.Shapeshift v2.0
This commit is contained in:
@@ -0,0 +1,724 @@
|
||||
# Project: jQuery.Shapeshift
|
||||
# Description: Align elements to grid with drag and drop.
|
||||
# Author: Scott Elwood
|
||||
# Maintained By: We the Media, inc.
|
||||
# License: MIT
|
||||
|
||||
(($, window, document) ->
|
||||
pluginName = "shapeshift"
|
||||
defaults =
|
||||
# The Basics
|
||||
selector: "*"
|
||||
|
||||
# Features
|
||||
enableDrag: true
|
||||
enableCrossDrop: true
|
||||
enableResize: true
|
||||
enableTrash: false
|
||||
|
||||
# Grid Properties
|
||||
align: "center"
|
||||
colWidth: null
|
||||
columns: null
|
||||
minColumns: 1
|
||||
autoHeight: true
|
||||
maxHeight: null
|
||||
minHeight: 100
|
||||
gutterX: 10
|
||||
gutterY: 10
|
||||
paddingX: 10
|
||||
paddingY: 10
|
||||
|
||||
# Animation
|
||||
animated: true
|
||||
animateOnInit: false
|
||||
animationSpeed: 225
|
||||
animationThreshold: 100
|
||||
|
||||
# Drag/Drop Options
|
||||
dragClone: false
|
||||
deleteClone: true
|
||||
dragRate: 100
|
||||
dragWhitelist: "*"
|
||||
crossDropWhitelist: "*"
|
||||
cutoffStart: null
|
||||
cutoffEnd: null
|
||||
handle: false
|
||||
|
||||
# Customize CSS
|
||||
cloneClass: "ss-cloned-child"
|
||||
activeClass: "ss-active-child"
|
||||
draggedClass: "ss-dragged-child"
|
||||
placeholderClass: "ss-placeholder-child"
|
||||
originalContainerClass: "ss-original-container"
|
||||
currentContainerClass: "ss-current-container"
|
||||
previousContainerClass: "ss-previous-container"
|
||||
|
||||
class Plugin
|
||||
constructor: (@element, options) ->
|
||||
@options = $.extend {}, defaults, options
|
||||
@globals = {}
|
||||
@$container = $(element)
|
||||
|
||||
if @errorCheck()
|
||||
@init()
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# errorCheck:
|
||||
# Determine if there are any conflicting options
|
||||
# ----------------------------
|
||||
errorCheck: ->
|
||||
options = @options
|
||||
errors = false
|
||||
error_msg = "Shapeshift ERROR:"
|
||||
|
||||
# If there are no available children, a colWidth must be set
|
||||
if options.colWidth is null
|
||||
$children = @$container.children(options.selector)
|
||||
|
||||
if $children.length is 0
|
||||
errors = true
|
||||
console.error "#{error_msg} option colWidth must be specified if Shapeshift is initialized with no active children."
|
||||
|
||||
return !errors
|
||||
|
||||
# ----------------------------
|
||||
# Init:
|
||||
# Only enable features on initialization,
|
||||
# then call a full render of the elements
|
||||
# ----------------------------
|
||||
init: ->
|
||||
@createEvents()
|
||||
@setGlobals()
|
||||
@setIdentifier()
|
||||
@setActiveChildren()
|
||||
@enableFeatures()
|
||||
@gridInit()
|
||||
@render()
|
||||
@afterInit()
|
||||
|
||||
# ----------------------------
|
||||
# createEvents:
|
||||
# Triggerable events on the container
|
||||
# which run certain functions
|
||||
# ----------------------------
|
||||
createEvents: ->
|
||||
options = @options
|
||||
$container = @$container
|
||||
|
||||
$container.off("ss-arrange").on "ss-arrange", (e, trigger_drop_finished = false) => @render(false, trigger_drop_finished)
|
||||
$container.off("ss-rearrange").on "ss-rearrange", => @render(true)
|
||||
$container.off("ss-setTargetPosition").on "ss-setTargetPosition", => @setTargetPosition()
|
||||
$container.off("ss-destroy").on "ss-destroy", => @destroy()
|
||||
|
||||
# ----------------------------
|
||||
# setGlobals:
|
||||
# Globals that only need to be set on initialization
|
||||
# ----------------------------
|
||||
setGlobals: ->
|
||||
# Prevent initial animation if applicable
|
||||
@globals.animated = @options.animateOnInit
|
||||
|
||||
# ----------------------------
|
||||
# afterInit:
|
||||
# Take care of some dirty business
|
||||
# ----------------------------
|
||||
afterInit: ->
|
||||
# Return animation to normal
|
||||
@globals.animated = @options.animated
|
||||
|
||||
# ----------------------------
|
||||
# setIdentifier
|
||||
# Create a random identifier to tie to this container so that
|
||||
# it is easy to unbind the specific resize event from the browser
|
||||
# ----------------------------
|
||||
setIdentifier: ->
|
||||
@identifier = "shapeshifted_container_" + Math.random().toString(36).substring(7)
|
||||
@$container.addClass(@identifier)
|
||||
|
||||
# ----------------------------
|
||||
# enableFeatures:
|
||||
# Enables options features
|
||||
# ----------------------------
|
||||
enableFeatures: ->
|
||||
@enableResize() if @options.enableResize
|
||||
@enableDragNDrop() if @options.enableDrag or @options.enableCrossDrop
|
||||
|
||||
# ----------------------------
|
||||
# setActiveChildren:
|
||||
# Make sure that only the children set by the
|
||||
# selector option can be affected by Shapeshifting
|
||||
# ----------------------------
|
||||
setActiveChildren: ->
|
||||
options = @options
|
||||
|
||||
# Add active child class to each available child element
|
||||
$children = @$container.children(options.selector)
|
||||
active_child_class = options.activeClass
|
||||
total = $children.length
|
||||
|
||||
for i in [0...total]
|
||||
$($children[i]).addClass(active_child_class)
|
||||
|
||||
@setParsedChildren()
|
||||
|
||||
# Detect if there are any colspans wider than
|
||||
# the column options that were set
|
||||
columns = options.columns
|
||||
for i in [0...@parsedChildren.length]
|
||||
colspan = @parsedChildren[i].colspan
|
||||
|
||||
min_columns = options.minColumns
|
||||
if colspan > columns and colspan > min_columns
|
||||
options.minColumns = colspan
|
||||
console.error "Shapeshift ERROR: There are child elements that have a larger colspan than the minimum columns set through options.\noptions.minColumns has been set to #{colspan}"
|
||||
|
||||
# ----------------------------
|
||||
# setParsedChildren:
|
||||
# Calculates and returns commonly used
|
||||
# attributes for all the active children
|
||||
# ----------------------------
|
||||
setParsedChildren: ->
|
||||
$children = @$container.find("." + @options.activeClass).filter(":visible")
|
||||
total = $children.length
|
||||
|
||||
parsedChildren = []
|
||||
for i in [0...total]
|
||||
$child = $($children[i])
|
||||
child =
|
||||
i: i
|
||||
el: $child
|
||||
colspan: parseInt($child.attr("data-ss-colspan")) || 1
|
||||
height: $child.outerHeight()
|
||||
parsedChildren.push child
|
||||
@parsedChildren = parsedChildren
|
||||
|
||||
# ----------------------------
|
||||
# setGrid:
|
||||
# Calculates the dimensions of each column
|
||||
# and determines to total number of columns
|
||||
# ----------------------------
|
||||
gridInit: ->
|
||||
gutter_x = @options.gutterX
|
||||
|
||||
unless @options.colWidth >= 1
|
||||
# Determine single item / col width
|
||||
first_child = @parsedChildren[0]
|
||||
fc_width = first_child.el.outerWidth()
|
||||
fc_colspan = first_child.colspan
|
||||
single_width = (fc_width - ((fc_colspan - 1) * gutter_x)) / fc_colspan
|
||||
@globals.col_width = single_width + gutter_x
|
||||
else
|
||||
@globals.col_width = @options.colWidth + gutter_x
|
||||
|
||||
# ----------------------------
|
||||
# render:
|
||||
# Determine the active children and
|
||||
# arrange them to the calculated grid
|
||||
# ----------------------------
|
||||
render: (reparse = false, trigger_drop_finished) ->
|
||||
@setGridColumns()
|
||||
@arrange(reparse, trigger_drop_finished)
|
||||
|
||||
# ----------------------------
|
||||
# setGrid:
|
||||
# Calculates the dimensions of each column
|
||||
# and determines to total number of columns
|
||||
# ----------------------------
|
||||
setGridColumns: ->
|
||||
# Common
|
||||
globals = @globals
|
||||
options = @options
|
||||
col_width = globals.col_width
|
||||
gutter_x = options.gutterX
|
||||
padding_x = options.paddingX
|
||||
inner_width = @$container.innerWidth() - (padding_x * 2)
|
||||
|
||||
# Determine how many columns there currently can be
|
||||
minColumns = options.minColumns
|
||||
columns = options.columns || Math.floor (inner_width + gutter_x) / col_width
|
||||
if minColumns and minColumns > columns
|
||||
columns = minColumns
|
||||
globals.columns = columns
|
||||
|
||||
# Columns cannot exceed children
|
||||
children_count = @parsedChildren.length
|
||||
if columns > children_count
|
||||
columns = children_count
|
||||
|
||||
# Calculate the child offset from the left
|
||||
globals.child_offset = padding_x
|
||||
switch options.align
|
||||
when "center"
|
||||
grid_width = (columns * col_width) - gutter_x
|
||||
globals.child_offset += (inner_width - grid_width) / 2
|
||||
|
||||
when "right"
|
||||
grid_width = (columns * col_width) - gutter_x
|
||||
globals.child_offset += (inner_width - grid_width)
|
||||
|
||||
# ----------------------------
|
||||
# arrange:
|
||||
# Animates the elements into their calcluated positions
|
||||
# ----------------------------
|
||||
arrange: (reparse, trigger_drop_finished) ->
|
||||
@setParsedChildren() if reparse
|
||||
|
||||
globals = @globals
|
||||
options = @options
|
||||
|
||||
# Common
|
||||
$container = @$container
|
||||
child_positions = @getPositions()
|
||||
|
||||
parsed_children = @parsedChildren
|
||||
total_children = parsed_children.length
|
||||
|
||||
animated = globals.animated and total_children <= options.animationThreshold
|
||||
animation_speed = options.animationSpeed
|
||||
dragged_class = options.draggedClass
|
||||
|
||||
# Arrange each child element
|
||||
for i in [0...total_children]
|
||||
$child = parsed_children[i].el
|
||||
attributes = child_positions[i]
|
||||
is_dragged_child = $child.hasClass(dragged_class)
|
||||
|
||||
if is_dragged_child
|
||||
placeholder_class = options.placeholderClass
|
||||
$child = $child.siblings("." + placeholder_class)
|
||||
|
||||
if animated and !is_dragged_child
|
||||
$child.stop(true, false).animate attributes, animation_speed, ->
|
||||
else
|
||||
$child.css attributes
|
||||
|
||||
|
||||
if trigger_drop_finished
|
||||
if animated
|
||||
setTimeout (->
|
||||
$container.trigger("ss-drop-complete")
|
||||
), animation_speed
|
||||
else
|
||||
$container.trigger("ss-drop-complete")
|
||||
$container.trigger("ss-arranged")
|
||||
|
||||
# Set the container height
|
||||
if options.autoHeight
|
||||
container_height = globals.container_height
|
||||
max_height = options.maxHeight
|
||||
min_height = options.minHeight
|
||||
|
||||
if min_height and container_height < min_height
|
||||
container_height = min_height
|
||||
else if max_height and container_height > max_height
|
||||
container_height = max_height
|
||||
|
||||
$container.height container_height
|
||||
|
||||
# ----------------------------
|
||||
# getPositions:
|
||||
# Go over each child and determine which column they
|
||||
# fit into and return an array of their x/y dimensions
|
||||
# ----------------------------
|
||||
getPositions: (include_dragged = true) ->
|
||||
globals = @globals
|
||||
options = @options
|
||||
gutter_y = options.gutterY
|
||||
padding_y = options.paddingY
|
||||
dragged_class = options.draggedClass
|
||||
|
||||
parsed_children = @parsedChildren
|
||||
total_children = parsed_children.length
|
||||
|
||||
# Store the height for each column
|
||||
col_heights = []
|
||||
for i in [0...globals.columns]
|
||||
col_heights.push padding_y
|
||||
|
||||
# ----------------------------
|
||||
# savePosition
|
||||
# Takes a child which has been correctly placed in a
|
||||
# column and saves it to that final x/y position.
|
||||
# ----------------------------
|
||||
savePosition = (child) =>
|
||||
col = child.col
|
||||
colspan = child.colspan
|
||||
offset_x = (child.col * globals.col_width) + globals.child_offset
|
||||
offset_y = col_heights[col]
|
||||
|
||||
positions[child.i] = left: offset_x, top: offset_y
|
||||
col_heights[col] += child.height + gutter_y
|
||||
|
||||
if colspan >= 1
|
||||
for j in [1...colspan]
|
||||
col_heights[col + j] = col_heights[col]
|
||||
|
||||
# ----------------------------
|
||||
# determineMultiposition
|
||||
# Children with multiple column spans will need special
|
||||
# rules to determine if they are currently able to be
|
||||
# placed in the grid.
|
||||
# ----------------------------
|
||||
determineMultiposition = (child) =>
|
||||
# Only use the columns that this child can fit into
|
||||
possible_cols = col_heights.length - child.colspan + 1
|
||||
possible_col_heights = col_heights.slice(0).splice(0, possible_cols)
|
||||
|
||||
chosen_col = undefined
|
||||
for offset in [0...possible_cols]
|
||||
col = @lowestCol(possible_col_heights, offset)
|
||||
colspan = child.colspan
|
||||
height = col_heights[col]
|
||||
|
||||
kosher = true
|
||||
|
||||
# Determine if it is able to be placed at this col
|
||||
for span in [1...colspan]
|
||||
next_height = col_heights[col + span]
|
||||
|
||||
# The next height must not be higher
|
||||
if height < next_height
|
||||
kosher = false
|
||||
break
|
||||
|
||||
if kosher
|
||||
chosen_col = col
|
||||
break
|
||||
|
||||
return chosen_col
|
||||
|
||||
# ----------------------------
|
||||
# recalculateSavedChildren
|
||||
# Sometimes child elements cannot save the first time around,
|
||||
# iterate over those children and determine if its ok to place now.
|
||||
# ----------------------------
|
||||
saved_children = []
|
||||
recalculateSavedChildren = =>
|
||||
to_pop = []
|
||||
for saved_i in [0...saved_children.length]
|
||||
saved_child = saved_children[saved_i]
|
||||
saved_child.col = determineMultiposition(saved_child)
|
||||
|
||||
if saved_child.col >= 0
|
||||
savePosition(saved_child)
|
||||
to_pop.push(saved_i)
|
||||
|
||||
# Popeye. Lol.
|
||||
for pop_i in [to_pop.length - 1..0] by -1
|
||||
index = to_pop[pop_i]
|
||||
saved_children.splice(index,1)
|
||||
|
||||
# ----------------------------
|
||||
# determinePositions
|
||||
# Iterate over all the parsed children and determine
|
||||
# the calculations needed to get its x/y value.
|
||||
# ----------------------------
|
||||
positions = []
|
||||
do determinePositions = =>
|
||||
for i in [0...total_children]
|
||||
child = parsed_children[i]
|
||||
|
||||
unless !include_dragged and child.el.hasClass(dragged_class)
|
||||
if child.colspan > 1
|
||||
child.col = determineMultiposition(child)
|
||||
else
|
||||
child.col = @lowestCol(col_heights)
|
||||
|
||||
if child.col is undefined
|
||||
saved_children.push child
|
||||
else
|
||||
savePosition(child)
|
||||
|
||||
recalculateSavedChildren()
|
||||
|
||||
# Store the container height since we already have the data
|
||||
if options.autoHeight
|
||||
grid_height = col_heights[@highestCol(col_heights)] - gutter_y
|
||||
globals.container_height = grid_height + padding_y
|
||||
|
||||
return positions
|
||||
|
||||
# ----------------------------
|
||||
# enableDrag:
|
||||
# Optional feature.
|
||||
# Initialize dragging.
|
||||
# ----------------------------
|
||||
enableDragNDrop: ->
|
||||
options = @options
|
||||
|
||||
$container = @$container
|
||||
active_class = options.activeClass
|
||||
dragged_class = options.draggedClass
|
||||
placeholder_class = options.placeholderClass
|
||||
original_container_class = options.originalContainerClass
|
||||
current_container_class = options.currentContainerClass
|
||||
previous_container_class = options.previousContainerClass
|
||||
delete_clone = options.deleteClone
|
||||
drag_rate = options.dragRate
|
||||
drag_clone = options.dragClone
|
||||
clone_class = options.cloneClass
|
||||
|
||||
$selected = $placeholder = $clone = selected_offset_y = selected_offset_x = null
|
||||
dragging = false
|
||||
|
||||
if options.enableDrag
|
||||
$container.children("." + active_class).filter(options.dragWhitelist).draggable
|
||||
addClasses: false
|
||||
containment: 'document'
|
||||
handle: options.handle
|
||||
zIndex: 9999
|
||||
|
||||
start: (e, ui) ->
|
||||
# Set $selected globals
|
||||
$selected = $(e.target)
|
||||
|
||||
if drag_clone
|
||||
$clone = $selected.clone(true).insertBefore($selected).addClass(clone_class)
|
||||
|
||||
$selected.addClass(dragged_class)
|
||||
|
||||
# Create Placeholder
|
||||
selected_tag = $selected.prop("tagName")
|
||||
$placeholder = $("<#{selected_tag} class='#{placeholder_class}' style='height: #{$selected.height()}px; width: #{$selected.width()}px'></#{selected_tag}>")
|
||||
|
||||
# Set current container
|
||||
$selected.parent().addClass(original_container_class).addClass(current_container_class)
|
||||
|
||||
# For manually centering the element with respect to mouse position
|
||||
selected_offset_y = $selected.outerHeight() / 2
|
||||
selected_offset_x = $selected.outerWidth() / 2
|
||||
|
||||
drag: (e, ui) =>
|
||||
if !dragging and !(drag_clone and delete_clone and $("." + current_container_class)[0] is $("." + original_container_class)[0])
|
||||
# Append placeholder to container
|
||||
$placeholder.remove().appendTo("." + current_container_class)
|
||||
|
||||
# Set drag target and rearrange everything
|
||||
$("." + current_container_class).trigger("ss-setTargetPosition")
|
||||
|
||||
# Disallow dragging from occurring too much
|
||||
dragging = true
|
||||
window.setTimeout ( ->
|
||||
dragging = false
|
||||
), drag_rate
|
||||
|
||||
# Manually center the element with respect to mouse position
|
||||
ui.position.left = e.pageX - $selected.parent().offset().left - selected_offset_x;
|
||||
ui.position.top = e.pageY - $selected.parent().offset().top - selected_offset_y;
|
||||
|
||||
stop: ->
|
||||
$original_container = $("." + original_container_class)
|
||||
$current_container = $("." + current_container_class)
|
||||
$previous_container = $("." + previous_container_class)
|
||||
|
||||
# Clear globals
|
||||
$selected.removeClass(dragged_class)
|
||||
$("." + placeholder_class).remove()
|
||||
|
||||
if drag_clone
|
||||
if delete_clone and $("." + current_container_class)[0] is $("." + original_container_class)[0]
|
||||
$clone.remove()
|
||||
$("." + current_container_class).trigger("ss-rearrange")
|
||||
else
|
||||
$clone.removeClass(clone_class)
|
||||
|
||||
# Trigger Events
|
||||
if $original_container[0] is $current_container[0]
|
||||
$current_container.trigger("ss-rearranged", $selected)
|
||||
else
|
||||
$original_container.trigger("ss-removed", $selected)
|
||||
$current_container.trigger("ss-added", $selected)
|
||||
|
||||
# Arrange dragged item into place and clear container classes
|
||||
$original_container.trigger("ss-arrange").removeClass(original_container_class)
|
||||
$current_container.trigger("ss-arrange", true).removeClass(current_container_class)
|
||||
$previous_container.trigger("ss-arrange").removeClass(previous_container_class)
|
||||
|
||||
$selected = $placeholder = null
|
||||
|
||||
|
||||
if options.enableCrossDrop
|
||||
$container.droppable
|
||||
accept: options.crossDropWhitelist
|
||||
tolerance: 'intersect'
|
||||
over: (e) =>
|
||||
$("." + previous_container_class).removeClass(previous_container_class)
|
||||
$("." + current_container_class).removeClass(current_container_class).addClass(previous_container_class)
|
||||
$(e.target).addClass(current_container_class)
|
||||
|
||||
drop: (e, selected) =>
|
||||
if @options.enableTrash
|
||||
$original_container = $("." + original_container_class)
|
||||
$current_container = $("." + current_container_class)
|
||||
$previous_container = $("." + previous_container_class)
|
||||
$selected = $(selected.helper)
|
||||
|
||||
$current_container.trigger("ss-trashed", $selected)
|
||||
$selected.remove()
|
||||
|
||||
$original_container.trigger("ss-rearrange").removeClass(original_container_class)
|
||||
$current_container.trigger("ss-rearrange").removeClass(current_container_class)
|
||||
$previous_container.trigger("ss-arrange").removeClass(previous_container_class)
|
||||
|
||||
# ----------------------------
|
||||
# getTargetPosition:
|
||||
# Determine the target position for the selected
|
||||
# element and arrange it into place
|
||||
# ----------------------------
|
||||
setTargetPosition: ->
|
||||
options = @options
|
||||
|
||||
unless options.enableTrash
|
||||
dragged_class = options.draggedClass
|
||||
|
||||
$selected = $("." + dragged_class)
|
||||
$start_container = $selected.parent()
|
||||
parsed_children = @parsedChildren
|
||||
child_positions = @getPositions(false)
|
||||
total_positions = child_positions.length
|
||||
|
||||
selected_x = $selected.offset().left - $start_container.offset().left + (@globals.col_width / 2)
|
||||
selected_y = $selected.offset().top - $start_container.offset().top + ($selected.height() / 2)
|
||||
|
||||
shortest_distance = 9999999
|
||||
target_position = 0
|
||||
|
||||
if total_positions > 1
|
||||
cutoff_start = options.cutoffStart + 1 || 0
|
||||
cutoff_end = options.cutoffEnd || total_positions
|
||||
|
||||
for position_i in [cutoff_start...cutoff_end]
|
||||
attributes = child_positions[position_i]
|
||||
|
||||
if attributes
|
||||
y_dist = selected_x - attributes.left
|
||||
x_dist = selected_y - attributes.top
|
||||
|
||||
if y_dist > 0 and x_dist > 0
|
||||
distance = Math.sqrt((x_dist * x_dist) + (y_dist * y_dist))
|
||||
|
||||
if distance < shortest_distance
|
||||
shortest_distance = distance
|
||||
target_position = position_i
|
||||
|
||||
if position_i is total_positions - 1
|
||||
if y_dist > parsed_children[position_i].height / 2
|
||||
target_position++
|
||||
|
||||
|
||||
|
||||
if target_position is parsed_children.length
|
||||
$target = parsed_children[target_position - 1].el
|
||||
$selected.insertAfter($target)
|
||||
else
|
||||
$target = parsed_children[target_position].el
|
||||
$selected.insertBefore($target)
|
||||
else
|
||||
if total_positions is 1
|
||||
attributes = child_positions[0]
|
||||
|
||||
if attributes.left < selected_x
|
||||
@$container.append $selected
|
||||
else
|
||||
@$container.prepend $selected
|
||||
else
|
||||
@$container.append $selected
|
||||
|
||||
@arrange(true)
|
||||
|
||||
if $start_container[0] isnt $selected.parent()[0]
|
||||
previous_container_class = options.previousContainerClass
|
||||
$("." + previous_container_class).trigger "ss-rearrange"
|
||||
else
|
||||
placeholder_class = @options.placeholderClass
|
||||
$("." + placeholder_class).remove()
|
||||
|
||||
# ----------------------------
|
||||
# resize:
|
||||
# Optional feature.
|
||||
# Runs a full render of the elements when
|
||||
# the browser window is resized.
|
||||
# ----------------------------
|
||||
enableResize: ->
|
||||
animation_speed = @options.animationSpeed
|
||||
|
||||
resizing = false
|
||||
binding = "resize." + @identifier
|
||||
$(window).on binding, =>
|
||||
unless resizing
|
||||
resizing = true
|
||||
|
||||
# Some funkyness to prevent too many renderings
|
||||
setTimeout (=> @render()), animation_speed / 3
|
||||
setTimeout (=> @render()), animation_speed / 3
|
||||
|
||||
setTimeout =>
|
||||
resizing = false
|
||||
@render()
|
||||
, animation_speed / 3
|
||||
|
||||
# ----------------------------
|
||||
# lowestCol:
|
||||
# Helper
|
||||
# Returns the index position of the
|
||||
# array column with the lowest number
|
||||
# ----------------------------
|
||||
lowestCol: (array, offset = 0) ->
|
||||
length = array.length
|
||||
augmented_array = []
|
||||
|
||||
for i in [0...length]
|
||||
augmented_array.push [array[i], i]
|
||||
|
||||
augmented_array.sort (a, b) ->
|
||||
ret = a[0] - b[0]
|
||||
ret = a[1] - b[1] if ret is 0
|
||||
ret
|
||||
augmented_array[offset][1]
|
||||
|
||||
# ----------------------------
|
||||
# highestCol:
|
||||
# Helper
|
||||
# Returns the index position of the
|
||||
# array column with the highest number
|
||||
# ----------------------------
|
||||
highestCol: (array) ->
|
||||
$.inArray Math.max.apply(window,array), array
|
||||
|
||||
# ----------------------------
|
||||
# destroy:
|
||||
# ----------------------------
|
||||
destroy: ->
|
||||
$container = @$container
|
||||
$container.off("ss-arrange")
|
||||
$container.off("ss-rearrange")
|
||||
$container.off("ss-setTargetPosition")
|
||||
$container.off("ss-destroy")
|
||||
|
||||
active_class = @options.activeClass
|
||||
$active_children = $container.find("." + active_class)
|
||||
|
||||
if @options.enableDrag
|
||||
$active_children.draggable('destroy')
|
||||
if @options.enableCrossDrop
|
||||
$container.droppable('destroy')
|
||||
|
||||
$active_children.removeClass(active_class)
|
||||
$container.removeClass(@identifier)
|
||||
|
||||
|
||||
$.fn[pluginName] = (options) ->
|
||||
@each ->
|
||||
# Destroy any old resize events
|
||||
old_class = $(@).attr("class").match(/shapeshifted_container_\w+/)?[0]
|
||||
if old_class
|
||||
bound_indentifier = "resize." + old_class
|
||||
$(window).off(bound_indentifier)
|
||||
$(@).removeClass(old_class)
|
||||
|
||||
# Create the new plugin instance
|
||||
$.data(@, "plugin_#{pluginName}", new Plugin(@, options))
|
||||
|
||||
)(jQuery, window, document)
|
||||
@@ -0,0 +1,634 @@
|
||||
// Generated by CoffeeScript 1.4.0
|
||||
(function() {
|
||||
|
||||
(function($, window, document) {
|
||||
var Plugin, defaults, pluginName;
|
||||
pluginName = "shapeshift";
|
||||
defaults = {
|
||||
selector: "*",
|
||||
enableDrag: true,
|
||||
enableCrossDrop: true,
|
||||
enableResize: true,
|
||||
enableTrash: false,
|
||||
align: "center",
|
||||
colWidth: null,
|
||||
columns: null,
|
||||
minColumns: 1,
|
||||
autoHeight: true,
|
||||
maxHeight: null,
|
||||
minHeight: 100,
|
||||
gutterX: 10,
|
||||
gutterY: 10,
|
||||
paddingX: 10,
|
||||
paddingY: 10,
|
||||
animated: true,
|
||||
animateOnInit: false,
|
||||
animationSpeed: 225,
|
||||
animationThreshold: 100,
|
||||
dragClone: false,
|
||||
deleteClone: true,
|
||||
dragRate: 100,
|
||||
dragWhitelist: "*",
|
||||
crossDropWhitelist: "*",
|
||||
cutoffStart: null,
|
||||
cutoffEnd: null,
|
||||
handle: false,
|
||||
cloneClass: "ss-cloned-child",
|
||||
activeClass: "ss-active-child",
|
||||
draggedClass: "ss-dragged-child",
|
||||
placeholderClass: "ss-placeholder-child",
|
||||
originalContainerClass: "ss-original-container",
|
||||
currentContainerClass: "ss-current-container",
|
||||
previousContainerClass: "ss-previous-container"
|
||||
};
|
||||
Plugin = (function() {
|
||||
|
||||
function Plugin(element, options) {
|
||||
this.element = element;
|
||||
this.options = $.extend({}, defaults, options);
|
||||
this.globals = {};
|
||||
this.$container = $(element);
|
||||
if (this.errorCheck()) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
Plugin.prototype.errorCheck = function() {
|
||||
var $children, error_msg, errors, options;
|
||||
options = this.options;
|
||||
errors = false;
|
||||
error_msg = "Shapeshift ERROR:";
|
||||
if (options.colWidth === null) {
|
||||
$children = this.$container.children(options.selector);
|
||||
if ($children.length === 0) {
|
||||
errors = true;
|
||||
console.error("" + error_msg + " option colWidth must be specified if Shapeshift is initialized with no active children.");
|
||||
}
|
||||
}
|
||||
return !errors;
|
||||
};
|
||||
|
||||
Plugin.prototype.init = function() {
|
||||
this.createEvents();
|
||||
this.setGlobals();
|
||||
this.setIdentifier();
|
||||
this.setActiveChildren();
|
||||
this.enableFeatures();
|
||||
this.gridInit();
|
||||
this.render();
|
||||
return this.afterInit();
|
||||
};
|
||||
|
||||
Plugin.prototype.createEvents = function() {
|
||||
var $container, options,
|
||||
_this = this;
|
||||
options = this.options;
|
||||
$container = this.$container;
|
||||
$container.off("ss-arrange").on("ss-arrange", function(e, trigger_drop_finished) {
|
||||
if (trigger_drop_finished == null) {
|
||||
trigger_drop_finished = false;
|
||||
}
|
||||
return _this.render(false, trigger_drop_finished);
|
||||
});
|
||||
$container.off("ss-rearrange").on("ss-rearrange", function() {
|
||||
return _this.render(true);
|
||||
});
|
||||
$container.off("ss-setTargetPosition").on("ss-setTargetPosition", function() {
|
||||
return _this.setTargetPosition();
|
||||
});
|
||||
return $container.off("ss-destroy").on("ss-destroy", function() {
|
||||
return _this.destroy();
|
||||
});
|
||||
};
|
||||
|
||||
Plugin.prototype.setGlobals = function() {
|
||||
return this.globals.animated = this.options.animateOnInit;
|
||||
};
|
||||
|
||||
Plugin.prototype.afterInit = function() {
|
||||
return this.globals.animated = this.options.animated;
|
||||
};
|
||||
|
||||
Plugin.prototype.setIdentifier = function() {
|
||||
this.identifier = "shapeshifted_container_" + Math.random().toString(36).substring(7);
|
||||
return this.$container.addClass(this.identifier);
|
||||
};
|
||||
|
||||
Plugin.prototype.enableFeatures = function() {
|
||||
if (this.options.enableResize) {
|
||||
this.enableResize();
|
||||
}
|
||||
if (this.options.enableDrag || this.options.enableCrossDrop) {
|
||||
return this.enableDragNDrop();
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.setActiveChildren = function() {
|
||||
var $children, active_child_class, colspan, columns, i, min_columns, options, total, _i, _j, _ref, _results;
|
||||
options = this.options;
|
||||
$children = this.$container.children(options.selector);
|
||||
active_child_class = options.activeClass;
|
||||
total = $children.length;
|
||||
for (i = _i = 0; 0 <= total ? _i < total : _i > total; i = 0 <= total ? ++_i : --_i) {
|
||||
$($children[i]).addClass(active_child_class);
|
||||
}
|
||||
this.setParsedChildren();
|
||||
columns = options.columns;
|
||||
_results = [];
|
||||
for (i = _j = 0, _ref = this.parsedChildren.length; 0 <= _ref ? _j < _ref : _j > _ref; i = 0 <= _ref ? ++_j : --_j) {
|
||||
colspan = this.parsedChildren[i].colspan;
|
||||
min_columns = options.minColumns;
|
||||
if (colspan > columns && colspan > min_columns) {
|
||||
options.minColumns = colspan;
|
||||
_results.push(console.error("Shapeshift ERROR: There are child elements that have a larger colspan than the minimum columns set through options.\noptions.minColumns has been set to " + colspan));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Plugin.prototype.setParsedChildren = function() {
|
||||
var $child, $children, child, i, parsedChildren, total, _i;
|
||||
$children = this.$container.find("." + this.options.activeClass).filter(":visible");
|
||||
total = $children.length;
|
||||
parsedChildren = [];
|
||||
for (i = _i = 0; 0 <= total ? _i < total : _i > total; i = 0 <= total ? ++_i : --_i) {
|
||||
$child = $($children[i]);
|
||||
child = {
|
||||
i: i,
|
||||
el: $child,
|
||||
colspan: parseInt($child.attr("data-ss-colspan")) || 1,
|
||||
height: $child.outerHeight()
|
||||
};
|
||||
parsedChildren.push(child);
|
||||
}
|
||||
return this.parsedChildren = parsedChildren;
|
||||
};
|
||||
|
||||
Plugin.prototype.gridInit = function() {
|
||||
var fc_colspan, fc_width, first_child, gutter_x, single_width;
|
||||
gutter_x = this.options.gutterX;
|
||||
if (!(this.options.colWidth >= 1)) {
|
||||
first_child = this.parsedChildren[0];
|
||||
fc_width = first_child.el.outerWidth();
|
||||
fc_colspan = first_child.colspan;
|
||||
single_width = (fc_width - ((fc_colspan - 1) * gutter_x)) / fc_colspan;
|
||||
return this.globals.col_width = single_width + gutter_x;
|
||||
} else {
|
||||
return this.globals.col_width = this.options.colWidth + gutter_x;
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.render = function(reparse, trigger_drop_finished) {
|
||||
if (reparse == null) {
|
||||
reparse = false;
|
||||
}
|
||||
this.setGridColumns();
|
||||
return this.arrange(reparse, trigger_drop_finished);
|
||||
};
|
||||
|
||||
Plugin.prototype.setGridColumns = function() {
|
||||
var children_count, col_width, columns, globals, grid_width, gutter_x, inner_width, minColumns, options, padding_x;
|
||||
globals = this.globals;
|
||||
options = this.options;
|
||||
col_width = globals.col_width;
|
||||
gutter_x = options.gutterX;
|
||||
padding_x = options.paddingX;
|
||||
inner_width = this.$container.innerWidth() - (padding_x * 2);
|
||||
minColumns = options.minColumns;
|
||||
columns = options.columns || Math.floor((inner_width + gutter_x) / col_width);
|
||||
if (minColumns && minColumns > columns) {
|
||||
columns = minColumns;
|
||||
}
|
||||
globals.columns = columns;
|
||||
children_count = this.parsedChildren.length;
|
||||
if (columns > children_count) {
|
||||
columns = children_count;
|
||||
}
|
||||
globals.child_offset = padding_x;
|
||||
switch (options.align) {
|
||||
case "center":
|
||||
grid_width = (columns * col_width) - gutter_x;
|
||||
return globals.child_offset += (inner_width - grid_width) / 2;
|
||||
case "right":
|
||||
grid_width = (columns * col_width) - gutter_x;
|
||||
return globals.child_offset += inner_width - grid_width;
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.arrange = function(reparse, trigger_drop_finished) {
|
||||
var $child, $container, animated, animation_speed, attributes, child_positions, container_height, dragged_class, globals, i, is_dragged_child, max_height, min_height, options, parsed_children, placeholder_class, total_children, _i;
|
||||
if (reparse) {
|
||||
this.setParsedChildren();
|
||||
}
|
||||
globals = this.globals;
|
||||
options = this.options;
|
||||
$container = this.$container;
|
||||
child_positions = this.getPositions();
|
||||
parsed_children = this.parsedChildren;
|
||||
total_children = parsed_children.length;
|
||||
animated = globals.animated && total_children <= options.animationThreshold;
|
||||
animation_speed = options.animationSpeed;
|
||||
dragged_class = options.draggedClass;
|
||||
for (i = _i = 0; 0 <= total_children ? _i < total_children : _i > total_children; i = 0 <= total_children ? ++_i : --_i) {
|
||||
$child = parsed_children[i].el;
|
||||
attributes = child_positions[i];
|
||||
is_dragged_child = $child.hasClass(dragged_class);
|
||||
if (is_dragged_child) {
|
||||
placeholder_class = options.placeholderClass;
|
||||
$child = $child.siblings("." + placeholder_class);
|
||||
}
|
||||
if (animated && !is_dragged_child) {
|
||||
$child.stop(true, false).animate(attributes, animation_speed, function() {});
|
||||
} else {
|
||||
$child.css(attributes);
|
||||
}
|
||||
}
|
||||
if (trigger_drop_finished) {
|
||||
if (animated) {
|
||||
setTimeout((function() {
|
||||
return $container.trigger("ss-drop-complete");
|
||||
}), animation_speed);
|
||||
} else {
|
||||
$container.trigger("ss-drop-complete");
|
||||
}
|
||||
}
|
||||
$container.trigger("ss-arranged");
|
||||
if (options.autoHeight) {
|
||||
container_height = globals.container_height;
|
||||
max_height = options.maxHeight;
|
||||
min_height = options.minHeight;
|
||||
if (min_height && container_height < min_height) {
|
||||
container_height = min_height;
|
||||
} else if (max_height && container_height > max_height) {
|
||||
container_height = max_height;
|
||||
}
|
||||
return $container.height(container_height);
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.getPositions = function(include_dragged) {
|
||||
var col_heights, determineMultiposition, determinePositions, dragged_class, globals, grid_height, gutter_y, i, options, padding_y, parsed_children, positions, recalculateSavedChildren, savePosition, saved_children, total_children, _i, _ref,
|
||||
_this = this;
|
||||
if (include_dragged == null) {
|
||||
include_dragged = true;
|
||||
}
|
||||
globals = this.globals;
|
||||
options = this.options;
|
||||
gutter_y = options.gutterY;
|
||||
padding_y = options.paddingY;
|
||||
dragged_class = options.draggedClass;
|
||||
parsed_children = this.parsedChildren;
|
||||
total_children = parsed_children.length;
|
||||
col_heights = [];
|
||||
for (i = _i = 0, _ref = globals.columns; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
col_heights.push(padding_y);
|
||||
}
|
||||
savePosition = function(child) {
|
||||
var col, colspan, j, offset_x, offset_y, _j, _results;
|
||||
col = child.col;
|
||||
colspan = child.colspan;
|
||||
offset_x = (child.col * globals.col_width) + globals.child_offset;
|
||||
offset_y = col_heights[col];
|
||||
positions[child.i] = {
|
||||
left: offset_x,
|
||||
top: offset_y
|
||||
};
|
||||
col_heights[col] += child.height + gutter_y;
|
||||
if (colspan >= 1) {
|
||||
_results = [];
|
||||
for (j = _j = 1; 1 <= colspan ? _j < colspan : _j > colspan; j = 1 <= colspan ? ++_j : --_j) {
|
||||
_results.push(col_heights[col + j] = col_heights[col]);
|
||||
}
|
||||
return _results;
|
||||
}
|
||||
};
|
||||
determineMultiposition = function(child) {
|
||||
var chosen_col, col, colspan, height, kosher, next_height, offset, possible_col_heights, possible_cols, span, _j, _k;
|
||||
possible_cols = col_heights.length - child.colspan + 1;
|
||||
possible_col_heights = col_heights.slice(0).splice(0, possible_cols);
|
||||
chosen_col = void 0;
|
||||
for (offset = _j = 0; 0 <= possible_cols ? _j < possible_cols : _j > possible_cols; offset = 0 <= possible_cols ? ++_j : --_j) {
|
||||
col = _this.lowestCol(possible_col_heights, offset);
|
||||
colspan = child.colspan;
|
||||
height = col_heights[col];
|
||||
kosher = true;
|
||||
for (span = _k = 1; 1 <= colspan ? _k < colspan : _k > colspan; span = 1 <= colspan ? ++_k : --_k) {
|
||||
next_height = col_heights[col + span];
|
||||
if (height < next_height) {
|
||||
kosher = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kosher) {
|
||||
chosen_col = col;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return chosen_col;
|
||||
};
|
||||
saved_children = [];
|
||||
recalculateSavedChildren = function() {
|
||||
var index, pop_i, saved_child, saved_i, to_pop, _j, _k, _ref1, _ref2, _results;
|
||||
to_pop = [];
|
||||
for (saved_i = _j = 0, _ref1 = saved_children.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; saved_i = 0 <= _ref1 ? ++_j : --_j) {
|
||||
saved_child = saved_children[saved_i];
|
||||
saved_child.col = determineMultiposition(saved_child);
|
||||
if (saved_child.col >= 0) {
|
||||
savePosition(saved_child);
|
||||
to_pop.push(saved_i);
|
||||
}
|
||||
}
|
||||
_results = [];
|
||||
for (pop_i = _k = _ref2 = to_pop.length - 1; _k >= 0; pop_i = _k += -1) {
|
||||
index = to_pop[pop_i];
|
||||
_results.push(saved_children.splice(index, 1));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
positions = [];
|
||||
(determinePositions = function() {
|
||||
var child, _j, _results;
|
||||
_results = [];
|
||||
for (i = _j = 0; 0 <= total_children ? _j < total_children : _j > total_children; i = 0 <= total_children ? ++_j : --_j) {
|
||||
child = parsed_children[i];
|
||||
if (!(!include_dragged && child.el.hasClass(dragged_class))) {
|
||||
if (child.colspan > 1) {
|
||||
child.col = determineMultiposition(child);
|
||||
} else {
|
||||
child.col = _this.lowestCol(col_heights);
|
||||
}
|
||||
if (child.col === void 0) {
|
||||
saved_children.push(child);
|
||||
} else {
|
||||
savePosition(child);
|
||||
}
|
||||
_results.push(recalculateSavedChildren());
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
if (options.autoHeight) {
|
||||
grid_height = col_heights[this.highestCol(col_heights)] - gutter_y;
|
||||
globals.container_height = grid_height + padding_y;
|
||||
}
|
||||
return positions;
|
||||
};
|
||||
|
||||
Plugin.prototype.enableDragNDrop = function() {
|
||||
var $clone, $container, $placeholder, $selected, active_class, clone_class, current_container_class, delete_clone, drag_clone, drag_rate, dragged_class, dragging, options, original_container_class, placeholder_class, previous_container_class, selected_offset_x, selected_offset_y,
|
||||
_this = this;
|
||||
options = this.options;
|
||||
$container = this.$container;
|
||||
active_class = options.activeClass;
|
||||
dragged_class = options.draggedClass;
|
||||
placeholder_class = options.placeholderClass;
|
||||
original_container_class = options.originalContainerClass;
|
||||
current_container_class = options.currentContainerClass;
|
||||
previous_container_class = options.previousContainerClass;
|
||||
delete_clone = options.deleteClone;
|
||||
drag_rate = options.dragRate;
|
||||
drag_clone = options.dragClone;
|
||||
clone_class = options.cloneClass;
|
||||
$selected = $placeholder = $clone = selected_offset_y = selected_offset_x = null;
|
||||
dragging = false;
|
||||
if (options.enableDrag) {
|
||||
$container.children("." + active_class).filter(options.dragWhitelist).draggable({
|
||||
addClasses: false,
|
||||
containment: 'document',
|
||||
handle: options.handle,
|
||||
zIndex: 9999,
|
||||
start: function(e, ui) {
|
||||
var selected_tag;
|
||||
$selected = $(e.target);
|
||||
if (drag_clone) {
|
||||
$clone = $selected.clone(true).insertBefore($selected).addClass(clone_class);
|
||||
}
|
||||
$selected.addClass(dragged_class);
|
||||
selected_tag = $selected.prop("tagName");
|
||||
$placeholder = $("<" + selected_tag + " class='" + placeholder_class + "' style='height: " + ($selected.height()) + "px; width: " + ($selected.width()) + "px'></" + selected_tag + ">");
|
||||
$selected.parent().addClass(original_container_class).addClass(current_container_class);
|
||||
selected_offset_y = $selected.outerHeight() / 2;
|
||||
return selected_offset_x = $selected.outerWidth() / 2;
|
||||
},
|
||||
drag: function(e, ui) {
|
||||
if (!dragging && !(drag_clone && delete_clone && $("." + current_container_class)[0] === $("." + original_container_class)[0])) {
|
||||
$placeholder.remove().appendTo("." + current_container_class);
|
||||
$("." + current_container_class).trigger("ss-setTargetPosition");
|
||||
dragging = true;
|
||||
window.setTimeout((function() {
|
||||
return dragging = false;
|
||||
}), drag_rate);
|
||||
}
|
||||
ui.position.left = e.pageX - $selected.parent().offset().left - selected_offset_x;
|
||||
return ui.position.top = e.pageY - $selected.parent().offset().top - selected_offset_y;
|
||||
},
|
||||
stop: function() {
|
||||
var $current_container, $original_container, $previous_container;
|
||||
$original_container = $("." + original_container_class);
|
||||
$current_container = $("." + current_container_class);
|
||||
$previous_container = $("." + previous_container_class);
|
||||
$selected.removeClass(dragged_class);
|
||||
$("." + placeholder_class).remove();
|
||||
if (drag_clone) {
|
||||
if (delete_clone && $("." + current_container_class)[0] === $("." + original_container_class)[0]) {
|
||||
$clone.remove();
|
||||
$("." + current_container_class).trigger("ss-rearrange");
|
||||
} else {
|
||||
$clone.removeClass(clone_class);
|
||||
}
|
||||
}
|
||||
if ($original_container[0] === $current_container[0]) {
|
||||
$current_container.trigger("ss-rearranged", $selected);
|
||||
} else {
|
||||
$original_container.trigger("ss-removed", $selected);
|
||||
$current_container.trigger("ss-added", $selected);
|
||||
}
|
||||
$original_container.trigger("ss-arrange").removeClass(original_container_class);
|
||||
$current_container.trigger("ss-arrange", true).removeClass(current_container_class);
|
||||
$previous_container.trigger("ss-arrange").removeClass(previous_container_class);
|
||||
return $selected = $placeholder = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (options.enableCrossDrop) {
|
||||
return $container.droppable({
|
||||
accept: options.crossDropWhitelist,
|
||||
tolerance: 'intersect',
|
||||
over: function(e) {
|
||||
$("." + previous_container_class).removeClass(previous_container_class);
|
||||
$("." + current_container_class).removeClass(current_container_class).addClass(previous_container_class);
|
||||
return $(e.target).addClass(current_container_class);
|
||||
},
|
||||
drop: function(e, selected) {
|
||||
var $current_container, $original_container, $previous_container;
|
||||
if (_this.options.enableTrash) {
|
||||
$original_container = $("." + original_container_class);
|
||||
$current_container = $("." + current_container_class);
|
||||
$previous_container = $("." + previous_container_class);
|
||||
$selected = $(selected.helper);
|
||||
$current_container.trigger("ss-trashed", $selected);
|
||||
$selected.remove();
|
||||
$original_container.trigger("ss-rearrange").removeClass(original_container_class);
|
||||
$current_container.trigger("ss-rearrange").removeClass(current_container_class);
|
||||
return $previous_container.trigger("ss-arrange").removeClass(previous_container_class);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.setTargetPosition = function() {
|
||||
var $selected, $start_container, $target, attributes, child_positions, cutoff_end, cutoff_start, distance, dragged_class, options, parsed_children, placeholder_class, position_i, previous_container_class, selected_x, selected_y, shortest_distance, target_position, total_positions, x_dist, y_dist, _i;
|
||||
options = this.options;
|
||||
if (!options.enableTrash) {
|
||||
dragged_class = options.draggedClass;
|
||||
$selected = $("." + dragged_class);
|
||||
$start_container = $selected.parent();
|
||||
parsed_children = this.parsedChildren;
|
||||
child_positions = this.getPositions(false);
|
||||
total_positions = child_positions.length;
|
||||
selected_x = $selected.offset().left - $start_container.offset().left + (this.globals.col_width / 2);
|
||||
selected_y = $selected.offset().top - $start_container.offset().top + ($selected.height() / 2);
|
||||
shortest_distance = 9999999;
|
||||
target_position = 0;
|
||||
if (total_positions > 1) {
|
||||
cutoff_start = options.cutoffStart + 1 || 0;
|
||||
cutoff_end = options.cutoffEnd || total_positions;
|
||||
for (position_i = _i = cutoff_start; cutoff_start <= cutoff_end ? _i < cutoff_end : _i > cutoff_end; position_i = cutoff_start <= cutoff_end ? ++_i : --_i) {
|
||||
attributes = child_positions[position_i];
|
||||
if (attributes) {
|
||||
y_dist = selected_x - attributes.left;
|
||||
x_dist = selected_y - attributes.top;
|
||||
if (y_dist > 0 && x_dist > 0) {
|
||||
distance = Math.sqrt((x_dist * x_dist) + (y_dist * y_dist));
|
||||
if (distance < shortest_distance) {
|
||||
shortest_distance = distance;
|
||||
target_position = position_i;
|
||||
if (position_i === total_positions - 1) {
|
||||
if (y_dist > parsed_children[position_i].height / 2) {
|
||||
target_position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (target_position === parsed_children.length) {
|
||||
$target = parsed_children[target_position - 1].el;
|
||||
$selected.insertAfter($target);
|
||||
} else {
|
||||
$target = parsed_children[target_position].el;
|
||||
$selected.insertBefore($target);
|
||||
}
|
||||
} else {
|
||||
if (total_positions === 1) {
|
||||
attributes = child_positions[0];
|
||||
if (attributes.left < selected_x) {
|
||||
this.$container.append($selected);
|
||||
} else {
|
||||
this.$container.prepend($selected);
|
||||
}
|
||||
} else {
|
||||
this.$container.append($selected);
|
||||
}
|
||||
}
|
||||
this.arrange(true);
|
||||
if ($start_container[0] !== $selected.parent()[0]) {
|
||||
previous_container_class = options.previousContainerClass;
|
||||
return $("." + previous_container_class).trigger("ss-rearrange");
|
||||
}
|
||||
} else {
|
||||
placeholder_class = this.options.placeholderClass;
|
||||
return $("." + placeholder_class).remove();
|
||||
}
|
||||
};
|
||||
|
||||
Plugin.prototype.enableResize = function() {
|
||||
var animation_speed, binding, resizing,
|
||||
_this = this;
|
||||
animation_speed = this.options.animationSpeed;
|
||||
resizing = false;
|
||||
binding = "resize." + this.identifier;
|
||||
return $(window).on(binding, function() {
|
||||
if (!resizing) {
|
||||
resizing = true;
|
||||
setTimeout((function() {
|
||||
return _this.render();
|
||||
}), animation_speed / 3);
|
||||
setTimeout((function() {
|
||||
return _this.render();
|
||||
}), animation_speed / 3);
|
||||
return setTimeout(function() {
|
||||
resizing = false;
|
||||
return _this.render();
|
||||
}, animation_speed / 3);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Plugin.prototype.lowestCol = function(array, offset) {
|
||||
var augmented_array, i, length, _i;
|
||||
if (offset == null) {
|
||||
offset = 0;
|
||||
}
|
||||
length = array.length;
|
||||
augmented_array = [];
|
||||
for (i = _i = 0; 0 <= length ? _i < length : _i > length; i = 0 <= length ? ++_i : --_i) {
|
||||
augmented_array.push([array[i], i]);
|
||||
}
|
||||
augmented_array.sort(function(a, b) {
|
||||
var ret;
|
||||
ret = a[0] - b[0];
|
||||
if (ret === 0) {
|
||||
ret = a[1] - b[1];
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
return augmented_array[offset][1];
|
||||
};
|
||||
|
||||
Plugin.prototype.highestCol = function(array) {
|
||||
return $.inArray(Math.max.apply(window, array), array);
|
||||
};
|
||||
|
||||
Plugin.prototype.destroy = function() {
|
||||
var $active_children, $container, active_class;
|
||||
$container = this.$container;
|
||||
$container.off("ss-arrange");
|
||||
$container.off("ss-rearrange");
|
||||
$container.off("ss-setTargetPosition");
|
||||
$container.off("ss-destroy");
|
||||
active_class = this.options.activeClass;
|
||||
$active_children = $container.find("." + active_class);
|
||||
if (this.options.enableDrag) {
|
||||
$active_children.draggable('destroy');
|
||||
}
|
||||
if (this.options.enableCrossDrop) {
|
||||
$container.droppable('destroy');
|
||||
}
|
||||
$active_children.removeClass(active_class);
|
||||
return $container.removeClass(this.identifier);
|
||||
};
|
||||
|
||||
return Plugin;
|
||||
|
||||
})();
|
||||
return $.fn[pluginName] = function(options) {
|
||||
return this.each(function() {
|
||||
var bound_indentifier, old_class, _ref;
|
||||
old_class = (_ref = $(this).attr("class").match(/shapeshifted_container_\w+/)) != null ? _ref[0] : void 0;
|
||||
if (old_class) {
|
||||
bound_indentifier = "resize." + old_class;
|
||||
$(window).off(bound_indentifier);
|
||||
$(this).removeClass(old_class);
|
||||
}
|
||||
return $.data(this, "plugin_" + pluginName, new Plugin(this, options));
|
||||
});
|
||||
};
|
||||
})(jQuery, window, document);
|
||||
|
||||
}).call(this);
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "jquery.shapeshift",
|
||||
"version": "2.0",
|
||||
"filename": "jquery.shapeshift.min.js",
|
||||
"homepage": "https://github.com/McPants/jquery.shapeshift",
|
||||
"description": "jQuery plugin which creates a column based grid system that allows drag and drop even between multiple containers.",
|
||||
"keywords": [
|
||||
"grid",
|
||||
"column",
|
||||
"drag",
|
||||
"drop"
|
||||
],
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Scott Elwood",
|
||||
"web": "http://www.scottelwood.com"
|
||||
},
|
||||
{
|
||||
"name": "We the Media, Inc.",
|
||||
"web": "http://www.wtmworldwide.com.com"
|
||||
}
|
||||
],
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "git@github.com:McPants/jquery.shapeshift.git"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "~1.9.1",
|
||||
"jqueryui": "~1.9.2"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user