dom/tests/mochitest/ajax/mochikit/MochiKit/DragAndDrop.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/tests/mochitest/ajax/mochikit/MochiKit/DragAndDrop.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,824 @@
     1.4 +/***
     1.5 +MochiKit.DragAndDrop 1.4
     1.6 +
     1.7 +See <http://mochikit.com/> for documentation, downloads, license, etc.
     1.8 +
     1.9 +Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
    1.10 +    Mochi-ized By Thomas Herve (_firstname_@nimail.org)
    1.11 +
    1.12 +***/
    1.13 +
    1.14 +if (typeof(dojo) != 'undefined') {
    1.15 +    dojo.provide('MochiKit.DragAndDrop');
    1.16 +    dojo.require('MochiKit.Base');
    1.17 +    dojo.require('MochiKit.DOM');
    1.18 +    dojo.require('MochiKit.Iter');
    1.19 +    dojo.require('MochiKit.Visual');
    1.20 +    dojo.require('MochiKit.Signal');
    1.21 +}
    1.22 +
    1.23 +if (typeof(JSAN) != 'undefined') {
    1.24 +    JSAN.use("MochiKit.Base", []);
    1.25 +    JSAN.use("MochiKit.DOM", []);
    1.26 +    JSAN.use("MochiKit.Visual", []);
    1.27 +    JSAN.use("MochiKit.Iter", []);
    1.28 +    JSAN.use("MochiKit.Signal", []);
    1.29 +}
    1.30 +
    1.31 +try {
    1.32 +    if (typeof(MochiKit.Base) == 'undefined' ||
    1.33 +        typeof(MochiKit.DOM) == 'undefined' ||
    1.34 +        typeof(MochiKit.Visual) == 'undefined' ||
    1.35 +        typeof(MochiKit.Signal) == 'undefined' ||
    1.36 +        typeof(MochiKit.Iter) == 'undefined') {
    1.37 +        throw "";
    1.38 +    }
    1.39 +} catch (e) {
    1.40 +    throw "MochiKit.DragAndDrop depends on MochiKit.Base, MochiKit.DOM, MochiKit.Visual, MochiKit.Signal and MochiKit.Iter!";
    1.41 +}
    1.42 +
    1.43 +if (typeof(MochiKit.DragAndDrop) == 'undefined') {
    1.44 +    MochiKit.DragAndDrop = {};
    1.45 +}
    1.46 +
    1.47 +MochiKit.DragAndDrop.NAME = 'MochiKit.DragAndDrop';
    1.48 +MochiKit.DragAndDrop.VERSION = '1.4';
    1.49 +
    1.50 +MochiKit.DragAndDrop.__repr__ = function () {
    1.51 +    return '[' + this.NAME + ' ' + this.VERSION + ']';
    1.52 +};
    1.53 +
    1.54 +MochiKit.DragAndDrop.toString = function () {
    1.55 +    return this.__repr__();
    1.56 +};
    1.57 +
    1.58 +MochiKit.DragAndDrop.EXPORT = [
    1.59 +    "Droppable",
    1.60 +    "Draggable"
    1.61 +];
    1.62 +
    1.63 +MochiKit.DragAndDrop.EXPORT_OK = [
    1.64 +    "Droppables",
    1.65 +    "Draggables"
    1.66 +];
    1.67 +
    1.68 +MochiKit.DragAndDrop.Droppables = {
    1.69 +    /***
    1.70 +
    1.71 +    Manage all droppables. Shouldn't be used, use the Droppable object instead.
    1.72 +
    1.73 +    ***/
    1.74 +    drops: [],
    1.75 +
    1.76 +    remove: function (element) {
    1.77 +        this.drops = MochiKit.Base.filter(function (d) {
    1.78 +            return d.element != MochiKit.DOM.getElement(element);
    1.79 +        }, this.drops);
    1.80 +    },
    1.81 +
    1.82 +    register: function (drop) {
    1.83 +        this.drops.push(drop);
    1.84 +    },
    1.85 +
    1.86 +    unregister: function (drop) {
    1.87 +        this.drops = MochiKit.Base.filter(function (d) {
    1.88 +            return d != drop;
    1.89 +        }, this.drops);
    1.90 +    },
    1.91 +
    1.92 +    prepare: function (element) {
    1.93 +        MochiKit.Base.map(function (drop) {
    1.94 +            if (drop.isAccepted(element)) {
    1.95 +                if (drop.options.activeclass) {
    1.96 +                    MochiKit.DOM.addElementClass(drop.element,
    1.97 +                                                 drop.options.activeclass);
    1.98 +                }
    1.99 +                drop.options.onactive(drop.element, element);
   1.100 +            }
   1.101 +        }, this.drops);
   1.102 +    },
   1.103 +
   1.104 +    findDeepestChild: function (drops) {
   1.105 +        deepest = drops[0];
   1.106 +
   1.107 +        for (i = 1; i < drops.length; ++i) {
   1.108 +            if (MochiKit.DOM.isParent(drops[i].element, deepest.element)) {
   1.109 +                deepest = drops[i];
   1.110 +            }
   1.111 +        }
   1.112 +        return deepest;
   1.113 +    },
   1.114 +
   1.115 +    show: function (point, element) {
   1.116 +        if (!this.drops.length) {
   1.117 +            return;
   1.118 +        }
   1.119 +        var affected = [];
   1.120 +
   1.121 +        if (this.last_active) {
   1.122 +            this.last_active.deactivate();
   1.123 +        }
   1.124 +        MochiKit.Iter.forEach(this.drops, function (drop) {
   1.125 +            if (drop.isAffected(point, element)) {
   1.126 +                affected.push(drop);
   1.127 +            }
   1.128 +        });
   1.129 +        if (affected.length > 0) {
   1.130 +            drop = this.findDeepestChild(affected);
   1.131 +            MochiKit.Position.within(drop.element, point.page.x, point.page.y);
   1.132 +            drop.options.onhover(element, drop.element,
   1.133 +                MochiKit.Position.overlap(drop.options.overlap, drop.element));
   1.134 +            drop.activate();
   1.135 +        }
   1.136 +    },
   1.137 +
   1.138 +    fire: function (event, element) {
   1.139 +        if (!this.last_active) {
   1.140 +            return;
   1.141 +        }
   1.142 +        MochiKit.Position.prepare();
   1.143 +
   1.144 +        if (this.last_active.isAffected(event.mouse(), element)) {
   1.145 +            this.last_active.options.ondrop(element,
   1.146 +               this.last_active.element, event);
   1.147 +        }
   1.148 +    },
   1.149 +
   1.150 +    reset: function (element) {
   1.151 +        MochiKit.Base.map(function (drop) {
   1.152 +            if (drop.options.activeclass) {
   1.153 +                MochiKit.DOM.removeElementClass(drop.element,
   1.154 +                                                drop.options.activeclass);
   1.155 +            }
   1.156 +            drop.options.ondesactive(drop.element, element);
   1.157 +        }, this.drops);
   1.158 +        if (this.last_active) {
   1.159 +            this.last_active.deactivate();
   1.160 +        }
   1.161 +    }
   1.162 +};
   1.163 +
   1.164 +/** @id MochiKit.DragAndDrop.Droppable */
   1.165 +MochiKit.DragAndDrop.Droppable = function (element, options) {
   1.166 +    var cls = arguments.callee;
   1.167 +    if (!(this instanceof cls)) {
   1.168 +        return new cls(element, options);
   1.169 +    }
   1.170 +    this.__init__(element, options);
   1.171 +};
   1.172 +
   1.173 +MochiKit.DragAndDrop.Droppable.prototype = {
   1.174 +    /***
   1.175 +
   1.176 +    A droppable object. Simple use is to create giving an element:
   1.177 +
   1.178 +        new MochiKit.DragAndDrop.Droppable('myelement');
   1.179 +
   1.180 +    Generally you'll want to define the 'ondrop' function and maybe the
   1.181 +    'accept' option to filter draggables.
   1.182 +
   1.183 +    ***/
   1.184 +    __class__: MochiKit.DragAndDrop.Droppable,
   1.185 +
   1.186 +    __init__: function (element, /* optional */options) {
   1.187 +        var d = MochiKit.DOM;
   1.188 +        var b = MochiKit.Base;
   1.189 +        this.element = d.getElement(element);
   1.190 +        this.options = b.update({
   1.191 +
   1.192 +            /** @id MochiKit.DragAndDrop.greedy */
   1.193 +            greedy: true,
   1.194 +
   1.195 +            /** @id MochiKit.DragAndDrop.hoverclass */
   1.196 +            hoverclass: null,
   1.197 +
   1.198 +            /** @id MochiKit.DragAndDrop.activeclass */
   1.199 +            activeclass: null,
   1.200 +
   1.201 +            /** @id MochiKit.DragAndDrop.hoverfunc */
   1.202 +            hoverfunc: b.noop,
   1.203 +
   1.204 +            /** @id MochiKit.DragAndDrop.accept */
   1.205 +            accept: null,
   1.206 +
   1.207 +            /** @id MochiKit.DragAndDrop.onactive */
   1.208 +            onactive: b.noop,
   1.209 +
   1.210 +            /** @id MochiKit.DragAndDrop.ondesactive */
   1.211 +            ondesactive: b.noop,
   1.212 +
   1.213 +            /** @id MochiKit.DragAndDrop.onhover */
   1.214 +            onhover: b.noop,
   1.215 +
   1.216 +            /** @id MochiKit.DragAndDrop.ondrop */
   1.217 +            ondrop: b.noop,
   1.218 +
   1.219 +            /** @id MochiKit.DragAndDrop.containment */
   1.220 +            containment: [],
   1.221 +            tree: false
   1.222 +        }, options || {});
   1.223 +
   1.224 +        // cache containers
   1.225 +        this.options._containers = [];
   1.226 +        b.map(MochiKit.Base.bind(function (c) {
   1.227 +            this.options._containers.push(d.getElement(c));
   1.228 +        }, this), this.options.containment);
   1.229 +
   1.230 +        d.makePositioned(this.element); // fix IE
   1.231 +
   1.232 +        MochiKit.DragAndDrop.Droppables.register(this);
   1.233 +    },
   1.234 +
   1.235 +    /** @id MochiKit.DragAndDrop.isContained */
   1.236 +    isContained: function (element) {
   1.237 +        if (this.options._containers.length) {
   1.238 +            var containmentNode;
   1.239 +            if (this.options.tree) {
   1.240 +                containmentNode = element.treeNode;
   1.241 +            } else {
   1.242 +                containmentNode = element.parentNode;
   1.243 +            }
   1.244 +            return MochiKit.Iter.some(this.options._containers, function (c) {
   1.245 +                return containmentNode == c;
   1.246 +            });
   1.247 +        } else {
   1.248 +            return true;
   1.249 +        }
   1.250 +    },
   1.251 +
   1.252 +    /** @id MochiKit.DragAndDrop.isAccepted */
   1.253 +    isAccepted: function (element) {
   1.254 +        return ((!this.options.accept) || MochiKit.Iter.some(
   1.255 +          this.options.accept, function (c) {
   1.256 +            return MochiKit.DOM.hasElementClass(element, c);
   1.257 +        }));
   1.258 +    },
   1.259 +
   1.260 +    /** @id MochiKit.DragAndDrop.isAffected */
   1.261 +    isAffected: function (point, element) {
   1.262 +        return ((this.element != element) &&
   1.263 +                this.isContained(element) &&
   1.264 +                this.isAccepted(element) &&
   1.265 +                MochiKit.Position.within(this.element, point.page.x,
   1.266 +                                                       point.page.y));
   1.267 +    },
   1.268 +
   1.269 +    /** @id MochiKit.DragAndDrop.deactivate */
   1.270 +    deactivate: function () {
   1.271 +        /***
   1.272 +
   1.273 +        A droppable is deactivate when a draggable has been over it and left.
   1.274 +
   1.275 +        ***/
   1.276 +        if (this.options.hoverclass) {
   1.277 +            MochiKit.DOM.removeElementClass(this.element,
   1.278 +                                            this.options.hoverclass);
   1.279 +        }
   1.280 +        this.options.hoverfunc(this.element, false);
   1.281 +        MochiKit.DragAndDrop.Droppables.last_active = null;
   1.282 +    },
   1.283 +
   1.284 +    /** @id MochiKit.DragAndDrop.activate */
   1.285 +    activate: function () {
   1.286 +        /***
   1.287 +
   1.288 +        A droppable is active when a draggable is over it.
   1.289 +
   1.290 +        ***/
   1.291 +        if (this.options.hoverclass) {
   1.292 +            MochiKit.DOM.addElementClass(this.element, this.options.hoverclass);
   1.293 +        }
   1.294 +        this.options.hoverfunc(this.element, true);
   1.295 +        MochiKit.DragAndDrop.Droppables.last_active = this;
   1.296 +    },
   1.297 +
   1.298 +    /** @id MochiKit.DragAndDrop.destroy */
   1.299 +    destroy: function () {
   1.300 +        /***
   1.301 +
   1.302 +        Delete this droppable.
   1.303 +
   1.304 +        ***/
   1.305 +        MochiKit.DragAndDrop.Droppables.unregister(this);
   1.306 +    },
   1.307 +
   1.308 +    /** @id MochiKit.DragAndDrop.repr */
   1.309 +    repr: function () {
   1.310 +        return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
   1.311 +    }
   1.312 +};
   1.313 +
   1.314 +MochiKit.DragAndDrop.Draggables = {
   1.315 +    /***
   1.316 +
   1.317 +    Manage draggables elements. Not intended to direct use.
   1.318 +
   1.319 +    ***/
   1.320 +    drags: [],
   1.321 +
   1.322 +    register: function (draggable) {
   1.323 +        if (this.drags.length === 0) {
   1.324 +            var conn = MochiKit.Signal.connect;
   1.325 +            this.eventMouseUp = conn(document, 'onmouseup', this, this.endDrag);
   1.326 +            this.eventMouseMove = conn(document, 'onmousemove', this,
   1.327 +                                       this.updateDrag);
   1.328 +            this.eventKeypress = conn(document, 'onkeypress', this,
   1.329 +                                      this.keyPress);
   1.330 +        }
   1.331 +        this.drags.push(draggable);
   1.332 +    },
   1.333 +
   1.334 +    unregister: function (draggable) {
   1.335 +        this.drags = MochiKit.Base.filter(function (d) {
   1.336 +            return d != draggable;
   1.337 +        }, this.drags);
   1.338 +        if (this.drags.length === 0) {
   1.339 +            var disc = MochiKit.Signal.disconnect;
   1.340 +            disc(this.eventMouseUp);
   1.341 +            disc(this.eventMouseMove);
   1.342 +            disc(this.eventKeypress);
   1.343 +        }
   1.344 +    },
   1.345 +
   1.346 +    activate: function (draggable) {
   1.347 +        // allows keypress events if window is not currently focused
   1.348 +        // fails for Safari
   1.349 +        window.focus();
   1.350 +        this.activeDraggable = draggable;
   1.351 +    },
   1.352 +
   1.353 +    deactivate: function () {
   1.354 +        this.activeDraggable = null;
   1.355 +    },
   1.356 +
   1.357 +    updateDrag: function (event) {
   1.358 +        if (!this.activeDraggable) {
   1.359 +            return;
   1.360 +        }
   1.361 +        var pointer = event.mouse();
   1.362 +        // Mozilla-based browsers fire successive mousemove events with
   1.363 +        // the same coordinates, prevent needless redrawing (moz bug?)
   1.364 +        if (this._lastPointer && (MochiKit.Base.repr(this._lastPointer.page) ==
   1.365 +                                  MochiKit.Base.repr(pointer.page))) {
   1.366 +            return;
   1.367 +        }
   1.368 +        this._lastPointer = pointer;
   1.369 +        this.activeDraggable.updateDrag(event, pointer);
   1.370 +    },
   1.371 +
   1.372 +    endDrag: function (event) {
   1.373 +        if (!this.activeDraggable) {
   1.374 +            return;
   1.375 +        }
   1.376 +        this._lastPointer = null;
   1.377 +        this.activeDraggable.endDrag(event);
   1.378 +        this.activeDraggable = null;
   1.379 +    },
   1.380 +
   1.381 +    keyPress: function (event) {
   1.382 +        if (this.activeDraggable) {
   1.383 +            this.activeDraggable.keyPress(event);
   1.384 +        }
   1.385 +    },
   1.386 +
   1.387 +    notify: function (eventName, draggable, event) {
   1.388 +        MochiKit.Signal.signal(this, eventName, draggable, event);
   1.389 +    }
   1.390 +};
   1.391 +
   1.392 +/** @id MochiKit.DragAndDrop.Draggable */
   1.393 +MochiKit.DragAndDrop.Draggable = function (element, options) {
   1.394 +    var cls = arguments.callee;
   1.395 +    if (!(this instanceof cls)) {
   1.396 +        return new cls(element, options);
   1.397 +    }
   1.398 +    this.__init__(element, options);
   1.399 +};
   1.400 +
   1.401 +MochiKit.DragAndDrop.Draggable.prototype = {
   1.402 +    /***
   1.403 +
   1.404 +    A draggable object. Simple instantiate :
   1.405 +
   1.406 +        new MochiKit.DragAndDrop.Draggable('myelement');
   1.407 +
   1.408 +    ***/
   1.409 +    __class__ : MochiKit.DragAndDrop.Draggable,
   1.410 +
   1.411 +    __init__: function (element, /* optional */options) {
   1.412 +        var v = MochiKit.Visual;
   1.413 +        var b = MochiKit.Base;
   1.414 +        options = b.update({
   1.415 +
   1.416 +            /** @id MochiKit.DragAndDrop.handle */
   1.417 +            handle: false,
   1.418 +
   1.419 +            /** @id MochiKit.DragAndDrop.starteffect */
   1.420 +            starteffect: function (innerelement) {
   1.421 +                this._savedOpacity = MochiKit.Style.getStyle(innerelement, 'opacity') || 1.0;
   1.422 +                new v.Opacity(innerelement, {duration:0.2, from:this._savedOpacity, to:0.7});
   1.423 +            },
   1.424 +            /** @id MochiKit.DragAndDrop.reverteffect */
   1.425 +            reverteffect: function (innerelement, top_offset, left_offset) {
   1.426 +                var dur = Math.sqrt(Math.abs(top_offset^2) +
   1.427 +                          Math.abs(left_offset^2))*0.02;
   1.428 +                return new v.Move(innerelement,
   1.429 +                            {x: -left_offset, y: -top_offset, duration: dur});
   1.430 +            },
   1.431 +
   1.432 +            /** @id MochiKit.DragAndDrop.endeffect */
   1.433 +            endeffect: function (innerelement) {
   1.434 +                new v.Opacity(innerelement, {duration:0.2, from:0.7, to:this._savedOpacity});
   1.435 +            },
   1.436 +
   1.437 +            /** @id MochiKit.DragAndDrop.onchange */
   1.438 +            onchange: b.noop,
   1.439 +
   1.440 +            /** @id MochiKit.DragAndDrop.zindex */
   1.441 +            zindex: 1000,
   1.442 +
   1.443 +            /** @id MochiKit.DragAndDrop.revert */
   1.444 +            revert: false,
   1.445 +
   1.446 +            /** @id MochiKit.DragAndDrop.scroll */
   1.447 +            scroll: false,
   1.448 +
   1.449 +            /** @id MochiKit.DragAndDrop.scrollSensitivity */
   1.450 +            scrollSensitivity: 20,
   1.451 +
   1.452 +            /** @id MochiKit.DragAndDrop.scrollSpeed */
   1.453 +            scrollSpeed: 15,
   1.454 +            // false, or xy or [x, y] or function (x, y){return [x, y];}
   1.455 +
   1.456 +            /** @id MochiKit.DragAndDrop.snap */
   1.457 +            snap: false
   1.458 +        }, options || {});
   1.459 +
   1.460 +        var d = MochiKit.DOM;
   1.461 +        this.element = d.getElement(element);
   1.462 +
   1.463 +        if (options.handle && (typeof(options.handle) == 'string')) {
   1.464 +            this.handle = d.getFirstElementByTagAndClassName(null,
   1.465 +                                       options.handle, this.element);
   1.466 +        }
   1.467 +        if (!this.handle) {
   1.468 +            this.handle = d.getElement(options.handle);
   1.469 +        }
   1.470 +        if (!this.handle) {
   1.471 +            this.handle = this.element;
   1.472 +        }
   1.473 +
   1.474 +        if (options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
   1.475 +            options.scroll = d.getElement(options.scroll);
   1.476 +            this._isScrollChild = MochiKit.DOM.isChildNode(this.element, options.scroll);
   1.477 +        }
   1.478 +
   1.479 +        d.makePositioned(this.element);  // fix IE
   1.480 +
   1.481 +        this.delta = this.currentDelta();
   1.482 +        this.options = options;
   1.483 +        this.dragging = false;
   1.484 +
   1.485 +        this.eventMouseDown = MochiKit.Signal.connect(this.handle,
   1.486 +                              'onmousedown', this, this.initDrag);
   1.487 +        MochiKit.DragAndDrop.Draggables.register(this);
   1.488 +    },
   1.489 +
   1.490 +    /** @id MochiKit.DragAndDrop.destroy */
   1.491 +    destroy: function () {
   1.492 +        MochiKit.Signal.disconnect(this.eventMouseDown);
   1.493 +        MochiKit.DragAndDrop.Draggables.unregister(this);
   1.494 +    },
   1.495 +
   1.496 +    /** @id MochiKit.DragAndDrop.currentDelta */
   1.497 +    currentDelta: function () {
   1.498 +        var s = MochiKit.Style.getStyle;
   1.499 +        return [
   1.500 +          parseInt(s(this.element, 'left') || '0'),
   1.501 +          parseInt(s(this.element, 'top') || '0')];
   1.502 +    },
   1.503 +
   1.504 +    /** @id MochiKit.DragAndDrop.initDrag */
   1.505 +    initDrag: function (event) {
   1.506 +        if (!event.mouse().button.left) {
   1.507 +            return;
   1.508 +        }
   1.509 +        // abort on form elements, fixes a Firefox issue
   1.510 +        var src = event.target();
   1.511 +        var tagName = (src.tagName || '').toUpperCase();
   1.512 +        if (tagName === 'INPUT' || tagName === 'SELECT' ||
   1.513 +            tagName === 'OPTION' || tagName === 'BUTTON' ||
   1.514 +            tagName === 'TEXTAREA') {
   1.515 +            return;
   1.516 +        }
   1.517 +
   1.518 +        if (this._revert) {
   1.519 +            this._revert.cancel();
   1.520 +            this._revert = null;
   1.521 +        }
   1.522 +
   1.523 +        var pointer = event.mouse();
   1.524 +        var pos = MochiKit.Position.cumulativeOffset(this.element);
   1.525 +        this.offset = [pointer.page.x - pos.x, pointer.page.y - pos.y];
   1.526 +
   1.527 +        MochiKit.DragAndDrop.Draggables.activate(this);
   1.528 +        event.stop();
   1.529 +    },
   1.530 +
   1.531 +    /** @id MochiKit.DragAndDrop.startDrag */
   1.532 +    startDrag: function (event) {
   1.533 +        this.dragging = true;
   1.534 +        if (this.options.selectclass) {
   1.535 +            MochiKit.DOM.addElementClass(this.element,
   1.536 +                                         this.options.selectclass);
   1.537 +        }
   1.538 +        if (this.options.zindex) {
   1.539 +            this.originalZ = parseInt(MochiKit.Style.getStyle(this.element,
   1.540 +                                      'z-index') || '0');
   1.541 +            this.element.style.zIndex = this.options.zindex;
   1.542 +        }
   1.543 +
   1.544 +        if (this.options.ghosting) {
   1.545 +            this._clone = this.element.cloneNode(true);
   1.546 +            this.ghostPosition = MochiKit.Position.absolutize(this.element);
   1.547 +            this.element.parentNode.insertBefore(this._clone, this.element);
   1.548 +        }
   1.549 +
   1.550 +        if (this.options.scroll) {
   1.551 +            if (this.options.scroll == window) {
   1.552 +                var where = this._getWindowScroll(this.options.scroll);
   1.553 +                this.originalScrollLeft = where.left;
   1.554 +                this.originalScrollTop = where.top;
   1.555 +            } else {
   1.556 +                this.originalScrollLeft = this.options.scroll.scrollLeft;
   1.557 +                this.originalScrollTop = this.options.scroll.scrollTop;
   1.558 +            }
   1.559 +        }
   1.560 +
   1.561 +        MochiKit.DragAndDrop.Droppables.prepare(this.element);
   1.562 +        MochiKit.DragAndDrop.Draggables.notify('start', this, event);
   1.563 +        if (this.options.starteffect) {
   1.564 +            this.options.starteffect(this.element);
   1.565 +        }
   1.566 +    },
   1.567 +
   1.568 +    /** @id MochiKit.DragAndDrop.updateDrag */
   1.569 +    updateDrag: function (event, pointer) {
   1.570 +        if (!this.dragging) {
   1.571 +            this.startDrag(event);
   1.572 +        }
   1.573 +        MochiKit.Position.prepare();
   1.574 +        MochiKit.DragAndDrop.Droppables.show(pointer, this.element);
   1.575 +        MochiKit.DragAndDrop.Draggables.notify('drag', this, event);
   1.576 +        this.draw(pointer);
   1.577 +        this.options.onchange(this);
   1.578 +
   1.579 +        if (this.options.scroll) {
   1.580 +            this.stopScrolling();
   1.581 +            var p, q;
   1.582 +            if (this.options.scroll == window) {
   1.583 +                var s = this._getWindowScroll(this.options.scroll);
   1.584 +                p = new MochiKit.Style.Coordinates(s.left, s.top);
   1.585 +                q = new MochiKit.Style.Coordinates(s.left + s.width,
   1.586 +                                                   s.top + s.height);
   1.587 +            } else {
   1.588 +                p = MochiKit.Position.page(this.options.scroll);
   1.589 +                p.x += this.options.scroll.scrollLeft;
   1.590 +                p.y += this.options.scroll.scrollTop;
   1.591 +                p.x += (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0);
   1.592 +                p.y += (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
   1.593 +                q = new MochiKit.Style.Coordinates(p.x + this.options.scroll.offsetWidth,
   1.594 +                                                   p.y + this.options.scroll.offsetHeight);
   1.595 +            }
   1.596 +            var speed = [0, 0];
   1.597 +            if (pointer.page.x > (q.x - this.options.scrollSensitivity)) {
   1.598 +                speed[0] = pointer.page.x - (q.x - this.options.scrollSensitivity);
   1.599 +            } else if (pointer.page.x < (p.x + this.options.scrollSensitivity)) {
   1.600 +                speed[0] = pointer.page.x - (p.x + this.options.scrollSensitivity);
   1.601 +            }
   1.602 +            if (pointer.page.y > (q.y - this.options.scrollSensitivity)) {
   1.603 +                speed[1] = pointer.page.y - (q.y - this.options.scrollSensitivity);
   1.604 +            } else if (pointer.page.y < (p.y + this.options.scrollSensitivity)) {
   1.605 +                speed[1] = pointer.page.y - (p.y + this.options.scrollSensitivity);
   1.606 +            }
   1.607 +            this.startScrolling(speed);
   1.608 +        }
   1.609 +
   1.610 +        // fix AppleWebKit rendering
   1.611 +        if (/AppleWebKit'/.test(navigator.appVersion)) {
   1.612 +            window.scrollBy(0, 0);
   1.613 +        }
   1.614 +        event.stop();
   1.615 +    },
   1.616 +
   1.617 +    /** @id MochiKit.DragAndDrop.finishDrag */
   1.618 +    finishDrag: function (event, success) {
   1.619 +        var dr = MochiKit.DragAndDrop;
   1.620 +        this.dragging = false;
   1.621 +        if (this.options.selectclass) {
   1.622 +            MochiKit.DOM.removeElementClass(this.element,
   1.623 +                                            this.options.selectclass);
   1.624 +        }
   1.625 +
   1.626 +        if (this.options.ghosting) {
   1.627 +            // XXX: from a user point of view, it would be better to remove
   1.628 +            // the node only *after* the MochiKit.Visual.Move end when used
   1.629 +            // with revert.
   1.630 +            MochiKit.Position.relativize(this.element, this.ghostPosition);
   1.631 +            MochiKit.DOM.removeElement(this._clone);
   1.632 +            this._clone = null;
   1.633 +        }
   1.634 +
   1.635 +        if (success) {
   1.636 +            dr.Droppables.fire(event, this.element);
   1.637 +        }
   1.638 +        dr.Draggables.notify('end', this, event);
   1.639 +
   1.640 +        var revert = this.options.revert;
   1.641 +        if (revert && typeof(revert) == 'function') {
   1.642 +            revert = revert(this.element);
   1.643 +        }
   1.644 +
   1.645 +        var d = this.currentDelta();
   1.646 +        if (revert && this.options.reverteffect) {
   1.647 +            this._revert = this.options.reverteffect(this.element,
   1.648 +                d[1] - this.delta[1], d[0] - this.delta[0]);
   1.649 +        } else {
   1.650 +            this.delta = d;
   1.651 +        }
   1.652 +
   1.653 +        if (this.options.zindex) {
   1.654 +            this.element.style.zIndex = this.originalZ;
   1.655 +        }
   1.656 +
   1.657 +        if (this.options.endeffect) {
   1.658 +            this.options.endeffect(this.element);
   1.659 +        }
   1.660 +
   1.661 +        dr.Draggables.deactivate();
   1.662 +        dr.Droppables.reset(this.element);
   1.663 +    },
   1.664 +
   1.665 +    /** @id MochiKit.DragAndDrop.keyPress */
   1.666 +    keyPress: function (event) {
   1.667 +        if (event.key().string != "KEY_ESCAPE") {
   1.668 +            return;
   1.669 +        }
   1.670 +        this.finishDrag(event, false);
   1.671 +        event.stop();
   1.672 +    },
   1.673 +
   1.674 +    /** @id MochiKit.DragAndDrop.endDrag */
   1.675 +    endDrag: function (event) {
   1.676 +        if (!this.dragging) {
   1.677 +            return;
   1.678 +        }
   1.679 +        this.stopScrolling();
   1.680 +        this.finishDrag(event, true);
   1.681 +        event.stop();
   1.682 +    },
   1.683 +
   1.684 +    /** @id MochiKit.DragAndDrop.draw */
   1.685 +    draw: function (point) {
   1.686 +        var pos = MochiKit.Position.cumulativeOffset(this.element);
   1.687 +        var d = this.currentDelta();
   1.688 +        pos.x -= d[0];
   1.689 +        pos.y -= d[1];
   1.690 +
   1.691 +        if (this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
   1.692 +            pos.x -= this.options.scroll.scrollLeft - this.originalScrollLeft;
   1.693 +            pos.y -= this.options.scroll.scrollTop - this.originalScrollTop;
   1.694 +        }
   1.695 +
   1.696 +        var p = [point.page.x - pos.x - this.offset[0],
   1.697 +                 point.page.y - pos.y - this.offset[1]];
   1.698 +
   1.699 +        if (this.options.snap) {
   1.700 +            if (typeof(this.options.snap) == 'function') {
   1.701 +                p = this.options.snap(p[0], p[1]);
   1.702 +            } else {
   1.703 +                if (this.options.snap instanceof Array) {
   1.704 +                    var i = -1;
   1.705 +                    p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
   1.706 +                            i += 1;
   1.707 +                            return Math.round(v/this.options.snap[i]) *
   1.708 +                                   this.options.snap[i];
   1.709 +                        }, this), p);
   1.710 +                } else {
   1.711 +                    p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
   1.712 +                        return Math.round(v/this.options.snap) *
   1.713 +                               this.options.snap;
   1.714 +                        }, this), p);
   1.715 +                }
   1.716 +            }
   1.717 +        }
   1.718 +        var style = this.element.style;
   1.719 +        if ((!this.options.constraint) ||
   1.720 +            (this.options.constraint == 'horizontal')) {
   1.721 +            style.left = p[0] + 'px';
   1.722 +        }
   1.723 +        if ((!this.options.constraint) ||
   1.724 +            (this.options.constraint == 'vertical')) {
   1.725 +            style.top = p[1] + 'px';
   1.726 +        }
   1.727 +        if (style.visibility == 'hidden') {
   1.728 +            style.visibility = '';  // fix gecko rendering
   1.729 +        }
   1.730 +    },
   1.731 +
   1.732 +    /** @id MochiKit.DragAndDrop.stopScrolling */
   1.733 +    stopScrolling: function () {
   1.734 +        if (this.scrollInterval) {
   1.735 +            clearInterval(this.scrollInterval);
   1.736 +            this.scrollInterval = null;
   1.737 +            MochiKit.DragAndDrop.Draggables._lastScrollPointer = null;
   1.738 +        }
   1.739 +    },
   1.740 +
   1.741 +    /** @id MochiKit.DragAndDrop.startScrolling */
   1.742 +    startScrolling: function (speed) {
   1.743 +        if (!speed[0] && !speed[1]) {
   1.744 +            return;
   1.745 +        }
   1.746 +        this.scrollSpeed = [speed[0] * this.options.scrollSpeed,
   1.747 +                            speed[1] * this.options.scrollSpeed];
   1.748 +        this.lastScrolled = new Date();
   1.749 +        this.scrollInterval = setInterval(MochiKit.Base.bind(this.scroll, this), 10);
   1.750 +    },
   1.751 +
   1.752 +    /** @id MochiKit.DragAndDrop.scroll */
   1.753 +    scroll: function () {
   1.754 +        var current = new Date();
   1.755 +        var delta = current - this.lastScrolled;
   1.756 +        this.lastScrolled = current;
   1.757 +
   1.758 +        if (this.options.scroll == window) {
   1.759 +            var s = this._getWindowScroll(this.options.scroll);
   1.760 +            if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
   1.761 +                var dm = delta / 1000;
   1.762 +                this.options.scroll.scrollTo(s.left + dm * this.scrollSpeed[0],
   1.763 +                                             s.top + dm * this.scrollSpeed[1]);
   1.764 +            }
   1.765 +        } else {
   1.766 +            this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
   1.767 +            this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
   1.768 +        }
   1.769 +
   1.770 +        var d = MochiKit.DragAndDrop;
   1.771 +
   1.772 +        MochiKit.Position.prepare();
   1.773 +        d.Droppables.show(d.Draggables._lastPointer, this.element);
   1.774 +        d.Draggables.notify('drag', this);
   1.775 +        if (this._isScrollChild) {
   1.776 +            d.Draggables._lastScrollPointer = d.Draggables._lastScrollPointer || d.Draggables._lastPointer;
   1.777 +            d.Draggables._lastScrollPointer.x += this.scrollSpeed[0] * delta / 1000;
   1.778 +            d.Draggables._lastScrollPointer.y += this.scrollSpeed[1] * delta / 1000;
   1.779 +            if (d.Draggables._lastScrollPointer.x < 0) {
   1.780 +                d.Draggables._lastScrollPointer.x = 0;
   1.781 +            }
   1.782 +            if (d.Draggables._lastScrollPointer.y < 0) {
   1.783 +                d.Draggables._lastScrollPointer.y = 0;
   1.784 +            }
   1.785 +            this.draw(d.Draggables._lastScrollPointer);
   1.786 +        }
   1.787 +
   1.788 +        this.options.onchange(this);
   1.789 +    },
   1.790 +
   1.791 +    _getWindowScroll: function (win) {
   1.792 +        var vp, w, h;
   1.793 +        MochiKit.DOM.withWindow(win, function () {
   1.794 +            vp = MochiKit.Style.getViewportPosition(win.document);
   1.795 +        });
   1.796 +        if (win.innerWidth) {
   1.797 +            w = win.innerWidth;
   1.798 +            h = win.innerHeight;
   1.799 +        } else if (win.document.documentElement && win.document.documentElement.clientWidth) {
   1.800 +            w = win.document.documentElement.clientWidth;
   1.801 +            h = win.document.documentElement.clientHeight;
   1.802 +        } else {
   1.803 +            w = win.document.body.offsetWidth;
   1.804 +            h = win.document.body.offsetHeight;
   1.805 +        }
   1.806 +        return {top: vp.x, left: vp.y, width: w, height: h};
   1.807 +    },
   1.808 +
   1.809 +    /** @id MochiKit.DragAndDrop.repr */
   1.810 +    repr: function () {
   1.811 +        return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
   1.812 +    }
   1.813 +};
   1.814 +
   1.815 +MochiKit.DragAndDrop.__new__ = function () {
   1.816 +    MochiKit.Base.nameFunctions(this);
   1.817 +
   1.818 +    this.EXPORT_TAGS = {
   1.819 +        ":common": this.EXPORT,
   1.820 +        ":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
   1.821 +    };
   1.822 +};
   1.823 +
   1.824 +MochiKit.DragAndDrop.__new__();
   1.825 +
   1.826 +MochiKit.Base._exportSymbols(this, MochiKit.DragAndDrop);
   1.827 +

mercurial