PageSourceSearch

https://newrunners.ru/local/templates/stsport/js/libs/cropimg.jquery.js

js newrunners.ru collected 2026-10-02 03:07:19 UTC 43,081 bytes, 1,298 lines download raw bytes

1/**
2 * Available for use under the MIT License (http://en.wikipedia.org/wiki/MIT_License)
3 * 
4 * Copyright (c) 2014 - 2015 by Adam Banaszkiewicz
5 * 
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 * 
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 * 
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 * 
24 * @version 0.3.1
25 * @date    2015.12.14
26 * @author  Adam Banaszkiewicz
27 */
28(function($){
29  /**
30   * Zwraca obiekt z szerokością strony.
31   * 
32   * @result object
33   */
34  document.getWindowWidth = function() {
35    if( typeof( window.innerWidth ) == 'number' )
36    {
37      return window.innerWidth;
38    }
39    else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight))
40    {
41      return document.documentElement.clientWidth;
42    }
43    else if(document.body && (document.body.clientWidth || document.body.clientHeight))
44    {
45      return document.body.clientWidth;
46    }
47    
48    return 1280;
49  };
50
51  $.fn.cropimg = function(options) {
52    options = $.extend({
53      /**
54       * Maksymalna szerokość kontenera z narzędziami. Null oznacza 100%.
55       * 
56       * @var integer
57       * @var null
58       */
59      maxContainerWidth: null,
60      
61      /**
62       * Szerokość obrazka po kadrowaniu.
63       * 
64       * @var integer
65       */
66      resultWidth: 100,
67      
68      /**
69       * Wysokość obrazka po kadrowaniu.
70       * 
71       * @var integer
72       */
73      resultHeight: 100,
74      
75      /**
76       * Przedrostek ID elementów INPUT do których wrzucane będą dane na temat
77       * pozycji obrazka oraz zaznaczonej jego części.
78       * 
79       * @var string
80       */
81      inputPrefix: '',
82      
83      /**
84       * Opóźnienie w czasie, pomiędzy jednorazowym zoomem, a zoomem 
85       * wielokrotnym. Wartośc podawana w milisekundach.
86       * 
87       * @var integer
88       */
89      zoomDelay: 400,
90      
91      /**
92       * krotność przybliżenia dla kółka myszki.
93       * 
94       * @var integer
95       */
96      mouseWheelZoomTimes: 10,
97
98      /**
99       * O jaką część całości ma odbywać się zoomowanie.
100       * 
101       * @type integer
102       */
103      zoomStep: 25,
104      
105      /**
106       * Czy pokazywać tooltipy na buttonach?
107       * 
108       * @var boolean
109       */
110      showBtnTips: true,
111
112      /**
113       * Display zooming buttons?
114       * 
115       * @var boolean
116       */
117      displayZoomingButtons: true,
118
119      /**
120       * Display fixing positions buttons?
121       * 
122       * @var boolean
123       */
124      displayFixingPositionsButtons: true,
125
126      /**
127       * Display fixing size buttons?
128       * 
129       * @var boolean
130       */
131      displayFixingSizeButtons: true,
132      
133      /**
134       * Czas animacji pokazywania i ukrywania tooltipów.
135       * 
136       * @var integer
137       */
138      btnTipsFadeTime: 100,
139      
140      /**
141       * Treść tooltipa przycisku: przybliż.
142       * 
143       * @var string
144       */
145      textBtnTipZoomIn: 'Zoom in',
146      
147      /**
148       * Treść tooltipa przycisku: oddal.
149       * 
150       * @var string
151       */
152      textBtnTipZoomOut: 'Zoom out',
153      
154      /**
155       * Treść tooltipa przycisku: dopasuj do szerokości.
156       * 
157       * @var string
158       */
159      textBtnTipRTW: 'Resize to container width',
160      
161      /**
162       * Treść tooltipa przycisku: dopasuj do wydokości.
163       * 
164       * @var string
165       */
166      textBtnTipRTH: 'Resize to container height',
167      
168      /**
169       * Treść tooltipa przycisku: przenieś w lewy górny róg.
170       * 
171       * @var string
172       */
173      textBtnTipFPTL: 'Move image to Top Left Corner',
174      
175      /**
176       * Treść tooltipa przycisku: przenieś w górę na środek.
177       * 
178       * @var string
179       */
180      textBtnTipFPTC: 'Move image to Top Center',
181      
182      /**
183       * Treść tooltipa przycisku: przenieś w prawy górny róg.
184       * 
185       * @var string
186       */
187      textBtnTipFPTR: 'Move image to Top Right Corner',
188      
189      /**
190       * Treść tooltipa przycisku: przenieś w lewo na środek.
191       * 
192       * @var string
193       */
194      textBtnTipFPCL: 'Move image to Center Left',
195      
196      /**
197       * Treść tooltipa przycisku: przenieś na sam środek kontenera.
198       * 
199       * @var string
200       */
201      textBtnTipFPCC: 'Move image to Center of container',
202      
203      /**
204       * Treść tooltipa przycisku: przenieś w prawo na środek.
205       * 
206       * @var string
207       */
208      textBtnTipFPCR: 'Move image to Center Right',
209      
210      /**
211       * Treść tooltipa przycisku: przenieś w dolny lewy róg.
212       * 
213       * @var string
214       */
215      textBtnTipFPBL: 'Move image to Bottom Left Corner',
216      
217      /**
218       * Treść tooltipa przycisku: przenieś w dolny róg na środek.
219       * 
220       * @var string
221       */
222      textBtnTipFPBC: 'Move image to Bottom Center',
223      
224      /**
225       * Treść tooltipa przycisku: przenieś w dolny prawy róg.
226       * 
227       * @var string
228       */
229      textBtnTipFPBR: 'Move image to Bottom Right Corner',
230      
231      /**
232       * Wywoływana podczas inicjacji pluginu.
233       * 
234       * @var function
235       */
236      onInit: function() {},
237      
238      /**
239       * Wywoływana podczas zmiany zoomu, lub pozycji obrazka.
240       * 
241       * @var function
242       */
243      onChange: function(w, h, x, y, img) {}
244    }, options);
245
246    var CI_Main = function(image, options) {
247      this.options = options;
248
249      /**
250       * Przechowuje informacje, czy obrazek został już zmieniony, czy jeszcze
251       * nic user nie robił.
252       * 
253       * @var boolean
254       */
255      this.changed = false;
256
257      /**
258       * Obiekt jQuery z obrazkiem.
259       * 
260       * @var jQuery
261       */
262      this.image = image;
263      
264      /**
265       * Obiekt z danymi na temat obrazka.
266       * 
267       * @var jQuery
268       */
269      this.imageData = {};
270      
271      /**
272       * Obiekt jQuery z głównym kontenerem w którym znajduje się cały plugin.
273       * 
274       * @var jQuery
275       */
276      this.container = null;
277      
278      /**
279       * Obiekt jQuery z kontenerem obrazka.
280       * 
281       * @var jQuery
282       */
283      this.imageContainer = null;
284      
285      /**
286       * Obiekt z danymi na temat kontenera obrazka.
287       * 
288       * @var jQuery
289       */
290      this.imgCntData = {width: -1};
291      
292      /**
293       * Przechowuje czas w mikrosekundach wywołania pluginu. Potrzebne do
294       * nadawania ID elementom.
295       * 
296       * @var integer
297       */
298      this.mt = (new Date()).getTime() + Math.floor((Math.random() * 1000) + 1);
299      
300      this.vars = {
301        x: 0,
302        y: 0,
303        w: 0,
304        h: 0
305      };
306
307      this.ToolDrawer = null;
308      this.BtnTips = null;
309      this.Movable = null;
310      this.Zooming = null;
311      this.CroppingResult = null;
312      this.Reset = null;
313    };
314
315    /**
316     * Obiekt z metodami do rysowania narzędzi pluginu.
317     */
318    var CI_TOOLDRAWER = function(main) {
319      this.main = main;
320
321      /**
322       * Domyślna metoda obiektu.
323       */
324      this.draw = function() {
325        this.drawContainers();
326        
327        if (this.main.options.displayZoomingButtons) {
328          this.drawZoomingButtons();  
329        }
330        
331        if (this.main.options.displayFixingPositionsButtons) {
332          this.drawFixingPositionButtons();  
333        }
334
335        if (this.main.options.displayFixingSizeButtons) {
336          this.drawFixingSizeButtons();  
337        }
338
339        var self = this;
340        
341        $(window).resize(function(e) {
342          self.onResize(self, e);
343        });
344      };
345
346      /**
347       * Rysuje kontenery (DIV) i te ważniejsze przypisuje do zmiennych.
348       * 
349       * @return void
350       */
351      this.drawContainers = function() {
352        // Tworzymy główny kontener na aplikację
353        this.main.image.wrap($('<div />', {'class':'ci-main','id':'ci-main-'+this.main.mt,'style':'max-width:'+this.main.options.resultWidth+'px'}));
354        this.main.container = $('.ci-main#ci-main-'+this.main.mt);
355        
356        // Tworzymy kontener bezpośrednio na zdjęcie
357        this.main.image.wrap($('<div />', {'class':'ci-image-wrapper','id':'ci-image-wrapper-'+this.main.mt,'style':'max-width:'+this.main.options.resultWidth+'px;height:'+this.main.options.resultHeight+'px'}));
358        this.main.imageContainer = $('.ci-image-wrapper#ci-image-wrapper-'+this.main.mt);
359        
360        // Kontener na "przybliż - oddal"
361        this.main.container.append($('<div />', {'class':'ci-tool ci-zooming'}));
362      };
363
364      /**
365       * Tworzy buttony "przybliż - oddal".
366       * 
367       * @return void
368       */ 
369      this.drawZoomingButtons = function() {
370        this.main.container.find('.ci-tool.ci-zooming')
371          .append($('<span />', {'title':this.main.options.textBtnTipZoomIn,'href':'#','class':'ci-button ci-tool-zoomin'}).click(function(){return false;}))
372          .append($('<span />', {'title':this.main.options.textBtnTipZoomOut,'href':'#','class':'ci-button ci-tool-zoomout'}).click(function(){return false;}));
373      },
374
375      /**
376       * Rysuje buttony przesuwania zdjęcia do krawędzi i rogów kontenera.
377       * 
378       * @return void
379       */
380      this.drawFixingPositionButtons = function() {
381        this.main.imageContainer
382          .append($('<span />', {'title':this.main.options.textBtnTipFPTL,'href':'#','class':'ci-fixing-position ci-fptl'}).click(function(){return false;}))
383          .append($('<span />', {'title':this.main.options.textBtnTipFPTC,'href':'#','class':'ci-fixing-position ci-fptc'}).click(function(){return false;}))
384          .append($('<span />', {'title':this.main.options.textBtnTipFPTR,'href':'#','class':'ci-fixing-position ci-fptr'}).click(function(){return false;}))
385          .append($('<span />', {'title':this.main.options.textBtnTipFPCL,'href':'#','class':'ci-fixing-position ci-fpcl'}).click(function(){return false;}))
386          .append($('<span />', {'title':this.main.options.textBtnTipFPCC,'href':'#','class':'ci-fixing-position ci-fpcc'}).click(function(){return false;}))
387          .append($('<span />', {'title':this.main.options.textBtnTipFPCR,'href':'#','class':'ci-fixing-position ci-fpcr'}).click(function(){return false;}))
388          .append($('<span />', {'title':this.main.options.textBtnTipFPBL,'href':'#','class':'ci-fixing-position ci-fpbl'}).click(function(){return false;}))
389          .append($('<span />', {'title':this.main.options.textBtnTipFPBC,'href':'#','class':'ci-fixing-position ci-fpbc'}).click(function(){return false;}))
390          .append($('<span />', {'title':this.main.options.textBtnTipFPBR,'href':'#','class':'ci-fixing-position ci-fpbr'}).click(function(){return false;}));
391      },
392
393      /**
394       * Rysuje buttony zmiany rozmiarów zdjęcia względem kontenera.
395       * 
396       * @return void
397       */
398      this.drawFixingSizeButtons = function() {
399        this.main.container.find('.ci-tool.ci-zooming')
400          .append($('<span />', {'title':this.main.options.textBtnTipRTW,'href':'#','class':'ci-fixing-size ci-fsw'}).click(function(){return false;}))
401          .append($('<span />', {'title':this.main.options.textBtnTipRTH,'href':'#','class':'ci-fixing-size ci-fsh'}).click(function(){return false;}));
402      },
403
404      /**
405       * Rysuje buttony zmiany rozmiarów zdjęcia względem kontenera.
406       * 
407       * @return void
408       */
409      this.drawFixingSizeButtons = function() {
410        this.main.container.find('.ci-tool.ci-zooming')
411          .append($('<span />', {'title':this.main.options.textBtnTipRTW,'href':'#','class':'ci-fixing-size ci-fsw'}).click(function(){return false;}))
412          .append($('<span />', {'title':this.main.options.textBtnTipRTH,'href':'#','class':'ci-fixing-size ci-fsh'}).click(function(){return false;}));
413      },
414
415      this.onResize = function(self, e) {
416        /**
417         * Jeśli szerokość kontenera zdjęcia jest mniejsza niż szerokość
418         * domyślna zaznaczenia to zmniejszamy wysokość proporcjonalnie
419         * do zmniejszonej szerokości by zachować proporcje.
420         */
421        if(self.main.imageContainer.width() < self.main.options.resultWidth)
422        {
423          self.main.imgCntData.proportionsToOriginal  = self.main.imageContainer.width() / self.main.options.resultWidth;
424          self.main.imageContainer.css('height', (self.main.options.resultHeight * self.main.imgCntData.proportionsToOriginal)+'px');
425          
426          // Uaktualniamy dane na temat kontenera obrazka
427          self.main.imgCntData.width   = self.main.imageContainer.width();
428          self.main.imgCntData.height  = self.main.imageContainer.height();
429          
430          // Uaktualniamy dane na temat zaznaczonego obszaru zdjęcia
431          self.main.CroppingResult.cropPercent = self.main.imgCntData.proportionsToOriginal;
432        }
433        /**
434         * W każdym innym wypadku ustawiamy wysokość kontenera na domyślną
435         * wysokość kadrowanego obrazu oraz ustawiamy proporcje kontenera
436         * na 1 - czyli nieprzeskalowane (oryginał).
437         */
438        else
439        {
440          self.main.imageContainer.css('height', self.main.options.resultHeight);
441          
442          // Uaktualniamy dane na temat kontenera obrazka
443          self.main.imgCntData.width   = self.main.imageContainer.width();
444          self.main.imgCntData.height  = self.main.options.resultHeight;
445          self.main.imgCntData.proportionsToOriginal = 1;
446        }
447        
448        // Odświeżamy wartości
449        if(self.main.changed)
450        {
451          self.main.Zooming.eventMouseUp();
452        }
453      }
454    };
455
456
457    /**
458     * Obiekt z metodami do zarządzania tooltipami przycisków.
459     */
460    var CI_BTNSTIPS = function(main) {
461      this.main = main;
462
463      /**
464       * Przechowuje ID tooltipu, który aktualnie jest dodawany do BODY.
465       * 
466       * @var string
467       */
468      this.currentTipId = '';
469
470      /**
471       * Przechowuje ID tooltipu, który aktualnie jest już BODY, który można usunąć.
472       * 
473       * @var string
474       */
475      this.lastTipId = '';
476
477      /**
478       * Inicjacja tooltipów
479       * 
480       * @return void
481       */
482      this.init = function() {
483        var self = this;
484
485        // Tylko, jeśli tak wybrano.
486        if(this.main.options.showBtnTips == false)
487        {
488          return false;
489        }
490        
491        /**
492         * Szukamy wszystkie elementy, które posiadają atrybut title. Treść
493         * z TITLE wrzucamy do DATA-TXT i usuwamy TITLE a następnie
494         * podpinamy zdarzenia na hover.
495         */
496        $('[title]', this.main.container).add($('[title]', this.main.imageContainer)).each(function() {
497          $(this).attr('data-txt', $(this).attr('title'))
498            .removeAttr('title')
499            .hover(function() {
500              self.main.BtnTips.show(self, this);
501            }, function() {
502              self.main.BtnTips.hide(self, this);
503            });
504        });
505      },
506
507      /**
508       * Pokazuje tooltip. Podpinane na zdarzenie elementu mouseenter.
509       * 
510       * @return void
511       */
512      this.show = function(self, elm) {
513        // Tworzymy nowe ID tooltipu
514        self.currentTipId = 'ci-tip-'+(new Date()).getTime();
515        
516        // Dodajemy Tooltip do body
517        $('body').append($('<span class="ci-tip" id="'+self.currentTipId+'">'+$(elm).attr('data-txt')+'</span>').fadeTo(0, 0).fadeTo(self.main.options.btnTipsFadeTime, 1));
518        
519        // Pobieramy offset elementu, do którego należy tooltip
520        var elmOffset = $(elm).offset(),
521            // Pobieramy przed chwilą dodany do BODY tooltip
522            tip       = $('body').find('.ci-tip#'+self.currentTipId);
523        
524        // Obliczamy pozycję nowego toltipa
525        tip.css({
526          'left': elmOffset.left - (tip.outerWidth() / 2) + ($(elm).outerWidth() / 2),
527          'top' : elmOffset.top - (tip.outerHeight()) - (($(elm).outerHeight() - 5) / 2)
528        });
529        
530        // Przepisujemy ID tooltipa z Aktualy na Ostatni
531        self.lastTipId = self.currentTipId;
532      },
533
534      /**
535       * Ukrywa a następnie usuwa tooltip. Dodatkowe zdarzenie pozwala
536       * ukryć element od razu, po najechaniu na niego, a nie czekać aż ukryje
537       * się on animacją fade. Podpinane na zdarzenie elementu mouseout.
538       * 
539       * @return void
540       */
541      this.hide = function() {
542        $('body').find('.ci-tip#'+this.lastTipId).hover(function() {$(this).remove();}, $.noop).fadeTo(this.main.options.btnTipsFadeTime, 0, function() {
543          $(this).remove();
544        });
545      }
546    };
547
548
549    var CI_MOVABLE = function(main) {
550      this.main = main;
551
552      /**
553       * Przechowuje obiekt z wartościami pozycji myszki na której był kursor,
554       * podczas rozpoczęcia przesuwania obrazka.
555       *  
556       * @var object
557       */
558      this.mousePositionStart = {
559        x:0,
560        y:0
561      };
562
563      this.imagePosition = {
564        'left':0,
565        'top':0
566      };
567
568      /**
569       * Przechowuje informacje dla metod Eventów o tym,
570       * czy przycisk myszki jest wciśnięty - mousedown.
571       */
572      this.mouseDowned = false;
573
574      /**
575       * Metoda inicjująca.
576       */
577      this.init = function() {
578        var self = this;
579
580        /**
581         * Po kliknięciu na kontener obrazka rozpoczynamy przesuwanie zdjęcia.
582         */
583        this.main.imageContainer.bind('mousedown', function(e) {
584          self.eventMouseDown(self, e);
585        });
586
587        this.main.imageContainer.bind('touchstart', function(e) {
588          self.eventMouseDown(self, e);
589        });
590
591        $('body')
592          /**
593           * Podczas jeżdżenia po BODY przesuwamy obrazek względem pozycji myszki.
594           */
595          .bind('mousemove', function(e) {
596            self.eventMouseMove(self, e);
597          })
598          .bind('touchmove', function(e) {
599            self.eventMouseMove(self, e);
600          })
601          /**
602           * Po puszczeniu przycisku myszki kończymy przesuwanie.
603           */
604          .bind('mouseup', function(e) {
605            self.eventMouseUp(self, e);
606          })
607          .bind('touchend', function(e) {
608            self.eventMouseUp(self, e);
609          });
610        
611        /**
612         * Dzięki temu, po kliknięciu na obrazek i próbie "przeniesienia go"
613         * nie wykona się domyślna reakcja przeglądarki.
614         */
615        var _sp = function(e) {
616          e.preventDefault();
617        };
618        
619        this.main.imageContainer.find('img')
620          .bind('mousemove', _sp)
621          .bind('mouseup', _sp)
622          .bind('mousedown', _sp);
623        
624        this.bindFixingButtons();
625      },
626
627      /**
628       * Metoda eventu onmousedown. Zapisuje pozycję myszki oraz obrazka
629       * by można było obliczyć nową pozycję podczas przenosin. Podpina
630       * zdarzenia przenoszenia dla BODY.
631       * 
632       * @event onmousedown
633       * @param object e
634       * @return void
635       */
636      this.eventMouseDown = function(self, e) {
637        if(self.mouseDowned === false || e.type == 'touchstart')
638        {
639          // Zapisujemy pozycję myszki
640
641          if (e.type == 'touchstart')
642          {
643            self.mousePositionStart.x = e.originalEvent.touches[0].pageX;
644            self.mousePositionStart.y = e.originalEvent.touches[0].pageY;
645          }
646          else
647          {
648            self.mousePositionStart.x = e.pageX;
649            self.mousePositionStart.y = e.pageY;
650          }
651          
652          // Potrzebujemy te dane o obrazku by móc dobrze go przesunąć z tych wartości początkowych
653          self.imagePosition.left = parseInt(self.main.image.css('left').replace('px', ''));
654          self.imagePosition.top  = parseInt(self.main.image.css('top').replace('px', ''));
655          
656          // Ustawiamy, że już było zmieniane
657          self.main.changed = true;
658
659          self.mouseDowned = true;
660        }
661      },
662
663      /**
664       * Metoda eventu onmouseup. Zdejmuje zdarzenia przenosin z BODY.
665       * 
666       * @event onmouseup
667       * @return void
668       */
669      this.eventMouseUp = function(self, e) {
670        if(self.mouseDowned === true || e.type == 'touchend')
671        {
672          self.mouseDowned = false;
673
674          /**
675           * Uaktualniamy pozycję obrazka. Robimy to tutaj a nie w funkcji
676           * przesuwania ponieważ tam zabierałaby niepotrzebnie moc obliczeniową
677           * przeglądarki wrzucając co jeden piksel dane do inputów a tak
678           * oblicza pozycję tylko raz i tylko raz wrzuca ją do inputów.
679           */
680          self.main.CroppingResult.update(parseInt(self.main.image.css('left').replace('px', '')), parseInt(self.main.image.css('top').replace('px', '')));
681
682          /**
683           * Może zdarzyć się tak, że użytkownik tylko kliknie w przeniesienie
684           * obrazka do którejś z krawędzi. W ten sposób (jeśli nie ma) dodadzą
685           * się pozycje X i Y obrazka lub uaktualnią, ale nic nie stanie się
686           * z wartościami W i H obrazka - więc jeśli ich tam nie było, to po
687           * uaktualnieniu ich nadal nie będzie (lub będzie 0 i 0), dla tego
688           * musimy tutaj sztucznie wymusić ustawienie wartości W i H obrazka.
689           */
690          self.main.Zooming.eventMouseUp();
691        }
692      },
693
694      /**
695       * Metoda eventu onmousemove. Za pomocą metody pomocniczej oblicza
696       * pozycję obrazka i przesuwa go.
697       * 
698       * @event onmousemove
699       * @param object e
700       * @return void
701       */
702      this.eventMouseMove = function(self, e) {
703        if(self.mouseDowned === true || e.type == 'touchmove')
704        {
705          // Ustawiamy, że już było zmieniane
706          self.main.changed = true;
707          
708          // Obliczamy nowe pozycje i przesuwamy obrazek.
709          if (e.type == 'touchmove')
710          {
711            self.main.image.css(self.calculatePosition(e.originalEvent.touches[0].pageX, e.originalEvent.touches[0].pageY));
712          }
713          else
714          {
715            self.main.image.css(self.calculatePosition(e.pageX, e.pageY));
716          }
717        }
718      },
719
720      /**
721       * Podpina funkcje pod przyciski w kontenerze zdjęcia odpowiedzialne
722       * za przesunięcie zdjęcia do danej krawędzi lub rogu kontenera.
723       * 
724       * @return void
725       */
726      this.bindFixingButtons = function() {
727        var self = this;
728
729        // Top left
730        this.main.imageContainer.find('.ci-fixing-position.ci-fptl').mou
730seup(function() {
731          self.main.image.css({'top':'0px','left':'0px'});
732          self.main.vars.x = 0;
733          self.main.vars.y = 0;
734          self.main.CroppingResult.update(0, 0);
735
736        });
737        
738        // Top center
739        this.main.imageContainer.find('.ci-fixing-position.ci-fptc').mouseup(function() {        
740          var left = -((self.main.imageData.width / 2) - (self.main.imgCntData.width / 2));
741          self.main.image.css({'top':'0px','left':left+'px'});
742          self.main.vars.x = 0;
743          self.main.vars.y = left;
744          self.main.CroppingResult.update(left, 0);
745
746        });
747        
748        // Top right
749        this.main.imageContainer.find('.ci-fixing-position.ci-fptr').mouseup(function() {
750          var left = -(self.main.imageData.width - self.main.imgCntData.width);
751          self.main.image.css({'top':'0px','left':left+'px'});
752          self.main.vars.x = 0;
753          self.main.vars.y = left;
754          self.main.CroppingResult.update(left, 0);
755
756        });
757        
758        // Center left
759        this.main.imageContainer.find('.ci-fixing-position.ci-fpcl').mouseup(function() {
760          var top = -((self.main.imageData.height / 2) - (self.main.imgCntData.height / 2));
761          self.main.image.css({'top':top+'px','left':'0px'});
762          self.main.vars.x = 0;
763          self.main.vars.y = top;
764          self.main.CroppingResult.update(0, top);
765
766        });
767        
768        // Center center
769        this.main.imageContainer.find('.ci-fixing-position.ci-fpcc').mouseup(function() {
770          var top   = -((self.main.imageData.height / 2) - (self.main.imgCntData.height / 2));
771          var left  = -((self.main.imageData.width / 2) - (self.main.imgCntData.width / 2));
772          self.main.image.css({'top':top+'px','left':left+'px'});
773          self.main.vars.x = left;
774          self.main.vars.y = top;
775          self.main.CroppingResult.update(left, top);
776
777        });
778        
779        // Center right
780        this.main.imageContainer.find('.ci-fixing-position.ci-fpcr').mouseup(function() {
781          var top   = -((self.main.imageData.height / 2) - (self.main.imgCntData.height / 2));
782          var left  = -(self.main.imageData.width - self.main.imgCntData.width);
783          self.main.image.css({'top':top+'px','left':left+'px'});
784          self.main.vars.x = left;
785          self.main.vars.y = top;
786          self.main.CroppingResult.update(left, top);
787
788        });
789        
790        // Bottom left
791        this.main.imageContainer.find('.ci-fixing-position.ci-fpbl').mouseup(function() {
792          var top = -(self.main.imageData.height - self.main.imgCntData.height);
793          self.main.image.css({'top':top+'px','left':'0px'});
794          self.main.vars.x = 0;
795          self.main.vars.y = top;
796          self.main.CroppingResult.update(0, top);
797
798        });
799        
800        // Bottom center
801        this.main.imageContainer.find('.ci-fixing-position.ci-fpbc').mouseup(function() {
802          var top   = -(self.main.imageData.height - self.main.imgCntData.height);
803          var left  = -((self.main.imageData.width / 2) - (self.main.imgCntData.width / 2));
804          self.main.image.css({'top':top+'px','left':left+'px'});
805          self.main.vars.x = left;
806          self.main.vars.y = top;
807          self.main.CroppingResult.update(left, top);
808
809        });
810        
811        // Bottom right
812        this.main.imageContainer.find('.ci-fixing-position.ci-fpbr').mouseup(function() {
813          var top   = -(self.main.imageData.height - self.main.imgCntData.height);
814          var left  = -(self.main.imageData.width - self.main.imgCntData.width);
815          self.main.image.css({'top':top+'px','left':left+'px'});
816          self.main.vars.x = left;
817          self.main.vars.y = top;
818          self.main.CroppingResult.update(left, top);
819
820        });
821      },
822
823      /**
824       * Metoda oblicza pozycję obrazka względem pozycji kursora oraz 
825       * domyślnej pozycji obrazka tuż przed przenoszeniem i zwraca obiekt
826       * z obliczonymi nowymi współrzędnymi obrazka.
827       * 
828       * @param integer pageX Wartość obiektu event.pageX
829       * @param integer pageY Wartość obiektu event.pageY
830       * 
831       * @return object
832       */
833      this.calculatePosition = function(pageX, pageY) {
834        return {'top':pageY - this.mousePositionStart.y + this.imagePosition.top,'left':pageX - this.mousePositionStart.x + this.imagePosition.left};
835      }
836    };
837
838
839    /**
840     * Obiekt odpowiedzialny za "przybliż - oddal".
841     */
842    var CI_ZOOMING = function(main) {
843      this.main = main;
844
845      /**
846       * Przechowuje obiekt interwału zoomowania.
847       * 
848       * @var object
849       */
850      this.interval = null;
851
852      /**
853       * Czas, który pozostał, do rozpoczęcia zoomu w petli.
854       * 
855       * @var integer
856       */
857      this.timesLeftToZoom = 10;
858
859      /**
860       * Przechowuje informacje na temat tego, czy można zastopować
861       * zoomowanie podczas zdarzenia mouseup na body.
862       * 
863       * @var boolean
864       */
865      this.canStopZoom = false;
866
867      /**
868       * Przechowuje funkcję callable z wywołaniem funkcji zoom z parametrem
869       * określającym czy ma przybliżać czy oddalać.
870       * 
871       * @var function
872       */
873      this.zoomFunction = function() {};
874
875      /**
876       * Inicjator.
877       */   
878      this.init = function() {
879        var self = this;
880
881        this.timesLeftToZoom = this.main.options.zoomDelay;
882
883        // Podpinamy zoom dla przycisków
884        this.main.container
885          .find('.ci-tool.ci-zooming .ci-button')
886          .mousedown(function() {
887            self.canStopZoom = true;
888            self.eventMouseDown($(this).hasClass('ci-tool-zoomin') ? 'in' : 'out');
889          })
890          .mouseup(function(e) {
891            self.eventMouseUp();
892            self.canStopZoom = false;
893            e.stopPropagation();
894          })
895          .click(function() {
896            self.canStopZoom = false;
897            self.eventMouseClick($(this).hasClass('ci-tool-zoomin') ? 'in' : 'out');
898          });
899        
900        // Reset zoom
901        $('body').mouseup(function() {
902          if(self.canStopZoom)
903            self.stopZoom();
904        });
905        
906        /**
907         * Musimy pobrać wymiary obrazka, ale nie uda nam się to przed jego 
908         * załadowaniem, dlatego tworzymy jeszcze jeden obrazek w kontenerze,
909         * podpinamy pod niego zdarzenie, by po wywołaniu pobrało wymiary,
910         * i ładujemy go do kontenera. Po załadowaniu usuwamy z kontenera,
911         * by nie pozostawić śladów.                  
912         */                 
913        var loader = document.createElement('IMG');
914            loader.className = 'ci-image-loader';
915            loader.onload = function() {
916              // Dane obrazka
917              self.main.imageData = {
918                // Oryginalne wymiary obrazka
919                originalWidth: self.main.image.width(),
920                originalHeight: self.main.image.height(),
921                // Aktualne wymiary obrazka
922                width: self.main.image.width(),
923                height: self.main.image.height(),
924                // Poporcje wymiarów obrazka względem oryginalnych
925                proportions: 1
926              };
927              
928              $('.ci-image-loader', self.main.imageContainer).remove();
929              self.main.options.onInit();
930            };
931            loader.src = this.main.image.attr('src');
932        
933        this.bindFixingButtons();
934        
935        /**
936         * Jeśli jest skrypt mousewheel to podpinamy zoomowanie za pomocą
937         * kółka myszki.
938         */
939        if(typeof this.main.container.mousewheel == 'function')
940        {
941          this.main.container.mousewheel(function(e) {
942            var type = e.deltaY == 1 ? 'in' : 'out';
943
944            self.zoom(type);
945
946            self.eventMouseUp();
947
948            e.stopPropagation();
949            e.preventDefault();
950            return false;
951          });
952        }
953      },
954
955      /**
956       * Metoda przygotowuje metodę zoomowania w zależności od podanej wartości
957       * w parametrze type.
958       * 
959       * @param string type
960       * @return void         
961       */
962      this.prepareToZoom = function(type) {
963        // Ustawiamy, że już było zmieniane
964        this.main.changed = true;
965        
966        // Ustawiamy, że w interwale może być wykonywana funkcja zoomowania
967        this.allowedZoomingFromInterval = true;
968        
969        // Ustawiamy funkcję wywołującą funkcję zoomowania w zależności od typu
970        this.zoomFunction = function() {this.zoom(type);};
971      },
972
973      /**
974       * Metoda rozpoczyna zmianę rozmiaru w zależności od podanego typu.
975       * Typ 'in' oznacza przybliżenie; Typ 'out' oznacza oddalenie. Najpierw
976       * wykonuje raz funkcję zoomowania, a nastepnie ustawia interval tak, by
977       * po wciśnięciu i przytrzymaniu klawisza myszki można było zoomować
978       * cały czas bez kolejnych wciśnięć.
979       * 
980       * @param string type
981       * @return false
982       */
983      this.eventMouseDown = function(type) {
984        var self = this;
985
986        // Przygotowujemy metodę do zoomowania
987        this.prepareToZoom(type);
988        
989        // Ustawiamy odliczanie na zoomowanie ciągłe
990        this.interval = setInterval(function() {
991          self.timesLeftToZoom = self.timesLeftToZoom - 10;
992          
993          if(self.timesLeftToZoom <= 0)
994            self.zoomFunction();
995        }, 10);
996        
997        return false;
998      },
999
1000      /**
1001       * Zatrzymanie zmiany rozmiaru.
1002       * 
1003       * @return void
1004       */
1005      this.eventMouseUp = function() {
1006        this.main.CroppingResult.update(
1007          undefined,
1008          undefined,
1009          this.main.options.resultWidth * parseFloat(this.main.CroppingResult.cropPercent),
1010          this.main.options.resultHeight * parseFloat(this.main.CroppingResult.cropPercent),
1011          true
1012        );
1013
1014        this.stopZoom();
1015      },
1016
1017      /**
1018       * Zdarzenie pojedyńczego kliknięcia w przycisk. Jeśli tylko kliknie
1019       * zoomujemy o jeden stopień.
1020       * 
1021       * @param string type
1022       * @return void
1023       */
1024      this.eventMouseClick = function(type) {
1025        // Zatrzymujemy to co było do tej pory
1026        this.stopZoom();
1027        // Przygotowujemy metodę do zoomowania
1028        this.prepareToZoom(type);
1029        // Wykonujemy jeden raz funkcję zoomowania
1030        this.zoomFunction();
1031      },
1032
1033      /**
1034       * Metoda resetuje i stopuje ZOOM.
1035       * 
1036       * @return void
1037       */
1038      this.stopZoom = function() {
1039        this.timesLeftToZoom = this.main.options.zoomDelay;
1040        
1041        clearInterval(this.interval);
1042      },
1043
1044      /**
1045       * Główna metoda odpowiedzialna za zoomowanie obrazka. Parametr type='in' oznacza
1046       * przybliżenie, parametr type='out' oznacza oddalenie.
1047       * 
1048       * @param string type 'in' lub 'out'
1049       * @return void
1050       */
1051      this.zoom = function(type) {
1052        // Zmieniamy wielkość procent w zależności od tego, czy przybliżamy czy oddalamy
1053        if(type == 'in')
1054          this.main.imageData.proportions = (parseFloat(this.main.imageData.proportions) + (this.main.options.zoomStep / 1000)).toFixed(4);
1055        else
1056          this.main.imageData.proportions = (parseFloat(this.main.imageData.proportions) - (this.main.options.zoomStep / 1000)).toFixed(4);
1057        
1058        // Maksymalne przybliżenie to 200%
1059        if(this.main.imageData.proportions >= 2) {
1060          this.main.imageData.proportions = 2;
1061          $('.ci-button.ci-tool-zoomin').addClass('disabled');
1062        } else {
1063          $('.ci-button.ci-tool-zoomin').removeClass('disabled');
1064        }
1065        
1066        // Maksymalne oddalenie to 1%
1067        if(this.main.imageData.proportions <= 1){
1068          this.main.imageData.proportions = 1;
1069          $('.ci-button.ci-tool-zoomout').addClass('disabled');
1070        } else {
1071          $('.ci-button.ci-tool-zoomout').removeClass('disabled');
1072        }
1073
1074        $('#image-slider-size').slider('value', (this.main.imageData.proportions - 1) * 40);
1075        
1076        
1077        this.main.imageData.width   = (this.main.imageData.originalWidth * this.main.imageData.proportions);
1078        this.main.imageData.height  = (this.main.imageData.originalHeight * this.main.imageData.proportions)
1079        
1080        // Obliczamy nowe wymiary obrazka względem obliczonych procentów
1081        var newSizes = this.fixSizes(
1082          this.main.imageData.originalWidth * this.main.imageData.proportions,
1083          this.main.imageData.originalHeight * this.main.imageData.proportions
1084        );
1085        
1086        // Zmieniamy rozmiar zdjęcia
1087        this.main.image.css({
1088          'width':newSizes.width,
1089          'height':newSizes.height,
1090          'max-width':newSizes.width,
1091          'max-height':newSizes.height,
1092          'min-width':newSizes.width,
1093          'min-height':newSizes.height
1094        });
1095      },
1096
1097      /**
1098       * Podpina funkcje pod przyciski w kontenerze zdjęcia odpowiedzialne
1099       * za zmianę rozmiaru zdjęcia względem rozmiaru kontenera.
1100       * 
1101       * @return void
1102       */
1103      this.bindFixingButtons = function() {
1104        var self = this;
1105
1106        var update = function() {
1107          self.main.imageData.width   = (self.main.imageData.originalWidth * self.main.imageData.proportions);
1108          self.main.imageData.height  = (self.main.imageData.originalHeight * self.main.imageData.proportions)
1109          
1110          // Obliczamy nowe wymiary obrazka względem obliczonych procentów
1111          var newSizes = self.fixSizes(
1112            self.main.imageData.originalWidth * self.main.imageData.proportions,
1113            self.main.imageData.originalHeight * self.main.imageData.proportions
1114          );
1115          
1116          // Zmieniamy rozmiar zdjęcia
1117          self.main.image.css({
1118            'width':newSizes.width,
1119            'height':newSizes.height,
1120            'max-width':newSizes.width,
1121            'max-height':newSizes.height,
1122            'min-width':newSizes.width,
1123            'min-height':newSizes.height
1124          });
1125
1126          self.main.CroppingResult.update(undefined, undefined, self.main.options.resultWidth * parseFloat(self.main.CroppingResult.cropPercent), self.main.options.resultHeight * parseFloat(self.main.CroppingResult.cropPercent), true);
1127        };
1128
1129        // Szerokość kontenera
1130        this.main.container.find('.ci-fixing-size.ci-fsw').click(function() {
1131          self.main.imageData.proportions = self.main.imageContainer.width() / self.main.imageData.originalWidth;
1132          update();
1133        });
1134        
1135        // Wysokość kontenera
1136        this.main.container.find('.ci-fixing-size.ci-fsh').click(function() {
1137          self.main.imageData.proportions = self.main.imageContainer.height() / self.main.imageData.originalHeight;
1138          update();
1139        });
1140      },
1141
1142      this.fixSizes = function(width, height) {
1143        /**
1144         * Jeśli z jakiegoś powodu któraś z wartości jest równa zero, to
1145         * ustawiamy domyślne wymiary zdjęcia.
1146         */
1147        if(width == 0 || height == 0)
1148        {
1149          width = this.main.imageData.width;
1150          height = this.main.imageData.height;
1151        }
1152        
1153        var containerSizes = {
1154          'width':this.main.options.resultWidth,
1155          'height':this.main.options.resultHeight
1156        };
1157
1158        if(this.main.options.restrictedBounds)
1159        {
1160          if(containerSizes.width > width || containerSizes.height > height)
1161          {
1162            var propsWidth  = containerSizes.width / width;
1163            var propsHeight = containerSizes.height / height;
1164            
1165            var smaller = 0;
1166            
1167            if(propsWidth > propsHeight)
1168              smaller = propsWidth;
1169            else
1170              smaller = propsHeight;
1171            
1172            width = width * smaller;
1173            height = height * smaller;
1174            
1175            this.main.Zooming.eventMouseUp();
1176          }
1177        }
1178
1179        return {'width':width+'px','height':height+'px'};
1180      }
1181    };
1182
1183
1184    /**
1185     * Obiekt odpowiedzialny jest za wrzucanie danych na temat pozycji zdjęcia
1186     * w kontenerze oraz jego wymiarów do inputów przechowujących te dane.
1187     */
1188    var CI_CROPPING_RESULT = function(main) {
1189      this.main = main;
1190
1191      /**
1192       * Współrzędne punktu zaczepienia zaznaczenia obrazka.
1193       */
1194      this.coordinates = { 'x' : 0, 'y' : 0 };
1195
1196      /**
1197       * Wartość w procentach zaznaczenia obrazka. Domyślnie: 1 == 100%
1198       */             
1199      this.cropPercent = 1;
1200
1201      /**
1202       * Zapisuje podane dane do inputów o ID typu z doklejonym prefiksem. Jeśli
1203       * podana wartość jest undefined lub niepodana to pobieramy wartość
1204       * aktualną danego inputa i ją wrzucamy. W innym wypadku wrzucamy wartość
1205       * zero.
1206       * 
1207       * @param integer x Współrzędna X
1208       * @param integer y Współrzędna Y
1209       * @param integer w Szerokość zaznaczenia obrazka
1210       * @param integer h Wysokość  zaznaczenia obrazka
1211       * 
1212       * @return void
1213       */
1214      this.update = function(x, y, w, h, triggerEvent) {
1215        var prop  = this.main.imageData.originalWidth / this.main.imageData.width;
1216        
1217        var valueX = this.main.vars.x;
1218        
1219        if(x != undefined)      valueX = Math.ceil(prop * x);
1220        else if(valueX == '')   valueX = 0;
1221        
1222        x = valueX;
1223        $('#'+this.main.options.inputPrefix+'x').val(valueX);
1224        this.main.vars.x = valueX;
1225        
1226        
1227        var valueY = this.main.vars.y;
1228        
1229        if(y != undefined)      valueY = Math.ceil(prop * y);
1230        else if(valueY == '')   valueY = 0;
1231        
1232        y = valueY;
1233        $('#'+this.main.options.inputPrefix+'y').val(valueY);
1234        this.main.vars.y = valueY;
1235        
1236        
1237        var valueW = this.main.vars.w;
1238        
1239        if(w != undefined)      valueW = Math.ceil(prop * w)
1240        else if(valueW == '')   valueW = 0;
1241        
1242        w = valueW;
1243        $('#'+this.main.options.inputPrefix+'w').val(valueW);
1244        this.main.vars.w = valueW;
1245        
1246        
1247        var valueH = this.main.vars.h;
1248        
1249        if(h != undefined)      valueH = Math.ceil(prop * h)
1250        else if(valueH == '')   valueH = 0;
1251        
1252        h = valueH;
1253        $('#'+this.main.options.inputPrefix+'h').val(valueH);
1254        this.main.vars.h = valueH;
1255
1256        if(triggerEvent === true)
1257        {
1258          this.main.options.onChange(this.main.vars.x, this.main.vars.y, this.main.vars.w, this.main.vars.h, this.main.image);
1259        }
1260      }
1261    };
1262
1263    /**
1264     * Resetuje obiekt pluginu i zostawia sam obrazek usuwając kod HTML.
1265     */
1266    var CI_RESET = function(main) {
1267      this.main = main;
1268
1269      this.reset = function() {
1270        var img = this.main.image.clone().removeAttr('style');
1271
1272        this.main.container.replaceWith(img);
1273
1274        img.data('cropimg', null);
1275      };
1276    }
1277
1278    
1279    return this.each(function() {
1280      var Main = new CI_Main($(this), options);
1281      Main.ToolDrawer = new CI_TOOLDRAWER(Main);
1282      Main.BtnTips = new CI_BTNSTIPS(Main);
1283      Main.Movable = new CI_MOVABLE(Main);
1284      Main.Zooming = new CI_ZOOMING(Main);
1285      Main.CroppingResult = new CI_CROPPING_RESULT(Main);
1286      Main.Reset = new CI_RESET(Main);
1287
1288      Main.ToolDrawer.draw();
1289      Main.BtnTips.init();
1290      Main.Movable.init();
1291      Main.Zooming.init();
1292
1293      $(this).data('cropimg', Main.Reset);
1294      
1295      $(window).trigger('resize');
1296    });
1297  }
1298})(jQuery);

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.