Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla5/media/com_fabrik/js/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla5/media/com_fabrik/js/element.js

/**
 * Element
 *
 * @copyright: Copyright (C) 2005-2013, fabrikar.com - All rights reserved.
 * @license:   GNU/GPL http://www.gnu.org/copyleft/gpl.html
 */

/*jshint mootools: true */
/*global Fabrik:true, fconsole:true, Joomla:true, CloneObject:true,
$H:true,unescape:true,Asset:true */

define(['jquery'], function (jQuery) {
    window.FbElement = new Class({

        Implements: [Events, Options],

        options: {
	        element    : null,
	        defaultVal : '',
	        value      : '',
	        label      : '',
	        editable   : false,
	        isJoin     : false,
	        joinId     : 0,
	        changeEvent: 'change',
            hasAjaxValidation: false
        },

        /**
         * Ini the element
         *
         * @return  bool  false if document.id(this.options.element) not
found
         */

        initialize: function (element, options) {

			var tooltipTriggerList =
[].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
			var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
			  return new bootstrap.Tooltip(tooltipTriggerEl)
			});

            var self = this;
            this.setPlugin('');
            options.element = element;
            this.strElement = element;
            this.loadEvents = []; // need to store these for use if the
form is reset
            this.events = $H({}); // was changeEvents
            this.setOptions(options);
            // If this element is a 'chosen' select, we need to
relay the jQuery change event to Moo
            if (this.options.advanced) {
                var changeEvent = this.getChangeEvent();
                jQuery('#' +
this.options.element).on('change', {changeEvent: changeEvent},
function (event) {
                    document.id(this.id).fireEvent(event.data.changeEvent,
new Event.Mock(document.id(this.id),
                        event.data.changeEvent));
                });
            }

            // In ajax pop up form. Close the validation tip message when
we focus in the element
            Fabrik.on('fabrik.form.element.added', function
(form, elId, el) {
                if (el === self) {
                    self.addNewEvent(self.getFocusEvent(), function () {
                        self.removeTipMsg();
                    });
                }
            });

            return this.setElement();
        },

        /**
         * Called when form closed in ajax window
         * Should remove any events added to Window or Fabrik
         */
        destroy: function () {

        },

        setPlugin: function (plugin) {
            if (typeOf(this.plugin) === 'null' || this.plugin ===
'') {
                this.plugin = plugin;
            }
        },

        getPlugin: function () {
            return this.plugin;
        },

        setElement: function () {
            if (document.id(this.options.element)) {
                this.element = document.id(this.options.element);
                this.setorigId();
                return true;
            }
            return false;
        },

        get: function (v) {
            if (v === 'value') {
                return this.getValue();
            }
        },

        /**
         * Sets the element key used in Fabrik.blocks.form_X.formElements
         * Overwritten by any element which performs a n-n join (multi ajax
fileuploads, dbjoins as checkboxes)
         *
         * @since   3.0.7
         *
         * @return  string
         */
        getFormElementsKey: function (elId) {
            this.baseElementId = elId;
            return elId;
        },

        attachedToForm: function () {
            this.setElement();
            if (Fabrik.bootstrapped) {
                this.alertImage = new Element('i.' +
this.form.options.images.alert);
                this.successImage = new
Element('i.icon-checkmark', {'styles':
{'color': 'green'}});
            } else {
                this.alertImage = new
Asset.image(this.form.options.images.alert);
                this.alertImage.setStyle('cursor',
'pointer');
                this.successImage = new
Asset.image(this.form.options.images.action_check);
            }

            if
(jQuery(this.form.options.images.ajax_loader).data('isicon')) {
                this.loadingImage = new
Element('span').set('html',
this.form.options.images.ajax_loader);
            } else {
                this.loadingImage = new
Asset.image(this.form.options.images.ajax_loader);
            }

            this.form.addMustValidate(this);
            //put ini code in here that can't be put in initialize()
            // generally any code that needs to refer to  this.form, which
            //is only set when the element is assigned to the form.
        },

        /**
         * Allows you to fire an array of events to element /  sub
elements, used in calendar
         * to trigger js events when the calendar closes
         * @param {array} evnts
         */
        fireEvents: function (evnts) {
            if (this.hasSubElements()) {
                this._getSubElements().each(function (el) {
                    Array.mfrom(evnts).each(function (e) {
                        el.fireEvent(e);
                    }.bind(this));
                }.bind(this));
            } else {
                Array.mfrom(evnts).each(function (e) {
                    if (this.element) {
                        this.element.fireEvent(e);
                    }
                }.bind(this));
            }
        },

        getElement: function () {
            //use this in mocha forms whose elements (such as database
joins) aren't loaded
            //when the class is ini'd
            if (typeOf(this.element) === 'null') {
                this.element = document.id(this.options.element);
            }
            return this.element;
        },

        /**
         * Used for elements like checkboxes or radio buttons
         * @returns [DomNodes]
         * @private
         */
        _getSubElements: function () {
            var element = this.getElement();
            if (typeOf(element) === 'null') {
                return false;
            }
            this.subElements =
element.getElements('.fabrikinput');
            return this.subElements;
        },

        hasSubElements: function () {
            this._getSubElements();
            if (typeOf(this.subElements) === 'array' ||
typeOf(this.subElements) === 'elements') {
                return this.subElements.length > 0 ? true : false;
            }
            return false;
        },

        unclonableProperties: function () {
            return ['form'];
        },

        /**
         * Set names/ids/elements etc. when the elements group is cloned
         *
         * @param   int  id  element id
         * @since   3.0.7
         */

        cloneUpdateIds: function (id) {
            this.element = document.id(id);
            this.options.element = id;
        },

        runLoadEvent: function (js, delay) {
            delay = delay ? delay : 0;
            //should use eval and not Browser.exec to maintain reference to
'this'
            if (typeOf(js) === 'function') {
                js.delay(delay);
            } else {
                if (delay === 0) {
                    eval(js);
                } else {
                    (function () {
                        console.log('delayed calling runLoadEvent for
' + delay);
                        eval(js);
                    }.bind(this)).delay(delay);
                }
            }
        },

        /**
         * called from list when ajax form closed
         * fileupload needs to remove its onSubmit event
         * otherwise 2nd form submission will use first forms event
         */
        removeCustomEvents: function () {
        },

        /**
         * Was renewChangeEvents() but don't see why change events
should be treated
         * differently to other events?
         *
         * @since 3.0.7
         */
        renewEvents: function () {
            this.events.each(function (fns, type) {
                this.element.removeEvents(type);
                fns.each(function (js) {
                    this.addNewEventAux(type, js);
                }.bind(this));
            }.bind(this));
        },

        addNewEventAux: function (action, js) {
            this.element.addEvent(action, function (e) {
                // Don't stop event - means fx's onchange events
wouldn't fire.
                typeOf(js) === 'function' ? js.delay(0, this,
this) : eval(js);
            }.bind(this));
        },

        /**
         * Add a JS event to the element
         * @param {string} action
         * @param {string|function} js
         */
        addNewEvent: function (action, js) {
            if (action === 'load') {
                this.loadEvents.push(js);
                this.runLoadEvent(js);
            } else {
                if (!this.element) {
                    this.element = document.id(this.strElement);
                }
                if (this.element) {
                    if (!Object.keys(this.events).contains(action)) {
                        this.events[action] = [];
                    }
                    this.events[action].push(js);
                    this.addNewEventAux(action, js);
                }
            }
        },

        // Alias to addNewEvent.
        addEvent: function (action, js) {
            this.addNewEvent(action, js);
        },

        validate: function () {
        },

        /**
         * Add AJAX validation trigger, called from form model setup or
when cloned
         */
        addAjaxValidationAux: function () {
            var self = this;
            // the hasAjaxValidation flag is only set during setup
            if (this.element && this.options.hasAjaxValidation) {
                var $el = jQuery(this.element);
                if ($el.hasClass('fabrikSubElementContainer')) {
                    // check for things like radio buttons & checkboxes
                   
$el.find('.fabrikinput').on(this.getChangeEvent(), function (e) {
                        self.form.doElementValidation(e, true);
                    });
                    return;
                }
                $el.on(this.getChangeEvent(), function (e) {
                    self.form.doElementValidation(e, false);
                });
            }
        },

        /**
         * Add AJAX validation trigger, called from form model
         */
        addAjaxValidation: function () {
            var self = this;
            if (!this.element) {
                this.element = document.id(this.strElement);
            }
            if (this.element) {
                // set our hasAjaxValidation flag and do the actual event
add
                this.options.hasAjaxValidation = true;
                this.addAjaxValidationAux();
            }
        },

        //store new options created by user in hidden field
        addNewOption: function (val, label) {
            var a;
            var added = document.id(this.options.element +
'_additions').value;
            var json = {'val': val, 'label': label};
            if (added !== '') {
                a = JSON.parse(added);
            } else {
                a = [];
            }
            a.push(json);
            var s = '[';
            for (var i = 0; i < a.length; i++) {
                s += JSON.stringify(a[i]) + ',';
            }
            s = s.substring(0, s.length - 1) + ']';
            document.id(this.options.element +
'_additions').value = s;
        },

        getLabel: function () {
            return this.options.label;
        },

        /**
         * Set the label (uses textContent attribute, prolly won't
work on IE < 9)
         *
         * @param {string} label
         */
        setLabel: function (label) {
            this.options.label = label;
            var c = this.getLabelElement();
            if (c) {
                c[0].textContent = label;
            }
        },

        //below functions can override in plugin element classes

        update: function (val) {
            //have to call getElement() - otherwise inline editor
doesn't work when editing 2nd row of data.
            if (this.getElement()) {
                if (this.options.editable) {
                    this.element.value = val;
                } else {
                    this.element.innerHTML = val;
                }
            }
        },

        /**
         * $$$ hugh - testing something for join elements, where in some
corner cases,
         * like reverse Geocoding in the map element, we need to update
elements that might be
         * joins, and all we have is the label (like "Austria"
for country).  So am overriding this
         * new function in the join element, with code that finds the first
occurrence of the label,
         * and sets the value accordingly.  But all we need to do here is
make it a wrapper for update().
         */
        updateByLabel: function (label) {
            this.update(label);
        },

        // Alias to update()
        set: function (val) {
            this.update(val);
        },

        getValue: function () {
            if (this.element) {
                if (this.options.editable) {
                    return this.element.value;
                } else {
                    return this.options.value;
                }
            }
            return false;
        },

        reset: function () {
            if (this.options.editable === true) {
                this.update(this.options.defaultVal);
            }
            this.resetEvents();
        },

        resetEvents: function () {
            this.loadEvents.each(function (js) {
                this.runLoadEvent(js, 100);
            }.bind(this));
        },

        clear: function () {
            this.update('');
        },

        /**
         * Called from FbFormSubmit
         *
         * @params   function  cb  Callback function to run when the
element is in an
         *                         acceptable state for the form processing
to continue
         *                         Should use cb(true) to allow for the
form submission,
         *                         cb(false) stops the form submission.
         *
         * @return  void
         */
        onsubmit: function (cb) {
            if (cb) {
                cb(true);
            }
        },

        /**
         * As ajax validations call onsubmit to get the correct date, we
need to
         * reset the date back to the display date when the validation is
complete
         */
        afterAjaxValidation: function () {

        },

        /**
         * Called before an AJAX validation is triggered, in case an
element wants to abort it,
         * for example date element with time picker
         */
        shouldAjaxValidate: function () {
            return true;
        },

        /**
         * Run when the element is cloned in a repeat group
         */
        cloned: function (c) {
            this.renewEvents();
            this.resetEvents();
            this.addAjaxValidationAux();
            var changeEvent = this.getChangeEvent();
            if (this.element.hasClass('chosen-done')) {
                this.element.removeClass('chosen-done');
                this.element.addClass('chosen-select');
               
this.element.getParent().getElement('.chosen-container').destroy();
                jQuery('#' + this.element.id).chosen();
                jQuery(this.element).addClass('chosen-done');

                jQuery('#' +
this.options.element).on('change', {changeEvent: changeEvent},
function (event) {
                    document.id(this.id).fireEvent(event.data.changeEvent,
new Event.Mock(event.data.changeEvent,
                        document.id(this.id)));
                });
            }
        },

        /**
         * Run when the element is de-cloned from the form as part of a
deleted repeat group
         */
        decloned: function (groupid) {
            this.form.removeMustValidate(this);
        },

        /**
         * get the wrapper dom element that contains all of the elements
dom objects
         */
        getContainer: function () {
            var c =
jQuery(this.element).closest('.fabrikElementContainer');
            if (c.length === 0) {
                c = false;
            } else {
                c = c[0];
            }
            return typeOf(this.element) === 'null' ? false : c;
        },

        /**
         * get the dom element which shows the error messages
         */
        getErrorElement: function () {
            return
this.getContainer().getElements('.fabrikErrorMessage');
        },

        /**
         * get the dom element which contains the label
         */
        getLabelElement: function () {
            return
this.getContainer().getElements('.fabrikLabel');
        },

        /**
         * Get the fx to fade up/down element validation feedback text
         */
        getValidationFx: function () {
            if (!this.validationFX) {
                this.validationFX = new Fx.Morph(this.getErrorElement()[0],
{duration: 500, wait: true});
            }
            return this.validationFX;
        },

        /**
         * Get all tips attached to the element
         *
         * @return array of tips
         */
        tips: function () {
            var self = this;
            return jQuery(Fabrik.tips.elements).filter(function (index, t)
{
                if (t === self.getContainer() || t.getParent() ===
self.getContainer()) {
                    return true;
                }
            });
        },

        /**
         * In 3.1 show error messages in tips - avoids jumpy pages with
ajax validations
         */
        addTipMsg: function (msg, klass) {
            // Append notice to tip
            klass = klass ? klass : 'error';
            var ul, a, d, li, html, t = this.tips();
            if (t.length === 0) {
                return;
            }
            t = jQuery(t[0]);

            if (t.attr(klass) === undefined) {
                t.attr(klass, msg);
                a = this._tipContent(t, false);

                d = jQuery('<div>');
                d.html(a.html());
                li = jQuery('<li>').addClass(klass);
                li.html(msg);
               
jQuery('<i>').addClass(this.form.options.images.alert).prependTo(li);

                // Only append the message once (was duplicating on
multi-page forms)
                if (d.find('li:contains("' +
jQuery(msg).text() + '")').length === 0) {
                    d.find('ul').append(li);
                }
                html = unescape(d.html());

                if (t.data('fabrik-tip-orig') === undefined) {
                    t.data('fabrik-tip-orig', a.html());
                }

                this._recreateTip(t, html);
            }
            try {
                t.data('popover').show();
            } catch (e) {
                t.popover('show');
            }
        },

        /**
         * Recreate the popover tip with html
         * @param {jQuery} t
         * @param {string} html
         * @private
         */
        _recreateTip: function (t, html) {
            try {
                t.data('content', html);
                t.data('popover').setContent();
                t.data('popover').options.content = html;
            } catch (e) {
                // Try Bootstrap 3
                //t.popover('destroy');
                t.attr('data-bs-content', html);
                t.popover('show');
            }
        },

        /**
         * Get tip content
         * @param {jQuery} t
         * @param {bool} get original tip message (true) or computed tip
message (false)
         * @returns {*}
         * @private
         */
        _tipContent: function (t, getOrig) {
            var a;
            try {
                t.data('popover').show();
                a =
t.data('popover').tip().find('.popover-content');
            } catch (err) {
                // Try Bootstrap 3
                if (t.data('fabrik-tip-orig') === undefined ||
!getOrig) {
                    a =
jQuery('<div>').append(jQuery(t.data('content')));
                } else {
                    a =
jQuery('<div>').append(jQuery(t.data('fabrik-tip-orig')));
                }
            }
            return a;
        },

        /**
         * In 3.1 show/hide error messages in tips - avoids jumpy pages
with ajax validations
         */
        removeTipMsg: function () {
            var a, klass = klass ? klass : 'error',
                t = this.tips();
            t = jQuery(t[0]);
            if (t.attr(klass) !== undefined) {
                a = this._tipContent(t, true);
                this._recreateTip(t, a.html());
                t.removeAttr(klass);
                try {
                    t.data('popover').hide();
                } catch (e) {
                    t.popover('hide');
                }
            }
        },

        /**
         * Move the tip using its position top property. Used when inside a
modal form that
         * scrolls vertically or modal is moved, and ensures the tip stays
attached to the triggering element
         * @param {number} top
         * @param {number} left
         */
        moveTip: function (top, left) {
            var t = this.tips(), tip, origPos, popover;
            if (t.length > 0) {
                t = jQuery(t[0]);
                popover = t.data('popover');
                if (popover) {
                    tip = popover.$tip;
                    if (tip) {
                        origPos = tip.data('origPos');
                        if (origPos === undefined) {
                            origPos = {
                                'top':
parseInt(t.data('popover').$tip.css('top'), 10) + top,
                                'left':
parseInt(t.data('popover').$tip.css('left'), 10) + left
                            };
                            tip.data('origPos', origPos);
                        }
                        tip.css({
                            'top': origPos.top - top,
                            'left': origPos.left - left
                        });
                    }
                }
            }
        },

        /**
         * Set the failed validation message
         * @param {string} msg
         * @param {string} classname
         */
        setErrorMessage: function (msg, classname) {
            var a, i;
            var classes = ['fabrikValidating',
'fabrikError', 'fabrikSuccess'];
            var container = this.getContainer();
            if (container === false) {
                console.log('Notice: couldn not set error msg for
' + msg + ' no container class found');
                return;
            }
            classes.each(function (c) {
                var r = classname === c ? container.addClass(c) :
container.removeClass(c);
            });
            var errorElements = this.getErrorElement();
            errorElements.each(function (e) {
                e.empty();
            });
            switch (classname) {
                case 'fabrikError':
                    Fabrik.loader.stop(this.element);
                    // repeat groups in table format don't have
anything to attach a tip msg to!
                    var t = this.tips();
                    if (Fabrik.bootstrapped && t.length !== 0) {
                        this.addTipMsg(msg);
                    } else {
						var raw_msg = jQuery(msg).text();
                        a = new Element('a', {
                            'href': '#',
'class':'text-danger', 'text': raw_msg,
'events': {
                                'click': function (e) {
                                    e.stop();
                                }
                            }
                        });
						a.prepend(this.alertImage);
                        Fabrik.tips.attach(a);
                    }
                    errorElements[0].adopt(a);

                   
container.removeClass('success').removeClass('info').addClass('error');
                    // bs3
                   
container.addClass('has-error').removeClass('has-success');
					//bs5
					this.element.addClass('is-invalid').removeClass('is-valid')

                    // If tmpl has additional error message divs (e.g
labels above) then set html msg there
                    if (errorElements.length > 1) {
                        for (i = 1; i < errorElements.length; i++) {
                            errorElements[i].set('html', msg);
                        }
                    }

                    var tabDiv = this.getTabDiv();
                    if (tabDiv) {
                        var tab = this.getTab(tabDiv);
                        if (tab) {
                            tab.addClass('fabrikErrorGroup');
                        }
                    }

                    break;
                case 'fabrikSuccess':
                   
container.addClass('success').removeClass('info').removeClass('error');
                   
container.addClass('has-success').removeClass('has-error');
					//bs5
					this.element.addClass('is-valid').removeClass('is-invalid');
                    if (Fabrik.bootstrapped) {
                        Fabrik.loader.stop(this.element);
                        this.removeTipMsg();
                    } else {

                        errorElements[0].adopt(this.successImage);
                        var delFn = function () {
                           
errorElements[0].addClass('fabrikHide');
                            container.removeClass('success');
                        };
                        delFn.delay(700);
                    }
                    break;
                case 'fabrikValidating':
                   
container.removeClass('success').addClass('info').removeClass('error');
                    //errorElements[0].adopt(this.loadingImage);
                    Fabrik.loader.start(this.element, msg);
                    break;
            }

            this.getErrorElement().removeClass('fabrikHide');
            var parent = this.form;
            if (classname === 'fabrikError' || classname ===
'fabrikSuccess') {
                parent.updateMainError();
            }

            var fx = this.getValidationFx();
            switch (classname) {
                case 'fabrikValidating':
                case 'fabrikError':
                    fx.start({
                        'opacity': 1
                    });
                    break;
                case 'fabrikSuccess':
                    fx.start({
                        'opacity': 1
                    }).chain(function () {
                        // Only fade out if its still the success message
                        if (container.hasClass('fabrikSuccess'))
{
                           
container.removeClass('fabrikSuccess');
                            this.start.delay(700, this, {
                                'opacity'   : 0,
                                'onComplete': function () {
                                   
container.addClass('success').removeClass('error');
                                    parent.updateMainError();
                                    classes.each(function (c) {
                                        container.removeClass(c);
                                    });
                                }
                            });
                        }
                    });
                    break;
            }
        },

        setorigId: function () {
            // $$$ added inRepeatGroup option, as repeatCounter > 0
doesn't help
            // if element is in first repeat of a group
            //if (this.options.repeatCounter > 0) {
            if (this.options.inRepeatGroup) {
                var e = this.options.element;
                this.origId = e.substring(0, e.length - 1 -
this.options.repeatCounter.toString().length);
            }
        },

        decreaseName: function (delIndex) {
            var element = this.getElement();
            if (typeOf(element) === 'null') {
                return false;
            }
            if (this.hasSubElements()) {
                this._getSubElements().each(function (e) {
                    e.name = this._decreaseName(e.name, delIndex);
                    e.id = this._decreaseId(e.id, delIndex);
                }.bind(this));
            } else {
                if (typeOf(this.element.name) !== 'null') {
                    this.element.name =
this._decreaseName(this.element.name, delIndex);
                }
            }
            if (typeOf(this.element.id) !== 'null') {
                this.element.id = this._decreaseId(this.element.id,
delIndex);
            }
            if (this.options.repeatCounter > delIndex) {
                this.options.repeatCounter--;
            }
            return this.element.id;
        },

        /**
         * @param    string    name to decrease
         * @param    int        delete index
         * @param    string    name suffix to keep (used for db join
autocomplete element)
         */

        _decreaseId: function (n, delIndex, suffix) {
            var suffixFound = false;
            suffix = suffix ? suffix : false;
            if (suffix !== false) {
                if (n.contains(suffix)) {
                    n = n.replace(suffix, '');
                    suffixFound = true;
                }
            }
            var bits = Array.mfrom(n.split('_'));
            var i = bits.getLast();
            if (typeOf(i.toInt()) === 'null') {
                return bits.join('_');
            }
            if (i >= 1 && i > delIndex) {
                i--;
            }
            bits.splice(bits.length - 1, 1, i);
            var r = bits.join('_');
            if (suffixFound) {
                r += suffix;
            }
            this.options.element = r;
            return r;
        },

        /**
         * @param    string    name to decrease
         * @param    int        delete index
         * @param    string    name suffix to keep (used for db join
autocomplete element)
         */

        _decreaseName: function (n, delIndex, suffix) {

            var suffixFound = false;
            suffix = suffix ? suffix : false;
            if (suffix !== false) {
                if (n.contains(suffix)) {
                    n = n.replace(suffix, '');
                    suffixFound = true;
                }
            }
            var namebits = n.split('[');
            var i = namebits[1].replace(']',
'').toInt();
            if (i >= 1 && i > delIndex) {
                i--;
            }
            i = i + ']';

            namebits[1] = i;
            var r = namebits.join('[');
            if (suffixFound) {
                r += suffix;
            }
            return r;
        },

        setContainerRepeatNum: function(oldRepeatCount, newRepeatCount)
        {
            var container = this.getContainer();
            jQuery(container).removeClass('fb_el_' + this.origId
+ '_' + oldRepeatCount);
            jQuery(container).addClass('fb_el_' + this.origId +
'_' + newRepeatCount);
        },

        setName: function (repeatCount) {
            var element = this.getElement();
            if (typeOf(element) === 'null') {
                return false;
            }
            if (this.hasSubElements()) {
                this._getSubElements().each(function (e) {
                    e.name = this._setName(e.name, repeatCount);
                    e.id = this._setId(e.id, repeatCount);
                }.bind(this));
            } else {
                if (typeOf(this.element.name) !== 'null') {
                    this.element.name = this._setName(this.element.name,
repeatCount);
                }
            }
            if (typeOf(this.element.id) !== 'null') {
                this.element.id = this._setId(this.element.id,
repeatCount);
            }
            this.setContainerRepeatNum(this.options.repeatCounter,
repeatCount);
            this.options.repeatCounter = repeatCount;
            return this.element.id;
        },

        /**
         * @param    string    name to decrease
         * @param    int        delete index
         * @param    string    name suffix to keep (used for db join
autocomplete element)
         */

        _setId: function (n, repeatCount, suffix) {
            var suffixFound = false;
            suffix = suffix ? suffix : false;
            var match = '';
            if (suffix !== false) {
                var re = new RegExp(suffix);
                if (n.test(re)) {
                    match = n.match(re)[0];
                    n = n.replace(re, '');
                    suffixFound = true;
                }
            }
            var bits = Array.mfrom(n.split('_'));
            var i = bits.getLast();
            if (typeOf(i.toInt()) === 'null') {
                return n + match;
            }
            if (i.toInt() === repeatCount) {
                return n + match;
            }
            i = repeatCount;
            bits.splice(bits.length - 1, 1, i);
            var r = bits.join('_');
            if (suffixFound) {
                r += match;
            }
            this.options.element = r;
            return r;
        },

        /**
         * @param    string    name to decrease
         * @param    int        delete index
         * @param    string    name suffix to keep (used for db join
autocomplete element)
         */

        _setName: function (n, repeatCount, suffix) {

            var suffixFound = false;
            suffix = suffix ? suffix : false;
            var match = '';
            if (suffix !== false) {
                var re = new RegExp(suffix);
                if (n.test(re)) {
                    match = n.match(re)[0];
                    n = n.replace(re, '');
                    suffixFound = true;
                }
            }
            var namebits = n.split('[');
            var i = namebits[1].replace(']',
'').toInt();

            if (i.toInt() === repeatCount) {
                return n + match;
            }

            i = repeatCount;
            i = i + ']';

            namebits[1] = i;
            var r = namebits.join('[');
            if (suffixFound) {
                r += match;
            }
            return r;
        },

        /**
         * determine which duplicated instance of the repeat group the
         * element belongs to, returns false if not in a repeat group
         * other wise an integer
         */
        getRepeatNum: function () {
            if (this.options.inRepeatGroup === false) {
                return false;
            }
            return this.element.id.split('_').getLast();
        },

        getBlurEvent: function () {
            return this.element.get('tag') === 'select'
? 'change' : 'blur';
        },

        /**
         * Get focus event
         * @returns {string}
         */
        getFocusEvent: function () {
            return this.element.get('tag') === 'select'
? 'click' : 'focus';
        },

	    getChangeEvent: function () {
		    return this.options.changeEvent;
	    },

        select: function () {
        },
        focus : function () {
            this.removeTipMsg();
        },

        hide: function () {
            var c = this.getContainer();
            if (c) {
                jQuery(c).hide();
                jQuery(c).addClass('fabrikHide');

            }
        },

        show: function () {
            var c = this.getContainer();
            if (c) {
                jQuery(c).show();
                jQuery(c).removeClass('fabrikHide');
            }
        },

        toggle: function () {
            var c = this.getContainer();
            if (c) {
                c.toggle();
            }
        },

        /**
         * Used to find element when form clones a group
         * WYSIWYG text editor needs to return something specific as
options.element has to use name
         * and not id.
         */
        getCloneName: function () {
            return this.options.element;
        },

        /**
         * Testing some stuff to try and get maps to display properly when
they are in the
         * tab template.  If a map is in a tab which isn't selected on
page load, the map
         * will not render properly, and needs to be refreshed when the tab
it is in is selected.
         * NOTE that this stuff is very specific to the Fabrik tabs
template, using J!'s tabs.
         */

        doTab: function (event) {
            (function () {
                this.redraw();
                if (!Fabrik.bootstrapped) {
                    this.options.tab_dt.removeEvent('click',
function (e) {
                        this.doTab(e);
                    }.bind(this));
                }
            }.bind(this)).delay(500);
        },

        getTab: function(tab_div) {
            var tab_dl;
	        if (Fabrik.bootstrapped) {
		        var a = jQuery("[data-bs-target='#" + tab_div.id +
"']");
		        tab_dl = a.closest('.nav-item');
	        } else {
		        tab_dl = tab_div.getPrevious('.tabs');
	        }
	        if (tab_dl) {
	            return tab_dl;
            }
            return false;
        },

        getTabDiv: function() {
	        var c = Fabrik.bootstrapped ? '.tab-pane' :
'.current';
	        var tab_div = this.element.getParent(c);
	        if (tab_div) {
	            return tab_div;
            }
            return false;
        },

        /**
         * Tabs mess with element positioning - some element (googlemaps,
file upload) need to redraw themselves
         * when the tab is clicked
         */
        watchTab      : function () {
            var c = Fabrik.bootstrapped ? '.tab-pane' :
'.current',
                a, tab_dl;
            var tab_div = this.element.getParent(c);
            if (tab_div) {
                if (Fabrik.bootstrapped) {
                    a =
document.getElement("[data-bs-target='#" + tab_div.id +
"']");
                    tab_dl = a.getParent('ul.nav');
                    tab_dl.addEvent('click:relay(a)', function
(event, target) {
                        this.doTab(event);
                    }.bind(this));
                } else {
                    tab_dl = tab_div.getPrevious('.tabs');
                    if (tab_dl) {
                        this.options.tab_dd =
this.element.getParent('.fabrikGroup');
                        if
(this.options.tab_dd.style.getPropertyValue('display') ===
'none') {
                            this.options.tab_dt =
tab_dl.getElementById('group' + this.groupid + '_tab');
                            if (this.options.tab_dt) {
                               
this.options.tab_dt.addEvent('click', function (e) {
                                    this.doTab(e);
                                }.bind(this));
                            }
                        }
                    }
                }
            }
        },
        /**
         * When a form/details view is updating its own data, then should
we use the raw data or the html?
         * Raw is used for cdd/db join elements
         *
         * @returns {boolean}
         */
        updateUsingRaw: function () {
            return false;
        }
    });

    return window.FbElement;
});