Make WordPress Core

Ticket #19881: 19881.patch

File 19881.patch, 33.2 KB (added by ocean90, 13 years ago)
  • wp-includes/js/imgareaselect/jquery.imgareaselect.dev.js

     
    11/*
    22 * imgAreaSelect jQuery plugin
    3  * version 0.9.6
     3 * version 0.9.8
    44 *
    55 * Copyright (c) 2008-2011 Michal Wojciechowski (odyniec.net)
    66 *
     
    1313
    1414(function($) {
    1515
     16/*
     17 * Math functions will be used extensively, so it's convenient to make a few
     18 * shortcuts
     19 */
    1620var abs = Math.abs,
    1721    max = Math.max,
    1822    min = Math.min,
    1923    round = Math.round;
    2024
     25/**
     26 * Create a new HTML div element
     27 *
     28 * @return A jQuery object representing the new element
     29 */
    2130function div() {
    2231    return $('<div/>');
    2332}
    2433
     34/**
     35 * imgAreaSelect initialization
     36 *
     37 * @param img
     38 *            A HTML image element to attach the plugin to
     39 * @param options
     40 *            An options object
     41 */
    2542$.imgAreaSelect = function (img, options) {
    2643    var
    27 
     44        /* jQuery object representing the image */
    2845        $img = $(img),
    2946
     47        /* Has the image finished loading? */
    3048        imgLoaded,
    3149
     50        /* Plugin elements */
     51
     52        /* Container box */
    3253        $box = div(),
     54        /* Selection area */
    3355        $area = div(),
     56        /* Border (four divs) */
    3457        $border = div().add(div()).add(div()).add(div()),
     58        /* Outer area (four divs) */
    3559        $outer = div().add(div()).add(div()).add(div()),
     60        /* Handles (empty by default, initialized in setOptions()) */
    3661        $handles = $([]),
    3762
     63        /*
     64         * Additional element to work around a cursor problem in Opera
     65         * (explained later)
     66         */
    3867        $areaOpera,
    3968
     69        /* Image position (relative to viewport) */
    4070        left, top,
    4171
     72        /* Image offset (as returned by .offset()) */
    4273        imgOfs = { left: 0, top: 0 },
    4374
     75        /* Image dimensions (as returned by .width() and .height()) */
    4476        imgWidth, imgHeight,
    4577
     78        /*
     79         * jQuery object representing the parent element that the plugin
     80         * elements are appended to
     81         */
    4682        $parent,
    4783
     84        /* Parent element offset (as returned by .offset()) */
    4885        parOfs = { left: 0, top: 0 },
    4986
     87        /* Base z-index for plugin elements */
    5088        zIndex = 0,
    5189
     90        /* Plugin elements position */
    5291        position = 'absolute',
    5392
     93        /* X/Y coordinates of the starting point for move/resize operations */
    5494        startX, startY,
    5595
     96        /* Horizontal and vertical scaling factors */
    5697        scaleX, scaleY,
    5798
    58         resizeMargin = 10,
    59 
     99        /* Current resize mode ("nw", "se", etc.) */
    60100        resize,
    61101
     102        /* Selection area constraints */
    62103        minWidth, minHeight, maxWidth, maxHeight,
    63104
     105        /* Aspect ratio to maintain (floating point number) */
    64106        aspectRatio,
    65107
     108        /* Are the plugin elements currently displayed? */
    66109        shown,
    67110
     111        /* Current selection (relative to parent element) */
    68112        x1, y1, x2, y2,
    69113
     114        /* Current selection (relative to scaled image) */
    70115        selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 },
    71116
     117        /* Document element */
    72118        docElem = document.documentElement,
    73119
     120        /* Various helper variables used throughout the code */
    74121        $p, d, i, o, w, h, adjusted;
    75122
     123    /*
     124     * Translate selection coordinates (relative to scaled image) to viewport
     125     * coordinates (relative to parent element)
     126     */
     127
     128    /**
     129     * Translate selection X to viewport X
     130     *
     131     * @param x
     132     *            Selection X
     133     * @return Viewport X
     134     */
    76135    function viewX(x) {
    77136        return x + imgOfs.left - parOfs.left;
    78137    }
    79138
     139    /**
     140     * Translate selection Y to viewport Y
     141     *
     142     * @param y
     143     *            Selection Y
     144     * @return Viewport Y
     145     */
    80146    function viewY(y) {
    81147        return y + imgOfs.top - parOfs.top;
    82148    }
    83149
     150    /*
     151     * Translate viewport coordinates to selection coordinates
     152     */
     153
     154    /**
     155     * Translate viewport X to selection X
     156     *
     157     * @param x
     158     *            Viewport X
     159     * @return Selection X
     160     */
    84161    function selX(x) {
    85162        return x - imgOfs.left + parOfs.left;
    86163    }
    87164
     165    /**
     166     * Translate viewport Y to selection Y
     167     *
     168     * @param y
     169     *            Viewport Y
     170     * @return Selection Y
     171     */
    88172    function selY(y) {
    89173        return y - imgOfs.top + parOfs.top;
    90174    }
    91175
     176    /*
     177     * Translate event coordinates (relative to document) to viewport
     178     * coordinates
     179     */
     180
     181    /**
     182     * Get event X and translate it to viewport X
     183     *
     184     * @param event
     185     *            The event object
     186     * @return Viewport X
     187     */
    92188    function evX(event) {
    93189        return event.pageX - parOfs.left;
    94190    }
    95191
     192    /**
     193     * Get event Y and translate it to viewport Y
     194     *
     195     * @param event
     196     *            The event object
     197     * @return Viewport Y
     198     */
    96199    function evY(event) {
    97200        return event.pageY - parOfs.top;
    98201    }
    99202
     203    /**
     204     * Get the current selection
     205     *
     206     * @param noScale
     207     *            If set to <code>true</code>, scaling is not applied to the
     208     *            returned selection
     209     * @return Selection object
     210     */
    100211    function getSelection(noScale) {
    101212        var sx = noScale || scaleX, sy = noScale || scaleY;
    102213
     
    108219            height: round(selection.y2 * sy) - round(selection.y1 * sy) };
    109220    }
    110221
     222    /**
     223     * Set the current selection
     224     *
     225     * @param x1
     226     *            X coordinate of the upper left corner of the selection area
     227     * @param y1
     228     *            Y coordinate of the upper left corner of the selection area
     229     * @param x2
     230     *            X coordinate of the lower right corner of the selection area
     231     * @param y2
     232     *            Y coordinate of the lower right corner of the selection area
     233     * @param noScale
     234     *            If set to <code>true</code>, scaling is not applied to the
     235     *            new selection
     236     */
    111237    function setSelection(x1, y1, x2, y2, noScale) {
    112238        var sx = noScale || scaleX, sy = noScale || scaleY;
    113239
     
    122248        selection.height = selection.y2 - selection.y1;
    123249    }
    124250
     251    /**
     252     * Recalculate image and parent offsets
     253     */
    125254    function adjust() {
     255        /*
     256         * Do not adjust if image width is not a positive number. This might
     257         * happen when imgAreaSelect is put on a parent element which is then
     258         * hidden.
     259         */
    126260        if (!$img.width())
    127261            return;
    128262
     263        /*
     264         * Get image offset. The .offset() method returns float values, so they
     265         * need to be rounded.
     266         */
    129267        imgOfs = { left: round($img.offset().left), top: round($img.offset().top) };
    130268
     269        /* Get image dimensions */
    131270        imgWidth = $img.innerWidth();
    132271        imgHeight = $img.innerHeight();
    133272
    134273        imgOfs.top += ($img.outerHeight() - imgHeight) >> 1;
    135274        imgOfs.left += ($img.outerWidth() - imgWidth) >> 1;
    136275
    137         minWidth = options.minWidth || 0;
    138         minHeight = options.minHeight || 0;
    139         maxWidth = min(options.maxWidth || 1<<24, imgWidth);
    140         maxHeight = min(options.maxHeight || 1<<24, imgHeight);
     276        /* Set minimum and maximum selection area dimensions */
     277        minWidth = round(options.minWidth / scaleX) || 0;
     278        minHeight = round(options.minHeight / scaleY) || 0;
     279        maxWidth = round(min(options.maxWidth / scaleX || 1<<24, imgWidth));
     280        maxHeight = round(min(options.maxHeight / scaleY || 1<<24, imgHeight));
    141281
     282        /*
     283         * Workaround for jQuery 1.3.2 incorrect offset calculation, originally
     284         * observed in Safari 3. Firefox 2 is also affected.
     285         */
    142286        if ($().jquery == '1.3.2' && position == 'fixed' &&
    143287            !docElem['getBoundingClientRect'])
    144288        {
     
    146290            imgOfs.left += max(document.body.scrollLeft, docElem.scrollLeft);
    147291        }
    148292
    149         parOfs = $.inArray($parent.css('position'), ['absolute', 'relative']) + 1 ?
     293        /* Determine parent element offset */
     294        parOfs = /absolute|relative/.test($parent.css('position')) ?
    150295            { left: round($parent.offset().left) - $parent.scrollLeft(),
    151296                top: round($parent.offset().top) - $parent.scrollTop() } :
    152297            position == 'fixed' ?
     
    156301        left = viewX(0);
    157302        top = viewY(0);
    158303
     304        /*
     305         * Check if selection area is within image boundaries, adjust if
     306         * necessary
     307         */
    159308        if (selection.x2 > imgWidth || selection.y2 > imgHeight)
    160309            doResize();
    161310    }
    162311
     312    /**
     313     * Update plugin elements
     314     *
     315     * @param resetKeyPress
     316     *            If set to <code>false</code>, this instance's keypress
     317     *            event handler is not activated
     318     */
    163319    function update(resetKeyPress) {
     320        /* If plugin elements are hidden, do nothing */
    164321        if (!shown) return;
    165322
     323        /*
     324         * Set the position and size of the container box and the selection area
     325         * inside it
     326         */
    166327        $box.css({ left: viewX(selection.x1), top: viewY(selection.y1) })
    167328            .add($area).width(w = selection.width).height(h = selection.height);
    168329
     330        /*
     331         * Reset the position of selection area, borders, and handles (IE6/IE7
     332         * position them incorrectly if we don't do this)
     333         */
    169334        $area.add($border).add($handles).css({ left: 0, top: 0 });
    170335
     336        /* Set border dimensions */
    171337        $border
    172338            .width(max(w - $border.outerWidth() + $border.innerWidth(), 0))
    173339            .height(max(h - $border.outerHeight() + $border.innerHeight(), 0));
    174340
     341        /* Arrange the outer area elements */
    175342        $($outer[0]).css({ left: left, top: top,
    176343            width: selection.x1, height: imgHeight });
    177344        $($outer[1]).css({ left: left + selection.x1, top: top,
     
    184351        w -= $handles.outerWidth();
    185352        h -= $handles.outerHeight();
    186353
     354        /* Arrange handles */
    187355        switch ($handles.length) {
    188356        case 8:
    189357            $($handles[4]).css({ left: w >> 1 });
     
    196364        }
    197365
    198366        if (resetKeyPress !== false) {
     367            /*
     368             * Need to reset the document keypress event handler -- unbind the
     369             * current handler
     370             */
    199371            if ($.imgAreaSelect.keyPress != docKeyPress)
    200372                $(document).unbind($.imgAreaSelect.keyPress,
    201373                    $.imgAreaSelect.onKeyPress);
    202374
    203375            if (options.keys)
     376                /*
     377                 * Set the document keypress event handler to this instance's
     378                 * docKeyPress() function
     379                 */
    204380                $(document)[$.imgAreaSelect.keyPress](
    205381                    $.imgAreaSelect.onKeyPress = docKeyPress);
    206382        }
    207383
     384        /*
     385         * Internet Explorer displays 1px-wide dashed borders incorrectly by
     386         * filling the spaces between dashes with white. Toggling the margin
     387         * property between 0 and "auto" fixes this in IE6 and IE7 (IE8 is still
     388         * broken). This workaround is not perfect, as it requires setTimeout()
     389         * and thus causes the border to flicker a bit, but I haven't found a
     390         * better solution.
     391         *
     392         * Note: This only happens with CSS borders, set with the borderWidth,
     393         * borderOpacity, borderColor1, and borderColor2 options (which are now
     394         * deprecated). Borders created with GIF background images are fine.
     395         */
    208396        if ($.browser.msie && $border.outerWidth() - $border.innerWidth() == 2) {
    209397            $border.css('margin', 0);
    210398            setTimeout(function () { $border.css('margin', 'auto'); }, 0);
    211399        }
    212400    }
    213401
     402    /**
     403     * Do the complete update sequence: recalculate offsets, update the
     404     * elements, and set the correct values of x1, y1, x2, and y2.
     405     *
     406     * @param resetKeyPress
     407     *            If set to <code>false</code>, this instance's keypress
     408     *            event handler is not activated
     409     */
    214410    function doUpdate(resetKeyPress) {
    215411        adjust();
    216412        update(resetKeyPress);
     
    218414        x2 = viewX(selection.x2); y2 = viewY(selection.y2);
    219415    }
    220416
     417    /**
     418     * Hide or fade out an element (or multiple elements)
     419     *
     420     * @param $elem
     421     *            A jQuery object containing the element(s) to hide/fade out
     422     * @param fn
     423     *            Callback function to be called when fadeOut() completes
     424     */
    221425    function hide($elem, fn) {
    222426        options.fadeSpeed ? $elem.fadeOut(options.fadeSpeed, fn) : $elem.hide();
    223 
    224427    }
    225428
     429    /**
     430     * Selection area mousemove event handler
     431     *
     432     * @param event
     433     *            The event object
     434     */
    226435    function areaMouseMove(event) {
    227436        var x = selX(evX(event)) - selection.x1,
    228437            y = selY(evY(event)) - selection.y1;
     
    234443            $box.one('mouseout', function () { adjusted = false; });
    235444        }
    236445
     446        /* Clear the resize mode */
    237447        resize = '';
    238448
    239449        if (options.resizable) {
     450            /*
     451             * Check if the mouse pointer is over the resize margin area and set
     452             * the resize mode accordingly
     453             */
    240454            if (y <= options.resizeMargin)
    241455                resize = 'n';
    242456            else if (y >= selection.height - options.resizeMargin)
     
    253467            $areaOpera.toggle();
    254468    }
    255469
     470    /**
     471     * Document mouseup event handler
     472     *
     473     * @param event
     474     *            The event object
     475     */
    256476    function docMouseUp(event) {
     477        /* Set back the default cursor */
    257478        $('body').css('cursor', '');
     479        /*
     480         * If autoHide is enabled, or if the selection has zero width/height,
     481         * hide the selection and the outer area
     482         */
    258483        if (options.autoHide || selection.width * selection.height == 0)
    259484            hide($box.add($outer), function () { $(this).hide(); });
    260485
     
    264489        options.onSelectEnd(img, getSelection());
    265490    }
    266491
     492    /**
     493     * Selection area mousedown event handler
     494     *
     495     * @param event
     496     *            The event object
     497     * @return false
     498     */
    267499    function areaMouseDown(event) {
    268500        if (event.which != 1) return false;
    269501
    270502        adjust();
    271503
    272504        if (resize) {
     505            /* Resize mode is in effect */
    273506            $('body').css('cursor', resize + '-resize');
    274507
    275508            x1 = viewX(selection[/w/.test(resize) ? 'x2' : 'x1']);
     
    299532        return false;
    300533    }
    301534
     535    /**
     536     * Adjust the x2/y2 coordinates to maintain aspect ratio (if defined)
     537     *
     538     * @param xFirst
     539     *            If set to <code>true</code>, calculate x2 first. Otherwise,
     540     *            calculate y2 first.
     541     */
    302542    function fixAspectRatio(xFirst) {
    303543        if (aspectRatio)
    304544            if (xFirst) {
    305545                x2 = max(left, min(left + imgWidth,
    306546                    x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1)));
    307 
    308547                y2 = round(max(top, min(top + imgHeight,
    309548                    y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1))));
    310549                x2 = round(x2);
     
    318557            }
    319558    }
    320559
     560    /**
     561     * Resize the selection area respecting the minimum/maximum dimensions and
     562     * aspect ratio
     563     */
    321564    function doResize() {
     565        /*
     566         * Make sure the top left corner of the selection area stays within
     567         * image boundaries (it might not if the image source was dynamically
     568         * changed).
     569         */
    322570        x1 = min(x1, left + imgWidth);
    323571        y1 = min(y1, top + imgHeight);
    324572
    325573        if (abs(x2 - x1) < minWidth) {
     574            /* Selection width is smaller than minWidth */
    326575            x2 = x1 - minWidth * (x2 < x1 || -1);
    327576
    328577            if (x2 < left)
     
    332581        }
    333582
    334583        if (abs(y2 - y1) < minHeight) {
     584            /* Selection height is smaller than minHeight */
    335585            y2 = y1 - minHeight * (y2 < y1 || -1);
    336586
    337587            if (y2 < top)
     
    346596        fixAspectRatio(abs(x2 - x1) < abs(y2 - y1) * aspectRatio);
    347597
    348598        if (abs(x2 - x1) > maxWidth) {
     599            /* Selection width is greater than maxWidth */
    349600            x2 = x1 - maxWidth * (x2 < x1 || -1);
    350601            fixAspectRatio();
    351602        }
    352603
    353604        if (abs(y2 - y1) > maxHeight) {
     605            /* Selection height is greater than maxHeight */
    354606            y2 = y1 - maxHeight * (y2 < y1 || -1);
    355607            fixAspectRatio(true);
    356608        }
     
    364616        options.onSelectChange(img, getSelection());
    365617    }
    366618
     619    /**
     620     * Mousemove event handler triggered when the user is selecting an area
     621     *
     622     * @param event
     623     *            The event object
     624     * @return false
     625     */
    367626    function selectingMouseMove(event) {
    368         x2 = resize == '' || /w|e/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2);
    369         y2 = resize == '' || /n|s/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2);
     627        x2 = /w|e|^$/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2);
     628        y2 = /n|s|^$/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2);
    370629
    371630        doResize();
    372631
    373632        return false;
    374 
    375633    }
    376634
     635    /**
     636     * Move the selection area
     637     *
     638     * @param newX1
     639     *            New viewport X1
     640     * @param newY1
     641     *            New viewport Y1
     642     */
    377643    function doMove(newX1, newY1) {
    378644        x2 = (x1 = newX1) + selection.width;
    379645        y2 = (y1 = newY1) + selection.height;
     
    386652        options.onSelectChange(img, getSelection());
    387653    }
    388654
     655    /**
     656     * Mousemove event handler triggered when the selection area is being moved
     657     *
     658     * @param event
     659     *            The event object
     660     * @return false
     661     */
    389662    function movingMouseMove(event) {
    390663        x1 = max(left, min(startX + evX(event), left + imgWidth - selection.width));
    391664        y1 = max(top, min(startY + evY(event), top + imgHeight - selection.height));
     
    393666        doMove(x1, y1);
    394667
    395668        event.preventDefault();
    396 
    397669        return false;
    398670    }
    399671
     672    /**
     673     * Start selection
     674     */
    400675    function startSelection() {
    401676        $(document).unbind('mousemove', startSelection);
    402677        adjust();
    403678
    404679        x2 = x1;
    405680        y2 = y1;
    406 
    407681        doResize();
    408682
    409683        resize = '';
    410684
    411         if ($outer.is(':not(:visible)'))
     685        if (!$outer.is(':visible'))
     686            /* Show the plugin elements */
    412687            $box.add($outer).hide().fadeIn(options.fadeSpeed||0);
    413688
    414689        shown = true;
     
    420695        options.onSelectStart(img, getSelection());
    421696    }
    422697
     698    /**
     699     * Cancel selection
     700     */
    423701    function cancelSelection() {
    424702        $(document).unbind('mousemove', startSelection)
    425703            .unbind('mouseup', cancelSelection);
     
    427705
    428706        setSelection(selX(x1), selY(y1), selX(x1), selY(y1));
    429707
    430         options.onSelectChange(img, getSelection());
    431         options.onSelectEnd(img, getSelection());
     708        /* If this is an API call, callback functions should not be triggered */
     709        if (!this instanceof $.imgAreaSelect) {
     710            options.onSelectChange(img, getSelection());
     711            options.onSelectEnd(img, getSelection());
     712        }
    432713    }
    433714
     715    /**
     716     * Image mousedown event handler
     717     *
     718     * @param event
     719     *            The event object
     720     * @return false
     721     */
    434722    function imgMouseDown(event) {
     723        /* Ignore the event if animation is in progress */
    435724        if (event.which != 1 || $outer.is(':animated')) return false;
    436725
    437726        adjust();
    438727        startX = x1 = evX(event);
    439728        startY = y1 = evY(event);
    440729
     730        /* Selection will start when the mouse is moved */
    441731        $(document).mousemove(startSelection).mouseup(cancelSelection);
    442732
    443733        return false;
    444734    }
    445735
     736    /**
     737     * Window resize event handler
     738     */
    446739    function windowResize() {
    447740        doUpdate(false);
    448741    }
    449742
     743    /**
     744     * Image load event handler. This is the final part of the initialization
     745     * process.
     746     */
    450747    function imgLoad() {
    451748        imgLoaded = true;
    452749
     750        /* Set options */
    453751        setOptions(options = $.extend({
    454752            classPrefix: 'imgareaselect',
    455753            movable: true,
     
    471769            $box.add($outer).hide().fadeIn(options.fadeSpeed||0);
    472770        }
    473771
     772        /*
     773         * Call the onInit callback. The setTimeout() call is used to ensure
     774         * that the plugin has been fully initialized and the object instance is
     775         * available (so that it can be obtained in the callback).
     776         */
    474777        setTimeout(function () { options.onInit(img, getSelection()); }, 0);
    475778    }
    476779
     780    /**
     781     * Document keypress event handler
     782     *
     783     * @param event
     784     *            The event object
     785     * @return false
     786     */
    477787    var docKeyPress = function(event) {
    478788        var k = options.keys, d, t, key = event.keyCode;
    479789
     
    486796            (k.ctrl == 'resize' && event.ctrlKey) ||
    487797            (k.alt == 'resize' && (event.altKey || event.originalEvent.altKey)))
    488798        {
     799            /* Resize selection */
     800
    489801            switch (key) {
    490802            case 37:
     803                /* Left */
    491804                d = -d;
    492805            case 39:
     806                /* Right */
    493807                t = max(x1, x2);
    494808                x1 = min(x1, x2);
    495809                x2 = max(t + d, x1);
    496810                fixAspectRatio();
    497811                break;
    498812            case 38:
     813                /* Up */
    499814                d = -d;
    500815            case 40:
     816                /* Down */
    501817                t = max(y1, y2);
    502818                y1 = min(y1, y2);
    503819                y2 = max(t + d, y1);
     
    510826            doResize();
    511827        }
    512828        else {
     829            /* Move selection */
     830
    513831            x1 = min(x1, x2);
    514832            y1 = min(y1, y2);
    515833
    516834            switch (key) {
    517835            case 37:
     836                /* Left */
    518837                doMove(max(x1 - d, left), y1);
    519838                break;
    520839            case 38:
     840                /* Up */
    521841                doMove(x1, max(y1 - d, top));
    522842                break;
    523843            case 39:
     844                /* Right */
    524845                doMove(x1 + min(d, imgWidth - selX(x2)), y1);
    525846                break;
    526847            case 40:
     848                /* Down */
    527849                doMove(x1, y1 + min(d, imgHeight - selY(y2)));
    528850                break;
    529851            default:
     
    534856        return false;
    535857    };
    536858
     859    /**
     860     * Apply style options to plugin element (or multiple elements)
     861     *
     862     * @param $elem
     863     *            A jQuery object representing the element(s) to style
     864     * @param props
     865     *            An object that maps option names to corresponding CSS
     866     *            properties
     867     */
    537868    function styleOptions($elem, props) {
    538869        for (option in props)
    539870            if (options[option] !== undefined)
    540871                $elem.css(props[option], options[option]);
    541872    }
    542873
     874    /**
     875     * Set plugin options
     876     *
     877     * @param newOptions
     878     *            The new options object
     879     */
    543880    function setOptions(newOptions) {
    544881        if (newOptions.parent)
    545882            ($parent = $(newOptions.parent)).append($box.add($outer));
    546883
     884        /* Merge the new options with the existing ones */
    547885        $.extend(options, newOptions);
    548886
    549887        adjust();
    550888
    551889        if (newOptions.handles != null) {
     890            /* Recreate selection area handles */
    552891            $handles.remove();
    553892            $handles = $([]);
    554893
     
    557896            while (i--)
    558897                $handles = $handles.add(div());
    559898
     899            /* Add a class to handles and set the CSS properties */
    560900            $handles.addClass(options.classPrefix + '-handle').css({
    561901                position: 'absolute',
     902                /*
     903                 * The font-size property needs to be set to zero, otherwise
     904                 * Internet Explorer makes the handles too large
     905                 */
    562906                fontSize: 0,
    563907                zIndex: zIndex + 1 || 1
    564908            });
    565909
     910            /*
     911             * If handle width/height has not been set with CSS rules, set the
     912             * default 5px
     913             */
    566914            if (!parseInt($handles.css('width')) >= 0)
    567915                $handles.width(5).height(5);
    568916
     917            /*
     918             * If the borderWidth option is in use, add a solid border to
     919             * handles
     920             */
    569921            if (o = options.borderWidth)
    570922                $handles.css({ borderWidth: o, borderStyle: 'solid' });
    571923
     924            /* Apply other style options */
    572925            styleOptions($handles, { borderColor1: 'border-color',
    573926                borderColor2: 'background-color',
    574927                borderOpacity: 'opacity' });
    575928        }
    576929
     930        /* Calculate scale factors */
    577931        scaleX = options.imageWidth / imgWidth || 1;
    578932        scaleY = options.imageHeight / imgHeight || 1;
    579933
     934        /* Set selection */
    580935        if (newOptions.x1 != null) {
    581936            setSelection(newOptions.x1, newOptions.y1, newOptions.x2,
    582937                newOptions.y2);
     
    584939        }
    585940
    586941        if (newOptions.keys)
     942            /* Enable keyboard support */
    587943            options.keys = $.extend({ shift: 1, ctrl: 'resize' },
    588944                newOptions.keys);
    589945
     946        /* Add classes to plugin elements */
    590947        $outer.addClass(options.classPrefix + '-outer');
    591948        $area.addClass(options.classPrefix + '-selection');
    592949        for (i = 0; i++ < 4;)
    593950            $($border[i-1]).addClass(options.classPrefix + '-border' + i);
    594951
     952        /* Apply style options */
    595953        styleOptions($area, { selectionColor: 'background-color',
    596954            selectionOpacity: 'opacity' });
    597955        styleOptions($border, { borderOpacity: 'opacity',
     
    603961        if (o = options.borderColor2)
    604962            $($border[1]).css({ borderStyle: 'dashed', borderColor: o });
    605963
     964        /* Append all the selection area elements to the container box */
    606965        $box.append($area.add($border).add($areaOpera).add($handles));
    607966
    608967        if ($.browser.msie) {
    609             if (o = $outer.css('filter').match(/opacity=([0-9]+)/))
     968            if (o = $outer.css('filter').match(/opacity=(\d+)/))
    610969                $outer.css('opacity', o[1]/100);
    611             if (o = $border.css('filter').match(/opacity=([0-9]+)/))
     970            if (o = $border.css('filter').match(/opacity=(\d+)/))
    612971                $border.css('opacity', o[1]/100);
    613972        }
    614973
     
    620979            doUpdate();
    621980        }
    622981
     982        /* Calculate the aspect ratio factor */
    623983        aspectRatio = (d = (options.aspectRatio || '').split(/:/))[0] / d[1];
    624984
    625985        $img.add($outer).unbind('mousedown', imgMouseDown);
    626986
    627987        if (options.disable || options.enable === false) {
     988            /* Disable the plugin */
    628989            $box.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown);
    629990            $(window).unbind('resize', windowResize);
    630991        }
    631992        else {
    632993            if (options.enable || options.disable === false) {
     994                /* Enable the plugin */
    633995                if (options.resizable || options.movable)
    634996                    $box.mousemove(areaMouseMove).mousedown(areaMouseDown);
    635997
     
    6431005        options.enable = options.disable = undefined;
    6441006    }
    6451007
     1008    /**
     1009     * Remove plugin completely
     1010     */
    6461011    this.remove = function () {
     1012        /*
     1013         * Call setOptions with { disable: true } to unbind the event handlers
     1014         */
    6471015        setOptions({ disable: true });
    6481016        $box.add($outer).remove();
    6491017    };
    6501018
     1019    /*
     1020     * Public API
     1021     */
     1022
     1023    /**
     1024     * Get current options
     1025     *
     1026     * @return An object containing the set of options currently in use
     1027     */
    6511028    this.getOptions = function () { return options; };
    6521029
     1030    /**
     1031     * Set plugin options
     1032     *
     1033     * @param newOptions
     1034     *            The new options object
     1035     */
    6531036    this.setOptions = setOptions;
    6541037
     1038    /**
     1039     * Get the current selection
     1040     *
     1041     * @param noScale
     1042     *            If set to <code>true</code>, scaling is not applied to the
     1043     *            returned selection
     1044     * @return Selection object
     1045     */
    6551046    this.getSelection = getSelection;
    6561047
     1048    /**
     1049     * Set the current selection
     1050     *
     1051     * @param x1
     1052     *            X coordinate of the upper left corner of the selection area
     1053     * @param y1
     1054     *            Y coordinate of the upper left corner of the selection area
     1055     * @param x2
     1056     *            X coordinate of the lower right corner of the selection area
     1057     * @param y2
     1058     *            Y coordinate of the lower right corner of the selection area
     1059     * @param noScale
     1060     *            If set to <code>true</code>, scaling is not applied to the
     1061     *            new selection
     1062     */
    6571063    this.setSelection = setSelection;
    6581064
     1065    /**
     1066     * Cancel selection
     1067     */
     1068    this.cancelSelection = cancelSelection;
     1069
     1070    /**
     1071     * Update plugin elements
     1072     *
     1073     * @param resetKeyPress
     1074     *            If set to <code>false</code>, this instance's keypress
     1075     *            event handler is not activated
     1076     */
    6591077    this.update = doUpdate;
    6601078
     1079    /*
     1080     * Traverse the image's parent elements (up to <body>) and find the
     1081     * highest z-index
     1082     */
    6611083    $p = $img;
    6621084
    6631085    while ($p.length) {
    6641086        zIndex = max(zIndex,
    6651087            !isNaN($p.css('z-index')) ? $p.css('z-index') : zIndex);
     1088        /* Also check if any of the ancestor elements has fixed position */
    6661089        if ($p.css('position') == 'fixed')
    6671090            position = 'fixed';
    6681091
    6691092        $p = $p.parent(':not(body)');
    6701093    }
    6711094
     1095    /*
     1096     * If z-index is given as an option, it overrides the one found by the
     1097     * above loop
     1098     */
    6721099    zIndex = options.zIndex || zIndex;
    6731100
    6741101    if ($.browser.msie)
    6751102        $img.attr('unselectable', 'on');
    6761103
     1104    /*
     1105     * In MSIE and WebKit, we need to use the keydown event instead of keypress
     1106     */
    6771107    $.imgAreaSelect.keyPress = $.browser.msie ||
    6781108        $.browser.safari ? 'keydown' : 'keypress';
    6791109
     1110    /*
     1111     * There is a bug affecting the CSS cursor property in Opera (observed in
     1112     * versions up to 10.00) that prevents the cursor from being updated unless
     1113     * the mouse leaves and enters the element again. To trigger the mouseover
     1114     * event, we're adding an additional div to $box and we're going to toggle
     1115     * it when mouse moves inside the selection area.
     1116     */
    6801117    if ($.browser.opera)
    6811118        $areaOpera = div().css({ width: '100%', height: '100%',
    6821119            position: 'absolute', zIndex: zIndex + 2 || 2 });
    6831120
     1121    /*
     1122     * We initially set visibility to "hidden" as a workaround for a weird
     1123     * behaviour observed in Google Chrome 1.0.154.53 (on Windows XP). Normally
     1124     * we would just set display to "none", but, for some reason, if we do so
     1125     * then Chrome refuses to later display the element with .show() or
     1126     * .fadeIn().
     1127     */
    6841128    $box.add($outer).css({ visibility: 'hidden', position: position,
    6851129        overflow: 'hidden', zIndex: zIndex || '0' });
    6861130    $box.css({ zIndex: zIndex + 2 || 2 });
    6871131    $area.add($border).css({ position: 'absolute', fontSize: 0 });
    6881132
     1133    /*
     1134     * If the image has been fully loaded, or if it is not really an image (eg.
     1135     * a div), call imgLoad() immediately; otherwise, bind it to be called once
     1136     * on image load event.
     1137     */
    6891138    img.complete || img.readyState == 'complete' || !$img.is('img') ?
    6901139        imgLoad() : $img.one('load', imgLoad);
    6911140
    692     if ($.browser.msie && $.browser.version >= 9)
     1141    /*
     1142     * MSIE 9.0 doesn't always fire the image load event -- resetting the src
     1143     * attribute seems to trigger it. The check is for version 7 and above to
     1144     * accommodate for MSIE 9 running in compatibility mode.
     1145     */
     1146   if ($.browser.msie && $.browser.version >= 7)
    6931147        img.src = img.src;
    6941148};
    6951149
     1150/**
     1151 * Invoke imgAreaSelect on a jQuery object containing the image(s)
     1152 *
     1153 * @param options
     1154 *            Options object
     1155 * @return The jQuery object or a reference to imgAreaSelect instance (if the
     1156 *         <code>instance</code> option was specified)
     1157 */
    6961158$.fn.imgAreaSelect = function (options) {
    6971159    options = options || {};
    6981160
    6991161    this.each(function () {
     1162        /* Is there already an imgAreaSelect instance bound to this element? */
    7001163        if ($(this).data('imgAreaSelect')) {
     1164            /* Yes there is -- is it supposed to be removed? */
    7011165            if (options.remove) {
     1166                /* Remove the plugin */
    7021167                $(this).data('imgAreaSelect').remove();
    7031168                $(this).removeData('imgAreaSelect');
    7041169            }
    7051170            else
     1171                /* Reset options */
    7061172                $(this).data('imgAreaSelect').setOptions(options);
    7071173        }
    7081174        else if (!options.remove) {
     1175            /* No exising instance -- create a new one */
     1176
     1177            /*
     1178             * If neither the "enable" nor the "disable" option is present, add
     1179             * "enable" as the default
     1180             */
    7091181            if (options.enable === undefined && options.disable === undefined)
    7101182                options.enable = true;
    7111183
     
    7141186    });
    7151187
    7161188    if (options.instance)
     1189        /*
     1190         * Return the imgAreaSelect instance bound to the first element in the
     1191         * set
     1192         */
    7171193        return $(this).data('imgAreaSelect');
    7181194
    7191195    return this;
    7201196};
    7211197
    722 })(jQuery);
     1198})(jQuery);
     1199 No newline at end of file