WordPress.org

Make WordPress Core

Ticket #19881: 19881.patch

File 19881.patch, 33.2 KB (added by ocean90, 2 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