<div id="crop-wrap" class="account-img-wrap">          <div class="account-imges noflow mt_10">              <form data-action="http://mail.139qy.com/webmail/service/contacts?func=addr:userUpImg&amp;sid=4aAIjSaJ1ieXP1RcLOvO8Ner6d3Jd6Is000001&amp;cguid=0.7667588309847113,328" method="post" enctype="multipart/form-data" target="ifr" data-dom="form" action="http://mail.139qy.com/webmail/service/contacts?func=addr:userUpImg&amp;sid=4aAIjSaJ1ieXP1RcLOvO8Ner6d3Jd6Is000001&amp;cguid=0.7667588309847113,328">                  <input type="hidden" name="x" data-dom="x" value="136.75675675675674">                  <input type="hidden" name="y" data-dom="y" value="231.89189189189187">                  <input type="hidden" name="w" data-dom="w" value="276.48648648648646">                  <input type="hidden" name="h" data-dom="h" value="273.5135135135135">                  <input id="avatarUrl" type="hidden" name="u" data-dom="u">                  <span class="uploadBtn" style="overflow: hidden;">                      <input class="file" data-dom="file" name="file" style="outline: none;" hidefocus="true" type="file" title="点击上传头像">                      <img id="uplaodAvatarBtn" class="avatar" src="/resource_addr/images/upload_p.jpg" data-def="/resource_addr/images/upload_p.jpg" alt="" title="" width="90" height="90">                  </span>              </form>          </div>          <div class="account-img-tool mt_5 ta_c"><a class="delAvatar she-btn  hide " href="javascript:void(0)"><span><span>删除</span></span></a></div>      </div>

 

 function uploadAvatar(avatarShow, avatarId) {

                        //初始化上传环境
                        var wrap = $('#crop-wrap');
                        var delAvatarBtn = wrap.find('.delAvatar');
                        var cut = new Cutting(wrap, {
                            dblcallback:function(){
                                cut.submit(function (url) {
                                    tip(Lang.Addr.a0003);
                                    var domAvatarShow = avatarShow[0];
                                    domAvatarShow.src = util.avatarUrl(url);
                                    avatarId.val(url);
                                    dialog.hide("show-crop");
                                    delAvatarBtn.removeClass('hide');
                                });
                            },
                            afterSelect: function (path, url) {

                                t.showDialog("crop", {avatar: path}, function () {
                                    var content = dialog.getContent("show-crop");
                                    cut.crop = content.find('.previewBig');
                                    cut.small = content.find('.previewSmall');
                                    cut.adapt = cut.crop.parent();
                                    cut.crop.attr('src', path);
                                    cut.crop.attr('src', path);
                                    if (url) {
                                        $("#avatarUrl").val(url);
                                    }
                                    cut.create();
                                    tip(false);

                                    content.bind("ok", $.proxy(cut.dblclick, cut));
                                }, 'show-crop');
                            }
                        });
//                        content.bind("ok", $.proxy(cut.dblclick,cut));
                        delAvatarBtn.click(function () {
                            avatarShow.attr("src", avatarShow.data('def'));
                            avatarId.val('');
                            dialog.hide("show-crop");
                            delAvatarBtn.addClass('hide');
                        });
                    }

 

 

/**
 * 截图上传控件
 *
 * development by Ryan
 * mail: zengyi.zal@gmail.com
 *
 * useing jQuery JavaScript frame v1.6.1+
 */
;;;(function(window, $){
    var util = window.util;
    var tip = window.tip || function(){};
    var Lang = window.Lang || {};
    Lang.Addr = Lang.Addr || {};
    /**
     * iframe upload
     * @param form
     * @param extraData
     * @param handleName
     * @param handle
     */
    function submitForm(form, extraData, handleName, handle) {
        var data = $.extend({
            'sid': window.sid,
            'callback': handleName
        }, extraData);
        var action = util.obj2Url(data, form.attr('action'));
        form.attr('action', action);
        window[handleName] = handle;
        window.callback = function () {};
        form.one('submit', function () {
            tip(Lang.Addr.a0129, 1, -1);
        });
        form.submit();
    }

    var Cutting = function(){
        this.initialize.apply(this, arguments);
    }

    /**
     * 扩展原型
     * @type {{constructor: Function, initialize: Function, create: Function, position: Function, select: Function, update: Function, setCrop: Function, preview: Function, imgReady: null}}
     */
    Cutting.prototype = {
        //构造函数
        constructor : Cutting,
        //初始化函數
        initialize : function(element, options) {
            var t = this;
            this.element = $(element);
            this.options = $.extend(true,{
                SIZE_MID:96.0,
                maxWidth:256.0,
                maxHeight:248.0,
                drag:false,
                initcallback:function(){},
                dblcallback:function(){},
                afterSelect: function () {}
            },options);

            this.maxWidth  = this.options.maxWidth;
            this.maxHeight  = this.options.maxHeight;
            this.SIZE_MID = this.options.SIZE_MID;
            this.dblclick = this.options.dblcallback;

            this.file = $(t.options.file);

            //初始化dom
            this.element.find("[data-dom]").each(function(i,o){
                var dom = $(o),domName  = dom.data("dom");
                domName && (t[domName] = dom);
            });

            this.action = this.form.data("action") || "";
            this.form.attr("action", this.action);
            this.file.change(function(e){
                t.select(this);
            });
            this.options.drag && this.create();
        },
        /**
         * 自适应图片,并创建控件
         * @param img
         * @param afterAdapt
         */
        create:function (img, afterAdapt){
            var t = this;
            if(typeof img === "function") {
                afterAdapt = img,img = null;
            }
            img  =  img || t.crop[0];
            //预先设置图片不可见,以防出现闪烁的情况。
            img.style.visibility = 'hidden';
            var maxHeight = this.maxHeight, maxWidth = this.maxWidth;
            var aspect = maxWidth / maxHeight;

            //利用imgReady提前获取图片大小自适应大小
            t.imgReady(img.src, function (){
                var w = this.width, h = this.height, adaptW, adaptH;
                var picAspect = w / h;

                if (w <= maxWidth && h <= maxHeight) {
                    adaptW = w;
                    adaptH = h;
                } else {
                    if (picAspect > aspect) {
                        adaptW = w > maxWidth ? maxWidth : w;
                        adaptH = adaptW / w * h;
                    } else {
                        adaptH = h > maxHeight ? maxHeight : h;
                        adaptW = adaptH / h * w;
                    }
                }
                img.width = adaptW;
                img.height = adaptH;
                img.style.visibility = 'visible';
                img.ow = w;
                img.oh = h;
            }, function (){
                t.position();
//                console.log(t.cropApi);
//                if(t.cropApi){
//                    t.update(img.width, img.height);
//                }else{
                    t.setCrop(img, img.width, img.height, t.options.initcallback);
//                }
                typeof afterAdapt === 'function' && afterAdapt.call(img, img.width, img.height);
            }, function (){
                window.console && console.log(Lang.Addr.a0060);
            });
        },
        /**
         *  设置图片位置
         */
        position:function(){
            var t = this,maxWidth = this.maxWidth,maxHeight = this.maxHeight;
            var crop = t.crop,width = crop.width(),height = crop.height();
            crop.css({
                marginLeft:(width < maxWidth) ? (maxWidth-width) / 2 : 0,
                marginTop:(height < maxHeight) ? (maxHeight-height) / 2 : 0
            });
        },
        /**
         * 选中文件后
         * @param fileInput
         */
        select : function(fileInput){
            var t =this;
            var files = fileInput.files;
            if (files) {
                //ff and chrome
                if (!files.length) {
                    return;
                }
                //遍历files并处理
                for (var i = 0; i < files.length; i++) {
                    var file =  files[i];
                    var imageType = /image.*/;
                    //通过type属性进行图片格式过滤
                    if (!file.type.match(imageType)) {
                        tip(top.Lang.Addr.wenjiangeshicuowu, 2);//文件格式错误
                        continue;
                    }
                    standardHandle(file);
                }
            } else {
                //ie
                ieHandle();
            }

            function ieHandle () {
                submitForm(t.form, {'flag':2}, 'avatarUploadHandle', function(resp){
                    if(resp){
                        var info = resp["var"];
                        if (resp.code === 'S_OK') {
                            var path  = util.avatarUrl(info);
                            t.options.afterSelect.call(t, path, info);
//                            t.crop.attr("src",path);
//                            t.small.attr("src",path);
//                            t.u.val(info);
//                            t.create();
//                            tip(false);
                        } else {
                            info = info || Lang.Addr.a0126;
                            tip(info, 2);
                        }
                    }
                });
            }
            function standardHandle (file) {
                //读入文件
                var reader = new FileReader();
                reader.onload = function(e){
                    var imgData = e.target.result;
                    t.options.afterSelect.call(t, imgData);
//                    t.crop.attr("src",imgData);
//                    t.small.attr("src",imgData);
//                    t.create();
                };
                reader.readAsDataURL(file);
            }
        },
        /**
         * 更新选区
         * @param width
         * @param height
         */
        update:function(width,height){
            var initValue = (width > height ? height : width) / 2;
            this.cropApi.setSelection((width - initValue) / 2,(height - initValue) / 2,(width + initValue) / 2,(height + initValue) / 2,true);
            this.cropApi.setOptions({ show: true });
            this.cropApi.update();
        },
        /**
         * 设置截图控件
         * @param img
         * @param width
         * @param height
         * @param afterInit
         */
        setCrop:function (img, width, height, afterInit){
            //截图区域偏移值
            var initValue = (width > height ? height : width) > this.SIZE_MID ? (width > height ? height : width) / 2 : width;

            //初始化截图控件
            this.cropApi = $(img).crop({
                keys: true,
                fadeSpeed: 200,
                handles: true,
                aspectRatio: '1:1',
                parent: this.adapt,
                onInit: $.proxy(this.preview,this),
                onSelectChange: $.proxy(this.preview,this),
                ondblclick: $.proxy(this.dblclick,this),
                persistent: true,
                imageWidth: width,
                imageHeight: height,
                instance: true,
                x1: (width - initValue) / 2,
                y1: (height - initValue) / 2,
                x2: (width + initValue) / 2,
                y2: (height + initValue) / 2
            });

            //初始化完成后的回调
            typeof afterInit === 'function' && afterInit.call(img, width, height);
        },
        //预览图生成
        preview : function(img, selection){
            if (!selection.width || !selection.height) {
                return;
            }
            var SIZE_MID = this.SIZE_MID;
            var w = selection.width;
            var h = selection.height;
            var iw = img.width;
            var ih = img.height;
            var ox = selection.x1;
            var oy = selection.y1;

            var v = img.ow / iw;

            var getMargin = function (size, pos, limit){
                return -Math.round(limit * pos / size);
            };

            var getSize = function (size, isize, limit){
                return Math.round(limit * isize / size);
            };

            var setCss = function (elem, limit){
                elem && elem.css({
                    width: getSize(w, iw, limit),
                    height: getSize(h, ih, limit),
                    marginLeft: getMargin(w, ox, limit),
                    marginTop: getMargin(h, oy, limit)
                });
            };
            setCss(this.small, SIZE_MID);
            this.w.val(v * w);
            this.h.val(v * h);
            this.x.val(v * ox);
            this.y.val(v * oy);
        },
        /**
         * 提交截图数据
         * @param callback
         */
        submit:function(callback){
            var t = this;
            if (!t.file.val()) {
                return tip(Lang.Addr.a0217, 2);
            }
            var flag = 0;
            if (typeof (FileReader) == 'undefined') {
                flag = 1;
                t.file.prop('disabled', true);
            }
            submitForm(t.form, {flag : flag}, 'avatarUploadHandle', function(resp){
                var info = resp["var"];
                if (resp.code === 'S_OK') {
                    callback && callback.call(t,info)
                } else {
                    info = info || Lang.Addr.a0126;
                    tip(info, 2);
                }
                t.file.prop('disabled', false);
            });
            t.form.attr("action", t.options.action);
        },
        /**
         * 图片头数据加载就绪事件 - 更快获取图片尺寸
         * @version    2011.05.27
         * @author    TangBin
         * http://www.planeart.cn/?p=1121
         * @param    {String}    图片路径
         * @param    {Function}    尺寸就绪
         * @param    {Function}    加载完毕 (可选)
         * @param    {Function}    加载错误 (可选)
         * @example imgReady('http://www.google.com.hk/intl/zh-CN/images/logo_cn.png', function () {
            alert('size ready: width=' + this.width + '; height=' + this.height);
         });
         */
        imgReady :(function () {
            var list = [], intervalId = null,
            // 用来执行队列
                tick = function () {
                    var i = 0;
                    for (; i < list.length; i++) {
                        var item = list[i];
                        item.end ? list.splice(i--, 1) : list[i]();
                    };
                    !list.length && stop();
                },

            // 停止所有定时器队列
                stop = function () {
                    clearInterval(intervalId);
                    intervalId = null;
                };

            return function (url, ready, load, error) {
                var onready, width, height, newWidth, newHeight,
                    img = new Image();

                img.src = url;

                // 如果图片被缓存,则直接返回缓存数据
                if (img.complete) {
                    ready.call(img);
                    load && load.call(img);
                    return;
                };

                width = img.width;
                height = img.height;

                // 加载错误后的事件
                img.onerror = function () {
                    error && error.call(img);
                    onready.end = true;
                    img = img.onload = img.onerror = null;
                };
                // 图片尺寸就绪
                onready = function () {
                    newWidth = img.width;
                    newHeight = img.height;
                    if (newWidth !== width || newHeight !== height ||
                        // 如果图片已经在其他地方加载可使用面积检测
                        newWidth * newHeight > 1024
                        ) {
                        ready.call(img);
                        onready.end = true;
                    };
                };
                onready();
                // 完全加载完毕的事件
                img.onload = function () {
                    // onload在定时器时间差范围内可能比onready快
                    // 这里进行检查并保证onready优先执行
                    !onready.end && onready();
                    load && load.call(img);
                    // IE gif动画会循环执行onload,置空onload即可
                    img = img.onload = img.onerror = null;
                };

                // 加入队列中定期执行
                if (!onready.end) {
                    list.push(onready);
                    // 无论何时只允许出现一个定时器,减少浏览器性能损耗
                    if (intervalId === null) intervalId = setInterval(tick, 40);
                };
            };
        })()
    };
    window["Cutting"] = Cutting;
})(window, jQuery);

jquery.crop.js

 

/**
 *  Crop
 */
(function(window, $) {

    var document = window.document;
    var navigator = window.navigator;

var abs = Math.abs,
    max = Math.max,
    min = Math.min,
    round = Math.round;

function div() {
    return $('<div/>');
}

$.crop = function (img, options) {
    var $img = $(img),
        imgLoaded,

        $box = div(),
        $area = div(),
        $border = div().add(div()).add(div()).add(div()),
        $outer = div().add(div()).add(div()).add(div()),
        $handles = $([]),

        $areaOpera,

        left, top,

        imgOfs = { left: 0, top: 0 },

        imgWidth, imgHeight,

        $parent,

        parOfs = { left: 0, top: 0 },

        zIndex = 0,

        position = 'absolute',

        startX, startY,

        scaleX, scaleY,

        resize,

        minWidth, minHeight, maxWidth, maxHeight,

        aspectRatio,

        shown,

        x1, y1, x2, y2,

        selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 },

        docElem = document.documentElement,

        ua = navigator.userAgent,

        $p, d, i, o, w, h, adjusted;

    function viewX(x) {
        return x + imgOfs.left - parOfs.left;
    }

    function viewY(y) {
        return y + imgOfs.top - parOfs.top;
    }

    function selX(x) {
        return x - imgOfs.left + parOfs.left;
    }

    function selY(y) {
        return y - imgOfs.top + parOfs.top;
    }

    function evX(event) {
        return event.pageX - parOfs.left;
    }

    function evY(event) {
        return event.pageY - parOfs.top;
    }

    function getSelection(noScale) {
        var sx = noScale || scaleX, sy = noScale || scaleY;

        return { x1: round(selection.x1 * sx),
            y1: round(selection.y1 * sy),
            x2: round(selection.x2 * sx),
            y2: round(selection.y2 * sy),
            width: round(selection.x2 * sx) - round(selection.x1 * sx),
            height: round(selection.y2 * sy) - round(selection.y1 * sy) };
    }

    function setSelection(x1, y1, x2, y2, noScale) {
        var sx = noScale || scaleX, sy = noScale || scaleY;

        selection = {
            x1: round(x1 / sx || 0),
            y1: round(y1 / sy || 0),
            x2: round(x2 / sx || 0),
            y2: round(y2 / sy || 0)
        };

        selection.width = selection.x2 - selection.x1;
        selection.height = selection.y2 - selection.y1;
    }

    function adjust() {
        if (!imgLoaded || !$img.width())
            return;

        imgOfs = { left: round($img.offset().left), top: round($img.offset().top) };

        imgWidth = $img.innerWidth();
        imgHeight = $img.innerHeight();

        imgOfs.top += ($img.outerHeight() - imgHeight) >> 1;
        imgOfs.left += ($img.outerWidth() - imgWidth) >> 1;

        minWidth = round(options.minWidth / scaleX) || 0;
        minHeight = round(options.minHeight / scaleY) || 0;
        maxWidth = round(min(options.maxWidth / scaleX || 1<<24, imgWidth));
        maxHeight = round(min(options.maxHeight / scaleY || 1<<24, imgHeight));

        if ($().jquery == '1.3.2' && position == 'fixed' &&
            !docElem['getBoundingClientRect'])
        {
            imgOfs.top += max(document.body.scrollTop, docElem.scrollTop);
            imgOfs.left += max(document.body.scrollLeft, docElem.scrollLeft);
        }

        parOfs = /absolute|relative/.test($parent.css('position')) ?
            { left: round($parent.offset().left) - $parent.scrollLeft(),
                top: round($parent.offset().top) - $parent.scrollTop() } :
            position == 'fixed' ?
                { left: $(document).scrollLeft(), top: $(document).scrollTop() } :
                { left: 0, top: 0 };

        left = viewX(0);
        top = viewY(0);

        if (selection.x2 > imgWidth || selection.y2 > imgHeight)
            doResize();
    }

    function update(resetKeyPress) {
        if (!shown) return;

        $box.css({ left: viewX(selection.x1), top: viewY(selection.y1) })
            .add($area).width(w = selection.width).height(h = selection.height);

        $area.add($border).add($handles).css({ left: 0, top: 0 });

        $border.width(max(w - $border.outerWidth() + $border.innerWidth(), 0))
            .height(max(h - $border.outerHeight() + $border.innerHeight(), 0));

        $($outer[0]).css({ left: left, top: top,
            width: selection.x1, height: imgHeight });
        $($outer[1]).css({ left: left + selection.x1, top: top,
            width: w, height: selection.y1 });
        $($outer[2]).css({ left: left + selection.x2, top: top,
            width: imgWidth - selection.x2, height: imgHeight });
        $($outer[3]).css({ left: left + selection.x1, top: top + selection.y2,
            width: w, height: imgHeight - selection.y2 });

        w -= $handles.outerWidth();
        h -= $handles.outerHeight();

        switch ($handles.length) {
        case 8:
            $($handles[4]).css({ left: w >> 1 });
            $($handles[5]).css({ left: w, top: h >> 1 });
            $($handles[6]).css({ left: w >> 1, top: h });
            $($handles[7]).css({ top: h >> 1 });
        case 4:
            $handles.slice(1,3).css({ left: w });
            $handles.slice(2,4).css({ top: h });
        }

        if (resetKeyPress !== false) {
            if ($.crop.onKeyPress != docKeyPress)
                $(document).unbind($.crop.keyPress,
                    $.crop.onKeyPress);

            if (options.keys)
                $(document)[$.crop.keyPress](
                    $.crop.onKeyPress = docKeyPress);
        }

        if (msie && $border.outerWidth() - $border.innerWidth() == 2) {
            $border.css('margin', 0);
            setTimeout(function () { $border.css('margin', 'auto'); }, 0);
        }
    }

    function doUpdate(resetKeyPress) {
        adjust();
        update(resetKeyPress);
        x1 = viewX(selection.x1); y1 = viewY(selection.y1);
        x2 = viewX(selection.x2); y2 = viewY(selection.y2);
    }

    function hide($elem, fn) {
        options.fadeSpeed ? $elem.fadeOut(options.fadeSpeed, fn) : $elem.hide();

    }

    function areaMouseMove(event) {
        var x = selX(evX(event)) - selection.x1,
            y = selY(evY(event)) - selection.y1;

        if (!adjusted) {
            adjust();
            adjusted = true;

            $box.one('mouseout', function () { adjusted = false; });
        }

        resize = '';

        if (options.resizable) {
            if (y <= options.resizeMargin)
                resize = 'n';
            else if (y >= selection.height - options.resizeMargin)
                resize = 's';
            if (x <= options.resizeMargin)
                resize += 'w';
            else if (x >= selection.width - options.resizeMargin)
                resize += 'e';
        }

        $box.css('cursor', resize ? resize + '-resize' :
            options.movable ? 'move' : '');
        if ($areaOpera)
            $areaOpera.toggle();
    }

    function docMouseUp(event) {
        $('body').css('cursor', '');
        if (options.autoHide || selection.width * selection.height == 0)
            hide($box.add($outer), function () { $(this).hide(); });

        $(document).unbind('mousemove', selectingMouseMove);
        $box.mousemove(areaMouseMove);

        options.onSelectEnd(img, getSelection());
    }

    function areaMouseDown(event) {
        if (event.which != 1) return false;

        adjust();

        if (resize) {
            $('body').css('cursor', resize + '-resize');

            x1 = viewX(selection[/w/.test(resize) ? 'x2' : 'x1']);
            y1 = viewY(selection[/n/.test(resize) ? 'y2' : 'y1']);

            $(document).mousemove(selectingMouseMove)
                .one('mouseup', docMouseUp);
            $box.unbind('mousemove', areaMouseMove);
        }
        else if (options.movable) {
            startX = left + selection.x1 - evX(event);
            startY = top + selection.y1 - evY(event);

            $box.unbind('mousemove', areaMouseMove);

            $(document).mousemove(movingMouseMove)
                .one('mouseup', function () {
                    options.onSelectEnd(img, getSelection());

                    $(document).unbind('mousemove', movingMouseMove);
                    $box.mousemove(areaMouseMove);
                });
        }
        else
            $img.mousedown(event);

        return false;
    }

    function fixAspectRatio(xFirst) {
        if (aspectRatio)
            if (xFirst) {
                x2 = max(left, min(left + imgWidth,
                    x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1)));

                y2 = round(max(top, min(top + imgHeight,
                    y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1))));
                x2 = round(x2);
            }
            else {
                y2 = max(top, min(top + imgHeight,
                    y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1)));
                x2 = round(max(left, min(left + imgWidth,
                    x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1))));
                y2 = round(y2);
            }
    }

    function doResize() {
        x1 = min(x1, left + imgWidth);
        y1 = min(y1, top + imgHeight);

        if (abs(x2 - x1) < minWidth) {
            x2 = x1 - minWidth * (x2 < x1 || -1);

            if (x2 < left)
                x1 = left + minWidth;
            else if (x2 > left + imgWidth)
                x1 = left + imgWidth - minWidth;
        }

        if (abs(y2 - y1) < minHeight) {
            y2 = y1 - minHeight * (y2 < y1 || -1);

            if (y2 < top)
                y1 = top + minHeight;
            else if (y2 > top + imgHeight)
                y1 = top + imgHeight - minHeight;
        }

        x2 = max(left, min(x2, left + imgWidth));
        y2 = max(top, min(y2, top + imgHeight));

        fixAspectRatio(abs(x2 - x1) < abs(y2 - y1) * aspectRatio);

        if (abs(x2 - x1) > maxWidth) {
            x2 = x1 - maxWidth * (x2 < x1 || -1);
            fixAspectRatio();
        }

        if (abs(y2 - y1) > maxHeight) {
            y2 = y1 - maxHeight * (y2 < y1 || -1);
            fixAspectRatio(true);
        }

        selection = { x1: selX(min(x1, x2)), x2: selX(max(x1, x2)),
            y1: selY(min(y1, y2)), y2: selY(max(y1, y2)),
            width: abs(x2 - x1), height: abs(y2 - y1) };

        update();

        options.onSelectChange(img, getSelection());
    }

    function selectingMouseMove(event) {
        x2 = /w|e|^$/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2);
        y2 = /n|s|^$/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2);

        doResize();

        return false;

    }

    function doMove(newX1, newY1) {
        x2 = (x1 = newX1) + selection.width;
        y2 = (y1 = newY1) + selection.height;

        $.extend(selection, { x1: selX(x1), y1: selY(y1), x2: selX(x2),
            y2: selY(y2) });

        update();

        options.onSelectChange(img, getSelection());
    }

    function movingMouseMove(event) {
        x1 = max(left, min(startX + evX(event), left + imgWidth - selection.width));
        y1 = max(top, min(startY + evY(event), top + imgHeight - selection.height));

        doMove(x1, y1);

        event.preventDefault();

        return false;
    }

    function startSelection() {
        $(document).unbind('mousemove', startSelection);
        adjust();

        x2 = x1;
        y2 = y1;

        doResize();

        resize = '';

        if (!$outer.is(':visible'))
            $box.add($outer).hide().fadeIn(options.fadeSpeed||0);

        shown = true;

        $(document).unbind('mouseup', cancelSelection)
            .mousemove(selectingMouseMove).one('mouseup', docMouseUp);
        $box.unbind('mousemove', areaMouseMove);

        options.onSelectStart(img, getSelection());
    }

    function cancelSelection() {
        $(document).unbind('mousemove', startSelection)
            .unbind('mouseup', cancelSelection);
        hide($box.add($outer));

        setSelection(selX(x1), selY(y1), selX(x1), selY(y1));

        if (!(this instanceof $.crop)) {
            options.onSelectChange(img, getSelection());
            options.onSelectEnd(img, getSelection());
        }
    }

    function imgMouseDown(event) {
        if (event.which != 1 || $outer.is(':animated')) return false;

        adjust();
        startX = x1 = evX(event);
        startY = y1 = evY(event);

        $(document).mousemove(startSelection).mouseup(cancelSelection);

        return false;
    }

    function windowResize() {
        doUpdate(false);
    }

    function imgLoad() {
        imgLoaded = true;

        setOptions(options = $.extend({
            classPrefix: 'crop',
            movable: true,
            parent: 'body',
            resizable: true,
            resizeMargin: 10,
            onInit: function () {},
            onSelectStart: function () {},
            onSelectChange: function () {},
            onSelectEnd: function () {}
        }, options));

        $box.add($outer).css({ visibility: '' });

        if (options.show) {
            shown = true;
            adjust();
            update();
            $box.add($outer).hide().fadeIn(options.fadeSpeed||0);
        }

        setTimeout(function () { options.onInit(img, getSelection()); }, 0);
    }

    var docKeyPress = function(event) {
        var k = options.keys, d, t, key = event.keyCode;

        d = !isNaN(k.alt) && (event.altKey || event.originalEvent.altKey) ? k.alt :
            !isNaN(k.ctrl) && event.ctrlKey ? k.ctrl :
            !isNaN(k.shift) && event.shiftKey ? k.shift :
            !isNaN(k.arrows) ? k.arrows : 10;

        if (k.arrows == 'resize' || (k.shift == 'resize' && event.shiftKey) ||
            (k.ctrl == 'resize' && event.ctrlKey) ||
            (k.alt == 'resize' && (event.altKey || event.originalEvent.altKey)))
        {
            switch (key) {
            case 37:
                d = -d;
            case 39:
                t = max(x1, x2);
                x1 = min(x1, x2);
                x2 = max(t + d, x1);
                fixAspectRatio();
                break;
            case 38:
                d = -d;
            case 40:
                t = max(y1, y2);
                y1 = min(y1, y2);
                y2 = max(t + d, y1);
                fixAspectRatio(true);
                break;
            default:
                return;
            }

            doResize();
        }
        else {
            x1 = min(x1, x2);
            y1 = min(y1, y2);

            switch (key) {
            case 37:
                doMove(max(x1 - d, left), y1);
                break;
            case 38:
                doMove(x1, max(y1 - d, top));
                break;
            case 39:
                doMove(x1 + min(d, imgWidth - selX(x2)), y1);
                break;
            case 40:
                doMove(x1, y1 + min(d, imgHeight - selY(y2)));
                break;
            default:
                return;
            }
        }

        return false;
    };

    function styleOptions($elem, props) {
        for (var option in props)
            if (options[option] !== undefined)
                $elem.css(props[option], options[option]);
    }

    function setOptions(newOptions) {
        if (newOptions.parent)
            ($parent = $(newOptions.parent)).append($box.add($outer));

        $.extend(options, newOptions);

        adjust();

        if (newOptions.handles != null) {
            $handles.remove();
            $handles = $([]);

            i = newOptions.handles ? newOptions.handles == 'corners' ? 4 : 8 : 0;

            while (i--)
                $handles = $handles.add(div());

            $handles.addClass(options.classPrefix + '-handle').css({
                position: 'absolute',
                fontSize: 0,
                zIndex: zIndex + 1 || 1
            });

            if (!parseInt($handles.css('width')) >= 0)
                $handles.width(5).height(5);

            if (o = options.borderWidth)
                $handles.css({ borderWidth: o, borderStyle: 'solid' });

            styleOptions($handles, { borderColor1: 'border-color',
                borderColor2: 'background-color',
                borderOpacity: 'opacity' });
        }

        scaleX = options.imageWidth / imgWidth || 1;
        scaleY = options.imageHeight / imgHeight || 1;

        if (newOptions.x1 != null) {
            setSelection(newOptions.x1, newOptions.y1, newOptions.x2,
                newOptions.y2);
            newOptions.show = !newOptions.hide;
        }

        if (newOptions.keys)
            options.keys = $.extend({ shift: 1, ctrl: 'resize' },
                newOptions.keys);

        $outer.addClass(options.classPrefix + '-outer');
        $area.addClass(options.classPrefix + '-selection');
        for (i = 0; i++ < 4;)
            $($border[i-1]).addClass(options.classPrefix + '-border' + i);

        styleOptions($area, { selectionColor: 'background-color',
            selectionOpacity: 'opacity' });
        styleOptions($border, { borderOpacity: 'opacity',
            borderWidth: 'border-width' });
        styleOptions($outer, { outerColor: 'background-color',
            outerOpacity: 'opacity' });
        if (o = options.borderColor1)
            $($border[0]).css({ borderStyle: 'solid', borderColor: o });
        if (o = options.borderColor2)
            $($border[1]).css({ borderStyle: 'dashed', borderColor: o });

        $box.append($area.add($border).add($areaOpera)).append($handles);

        if (msie) {
            if (o = ($outer.css('filter')||'').match(/opacity=(\d+)/))
                $outer.css('opacity', o[1]/100);
            if (o = ($border.css('filter')||'').match(/opacity=(\d+)/))
                $border.css('opacity', o[1]/100);
        }

        if (newOptions.hide)
            hide($box.add($outer));
        else if (newOptions.show && imgLoaded) {
            shown = true;
            $box.add($outer).fadeIn(options.fadeSpeed||0);
            doUpdate();
        }

        aspectRatio = (d = (options.aspectRatio || '').split(/:/))[0] / d[1];

        $img.add($outer).unbind('mousedown', imgMouseDown);

        if (options.disable || options.enable === false) {
            $box.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown);
            $(window).unbind('resize', windowResize);
        }
        else {
            if (options.enable || options.disable === false) {
                if (options.resizable || options.movable)
                    $box.mousemove(areaMouseMove).mousedown(areaMouseDown).bind("dblclick", options.ondblclick);

                $(window).resize(windowResize);
            }

            if (!options.persistent)
                $img.add($outer).mousedown(imgMouseDown);
        }

        options.enable = options.disable = undefined;
    }

    this.remove = function () {
        setOptions({ disable: true });
        $box.add($outer).remove();
    };

    this.getOptions = function () { return options; };

    this.setOptions = setOptions;

    this.getSelection = getSelection;

    this.setSelection = setSelection;

    this.cancelSelection = cancelSelection;

    this.update = doUpdate;

    var msie = (/msie ([\w.]+)/i.exec(ua)||[])[1],
        opera = /opera/i.test(ua),
        safari = /webkit/i.test(ua) && !/chrome/i.test(ua);

    $p = $img;

    while ($p.length) {
        zIndex = max(zIndex,
            !isNaN($p.css('z-index')) ? $p.css('z-index') : zIndex);
        if ($p.css('position') == 'fixed')
            position = 'fixed';

        $p = $p.parent(':not(body)');
    }

    zIndex = options.zIndex || zIndex;

    if (msie)
        $img.attr('unselectable', 'on');

    $.crop.keyPress = msie || safari ? 'keydown' : 'keypress';

    if (opera)

        $areaOpera = div().css({ width: '100%', height: '100%',
            position: 'absolute', zIndex: zIndex + 2 || 2 });

    $box.add($outer).css({ visibility: 'hidden', position: position,
        overflow: 'hidden', zIndex: zIndex || '0' });
    $box.css({ zIndex: zIndex + 2 || 2 });
    $area.add($border).css({ position: 'absolute', fontSize: 0 });

    img.complete || img.readyState == 'complete' || !$img.is('img') ?
        imgLoad() : $img.one('load', imgLoad);

    if (!imgLoaded && msie && msie >= 7)
        img.src = img.src;
};

$.fn.crop = function (options) {
    options = options || {};

    this.each(function () {
        if ($(this).data('crop')) {
            if (options.remove) {
                $(this).data('crop').remove();
                $(this).removeData('crop');
            }
            else
                $(this).data('crop').setOptions(options);
        }
        else if (!options.remove) {
            if (options.enable === undefined && options.disable === undefined)
                options.enable = true;

            $(this).data('crop', new $.crop(this, options));
        }
    });

    if (options.instance)
        return $(this).data('crop');

    return this;
};

})(window, jQuery);