PageSourceSearch

https://zalamo.com/js/vendors/icropper.js

js zalamo.com collected 2026-10-03 22:07:32 UTC 18,007 bytes, 438 lines download raw bytes

1(function () {
2    //Some common utility functions
3    var util = {
4        mixin      : function (dest, src) {
5            for (var p in src)dest[p] = src[p];
6        }, byId    : function (id) {
7            if (typeof id == 'string')return document.getElementById(id); else return id;
8        }, create  : function (tag, attrs) {
9            var node = document.createElement(tag);
10            this.mixin(node, attrs);
11            return node;
12        }, connect : function (node, evtType, context, callback) {
13            //TODO: use event listeners instead
14            var self = this;
15
16            function handler(evt) {
17                evt = self.fixEvent(evt);
18                context[callback](evt);
19            }
20
21            if (node.attachEvent)node.attachEvent('on' + evtType, handler); else node.addEventListener(evtType, handler, false);
22        }, style   : function (node, args) {
23            if (typeof args == 'string') {
24                var value = node.style[args];
25                if (!value) {
26                    s = window.getComputedStyle ? getComputedStyle(node) : node.currentStyle;
27                    value = s[args];
28                }
29                return value;
30            } else this.mixin(node.style, args);
31        }, each    : function (arr, callback) {
32            for (var i = 0; i < arr.length; i++)
33                callback(arr[i], i);
34        }, indexOf : function (arr, value) {
35            for (var i = 0; i < arr.length; i++)
36                if (value == arr[i])return i;
37            return -1;
38        }, addCss  : function (node, css) {
39            if (!node)return;
40            var cn = node.className || '', arr = cn.split(' '), i = util.indexOf(arr, css);
41            if (i < 0)arr.push(css);
42            node.className = arr.join(' ');
43        }, rmCss   : function (node, css) {
44            if (!node)return;
45            var cn = node.className || '', arr = cn.split(' '), i = util.indexOf(arr, css);
46            if (i >= 0)arr.splice(i, 1);
47            node.className = arr.join(' ');
48        }, fixEvent: function (evt) {
49            evt = evt || event;
50            if (!evt.target)evt.target = evt.srcElement;
51            if (!evt.keyCode)evt.keyCode = evt.which || evt.charCode;
52            if (!evt.pageX) {//only for IE
53                evt.pageX = evt.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
54                evt.pageY = evt.clientY + document.body.scrollTop + document.documentElement.scrollTop;
55            }
56            return evt;
57        }
58    };
59    window.ICropper = function (container, options) {
60        // summary:
61        //  Constructor of the Image Cropper, the container could be a dom node or id.
62        container = util.byId(container);
63        if (options.keepSquare) {
64            //keepSquare is deprecated. Should use ratio=1 instead.
65            options.ratio = 1;
66            delete options.keepSquare;
67        }
68        for (var p in options) {
69            if (options[p])this[p] = options[p];
70        }
71        this.domNode = container || util.create('div');
72        this._init();
73    }
74    ICropper.prototype = {
75
76        //The image url
77        image             : ''
78
79        //The minimal size of the cropping area
80        , minWidth        : 20, minHeight: 20
81
82        //The default gap between crop region border and container border
83        , gap             : 50
84
85        //the initial crop region width and height
86        , initialSize     : 0
87
88        //whether to keep crop region as a square
89        //DEPRECATED: use ratio=1 instead.
90        , keepSquare      : false
91
92        //whether to keep the ratio of width:height, 0 means not set
93        , ratio           : 0
94
95        //array: the nodes to show previews of cropped image
96        , preview         : null, domNode: null, cropNode: null, imageNode: null
97
98        //Public APIs
99        //------------------------------------------------------------
100        , setImage        : function (url) {
101            // summary:
102            //  Set the image to be cropped. The container size will fit the image.
103            var img = new Image();
104            img.src = url;
105            this.image = url;
106            if (!this.imageNode) {
107                this.imageNode = util.create('img');
108                this.domNode.appendChild(this.imageNode);
109                var self = this;
110                //TODO: onerror?
111                this.imageNode.onload = function () {
112                    self._setSize(this.offsetWidth, this.offsetHeight);
113                }
114            }
115            this.imageNode.src = url;
116        }, bindPreview    : function (node) {
117            // summary:
118            //  Bind a node as the preview area. e.g: a real size avatar
119            node = util.byId(node);
120            util.style(node, {overflow: 'hidden'});
121            var width = parseInt(util.style(node, 'width'))
122                , height = parseInt(util.style(node, 'height'));
123            var previewImage = util.create('img', {src: this.image});
124            node.appendChild(previewImage);
125            var _oldOnChange = this.onChange;
126            var self = this;
127            this.onChange = function (info) {
128                _oldOnChange.call(this, info);
129                var r = info.w / info.h
130                    , w2 = height * r
131                    , h2 = width / r;
132                if (w2 >= width)w2 = width;
133                if (h2 >= height)h2 = height;
134                util.style(node, {width: w2 + 'px', height: h2 + 'px'});
135                var rateX = w2 / info.w
136                    , rateY = h2 / info.h;
137                util.style(previewImage, {
138                    width: info.cw * rateX + 'px', height: info.ch * rateY + 'px', marginLeft: -info.l * rateX + 'px', marginTop: -info.t * rateY + 'px'
139                });
140            }
141        }, getInfo        : function () {
142            // summary:
143            //  Get the cropping infomation. Such as being used by server side for real cropping.
144            return {
145                w   : this.cropNode.offsetWidth - 2    //2 is hard code border width
146                , h : this.cropNode.offsetHeight - 2, l: parseInt(util.style(this.cropNode, 'left')), t: parseInt(util.style(this.cropNode, 'top')), cw: this.domNode.offsetWidth //container width
147                , ch: this.domNode.offsetHeight //container height
148            };
149        }, onChange       : function () {
150            //Event:
151            //    When the cropping size is changed.
152        }, onComplete     : function () {
153            //Event:
154            //    When mouseup.
155        }, destroy        : function () {
156            //TODO: destroy self to release memory
157        }
158
159        //Private APIs
160        //------------------------------------------------------------
161        , _init           : function () {
162            util.addCss(this.domNode, 'icropper');
163            this._buildRendering();
164            this._updateUI();
165            util.connect(this.cropNode, 'mousedown', this, '_onMouseDown');
166            util.connect(document, 'mouseup', this, '_onMouseUp');
167            util.connect(document, 'mousemove', this, '_onMouseMove');
168            this.image && this.setImage(this.image);
169            if (this.preview) {
170                var self = this;
171                util.each(this.preview, function (node) {
172                    self.bindPreview(node);
173                });
174            }
175        }, _buildRendering: function () {
176            this._archors = {};
177            this._blockNodes = {};
178            this.cropNode = util.create('div', {className: 'crop-node no-select'});
179            this.domNode.appendChild(this.cropNode);
180            //Create archors
181            var arr = ['lt', 't', 'rt', 'r', 'rb', 'b', 'lb', 'l'];
182            for (var i = 0; i < 8; i++) {
183                var n = util.create('div', {className: 'archor archor-' + arr[i]});
184                this.cropNode.appendChild(n);
185                this._archors[arr[i]] = n;
186            }
187            //Create blocks for showing dark areas
188            arr = ['l', 't', 'r', 'b'];
189            for (var i = 0; i < 4; i++) {
190                var n = util.create('div', {className: 'block block-' + arr[i]});
191                this.domNode.appendChild(n);
192                this._blockNodes[arr[i]] = n;
193            }
194        }, _setSize       : function (w, h) {
195            this.domNode.style.width = w + 'px';
196            this.domNode.style.height = h + 'px';
197            var w2, h2;
198            if (this.initialSize) {
199//                var m = Math.min(w, h, this.initialSize);
200//                w2 = h2 = m - 2 + 'px';
201                if (w > h) {
202                    w2 = this.initialSize;
203                    if (this.ratio > 1) {
204                        h2 = w2 / this.ratio;
205                    } else {
206                        h2 = w2 * this.ratio;
207                    }
208                } else {
209                    h2 = this.initialSize;
210                    if (this.ratio > 1) {
211                        w2 = h2 / this.ratio;
212                    } else {
213                        w2 = h2 * this.ratio;
214                    }
215                }
216                w2 += 'px';
217                h2 += 'px';
218            } else {
219                w2 = w - this.gap * 2 - 2;
220                h2 = h - this.gap * 2 - 2;
221                if (this.ratio) {
222                    var _w2 = h2 * this.ratio, _h2 = w2 / this.ratio;
223                    if (w2 > _w2)w2 = _w2;
224                    if (h2 > _h2)h2 = _h2;
225                }
226                w2 += 'px';
227                h2 += 'px';
228            }
229            console.log(w2, h2);
230            var s = this.cropNode.style;
231            if (typeof this.defCrop != 'undefined' && this.defCrop != 0) {
232                config = this.defCrop.split(",");
233                s.width = config[2] * w / 100 + "px";
234                s.height = config[3] * h / 100 + "px";
235                s.left = config[0] * w / 100 + "px";
236                s.top = config[1] * h / 100 + "px";
237                console.log(s.height);
238            } else {
239                s.width = w2;
240                s.height = h2;
241                var l = (w - this.cropNode.offsetWidth) / 2
242                    , t = (h - this.cropNode.offsetHeight) / 2;
243                if (l < 0) l = 0;
244                if (t < 0) t = 0;
245                s.left = l + 'px';
246                s.top = t + 'px';
247            }
248            this._posArchors();
249            this._posBlocks();
250            this.onChange(this.getInfo());
251        }, _updateUI      : function () {
252            this._posArchors();
253            this._posBlocks();
254        }, _posArchors    : function () {
255            var a = this._archors, w = this.cropNode.offsetWidth, h = this.cropNode.offsetHeight;
256            w = w / 2 - 4 + 'px';
257            h = h / 2 - 4 + 'px';
258            a.t.style.left = a.b.style.left = w;
259            a.l.style.top = a.r.style.top = h;
260        }, _posBlocks     : function () {
261            var p = this.startedPos, b = this._blockNodes;
262            var l = parseInt(util.style(this.cropNode, 'left'));
263            var t = parseInt(util.style(this.cropNode, 'top'));
264            var w = this.cropNode.offsetWidth;
265            var ww = this.domNode.offsetWidth;
266            var h = this.cropNode.offsetHeight;
267            var hh = this.domNode.offsetHeight;
268            b = this._blockNodes;
269            b.t.style.height = b.l.style.top = b.r.style.top = t + 'px';
270            b.l.style.height = b.r.style.height = h + 'px';
271            b.l.style.width = l + 'px';
272            w = ww - w - l;
273            h = hh - h - t;
274            //fix IE
275            if (w < 0)w = 0;
276            if (h < 0)h = 0;
277            b.r.style.width = w + 'px';
278            b.b.style.height = h + 'px';
279        }, _onMouseDown   : function (e) {
280            var n = this.cropNode, s = n.style;
281            this.dragging = (e.target == n) ? 'move' : e.target.className;
282            if (this.dragging != 'move') {
283                var arr = this.dragging.split(' ');
284                this.dragging = arr.pop().split('-')[1];
285            }
286            this.startedPos = {
287                x  : e.pageX, y: e.pageY, h: n.offsetHeight - 2 //2 is border width
288                , w: n.offsetWidth - 2, l: parseInt(util.style(n, 'left')), t: parseInt(util.style(n, 'top'))
289            }
290            var c = util.style(e.target, 'cursor');
291            util.style(document.body, {
292                cursor: c
293            });
294            util.style(this.cropNode, {
295                cursor: c
296            });
297            util.addCss(document.body, 'no-select');
298            util.addCss(document.body, 'unselectable');//for IE
299        }, _onMouseUp     : function (e) {
300            this.dragging = false;
301            util.style(document.body, {
302                cursor: 'default'
303            });
304            util.style(this.cropNode, {
305                cursor: 'move'
306            });
307            util.rmCss(document.body, 'no-select');
308            util.rmCss(document.body, 'unselectable');
309            this.onComplete && this.onComplete(this.getInfo());
310        }, _onMouseMove   : function (e) {
311            if (!this.dragging) return;
312            if (this.dragging == 'move') this._doMove(e); else this._doResize(e);
313            this._updateUI();
314            this.onChange && this.onChange(this.getInfo());
315        }, _doMove        : function (e) {
316            var s = this.cropNode.style, p0 = this.startedPos;
317            var l = p0.l + e.pageX - p0.x;
318            var t = p0.t + e.pageY - p0.y;
319            if (l < 0) l = 0;
320            if (t < 0) t = 0;
321            var maxL = this.domNode.offsetWidth - this.cropNode.offsetWidth;
322            var maxT = this.domNode.offsetHeight - this.cropNode.offsetHeight;
323            if (l > maxL) l = maxL;
324            if (t > maxT) t = maxT;
325            s.left = l + 'px';
326            s.top = t + 'px'
327        }, _doResize      : function (e) {
328            var m = this.dragging
329                , s = this.cropNode.style
330                , cw = this.cropNode.offsetWidth
331                , ch = this.cropNode.offsetHeight
332                , p0 = this.startedPos;
333            //delta x and delta y
334            var dx = e.pageX - p0.x, dy = e.pageY - p0.y;
335            var ratio = this.ratio;
336            if (!ratio && e.shiftKey)ratio = 1;//Shiftkey is only available when there's no ratio set.
337            if (ratio) {
338                if (m == 'l') {
339                    dy = dx / ratio;
340                    if (p0.l + dx < 0) {
341                        dx = -p0.l;
342                        dy = dx / ratio;
343                    }
344                    if (p0.t + dy < 0) {
345                        dy = -p0.t;
346                        dx = dy * ratio;
347                    }
348                    m = 'lt';
349                } else if (m == 'r') {
350                    dy = dx / ratio;
351                    m = 'rb';
352                } else if (m == 'b') {
353                    dx = dy * ratio;
354                    m = 'rb';
355                } else if (m == 'lt') {
356                    dx = Math.abs(dx) > Math.abs(dy) ? dx : dy;
357                    dy = dx / ratio;
358                    if (p0.l + dx < 0) {
359                        dx = -p0.l;
360                        dy = dx / ratio;
361                    }
362                    if (p0.t + dy < 0) {
363                        dy = -p0.t;
364                        dx = dy * ratio;
365                    }
366                } else if (m == 'lb') {
367                    dx = Math.abs(dx) > Math.abs(dy) ? dx : -dy;
368                    dy = -dx / ratio;
369                    if (p0.l + dx < 0) {
370                        dx = -p0.l;
371                        dy = p0.l;
372                    }
373                } else if (m == 'rt' || m == 't') {
374                    dx = -dy * ratio;
375                    m = 'rt';
376                    if (p0.t + dy < 0) {
377                        dy = -p0.t;
378                        dx = -dy;
379                    }
380                }
381            }
382            if (/l/.test(m)) {
383                dx = Math.min(dx, p0.w - this.minWidth);
384                if (p0.l + dx >= 0) {
385                    s.left = p0.l + dx + 'px';
386                    s.width = p0.w - dx + 'px';
387                } else {
388                    s.left = 0;
389                    s.width = p0.l + p0.w + 'px';
390                }
391            }
392            if (/t/.test(m)) {
393                dy = Math.min(dy, p0.h - this.minHeight);
394                if (p0.t + dy >= 0) {
395                    s.top = p0.t + dy + 'px';
396                    s.height = p0.h - dy + 'px';
397                } else {
398                    s.top = 0;
399                    s.height = p0.t + p0.h + 'px';
400                }
401            }
402            if (/r/.test(m)) {
403                dx = Math.max(dx, this.minWidth - p0.w);
404                if (p0.l + p0.w + dx <= this.domNode.offsetWidth) {
405                    s.width = p0.w + dx + 'px';
406                } else {
407                    s.width = this.domNode.offsetWidth - p0.l - 2 + 'px';
408                }
409            }
410            if (/b/.test(m)) {
411                dy = Math.max(dy, this.minHeight - p0.h);
412                if (p0.t + p0.h + dy <= this.domNode.offsetHeight) {
413                    s.height = p0.h + dy + 'px';
414                } else {
415                    s.height = this.domNode.offsetHeight - p0.t - 2 + 'px';
416                }
417            }
418            if (ratio) {
419                var w = parseInt(s.width), h = parseInt(s.height);
420                var w2 = h * ratio, h2 = w / ratio;
421                if (w2 < w) {
422                    if (/l/.test(m)) {
423                        s.left = parseInt(s.left) + w - w2 + 'px';
424                    }
425                    w = w2;
426                }
427                if (h2 < h) {
428                    if (/t/.test(m)) {
429                        s.top = parseInt(s.top) + h - h2 + 'px';
430                    }
431                    h = h2;
432                }
433                s.width = w + 'px';
434                s.height = h + 'px';
435            }
436        }
437    }
438})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.