PageSourceSearch

https://publichealthgreybruce.on.ca/Resources/libraries/DnnPlugins/10_03_02/dnn.jquery.js?cdv=1351

js publichealthgreybruce.on.ca collected 2026-10-04 00:26:29 UTC 175,814 bytes, 4,342 lines download raw bytes

1(function ($) {
2    $.fn.dnnTabs = function (options) {
3        var opts = $.extend({}, $.fn.dnnTabs.defaultOptions, options),
4        $wrap = this;
5
6        $wrap.each(function () {
7            var showEvent, cookieId;
8            if (this.id) {
9                cookieId = 'dnnTabs-' + this.id;
10                if (opts.selected === -1) {
11                    var cookieValue = dnn.dom.getCookie(cookieId);
12                    if (cookieValue) {
13                        opts.selected = cookieValue;
14                    }
15                    if (opts.selected === -1) {
16                        opts.selected = 0;
17                    }
18                }
19                showEvent = (function (cid) {
20                    return function (event, ui) {
21                        dnn.dom.setCookie(cid, ui.newTab.index(), opts.cookieDays, '/', '', false, opts.cookieMilleseconds);
22                    };
23                })(cookieId);
24            } else {
25                showEvent = function () {
26                };
27            }
28
29            $wrap.tabs({
30                activate: showEvent,
31                active: opts.selected,
32                disabled: opts.disabled,
33                fx: {
34                    opacity: opts.opacity,
35                    duration: opts.duration
36                }
37            });
38
39            if (window.location.hash && window.location.hash != '#') {
40                var substr = window.location.hash.substr(0, 50);
41                $('a[href="' + encodeURI(substr) + '"]', $wrap).trigger('click');
42            }
43
44            // page validation integration - select tab that contain tripped validators
45            if (typeof window.Page_ClientValidate != "undefined" && $.isFunction(window.Page_ClientValidate)) {
46                $wrap.find(opts.validationTriggerSelector).click(function () {
47                    if (!window.Page_ClientValidate(opts.validationGroup)) {
48                        var invalidControl = $wrap.find(opts.invalidItemSelector).eq(0);
49                        var $parent = invalidControl.closest(".ui-tabs-panel");
50                        if ($parent.length > 0) {
51                            var tabId = $parent.attr("id");
52                            $parent.parent().find("a[href='#" + tabId + "']").click();
53                        }
54                    }
55                });
56            };
57        });
58
59        return $wrap;
60    };
61
62    $.fn.dnnTabs.defaultOptions = {
63        opacity: 'toggle',
64        duration: 'fast',
65        validationTriggerSelector: '.dnnPrimaryAction',
66        validationGroup: '',
67        invalidItemSelector: '.dnnFormError[style*="inline"]',
68        regionToToggleSelector: 'fieldset',
69        selected: -1,
70        cookieDays: 0,
71        cookieMilleseconds: 1200000 // twenty minutes
72    };
73
74})(jQuery);
75
76(function ($) {
77    $.fn.dnnConfirm = function (options) {
78        var opts = $.extend({}, $.fn.dnnConfirm.defaultOptions, options),
79        $wrap = this;
80        $wrap.each(function () {
81            var $this = $(this),
82                defaultAction = $this.attr('href'),
83                $dnnDialog;
84
85            if (defaultAction || opts.isButton) {
86                $dnnDialog = $("<div class='dnnDialog'></div>").html(opts.text).dialog(opts);
87                $dnnDialog.parent().find('.ui-dialog-titlebar-close').html('Close');
88                $this.click(function (e, isTrigger) {
89                    if (isTrigger) {
90                        return true;
91                    }
92
93                    if ($dnnDialog.is(':visible')) {
94                        $dnnDialog.dialog("close");
95                        return true;
96                    }
97                    $dnnDialog.dialog({
98                        open: function () {
99                            $('.ui-dialog-buttonpane').find('button:contains("' + opts.noText + '")').addClass('dnnConfirmCancel');
100                        },
101                        draggable: false,
102                        buttons: [
103                        {
104                            text: opts.yesText,
105                            click: function () {
106                                $dnnDialog.dialog("close");
107                                if ($.isFunction(opts.callbackTrue)) {
108                                    opts.callbackTrue.call(this);
109                                }
110                                else {
111                                    if (opts.isButton) {
112                                        $this.trigger("click", [true]);
113                                    }
114                                    else {
115                                        window.location.href = defaultAction;
116                                    }
117                                }
118                            },
119                            'class': opts.buttonYesClass
120                        },
121                        {
122                            text: opts.noText,
123                            click: function () {
124                                $(this).dialog("close");
125                                if ($.isFunction(opts.callbackFalse)) {
126                                    opts.callbackFalse.call(this);
127                                };
128                            },
129                            'class': opts.buttonNoClass
130                        }
131                        ]
132                    });
133
134                    $dnnDialog.dialog('open');
135                    e.preventDefault();
136                    return false;
137                });
138            }
139        });
140        return $wrap;
141    };
142
143    $.fn.dnnConfirm.defaultOptions = {
144        text: 'Are you sure?',
145        yesText: 'Yes',
146        noText: 'No',
147        buttonYesClass: 'dnnPrimaryAction',
148        buttonNoClass: 'dnnSecondaryAction',
149        actionUrl: window.location.href,
150        autoOpen: false,
151        resizable: false,
152        modal: true,
153        title: 'Confirm',
154        classes: {
155            'ui-dialog': 'dnnFormPopup dnnClear',
156        },
157        isButton: false
158    };
159
160})(jQuery);
161
162(function($) {
163    if ($.dnnConfirm) return;
164
165    $.dnnConfirm = function (opts) {
166        var defaultAction = opts.actionUrl ? opts.actionUrl : 'javascript:void(0);';
167        var shadowLink = $('<a href="' + defaultAction + '" />');
168        shadowLink.dnnConfirm(opts).click();
169    };
170})(jQuery);
171
172(function ($) {
173    $.dnnAlert = function (options) {
174        var opts = $.extend({}, $.dnnAlert.defaultOptions, options),
175        $dnnDialog = $("<div class='dnnDialog'></div>").html(opts.text).dialog(opts);
176
177        $dnnDialog.dialog({
178            buttons: [
179                {
180                    text: opts.okText,
181                    "class": opts.buttonOkClass,
182                    click: function () {
183                        $(this).dialog("close");
184                        if ($.isFunction(opts.callback)) {
185                            opts.callback.call(this);
186                        };
187                        return false;
188                    }
189                }
190            ]
191        });
192        $dnnDialog.dialog('open');
193    };
194
195    $.dnnAlert.defaultOptions = {
196        okText: 'Ok',
197        autoOpen: false,
198        resizable: false,
199        modal: true,
200        buttonOkClass: 'dnnPrimaryAction',
201        classes: {
202            'ui-dialog': 'dnnFormPopup dnnClear'
203        }
204    };
205
206})(jQuery);
207
208(function ($) {
209    $.fn.dnnPanels = function (options) {
210        var opts = $.extend({}, $.fn.dnnPanels.defaultOptions, options),
211        $wrap = this;
212
213        $wrap.each(function () {
214            var $this = $(this);
215            if (typeof (opts.onExpand) === "function") {
216                $this.on('onExpand', opts.onExpand);
217            }
218            if (typeof (opts.onHide) === "function") {
219                $this.on('onHide', opts.onHide);
220            }
221            // wire up click event to perform slide toggle
222            $this.find(opts.clickToToggleSelector).click(function (e) {
223                var toggle = $(this).toggleClass(opts.toggleClass).parent().next(opts.regionToToggleSelector).slideToggle(function () {
224                    var visible = $(this).is(':visible');
225                    if (opts.saveState) {
226                        var id = $(toggle).prev().attr("id");
227                        var cookieId = id ? id.replace(/[^a-zA-Z0-9\-]+/g, "") : '';
228                        if (cookieId) {
229                            dnn.dom.setCookie(cookieId, visible, opts.cookieDays, '/', '', false, opts.cookieMilleseconds);
230                        }
231                    }
232                    if (visible) {
233                        $(this).trigger("onExpand");
234                    }
235                    else {
236                        $(this).trigger("onHide");
237                    }
238                });
239
240                e.preventDefault();
241                e.stopImmediatePropagation();
242                return false;
243            });
244
245            function collapsePanel($clicker, $region) {
246                $clicker.removeClass(opts.toggleClass);
247                $region.hide();
248                $this.trigger("onHide");
249            }
250
251            function expandPanel($clicker, $region) {
252                $clicker.addClass(opts.toggleClass);
253                $region.show();
254                $this.trigger("onExpand");
255            }
256
257            // walk over each selector and expand or collapse as necessary
258            $this.find(opts.sectionHeadSelector).each(function (indexInArray, valueOfElement) {
259                var $self = $(valueOfElement),
260                    elementId = $self.attr("id"),
261                    cookieId = elementId ? elementId.replace(/[^a-zA-Z0-9\-]+/g, "") : '',
262                    cookieValue = cookieId ? dnn.dom.getCookie(cookieId) : '',
263                    $clicker = $self.find(opts.clickToToggleIsolatedSelector),
264                    $region = $self.next(opts.regionToToggleSelector),
265                    $parentSeparator = $self.parents(opts.panelSeparatorSelector),
266                    groupPanelIndex = $parentSeparator.find(opts.sectionHeadSelector).index($self);
267
268                // default value
269                var isOpen = false;
270                if ((indexInArray === 0 && opts.defaultState == "first") || // cookie set to true OR first panel
271                    ($parentSeparator.length > 0 && groupPanelIndex === 0 && opts.defaultState == "first") || // grouping is used & its the first panel in its group
272                    (opts.defaultState == "open"))  // default open
273                {
274                    isOpen = true;
275                }
276                if (opts.saveState) {
277                    if (cookieValue == "true") {
278                        isOpen = true;
279                    }
280                    else if (cookieValue == "false") {
281                        isOpen = false;
282                    }
283                }
284
285                if (isOpen) {
286                    expandPanel($clicker, $region);
287                }
288                else {
289                    collapsePanel($clicker, $region);
290                }
291            });
292
293            // page validation integration - expand collapsed panels that contain tripped validators
294            $this.find(opts.validationTriggerSelector).click(function () {
295                if (typeof window.Page_ClientValidate != "undefined" && $.isFunction(window.Page_ClientValidate)) {
296                    if (!window.Page_ClientValidate(opts.validationGroup)) {
297                        $this.find(opts.invalidItemSelector).each(function () {
298                            var $parent = $(this).closest(opts.regionToToggleSelector);
299                            if ($parent.is(':hidden')) {
300                                $parent.prev(opts.sectionHeadSelector).find(opts.clickToToggleIsolatedSelector).click();
301                            }
302                        });
303                    }
304                }
305            });
306        });
307        return $wrap;
308    };
309
310    $.fn.dnnPanels.defaultOptions = {
311        clickToToggleSelector: 'h2.dnnFormSectionHead a',
312        sectionHeadSelector: '.dnnFormSectionHead',
313        regionToToggleSelector: 'fieldset',
314        toggleClass: 'dnnSectionExpanded',
315        clickToToggleIsolatedSelector: 'a',
316        validationTriggerSelector: '.dnnPrimaryAction',
317        invalidItemSelector: '.dnnFormError[style*="inline"]',
318        validationGroup: '',
319        panelSeparatorSelector: '.ui-tabs-panel',
320        cookieDays: 0,
321        cookieMilleseconds: 1200000, // twenty minutes
322        saveState: true,
323        defaultState: 'first' // open | closed | first
324    };
325
326})(jQuery);
327
328(function ($) {
329    $.fn.dnnPreview = function (options) {
330        var opts = $.extend({}, $.fn.dnnPreview.defaultOptions, options),
331        $wrap = this;
332
333        $wrap.each(function () {
334            var $this = $(this);
335            $this.find(opts.linkSelector).click(function (e) {
336                e.preventDefault();
337                var params = "?";
338                var skin, container;
339
340                if (opts.useComboBox) {
341                    var skinComboBox = $('#' + opts.skinSelector);
342                    var containerComboBox = $('#' + opts.containerSelector);;
343
344                    skin = skinComboBox.length ? skinComboBox[0].selectize.getValue() : '';
345                    container = containerComboBox.length ? containerComboBox[0].selectize.getValue() : '';
346                }
347                else {
348                    skin = $this.find(opts.skinSelector).val();
349                    container = $this.find(opts.containerSelector).val();
350                }
351                if (skin) {
352                    params += "SkinSrc=" + skin;
353                }
354                if (container) {
355                    if (skin) {
356                        params += "&";
357                    }
358                    params += "ContainerSrc=" + container;
359                }
360                if (opts.ModuleId) {
361                    if (params !== "?") {
362                        params += "&ModuleID=" + opts.ModuleId;
363                    } else {
364                        params += "ModuleID=" + opts.ModuleId;
365                    }
366                }
367                if (params != "?") {
368                    window.open(encodeURI(opts.baseUrl + params.replace(/.ascx/gi, '')), "skinpreview");
369                }
370                else {
371                    $.dnnAlert({ text: opts.noSelectionMessage, okText: opts.alertOkText, closeText: opts.alertCloseText });
372                }
373            });
374        });
375
376        return $wrap;
377    };
378
379    $.fn.dnnPreview.defaultOptions = {
380        baseUrl: window.location.protocol + "//" + window.location.host + window.location.pathname,
381        linkSelector: 'a.dnnSecondaryAction',
382        skinSelector: '',
383        containerSelector: '',
384        noSelectionMessage: 'Please select a preview option.',
385        alertOkText: 'Ok',
386        alertCloseText: 'close',
387        useComboBox: false
388    };
389
390})(jQuery);
391
392(function ($) {
393    $.fn.dnnExpandAll = function (options) {
394        var opts = $.extend({}, $.fn.dnnExpandAll.defaultOptions, options),
395        $elem = this;
396
397        if (($(opts.targetArea).find(opts.targetSelector + ':visible').length ===
398            $(opts.targetArea).find(opts.targetSelector + opts.targetExpandedSelector + ':visible').length)
399            && !$(this).hasClass('expanded')) {
400            $(this).addClass('expanded').text(opts.collapseText);
401        }
402
403        $elem.click(function (e) {
404            e.preventDefault();
405            var $this = $(this);
406            if ($this.hasClass('expanded')) {
407                $this.removeClass('expanded').text(opts.expandText);
408                $(opts.targetArea).find(opts.targetSelector + opts.targetExpandedSelector + ':visible').click();
409            }
410            else {
411                $this.addClass('expanded').text(opts.collapseText);
412                $(opts.targetArea).find(opts.targetSelector + ':visible').not(opts.targetExpandedSelector).click();
413            }
414
415            //stop event from called again
416            e.stopImmediatePropagation();
417        });
418
419        return $elem;
420    };
421    $.fn.dnnExpandAll.defaultOptions = {
422        expandText: 'Expand All',
423        collapseText: 'Collapse All',
424        targetArea: '#dnnHostSettings',
425        targetSelector: 'h2.dnnFormSectionHead a',
426        targetExpandedSelector: '.dnnSectionExpanded'
427    };
428})(jQuery);
429
430(function ($) {
431    $.fn.dnnTooltip = function (options) {
432        var opts = $.extend({}, $.fn.dnnTooltip.defaultOptions, options),
433        $wrap = this;
434
435        $wrap.each(function () {
436            var $this = $(this),
437                dnnFormHelp = $this.prev();
438            if ($this.data('initialized')) return;
439            dnnFormHelp.on('click', function (e) {
440                e.preventDefault();
441            });
442            var helpSelector = $this.find(opts.helpSelector);
443            $this.parent().css({ position: 'relative' });
444            $this.css({ position: 'absolute', right: '-29%' });
445            var hoverOnToolTip = false, hoverOnPd = false;
446
447            dnnFormHelp.hoverIntent({
448                over: function () {
449                    hoverOnPd = true;
450                    var tooltipHeight = helpSelector.height();
451                    var top = -(tooltipHeight + 30);
452                    if ((tooltipHeight + 30) <= $this.parent().offset().top) {
453                        helpSelector.parent().css({ top: top + 'px' });
454                        $this.find("div.dnnFormHelpContent span").addClass("bottomArrow");
455                        $this.find("div.dnnFormHelpContent span").removeClass("topArrow");
456
457                    } else {
458                        helpSelector.parent().css({ top: 30 + 'px' });                  
459                        $this.find("div.dnnFormHelpContent span").addClass("topArrow");
460                        $this.find("div.dnnFormHelpContent span").removeClass("bottomArrow");
461                    }
462                    helpSelector.css('visibility', 'visible');
463                },
464                out: function () {
465                    hoverOnPd = false;
466                    if (!$this.hasClass(opts.pinnedClass) && !hoverOnToolTip) {
467                        helpSelector.css('visibility', 'hidden');
468                    }
469                },
470                timeout: 200,
471                interval: 200
472            });
473
474            helpSelector.hover(function () { hoverOnToolTip = true; }, function () {
475                hoverOnToolTip = false;
476                if (!$this.hasClass(opts.pinnedClass) && !hoverOnPd) {
477                    helpSelector.css('visibility', 'hidden');
478                }
479            });
480
481            var pinHelper = helpSelector.find(opts.pinSelector);
482
483            pinHelper.on('click', function (e) {
484                e.preventDefault();
485                if ($this.hasClass(opts.pinnedClass)) {
486                    helpSelector.css({ "left": '0', "top": '0' })
487                        .css('visibility', 'hidden')
488                        .draggable('destroy');
489                    $this.removeClass(opts.pinnedClass);
490                }
491                else {
492
493                    $this.addClass(opts.pinnedClass);
494                    if ($.isFunction($().draggable)) {
495                        helpSelector.draggable();
496                    }
497                }
498            });
499
500            $this.data('initialized', 1);
501        });
502
503        return $wrap;
504    };
505
506    $.fn.dnnTooltip.defaultOptions = {
507        pinSelector: 'a.pinHelp',
508        helpSelector: '.dnnFormHelpContent',
509        pinnedClass: 'dnnTooltipPinned'
510    };
511
512})(jQuery);
513
514(function ($) {
515    var cb = function (e) {
516        if (!e) e = window.event;
517        e.cancelBubble = true;
518        if (e.stopPropagation) e.stopPropagation();
519    };
520
521    /* DNN customized checkbox/radiobox */
522    $.fn.dnnCheckbox = function (options) {
523        var settings = {
524            cls: 'dnnCheckbox'  /* checkbox  */
525            , labelClass: 'dnnBoxLabel'
526        };
527        settings = $.extend(settings, options || {});
528
529        var addEvents = function (object) {
530            var checked = object.checked,
531                disabled = object.disabled,
532                $object = $(object);
533
534            if (object.stateInterval)
535                clearInterval(object.stateInterval);
536
537            object.stateInterval = setInterval(
538                function () {
539                    if (object.disabled != disabled)
540                        $object.trigger((disabled = !!object.disabled) ? 'disable' : 'enable');
541                    if (object.checked != checked)
542                        $object.trigger((checked = !!object.checked) ? 'check' : 'uncheck');
543                },
544                10 /* in miliseconds.*/
545            );
546            return $object;
547        };
548
549        return this.each(function () {
550            var ch = this;
551
552            if ($(ch).data("checkBoxWrapped")) {
553                return;
554            }
555            $(ch).data("checkBoxWrapped", true);
556
557            if ($(this).hasClass('normalCheckBox') || $(this).hasClass('normalRadioButton')) return;
558            var parentCheckBoxHolder = $(this).closest('.normalCheckBox');
559            var parentRadioButtonHolder = $(this).closest('.normalRadioButton');
560            if (parentCheckBoxHolder.length || parentRadioButtonHolder.length) return;
561            var $ch = addEvents(ch);
562            if (ch.wrapper) ch.wrapper.remove();
563            ch.wrapper = $('<span class="' + settings.cls + '"><span class="mark"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRFAAAAAAAApWe5zwAAAAF0Uk5TAEDm2GYAAAAMSURBVHjaYmAACDAAAAIAAU9tWeEAAAAASUVORK5CYII=" alt="checkbox" /></span></span>');
564            ch.wrapperInner = ch.wrapper.children('span:eq(0)');
565            ch.wrapper.hover(
566                function (e) { ch.wrapperInner.addClass(settings.cls + '-hover'); cb(e); },
567                function (e) { ch.wrapperInner.removeClass(settings.cls + '-hover'); cb(e); }
568            );
569
570            $ch.css({ position: 'absolute', zIndex: -1, opacity: 0 }).after(ch.wrapper);
571
572            var label, parentLabel = false;
573            label = $ch.closest('label');
574            if (!label.length)
575                label = false;
576            else
577                parentLabel = true;
578
579            if (!label && $ch.attr('id')) {
580                label = $('label[for="' + $ch.attr('id') + '"]');
581                if (!label.length) label = false;
582            }
583
584            if (label) {
585                label.addClass(settings.labelClass);
586                if (!parentLabel) {
587                    label.click(function (e) {
588                        clickHandler(e);
589                        return false;
590                    });
591                }
592                else {
593                    label.children().each(function () {
594                        var $this = $(this);
595                        if ($this.is('input')) return;
596
597                        $this.click(function (e) {
598                            clickHandler(e);
599                            return false;
600                        });
601                    });
602                }
603            }
604
605            if (!parentLabel) {
606                ch.wrapper.click(function (e) {
607                    clickHandler(e);
608                    return false;
609                });
610            }
611
612            function clickHandler(e) {
613                if (ch.disabled) {
614                    return;
615                }
616                $ch.triggerHandler('focus');
617                var previousChecked = ch.checked;
618                ch.click();
619                if (ch.checked == previousChecked && ch.type == 'checkbox') {
620                    ch.checked = !ch.checked;  //Fix for Firefox browser
621                }
622                $ch.trigger('change', [e]);
623                cb(e);
624            }
625
626            $ch.on('disable', function () { ch.wrapperInner.addClass(settings.cls + '-disabled'); }).on('enable', function () { ch.wrapperInner.removeClass(settings.cls + '-disabled'); });
627            $ch.on('check', function () { ch.wrapper.addClass(settings.cls + '-checked'); }).on('uncheck', function () { ch.wrapper.removeClass(settings.cls + '-checked'); });
628            $ch.on('focus', function (e) { if (!e.isTrigger) ch.wrapper.addClass(settings.cls + '-focus'); }).on('blur', function () { ch.wrapper.removeClass(settings.cls + '-focus'); });
629
630            /* Applying checkbox state */
631            if (ch.checked)
632                ch.wrapper.addClass(settings.cls + '-checked');
633            if (ch.disabled)
634                ch.wrapperInner.addClass(settings.cls + '-disabled');
635
636        });
637    };
638
639    $.fn.dnnHelperTipDestroy = function () {
640        return this.each(function () {
641            var pd = this;
642            if (pd.id) {
643                $('div[data-tipholder="' + pd.id + '"]').remove();
644            }
645        });
646    };
647
648    $.fn.dnnHelperTip = function (options) {
649        var settings = {
650            cls: 'dnnHelperTip',
651            helpContent: "This is hover helper tooltip",
652            holderId: '',
653            show: false // immediately show tooltip after call
654        };
655        settings = $.extend(settings, options || {});
656        return this.each(function () {
657            var pd = this,
658                $pd = $(this);
659            if (pd.tooltipWrapper) pd.tooltipWrapper.remove();
660
661            pd.tooltipWrapper = $('<div class="' + settings.cls + '" data-tipholder="' + settings.holderId + '"> <div class="dnnFormHelpContent dnnClear"><span class="dnnHelpText">' + settings.helpContent + '</span></div></div>');
662            $('body').append(pd.tooltipWrapper);
663            pd.tooltipWrapper.css({ position: 'absolute' });
664            pd.tooltipWrapperInner = $('.dnnFormHelpContent', pd.tooltipWrapper);
665
666            var tooltipHeight = pd.tooltipWrapperInner.height();
667            pd.tooltipWrapperInner.css({ left: '-10px', top: -(tooltipHeight + 30) + 'px' });
668            var hoverOnPd = false;
669            $pd.hover(
670                function () {
671                    hoverOnPd = true;
672                    setTimeout(function () {
673                        if (hoverOnPd)
674                            pd.tooltipWrapperInner.css('visibility', 'visible');
675                    }, 400);
676                },
677                function () {
678                    hoverOnPd = false;
679                    setTimeout(function () {
680                        if (!hoverOnPd)
681                            pd.tooltipWrapperInner.css('visibility', 'hidden');
682                    }, 400);
683
684                });
685
686            if (settings.show) {
687                hoverOnPd = true;
688                setTimeout(function () {
689                    pd.tooltipWrapperInner.css('visibility', 'visible');
690                }, 400);
691            }
692
693            $pd.on('mousemove', function (e) {
694                var x = e.pageX; var y = e.pageY;
695                
696                // Fix: Check if tooltip overflows the right edge of the window    
697                var tipWidth = pd.tooltipWrapperInner.outerWidth();    
698                var winWidth = $(window).width();    
699    
700                // Safety buffer of 20px for vertical scrollbar    
701                if ((x + tipWidth) > (winWidth - 20)) {        
702                    // Clamp x position to fit inside the screen        
703                    x = winWidth - tipWidth - 20;     
704                }
705                
706                var pos = $('body').css('position');
707                if (pos == 'relative') y -= 38;
708                pd.tooltipWrapper.css({ left: x + 'px', top: y + 'px', 'z-index': '99999' });
709            });
710        });
711    };
712
713    $.fn.dnnProgressbar = function () {
714        var $pd = $(this),
715            pd = this;
716
717        if (pd.tooltipWrapper) pd.tooltipWrapper.remove();
718        pd.tooltipWrapper = $('<div class="dnnTooltip"> <div class="dnnFormHelpContent dnnClear"><span class="dnnHelpText"></span></div></div>').insertAfter($pd);
719        pd.tooltipWrapperInner = $('.dnnFormHelpContent', pd.tooltipWrapper);
720        pd.tooltipWrapperInner.css({ width: '32px', padding: '7px' });
721        $pd.parent().css({ position: 'relative' });
722
723        var hoverOnToolTip = false, hoverOnPd = false;
724        $pd.hoverIntent({
725            over: function () {
726                hoverOnPd = true;
727                var val = $(this).children(':first').progressbar('value');
728                pd.update(val);
729                pd.tooltipWrapperInner.css('visibility', 'visible');
730
731            },
732            out: function () {
733                hoverOnPd = false;
734                if (!hoverOnToolTip) {
735                    pd.tooltipWrapperInner.css('visibility', 'hidden');
736                }
737            },
738            timeout: 200,
739            interval: 200
740        });
741
742        pd.tooltipWrapperInner.hover(function () { hoverOnToolTip = true; }, function () {
743            hoverOnToolTip = false;
744            if (!hoverOnPd) {
745                pd.tooltipWrapperInner.hide();
746            }
747        });
748
749        pd.update = function (value) {
750            pd.tooltipWrapperInner.find('span').html(value + ' %');
751            var pdTop = $pd.position().top,
752			    tooltipHeight = pd.tooltipWrapperInner.height();
753
754            pdTop -= (tooltipHeight + 10);
755            var pdLeft = value > 50 ? (value - 4) + '%' : value > 0 ? (value - 2) + '%' : '10px';
756            pd.tooltipWrapper.css({ position: 'absolute', left: pdLeft, top: pdTop + 'px' });
757        };
758
759        return this;
760    };
761
762    $.fn.dnnSpinner = function (options) {
763        var opt = $.extend({
764            type: 'range',
765            typedata: '',
766            width: '150px',
767            looping: false
768        }, options);
769
770        var otypedata;
771
772        if (options != null && options.typedata != null) {
773            otypedata = $.extend({
774                min: 1,
775                max: 10,
776                interval: 1,
777                decimalplaces: 0
778            }, options.typedata);
779        }
780        else {
781            otypedata = $.extend({
782                min: 1,
783                max: 10,
784                interval: 1,
785                decimalplaces: 0
786            });
787        }
788        opt.typedata = otypedata;
789
790        var inputControl = this;
791        if (!inputControl.is(':text'))
792            return inputControl;
793
794        if (inputControl.hasClass('dnnSpinnerInput')) {
795            return inputControl;
796        }
797        else {
798            inputControl.addClass('dnnSpinnerInput');
799        }
800
801        var strContainerDiv = '';
802        strContainerDiv += '<div class="dnnSpinner">';
803        strContainerDiv += '<div class="dnnSpinnerDisplay"></div>';
804        strContainerDiv += '<div class="dnnSpinnerCtrl">';
805        strContainerDiv += '<a class="dnnSpinnerTopButton"></a>';
806        strContainerDiv += '<a class="dnnSpinnerBotButton"></a>';
807        strContainerDiv += '</div></div>';
808        var objContainerDiv = $(strContainerDiv).insertAfter(inputControl);
809        inputControl.insertAfter($("div.dnnSpinnerDisplay", objContainerDiv));
810        $("div.dnnSpinnerDisplay", objContainerDiv).click(function () {
811            if (opt.type === 'range') {
812                var displayCtrl = $(this);
813                var innerInput = $('input[type="text"]', displayCtrl);
814                if (innerInput.length < 1) {
815                    var originalVal = displayCtrl.html();
816                    innerInput = $('<input type="text" />').val(originalVal);
817                    displayCtrl.html(innerInput);
818                    innerInput.blur(function () {
819                        var newVal = $(this).val();
820                        if (newVal > opt.typedata.max) {
821                            newVal = opt.typedata.max;
822                        }
823                        if (newVal < opt.typedata.min) {
824                            newVal = opt.typedata.min;
825                        }
826                        $(this).remove();
827                        selectedValue = parseInt(newVal);
828                        inputControl.val(newVal);
829                        displayCtrl.text(newVal);
830                    }).keypress(function (e) {
831                        var regex = new RegExp("^[0-9]+$");
832                        var key = String.fromCharCode(!e.charCode ? e.which : e.charCode);
833                        if (!regex.test(key)) {
834                            event.preventDefault();
835                            return false;
836                        }
837                        return true;
838                    });
839                }
840                innerInput.focus();
841            }
842
843            inputControl.triggerHandler('focus');
844        });
845        inputControl.css('display', 'none');
846
847        switch (opt.type) {
848            case 'range':
849                if (opt.defaultVal < opt.typedata.min || opt.defaultVal > opt.typedata.max) {
850                    opt.defaultVal = opt.typedata.min;
851                }
852                if (opt.defaultVal % opt.typedata.interval > 0) {
853                    opt.defaultVal = parseInt((opt.defaultVal / opt.typedata.interval).toFixed(0)) * opt.typedata.interval;
854                }
855                inputControl.val(opt.defaultVal.toFixed(opt.typedata.decimalplaces));
856                ($("div.dnnSpinnerDisplay", objContainerDiv)).html(opt.defaultVal.toFixed(opt.typedata.decimalplaces));
857                var selectedValue = opt.defaultVal;
858                if ((opt.typedata.max - opt.typedata.min) > opt.typedata.interval) {
859                    $("a.dnnSpinnerTopButton", objContainerDiv).click(function () {
860
861                        if ((selectedValue + opt.typedata.interval) <= opt.typedata.max || opt.looping) {
862                            if ((selectedValue + opt.typedata.interval) > opt.typedata.max) {
863                                selectedValue = opt.typedata.min - opt.typedata.interval;
864                            }
865                            var valueData = (selectedValue + opt.typedata.interval).toFixed(opt.typedata.decimalplaces);
866                            selectedValue += opt.typedata.interval;
867                            ($("div.dnnSpinnerDisplay", objContainerDiv)).html(valueData);
868                            inputControl.val(valueData);
869                        }
870                        inputControl.triggerHandler('focus');
871                        return false;
872                    });
873
874                    $("a.dnnSpinnerBotButton", objContainerDiv).click(function () {
875                        if ((selectedValue - opt.typedata.interval) >= opt.typedata.min || opt.looping) {
876                            if ((selectedValue - opt.typedata.interval) < opt.typedata.min) {
877                                selectedValue = opt.typedata.max + opt.typedata.interval;
878                            }
879                            var valueData = (selectedValue - opt.typedata.interval).toFixed(opt.typedata.decimalplaces);
880                            selectedValue -= opt.typedata.interval;
881                            ($("div.dnnSpinnerDisplay", objContainerDiv)).html(valueData);
882                            inputControl.val(valueData);
883                        }
884                        inputControl.triggerHandler('focus');
885                        return false;
886                    });
887                }
888
889                break;
890            case 'list':
891                if (!opt.typedata.list || opt.typedata.list.lenght == 0) {
892                    return inputControl;
893                }
894
895                var listItems = opt.typedata.list.split(',');
896                var selectedIndex = jQuery.inArray(opt.defaultVal, listItems);
897                if (selectedIndex < 0) {
898                    selectedIndex = 0;
899                    opt.defaultVal = listItems[0];
900                }
901
902                inputControl.val(opt.defaultVal);
903                ($("div.dnnSpinnerDisplay", objContainerDiv)).html(opt.defaultVal);
904
905                if (listItems.length > 1) {
906                    // attach events;
907                    $("a.dnnSpinnerBotButton", objContainerDiv).click(function () {
908                        if (selectedIndex < (listItems.length - 1) || opt.looping) {
909                            if (selectedIndex == listItems.length - 1) {
910                                selectedIndex = -1;
911                            }
912                            selectedIndex++;
913                            var valueData = listItems[selectedIndex];
914                            ($("div.dnnSpinnerDisplay", objContainerDiv)).html(valueData);
915                            inputControl.val(valueData);
916                        }
917                        inputControl.triggerHandler('focus');
918                        return false;
919                    });
920
921                    $("a.dnnSpinnerTopButton", objContainerDiv).click(function () {
922                        if (selectedIndex > 0 || opt.looping) {
923                            if (selectedIndex == 0) {
924                                selectedIndex = listItems.length;
925                            }
926                            selectedIndex--;
927                            var valueData = listItems[selectedIndex];
928                            ($("div.dnnSpinnerDisplay", objContainerDiv)).html(valueData);
929                            inputControl.val(valueData);
930                        }
931                        inputControl.triggerHandler('focus');
932                        return false;
933                    });
934                }
935
936                break;
937        };
938        return inputControl;
939    };
940})(jQuery);
941
942(function ($) {
943    $.fn.dnnAutocomplete = function (options) {
944        var url;
945        if (arguments.length > 1) {
946            url = options;
947            options = arguments[1];
948            options.url = url;
949        } else if (typeof options === 'string') {
950            url = options;
951            options = { url: url };
952        }
953        var opts = $.extend({}, $.fn.dnnAutocomplete.defaults, options);
954        return this.each(function () {
955            var $this = $(this);
956            $this.data('autocompleter', new $.dnnAutocompleter(
957                $this,
958                $.meta ? $.extend({}, opts, $this.data()) : opts
959            ));
960        });
961    };
962
963    $.fn.dnnAutocomplete.defaults = {
964        inputClass: 'dnn_acInput',
965        loadingClass: 'dnn_acLoading',
966        resultsClass: 'dnn_acResults',
967        selectClass: 'dnn_acSelect',
968        queryParamName: 'q',
969        contentTypeParamName: 'contentTypeId',
970        extraParams: {},
971        remoteDataType: false,
972        lineSeparator: '\n',
973        cellSeparator: '|',
974        minChars: 2,
975        maxItemsToShow: 10,
976        delay: 400,
977        useCache: false,
978        maxCacheLength: 10,
979        matchSubset: true,
980        matchCase: false,
981        matchInside: true,
982        mustMatch: false,
983        selectFirst: false,
984        selectOnly: false,
985        showResult: null,
986        preventDefaultReturn: 1,
987        preventDefaultTab: 0,
988        autoFill: false,
989        filterResults: true,
990        sortResults: true,
991        sortFunction: null,
992        onItemSelect: null,
993        onNoMatch: null,
994        onFinish: null,
995        matchStringConverter: null,
996        beforeUseConverter: null,
997        autoWidth: 'min-width',
998        useDelimiter: false,
999        delimiterChar: ',',
1000        delimiterKeyCode: 188,
1001        processData: null,
1002        onError: null,
1003        moduleId: null // dnn Module Id context if needed
1004    };
1005
1006    var sanitizeResult = function (result) {
1007        var value, data;
1008        var type = typeof result;
1009        if (type === 'string') {
1010            value = result;
1011            data = {};
1012        } else if ($.isArray(result)) {
1013            value = result[0];
1014            data = result.slice(1);
1015        } else if (type === 'object') {
1016            value = result.value;
1017            data = result.data;
1018        } else value = '';
1019        value = String(value);
1020        if (typeof data !== 'object') {
1021            data = {};
1022        }
1023        return {
1024            value: value,
1025            data: data
1026        };
1027    };
1028
1029    var sanitizeInteger = function (value, stdValue, options) {
1030        var num = parseInt(value, 10);
1031        options = options || {};
1032        if (isNaN(num) || (options.min && num < options.min)) {
1033            num = stdValue;
1034        }
1035        return num;
1036    };
1037
1038    var makeUrlParam = function (name, value) {
1039        return [name, encodeURIComponent(value)].join('=');
1040    };
1041
1042    var makeUrl = function (url, params) {
1043        var urlAppend = [];
1044        $.each(params, function (index, value) {
1045            urlAppend.push(makeUrlParam(index, value));
1046        });
1047        if (urlAppend.length) {
1048            url += url.indexOf('?') === -1 ? '?' : '&';
1049            url += urlAppend.join('&');
1050        }
1051        return url;
1052    };
1053
1054    var sortValueAlpha = function (a, b, matchCase) {
1055        a = String(a.value);
1056        b = String(b.value);
1057        if (!matchCase) {
1058            a = a.toLowerCase();
1059            b = b.toLowerCase();
1060        }
1061        if (a > b) {
1062            return 1;
1063        }
1064        if (a < b) {
1065            return -1;
1066        }
1067        return 0;
1068    };
1069
1070    $.dnnAutocompleter = function ($elem, options) {
1071
1072        if (!$elem || !($elem instanceof $) || $elem.length !== 1 || $elem.get(0).tagName.toUpperCase() !== 'INPUT') {
1073            throw new Error('Invalid parameter for dnnAutocompleter, jQuery object with one element with INPUT tag expected.');
1074        }
1075
1076        var self = this;
1077        this.options = options;
1078        this.cacheData_ = {};
1079        this.cacheLength_ = 0;
1080        this.selectClass_ = 'jquery-autocomplete-selected-item';
1081        this.keyTimeout_ = null;
1082        this.finishTimeout_ = null;
1083        this.lastKeyPressed_ = null;
1084        this.lastProcessedValue_ = null;
1085        this.lastSelectedValue_ = null;
1086        this.active_ = false;
1087        this.finishOnBlur_ = true;
1088
1089        this.options.minChars = sanitizeInteger(this.options.minChars, $.fn.dnnAutocomplete.defaults.minChars, { min: 0 });
1090        this.options.maxItemsToShow = sanitizeInteger(this.options.maxItemsToShow, $.fn.dnnAutocomplete.defaults.maxItemsToShow, { min: 0 });
1091        this.options.maxCacheLength = sanitizeInteger(this.options.maxCacheLength, $.fn.dnnAutocomplete.defaults.maxCacheLength, { min: 1 });
1092        this.options.delay = sanitizeInteger(this.options.delay, $.fn.dnnAutocomplete.defaults.delay, { min: 0 });
1093        if (this.options.preventDefaultReturn != 2) {
1094            this.options.preventDefaultReturn = this.options.preventDefaultReturn ? 1 : 0;
1095        }
1096        if (this.options.preventDefaultTab != 2) {
1097            this.options.preventDefaultTab = this.options.preventDefaultTab ? 1 : 0;
1098        }
1099
1100        this.dom = {};
1101        this.dom.$elem = $elem;
1102        this.dom.$elem.attr('autocomplete', 'off').addClass(this.options.inputClass);
1103        this.dom.$results = $('<div></div>').hide().addClass(this.options.resultsClass).css({
1104            position: 'absolute'
1105        });
1106        $('body').append(this.dom.$results);
1107        $elem.keydown(function (e) {
1108            self.lastKeyPressed_ = e.keyCode;
1109            switch (self.lastKeyPressed_) {
1110                case self.options.delimiterKeyCode: // comma = 188
1111                    if (self.options.useDelimiter && self.active_) {
1112                        self.selectCurrent();
1113                    }
1114                    break;
1115
1116                    // ignore navigational & special keys
1117                case 35: // end
1118                case 36: // home
1119                case 16: // shift
1120                case 17: // ctrl
1121                case 18: // alt
1122                case 37: // left
1123                case 39: // right
1124                    break;
1125
1126                case 38: // up
1127                    e.preventDefault();
1128                    if (self.active_) {
1129                        self.focusPrev();
1130                    } else {
1131                        self.activate();
1132                    }
1133                    return false;
1134
1135                case 40: // down
1136                    e.preventDefault();
1137                    if (self.active_) {
1138                        self.focusNext();
1139                    } else {
1140                        self.activate();
1141                    }
1142                    return false;
1143
1144                case 9: // tab
1145                    if (self.active_) {
1146                        self.selectCurrent();
1147                        if (self.options.preventDefaultTab) {
1148                            e.preventDefault();
1149                            return false;
1150                        }
1151                    }
1152                    if (self.options.preventDefaultTab === 2) {
1153                        e.preventDefault();
1154                        return false;
1155                    }
1156                    break;
1157
1158                case 13: // return
1159                    if (self.active_) {
1160                        self.selectCurrent();
1161                        if (self.options.preventDefaultReturn) {
1162                            e.preventDefault();
1163                            return false;
1164                        }
1165                    }
1166                    if (self.options.preventDefaultReturn === 2) {
1167                        e.preventDefault();
1168                        return false;
1169                    }
1170                    break;
1171
1172                case 27: // escape
1173                    if (self.active_) {
1174                        e.preventDefault();
1175                        self.deactivate(true);
1176                        return false;
1177                    }
1178                    break;
1179
1180                default:
1181                    self.activate();
1182
1183            }
1184            return true;
1185        });
1186
1187        var onBlurFunction = function () {
1188            self.deactivate(true);
1189        };
1190        $elem.blur(function () {
1191            if (self.finishOnBlur_) {
1192                self.finishTimeout_ = setTimeout(onBlurFunction, 1000);
1193            }
1194        });
1195
1196        $elem.parents('form').on('submit', onBlurFunction);
1197
1198    };
1199
1200    $.dnnAutocompleter.prototype.position = function () {
1201        var offset = this.dom.$elem.offset();
1202        var height = this.dom.$results.outerHeight();
1203        var totalHeight = window.outerHeight;
1204        var inputBottom = offset.top + this.dom.$elem.outerHeight();
1205        var bottomIfDown = inputBottom + height;
1206        // Set autocomplete results at the bottom of input
1207        var position = { top: inputBottom, left: offset.left };
1208        if (bottomIfDown > totalHeight) {
1209            // Try to set autocomplete results at the top of input
1210            var topIfUp = offset.top - height;
1211            if (topIfUp >= 0) {
1212                position.top = topIfUp;
1213            }
1214        }
1215        this.dom.$results.css(position);
1216    };
1217
1218    $.dnnAutocompleter.prototype.cacheRead = function (filter) {
1219        var filterLength, searchLength, search, maxPos, pos;
1220        if (this.options.useCache) {
1221            filter = String(filter);
1222            filterLength = filter.length;
1223            if (this.options.matchSubset) {
1224                searchLength = 1;
1225            } else {
1226                searchLength = filterLength;
1227            }
1228            while (searchLength <= filterLength) {
1229                if (this.options.matchInside) {
1230                    maxPos = filterLength - searchLength;
1231                } else {
1232                    maxPos = 0;
1233                }
1234                pos = 0;
1235                while (pos <= maxPos) {
1236                    search = filter.substr(0, searchLength);
1237                    if (this.cacheData_[search] !== undefined) {
1238                        return this.cacheData_[search];
1239                    }
1240                    pos++;
1241                }
1242                searchLength++;
1243            }
1244        }
1245        return false;
1246    };
1247
1248    $.dnnAutocompleter.prototype.cacheWrite = function (filter, data) {
1249        if (this.options.useCache) {
1250            if (this.cacheLength_ >= this.options.maxCacheLength) {
1251                this.cacheFlush();
1252            }
1253            filter = String(filter);
1254            if (this.cacheData_[filter] !== undefined) {
1255                this.cacheLength_++;
1256            }
1257            this.cacheData_[filter] = data;
1258            return this.cacheData_[filter];
1259        }
1260        return false;
1261    };
1262
1263    $.dnnAutocompleter.prototype.cacheFlush = function () {
1264        this.cacheData_ = {};
1265        this.cacheLength_ = 0;
1266    };
1267
1268    $.dnnAutocompleter.prototype.callHook = function (hook, data) {
1269        var f = this.options[hook];
1270        if (f && $.isFunction(f)) {
1271            return f(data, this);
1272        }
1273        return false;
1274    };
1275
1276    $.dnnAutocompleter.prototype.activate = function () {
1277        var self = this;
1278        if (this.keyTimeout_) {
1279            clearTimeout(this.keyTimeout_);
1280        }
1281        this.keyTimeout_ = setTimeout(function () {
1282            self.activateNow();
1283        }, this.options.delay);
1284    };
1285
1286    $.dnnAutocompleter.prototype.activateNow = function () {
1287        var value = this.beforeUseConverter(this.dom.$elem.val());
1288        if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) {
1289            this.fetchData(value);
1290        }
1291    };
1292
1293    $.dnnAutocompleter.prototype.fetchData = function (value) {
1294        var self = this;
1295        var processResults = function (results, filter) {
1296            if (self.options.processData) {
1297                results = self.options.processData(results);
1298            }
1299            self.showResults(self.filterResults(results, filter), filter);
1300        };
1301        this.lastProcessedValue_ = value;
1302        if (value.length < this.options.minChars) {
1303            processResults([], value);
1304        } else if (this.options.data) {
1305            processResults(this.options.data, value);
1306        } else {
1307            this.fetchRemoteData(value, function (remoteData) {
1308                processResults(remoteData, value);
1309            });
1310        }
1311    };
1312
1313    $.dnnAutocompleter.prototype.fetchRemoteData = function (filter, callback) {
1314        var data = this.cacheRead(filter);
1315        if (data) {
1316            callback(data);
1317        } else {
1318            var self = this;
1319            var ajaxCallback = function (d) {
1320                var parsed = false;
1321                if (d !== false) {
1322                    parsed = self.parseRemoteData(d);
1323                    self.cacheWrite(filter, parsed);
1324                }
1325                self.dom.$elem.removeClass(self.options.loadingClass);
1326                callback(parsed);
1327            };
1328
1329            this.dom.$elem.addClass(this.options.loadingClass);
1330            // DNN service framework attached if needed
1331            var services = self.options.moduleId ? ($.dnnSF ? $.dnnSF(self.options.moduleId) : null) : null;
1332            $.ajax({
1333                url: this.makeUrl(filter),
1334                beforeSend: services ? services.setModuleHeaders : null,
1335                success: ajaxCallback,
1336                error: function (jqXhr, textStatus, errorThrown) {
1337                    if ($.isFunction(self.options.onError)) {
1338                        self.options.onError(jqXhr, textStatus, errorThrown);
1339                    } else {
1340                        ajaxCallback(false);
1341                    }
1342                },
1343                type: 'GET',
1344                dataType: 'json',
1345                contentType: "application/json"
1346            });
1347        }
1348    };
1349
1350    $.dnnAutocompleter.prototype.setExtraParam = function (name, value) {
1351        var index = $.trim(String(name));
1352        if (index) {
1353            if (!this.options.extraParams) {
1354                this.options.extraParams = {};
1355            }
1356            if (this.options.extraParams[index] !== value) {
1357                this.options.extraParams[index] = value;
1358                this.cacheFlush();
1359            }
1360        }
1361    };
1362
1363    $.dnnAutocompleter.prototype.makeUrl = function (param) {
1364        var url = this.options.url;
1365        var params = {};
1366        params[this.options.queryParamName] = param;
1367        return makeUrl(url, params);
1368    };
1369
1370    $.dnnAutocompleter.prototype.parseRemoteData = function (remoteData) {
1371        var data = remoteData;
1372        if (typeof data['d'] != 'undefined') {
1373            data = $.parseJSON(data['d']);
1374        }
1375        return data;
1376    };
1377
1378    $.dnnAutocompleter.prototype.filterResult = function (result, filter) {
1379        if (!result.value) {
1380            return false;
1381        }
1382        if (this.options.filterResults) {
1383            var pattern = this.matchStringConverter(filter);
1384            var testValue = this.matchStringConverter(result.value);
1385            if (!this.options.matchCase) {
1386                pattern = pattern.toLowerCase();
1387                testValue = testValue.toLowerCase();
1388            }
1389            var patternIndex = testValue.indexOf(pattern);
1390            if (this.options.matchInside) {
1391                return patternIndex > -1;
1392            } else {
1393                return patternIndex === 0;
1394            }
1395        }
1396        return true;
1397    };
1398
1399    $.dnnAutocompleter.prototype.filterResults = function (results, filter) {
1400        var filtered = [];
1401        var i, result;
1402
1403        for (i = 0; i < results.length; i++) {
1404            result = sanitizeResult(results[i]);
1405            if (this.filterResult(result, filter)) {
1406                filtered.push(result);
1407            }
1408        }
1409        if (this.options.sortResults) {
1410            filtered = this.sortResults(filtered, filter);
1411        }
1412        if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) {
1413            filtered.length = this.options.maxItemsToShow;
1414        }
1415        return filtered;
1416    };
1417
1418    $.dnnAutocompleter.prototype.sortResults = function (results, filter) {
1419        var self = this;
1420        var sortFunction = this.options.sortFunction;
1421        if (!$.isFunction(sortFunction)) {
1422            sortFunction = function (a, b) {
1423                return sortValueAlpha(a, b, self.options.matchCase);
1424            };
1425        }
1426        results.sort(function (a, b) {
1427            return sortFunction(a, b, filter, self.options);
1428        });
1429        return results;
1430    };
1431
1432    $.dnnAutocompleter.prototype.matchStringConverter = function (s, a, b) {
1433        var converter = this.options.matchStringConverter;
1434        if ($.isFunction(converter)) {
1435            s = converter(s, a, b);
1436        }
1437        return s;
1438    };
1439
1440    $.dnnAutocompleter.prototype.beforeUseConverter = function (s, a, b) {
1441        s = this.getValue();
1442        var converter = this.options.beforeUseConverter;
1443        if ($.isFunction(converter)) {
1444            s = converter(s, a, b);
1445        }
1446        return s;
1447    };
1448
1449    $.dnnAutocompleter.prototype.enableFinishOnBlur = function () {
1450        this.finishOnBlur_ = true;
1451    };
1452
1453    $.dnnAutocompleter.prototype.disableFinishOnBlur = function () {
1454        this.finishOnBlur_ = false;
1455    };
1456
1457    $.dnnAutocompleter.prototype.createItemFromResult = function (result, filter) {
1458        var self = this;
1459        var $li = $('<li>' + this.showResult(result.value, result.data, filter) + '</li>');
1460        $li.data({ value: result.value, data: result.data })
1461            .click(function () {
1462                self.selectItem($li);
1463            })
1464            .mousedown(self.disableFinishOnBlur)
1465            .mouseup(self.enableFinishOnBlur)
1466        ;
1467        return $li;
1468    };
1469
1470    $.dnnAutocompleter.prototype.getItems = function () {
1471        return $('>ul>li', this.dom.$results);
1472    };
1473
1474    $.dnnAutocompleter.prototype.showResults = function (results, filter) {
1475        var numResults = results.length;
1476        var self = this;
1477        var $ul = $('<ul></ul>');
1478        var i, result, $li, autoWidth, first = false, $first = false;
1479
1480        if (numResults) {
1481            for (i = 0; i < numResults; i++) {
1482                result = results[i];
1483                $li = this.createItemFromResult(result, filter);
1484                $ul.append($li);
1485                if (first === false) {
1486                    first = String(result.value);
1487                    $first = $li;
1488                    $li.addClass(this.options.firstItemClass);
1489                }
1490                if (i === numResults - 1) {
1491                    $li.addClass(this.options.lastItemClass);
1492                }
1493            }
1494
1495            this.dom.$results.html($ul).show();
1496
1497            // Always recalculate position since window size or
1498            // input element location may have changed.
1499            this.position();
1500            if (this.options.autoWidth) {
1501                autoWidth = this.dom.$elem.outerWidth() - this.dom.$results.outerWidth() + this.dom.$results.width();
1502                this.dom.$results.css(this.options.autoWidth, autoWidth);
1503            }
1504            this.getItems().hover(
1505                function () { self.focusItem(this); },
1506                function () { /* void */ }
1507            );
1508            if (this.autoFill(first, filter) || this.options.selectFirst || (this.options.selectOnly && numResults === 1)) {
1509                this.focusItem($first);
1510            }
1511            this.active_ = true;
1512
1513            //Select the first one as default
1514            this.focusNext();
1515
1516        } else {
1517            this.hideResults();
1518            this.active_ = false;
1519        }
1520    };
1521
1522    $.dnnAutocompleter.prototype.showResult = function (value, data, filter) {
1523        if ($.isFunction(this.options.showResult)) {
1524            return this.options.showResult(value, data);
1525        } else {
1526            // add highlight keywords
1527            var regex = new RegExp('(' + filter + ')', 'gi');
1528            return value.replace(regex, function ($0, $1) {
1529                return ('<b>' + $1 + '</b>');
1530            });
1531        }
1532    };
1533
1534    $.dnnAutocompleter.prototype.autoFill = function (value, filter) {
1535        var lcValue, lcFilter, valueLength, filterLength;
1536        if (this.options.autoFill && this.lastKeyPressed_ !== 8) {
1537            lcValue = String(value).toLowerCase();
1538            lcFilter = String(filter).toLowerCase();
1539            valueLength = value.length;
1540            filterLength = filter.length;
1541            if (lcValue.substr(0, filterLength) === lcFilter) {
1542                var d = this.getDelimiterOffsets();
1543                var pad = d.start ? ' ' : ''; // if there is a preceding delimiter
1544                this.setValue(pad + value);
1545                var start = filterLength + d.start + pad.length;
1546                var end = valueLength + d.start + pad.length;
1547                this.selectRange(start, end);
1548                return true;
1549            }
1550        }
1551        return false;
1552    };
1553
1554    $.dnnAutocompleter.prototype.focusNext = function () {
1555        this.focusMove(+1);
1556    };
1557
1558    $.dnnAutocompleter.prototype.focusPrev = function () {
1559        this.focusMove(-1);
1560    };
1561
1562    $.dnnAutocompleter.prototype.focusMove = function (modifier) {
1563        var $items = this.getItems();
1564        modifier = sanitizeInteger(modifier, 0);
1565        if (modifier) {
1566            for (var i = 0; i < $items.length; i++) {
1567                if ($($items[i]).hasClass(this.selectClass_)) {
1568                    this.focusItem(i + modifier);
1569                    return;
1570                }
1571            }
1572        }
1573        this.focusItem(0);
1574    };
1575
1576    $.dnnAutocompleter.prototype.focusItem = function (item) {
1577        var $item, $items = this.getItems();
1578        if ($items.length) {
1579            $items.removeClass(this.selectClass_).removeClass(this.options.selectClass);
1580            if (typeof item === 'number') {
1581                if (item < 0) {
1582                    item = 0;
1583                } else if (item >= $items.length) {
1584                    item = $items.length - 1;
1585                }
1586                $item = $($items[item]);
1587            } else {
1588                $item = $(item);
1589            }
1590            if ($item) {
1591                $item.addClass(this.selectClass_).addClass(this.options.selectClass);
1592            }
1593        }
1594    };
1595
1596    $.dnnAutocompleter.prototype.selectCurrent = function () {
1597        var $item = $('li.' + this.selectClass_, this.dom.$results);
1598        if ($item.length === 1) {
1599            this.selectItem($item);
1600        } else {
1601            this.deactivate(false);
1602        }
1603    };
1604
1605    $.dnnAutocompleter.prototype.selectItem = function ($li) {
1606        var value = $li.data('value');
1607        var data = $li.data('data');
1608        var displayValue = this.displayValue(value, data);
1609        var processedDisplayValue = this.beforeUseConverter(displayValue);
1610        this.lastProcessedValue_ = processedDisplayValue;
1611        this.lastSelectedValue_ = processedDisplayValue;
1612        var d = this.getDelimiterOffsets();
1613        var delimiter = this.options.delimiterChar;
1614        var elem = this.dom.$elem;
1615        var extraCaretPos = 0;
1616        if (this.options.useDelimiter) {
1617            // if there is a preceding delimiter, add a space after the delimiter
1618            if (elem.val().substring(d.start - 1, d.start) == delimiter && delimiter != ' ') {
1619                displayValue = ' ' + displayValue;
1620            }
1621            // if there is not already a delimiter trailing this value, add it
1622            if (elem.val().substring(d.end, d.end + 1) != delimiter && this.lastKeyPressed_ != this.options.delimiterKeyCode) {
1623                displayValue = displayValue + delimiter;
1624            } else {
1625                // move the cursor after the existing trailing delimiter
1626                extraCaretPos = 1;
1627            }
1628        }
1629        this.setValue(displayValue);
1630        this.setCaret(d.start + displayValue.length + extraCaretPos);
1631        this.callHook('onItemSelect', { value: value, data: data });
1632        this.deactivate(true);
1633        elem.trigger('result', value);
1634    };
1635
1636    $.dnnAutocompleter.prototype.displayValue = function (value, data) {
1637        if ($.isFunction(this.options.displayValue)) {
1638            return this.options.displayValue(value, data);
1639        }
1640        return value;
1641    };
1642
1643    $.dnnAutocompleter.prototype.hideResults = function () {
1644        this.dom.$results.hide();
1645    };
1646
1647    $.dnnAutocompleter.prototype.deactivate = function (finish) {
1648        if (this.finishTimeout_) {
1649            clearTimeout(this.finishTimeout_);
1650        }
1651        if (this.keyTimeout_) {
1652            clearTimeout(this.keyTimeout_);
1653        }
1654        if (finish) {
1655            if (this.lastProcessedValue_ !== this.lastSelectedValue_) {
1656                if (this.options.mustMatch) {
1657                    this.setValue('');
1658                }
1659                this.callHook('onNoMatch');
1660            }
1661            if (this.active_) {
1662                this.callHook('onFinish');
1663            }
1664            this.lastKeyPressed_ = null;
1665            this.lastProcessedValue_ = null;
1666            this.lastSelectedValue_ = null;
1667            this.active_ = false;
1668        }
1669        this.hideResults();
1670    };
1671
1672    $.dnnAutocompleter.prototype.selectRange = function (start, end) {
1673        var input = this.dom.$elem.get(0);
1674        if (input.setSelectionRange) {
1675            input.focus();
1676            input.setSelectionRange(start, end);
1677        } else if (input.createTextRange) {
1678            var range = input.createTextRange();
1679            range.collapse(true);
1680            range.moveEnd('character', end);
1681            range.moveStart('character', start);
1682            range.select();
1683        }
1684    };
1685
1686    $.dnnAutocompleter.prototype.setCaret = function (pos) {
1687        this.selectRange(pos, pos);
1688    };
1689
1690    $.dnnAutocompleter.prototype.getCaret = function () {
1691        var elem = this.dom.$elem, s, e, range;
1692        if (!$.support.cssFloat) {
1693            // ie
1694            var selection = document.selection;
1695            if (elem[0].tagName.toLowerCase() != 'textarea') {
1696                var val = elem.val();
1697                range = selection.createRange().duplicate();
1698                range.moveEnd('character', val.length);
1699                s = (range.text == '' ? val.length : val.lastIndexOf(range.text));
1700                range = selection.createRange().duplicate();
1701                range.moveStart('character', -val.length);
1702                e = range.text.length;
1703            } else {
1704                range = selection.createRange();
1705                var storedRange = range.duplicate();
1706                storedRange.moveToElementText(elem[0]);
1707                storedRange.setEndPoint('EndToEnd', range);
1708                s = storedRange.text.length - range.text.length;
1709                e = s + range.text.length;
1710            }
1711        } else {
1712            // ff, chrome, safari
1713            s = elem[0].selectionStart;
1714            e = elem[0].selectionEnd;
1715        }
1716        return {
1717            start: s,
1718            end: e
1719        };
1720    };
1721
1722    $.dnnAutocompleter.prototype.setValue = function (value) {
1723        if (this.options.useDelimiter) {
1724            // set the substring between the current delimiters
1725            var val = this.dom.$elem.val();
1726            var d = this.getDelimiterOffsets();
1727            var preVal = val.substring(0, d.start);
1728            var postVal = val.substring(d.end);
1729            value = preVal + value + postVal;
1730        }
1731        this.dom.$elem.val(value).blur();
1732    };
1733
1734    $.dnnAutocompleter.prototype.getValue = function () {
1735        var val = this.dom.$elem.val();
1736        if (this.options.useDelimiter) {
1737            var d = this.getDelimiterOffsets();
1738            return val.substring(d.start, d.end).trim();
1739        } else {
1740            return val;
1741        }
1742    };
1743
1744    $.dnnAutocompleter.prototype.getDelimiterOffsets = function () {
1745        var val = this.dom.$elem.val();
1746        if (this.options.useDelimiter) {
1747            var preCaretVal = val.substring(0, this.getCaret().start);
1748            var start = preCaretVal.lastIndexOf(this.options.delimiterChar) + 1;
1749            var postCaretVal = val.substring(this.getCaret().start);
1750            var end = postCaretVal.indexOf(this.options.delimiterChar);
1751            if (end == -1) end = val.length;
1752            end += this.getCaret().start;
1753        } else {
1754            start = 0;
1755            end = val.length;
1756        }
1757        return {
1758            start: start,
1759            end: end
1760        };
1761    };
1762})(jQuery);
1763
1764(function ($) {
1765    // dnn customized tags
1766    var delimiter = new Array();
1767    var tagsCallbacks = new Array();
1768    $.fn.dnnDoAutosize = function (o) {
1769        var minWidth = $(this).data('minwidth'),
1770            maxWidth = $(this).data('maxwidth'),
1771            val = '',
1772            input = $(this),
1773            testSubject = $('#' + $(this).data('tester_id'));
1774
1775        if (val === (val = input.val())) { return; }
1776
1777        // Enter new content into testSubject
1778        var escaped = val.replace(/&/g, '&amp;').replace(/\s/g, ' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1779        testSubject.html(escaped);
1780        // Calculate new width + whether to change
1781        var testerWidth = testSubject.width(),
1782            newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
1783            currentWidth = input.width(),
1784            isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
1785                                 || (newWidth > minWidth && newWidth < maxWidth);
1786
1787        // Animate width
1788        if (isValidWidthChange) {
1789            input.width(newWidth);
1790        }
1791    };
1792
1793    $.fn.dnnResetAutosize = function (options) {
1794	    var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(),
1795	        maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.dnnTagsInput').width() - options.inputPadding),
1796	        $input = $(this);
1797
1798		var left = 0;
1799		var $lastSpan = $(this).closest('.dnnTagsInput').find('> span').last();
1800		if ($lastSpan.length > 0) {
1801			left = $lastSpan.offset().left - $lastSpan.parent().offset().left + $lastSpan.outerWidth();
1802		}
1803		var availableWidth = maxWidth - left;
1804	    if (availableWidth < parseInt(minWidth)) {
1805		    availableWidth = maxWidth;
1806	    }
1807
1808        $input.css('width', availableWidth);
1809    };
1810
1811    $.fn.dnnAddTag = function (value, options) {
1812        options = jQuery.extend({ focus: false, callback: true }, options);
1813        this.each(function () {
1814            var id = $(this).attr('id');
1815            var tagslist = $(this).val().split(delimiter[id]);
1816            if (tagslist[0] == '') {
1817                tagslist = new Array();
1818            }
1819			value = value.replace(/<.*?>/g, '');
1820            value = jQuery.trim(value);
1821            var skipTag;
1822            if (options.unique) {
1823                skipTag = $(this).dnnTagExist(value);
1824                if (skipTag == true) {
1825                    //Marks fake input as not_valid to let styling it
1826                    $('#' + id + '_tag').addClass('dnnTagsInvali
1826d');
1827                }
1828                else
1829                    $('#' + id + '_tag').removeClass('dnnTagsInvalid');
1830            } else {
1831                skipTag = false;
1832                $('#' + id + '_tag').removeClass('dnnTagsInvalid');
1833            }
1834
1835            if (value != '' && skipTag != true) {
1836                $('<span>').addClass('tag').append(
1837                    $('<span>').text(value).append('&nbsp;&nbsp;'),
1838                    $('<a aria-label="remove">', {
1839                        href: '#',
1840                        title: 'Removing tag'
1841                    }).click(function () {
1842                        return $('#' + id).dnnRemoveTag(escape(value));
1843                    })
1844                ).insertBefore('#' + id + '_addTag');
1845
1846                tagslist.push(value);
1847
1848                $('#' + id + '_tag').val('');
1849                if (options.focus) {
1850                    $('#' + id + '_tag').focus();
1851                } else {
1852                    $('#' + id + '_tag').blur();
1853                }
1854
1855                $.fn.dnnTagsInput.updateTagsField(this, tagslist);
1856                var f;
1857                if (options.callback && tagsCallbacks[id] && tagsCallbacks[id]['onAddTag']) {
1858                    f = tagsCallbacks[id]['onAddTag'];
1859                    f.call(this, value);
1860                }
1861                if (tagsCallbacks[id] && tagsCallbacks[id]['onChange']) {
1862                    var i = tagslist.length;
1863                    f = tagsCallbacks[id]['onChange'];
1864                    f.call(this, $(this), tagslist[i - 1]);
1865                }
1866            }
1867        });
1868        return false;
1869    };
1870
1871    $.fn.dnnRemoveTag = function (value) {
1872        value = unescape(value);
1873        this.each(function () {
1874            var id = $(this).attr('id');
1875            var old = $(this).val().split(delimiter[id]);
1876            $('#' + id + '_tagsinput .tag').remove();
1877            var str = '';
1878            for (var i = 0; i < old.length; i++) {
1879                if (old[i] != value) {
1880                    str = str + delimiter[id] + old[i];
1881                }
1882            }
1883            $.fn.dnnTagsInput.importTags(this, str);
1884            if (tagsCallbacks[id] && tagsCallbacks[id]['onRemoveTag']) {
1885                var f = tagsCallbacks[id]['onRemoveTag'];
1886                f.call(this, value);
1887            }
1888        });
1889
1890        return false;
1891    };
1892
1893    $.fn.dnnTagExist = function (val) {
1894        var id = $(this).attr('id'),
1895            tagslist = $(this).val().split(delimiter[id]);
1896        return (jQuery.inArray(val, tagslist) >= 0);
1897    };
1898
1899    $.fn.dnnImportTags = function (str) {
1900        var id = $(this).attr('id');
1901        $('#' + id + '_tagsinput .tag').remove();
1902        $.fn.dnnTagsInput.importTags(this, str);
1903    };
1904
1905    $.fn.dnnTagsInput = function (options) {
1906        var onError = null;
1907        var triggerOnError = function (handler) {
1908            if (!onError) {
1909                onError = setTimeout(function () {
1910                    onError = null;
1911                    if (handler) handler();
1912                }, 0);
1913            }
1914        };
1915        var settings = jQuery.extend({
1916            interactive: true,
1917            defaultText: 'Add a tag',
1918            minChars: 0,
1919            maxChars: 50,
1920            maxTags: 16,
1921            lessThanMinCharsErrorText: 'A tag cannot be less than {0} characters long',
1922            lessThanMinCharsErrorTitle: 'Tag Length Not Reached',
1923            moreThanMaxCharsErrorText: 'A tag cannot be more than {0} characters long',
1924            moreThanMaxCharsErrorTitle: 'Tag Length Exceeded',
1925            moreThanMaxTagsErrorText: 'A maximum of {0} tags can be attached here',
1926            moreThanMaxTagsErrorTitle: 'Tags limit exceeded',
1927            onErrorLessThanMinChars: function () { // can be customised by module dev
1928                $.dnnAlert({ text: String.format(settings.lessThanMinCharsErrorText, settings.minChars), title: settings.lessThanMinCharsErrorTitle });
1929            },
1930            onErrorMoreThanMaxChars: function () { // can be customised by module dev
1931                $.dnnAlert({ text: String.format(settings.moreThanMaxCharsErrorText, settings.maxChars), title: settings.moreThanMaxCharsErrorTitle });
1932            },
1933            onErrorMoreThanMaxTags: function () { // can be customised by module dev
1934                $.dnnAlert({ text: String.format(settings.moreThanMaxTagsErrorText, settings.maxTags), title: settings.moreThanMaxTagsErrorTitle });
1935            },
1936
1937            width: '45%',
1938            autocomplete: { selectFirst: false },
1939            'hide': true,
1940            'delimiter': ',',
1941            'unique': true,
1942            removeWithBackspace: true,
1943            placeholderColor: '#999',
1944            normalColor: '#666',
1945            autosize: true,
1946            comfortZone: 20,
1947            inputPadding: 6 * 2
1948
1949        }, options);
1950
1951        this.each(function () {
1952            var instance = $(this).data('dnnTagInput');
1953            if (instance) return this;
1954            if (settings.hide) {
1955                $(this).hide();
1956            }
1957            var id = $(this).attr('id');
1958            if (!id || delimiter[$(this).attr('id')]) {
1959                id = $(this).attr('id', 'tags' + new Date().getTime()).attr('id');
1960            }
1961            var data = jQuery.extend({
1962                pid: id,
1963                real_input: '#' + id,
1964                holder: '#' + id + '_tagsinput',
1965                input_wrapper: '#' + id + '_addTag',
1966                fake_input: '#' + id + '_tag'
1967            }, settings);
1968
1969            $(this).data('dnnTagInput', data);
1970
1971            delimiter[id] = data.delimiter;
1972
1973            if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
1974                tagsCallbacks[id] = new Array();
1975                tagsCallbacks[id]['onAddTag'] = settings.onAddTag;
1976                tagsCallbacks[id]['onRemoveTag'] = settings.onRemoveTag;
1977                tagsCallbacks[id]['onChange'] = settings.onChange;
1978            }
1979
1980            var markup = '<div id="' + id + '_tagsinput" class="dnnTagsInput">';
1981            markup += '<div id="' + id + '_addTag">';
1982
1983            if (settings.interactive) {
1984                markup += '<input id="' + id + '_tag" value="" data-default="' + settings.defaultText + '" autocomplete="off" aria-label="Search" />';
1985            }
1986
1987            markup += '</div>';
1988            markup = markup + '<div class="dnnTagsClear"></div></div>';
1989
1990            $(markup).insertAfter(this);
1991
1992            $(data.holder).css({
1993                'width': settings.width,
1994                'min-height': settings.height
1995            });
1996
1997            $(data.fake_input).attr("maxlength", settings.maxChars);
1998
1999            if ($(data.real_input).val() != '') {
2000                $.fn.dnnTagsInput.importTags($(data.real_input), $(data.real_input).val());
2001            }
2002            if (settings.interactive) {
2003                // placeholder stuff
2004                $(data.fake_input).dnnPlaceholder({
2005	                color: [settings.normalColor, settings.placeholderColor]
2006                });
2007
2008                $(data.fake_input).dnnResetAutosize(settings);
2009                $(data.holder).on('click', data, function (event) {
2010                    $(event.data.real_input).triggerHandler('focus');
2011                    $(event.data.fake_input).triggerHandler('focus');
2012                    return false;
2013                });
2014                if (settings.autocomplete_url != undefined) {
2015                    if ($.dnnAutocompleter !== undefined) {
2016                        if (settings.advanced && settings.advanced.length) {
2017                            settings.autocomplete.advanced = settings.advanced;
2018                        }
2019
2020                        $(data.fake_input).dnnAutocomplete(settings.autocomplete_url, settings.autocomplete);
2021                        $(data.fake_input).on('result', data, function (event, tag) {
2022                            if (tag) {
2023                                var tagslist = $(event.data.real_input).val().split(delimiter[id]);
2024                                if (tagslist[0] == '') {
2025                                    tagslist = new Array();
2026                                }
2027                                if (event.data.maxTags <= tagslist.length) {
2028                                    if (event.data.onErrorMoreThanMaxTags)
2029                                        triggerOnError(event.data.onErrorMoreThanMaxTags);
2030                                    $(data.fake_input).val('');
2031                                }
2032                                else
2033                                    $(event.data.real_input).dnnAddTag(tag, { focus: true, unique: (settings.unique) });
2034                            }
2035                        });
2036                    }
2037                } else {
2038                    // if a user tabs out of the field, create a new tag
2039                    // this is only available if autocomplete is not used.
2040                    $(data.fake_input).on('blur', data, function (event) {
2041                        var d = $(this).attr('data-default');
2042                        var tagslist = $(event.data.real_input).val().split(delimiter[id]);
2043                        if (tagslist[0] == '') {
2044                            tagslist = new Array();
2045                        }
2046                        if ($(event.data.fake_input).val() != '' && $(event.data.fake_input).val() != d) {
2047                            if (event.data.minChars > $(event.data.fake_input).val().length) {
2048                                if (event.data.onErrorLessThanMinChars)
2049                                    triggerOnError(event.data.onErrorLessThanMinChars);
2050                                $(data.fake_input).val('');
2051                            }
2052                            else if (event.data.maxChars < $(event.data.fake_input).val().length) {
2053                                if (event.data.onErrorMoreThanMaxChars)
2054                                    triggerOnError(event.data.onErrorMoreThanMaxChars);
2055                                $(data.fake_input).val('');
2056                            }
2057                            else if (event.data.maxTags <= tagslist.length) {
2058                                if (event.data.onErrorMoreThanMaxTags)
2059                                    triggerOnError(event.data.onErrorMoreThanMaxTags);
2060                                $(data.fake_input).val('');
2061                            }
2062                            else{
2063								var tags = $(event.data.fake_input).val().split(delimiter[id]);
2064								for(var i = 0; i < tags.length; i++){
2065									$(event.data.real_input).dnnAddTag(tags[i], { focus: true, unique: (settings.unique) });
2066								}
2067                            }
2068                            $(event.data.fake_input).dnnResetAutosize(sett
2068ings);
2069                        }
2070
2071                        return false;
2072                    });
2073
2074                }
2075
2076                function tagItems(data, event) {
2077                        var tagslist = $(event.data.real_input).val().split(delimiter[id]);
2078                        if (tagslist[0] == '') {
2079                            tagslist = new Array();
2080                        }
2081                        if (event.data.minChars > $(event.data.fake_input).val().length) {
2082                            if (event.data.onErrorLessThanMinChars)
2083                                triggerOnError(event.data.onErrorLessThanMinChars);
2084                            $(data.fake_input).val('');
2085                        }
2086                        else if (event.data.maxChars < $(event.data.fake_input).val().length) {
2087                            if (event.data.onErrorMoreThanMaxChars)
2088                                triggerOnError(event.data.onErrorMoreThanMaxChars);
2089                            $(data.fake_input).val('');
2090                        }
2091                        else if (event.data.maxTags <= tagslist.length) {
2092                            if (event.data.onErrorMoreThanMaxTags)
2093                                triggerOnError(event.data.onErrorMoreThanMaxTags);
2094                            $(data.fake_input).val('');
2095                        }
2096                        else {
2097                            var tags = $(event.data.fake_input).val().split(delimiter[id]);
2098                            for (var i = 0; i < tags.length; i++) {
2099                                $(event.data.real_input).dnnAddTag(tags[i], { focus: true, unique: (settings.unique) });
2100                            }
2101                        }
2102
2103                        $(event.data.fake_input).dnnResetAutosize(settings);
2104                        return false;
2105                }
2106
2107                var clickedOnAutoComplete = false;
2108
2109                $(document).mousedown(function (e) {
2110                    if ($(e.target).hasClass("dnn_acSelect") || $(e.target).parent().hasClass('dnn_acSelect')) {
2111                        clickedOnAutoComplete = true;
2112                    }
2113                });
2114
2115                var tagTooLongErrMsg = $('<span class="dnnFormError dnnFormMessage">' + String.format(settings.moreThanMaxCharsErrorText, settings.maxChars) + '</span>');
2116                // if user types a comma, create a new tag
2117                $(data.fake_input).on('keypress keydown blur', data, function (event) {
2118                    if ($(this).val() === "" || clickedOnAutoComplete) {
2119                        return;
2120                    }
2121                    var currValLength = $(this).val().length;
2122                    if ((currValLength >= settings.maxChars) && !(event.which == event.data.delimiter.charCodeAt(0) || event.which == 13 || event.which == 9)) {
2123                        tagTooLongErrMsg.insertAfter($(this)).show().delay(1500).fadeOut(1000);
2124                    }
2125                    if (event.which == event.data.delimiter.charCodeAt(0) || event.which == 13 || event.which == 9 || event.type == "blur") {
2126                        event.preventDefault();
2127                        if (!clickedOnAutoComplete) {
2128                            tagItems(data, event);
2129                        }
2130                        clickedOnAutoComplete = false;
2131                    } else if (event.data.autosize) {
2132                        $(event.data.fake_input).dnnDoAutosize(settings);
2133                    }
2134                    return true;
2135                });
2136                //Delete last tag on backspace
2137                data.removeWithBackspace && $(data.fake_input).on('keydown', function (event) {
2138                    if (event.keyCode == 8 && $(this).val() == '') {
2139                        event.preventDefault();
2140                        var lastTag = $(this).closest('.dnnTagsInput').find('.tag:last').text();
2141                        var lastTagId = $(this).attr('id').replace(/_tag$/, '');
2142                        lastTag = lastTag.replace(/[\s]+$/, '');
2143                        $('#' + lastTagId).dnnRemoveTag(escape(lastTag));
2144                        $(this).trigger('focus');
2145                    }
2146                });
2147                $(data.fake_input).blur();
2148
2149                //Removes the not_valid class when user changes the value of the fake input
2150                if (data.unique) {
2151                    $(data.fake_input).keydown(function (event) {
2152                        if (event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéíóúÁÉÍÓÚñÑ,/]+/)) {
2153                            $(this).removeClass('dnnTagsInvalid');
2154                        }
2155                    });
2156                }
2157
2158            } // if settings.interactive
2159            return this;
2160        });
2161        return this;
2162    };
2163
2164    $.fn.dnnTagsInput.updateTagsField = function (obj, tagslist) {
2165        var id = $(obj).attr('id');
2166        $(obj).val(tagslist.join(delimiter[id]));
2167    };
2168
2169    $.fn.dnnTagsInput.importTags = function (obj, val) {
2170        $(obj).val('');
2171        var id = $(obj).attr('id');
2172        var tags = val.split(delimiter[id]);
2173        for (var i = 0; i < tags.length; i++) {
2174            $(obj).dnnAddTag(tags[i], { focus: false, callback: false });
2175        }
2176        if (tagsCallbacks[id] && tagsCallbacks[id]['onChange']) {
2177            var f = tagsCallbacks[id]['onChange'];
2178            f.call(obj, obj, tags[i]);
2179        }
2180    };
2181
2182    $.fn.dnnPlaceholder = function (options) {
2183	    options = $.extend({}, {
2184	    	cssClass: 'dnnPlaceholder',
2185			color: []
2186	    }, options);
2187
2188	    this.each(function () {
2189		    var $this = $(this);
2190			var instance = $this.data('dnnPlaceHolder');
2191			if (instance) return true;
2192			$this.data('dnnPlaceHolder', true);
2193
2194			var placeholderSupported = ('placeholder' in $this[0]);
2195            if (placeholderSupported)
2196                $this.attr('placeholder', $this.attr('data-default'));
2197            else {
2198            	var $fakeInput = $('<input type="text" />')
2199					.attr('class', $this.attr('class'))
2200					.attr('style', $this.attr('style'))
2201					.val($this.attr('data-default'));
2202
2203            	$this.hide().after($fakeInput);
2204				if (options.color.length === 2) {
2205					$fakeInput.css('color', options.color[1]);
2206					$this.css('color', options.color[0]);
2207				} else {
2208					$fakeInput.addClass(options.cssClass);
2209				}
2210
2211
2212	            $fakeInput.on('focus', function(event) {
2213		            $fakeInput.hide();
2214		            $this.show().focus();
2215	            });
2216
2217				$this.on('blur', function (event) {
2218					var d = $this.attr('data-default');
2219					if ($this.val() === '') {
2220						$this.hide();
2221						$fakeInput.show();
2222					}
2223				});
2224
2225				var events = $._data(this, 'events')['blur'];
2226				var first = events.pop();
2227				events.splice(0, 0, first);
2228            }
2229
2230		    return true;
2231	    });
2232
2233		return this;
2234	};
2235})(jQuery);
2236
2237(function ($) {
2238    // dnnForm customised client side validation
2239    $.fn.toggleErrorMessage = function (options) {
2240        var defaultOptions = {
2241            errorMessage: "Error message",
2242            errorCls: "dnnFormError",
2243            show: true,
2244            removeErrorMessage: true
2245        };
2246
2247        options = $.extend(defaultOptions, options);
2248
2249        return this.each(function () {
2250            var dnnFormItem = $(this).closest('.dnnFormItem');
2251            if (options.show) {
2252                var errorSpan = dnnFormItem.find('span.dnnFormMessage.' + options.errorCls);
2253                if (errorSpan.length) {
2254                    errorSpan.html(options.errorMessage);
2255                } else {
2256                    errorSpan = $('<span class="dnnFormMessage ' + options.errorCls + '">' + options.errorMessage + '</span>');
2257                    dnnFormItem.append(errorSpan);
2258                }
2259
2260                if (this.tagName.toLowerCase() == 'div') {
2261                    // customised controls
2262                    if ($(this).hasClass('RadComboBox')) {
2263                        // RadComboBox
2264                        $(this).addClass('dnnError');
2265                    }
2266                }
2267                else {
2268                    if ($(this).parent().hasClass('RadPicker')) {
2269                        // RadDate Picker
2270                        $(this).parent().find('input.riTextBox').css('border', '1px solid red');
2271                    }
2272                    else if ($(this).hasClass('dnnSpinnerInput')) {
2273                        // Spinner
2274                        $(this).parent().css('border', '1px solid red');
2275                    }
2276                    else {
2277                        // normal ctrl
2278                        $(this).css('border', '1px solid red');
2279                    }
2280                }
2281            }
2282            else {
2283                if (options.removeErrorMessage)
2284                    dnnFormItem.find('span.' + options.errorCls).remove();
2285                else
2286                    dnnFormItem.find('span.' + options.errorCls).hide();
2287
2288                if (this.tagName.toLowerCase() == 'div') {
2289                    // customised controls
2290                    if ($(this).hasClass('RadComboBox')) {
2291                        // RadComboBox
2292                        $(this).removeClass('dnnError');
2293
2294                    }
2295                }
2296                else {
2297                    if ($(this).hasClass('dnnSpinnerInput')) {
2298                        // Spinner
2299                        $(this).parent().css('border', '1px solid #ccc');
2300                    }
2301                    else {
2302                        // normal ctrl
2303                        $(this).css('border', '1px solid #ccc');
2304                    }
2305                }
2306            }
2307        });
2308    };
2309    $.fn.dnnFormSubmit = function (options) {
2310        var defaultOptions = {
2311            validates: []
2312        };
2313
2314        options = $.extend(defaultOptions, options);
2315
2316        return this.each(function () {
2317            $(this).click(function () {
2318                var formValidate = true;
2319                for (var i = 0; i < options.validates.length; i++) {
2320                    var ele = $('#' + options.validates[i].ele);
2321                    var func = options.validates[i].func;
2322                    if (ele.length) {
2323                        var eleVal = ele.val();
2324                        var eleError = func.call(ele.get(0), eleVal);
2325                        if (eleError) {
2326                            ele.toggleErrorMessage({ errorMessage: eleError, show: true });
2327                            formValidate = false;
2328                        }
2329                        else {
2330                            ele.toggleErrorMessage({ show: false });
2331                        }
2332
2333                        //ele focus then remove error info
2334                        var hideErrorInfo = function () {
2335                            $(this).toggleErrorMessage({ show: false });
2336                        };
2337
2338                        ele.off('focus', hideErrorInfo).on('focus', hideErrorInfo);
2339                    }
2340                }
2341
2342                return formValidate;
2343            });
2344        });
2345    };
2346
2347    // fix telerik custom datepicker popup arrow position       
2348    $.dnnRadPickerHack = function () {
2349        //when click this icon, hide error info
2350        var hideErrorInfo = function () {
2351            $(this).toggleErrorMessage({ show: false, removeErrorMessage: false });
2352        };
2353        var dnnRadPickerPopupFix = function () {
2354            if ($.support.cssFloat) {
2355                var id = $(this).attr('id');
2356                var popupId = id.replace('popupButton', 'calendar_wrapper');
2357                var popupElement = $('#' + popupId);
2358                var wrapperId = id.replace('popupButton', 'wrapper');
2359                var wrapperElement = $('#' + wrapperId);
2360
2361                var popupElementTop = popupElement.parent().position().top;
2362                var wrapperElementTop = wrapperElement.offset().top;
2363                var popupTbl = popupElement.find('.RadCalendar_Default');
2364                var nextEle = popupTbl.next();
2365                if (nextEle.hasClass('RadCalendar_Default_PopupArrow_Down') || nextEle.hasClass('RadCalendar_Default_PopupArrow_Up'))
2366                    nextEle.remove();
2367
2368                if (popupElementTop < wrapperElementTop) { // popup above the calendar ctrl, so show arrow down
2369                    popupTbl.after('<div class="RadCalendar_Default_PopupArrow_Down"></div>');
2370                }
2371                else { // popup below the calendar ctrl, so show arrow up
2372                    popupTbl.after('<div class="RadCalendar_Default_PopupArrow_Up"></div>');
2373                }
2374            }
2375
2376            $(this).toggleErrorMessage({ show: false, removeErrorMessage: false });
2377        };
2378        $('.RadPicker_Default a.rcCalPopup').off('click', dnnRadPickerPopupFix).on('click', dnnRadPickerPopupFix);
2379        $('.RadPicker_Default .riTextBox').off('focus', hideErrorInfo).on('focus', hideErrorInfo);
2380    };
2381
2382    // remove combobox inline style
2383    $.dnnComboBoxLoaded = function (sender) {
2384        if (sender.constructor.__typeName == "Telerik.Web.UI.RadComboBox") {
2385            $(sender._inputDomElement).closest(".RadComboBox").removeAttr("style");
2386        }
2387    };
2388
2389    //fix combobox hide error info
2390    $.dnnComboBoxHack = function (sender) {
2391        $(('#' + sender._clientStateFieldID).replace('_ClientState', '')).toggleErrorMessage({ show: false, removeErrorMessage: false });
2392    };
2393
2394    //fix combobox scroll
2395    $.dnnComboBoxScroll = function (sender) {
2396        if ($.support.cssFloat) {
2397            var container = $(('#' + sender._clientStateFieldID + ' .rcbScroll').replace('ClientState', 'DropDown'));
2398            if (container.data('scrollPane')) {
2399                container.data('scrollPane').data('jsp').reinitialise();
2400            } else {
2401                container.data('scrollPane', container.jScrollPane());
2402            }
2403        }
2404    };
2405
2406    $.dnnComboBoxItemRequested = function (sender) {
2407        setTimeout(function() {
2408            var container = $(('#' + sender._clientStateFieldID + ' .rcbScroll').replace('ClientState', 'DropDown'));
2409            if (container.data('scrollPane')) {
2410                container.data('scrollPane').data('jsp').reinitialise();
2411            }
2412        }, 0);
2413    };
2414
2415    // fix grid issues 
2416    $.dnnGridCreated = function (sender) {
2417        var clientId = sender.ClientID;
2418        var $grid = $('#' + clientId);
2419        $('input.rgSortDesc, input.rgSortAsc', $grid).click(function () {
2420            var href = $(this).parent().find('a').get(0).href;
2421            window.location = href;
2422            return false;
2423        });
2424
2425        if ($grid.hasClass('dnnTooltipGrid')) {
2426            $grid.dnnHelperTipDestroy();
2427            $('.rgRow, .rgAltRow', $grid).each(function () {
2428                var info = "Here is some text will show up and explian more about this information";
2429                $(this).dnnHelperTip({ helpContent: info, holderId: clientId });
2430            });
2431        }
2432
2433        var grid = $find(clientId);
2434
2435        // while using customised checkbox - remove onclick event then attach onchange
2436        var headerCheck = $('.rgCheck', $grid);
2437        if (headerCheck.length) {
2438            headerCheck.each(function () {
2439                var checkbox = $(this).find('input[type="checkbox"]').get(0);
2440                var onclick = checkbox.onclick;
2441                checkbox.onchange = onclick;
2442                checkbox.onclick = null;
2443            });
2444
2445            // when use customised scrollbar and customised checkbox, the row cannot be correctly selected
2446            $('.rgDataDiv input[type="checkbox"]', $grid).change(function () {
2447                var masterTable = grid.get_masterTableView();
2448                var rowIndex = $(this).closest('tr').get(0).rowIndex;
2449                var checked = this.checked;
2450                if (checked)
2451                    masterTable.selectItem(rowIndex);
2452                else
2453                    masterTable.deselectItem(rowIndex);
2454            });
2455        }
2456
2457        // initialize dnnGrid customised scrollbar
2458        $('.rgDataDiv').each(function () {
2459            var $this = $(this);
2460            var ele = $this.get(0);
2461            ele.scrollPane = $this.jScrollPane();
2462            var api = ele.scrollPane.data('jsp');
2463            var throttleTimeout;
2464            $(window).on(
2465                'resize',
2466                function () {
2467                    if (!$.support.cssFloat) {
2468                        if (throttleTimeout) {
2469                            clearTimeout(throttleTimeout);
2470                            throttleTimeout = null;
2471                        }
2472                        throttleTimeout = setTimeout(
2473                            function () {
2474                                api.reinitialise();
2475                                throttleTimeout = null;
2476                            },
2477                            50
2478                        );
2479                    } else {
2480                        api.reinitialise();
2481                    }
2482                }
2483            );
2484            if (window.__rgDataDivScrollTopPersistArray && window.__rgDataDivScrollTopPersistArray.length) {
2485                var y = window.__rgDataDivScrollTopPersistArray.pop();
2486                api.scrollToY(y);
2487            }
2488        });
2489    };
2490})(jQuery);
2491
2492(function ($) {
2493    var types = ['DOMMouseScroll', 'mousewheel'];
2494    if ($.event.fixHooks) {
2495        for (var i = types.length; i;) {
2496            $.event.fixHooks[types[--i]] = $.event.mouseHooks;
2497        }
2498    }
2499    $.event.special.mousewheel = {
2500        setup: function () {
2501            if (this.addEventListener) {
2502                for (var i = types.length; i;) {
2503                    this.addEventListener(types[--i], handler, false);
2504                }
2505            } else {
2506                this.onmousewheel = handler;
2507            }
2508        },
2509
2510        teardown: function () {
2511            if (this.removeEventListener) {
2512                for (var i = types.length; i;) {
2513                    this.removeEventListener(types[--i], handler, false);
2514                }
2515            } else {
2516                this.onmousewheel = null;
2517            }
2518        }
2519    };
2520
2521    $.fn.extend({
2522        mousewheel: function (fn) {
2523            return fn ? this.on("mousewheel", fn) : this.trigger("mousewheel");
2524        },
2525
2526        unmousewheel: function (fn) {
2527            return this.off("mousewheel", fn);
2528        }
2529    });
2530
2531    function handler(event) {
2532        var orgEvent = event || window.event,
2533            args = [].slice.call(arguments, 1),
2534            delta = 0,
2535            deltaX = 0,
2536            deltaY = 0;
2537        event = $.event.fix(orgEvent);
2538        event.type = "mousewheel";
2539
2540        // Old school scrollwheel delta
2541        if (orgEvent.wheelDelta) { delta = orgEvent.wheelDelta / 120; }
2542        if (orgEvent.detail) { delta = -orgEvent.detail / 3; }
2543
2544        // New school multidimensional scroll (touchpads) deltas
2545        deltaY = delta;
2546
2547        // Gecko
2548        if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
2549            deltaY = 0;
2550            deltaX = -1 * delta;
2551        }
2552
2553        // Webkit
2554        if (orgEvent.wheelDeltaY !== undefined) { deltaY = orgEvent.wheelDeltaY / 120; }
2555        if (orgEvent.wheelDeltaX !== undefined) { deltaX = -1 * orgEvent.wheelDeltaX / 120; }
2556
2557        // Add event and delta to the front of the arguments
2558        args.unshift(event, delta, deltaX, deltaY);
2559        return ($.event.dispatch || $.event.handle).apply(this, args);
2560    }
2561
2562})(jQuery);
2563
2564(function ($) {
2565    $.fn.dnnFileInput = function (options) {
2566        var opts = $.extend({}, $.fn.dnnFileInput.defaultOptions, options);
2567
2568        return this.each(function () {
2569            var $ctrl = $(this);
2570            if ($ctrl.hasClass('normalFileUpload')) return;
2571
2572            if (this.wrapper)
2573                return;
2574
2575            //ignore decoration for elements in rad control.
2576            if ($ctrl.parents().hasClass("RadUpload"))
2577                return;
2578
2579            // if this.wrapper is undefined, then we check if parent node is a wrapper
2580            if (this.parentNode && this.parentNode.tagName.toLowerCase() == 'span' && $ctrl.parent().hasClass('dnnInputFileWrapper')) {
2581                return;
2582            }
2583
2584            this.wrapper = $("<span class='dnnInputFileWrapper " + opts.buttonClass + "'></span>");
2585            var text = $ctrl.data('text');
2586            text = text || 'Choose File';
2587            this.wrapper.text(text);
2588            $ctrl.wrap(this.wrapper);
2589            $ctrl.data("wrapper", $ctrl.parent());
2590
2591            if (opts.showSelectedFileNameAsButtonText) {
2592                $ctrl.change(function () {
2593                    var val = $(this).val();
2594                    if (val != '') {
2595                        var lastIdx = val.lastIndexOf('\\') + 1;
2596                        val = val.substring(lastIdx, val.length);
2597                    } else {
2598                        val = text;
2599                    }
2600                    $(this).data("wrapper").get(0).childNodes[0].nodeValue = val;
2601                });
2602            }
2603        });
2604    };
2605
2606    $.fn.dnnFileInput.defaultOptions = {
2607        buttonClass: 'dnnSecondaryAction',
2608        showSelectedFileNameAsButtonText: true
2609    };
2610})(jQuery);
2611
2612(function ($) {
2613    var supportAjaxUpload = function () {
2614        var xhr = new XMLHttpRequest;
2615        return !!(xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));
2616    };
2617
2618    $.fn.dnnFileUpload = function (settings) {
2619        return this.each(function () {
2620            // set scope and settings, service
2621            var scope = $(this).attr('id');
2622            window.dnn.dnnFileUpload.setSettings(scope, settings);
2623            var service = $.dnnSF();
2624
2625            // hide progress
2626            $('#' + settings.progressBarId).parent().hide();
2627            // detect draggable support or not
2628            var droppableSpan = $('#' + settings.dropZoneId + '>span');
2629            if ('draggable' in document.createElement('span')) {
2630                droppableSpan.show();
2631            }
2632            else {
2633                droppableSpan.hide();
2634            }
2635
2636            // set file upload
2637            var url = service.getServiceRoot('internalservices') + 'fileupload/postfile';
2638            if (!supportAjaxUpload()) {
2639                var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val();
2640                url += '?__RequestVerificationToken=' + antiForgeryToken;
2641            }
2642
2643            $('#' + scope + ' input[type="file"]').fileupload({
2644                url: url,
2645                beforeSend: service.setModuleHeaders,
2646                dropZone: $('#' + settings.dropZoneId),
2647                pasteZone: null,
2648                replaceFileInput: false,
2649                submit: function (e, data) {
2650                    data.formData = { folder: settings.folder, filter: settings.fileFilter, overwrite: 'true' };
2651                    return true;
2652                },
2653                progressall: function (e, data) {
2654                    var progress = parseInt(data.loaded / data.total * 100, 10);
2655                    if (progress < 100) {
2656                        $('#' + settings.progressBarId).parent().show();
2657                        $('#' + settings.progressBarId + '>div').css('width', progress + '%');
2658                    }
2659                    else
2660                        $('#' + settings.progressBarId).parent().hide();
2661                },
2662                done: function (e, data) {
2663                    $('#' + settings.progressBarId).parent().hide();
2664                    var img = new Image();
2665                    $(img).on('load', function () {
2666                        $('#' + settings.dropZoneId + ' img').remove();
2667                        $(img).css({ 'max-width': 180, 'max-height': 150 }).insertBefore($('#' + settings.dropZoneId + ' span'));
2668                    });
2669                    var src;
2670                    if (data.dataType && typeof(data.result) == "object" && data.result.length) {
2671                        data.result = JSON.parse(data.result.text());
2672                    } else {
2673                        data.result = JSON.parse(data.result);
2674                    }
2675                    var testContent = $('<pre>' + data.result.FilePath + '</pre>');
2676                    if (testContent.length) {
2677                        src = testContent.text();
2678                    }
2679                    else
2680                        src = data.result;
2681
2682                    if (src && $.trim(src)) {
2683                        var profileImagePath = dnn.getVar("sf_siteRoot", "/") + 'DnnImageHandler.ashx?mode=securefile&fileId=' + data.result.FileId + '&MaxWidth=180&MaxHeight=150';
2684                        img.src = profileImagePath;
2685                        
2686                        var fileName = data.result.FilePath.replace(/\\/g, '/');
2687                        if (fileName.indexOf('/') > -1) {
2688                            fileName = fileName.split('/')[fileName.split('/').length - 1];
2689                        }
2690                        if (fileName.indexOf('?') > -1) {
2691                            fileName = fileName.split('?')[0];
2692                        }
2693                        
2694                        dnn[settings.filesComboId].refresh(dnn[settings.foldersComboId].selectedItem().key);
2695                        dnn[settings.filesComboId].selectedItem({ key: data.result.FileId, value: fileName});
2696                    }
2697                },
2698                fail: function (e, data) {
2699                    $('#' + settings.progressBarId).parent().hide();
2700                    var resp = JSON.parse(data.jqXHR.responseText);
2701                    alert(resp.Message);
2702                }
2703            });
2704
2705            $('#' + scope + ' input[name=uploadFileButton]').click(function() {
2706                var instance = dnn[settings.fileUploadId];
2707                
2708                var options = instance.options;
2709                if (dnn[settings.foldersComboId].selectedItem() != null) {
2710                    instance.options.folderPicker.initialState.selectedItem = dnn[settings.foldersComboId].selectedItem();
2711                    instance.options.folderPath = window.dnn.dnnFileUpload.getSelectedPath(dnn[settings.foldersComboId]);
2712                }
2713
2714                instance.show(options);
2715                
2716                window.dnn.dnnFileUpload.updateExpandPath(dnn[settings.foldersComboId], instance._panel._folderPicker.id());
2717                
2718                instance._panel.$element.on("onfileuploadcomplete", function (event, data) {
2719                    if (typeof data == "string") {
2720						// for modern browsers
2721                        data = JSON.parse(data);
2722                    }else{
2723						// for IE8-9						
2724						var b = data[0];
2725						data = JSON.parse(b.body.innerText);
2726					}
2727                    if (data && data.fileId) {
2728                        var folderPicker = instance._panel._folderPicker;
2729                        dnn[settings.foldersComboId].selectedItem(folderPicker.selectedItem());
2730                        window.dnn.dnnFileUpload.Folders_Changed(dnn[settings.foldersComboId].selectedItem(), dnn[settings.foldersComboId].$element);
2731                        window.dnn.dnnFileUpload.updateExpandPath(folderPicker, settings.foldersComboId);
2732                        
2733                        dnn[settings.filesComboId].refresh(dnn[settings.foldersComboId].selectedItem().key);
2734                        dnn[settings.filesComboId].selectedItem({ key: data.fileId.toString(), value: data.fileName });
2735                        window.dnn.dnnFileUpload.Files_Changed(dnn[settings.filesComboId].selectedItem(), dnn[settings.filesComboId].$element);
2736                    }
2737                });
2738            });
2739
2740            // set initial thumb image
2741            setTimeout(function () {
2742                dnn[settings.filesComboId].options.services.parameters.parentId = settings.selectedFolderId;
2743                var filesCombo = dnn[settings.filesComboId];
2744                var selectedFileId = filesCombo.selectedItem() ? filesCombo.selectedItem().key : null;                
2745             	var fileId  = selectedFileId ? parseInt(selectedFileId) : 0;
2746                if (fileId > 0) {
2747                    var maxWidth = 180, maxHeight = 150;
2748                    var profileImagePath = dnn.getVar("sf_siteRoot", "/") + 'DnnImageHandler.ashx?mode=securefile&fileId=' + fileId + '&MaxWidth=' + maxWidth + '&MaxHeight=' + maxHeight;
2749                    var img = new Image();
2750
2751                    $(img).on('load', function () {
2752                        $('#' + settings.dropZoneId + ' img').remove();
2753                        $(img).css({ 'max-width': maxWidth, 'max-height': maxHeight }).insertBefore($('#' + settings.dropZoneId + ' span'));
2754                    });
2755                    img.src = profileImagePath;        
2756                }
2757            }, 500);
2758        });
2759    };
2760
2761    if (typeof window.dnn === 'undefined') window.dnn = {};
2762    window.dnn.dnnFileUpload = window.dnn.dnnFileUpload || {};
2763    window.dnn.dnnFileUpload.settings = {};
2764    window.dnn.dnnFileUpload.setSettings = function (scope, settings) {
2765        window.dnn.dnnFileUpload.settings[scope] = settings;
2766    };
2767    window.dnn.dnnFileUpload.getSettings = function (sender) {
2768        var scope = sender.closest('.dnnFileUploadScope').attr('id');
2769        return window.dnn.dnnFileUpload.settings[scope];
2770    };
2771    window.dnn.dnnFileUpload.Folders_Changed = function (node, sender) {
2772        var settings = window.dnn.dnnFileUpload.getSettings(sender);
2773        if (!settings) return false;
2774
2775        if (node) {
2776            //get the selected folder path
2777            var selectedPathArray = dnn[settings.foldersComboId].selectedPath();
2778            if (selectedPathArray.length === 0 && settings.folder) {
2779                return settings.folder;
2780            }
2781            var selectedPath = "";
2782            if (selectedPathArray.length > 1) {
2783                for (var i = 1, size = selectedPathArray.length; i < size; i++) {
2784                    selectedPath += selectedPathArray[i].name + "/";
2785                }
2786            } 
2787            settings.folder = selectedPath;
2788
2789            dnn[settings.filesComboId].refresh(node.key);
2790            dnn[settings.filesComboId].selectedItem(null);
2791            window.dnn.dnnFileUpload.Files_Changed({ key: null }, $('#' + settings.filesComboId));
2792        }
2793    };
2794    window.dnn.dnnFileUpload.Files_Changed = function (node, sender) {
2795        var settings = window.dnn.dnnFileUpload.getSettings(sender);
2796        if (!settings) return;
2797
2798        if (node) {
2799            var fileId = node.key;
2800            if (fileId) {
2801                var maxWidth = 180, maxHeight = 150;
2802                var profileImagePath = dnn.getVar("sf_siteRoot", "/") + 'DnnImageHandler.ashx?mode=securefile&fileId=' + fileId + '&MaxWidth=' + maxWidth + '&MaxHeight=' + maxHeight;
2803                var img = new Image();
2804
2805                $(img).on('load', function () {
2806                    $('#' + settings.dropZoneId + ' img').remove();
2807                    $(img).css({ 'max-width': maxWidth, 'max-height': maxHeight }).insertBefore($('#' + settings.dropZoneId + ' span'));
2808                });
2809                img.src = profileImagePath;        
2810            }
2811            else
2812                $('#' + settings.dropZoneId + ' img').remove();
2813        }
2814    };
2815    window.dnn.dnnFileUpload.updateExpandPath = function(dropDownList, targetId) {
2816        //set expand path
2817        var selectedPaths = dropDownList.selectedPath();
2818        var expandPath = "";
2819        if (selectedPaths.length == 0) { //which means the tree view hasn't opened.
2820            expandPath = dnn.getVar(dropDownList.id() + '_expandPath');
2821        }
2822        else if (selectedPaths.length > 1) {
2823            for (var i = 0; i < selectedPaths.length - 1; i++) {
2824                if (expandPath == "") {
2825                    expandPath = selectedPaths[i].id;
2826                } else {
2827                    expandPath = expandPath + "," + selectedPaths[i].id;
2828                }
2829            }
2830        }
2831        
2832        if (expandPath != "") {
2833            dnn.setVar(targetId + '_expandPath', expandPath);
2834        }
2835    };
2836    window.dnn.dnnFileUpload.getSelectedPath = function(dropDownList) {
2837        var selectedPathArray = dropDownList.selectedPath();
2838        var settings = window.dnn.dnnFileUpload.getSettings(dropDownList.$element);
2839        if (selectedPathArray.length === 0 && settings.folder) {
2840            return settings.folder;
2841        }
2842        var selectedPath = "";
2843        if (selectedPathArray.length > 1) {
2844            for (var i = 1, size = selectedPathArray.length; i < size; i++) {
2845                selectedPath += selectedPathArray[i].name + "/";
2846            }
2847        }
2848        return selectedPath;
2849    };
2850})(jQuery);
2851
2852(function ($) {
2853    /* BELOW jscrollPane code */
2854    $.fn.jScrollPane = function (settings) {
2855        // JScrollPane "class" - public methods are available through $('selector').data('jsp')
2856        function JScrollPane(elem, s) {
2857            var settings, jsp = this, pane, paneWidth, paneHeight, container, contentWidth, contentHeight,
2858				percentInViewH, percentInViewV, isScrollableV, isScrollableH, verticalDrag, dragMaxY,
2859				verticalDragPosition, horizontalDrag, dragMaxX, horizontalDragPosition,
2860				verticalBar, verticalTrack, scrollbarWidth, verticalTrackHeight, verticalDragHeight, arrowUp, arrowDown,
2861				horizontalBar, horizontalTrack, horizontalTrackWidth, horizontalDragWidth, arrowLeft, arrowRight,
2862				reinitialiseInterval, originalPadding, originalPaddingTotalWidth, previousContentWidth,
2863				wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false,
2864				originalElement = elem.clone(false, false).empty(),
2865				mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp';
2866
2867            originalPadding = elem.css('paddingTop') + ' ' +
2868								elem.css('paddingRight') + ' ' +
2869								elem.css('paddingBottom') + ' ' +
2870								elem.css('paddingLeft');
2871            originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) +
2872										(parseInt(elem.css('paddingRight'), 10) || 0);
2873
2874            function initialise(s) {
2875
2876                var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY,
2877						hasContainingSpaceChanged, originalScrollTop, originalScrollLeft,
2878						maintainAtBottom = false, maintainAtRight = false;
2879
2880                settings = s;
2881
2882                if (pane === undefined) {
2883                    originalScrollTop = elem.scrollTop();
2884                    originalScrollLeft = elem.scrollLeft();
2885
2886                    elem.css(
2887						{
2888						    overflow: 'hidden',
2889						    padding: 0
2890						}
2891					);
2892                    // TODO: Deal with where width/ height is 0 as it probably means the element is hidden and we should
2893                    // come back to it later and check once it is unhidden...
2894                    paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
2895                    paneHeight = elem.innerHeight();
2896
2897                    elem.width(paneWidth);
2898
2899                    pane = $('<div class="jspPane" />').css('padding', originalPadding).append(elem.children());
2900                    container = $('<div class="jspContainer" />')
2901						.css({
2902						    'width': paneWidth + 'px',
2903						    'height': paneHeight + 'px'
2904						}
2905					).append(pane).appendTo(elem);
2906
2907                    /*
2908					// Move any margins from the first and last children up to the container so they can still
2909					// collapse with neighbouring elements as they would before jScrollPane 
2910					firstChild = pane.find(':first-child');
2911					lastChild = pane.find(':last-child');
2912					elem.css(
2913						{
2914							'margin-top': firstChild.css('margin-top'),
2915							'margin-bottom': lastChild.css('margin-bottom')
2916						}
2917					);
2918					firstChild.css('margin-top', 0);
2919					lastChild.css('margin-bottom', 0);
2920					*/
2921                } else {
2922                    elem.css('width', '');
2923
2924                    maintainAtBottom = settings.stickToBottom && isCloseToBottom();
2925                    maintainAtRight = settings.stickToRight && isCloseToRight();
2926
2927                    hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight;
2928
2929                    if (hasContainingSpaceChanged) {
2930                        paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
2931                        paneHeight = elem.innerHeight();
2932                        container.css({
2933                            width: paneWidth + 'px',
2934                            height: paneHeight + 'px'
2935                        });
2936                    }
2937
2938                    // If nothing changed since last check...
2939                    if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) {
2940                        elem.width(paneWidth);
2941                        return;
2942                    }
2943                    previousContentWidth = contentWidth;
2944
2945                    pane.css('width', '');
2946                    elem.width(paneWidth);
2947
2948                    container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end();
2949                }
2950
2951                pane.css('overflow', 'auto');
2952                if (s.contentWidth) {
2953                    contentWidth = s.contentWidth;
2954                } else {
2955                    contentWidth = pane[0].scrollWidth;
2956                }
2957                contentHeight = pane[0].scrollHeight;
2958                pane.css('overflow', '');
2959
2960                percentInViewH = contentWidth / paneWidth;
2961                percentInViewV = contentHeight / paneHeight;
2962                isScrollableV = percentInViewV > 1;
2963
2964                isScrollableH = percentInViewH > 1;
2965
2966                if (!(isScrollableH || isScrollableV)) {
2967                    elem.removeClass('jspScrollable');
2968                    pane.css({
2969                        top: 0,
2970                        width: container.width() - originalPaddingTotalWidth
2971                    });
2972                    removeMousewheel();
2973                    removeFocusHandler();
2974                    removeKeyboardNav();
2975                    removeClickOnTrack();
2976                } else {
2977                    elem.addClass('jspScrollable');
2978
2979                    isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition);
2980                    if (isMaintainingPositon) {
2981                        lastContentX = contentPositionX();
2982                        lastContentY = contentPositionY();
2983                    }
2984
2985                    initialiseVerticalScroll();
2986                    initialiseHorizontalScroll();
2987                    resizeScrollbars();
2988
2989                    if (isMaintainingPositon) {
2990                        scrollToX(maintainAtRight ? (contentWidth - paneWidth) : lastContentX, false);
2991                        scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false);
2992                    }
2993
2994                    initFocusHandler();
2995                    initMousewheel();
2996                    initTouch();
2997
2998                    if (settings.enableKeyboardNavigation) {
2999                        initKeyboardNav();
3000                    }
3001                    if (settings.clickOnTrack) {
3002                        initClickOnTrack();
3003                    }
3004
3005                    observeHash();
3006                    if (settings.hijackInternalLinks) {
3007                        hijackInternalLinks();
3008                    }
3009                }
3010
3011                if (settings.autoReinitialise && !reinitialiseInterval) {
3012                    reinitialiseInterval = setInterval(
3013						function () {
3014						    initialise(settings);
3015						},
3016						settings.autoReinitialiseDelay
3017					);
3018                } else if (!settings.autoReinitialise && reinitialiseInterval) {
3019                    clearInterval(reinitialiseInterval);
3020                }
3021
3022                originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false);
3023                originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false);
3024
3025                elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]);
3026            }
3027
3028            function initialiseVerticalScroll() {
3029                if (isScrollableV) {
3030
3031                    container.append(
3032						$('<div class="jspVerticalBar" />').append(
3033							$('<div class="jspCap jspCapTop" />'),
3034							$('<div class="jspTrack" />').append(
3035								$('<div class="jspDrag" />').append(
3036									$('<div class="jspDragTop" />'),
3037									$('<div class="jspDragBottom" />')
3038								)
3039							),
3040							$('<div class="jspCap jspCapBottom" />')
3041						)
3042					);
3043
3044                    verticalBar = container.find('>.jspVerticalBar');
3045                    verticalTrack = verticalBar.find('>.jspTrack');
3046                    verticalDrag = verticalTrack.find('>.jspDrag');
3047
3048                    if (settings.showArrows) {
3049                        arrowUp = $('<a class="jspArrow jspArrowUp" />').on(
3050							'mousedown.jsp', getArrowScroll(0, -1)
3051						).on('click.jsp', nil);
3052                        arrowDown = $('<a class="jspArrow jspArrowDown" />').on(
3053							'mousedown.jsp', getArrowScroll(0, 1)
3054						).on('click.jsp', nil);
3055                        if (settings.arrowScrollOnHover) {
3056                            arrowUp.on('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
3057                            arrowDown.on('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
3058                        }
3059
3060                        appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
3061                    }
3062
3063                    verticalTrackHeight = paneHeight;
3064                    container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
3065						function () {
3066						    verticalTrackHeight -= $(this).outerHeight();
3067						}
3068					);
3069
3070
3071                    verticalDrag.hover(
3072						function () {
3073						    verticalDrag.addClass('jspHover');
3074						},
3075						function () {
3076						    verticalDrag.removeClass('jspHover');
3077						}
3078					).on(
3079						'mousedown.jsp',
3080						function (e) {
3081						    // Stop IE from allowing text selection
3082						    $('html').on('dragstart.jsp selectstart.jsp', nil);
3083
3084						    verticalDrag.addClass('jspActive');
3085
3086						    var startY = e.pageY - verticalDrag.position().top;
3087
3088						    $('html').on(
3089								'mousemove.jsp',
3090								function (e) {
3091								    positionDragY(e.pageY - startY, false);
3092								}
3093							).on('mouseup.jsp mouseleave.jsp', cancelDrag);
3094						    return false;
3095						}
3096					);
3097                    sizeVerticalScrollbar();
3098                }
3099            }
3100
3101            function sizeVerticalScrollbar() {
3102                verticalTrack.height(verticalTrackHeight + 'px');
3103                verticalDragPosition = 0;
3104                scrollbarWidth = settings.verticalGutter + verticalTrack.outerWidth();
3105
3106                // Make the pane thinner to allow for the vertical scrollbar
3107                pane.width(paneWidth - scrollbarWidth - originalPaddingTotalWidth);
3108
3109                // Add margin to the left of the pane if scrollbars are on that side (to position
3110                // the scrollbar on the left or right set it's left or right property in CSS)
3111                try {
3112                    if (verticalBar.position().left === 0) {
3113                        pane.css('margin-left', scrollbarWidth + 'px');
3114                    }
3115                } catch (err) {
3116                }
3117            }
3118
3119            function initialiseHorizontalScroll() {
3120                if (isScrollableH) {
3121
3122                    container.append(
3123						$('<div class="jspHorizontalBar" />').append(
3124							$('<div class="jspCap jspCapLeft" />'),
3125							$('<div class="jspTrack" />').append(
3126								$('<div class="jspDrag" />').append(
3127									$('<div class="jspDragLeft" />'),
3128									$('<div class="jspDragRight" />')
3129								)
3130							),
3131							$('<div class="jspCap jspCapRight" />')
3132						)
3133					);
3134
3135                    horizontalBar = container.find('>.jspHorizontalBar');
3136                    horizontalTrack = horizontalBar.find('>.jspTrack');
3137                    horizontalDrag = horizontalTrack.find('>.jspDrag');
3138
3139                    if (settings.showArrows) {
3140                        arrowLeft = $('<a class="jspArrow jspArrowLeft" />').on(
3141							'mousedown.jsp', getArrowScroll(-1, 0)
3142						).on('click.jsp', nil);
3143                        arrowRight = $('<a class="jspArrow jspArrowRight" />').on(
3144							'mousedown.jsp', getArrowScroll(1, 0)
3145						).on('click.jsp', nil);
3146                        if (settings.arrowScrollOnHover) {
3147                            arrowLeft.on('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
3148                            arrowRight.on('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
3149                        }
3150                        appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
3151                    }
3152
3153                    horizontalDrag.hover(
3154						function () {
3155						    horizontalDrag.addClass('jspHover');
3156						},
3157						function () {
3158						    horizontalDrag.removeClass('jspHover');
3159						}
3160					).on(
3161						'mousedown.jsp',
3162						function (e) {
3163						    // Stop IE from allowing text selection
3164						    $('html').on('dragstart.jsp selectstart.jsp', nil);
3165
3166						    horizontalDrag.addClass('jspActive');
3167
3168						    var startX = e.pageX - horizontalDrag.position().left;
3169
3170						    $('html').on(
3171								'mousemove.jsp',
3172								function (e) {
3173								    positionDragX(e.pageX - startX, false);
3174								}
3175							).on('mouseup.jsp mouseleave.jsp', cancelDrag);
3176						    return false;
3177						}
3178					);
3179                    horizontalTrackWidth = container.innerWidth();
3180                    sizeHorizontalScrollbar();
3181                }
3182            }
3183
3184            function sizeHorizontalScrollbar() {
3185                container.find('>.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow').each(
3186					function () {
3187					    horizontalTrackWidth -= $(this).outerWidth();
3188					}
3189				);
3190
3191                horizontalTrack.width(horizontalTrackWidth + 'px');
3192                horizontalDragPosition = 0;
3193            }
3194
3195            function resizeScrollbars() {
3196                if (isScrollableH && isScrollableV) {
3197                    var horizontalTrackHeight = horizontalTrack.outerHeight(),
3198						verticalTrackWidth = verticalTrack.outerWidth();
3199                    verticalTrackHeight -= horizontalTrackHeight;
3200                    $(horizontalBar).find('>.jspCap:visible,>.jspArrow').each(
3201						function () {
3202						    horizontalTrackWidth += $(this).outerWidth();
3203						}
3204					);
3205                    horizontalTrackWidth -= verticalTrackWidth;
3206                    paneHeight -= verticalTrackWidth;
3207                    paneWidth -= horizontalTrackHeight;
3208                    horizontalTrack.parent().append(
3209						$('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
3210					);
3211                    sizeVerticalScrollbar();
3212                    sizeHorizontalScrollbar();
3213                }
3214                // reflow content
3215                if (isScrollableH) {
3216                    pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
3217                }
3218                contentHeight = pane.outerHeight();
3219                percentInViewV = contentHeight / paneHeight;
3220
3221                if (isScrollableH) {
3222                    horizontalDragWidth = Math.ceil(1 / percentInViewH * horizontalTrackWidth);
3223                    if (horizontalDragWidth > settings.horizontalDragMaxWidth) {
3224                        horizontalDragWidth = settings.horizontalDragMaxWidth;
3225                    } else if (horizontalDragWidth < settings.horizontalDragMinWidth) {
3226                        horizontalDragWidth = settings.horizontalDragMinWidth;
3227                    }
3228                    horizontalDrag.width(horizontalDragWidth + 'px');
3229                    dragMaxX = horizontalTrackWidth - horizontalDragWidth;
3230                    _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons
3231                }
3232                if (isScrollableV) {
3233                    verticalDragHeight = Math.ceil(1 / percentInViewV * verticalTrackHeight);
3234                    if (verticalDragHeight > settings.verticalDragMaxHeight) {
3235                        verticalDragHeight = settings.verticalDragMaxHeight;
3236                    } else if (verticalDragHeight < settings.verticalDragMinHeight) {
3237                        verticalDragHeight = settings.verticalDragMinHeight;
3238                    }
3239                    verticalDrag.height(verticalDragHeight + 'px');
3240                    dragMaxY = verticalTrackHeight - verticalDragHeight;
3241                    _positionDragY(verticalDragPosition); // To update the state for the arrow buttons
3242                }
3243            }
3244
3245            function appendArrows(ele, p, a1, a2) {
3246                var p1 = "before", p2 = "after", aTemp;
3247
3248                // Sniff for mac... Is there a better way to determine whether the arrows would naturally appear
3249                // at the top or the bottom of the bar?
3250                if (p == "os") {
3251                    p = /Mac/.test(navigator.platform) ? "after" : "split";
3252                }
3253                if (p == p1) {
3254                    p2 = p;
3255                } else if (p == p2) {
3256                    p1 = p;
3257                    aTemp = a1;
3258                    a1 = a2;
3259                    a2 = aTemp;
3260                }
3261
3262                ele[p1](a1)[p2](a2);
3263            }
3264
3265            function getArrowScroll(dirX, dirY, ele) {
3266                return function () {
3267                    arrowScroll(dirX, dirY, this, ele);
3268                    this.blur();
3269                    return false;
3270                };
3271            }
3272
3273            function arrowScroll(dirX, dirY, arrow, ele) {
3274                arrow = $(arrow).addClass('jspActive');
3275
3276                var eve,
3277					scrollTimeout,
3278					isFirst = true,
3279					doScroll = function () {
3280					    if (dirX !== 0) {
3281					        jsp.scrollByX(dirX * settings.arrowButtonSpeed);
3282					    }
3283					    if (dirY !== 0) {
3284					        jsp.scrollByY(dirY * settings.arrowButtonSpeed);
3285					    }
3286					    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq);
3287					    isFirst = false;
3288					};
3289
3290                doScroll();
3291
3292                eve = ele ? 'mouseout.jsp' : 'mouseup.jsp';
3293                ele = ele || $('html');
3294                ele.on(
3295					eve,
3296					function () {
3297					    arrow.removeClass('jspActive');
3298					    scrollTimeout && clearTimeout(scrollTimeout);
3299					    scrollTimeout = null;
3300					    ele.off(eve);
3301					}
3302				);
3303            }
3304
3305            function initClickOnTrack() {
3306                removeClickOnTrack();
3307                if (isScrollableV) {
3308                    verticalTrack.on(
3309						'mousedown.jsp',
3310						function (e) {
3311						    if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
3312						        var clickedTrack = $(this),
3313									offset = clickedTrack.offset(),
3314									direction = e.pageY - offset.top - verticalDragPosition,
3315									scrollTimeout,
3316									isFirst = true,
3317									doScroll = function () {
3318									    var offset = clickedTrack.offset(),
3319											pos = e.pageY - offset.top - verticalDragHeight / 2,
3320											contentDragY = paneHeight * settings.scrollPagePercent,
3321											dragY = dragMaxY * contentDragY / (contentHeight - paneHeight);
3322									    if (direction < 0) {
3323									        if (verticalDragPosition - dragY > pos) {
3324									            jsp.scrollByY(-contentDragY);
3325									        } else {
3326									            positionDragY(pos);
3327									        }
3328									    } else if (direction > 0) {
3329									        if (verticalDragPosition + dragY < pos) {
3330									            jsp.scrollByY(contentDragY);
3331									        } else {
3332									            positionDragY(pos);
3333									        }
3334									    } else {
3335									        cancelClick();
3336									        return;
3337									    }
3338									    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
3339									    isFirst = false;
3340									},
3341									cancelClick = function () {
3342									    scrollTimeout && clearTimeout(scrollTimeout);
3343									    scrollTimeout = null;
3344									    $(document).off('mouseup.jsp', cancelClick);
3345									};
3346						        doScroll();
3347						        $(document).on('mouseup.jsp', cancelClick);
3348						        return false;
3349						    }
3350						}
3351					);
3352                }
3353
3354                if (isScrollableH) {
3355                    horizontalTrack.on(
3356						'mousedown.jsp',
3357						function (e) {
3358						    if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
3359						        var clickedTrack = $(this),
3360									offset = clickedTrack.offset(),
3361									direction = e.pageX - offset.left - horizontalDragPosition,
3362									scrollTimeout,
3363									isFirst = true,
3364									doScroll = function () {
3365									    var offset = clickedTrack.offset(),
3366											pos = e.pageX - offset.left - horizontalDragWidth / 2,
3367											contentDragX = paneWidth * settings.scrollPagePercent,
3368											dragX = dragMaxX * contentDragX / (contentWidth - paneWidth);
3369									    if (direction < 0) {
3370									        if (horizontalDragPosition - dragX > pos) {
3371									            jsp.scrollByX(-contentDragX);
3372									        } else {
3373									            positionDragX(pos);
3374									        }
3375									    } else if (direction > 0) {
3376									        if (horizontalDragPosition + dragX < pos) {
3377									            jsp.scrollByX(contentDragX);
3378									        } else {
3379									            positionDragX(pos);
3380									        }
3381									    } else {
3382									        cancelClick();
3383									        return;
3384									    }
3385									    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
3386									    isFirst = false;
3387									},
3388									cancelClick = function () {
3389									    scrollTimeout && clearTimeout(scrollTimeout);
3390									    scrollTimeout = null;
3391									    $(document).off('mouseup.jsp', cancelClick);
3392									};
3393						        doScroll();
3394						        $(document).on('mouseup.jsp', cancelClick);
3395						        return false;
3396						    }
3397						}
3398					);
3399                }
3400            }
3401
3402            function removeClickOnTrack() {
3403                if (horizontalTrack) {
3404                    horizontalTrack.off('mousedown.jsp');
3405                }
3406                if (verticalTrack) {
3407                    verticalTrack.off('mousedown.jsp');
3408                }
3409            }
3410
3411            function cancelDrag() {
3412                $('html').off('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp');
3413
3414                if (verticalDrag) {
3415                    verticalDrag.removeClass('jspActive');
3416                }
3417                if (horizontalDrag) {
3418                    horizontalDrag.removeClass('jspActive');
3419                }
3420            }
3421
3422            function positionDragY(destY, animate) {
3423                if (!isScrollableV) {
3424                    return;
3425                }
3426                if (destY < 0) {
3427                    destY = 0;
3428                } else if (destY > dragMaxY) {
3429                    destY = dragMaxY;
3430                }
3431
3432                // can't just check if(animate) because false is a valid value that could be passed in...
3433                if (animate === undefined) {
3434                    animate = settings.animateScroll;
3435                }
3436                if (animate) {
3437                    jsp.animate(verticalDrag, 'top', destY, _positionDragY);
3438                } else {
3439                    verticalDrag.css('top', destY);
3440                    _positionDragY(destY);
3441                }
3442
3443            }
3444
3445            function _positionDragY(destY) {
3446                if (destY === undefined) {
3447                    destY = verticalDrag.position().top;
3448                }
3449
3450                container.scrollTop(0);
3451                verticalDragPosition = destY;
3452
3453                var isAtTop = verticalDragPosition === 0,
3454					isAtBottom = verticalDragPosition == dragMaxY,
3455					percentScrolled = destY / dragMaxY,
3456					destTop = -percentScrolled * (contentHeight - paneHeight);
3457
3458                if (wasAtTop != isAtTop || wasAtBottom != isAtBottom) {
3459                    wasAtTop = isAtTop;
3460                    wasAtBottom = isAtBottom;
3461                    elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
3462                }
3463
3464                updateVerticalArrows(isAtTop, isAtBottom);
3465                pane.css('top', destTop);
3466                elem.trigger('jsp-scroll-y', [-destTop, isAtTop, isAtBottom]).trigger('scroll');
3467            }
3468
3469            function positionDragX(destX, animate) {
3470                if (!isScrollableH) {
3471                    return;
3472                }
3473                if (destX < 0) {
3474                    destX = 0;
3475                } else if (destX > dragMaxX) {
3476                    destX = dragMaxX;
3477                }
3478
3479                if (animate === undefined) {
3480                    animate = settings.animateScroll;
3481                }
3482                if (animate) {
3483                    jsp.animate(horizontalDrag, 'left', destX, _positionDragX);
3484                } else {
3485                    horizontalDrag.css('left', destX);
3486                    _positionDragX(destX);
3487                }
3488            }
3489
3490            function _positionDragX(destX) {
3491                if (destX === undefined) {
3492                    destX = horizontalDrag.position().left;
3493                }
3494
3495                container.scrollTop(0);
3496                horizontalDragPosition = destX;
3497
3498                var isAtLeft = horizontalDragPosition === 0,
3499					isAtRight = horizontalDragPosition == dragMaxX,
3500					percentScrolled = destX / dragMaxX,
3501					destLeft = -percentScrolled * (contentWidth - paneWidth);
3502
3503                if (wasAtLeft != isAtLeft || wasAtRight != isAtRight) {
3504                    wasAtLeft = isAtLeft;
3505                    wasAtRight = isAtRight;
3506                    elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
3507                }
3508
3509                updateHorizontalArrows(isAtLeft, isAtRight);
3510                pane.css('left', destLeft);
3511                elem.trigger('jsp-scroll-x', [-destLeft, isAtLeft, isAtRight]).trigger('scroll');
3512            }
3513
3514            function updateVerticalArrows(isAtTop, isAtBottom) {
3515                if (settings.showArrows) {
3516                    arrowUp[isAtTop ? 'addClass' : 'removeClass']('jspDisabled');
3517                    arrowDown[isAtBottom ? 'addClass' : 'removeClass']('jspDisabled');
3518                }
3519            }
3520
3521            function updateHorizontalArrows(isAtLeft, isAtRight) {
3522                if (settings.showArrows) {
3523                    arrowLeft[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
3524                    arrowRight[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
3525                }
3526            }
3527
3528            function scrollToY(destY, animate) {
3529                var percentScrolled = destY / (contentHeight - paneHeight);
3530                positionDragY(percentScrolled * dragMaxY, animate);
3531            }
3532
3533            function scrollToX(destX, animate) {
3534                var percentScrolled = destX / (contentWidth - paneWidth);
3535                positionDragX(percentScrolled * dragMaxX, animate);
3536            }
3537
3538            function scrollToElement(ele, stickToTop, animate) {
3539                var e, eleHeight, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX;
3540
3541                // Legal hash values aren't necessarily legal jQuery selectors so we need to catch any
3542                // errors from the lookup...
3543                try {
3544                    e = $(ele);
3545                } catch (err) {
3546                    return;
3547                }
3548                eleHeight = e.outerHeight();
3549                eleWidth = e.outerWidth();
3550
3551                container.scrollTop(0);
3552                container.scrollLeft(0);
3553
3554                // loop through parents adding the offset top of any elements that are relatively positioned between
3555                // the focused element and the jspPane so we can get the true distance from the top
3556                // of the focused element to the top of the scrollpane...
3557                while (!e.is('.jspPane')) {
3558                    eleTop += e.position().top;
3559                    eleLeft += e.position().left;
3560                    e = e.offsetParent();
3561                    if (/^body|html$/i.test(e[0].nodeName)) {
3562                        // we ended up too high in the document structure. Quit!
3563                        return;
3564                    }
3565                }
3566
3567                viewportTop = contentPositionY();
3568                maxVisibleEleTop = viewportTop + paneHeight;
3569                if (eleTop < viewportTop || stickToTop) { // element is above viewport
3570                    destY = eleTop - settings.verticalGutter;
3571                } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport
3572                    destY = eleTop - paneHeight + eleHeight + settings.verticalGutter;
3573                }
3574                if (destY) {
3575                    scrollToY(destY, animate);
3576                }
3577
3578                viewportLeft = contentPositionX();
3579                maxVisibleEleLeft = viewportLeft + paneWidth;
3580                if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport
3581                    destX = eleLeft - settings.horizontalGutter;
3582                } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport
3583                    destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter;
3584                }
3585                if (destX) {
3586                    scrollToX(destX, animate);
3587                }
3588
3589            }
3590
3591            function contentPositionX() {
3592                return -pane.position().left;
3593            }
3594
3595            function contentPositionY() {
3596                return -pane.position().top;
3597            }
3598
3599            function isCloseToBottom() {
3600                var scrollableHeight = contentHeight - paneHeight;
3601                return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10);
3602            }
3603
3604            function isCloseToRight() {
3605                var scrollableWidth = contentWidth - paneWidth;
3606                return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10);
3607            }
3608
3609            function initMousewheel() {
3610                container.off(mwEvent).on(
3611					mwEvent,
3612					function (event, delta, deltaX, deltaY) {
3613					    var dX = horizontalDragPosition, dY = verticalDragPosition;
3614					    jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -deltaY * settings.mouseWheelSpeed, false);
3615					    // return true if there was no movement so rest of screen can scroll
3616					    return dX == horizontalDragPosition && dY == verticalDragPosition;
3617					}
3618				);
3619            }
3620
3621            function removeMousewheel() {
3622                container.off(mwEvent);
3623            }
3624
3625            function nil() {
3626                return false;
3627            }
3628
3629            function initFocusHandler() {
3630                pane.find(':input,a').off('focus.jsp').on(
3631					'focus.jsp',
3632					function (e) {
3633					    scrollToElement(e.target, false);
3634					}
3635				);
3636            }
3637
3638            function removeFocusHandler() {
3639                pane.find(':input,a').off('focus.jsp');
3640            }
3641
3642            function initKeyboardNav() {
3643                var keyDown, elementHasScrolled, validParents = [];
3644                isScrollableH && validParents.push(horizontalBar[0]);
3645                isScrollableV && validParents.push(verticalBar[0]);
3646
3647                // IE also focuses elements that don't have tabindex set.
3648                pane.focus(
3649					function () {
3650					    elem.focus();
3651					}
3652				);
3653
3654                elem.attr('tabindex', 0)
3655					.off('keydown.jsp keypress.jsp')
3656					.on(
3657						'keydown.jsp',
3658						function (e) {
3659						    if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)) {
3660						        return;
3661						    }
3662						    var dX = horizontalDragPosition, dY = verticalDragPosition;
3663						    switch (e.keyCode) {
3664						        case 40: // down
3665						        case 38: // up
3666						        case 34: // page down
3667						        case 32: // space
3668						        case 33: // page up
3669						        case 39: // right
3670						        case 37: // left
3671						            keyDown = e.keyCode;
3672						            keyDownHandler();
3673						            break;
3674						        case 35: // end
3675						            scrollToY(contentHeight - paneHeight);
3676						            keyDown = null;
3677						            break;
3678						        case 36: // home
3679						            scrollToY(0);
3680						            keyDown = null;
3681						            break;
3682						    }
3683
3684						    elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition;
3685						    return !elementHasScrolled;
3686						}
3687					).off(
3688						'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls...
3689						function (e) {
3690						    if (e.keyCode == keyDown) {
3691						        keyDownHandler();
3692						    }
3693						    return !elementHasScrolled;
3694						}
3695					);
3696
3697                if (settings.hideFocus) {
3698                    elem.css('outline', 'none');
3699                    if ('hideFocus' in container[0]) {
3700                        elem.attr('hideFocus', true);
3701                    }
3702                } else {
3703                    elem.css('outline', '');
3704                    if ('hideFocus' in container[0]) {
3705                        elem.attr('hideFocus', false);
3706                    }
3707                }
3708
3709                function keyDownHandler() {
3710                    var dX = horizontalDragPosition, dY = verticalDragPosition;
3711                    switch (keyDown) {
3712                        case 40: // down
3713                            jsp.scrollByY(settings.keyboardSpeed, false);
3714                            break;
3715                        case 38: // up
3716                            jsp.scrollByY(-settings.keyboardSpeed, false);
3717                            break;
3718                        case 34: // page down
3719                        case 32: // space
3720                            jsp.scrollByY(paneHeight * settings.scrollPagePercent, false);
3721                            break;
3722                        case 33: // page up
3723                            jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false);
3724                            break;
3725                        case 39: // right
3726                            jsp.scrollByX(settings.keyboardSpeed, false);
3727                            break;
3728                        case 37: // left
3729                            jsp.scrollByX(-settings.keyboardSpeed, false);
3730                            break;
3731                    }
3732
3733                    elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition;
3734                    return elementHasScrolled;
3735                }
3736            }
3737
3738            function removeKeyboardNav() {
3739                elem.attr('tabindex', '-1')
3740					.removeAttr('tabindex')
3741					.off('keydown.jsp keypress.jsp');
3742            }
3743
3744            function observeHash() {
3745                if (location.hash && location.hash.length > 1) {
3746                    var e,
3747						retryInt,
3748						hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS
3749                    ;
3750                    try {
3751                        e = $('#' + hash + ', a[name="' + hash + '"]');
3752                    } catch (err) {
3753                        return;
3754                    }
3755
3756                    if (e.length && pane.find(hash)) {
3757                        // nasty workaround but it appears to take a little while before the hash has done its thing
3758                        // to the rendered page so we just wait until the container's scrollTop has been messed up.
3759                        if (container.scrollTop() === 0) {
3760                            retryInt = setInterval(
3761								function () {
3762								    if (container.scrollTop() > 0) {
3763								        scrollToElement(e, true);
3764								        $(document).scrollTop(container.position().top);
3765								        clearInterval(retryInt);
3766								    }
3767								},
3768								50
3769							);
3770                        } else {
3771                            scrollToElement(e, true);
3772                            $(document).scrollTop(container.position().top);
3773                        }
3774                    }
3775                }
3776            }
3777
3778            function hijackInternalLinks() {
3779                // only register the link handler once
3780                if ($(document.body).data('jspHijack')) {
3781                    return;
3782                }
3783
3784                // remember that the handler was bound
3785                $(document.body).data('jspHijack', true);
3786
3787                // use live handler to also capture newly created links
3788                $(document.body).delegate('a[href*=#]', 'click', function (event) {
3789                    // does the link point to the same page?
3790                    // this also takes care of cases with a <base>-Tag or Links not starting with the hash #
3791                    // e.g. <a href="index.html#test"> when the current url already is index.html
3792                    var href = this.href.substr(0, this.href.indexOf('#')),
3793						locationHref = location.href,
3794						hash,
3795						element,
3796						container,
3797						jsp,
3798						scrollTop,
3799						elementTop;
3800                    if (location.href.indexOf('#') !== -1) {
3801                        locationHref = location.href.substr(0, location.href.indexOf('#'));
3802                    }
3803                    if (href !== locationHref) {
3804                        // the link points to another page
3805                        return;
3806                    }
3807
3808                    // check if jScrollPane should handle this click event
3809                    hash = escape(this.href.substr(this.href.indexOf('#') + 1));
3810
3811                    // find the element on the page
3812                    element;
3813                    try {
3814                        element = $('#' + hash + ', a[name="' + hash + '"]');
3815                    } catch (e) {
3816                        // hash is not a valid jQuery identifier
3817                        return;
3818                    }
3819
3820                    if (!element.length) {
3821                        // this link does not point to an element on this page
3822                        return;
3823                    }
3824
3825                    container = element.closest('.jspScrollable');
3826                    jsp = container.data('jsp');
3827
3828                    // jsp might be another jsp instance than the one, that bound this event
3829                    // remember: this event is only bound once for all instances.
3830                    jsp.scrollToElement(element, true);
3831
3832                    if (container[0].scrollIntoView) {
3833                        // also scroll to the top of the container (if it is not visible)
3834                        scrollTop = $(window).scrollTop();
3835                        elementTop = element.offset().top;
3836                        if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) {
3837                            container[0].scrollIntoView();
3838                        }
3839                    }
3840
3841                    // jsp handled this event, prevent the browser default (scrolling :P)
3842                    event.preventDefault();
3843                });
3844            }
3845
3846            // Init touch on iPad, iPhone, iPod, Android
3847            function initTouch() {
3848                var startX,
3849					startY,
3850					touchStartX,
3851					touchStartY,
3852					moved,
3853					moving = false;
3854
3855                container.off('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').on(
3856					'touchstart.jsp',
3857					function (e) {
3858					    var touch = e.originalEvent.touches[0];
3859					    startX = contentPositionX();
3860					    startY = contentPositionY();
3861					    touchStartX = touch.pageX;
3862					    touchStartY = touch.pageY;
3863					    moved = false;
3864					    moving = true;
3865					}
3866				).on(
3867					'touchmove.jsp',
3868					function (ev) {
3869					    if (!moving) {
3870					        return;
3871					    }
3872
3873					    var touchPos = ev.originalEvent.touches[0],
3874							dX = horizontalDragPosition, dY = verticalDragPosition;
3875
3876					    jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY);
3877
3878					    moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5;
3879
3880					    // return true if there was no movement so rest of screen can scroll
3881					    return dX == horizontalDragPosition && dY == verticalDragPosition;
3882					}
3883				).on(
3884					'touchend.jsp',
3885					function (e) {
3886					    moving = false;
3887					    /*if(moved) {
3888							return false;
3889						}*/
3890					}
3891				).on(
3892					'click.jsp-touchclick',
3893					function (e) {
3894					    if (moved) {
3895					        moved = false;
3896					        return false;
3897					    }
3898					}
3899				);
3900            }
3901
3902            function destroy() {
3903                var currentY = contentPositionY(),
3904					currentX = contentPositionX();
3905                elem.removeClass('jspScrollable').off('.jsp');
3906                elem.replaceWith(originalElement.append(pane.children()));
3907                originalElement.scrollTop(currentY);
3908                originalElement.scrollLeft(currentX);
3909
3910                // clear reinitialize timer if active
3911                if (reinitialiseInterval) {
3912                    clearInterval(reinitialiseInterval);
3913                }
3914            }
3915
3916            // Public API
3917            $.extend(
3918				jsp,
3919				{
3920				    // Reinitialises the scroll pane (if it's internal dimensions have changed since the last time it
3921				    // was initialised). The settings object which is passed in will override any settings from the
3922				    // previous time it was initialised - if you don't pass any settings then the ones from the previous
3923				    // initialisation will be used.
3924				    reinitialise: function (s) {
3925				        s = $.extend({}, settings, s);
3926				        initialise(s);
3927				    },
3928				    // Scrolls the specified element (a jQuery object, DOM node or jQuery selector string) into view so
3929				    // that it can be seen within the viewport. If stickToTop is true then the element will appear at
3930				    // the top of the viewport, if it is false then the viewport will scroll as little as possible to
3931				    // show the element. You can also specify if you want animation to occur. If you don't provide this
3932				    // argument then the animateScroll value from the settings object is used instead.
3933				    scrollToElement: function (ele, stickToTop, animate) {
3934				        scrollToElement(ele, stickToTop, animate);
3935				    },
3936				    // Scrolls the pane so that the specified co-ordinates within the content are at the top left
3937				    // of the viewport. animate is optional and if not passed then the value of animateScroll from
3938				    // the settings object this jScrollPane was initialised with is used.
3939				    scrollTo: function (destX, destY, animate) {
3940				        scrollToX(destX, animate);
3941				        scrollToY(destY, animate);
3942				    },
3943				    // Scrolls the pane so that the specified co-ordinate within the content is at the left of the
3944				    // viewport. animate is optional and if not passed then the value of animateScroll from the settings
3945				    // object this jScrollPane was initialised with is used.
3946				    scrollToX: function (destX, animate) {
3947				        scrollToX(destX, animate);
3948				    },
3949				    // Scrolls the pane so that the specified co-ordinate within the content is at the top of the
3950				    // viewport. animate is optional and if not passed then the value of animateScroll from the settings
3951				    // object this jScrollPane was initialised with is used.
3952				    scrollToY: function (destY, animate) {
3953				        scrollToY(destY, animate);
3954				    },
3955				    // Scrolls the pane to the specified percentage of its maximum horizontal scroll position. animate
3956				    // is optional and if not passed then the value of animateScroll from the settings object this
3957				    // jScrollPane was initialised with is used.
3958				    scrollToPercentX: function (destPercentX, animate) {
3959				        scrollToX(destPercentX * (contentWidth - paneWidth), animate);
3960				    },
3961				    // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate
3962				    // is optional and if not passed then the value of animateScroll from the settings object this
3963				    // jScrollPane was initialised with is used.
3964				    scrollToPercentY: function (destPercentY, animate) {
3965				        scrollToY(destPercentY * (contentHeight - paneHeight), animate);
3966				    },
3967				    // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
3968				    // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
3969				    scrollBy: function (deltaX, deltaY, animate) {
3970				        jsp.scrollByX(deltaX, animate);
3971				        jsp.scrollByY(deltaY, animate);
3972				    },
3973				    // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
3974				    // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
3975				    scrollByX: function (deltaX, animate) {
3976				        var destX = contentPositionX() + Math[deltaX < 0 ? 'floor' : 'ceil'](deltaX),
3977							percentScrolled = destX / (contentWidth - paneWidth);
3978				        positionDragX(percentScrolled * dragMaxX, animate);
3979				    },
3980				    // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
3981				    // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
3982				    scrollByY: function (deltaY, animate) {
3983				        var destY = contentPositionY() + Math[deltaY < 0 ? 'floor' : 'ceil'](deltaY),
3984							percentScrolled = destY / (contentHeight - paneHeight);
3985				        positionDragY(percentScrolled * dragMaxY, animate);
3986				    },
3987				    // Positions the horizontal drag at the specified x position (and updates the viewport to reflect
3988				    // this). animate is optional and if not passed then the value of animateScroll from the settings
3989				    // object this jScrollPane was initialised with is used.
3990				    positionDragX: function (x, animate) {
3991				        positionDragX(x, animate);
3992				    },
3993				    // Positions the vertical drag at the specified y position (and updates the viewport to reflect
3994				    // this). animate is optional and if not passed then the value of animateScroll from the settings
3995				    // object this jScrollPane was initialised with is used.
3996				    positionDragY: function (y, animate) {
3997				        positionDragY(y, animate);
3998				    },
3999				    // This method is called when jScrollPane is trying to animate to a new position. You can override
4000				    // it if you want to provide advanced animation functionality. It is passed the following arguments:
4001				    //  * ele          - the element whose position is being animated
4002				    //  * prop         - the property that is being animated
4003				    //  * value        - the value it's being animated to
4004				    //  * stepCallback - a function that you must execute each time you update the value of the property
4005				    // You can use the default implementation (below) as a starting point for your own implementation.
4006				    animate: function (ele, prop, value, stepCallback) {
4007				        var params = {};
4008				        params[prop] = value;
4009				        ele.animate(
4010							params,
4011							{
4012							    'duration': settings.animateDuration,
4013							    'easing': settings.animateEase,
4014							    'queue': false,
4015							    'step': stepCallback
4016							}
4017						);
4018				    },
4019				    // Returns the current x position of the viewport with regards to the content pane.
4020				    getContentPositionX: function () {
4021				        return contentPositionX();
4022				    },
4023				    // Returns the current y position of the viewport with regards to the content pane.
4024				    getContentPositionY: function () {
4025				        return contentPositionY();
4026				    },
4027				    // Returns the width of the content within the scroll pane.
4028				    getContentWidth: function () {
4029				        return contentWidth;
4030				    },
4031				    // Returns the height of the content within the scroll pane.
4032				    getContentHeight: function () {
4033				        return contentHeight;
4034				    },
4035				    // Returns the horizontal position of the viewport within the pane content.
4036				    getPercentScrolledX: function () {
4037				        return contentPositionX() / (contentWidth - paneWidth);
4038				    },
4039				    // Returns the vertical position of the viewport within the pane content.
4040				    getPercentScrolledY: function () {
4041				        return contentPositionY() / (contentHeight - paneHeight);
4042				    },
4043				    // Returns whether or not this scrollpane has a horizontal scrollbar.
4044				    getIsScrollableH: function () {
4045				        return isScrollableH;
4046				    },
4047				    // Returns whether or not this scrollpane has a vertical scrollbar.
4048				    getIsScrollableV: function () {
4049				        return isScrollableV;
4050				    },
4051				    // Gets a reference to the content pane. It is important that you use this method if you want to
4052				    // edit the content of your jScrollPane as if you access the element directly then you may have some
4053				    // problems (as your original element has had additional elements for the scrollbars etc added into
4054				    // it).
4055				    getContentPane: function () {
4056				        return pane;
4057				    },
4058				    // Scrolls this jScrollPane down as far as it can currently scroll. If animate isn't passed then the
4059				    // animateScroll value from settings is used instead.
4060				    scrollToBottom: function (animate) {
4061				        positionDragY(dragMaxY, animate);
4062				    },
4063				    // Hijacks the links on the page which link to content inside the scrollpane. If you have changed
4064				    // the content of your page (e.g. via AJAX) and want to make sure any new anchor links to the
4065				    // contents of your scroll pane will work then call this function.
4066				    hijackInternalLinks: $.noop,
4067				    // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was
4068				    // initialised.
4069				    destroy: function () {
4070				        destroy();
4071				    }
4072				}
4073			);
4074
4075            initialise(s);
4076        }
4077
4078        // Pluginifying code...
4079        settings = $.extend({}, $.fn.jScrollPane.defaults, settings);
4080
4081        // Apply default speed
4082        $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function () {
4083            settings[this] = settings[this] || settings.speed;
4084        });
4085
4086        return this.each(
4087			function () {
4088			    var elem = $(this), jspApi = elem.data('jsp');
4089			    if (jspApi) {
4090			        jspApi.reinitialise(settings);
4091			    } else {
4092			        $("script", elem).filter('[type="text/javascript"], :not([type])').remove();
4093			        jspApi = new JScrollPane(elem, settings);
4094			        elem.data('jsp', jspApi);
4095			    }
4096			}
4097		);
4098    };
4099
4100    $.fn.jScrollPane.defaults = {
4101        showArrows: false,
4102        maintainPosition: true,
4103        stickToBottom: false,
4104        stickToRight: false,
4105        clickOnTrack: true,
4106        autoReinitialise: false,
4107        autoReinitialiseDelay: 500,
4108        verticalDragMinHeight: 30,
4109        verticalDragMaxHeight: 99999,
4110        horizontalDragMinWidth: 30,
4111        horizontalDragMaxWidth: 99999,
4112        contentWidth: undefined,
4113        animateScroll: false,
4114        animateDuration: 300,
4115        animateEase: 'linear',
4116        hijackInternalLinks: false,
4117        verticalGutter: 4,
4118        horizontalGutter: 4,
4119        mouseWheelSpeed: 0,
4120        arrowButtonSpeed: 0,
4121        arrowRepeatFreq: 50,
4122        arrowScrollOnHover: false,
4123        trackClickSpeed: 0,
4124        trackClickRepeatFreq: 70,
4125        verticalArrowPositions: 'split',
4126        horizontalArrowPositions: 'split',
4127        enableKeyboardNavigation: true,
4128        hideFocus: false,
4129        keyboardSpeed: 0,
4130        initialDelay: 300,        // Delay before starting repeating
4131        speed: 30,		// Default speed when others falsey
4132        scrollPagePercent: .8		// Percent of visible area scrolled when pageUp/Down or track area pressed
4133    };
4134
4135})(jQuery);
4136
4137(function ($) {
4138    $.fn.dnnSettingDropdown = function () {
4139        var clicked = function () {
4140            if ($(this).hasClass('dnnButtonDropdown')) {
4141                $(this).removeClass('dnnButtonDropdown').addClass('dnnButtonDropdown-clicked');
4142                $(this).next().show();
4143            }
4144        };
4145
4146        var hideDropdown = function () {
4147            var btn = $(this).children(':first');
4148            if (btn.hasClass('dnnButtonDropdown-clicked')) {
4149                btn.removeClass('dnnButtonDropdown-clicked').addClass('dnnButtonDropdown');
4150                btn.next().fadeOut();
4151            }
4152        };
4153
4154        var hoverConfig = {
4155            over: function () {
4156            },
4157            out: hideDropdown,
4158            timout: 600
4159        };
4160
4161        return $(this).each(function () {
4162            $(this).off('click', clicked).on('click', clicked);
4163            $(this).parent().hoverIntent(hoverConfig);
4164        });
4165    };
4166})(jQuery);
4167
4168(function ($) {
4169    $.fn.onEnter = function (fn) {
4170        return this.each(function () {
4171            var $this = $(this);
4172            $this.on('onEnter', fn);
4173            $this.keydown(function (e) {
4174                if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) {
4175                    e.preventDefault();
4176                    e.stopPropagation();
4177                    $this.trigger('onEnter');
4178                }
4179            });
4180        });
4181    };
4182})(jQuery);
4183
4184(function ($) {
4185    $.extend({
4186        onAjaxError: function (jqXhr, textStatus, errorThrown) {
4187            var title, text;
4188            if (jqXhr && jqXhr.status === 401) {
4189                dnnModal.show('../Login.aspx' + '?popUp=true', true, 300, 650, true, '');
4190                return;
4191            }
4192            if (jqXhr && jqXhr.responseText && jqXhr.statusText) {
4193                try {
4194                    title = jqXhr.statusText + " (" + jqXhr.status + ")";
4195                    text = JSON.parse(jqXhr.responseText).Message;
4196                }
4197                catch (e) {
4198                    text = errorThrown;
4199                }
4200            }
4201            $.dnnAlert({ title: title || "Error", text: text || "Unknown error" });
4202        }
4203    });
4204})(jQuery);
4205
4206(function ($) {
4207	$.fn.dnnSliderInput = function (options) {
4208		var sliderOptions = $.extend({}, $.fn.dnnSliderInput.defaults, options);
4209    	return $(this).each(function () {
4210    		var $this = $(this);
4211		    var value = $this.val();
4212		    var $slider = $('<div></div>', { class: "dnnSliderInput" });
4213		    $this.hide().after($slider);
4214
4215		    $slider.slider(sliderOptions);
4216		    $slider.slider('value', value);
4217
4218		    var $tooltip = $('<span></span>', { class: "dnnTooltip" });
4219            var $tooltipContent = $('<span></span>', { class: "dnnFormHelpContent dnnClear" });
4220            var $tooltipText = $('<span></span>', { class: "dnnHelpText bottomArrow" });
4221            $tooltipContent.add($tooltipText);
4222            $tooltip.add($tooltipContent);
4223
4224		    var calcTooltipPosition = function () {
4225			    setTimeout(function() {
4226				    var left = $slider.find('.ui-slider-handle')[0].style.left;
4227				    $tooltip.css('left', left);
4228			    }, 0);
4229		    };
4230
4231            $tooltipText.text(value);
4232		    $tooltip.data('initialized', true);
4233			$slider.append($tooltip);
4234
4235		    calcTooltipPosition();
4236		    $slider.on('slide', function(event, ui) {
4237                $tooltipText.text(ui.value);
4238		    	$this.val(ui.value);
4239			    calcTooltipPosition();
4240		    });
4241	    });
4242    };
4243
4244	$.fn.dnnSliderInput.defaults = {
4245		min: 0,
4246		max: 100,
4247		step: 1
4248	}
4249})(jQuery);
4250
4251// please keep this func at last of this file, thanks
4252(function ($) {
4253    /* Start customised controls */
4254    var inputFocusFix = function () {
4255        var errorMsg = $(this).next();
4256        if (errorMsg.hasClass('dnnFormError'))
4257            errorMsg.hide();
4258    };
4259    var throttle = null;
4260    var dnnInitCustomisedCtrls = function () {
4261        if (throttle != null) {
4262            clearTimeout(throttle);
4263            throttle = null;
4264        }
4265        throttle = setTimeout(function () {
4266            $('.dnnForm input[type="checkbox"]').dnnCheckbox();
4267            $('.dnnForm input[type="radio"]').dnnCheckbox({ cls: 'dnnRadiobutton' });
4268            $('.dnnTooltip').dnnTooltip();
4269            $('.dnnForm input[type="text"], .dnnForm input[type="password"]').off('focus', inputFocusFix).on('focus', inputFocusFix);
4270            $('.dnnForm :file').dnnFileInput();
4271	        $('.dnnForm input[data-default]').dnnPlaceholder();
4272        }, 200);
4273        //change the window confirm style to DNN style
4274        $("*[onclick*='return confirm']").each(function () {
4275            var instance = $(this);
4276            var isButton = this.nodeName.toLowerCase() == "img" || this.nodeName.toLowerCase() == "input";
4277            var script = /return confirm\((['"])([\s\S]*?)\1\)/g.exec(instance.attr("onclick"));
4278            if (script != null) {
4279                var confirmContent = script[2].split("\\" + script[1]).join(script[1]);
4280                //restore unicode chars.
4281                confirmContent = confirmContent.replace(/\\u([\d\w]{4})/gi, function(match, charCode) {
4282                    return String.fromCharCode(parseInt(charCode, 16));
4283                });
4284                instance.attr("onclick", instance.attr("onclick").replace(script[0], "void(0)")).dnnConfirm({
4285                    text: confirmContent,
4286                    isButton: isButton
4287                });
4288            }
4289        });
4290    };
4291    var saveRgDataDivScrollTop = function () {
4292        window.__rgDataDivScrollTopPersistArray = [];
4293        $('.rgDataDiv').each(function () {
4294            var $this = $(this);
4295            var ele = $this.get(0);
4296            if (ele.scrollPane) {
4297                var api = ele.scrollPane.data('jsp');
4298                var y = api.getContentPositionY();
4299                window.__rgDataDivScrollTopPersistArray.push(y);
4300            }
4301        });
4302    };
4303
4304    var handlerSendVerificationMailLink = function() {
4305        $(document.body).on('click', 'a.send-verification-mail', function(e) {
4306            e.preventDefault();
4307
4308            var service = $.dnnSF();
4309            var url = service.getServiceRoot('InternalServices') + 'NewUserNotificationService/SendVerificationMail';
4310            var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val();
4311            url += '?__RequestVerificationToken=' + antiForgeryToken;
4312
4313            $.ajax({
4314                url: url,
4315                beforeSend: service ? service.setModuleHeaders : null,
4316                success: function(data) {
4317                    $.dnnAlert({ text: data.Result });
4318                },
4319                error: function (xhr, textStatus, errorThrown) {
4320                    if (xhr && xhr.responseText) {
4321                        $.dnnAlert({ text: JSON.parse(xhr.responseText).Message });
4322                    }
4323                },
4324                type: 'POST',
4325                dataType: 'json',
4326                contentType: "application/json"
4327            });
4328        });
4329    };
4330
4331    function registerEvents() {
4332        Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(saveRgDataDivScrollTop);
4333        Sys.WebForms.PageRequestManager.getInstance().add_endRequest(dnnInitCustomisedCtrls);
4334    }
4335
4336    window.__rgDataDivScrollTopPersistArray = [];
4337    $(document).ajaxComplete(dnnInitCustomisedCtrls);
4338    $(dnnInitCustomisedCtrls);
4339    $(registerEvents);
4340    handlerSendVerificationMailLink();
4341
4342})(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.