PageSourceSearch

https://www.frapol.com.pl/js/jquery.easypin.js

js frapol.com.pl collected 2026-10-06 04:53:02 UTC 66,240 bytes, 2,042 lines download raw bytes

1(function($){
2
3	$.fn.easypin = function(options) {
4
5		options = options || {};
6
7        if(localStorage) {
8            localStorage.removeItem('easypin');
9        }
10
11		var parentClass = $.fn.easypin.defaults.parentClass;
12		var pinMapClass = $.fn.easypin.defaults.pinMapClass;
13		var hoverClass = $.fn.easypin.defaults.hoverClass;
14		var dashWidth = $.fn.easypin.defaults.dashWidth;
15		var imageZindex = $.fn.easypin.defaults.imageZindex;
16		var pinMapZindex = $.fn.easypin.defaults.pinMapZindex;
17		var hoverLayerZindex = $.fn.easypin.defaults.hoverLayerZindex;
18
19		// set default options values and became user side
20		$.extend($.fn.easypin.defaults, options );
21
22        var willPinningElements = this;
23        var loadedImgNum = 0;
24        var total = $(this).length;
25
26        // hide all images
27        willPinningElements.each(function(i) {
28            $(this).css('opacity', 0);
29        });
30
31        $(this).on('load', function() {
32
33            loadedImgNum += 1;
34            // show loaded image
35            $(this).animate(
36                {
37                    'opacity': '1'
38                },
39                {
40                    duration: 'fast',
41                    easing: 'easeInQuad'
42                }
43            );
44
45            if (loadedImgNum == total) {
46
47                willPinningElements.each(function(i) {
48
49        			// get targetimage sizes
50        			var imageWidth = $(this).width();
51        			var imageHeight = $(this).height();
52
53        			if(imageHeight > 0) {
54
55            			// create parent element and add than target image after
56            			var containerElement = $(this)
57            				.after(
58                                $('<div/>', {'class': parentClass})
59                                    .attr('data-index', setIndex(setClass(parentClass), document.body))
60                            )
61            				.appendTo(setClass(parentClass)+':last')
62            				.css('position', 'absolute')
63            				.css('z-index', imageZindex);
64
65            			// add class to target image
66            			$(this).addClass('easypin-target')
67
68                        // creating random key for easypin-id
69                        if(! $(this).attr('easypin-id')) {
70                            var easypinId = createRandomId();
71                            $(this).attr('easypin-id', easypinId);
72                        }else{
73                            var easypinId = $(this).attr('easypin-id');
74                        }
75
76            			// set target image sizes to parent container
77            			containerElement
78            				.parent()
79            				.attr($.fn.easypin.config('widthAttribute'), imageWidth)
80            				.attr($.fn.easypin.config('heightAttribute'), imageHeight)
81            				// and set style width, height and position
82            				.css({
83            					width: setPx(imageWidth),
84            					height: setPx(imageHeight),
85            					position: $.fn.easypin.config('parentPosition'),
86            					border: setPx(dashWidth)+' dashed #383838',
87                                'box-sizing': 'content-box',
88                                'webkit-box-sizing': 'content-box',
89                                '-moz-box-sizing': 'content-box'
90            				});
91
92                        initPin(easypinId, $(this));
93            		}
94        		});
95
96                // hover event
97        		var parentElement = $(setClass(parentClass));
98
99        		// on hover parent element then create opacity
100        		$(parentElement).hover(function() {
101        			// if popup is open stop hover animate
102        			if(! is_open('popup', $(this))) {
103        				$(this)
104        					.prepend(
105        						$('<div/>', {'class': hoverClass})
106        							.css({
107        								width: '100%',
108        								height: '100%',
109        								position: 'absolute',
110        								opacity: 0,
111        								'z-index': hoverLayerZindex,
112        								'background-color': 'black',
113        								cursor: 'copy'
114        							})
115        					)
116        					// cross to children object
117        					.children(setClass(hoverClass))
118        						.animate({
119        						    opacity: 0.2,
120        						}, 800);
121        			}
122
123        		// on mouseleave then remove opacity
124        		},function() {
125        			$(this)
126        				// cross to children object
127        				.children(setClass(hoverClass))
128        				.animate({
129        				    opacity: 0,
130        				},
131        				'fast', // how fast we are animating
132            			'swing', // the type of easing
133        				function() {
134        			   		$(this).remove();
135        				}
136        			);
137
138        		})
139        		.append($('<div/>', {'class': pinMapClass})
140        			// child element
141        			.css({
142        				position: 'absolute',
143        				'z-index': pinMapZindex
144        			})
145        		)
146        		// set mousedown event on parent element
147        		.bind('mousedown', function(e) {
148        			// if clicked event is not parent and hover class stop propagation
149        			if(! $(e.target).is(setClass(parentClass)) && !$(e.target).is(setClass(hoverClass))) {
150        				e.stopPropagation();
151        				return;
152        			}
153
154        			// only allow key code one
155        			if(e.which != 1) return;
156
157        			// get parent element instance
158        			var parentElement = e.currentTarget;
159
160                    // get total marker
161                    var totalMarker = $('.easy-marker', parentElement).size();
162
163                    // general limit
164                    var limit = parseInt($.fn.easypin.defaults.limit);
165
166                    // only element limit
167                    var elLimit = $('img'+setClass('easypin-target'), parentElement).attr('easypin-limit');
168
169                    // check the limit
170                    if(elLimit && !isNaN(elLimit) && parseInt(elLimit) != 0) {
171                        if(totalMarker >= parseInt(elLimit)) {
172                            $.fn.easypin.defaults.exceeded('limit exceeded');
173                            return;
174                        }
175                    }
176                    else if(limit != 0 && totalMarker >= limit) {
177                        $.fn.easypin.defaults.exceeded('limit exceeded');
178                        return;
179                    }
180
181        			// get target image sizes
182        			var imageWidth = $('img'+setClass('easypin-target'), parentElement).width();
183        			var imageHeight = $('img'+setClass('easypin-target'), parentElement).height();
184
185        			// pin map class sized
186        			$(setClass(pinMapClass), parentElement)
187        				.css({
188        					width: setPx(imageWidth),
189        					height: setPx(imageHeight)
190        				});
191
192        			// get config variable
193        			var src = $.fn.easypin.defaults.markerSrc;
194        			var markerWidth = $.fn.easypin.defaults.markerWidth;
195        			var markerHeight = $.fn.easypin.defaults.markerHeight == 'auto' ? markerWidth : $.fn.easypin.defaults.markerHeight;
196        			var markerClass = $.fn.easypin.defaults.markerClass;
197        			var markerContainerZindex = $.fn.easypin.defaults.markerContainerZindex;
198
199        			// canvas border width
200        			var dashWidth = $.fn.easypin.defaults.dashWidth;
201
202        			// get x, y balance value
203        			var posYBalance = $.fn.easypin.defaults.posYBalance;
204        			var posXBalance = $.fn.easypin.defaults.posXBalance;
205
206        			// get current target image instance
207        			var targetImage = $('img'+setClass('easypin-target'), parentElement);
208
209        			// set cursor position coordinate
210        			var imagePositionY = targetImage.offset().top - (dashWidth-posYBalance);
211        			var imagePositionX = targetImage.offset().left - (dashWidth-posXBalance);
212        			var clickPosX = (e.pageX-imagePositionX);
213        			var clickPosY = (e.pageY-imagePositionY);
214
215        			// get marker half size (width/height)
216        			var markerWidthHalf = (markerWidth/2);
217        	        var markerHeightHalf = (markerHeight/2);
218
219        			// set canvas border position
220        			var markerBorderX = clickPosX-(markerWidth/2);
221        			var markerBorderY = clickPosY-(markerHeight/2);
222
223        			if(markerBorderX < 0) {
224        				markerBorderX = 0;
225        			}
226        			else if(clickPosX+markerWidthHalf > imageWidth) {
227        				markerBorderX = imageWidth-markerWidth;
228        			}
229
230        			if(markerBorderY < 0) {
231        				markerBorderY = 0;
232        			}
233        			else if(clickPosY+markerHeightHalf > imageHeight) {
234        				markerBorderY = imageHeight-markerHeight;
235        			}
236
237        			var absX = markerBorderX.toFixed(3)-markerWidthHalf;
238        			var absY = markerBorderY.toFixed(3)-markerHeightHalf;
239
240                    // create tool
241                    var tools = createTools({
242                        markerWidth: markerWidth,
243                        markerHeight: markerHeight
244                    });
245
246                    // create marker container
247                    var markerContainer = createMarker({
248                        tools: tools,
249                        parentElement: parentElement,
250                        markerClass: markerClass,
251                        markerBorderX: markerBorderX,
252                        markerBorderY: markerBorderY,
253                        markerWidth: markerWidth,
254                        markerHeight: markerHeight,
255                        markerContainerZindex: markerContainerZindex,
256                        markerWidth: markerWidth,
257                        absX: absX,
258                        absY: absY,
259                        imageWidth: imageWidth,
260                        imageHeight: imageHeight,
261                        parentElement: parentElement,
262                        src: src
263                    });
264        		});
265
266                // object instance add to container
267                $.fn.easypin.di('instance', $.fn.easypin);
268
269            }
270
271        });
272
273		return this;
274	};
275
276    var createMarker = function(depends) {
277
278        var parentElement = depends.parentElement;
279
280        // create marker container
281        var markerContainer = $('<div/>', {'class': depends.markerClass})
282            .css('left', setPx(depends.markerBorderX))
283            .css('top', setPx(depends.markerBorderY-15))
284            .css('width', depends.markerWidth)
285            .css('height', depends.markerHeight)
286            .css('margin-left', setPx(depends.marginLeft))
287            .css('margin-top', setPx(depends.marginTop))
288            .css('position', 'absolute')
289            .css('opacity', 0)
290            .css('z-index', depends.markerContainerZindex+10)
291            .css('background-image', 'url('+depends.src+')')
292            .css('background-size', setPx(depends.markerWidth))
293            .css('cursor', 'move')
294            .attr($.fn.easypin.config('xAttribute'), depends.absX)
295            .attr($.fn.easypin.config('yAttribute'), depends.absY)
296            .attr($.fn.easypin.config('widthAttribute'), depends.imageWidth)
297            .attr($.fn.easypin.config('heightAttribute'), depends.imageHeight)
298            .attr('data-index', setIndex('.easy-marker', depends.parentElement));
299
300            var markerIndex = $(markerContainer).attr('data-index');
301            var parentIndex = $(depends.parentElement).attr('data-index');
302            var parentId = $('.easypin-target', depends.parentElement).attr('easypin-id');
303
304            // remove marker
305            $(markerContainer).on('click', '.easy-delete', function(e) {
306
307                dataRemove(parentId, markerIndex);
308
309                $(e.currentTarget).closest('.easy-marker').remove();
310            });
311
312            // set the marker content
313            $(markerContainer).on('click', '.easy-edit', function(e) {
314                // creates popup and return instance
315                var modalInstance = createPopup(e, markerContainer);
316
317                // data set to input fields
318                setDataToFields(parentId, markerIndex, modalInstance);
319            });
320
321            // marker tools append to marker container
322            $(markerContainer).append(depends.tools);
323
324            // set cursor x,y position
325            var xPosition = depends.markerBorderX.toFixed(3);
326            var yPosition = depends.markerBorderY.toFixed(3);
327
328            // marker container append to pin parent container and run callback function
329            if(is_open('popup', depends.parentElement)) {
330                $(depends.parentElement).prepend(markerContainer, $.fn.easypin.defaults.drop(depends.absX, depends.absY, markerContainer));
331            }else{
332                $(depends.parentElement).append(markerContainer, $.fn.easypin.defaults.drop(depends.absX, depends.absY, markerContainer));
333            }
334
335            // calculate tools position for animate
336            if((depends.markerBorderY+depends.markerHeight+10) > depends.imageHeight) {
337                var toolsPosition = -13;
338            }else {
339                var toolsPosition = depends.markerHeight+2;
340            }
341
342            // marker animate
343            $(markerContainer).animate(
344                {
345                    opacity: 1,
346                    top: setPx(depends.markerBorderY)
347                },
348                {
349                    duration: 'slow',
350                    easing: 'easeOutElastic',
351                    complete: function() {
352
353                        // tools animate
354                        $(depends.tools).animate(
355                            {
356                                'opacity': '.4',
357                                'top': setPx(toolsPosition)
358                            },
359                            {
360                                duration: 'slow',
361                                easing: 'easeOutElastic'
362                            }
363                        ).hover(function() {
364                            $(this).animate(
365                                {
366                                    'opacity': '1'
367                                },
368                                {
369                                    duration: 'slow',
370                                    easing: 'easeInOutQuint'
371                                }
372                            ).css('cursor', 'pointer');
373                        },function() {
374                            $(this).animate(
375                                {
376                                    'opacity': '.4'
377                                },
378                                {
379                                    duration: 'slow',
380                                    easing: 'easeInOutQuint'
381                                }
382                            );
383                        });
384                    }
385                }
386            );
387
388            var cc = false;
389            // binding methods mousedown and mousemove
390            $(markerContainer).bind('mousedown', function (e) {
391                e.stopPropagation();
392
393                if(e.which != 1) return;
394
395                var markerInstance = e.currentTarget;
396
397                if($(e.target).parent().is(setClass('popoverContent'))) {
398                    cc = true;
399                }else{
400                    cc = $(e.target).is(setClass('popoverContent'));
401                }
402
403                $(parentElement).bind('mousemove', function (e) {
404
405                    if((! $(e.target).is('div.easy-marker') &&
406                        !$(e.target).is(setClass($.fn.easypin.defaults.hoverClass))) &&
407                        cc === true
408                    ) return;
409
410                    var parentElement = $(markerInstance).parent();
411                    var markerContainer = $(markerInstance);
412
413                    var targetImage = $('img.easypin-target', parentElement)
414                    var markerWidthHalf = (depends.markerWidth/2);
415                    var markerHeightHalf = (depends.markerHeight/2);
416                    liveY = e.pageY-targetImage.offset().top;
417                    liveX = e.pageX-targetImage.offset().left;
418
419                    var relY = liveY;
420                    var relX = liveX;
421
422                    if(liveY - markerHeightHalf < 0) {
423                        var relY = markerHeightHalf;
424                    }
425                    else if(liveY + markerHeightHalf > depends.imageHeight) {
426                        var relY = depends.imageHeight-markerHeightHalf;
427                    }
428
429                    if(liveX - markerWidthHalf < 0) {
430                        var relX = markerWidthHalf;
431                    }
432                    else if(liveX + markerWidthHalf > depends.imageWidth) {
433                        var relX = depends.imageWidth-markerWidthHalf;
434                    }
435
436                    var absX = relX.toFixed(3)-markerWidthHalf;
437                    var absY = parseInt(relY.toFixed(3))+markerHeightHalf;
438
439                    // on move marker then check tool container position
440                    checkToolsPosition(absY, depends.imageHeight, markerContainer)
441
442                    // drag event
443                    $.fn.easypin.defaults.drag(absX, absY, markerContainer);
444										console.log(relX);
445                    $(markerContainer).css({
446                        position: 'absolute',
447                        top: setPx(relY),
448                        left: setPx(relX),
449                        marginTop: -(depends.markerHeight/2),
450                        marginLeft: -(depends.markerWidth/2),
451                    })
452                    .attr($.fn.easypin.config('xAttribute'), absX)
453                    .attr($.fn.easypin.config('yAttribute'), absY);
454                });
455            });
456
457            // unbinding the events and removing
458            $(markerContainer).bind('mouseup', function (e) {
459                cc = false;
460                var markerInstance = e.currentTarget;
461                var lat = $(markerInstance).attr($.fn.easypin.config('xAttribute'));
462                var long = $(markerInstance).attr($.fn.easypin.config('yAttribute'));
463
464                dataUpdate(parentId, markerIndex, {coords: {lat: lat, long: long}});
465
466                $(parentElement).unbind('mousemove');
467            });
468
469        return markerContainer;
470    };
471
472    var createTools = function(depends) {
473
474        var tools = $('<div/>', {'class': 'easy-tools'})
475            .css({
476                'width': setPx(depends.markerWidth),
477                'height': '10px',
478                'position': 'absolute',
479                'background-color': '#868585',
480                'left': '-1px',
481                'top': setPx((depends.markerHeight+2)-5),
482                'opacity': '0'
483
484            })
485            .append(function() { // edit button create
486                return $('<a/>', {'class': 'easy-edit'})
487                    .css({
488                        'display': 'inline-block',
489                        'width': setPx(depends.markerWidth/2),
490                        'height': '10px',
491                        'position': 'absolute',
492                        'left': '0px',
493                        'background-image': 'url('+$.fn.easypin.defaults.editSrc+')',
494                        'background-repeat': 'no-repeat',
495                        'background-size': '8px',
496                        'background-position-y': '1px',
497                        'background-position-x': '3px'
498                    }).hover(function() {
499                        $(this)
500                            .css('background-color', 'black')
501                            .css('opacity', '.6');
502                    },function() {
503                        $(this).css('background-color', 'inherit');
504                    });
505            })
506            .append(function() { // delete button
507                return $('<a/>', {'class': 'easy-delete'})
508                    .css({
509                        'display': 'inline-block',
510                        'width': setPx(depends.markerWidth/2),
511                        'height': '10px',
512                        'position': 'absolute',
513                        'right': '0px',
514                        'background-image': 'url('+$.fn.easypin.defaults.deleteSrc+')',
515                        'background-repeat': 'no-repeat',
516                        'background-size': '8px',
517                        'background-position-y': '1px',
518                        'background-position-x': '3px'
519                    }).hover(function() {
520                        $(this)
521                            .css('background-color', 'black')
522                            .css('opacity', '.6');
523                    },function() {
524                        $(this).css('background-color', 'inherit');
525                    });
526            });
527
528        return tools;
529    };
530
531	var checkToolsPosition = function(absY, imageHeight, markerContainer) {
532
533		var markerHeight = $(markerContainer).height();
534		var yBottom = absY+10;
535
536		if(yBottom > imageHeight && yBottom == imageHeight+1) {
537			$('.easy-tools', markerContainer).animate(
538				{
539					'top': setPx(-13)
540				},
541				{
542					duration: 'slow',
543					easing: 'easeOutElastic'
544				}
545			);
546		}
547
548		else if((absY-markerHeight)-10 == -1) {
549			$('.easy-tools', markerContainer).animate(
550				{
551					'top': setPx(markerHeight+2)
552				},
553				{
554					duration: 'slow',
555					easing: 'easeOutElastic'
556				}
557			);
558		}
559	};
560
561    var getEventData = function(namespace) {
562
563        switch (namespace) {
564            case "get.coordinates":
565                    if(localStorage) {
566                        return JSON.parse(localStorage.getItem('easypin'));
567                    }else {
568                        try {
569                            return JSON.parse(decodeURIComponent($('input[name="easypin-store"]').val()));
570                        } catch (e) {
571                            return null;
572                        }
573                    }
574                break;
575            default:
576                return null;
577        }
578
579    };
580
581    getByIndex = function(index, data) {
582
583        data = data || {};
584        index = parseInt(index);
585
586        if(typeof(data) == 'object') {
587
588            var j = 0;
589            for(var i in data) {
590
591                j++;
592                if(j == index) {
593                    return data[i];
594                }
595
596            }
597
598        }
599
600        return {};
601
602    };
603    $.fn.easypinShow = function(options) {
604
605        options = options || {};
606
607        // set default options values and became user side
608		$.extend($.fn.easypinShow.defaults, options );
609
610        try {
611
612            var depends = {
613                responsive: options.responsive || false,
614                pin: options.pin || 'marker.png',
615                data: options.data || {},
616                popover: options.popover || {},
617                error: typeof(options.error) != 'function' ? function(e) {} : options.error,
618                each:  typeof(options.each) != 'function' ? function(i, data) { return data;} : options.each,
619                success: typeof(options.success) != 'function' ? function() {} : options.success,
620                allCanvas: this
621            };
622
623            var loadedImgNum = 0;
624            var total = $(this).length;
625
626            // hide all images
627            depends.allCanvas.each(function(i) {
628                $(this).css('opacity', 0);
629            });
630
631            $(depends.allCanvas).one('load', function() {
632                loadedImgNum += 1;
633
634                // show loaded image
635                $(this).animate(
636                    {
637                        'opacity': '1'
638                    },
639                    {
640                        duration: 'fast',
641                        easing: 'easeInQuad'
642                    }
643                );
644
645                if (loadedImgNum == total) {
646
647                    var markerWidth = $(this)[0].width;
648                    var markerHeight = $(this)[0].height;
649                    var markerImgInstance = $(this);
650                    pinLocate(depends);
651                    depends.success.apply();
652                }
653            }).each(function() {
654              if(this.complete) $(this).load();
655            });
656
657        } catch (e) {
658            var args = new Array();
659            args.push(e.message);
660            args.push(e);
661            depends.error.apply(null, args);
662        }
663
664    };
665
666    pinLocate = function(depends) {
667
668        // for each all canvas
669        $(depends.allCanvas).each(function(i) {
670
671            var offsetTop = $(this).offset().top;
672            var offsetLeft = $(this).offset().left;
673            var canvas = $(this).parent();
674            var height = $(this).height();
675            var width = $(this).width();
676            var parentWidth = $(canvas).width();
677
678            if(depends.responsive === true) {
679                var absWidth = '100%';
680                var absHeight = '100%';
681            }else{
682                var absWidth = setPx(width);
683                var absHeight = setPx(height);
684            }
685
686            var pinContainer = $('<div/>')
687                .css({
688                    'width': absWidth,
689                    'height': absHeight,
690                    'position': 'relative'
691                })
692                .addClass('easypin');
693
694            $(this)
695                .css('position', 'relative')
696                .replaceWith(pinContainer);
697
698            $(pinContainer).html(
699                $('<div/>')
700                    .css('position', 'relative')
701                    .css('height', '100%')
702                    .append($(this))
703            );
704
705            var parentId = $(this).attr('easypin-id');
706
707            if(typeof(depends.data) == 'string') {
708                depends.data = JSON.parse(depends.data);
709            }
710
711            if(typeof(depends.data[parentId]) != 'undefined') {
712
713                for (var j in depends.data[parentId]) {
714                    if(j == 'canvas') return;
715
716                    var tpl = $('[easypin-tpl]').clone();
717
718                    // set current canvas_id and pin_id to di container
719                    $.fn.easypin.di('canvas_id', parentId);
720                    $.fn.easypin.di('pin_id', j);
721
722                    // run callback function
723                    var args = new Array();
724                    args.push(i);
725                    args.push(depends.data[parentId][j]);
726                    var returnData = depends.each.apply(null, args);
727                    var viewContainer = viewLocater(depends.data[parentId], j, parentWidth, createView(returnData, tpl));
728
729                    var opacity = getCssPropertyValue('opacity', $(viewContainer).clone());
730
731                    $(viewContainer).css('opacity', 0);
732                    $(pinContainer).append(viewContainer);
733
734                    if(depends.popover.show == true) {
735                        $('.easypin-popover', pinContainer).show();
736                    }
737
738                    // marker
739                    $(viewContainer).animate(
740                        {
741                            'opacity': opacity
742                        },
743                        {
744                            duration: 'slow',
745                            easing: 'easeOutBack'
746                        }
747                    );
748
749                    // popover
750
751										$('.closepin',pinContainer).click(function(e){
752											$('.easypin-popover', pinContainer).each(function() {
753													if($(this).css('display') == 'block' ) {
754															$(this).fadeOut('fast');
755													}
756											});
757										});
758
759                    $('.easypin-marker:last', pinContainer).click(function(e) {
760
761                        if(! $(e.target).is('div.easypin-marker') &&
762                            !$(e.target).parent().is('div.easypin-marker')) return;
763
764                        // set 0 to z-index all marker
765                        $('.easypin-marker', pinContainer).css('z-index', 0);
766
767                        // set 1 to z-index current marker
768                        $(this).css('z-index', 1);
769
770                        var ins = this;
771                        var clickedMarkerIndex = $(ins).index();
772
773                        if(depends.popover.animate === true) {
774
775                            // hide all content
776                            $('.easypin-popover', pinContainer).each(function() {
777                                if($(this).css('display') == 'block' && clickedMarkerIndex != $(this).closest('.easypin-marker').index()) {
778                                    $(this).toggle('fast');
779                                }
780                            });
781
782                            $('.easypin-popover', ins).toggle('fast');
783
784                        }else{
785                            // hide all content
786                            $('.easypin-popover', pinContainer).each(function() {
787                                if($(this).css('display') == 'block' && clickedMarkerIndex != $(this).closest('.easypin-marker').index()) {
788                                    $(this).hide();
789                                }
790                            });
791
792                            if ( $('.easypin-popover', this).css('display') == 'none' ){
793                                $('.easypin-popover', this).show();
794                            }else{
795                                $('.easypin-popover', this).hide();
796                            }
797                        }
798                    });
799                }
800            }
801        });
802    };
803
804    var createView = function(data, tplInstance) {
805
806        var popover = $('popover', tplInstance);
807        var marker = $('marker', tplInstance);
808
809        $(popover)
810            .children(':first')
811            .addClass('easypin-popover')
812            .css('position', 'absolute')
813            .css('display', 'none');
814
815        $(marker)
816            .children(':first')
817            .addClass('easypin-marker')
818            .css({
819                'position': 'absolute'
820            });
821
822        var markerBorderWidth = $(marker).children(':first').css('border-width').replace('px', '');
823        markerBorderWidth = markerBorderWidth != '' ? parseInt(markerBorderWidth) : 0;
824        var markerWidth = $(marker).children(':first').width();
825        var markerHeight = $(marker).children(':first').height();
826        var popoverHeight = $(popover).children(':first').height();
827
828        var popIns = $(popover).children(':first').clone();
829        var bottom = getCssPropertyValue('bottom', popover);
830        var newBottom = bottom == 'auto' ? setPx(markerHeight+markerBorderWidth) : bottom;
831
832        $(popover)
833            .children(':first')
834            .css('bottom', newBottom)
835            .css('cursor', 'default');
836
837        $(marker)
838            .children(':first')
839            .append(tplHandler(data, $(popover).html()))
840            .css('cursor', 'pointer');
841
842        return $(marker).html();
843
844    };
845
846    var viewLocater = function(data, markerIndex, parentWidth, markerContainer) {
847
848        var pinWidth = parseInt(data.canvas.width);
849        var pinHeight = parseInt(data.canvas.height);
850        var markerWidth = $(markerContainer).width();
851        var markerHeight = $(markerContainer).height();
852
853        var pos = calculatePinRate(data[markerIndex],pinWidth, markerWidth, pinHeight, markerHeight);
854        var pinLeft = pos.left;
855        var pinTop = pos.top;
856				var clas='';
857				if(parseInt(pinLeft)>=80){
858					clas='pinLeft';
859				}else if(parseInt(pinLeft)>50 && parseInt(pinLeft)<80){
860
861					clas='pinCenterLeft';
862
863				}else if(parseInt(pinLeft)>20 && parseInt(pinLeft)<=50){
864					clas='pinCenterRight';
865				}else{
866					clas='pinRight';
867				}
868
869        markerContainer = $(markerContainer).addClass(clas).css('left', pinLeft+'%').css('top', pinTop+'%')
870
871        return markerContainer;
872
873
874    };
875
876    var tplHandler = function(data, tpl) {
877
878        if(typeof(data) == 'object') {
879
880            var callbackVars = $.fn.easypinShow.defaults.variables;
881
882            for(var i in data) {
883
884                var content = data[i];
885
886                if(typeof(callbackVars) != 'undefined' && typeof(callbackVars[i]) == 'function') {
887
888                    var args = new Array();
889
890                    // current canvas id
891                    args.push($.fn.easypin.container['canvas_id']);
892
893                    // current pin id
894                    args.push($.fn.easypin.container['pin_id']);
895                    args.push(data[i]);
896                    content = callbackVars[i].apply(null, args)
897
898                }
899
900                var pattern = RegExp("\\{\\["+i+"\\]\\}", "g");
901                tpl = tpl.replace(pattern,content);
902            }
903        }
904
905        return tpl;
906    };
907
908    var calculatePinRate = function(data, pinWidth, markerWidth, pinHeight, markerHeight) {
909        return {
910            left: (parseInt(data.coords.lat)/pinWidth)*100,
911            top: ((parseInt(data.coords.long)-(markerHeight))/pinHeight)*100,
912        };
913    };
914
915    var getCssPropertyValue = function(prop, el) {
916        var el = $(el).hide().appendTo('body');
917        var val = el.css(prop);
918        el.remove();
919
920        return val;
921    };
922
923    $.fn.easypin.clear = function() {
924        if(localStorage) {
925            localStorage.removeItem('easypin');
926        }else {
927            $('input[name="easypin-store"]').val('');
928        }
929    };
930
931    $.fn.easypin.event = function(namespace, closure) {
932        $.fn.easypin.di(namespace, closure);
933    };
934
935    $.fn.easypin.fire = function(namespace, params, callback) {
936
937        if(typeof($.fn.easypin.container[namespace]) != 'undefined') {
938
939            if(typeof(params) == 'function') {
940                callback = params;
941                params = null;
942            }else{
943                params = params || null;
944                callback = callback || null;
945            }
946
947            if(typeof(callback) == 'function') {
948                var callbackArgs = new Array();
949                callbackArgs.push(getEventData(namespace));
950                var eventReturn = callback.apply(null, callbackArgs);
951            }else {
952                var eventReturn = getEventData(namespace);
953            }
954
955            var dependsArgs = new Array();
956            dependsArgs.push($.fn.easypin.container['instance']);
957            dependsArgs.push(eventReturn);
958            dependsArgs.push(params);
959			$.fn.easypin.container[namespace].apply(null, dependsArgs);
960
961        }
962    };
963
964	$.fn.easypin.config = function(attr) {
965		return $.fn.easypin.defaults[attr];
966	};
967
968	$.fn.easypin.di = function(key, depends) {
969
970		$.fn.easypin.container[key] = depends;
971	};
972
973	$.fn.easypin.call = function(func, params) {
974
975		params = params || '';
976
977		var depends = func.toString().match(/function\s*\(\s*(.*?)\s*\)/i);
978
979		if(depends.length > 1) {
980
981			depends = depends[1];
982
983			var clientParm = depends.replace(/(\$[a-zA-Z]+)/g, '');
984			clientParm = clientParm.replace(/\s+/g, '');
985			clientParm = clientParm.replace(/,+/g,',');
986			clientParm = clientParm.replace(/(^,)/, '');
987			clientParm = clientParm.split(/,/g);
988
989			expectParm = depends.match(/(\$[a-zA-Z]+)/g);
990
991			var dependsArgs = new Array();
992
993			for(var i in expectParm) {
994				if($.fn.easypin.container[expectParm[i]]) {
995					dependsArgs.push($.fn.easypin.container[expectParm[i]]);
996				}
997			}
998
999			dependsArgs.push(params);
1000			func.apply(null, dependsArgs);
1001		}
1002	};
1003
1004	$.fn.easypin.defaults = {
1005
1006        init: {},
1007        limit: 0,
1008        popover: {},
1009        exceeded: function() {},
1010       	drop: function() {},
1011       	drag: function() {},
1012       	modalWidth: '200px',
1013		widthAttribute: 'data-width',
1014       	heightAttribute: 'data-height',
1015       	xAttribute: 'data-x',
1016       	yAttribute: 'data-y',
1017		markerSrc: 'img/marker.png',
1018		editSrc: 'img/edit.png',
1019		deleteSrc: 'img/remove.png',
1020       	parentClass: 'pinParent',
1021		markerClass: 'easy-marker',
1022		hoverClass: 'hoverClass',
1023		pinMapClass: 'pinCanvas',
1024       	parentPosition: 'relative',
1025		popupOpacityLayer: 'popupOpacityLayer',
1026		markerWidth: 32,
1027		markerHeight: 'auto',
1028		animate: false,
1029		posYBalance: 2,
1030		posXBalance: 2,
1031		dashWidth: 2,
1032		imageZindex: 1,
1033		pinMapZindex: 2,
1034		hoverLayerZindex: 3,
1035		markerContainerZindex: 4,
1036		markerBorderColor: '#FFFF00',
1037		downPoint: 10
1038
1039	};
1040
1041    $.fn.easypinShow.defaults = {};
1042
1043	$.fn.easypin.container = {};
1044	$.fn.easypin.markerContainer = {};
1045
1046	var setClass = function(name) {
1047		return '.'+name;
1048	};
1049
1050	var setPx = function(num) {
1051		return num+'px';
1052	};
1053
1054	var getMarkerUrl = function() {
1055		return $.fn.easypin.defaults.markerSrc;
1056	};
1057
1058	var is_open = function(type, parentElement) {
1059
1060		if(type == 'popup') {
1061
1062			var className = setClass($.fn.easypin.defaults.popupOpacityLayer);
1063			return $(className, parentElement).size() > 0;
1064
1065		}
1066
1067	};
1068
1069	var createPopup = function(elem, markerContainer) {
1070
1071		var parentElement = $(elem.target).closest('.pinParent');
1072        var parentIndex = $(parentElement).attr('data-index');
1073        var targetImage = $('.easypin-target', parentElement);
1074		var widthAttr = $.fn.easypin.defaults.widthAttribute;
1075		var heightAttr = $.fn.easypin.defaults.heightAttribute;
1076
1077		// create modal base layer
1078		var opacityLayer = $('<div/>')
1079			.addClass('popupOpacityLayer')
1080			.css({
1081				'width': '100%',
1082				'height': '100%',
1083				'background-color': 'black',
1084				'position': 'absolute',
1085				'opacity': '.0',
1086				'z-index': 14
1087			});
1088
1089		// append to parent container
1090		$(parentElement)
1091			.append(opacityLayer)
1092
1093			// cross to child element
1094			.children(setClass($.fn.easypin.defaults.hoverClass))
1095				.hide() // hover class hide
1096
1097			// back to parent element
1098			.parent()
1099
1100			// base layer animate
1101			.children(setClass($.fn.easypin.defaults.popupOpacityLayer))
1102				.animate({
1103					opacity: 0.4,
1104				}, 800);
1105
1106		var width = parseInt($(parentElement).attr(widthAttr));
1107		var height = parseInt($(parentElement).attr(heightAttr));
1108
1109		// create modal parent element
1110		var modalParent = $('<div/>')
1111			.addClass('modalParent')
1112			.css({
1113				'width': '100%',
1114				'height': '100%',
1115				'position': 'absolute',
1116				'z-index': 15
1117			})
1118			.click(function(e) {
1119
1120				if($(e.target). is('div.modalParent')) {
1121					closePopup(parentElement);
1122				}
1123
1124				e.stopPropagation();
1125			});
1126
1127        // clonning modal content
1128        var modalContent = $('.easy-modal:last').clone();
1129
1130		// create modal body element
1131		var modalContext = $('<div/>')
1132			.addClass('modalContext')
1133			.css({
1134				'background-color': '#fff',
1135				'width': $.fn.easypin.defaults.modalWidth,
1136				'opacity': '0',
1137				'position': 'absolute',
1138				'padding': '10px',
1139				'-webkit-box-shadow': '10px 13px 5px 0px rgba(0,0,0,0.75)',
1140				'-moz-box-shadow': '10px 13px 5px 0px rgba(0,0,0,0.75)',
1141				'box-shadow': '10px 13px 5px 0px rgba(0,0,0,0.75)',
1142				'-webkit-border-radius': '5px',
1143				'-moz-border-radius': '5px',
1144				'border-radius': '5px',
1145				'cursor': 'move'
1146			})
1147			.append($(modalContent).show())
1148			.appendTo(modalParent); // modal body append to modal parent element
1149
1150        // modal parent element append to parent element
1151        $('.popupOpacityLayer', parentElement).after(modalParent);
1152
1153		var modalHeight = $('.modalContext').height()
1154		var modalWidth = $(modalContext).width();
1155
1156        var parentLeft = $(elem.target).closest(setClass($.fn.easypin.defaults.parentClass)).offset().left;
1157        var markerLeft = $(elem.target).offset().left;
1158        var clickPosLeft = (markerLeft - parentLeft);
1159
1160        var parentTop = $(elem.target).closest(setClass($.fn.easypin.defaults.parentClass)).offset().top;
1161        var markerTop = $(elem.target).offset().top;
1162        var clickPosTop = (markerTop - parentTop);
1163
1164        // modal position process
1165        if($(modalContent).attr('modal-position') == 'free') {
1166
1167
1168            // calculate free left position
1169            if((clickPosLeft-100) < modalWidth) {
1170                var modalLeftPosition = clickPosLeft+$(markerContainer).width()+50;
1171            }else{
1172                var modalLeftPosition = clickPosLeft-modalWidth-100;
1173            }
1174
1175            // calculate free top position
1176            if(modalHeight > height) {
1177                var modalTopPosition = parentTop;
1178            }
1179            else if((height-clickPosTop) < modalHeight) {
1180                var modalTopPosition = height - (modalHeight+100);
1181            }else{
1182                var modalTopPosition = clickPosTop-(modalHeight/2);
1183            }
1184        }else{
1185            var modalLeftPosition = (width/2)-(modalWidth/2)-10;
1186            var modalTopPosition = (height/2)-($(modalContext).height()/2)-10;
1187        }
1188
1189		// modal body hide by position
1190		$(modalContext)
1191			.css('top', -(modalHeight+5)+'px')
1192			.css('left', modalLeftPosition+'px');
1193
1194        // without onhover action (close modal)
1195        keyBinder(27, function() {
1196            if(is_open('popup', parentElement)) {
1197                closePopup(parentElement);
1198                $(document.body).unbind('keydown');
1199            }
1200        });
1201
1202        // on hover action (close modal)
1203        $(parentElement).hover(function() {
1204            if($(this).is(':hover') && is_open('popup', parentElement)) {
1205                keyBinder(27, function() {
1206                    closePopup(parentElement);
1207                });
1208            }
1209        },function() {
1210            $(document).unbind('keydown');
1211        });
1212
1213		// animate modal body
1214		$(modalContext).animate(
1215				{
1216					'top': modalTopPosition+'px',
1217					'opacity': '1'
1218				},
1219				{
1220					duration: 'slow',
1221					easing: 'easeOutElastic'
1222				}
1223			)
1224            .bind('mousedown', function(e) {
1225
1226                // if mouse down event is not either easy-modal, or modalContext
1227                // or modal form stop modal move
1228                if(! $(e.target).is('div.easy-modal') && !$(e.target).is('div.modalContext') && !$(e.target).is('form')) {
1229                    e.stopPropagation();
1230                    return;
1231                }
1232
1233                var pinParent = $(e.currentTarget).closest('.pinParent');
1234                var downPageY = e.pageY-$(e.currentTarget).offset().top;
1235                var downPageX = e.pageX-$(e.currentTarget).offset().left;
1236
1237                $(pinParent).bind('mousemove', function(e) {
1238
1239                    $(modalContext).css({
1240                        position: 'absolute',
1241                        top: setPx((e.pageY-parentElement.offset().top)-downPageY),
1242                        left: setPx((e.pageX-parentElement.offset().left)-downPageX)
1243                    });
1244
1245                });
1246            })
1247            .bind('mouseup', function(e) {
1248                var pinParent = $(e.currentTarget).closest('.pinParent');
1249                $(pinParent).unbind('mousemove');
1250            });
1251
1252		$('.easy-submit', modalContext)
1253			.click(function() {
1254
1255                var lat = $(markerContainer).attr($.fn.easypin.defaults.xAttribute);
1256                var long = $(markerContainer).attr($.fn.easypin.defaults.yAttribute);
1257                var ImgWidth = $(markerContainer).attr($.fn.easypin.defaults.widthAttribute);
1258                var ImgHeight = $(markerContainer).attr($.fn.easypin.defaults.heightAttribute);
1259                var markerIndex = $(markerContainer).attr('data-index');
1260                var parentId = $('.easypin-target', parentElement).attr('easypin-id');
1261
1262                // check the form exists
1263                var formExists = $('form', modalContext).size() > 0;
1264
1265                if(formExists) {
1266                    var modalBody = $('form', modalContext); // form instance
1267                }else{
1268                    var modalBody = $('.easy-modal', modalContext); // current modal instance
1269                }
1270
1271                // run callback function
1272                if(typeof($.fn.easypin.defaults.done) == 'function') {
1273
1274                    var result = $.fn.easypin.defaults.done(modalBody);
1275
1276                    if(typeof(result) == 'boolean') {
1277
1278                        if(result == true) {
1279
1280                            closePopup(parentElement);
1281                        }else{
1282                            return;
1283                        }
1284
1285                    }else{
1286                        closePopup(parentElement);
1287                    }
1288                }
1289
1290                var formData = getFormData(modalBody, function(data) {
1291
1292                    data['coords'] = new Object();
1293
1294                    data.coords['lat'] = lat;
1295                    data.coords['long'] = long;
1296                    data.coords['canvas'] = new Object();
1297                    data.coords.canvas['src'] = $(targetImage).attr('src');
1298                    data.coords.canvas['width'] = ImgWidth;
1299                    data.coords.canvas['height'] = ImgHeight;
1300
1301                    return data;
1302                });
1303
1304                dataInsert(parentId, markerIndex, formData);
1305
1306                createPopover(markerContainer, formData);
1307
1308			});
1309
1310            return modalContext;
1311	};
1312
1313    var dataInsert = function(parentId, markerIndex, data) {
1314
1315        if(localStorage) {
1316            storageInsert(parentId, markerIndex, data);
1317        }else{
1318            inputInsert(parentId, markerIndex, data);
1319        }
1320    };
1321
1322    // local storage
1323    var storageInsert = function(parentId, markerIndex, data) {
1324
1325        var items = localStorage.getItem('easypin');
1326
1327        if(! items) {
1328            var items = new Object();
1329        }else{
1330            try {
1331                var items = JSON.parse(items);
1332            }catch(e) {
1333                var items = new Object();
1334            }
1335        }
1336
1337        var items = setNestedObject(parentId, markerIndex, items);
1338
1339        if(typeof(items[parentId]['canvas']) == 'undefined') {
1340            items[parentId]['canvas'] = data.coords.canvas;
1341        }
1342
1343        delete data.coords.canvas;
1344
1345        if(typeof(data['canvas']) != 'undefined') {
1346            items[parentId]['canvas'] = data.canvas;
1347            delete data.canvas;
1348        }
1349
1350        items[parentId][markerIndex] = data;
1351
1352        localStorage.setItem('easypin', toJsonString(items));
1353    };
1354
1355    // stores in hidden field
1356    var inputInsert = function(parentId, markerIndex, data) {
1357
1358        var items = $('input[name="easypin-store"]').val();
1359
1360        if(! items) {
1361            var items = new Object();
1362        }else{
1363            try {
1364                var items = JSON.parse(decodeURIComponent(items));
1365            }catch(e) {
1366                var items = new Object();
1367            }
1368        }
1369
1370        var items = setNestedObject(parentId, markerIndex, items);
1371
1372        if(typeof(items[parentId]['canvas']) == 'undefined') {
1373            items[parentId]['canvas'] = data.coords.canvas;
1374        }
1375
1376        delete data.coords.canvas;
1377
1378        if(typeof(data['canvas']) != 'undefined') {
1379            items[parentId]['canvas'] = data.canvas;
1380            delete data.canvas;
1381        }
1382
1383        items[parentId][markerIndex] = data;
1384
1385        if($('input[name="easypin-store"]').size() < 1) {
1386            $(setClass($.fn.easypin.defaults.parentClass)+':first').before('<input type="hidden" name="easypin-store" value="'+encodeURIComponent(toJsonString(items))+'" />');
1387        }else{
1388            $('input[name="easypin-store"]').val(encodeURIComponent(toJsonString(items)));
1389        }
1390    };
1391
1392    var dataUpdate = function(parentId, markerIndex, data) {
1393        if(localStorage) {
1394            storageUpdate(parentId, markerIndex, data);
1395        }else{
1396            inputUpdate(parentId, markerIndex, data);
1397        }
1398    };
1399
1400    var storageUpdate = function(parentId, markerIndex, data) {
1401
1402        var items = localStorage.getItem('easypin');
1403
1404        if(items) {
1405
1406            try {
1407                var items = JSON.parse(items);
1408                items = setNestedObject(parentId, markerIndex, items);
1409                items[parentId][markerIndex] = merge(items[parentId][markerIndex], data);
1410                localStorage.setItem('easypin', toJsonString(items));
1411            }catch(e) {
1412                return false;
1413            }
1414        }
1415    };
1416
1417    var inputUpdate = function(parentId, markerIndex, data) {
1418
1419        var items = $('input[name="easypin-store"]').val();
1420
1421        if(items) {
1422
1423            try {
1424                var items = JSON.parse(decodeURIComponent(items));
1425                items = setNestedObject(parentId, markerIndex, items);
1426                items[parentId][markerIndex] = merge(items[parentId][markerIndex], data);
1427                $('input[name="easypin-store"]').val(encodeURIComponent(toJsonString(items)));
1428            }catch(e) {
1429                return false;
1430            }
1431        }
1432    };
1433
1434    /**
1435     * Remove data container function
1436     *
1437     * @param parentIndex int
1438     * @param markerIndex int
1439     */
1440    var dataRemove = function(parentId, markerIndex) {
1441
1442        if(localStorage) {
1443            removeFromStorage(parentId, markerIndex);
1444        }else{
1445            removeFromInput(parentId, markerIndex);
1446        }
1447
1448    };
1449
1450    /**
1451     * Remove data on input hidden field
1452     * @param  {[int]} parentIndex [parent container index]
1453     * @param  {[int]} markerIndex [marker container index]
1454     * @return {[void]}
1455     */
1456    var removeFromInput = function(parentId, markerIndex) {
1457
1458        var items = $('input[name="easypin-store"]').val();
1459        if(items) {
1460            try {
1461                var items = JSON.parse(decodeURIComponent(items));
1462
1463                items = removeHelper(parentId, markerIndex, items)
1464
1465                var totalPin = $('input[name="easypin-store"]').size();
1466                if(totalPin < 1) {
1467                    $(setClass($.fn.easypin.defaults.parentClass)+':first').before('<input type="hidden" name="easypin-store" value="'+encodeURIComponent(toJsonString(items))+'" />');
1468                }else{
1469                    $('input[name="easypin-store"]').val(encodeURIComponent(toJsonString(items)));
1470                }
1471
1472            } catch (e) {}
1473
1474        }
1475
1476    };
1477
1478    /**
1479     * Remove from local storage
1480     *
1481     * @param parentIndex int
1482     * @param markerIndex int
1483     * @return void
1484     */
1485    var removeFromStorage = function(parentId, markerIndex) {
1486
1487        var items = localStorage.getItem('easypin');
1488
1489        if(items) {
1490
1491            try {
1492                var items = JSON.parse(items);
1493
1494                localStorage.setItem('easypin', toJsonString(removeHelper(parentId, markerIndex, items)));
1495
1496            }catch(e) {}
1497
1498        }
1499
1500    };
1501
1502    /**
1503     * Remove process from data object
1504     *
1505     * @param  {[int]} parentIndex [parent container index]
1506     * @param  {[int]} markerIndex [marker container index]
1507     * @param  {[object]} items       [data object]
1508     * @return {[object]}
1509     */
1510    var removeHelper = function(parentId, markerIndex, items) {
1511
1512        if(parentId && !markerIndex) {
1513
1514            if(typeof(items[parentId]) != 'undefined') {
1515                delete items[parentId];
1516            }
1517
1518        }
1519
1520        if(parentId && markerIndex) {
1521
1522            if(typeof(items[parentId][markerIndex]) != 'undefined') {
1523                delete items[parentId][markerIndex];
1524
1525                if(sizeof(items[parentId]) < 1 || (sizeof(items[parentId]) == 1 && typeof(items[parentId]['canvas']) != 'undefined')) {
1526                    delete items[parentId];
1527                }
1528            }
1529
1530        }
1531
1532        return items;
1533    };
1534
1535    // set nested object
1536    /**
1537     * Set nested object
1538     * @param  int parentIndex parent container index
1539     * @param  int markerIndex marker ocntainer index
1540     * @param  int items       data object
1541     * @return object
1542     */
1543    var setNestedObject = function(parentId, markerIndex, items) {
1544
1545        if(typeof(items[parentId]) == 'undefined') {
1546            items[parentId] = new Object();
1547        }
1548
1549        if(typeof(items[parentId][markerIndex]) == 'undefined') {
1550            items[parentId][markerIndex] = new Object();
1551        }
1552
1553        return items;
1554    };
1555
1556    var getItem = function(parentIndex, markerIndex) {
1557
1558        if(localStorage) {
1559            var items = localStorage.getItem('easypin');
1560
1561            try {
1562                items = JSON.parse(items);
1563            } catch (e) {
1564                items = {};
1565            }
1566        }else{
1567            var items = $('input[name="easypin-store"]').val();
1568
1569            try {
1570                items = JSON.parse(decodeURIComponent(items));
1571            } catch (e) {
1572                items = {};
1573            }
1574        }
1575
1576        try {
1577            return items[parentIndex][markerIndex];
1578        } catch (e) {
1579            return null;
1580        }
1581    };
1582
1583    // get values of current modal
1584    var getFormData = function(element, callback) {
1585
1586        var elements = new Object();
1587
1588        $('input, select, textarea', element).each(function() {
1589
1590            var elementType = $(this).attr('type');
1591            var elementName = $(this).attr('name');
1592
1593            if(elementType == 'radio') {
1594
1595                var checked = $(this).filter(":checked").val();
1596
1597                if(typeof(checked) != 'undefined' && typeof(elements[elementName]) == 'undefined') {
1598                    elements[elementName] = checked;
1599                }
1600            }
1601
1602            else if(elementType == 'checkbox') {
1603
1604                if($(this).is(':checked')) {
1605                    elements[elementName] = $(this).val();
1606                }
1607            }
1608            else{
1609                if(typeof($(this).val()) != 'undefined') {
1610                    elements[elementName] = $(this).val();
1611                }
1612            }
1613
1614        });
1615
1616        if(typeof(callback) == 'function') {
1617
1618            var args = new Array();
1619            args.push(elements);
1620            return callback.apply(null, args);
1621
1622        }
1623
1624        return elements;
1625    };
1626
1627    var toJsonString = function(data) {
1628        return JSON.stringify(data);
1629    };
1630
1631    // modal close
1632	var closePopup = function(parentElement) {
1633
1634		// close opacity layer
1635		$(setClass($.fn.easypin.defaults.popupOpacityLayer), parentElement)
1636			.animate(
1637				{
1638					opacity:0
1639				},
1640				'fast', // how fast we are animating
1641				'swing', // the type of easing
1642				function() {
1643					$(this).remove();
1644				}
1645			);
1646
1647		var modalHeight = $('.modalContext', parentElement).height();
1648		var modalWidth = $('.modalContext', parentElement).width();
1649
1650		// animate modal body
1651		$('.modalContext', parentElement).animate(
1652				{
1653					'top': -(modalHeight+50)+'px',
1654					'opacity': '0',
1655					'z-index': 0
1656				},
1657				{
1658					duration: 'slow',
1659					easing: 'easeOutElastic',
1660					complete: function() {
1661						$('.modalParent', parentElement).remove();
1662					}
1663				}
1664			);
1665	};
1666
1667    var keyBinder = function(expectCode, callback) {
1668
1669        $(document).bind('keydown', function(e) {
1670
1671            if(e.which == expectCode) {
1672
1673                callback.apply(null);
1674
1675                $(this).unbind('keydown');
1676            }
1677        });
1678    };
1679
1680    var setIndex = function(selector, parent) {
1681
1682        var index = $(selector+':last', parent).attr('data-index');
1683
1684        if(typeof(index) == 'undefined') {
1685            return '0';
1686        }
1687
1688        return parseInt(index)+1;
1689    };
1690
1691    var sizeof = function(data) {
1692        if(typeof(data) == 'object') {
1693            var j = 0;
1694
1695            for(var i in data) {
1696                j++;
1697            }
1698
1699            return j;
1700        }
1701    };
1702
1703    /**
1704     * Set to input fields all data
1705     * @param  int parentIndex   parent container index
1706     * @param  int markerIndex   marker container index
1707     * @param  object modalInstance current modal instance
1708     * @return void
1709     */
1710    var setDataToFields = function(parentId, markerIndex, modalInstance) {
1711
1712        var item = getItem(parentId, markerIndex);
1713
1714        if(typeof(item) == 'object') {
1715
1716            for(var i in item) {
1717
1718                var element = $('[name="'+i+'"]', modalInstance);
1719                var type = $(element).prop('type');
1720
1721                if(type == 'text' || type == 'hidden') {
1722                    $(element).attr('value', item[i]);
1723                }
1724
1725                else if(type == 'checkbox') {
1726                    $(element).attr('checked', true);
1727                }
1728
1729                else if(type == 'radio') {
1730                    $('[value="'+item[i]+'"]', modalInstance).attr('checked', true);
1731                }
1732
1733                else if(type == 'textarea') {
1734                    $(element).val(item[i]);
1735                }
1736
1737                else if(type == 'select-one') {
1738                    $(element).val(item[i]).prop('selected', true);
1739                }
1740
1741            }
1742
1743        }
1744    };
1745
1746    var createPopover = function(markerContainer, formData) {
1747
1748        // check and set popover callbacks
1749        var popoverCallBacks = sizeof($.fn.easypin.defaults.popover) > 0 ? $.fn.easypin.defaults.popover : false;
1750
1751        var arrow = $('<div/>')
1752            .addClass('popover-arrow-down')
1753            .css({
1754                width: 0,
1755            	height: 0,
1756            	'border-left': '10px solid transparent',
1757            	'border-right': '10px solid transparent',
1758            	'border-top': '10px solid #000',
1759                'opacity': '.8',
1760                position: 'absolute',
1761                bottom: '-50px',
1762                left: '58px'
1763            });
1764
1765        var tooltipContainer = $('<div/>')
1766            .addClass('popover')
1767            .css('position', 'absolute')
1768            .css('display','inline')
1769            .css('top', '-51px')
1770            .css('left', '-51px')
1771            .css('opacity', '0');
1772
1773        var popoverHtml = $('[popover]:last').clone();
1774        popoverHtml.removeAttr('popover');
1775        var toHtml = popoverHtml.html();
1776        var popoverUserWidth = popoverHtml.attr('width') ? popoverHtml.attr('width') : 150;
1777
1778        var defaultStyle = {
1779            color: '#FFFFFF',
1780            background: '#000000',
1781            opacity: '.8',
1782            height: 'auto',
1783            'line-height': '40px',
1784            'border-radius': '5px',
1785            cursor: 'context-menu'
1786        };
1787
1788        if(typeof($.fn.easypin.defaults.popoverStyle) == 'object') {
1789            delete $.fn.easypin.defaults.popoverStyle.width;
1790            delete $.fn.easypin.defaults.popoverStyle.position;
1791            popoverStyle = merge(defaultStyle, $.fn.easypin.defaults.popoverStyle);
1792        }else{
1793            popoverStyle = defaultStyle;
1794        }
1795
1796        var span = $('<span/>')
1797            .addClass('popoverContent')
1798            .css({
1799                position: 'absolute',
1800                width:setPx(popoverUserWidth)
1801            })
1802            .css(popoverStyle);
1803
1804        var bgColor = $(span).css('background-color');
1805
1806        $(arrow).css('border-top-color', bgColor);
1807
1808        if(popoverHtml.attr('shadow') == 'true') {
1809            $(span)
1810                .css({
1811                    '-webkit-box-shadow': '10px 13px 5px 0px rgba(0,0,0,0.75)',
1812                    '-moz-box-shadow': '10px 13px 5px 0px rgba(0,0,0,0.75)',
1813                    'box-shadow': '10px 13px 5px 0px rgba(0,0,0,0.75)'
1814                });
1815        }
1816
1817        // delete canvas parameters
1818        delete formData['canvas'];
1819
1820        for(var i in formData) {
1821
1822            // callback check and run
1823            if(popoverCallBacks && typeof(popoverCallBacks[i]) == 'function') {
1824                var args = new Array();
1825                args.push(formData[i]);
1826                formData[i] = popoverCallBacks[i].apply(null, args);
1827            }
1828
1829            var pattern = RegExp("\\{\\["+i+"\\]\\}", "g");
1830            toHtml = toHtml.replace(pattern,formData[i]);
1831
1832        }
1833
1834        $(span).append(toHtml);
1835        $(tooltipContainer).append(span).append(arrow);
1836
1837        // remove previous popover
1838        if($('div.popover', markerContainer).size() > 0) {
1839            // animate modal body
1840    		$('div.popover', markerContainer).animate(
1841    				{
1842    					'top': '-'+setPx((popoverHeight-15)),
1843    					'opacity': '0'
1844    				},
1845    				{
1846    					duration: 'slow',
1847    					easing: 'easeOutElastic',
1848    					complete: function() {
1849    						$(this).remove();
1850    					}
1851    				}
1852    			);
1853        }
1854
1855        // popover element apend yo marker container
1856        $(markerContainer).prepend(tooltipContainer);
1857
1858        var popoverEl = $('div.popover > span:first', markerContainer);
1859        var popoverHeight = popoverEl.height();
1860        var popoverWidth = popoverEl.width();
1861
1862        // set popover container position
1863        $(tooltipContainer)
1864            .css('top', '-'+setPx((popoverHeight+12)-10))
1865            .css('left', '-'+setPx((popoverWidth/2)-16));
1866
1867        // set arrow position
1868        $(arrow, tooltipContainer)
1869            .css('left', setPx((popoverWidth/2)-10))
1870            .css('top', setPx(popoverHeight));
1871
1872        // animate modal body
1873        $(tooltipContainer).animate(
1874                {
1875                    'top': '-'+setPx((popoverHeight+12)),
1876                    'opacity': '1'
1877                },
1878                {
1879                    duration: 'slow',
1880                    easing: 'easeOutElastic'
1881                }
1882            );
1883    };
1884
1885    var initPin = function(imgIndex, element) {
1886
1887        var initData = $.fn.easypin.defaults.init;
1888        var config = getConfigs();
1889
1890        if(typeof(initData) == 'string') {
1891            initData = JSON.parse(initData)
1892        }
1893
1894        var parentElement = $(element).parents(setClass(config.parentClass));
1895
1896        if(sizeof(initData) > 0 && $(element).attr('easypin-init') != 'false') {
1897
1898            // canvas border width
1899            var dashWidth = $.fn.easypin.defaults.dashWidth;
1900
1901            // get x, y balance value
1902            var posYBalance = config.posYBalance;
1903            var posXBalance = config.posXBalance;
1904
1905            // get current target image instance
1906            var targetImage = $('img'+setClass('easypin-target'), parentElement);
1907
1908            if(typeof(initData[imgIndex]) == 'undefined') {
1909                return;
1910            }
1911
1912            for(var i in initData[imgIndex]) {
1913
1914                if(isNaN(i) === true) return;
1915
1916                var imageWidth = parseInt(initData[imgIndex].canvas.width);
1917                var imageHeight = parseInt(initData[imgIndex].canvas.height);
1918                var lat = parseInt(initData[imgIndex][i].coords.lat);
1919                var long = parseInt(initData[imgIndex][i].coords.long);
1920                // set cursor position coordinate
1921                var imagePositionY = targetImage.offset().top - (config.dashWidth-posYBalance);
1922                var imagePositionX = targetImage.offset().left - (config.dashWidth-posXBalance);
1923
1924                var clickPosX = lat;//(lat-imagePositionX);
1925                var clickPosY = long;//(long-imagePositionY);
1926                // get marker half size (width/height)
1927                var markerWidthHalf = (config.markerWidth/2);
1928                var markerHeightHalf = (config.markerHeight/2);
1929
1930                // set canvas border position
1931                var markerBorderX = clickPosX-(config.markerWidth/2);
1932                var markerBorderY = clickPosY-(config.markerHeight/2);
1933
1934                if(markerBorderX < 0) {
1935                    markerBorderX = 0;
1936                }
1937                else if(clickPosX+markerWidthHalf > imageWidth) {
1938                    markerBorderX = imageWidth-config.markerWidth;
1939                }
1940
1941                if(markerBorderY < 0) {
1942                    markerBorderY = 0;
1943                }
1944                else if(clickPosY+markerHeightHalf > imageHeight) {
1945                    markerBorderY = imageHeight-config.markerHeight;
1946                }
1947
1948                var absX = markerBorderX.toFixed(3)-markerWidthHalf;
1949                var absY = markerBorderY.toFixed(3)-markerHeightHalf;
1950
1951                // create tool
1952                var tools = createTools({
1953                    markerWidth: config.markerWidth,
1954                    markerHeight: config.markerHeight
1955                });
1956
1957                // create marker container
1958                var markerContainer = createMarker({
1959                    tools: tools,
1960                    parentElement: parentElement,
1961                    markerClass: config.markerClass,
1962                    markerBorderX: markerBorderX,
1963                    markerBorderY: markerBorderY,
1964                    marginLeft: (config.markerWidth/2),
1965                    marginTop: -(config.markerHeight/2),
1966                    markerWidth: config.markerWidth,
1967                    markerHeight: config.markerHeight,
1968                    markerContainerZindex: config.markerContainerZindex,
1969                    absX: absX,
1970                    absY: absY,
1971                    imageWidth: imageWidth,
1972                    imageHeight: imageHeight,
1973                    parentElement: parentElement,
1974                    src: config.src
1975                });
1976
1977                var markerIndex = $(markerContainer).attr('data-index');
1978                var markerData = merge(initData[imgIndex][i], {'canvas': initData[imgIndex]['canvas']});
1979
1980                dataInsert(imgIndex, markerIndex, markerData);
1981                createPopover(markerContainer, initData[imgIndex][i]);
1982            }
1983        }
1984    };
1985
1986    var createRandomId = function() {
1987        var length = 10;
1988        var strings = 'abcdefghijklmnoprstuvyzABCDEFGHIJKLMNOPRSTUVYZ1234567890_';
1989
1990        var key = '';
1991
1992        for(var i = 1; i<=length; i++) {
1993
1994            var randNum = Math.floor(Math.random() * (strings.length - 1 + 1) + 1);
1995
1996            if(typeof(strings[randNum]) != 'undefined') {
1997                key += strings[randNum];
1998            }
1999
2000        }
2001
2002        return key;
2003    };
2004
2005    var getConfigs = function() {
2006
2007        return {
2008            src: $.fn.easypin.defaults.markerSrc,
2009            markerWidth: $.fn.easypin.defaults.markerWidth,
2010            markerHeight: $.fn.easypin.defaults.markerHeight == 'auto' ? $.fn.easypin.defaults.markerWidth : $.fn.easypin.defaults.markerHeight,
2011            markerClass: $.fn.easypin.defaults.markerClass,
2012            parentClass: $.fn.easypin.defaults.parentClass,
2013            markerContainerZindex: $.fn.easypin.defaults.markerContainerZindex,
2014            // canvas border width
2015            dashWidth: $.fn.easypin.defaults.dashWidth,
2016            // get x, y balance value
2017            posYBalance: $.fn.easypin.defaults.posYBalance,
2018            posXBalance: $.fn.easypin.defaults.posXBalance,
2019            // canvas border width
2020            dashWidth: $.fn.easypin.defaults.dashWidth
2021        };
2022    };
2023
2024    /*
2025    * Recursively merge properties of two objects
2026    */
2027    function merge(obj1, obj2) {
2028
2029      for (var p in obj2) {
2030        try {
2031            obj1[p] = obj2[p];
2032
2033        } catch(e) {
2034          // Property in destination object not set; create it and set its value.
2035          obj1[p] = obj2[p];
2036
2037        }
2038      }
2039
2040      return obj1;
2041    }
2042}(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.