UNPKG

coffeescript-ui

Version:
291 lines (223 loc) 6.95 kB
### * coffeescript-ui - Coffeescript User Interface System (CUI) * Copyright (c) 2013 - 2016 Programmfabrik GmbH * MIT Licence * https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org ### class CUI.Droppable extends CUI.DragDropSelect @cls = "droppable" initOpts: -> super() @addOpts accept: check: Function drop: default: (ev, info) => pos = info.dropTargetPos or "on" CUI.alert( markdown: true, text: "You dropped me **"+pos+"**: " + CUI.dom.getAttribute(info.dropTarget, "class") ) check: Function hoverClass: default: "cui-droppable" check: String dropHelper: mandatory: true default: false check: Boolean targetHelper: mandatory: true default: false check: Boolean selector: check: (v) => CUI.util.isString(v) or CUI.util.isFunction(v) accept: (ev, info) -> @_accept?(ev, info) destroy: -> @removeHelper() super() readOpts: -> super() if @_targetHelper CUI.util.assert(@_selector, "new CUI.Droppable", "opts.targetHelper needs opts.selector to be set.", opts: @opts) if @_dropHelper CUI.util.assert(not @_selector or @_targetHelper, "new CUI.Droppable", "opts.dropHelper does only work without opts.selector or with opts.targetHelper and opts.selector. needs opts.selector to be set.", opts: @opts) @__dropHelper = CUI.dom.element("DIV", class: "cui-droppable-drop-helper") return removeHelper: -> @resetMargin() if @__selectedTarget CUI.dom.removeClass(@__selectedTarget, @_hoverClass) @__selectedTarget = null if @__dropHelper CUI.dom.remove(@__dropHelper) if @_targetHelper for el in CUI.dom.findElements(@_element, @_selector) el.classList.remove("cui-droppable-target-helper") @__dropTarget = undefined @__dropTargetPos = undefined resetMargin: -> if not @__resetMargin return @__resetMargin.classList.remove(@__resetMargin.__target_helper_class) delete(@__resetMargin.__target_helper_class) delete(@__resetMargin) delete(@__saveZoneDims) insideSaveZone: (coord) -> if not @__saveZoneDims return false buf = 5 # add extra pixels for zone in @__saveZoneDims if (zone.viewportTopMargin - buf) <= coord.pageY <= (zone.viewportBottomMargin + buf) and (zone.viewportLeftMargin - buf) <= coord.pageX <= (zone.viewportRightMargin + buf) return true return false syncDropHelper: -> # drop helper goes on top dim = CUI.dom.getDimensions(@_element) document.body.appendChild(@__dropHelper) CUI.dom.setDimensions @__dropHelper, contentBoxWidth: dim.borderBoxWidth contentBoxHeight: dim.borderBoxHeight drop_helper_dim = CUI.dom.getDimensions(@__dropHelper) CUI.dom.setStyle @__dropHelper, position: "absolute" top: dim.viewportTop - drop_helper_dim.borderTopWidth - drop_helper_dim.marginTop left: dim.viewportLeft - drop_helper_dim.borderLeftWidth - drop_helper_dim.marginLeft syncTargetHelper: (ev, info) -> target = ev.getTarget() coord = CUI.util.getCoordinatesFromEvent(info.originalEvent) if ev.getType() == "cui-dragleave" new_target = info.originalEvent.getTarget() if CUI.dom.closest(new_target, ".cui-drag-drop-select-droppable") != @_element # outside us @removeHelper() return true if @_targetHelper or not @_selector # ignore the event return acceptable = (dropTarget, dropTargetPos) => info.dropTarget = dropTarget if @_targetHelper info.dropTargetPos = dropTargetPos if @accept(ev, info) == false @removeHelper() return false else return true if not @__initialized # check axis last_dim = null @__axis = undefined for el in CUI.dom.findElements(@_element, @_selector) if @_targetHelper el.classList.add("cui-droppable-target-helper") # we only need to check the first two elements # if we only have one we cannot determine the "axis" anyway if @__axis != undefined continue dim = CUI.dom.getDimensions(el) if last_dim @__axis = null if last_dim.viewportLeft == dim.viewportLeft @__axis = "y" if last_dim.viewportTop == dim.viewportTop @__axis = "x" last_dim = dim if not @__axis @__axis = "x" @__dropTargetPos = null @__dropTarget = null @__initialized = true CUI.dom.removeClass(@__selectedTarget, @_hoverClass) if @_selector @__selectedTarget = CUI.dom.closest(target, @_selector) else @__selectedTarget = @_element if not @_targetHelper if not acceptable(@__selectedTarget) @removeHelper() if @_selector and not @__selectedTarget # bubble return true return @__dropTarget = @__selectedTarget @__dropTargetPos = null CUI.dom.addClass(@__selectedTarget, @_hoverClass) if @__dropHelper @syncDropHelper() return if not @__selectedTarget if @insideSaveZone(coord) console.info("Inside save zone...") return @resetMargin() if @__dropHelper if not acceptable(@_element) return @__dropTarget = @_element @__dropTargetPos = null @syncDropHelper() else console.info("No selected target, no dropHelper...") @removeHelper() # bubble return true return CUI.dom.remove(@__dropHelper) dim = CUI.dom.getDimensions(@__selectedTarget) if (@__axis == "x" and coord.pageX > dim.viewportCenterLeft) or (@__axis == "y" and coord.pageY > dim.viewportCenterTop) dropTargetPos = "after" else dropTargetPos = "before" dropTarget = @__selectedTarget if not acceptable(dropTarget, dropTargetPos) @removeHelper() return @__dropTarget = dropTarget @__dropTargetPos = dropTargetPos helper_cls = "cui-droppable-target-helper-"+@__axis+"--"+@__dropTargetPos if @__resetMargin == @__selectedTarget and @__selectedTarget.__target_helper_class == helper_cls ; # target helper is still ok else @resetMargin() @__saveZoneDims = [ CUI.dom.getDimensions(@__selectedTarget) ] @__selectedTarget.__target_helper_class = helper_cls CUI.dom.addClass(@__selectedTarget, @__selectedTarget.__target_helper_class) @__saveZoneDims.push(CUI.dom.getDimensions(@__selectedTarget)) @__resetMargin = @__selectedTarget return init: -> CUI.Events.listen node: @element type: "cui-dragend" instance: @ call: (ev, info) => @removeHelper() CUI.Events.listen node: @element type: "cui-drop" instance: @ call: (ev, info) => if not @__dropTarget return info.dropTarget = @__dropTarget if @_targetHelper info.dropTargetPos = @__dropTargetPos if @accept(ev, info) != false ev.stopPropagation() CUI.setTimeout call: => @_drop(ev, info) return CUI.Events.listen node: @element type: ["cui-dragover", "cui-dragenter", "cui-dragleave"] instance: @ call: (ev, info) => @syncTargetHelper(ev, info) ev.stopPropagation() return