This will be used to render the add form in the modal tab
771021
public function modalTabToolTemplateAddAction()
    {
        // declare the Tool service that we will be using to completely create our tool.
        $melisTool = $this->getServiceLocator()->get('MelisCoreTool');

        // tell the Tool what configuration in the app.tool.php that will be used.
        $melisTool->setMelisToolKey('meliscms', 'meliscms_tool_templates');

        $view = new ViewModel();

        $view->setVariable('meliscms_tool_template_add', $melisTool->getForm('meliscms_tool_template_generic_form'));

        return $view;
    }
954664
function renderAttribute(attribute, mode) {

    var daList;
    var daItems;
    var formGroup;
    var label;
    var inputDiv;
    var input;
    var helpTextDiv;
    var sz;
    var button;
    var select;
    var textNode;
    var inputGroupDiv;
    var inputGroupSpan;
    var inputGroupButton;
    var inputGroupDropDownMenu;
    var initSwitchery;
    var items;
    var j;
    var validating;

    /**
     * Create formGroup container and label
     */

    formGroup = addEle(panel.panelForm, 'div', 'form-group');
    addEle(formGroup, 'label', 'col-sm-3 control-label').innerHTML = attribute.label;

    /**
     * Create inputDiv - set with of input based on size of field
     */
    sz = '1';
    if (attribute.size > 2) sz = '2';
    if (attribute.size > 5) sz = '3';
    if (attribute.size > 10) sz = '4';
    if (attribute.size > 20) sz = '5';
    if (attribute.size > 25) sz = '6';
    if (attribute.size > 30) sz = '7';
    if (attribute.size > 40) sz = '8';
    if (attribute.size > 50) sz = '9';
    if (attribute.type == 'Number') sz = '3';
    if (attribute.type == 'Date') sz = '3';
    if (attribute.type == 'Boolean') sz = '3';
    inputDiv = addEle(formGroup, 'div', 'col-sm-' + sz);

    /**
     * Render based on type
     */
    switch (mode + attribute.type) {

      case 'ViewBoolean':
        input = addEle(inputDiv, 'input', 'js-switch');
        input.setAttribute("type", "checkbox");
        if (attribute.value)
          input.setAttribute("checked", "true");

        initSwitchery = new Switchery(input, {
          //color: window.getComputedStyle(panel.panelTitle, null).getPropertyValue('color'),
          color: '#5bc0de', // todo based on panel theme
          secondaryColor: '#dfdfdf',
          className: 'switchery',
          disabled: true,
          disabledOpacity: 0.5,
          speed: '0.1s'
        });
        $(input).on('change', function () {
          attribute.value = input.checked;
        });
        break;

      case 'EditBoolean':
        input = addEle(inputDiv, 'input', 'js-switch');
        input.setAttribute("type", "checkbox");
        if (attribute.value)
          input.setAttribute("checked", "true");

        initSwitchery = new Switchery(input, {
          //color: window.getComputedStyle(panel.panelTitle, null).getPropertyValue('color'),
          color: '#5bc0de', // todo based on panel theme
          secondaryColor: '#dfdfdf',
          className: 'switchery',
          disabled: false,
          disabledOpacity: 0.5,
          speed: '0.1s'
        });
        $(input).on('change', function () {
          attribute.value = input.checked;
        });
        break;

      case 'EditDate':
        inputGroupDiv = addEle(inputDiv, 'div', 'input-group date');
        input = addEle(inputGroupDiv, 'input', 'form-control');
        if (attribute.placeHolder)
          input.setAttribute("placeHolder", attribute.placeHolder);
        if (attribute.value)
          input.value = (1 + attribute.value.getMonth()) + '/' + attribute.value.getDate() + '/' + attribute.value.getFullYear();
        inputGroupSpan = addEle(inputGroupDiv, 'span', 'input-group-addon');
        inputGroupSpan.innerHTML = '<i class="fa fa-calendar"></i>';
        $(inputGroupDiv).datepicker({
          autoclose: true,
          todayBtn: true,
          todayHighlight: true,
          showOnFocus: false
        }).on('hide', function (e) {
          validateInput();
          e.preventDefault();
        });
        panel.listeners.push(inputGroupDiv); // so we can avoid leakage on deleting panel
        break;

      case 'EditNumber':
        input = addEle(inputDiv, 'input', 'form-control');
        if (attribute.placeHolder)
          input.setAttribute("placeHolder", attribute.placeHolder);
        input.setAttribute("type", "number");
        input.setAttribute("maxlength", attribute.size);
        input.setAttribute("value", attribute.value ? attribute.value : 0);
        break;

      case 'EditString':
        if (attribute.quickPick) {
          inputGroupDiv = addEle(inputDiv, 'div', 'input-group');
          input = addEle(inputGroupDiv, 'input', 'form-control');
        } else {
          input = addEle(inputDiv, 'input', 'form-control');
        }
        if (attribute.placeHolder)
          input.setAttribute("placeHolder", attribute.placeHolder);
        input.setAttribute("type", attribute.hint.password ? "password" : "text");
        input.setAttribute("maxlength", attribute.size);
        if (attribute.value)
          input.setAttribute("value", attribute.value);
        if (attribute.quickPick) {
          inputGroupSpan = addEle(inputGroupDiv, 'span', 'input-group-btn');
          inputGroupButton = addEle(inputGroupSpan, 'button', 'btn btn-default dropdown-toggle');
          inputGroupButton.type = 'button';
          inputGroupButton.setAttribute('data-toggle', 'dropdown');
          inputGroupButton.innerHTML = '<span class="caret"></span>';
          daItems = attribute.quickPick;
          daList = '';
          for (j = 0; j < daItems.length; j++) {
            daList += '<li><a href="#">' + daItems[j] + '</a></li>';
          }
          inputGroupDropDownMenu = addEle(inputGroupSpan, 'ul', 'dropdown-menu pull-right');
          inputGroupDropDownMenu.innerHTML = daList;
          $(inputGroupDropDownMenu).click(function (e) {
            input.value = e.originalEvent.srcElement.innerText;
            validateInput();
            e.preventDefault();
          });
          panel.listeners.push(inputGroupDropDownMenu); // so we can avoid leakage on deleting panel
        }
        break;

      case 'ViewDate':
        input = addEle(inputDiv, 'p', 'form-control-static');
        if (attribute.value)
          input.innerHTML = (1 + attribute.value.getMonth()) + '/' + attribute.value.getDate() + '/' + attribute.value.getFullYear();

        break;

      default: // View
        input = addEle(inputDiv, 'p', 'form-control-static');
        input.innerHTML = attribute.value;

    }

    /**
     * When focus lost on attribute - validate it
     */
    var validateInput = function (event) {
      switch (attribute.type) {
        case 'Date':
          attribute.value = (input.value === '') ? null : attribute.coerce(input.value);
          if (attribute.value != null) {
            var mm = attribute.value.getMonth() + 1;
            var dd = attribute.value.getDate();
            var yyyy = attribute.value.getFullYear();
            if (mm < 10) mm = '0' + mm;
            if (dd < 10) dd = '0' + dd;
            input.value = mm + '/' + dd + '/' + yyyy;
          } else {
            input.value = '';
          }
          break;
        default:
          attribute.value = (input.value === '') ? null : attribute.coerce(input.value);
          if (attribute.value != null)
            input.value = attribute.value;
          break;
      }
      attribute.validate(function () {
      });
    };
    /**
     * Validate when focus lost
     */
    $(input).on('focusout', validateInput);
    panel.listeners.push(input); // so we can avoid leakage on deleting panel

    /**
     * Monitor state changes to attribute
     */
    attribute.onEvent('Validate', function () {
      attribute._validationDone = true;
    });
    attribute.onEvent('StateChange', function () {
      switch (mode + attribute.type) {
        case 'EditBoolean':
          if (( attribute.value ? true : false ) != input.checked)
            $(input).click();
          break;
        case 'EditDate':
          input.value = attribute.value ? '' + (1 + attribute.value.getMonth()) + '/' + attribute.value.getDate() + '/' + attribute.value.getFullYear() : '';
          break;
        case 'EditNumber':
          input.value = attribute.value ? attribute.value : 0;
          break;
        case 'EditString':
          input.value = attribute.value ? '' + attribute.value : '';
          break;
        case 'ViewDate':
          input.innerHTML = attribute.value ? '' + (1 + attribute.value.getMonth()) + '/' + attribute.value.getDate() + '/' + attribute.value.getFullYear() : '';
          break;
        default: // View String
          input.innerHTML = attribute.value;
          break;
      }
      renderHelpText(attribute._validationDone ? attribute.validationMessage : '');
      attribute._validationDone = false;
    });
    panel.attributeListeners.push(attribute); // so we can avoid leakage on deleting panel

    /**
     * For attribute error display
     */
    function renderHelpText(text) {
      if (text) {
        if (!helpTextDiv) {
          helpTextDiv = document.createElement("div");
          helpTextDiv.className = 'col-sm-9 col-sm-offset-3 has-error';
          formGroup.appendChild(helpTextDiv);
        }
        helpTextDiv.innerHTML = '<span style="display: block;" class="help-block">' + text + '</span>';
        $(formGroup).addClass('has-error');
        if (inputGroupButton)
          $(inputGroupButton).addClass('btn-danger');
      } else {
        setTimeout(function () {
          if (helpTextDiv) {
            $(helpTextDiv).remove();
            helpTextDiv = null;
          }
        }, 250);
        $(formGroup).removeClass('has-error');
        if (inputGroupButton)
          $(inputGroupButton).removeClass('btn-danger');
      }
    }
  }
411283
function () {

		// make sure the listener for checkpanels is set-up
		Dispatcher.addListener('insertPanels', modalViewer.insert);

		// add the info/code panel onclick handler
		$('.pl-js-pattern-info-toggle').click(function (e) {
			modalViewer.toggle();
		});

		// make sure the close button handles the click
		$('.pl-js-modal-close-btn').on('click', function (e) {

			// hide any open annotations
			obj = JSON.stringify({
				'event': 'patternLab.annotationsHighlightHide'
			});
			document.querySelector('.pl-js-iframe').contentWindow.postMessage(obj, modalViewer.targetOrigin);

			// hide the viewer
			modalViewer.close();

		});

		// see if the modal is already active, if so update attributes as appropriate
		if (DataSaver.findValue('modalActive') === 'true') {
			modalViewer.active = true;
			$('.pl-js-pattern-info-toggle').html("Hide Pattern Info");
		}

		// make sure the modal viewer is not viewable, it's always hidden by default. the pageLoad event determines when it actually opens
		modalViewer.hide();

		// review the query strings in case there is something the modal viewer is supposed to handle by default
		var queryStringVars = urlHandler.getRequestVars();

		// show the modal if code view is called via query string
		if ((queryStringVars.view !== undefined) && ((queryStringVars.view === 'code') || (queryStringVars.view === 'c'))) {
			modalViewer.queryPattern();
		}

		// show the modal if the old annotations view is called via query string
		if ((queryStringVars.view !== undefined) && ((queryStringVars.view === 'annotations') || (queryStringVars.view === 'a'))) {
			modalViewer.queryPattern();
		}

	}
628679
public function run()
    {
        $view = $this->getView();

        $jsOptions = Json::encode([
            'id' => $this->id
        ]);

        $view->registerJs(<<<JS
        (function(sx, $, _)
        {
            sx.classes.FormUseTabs = sx.classes.Component.extend({

                _init: function()
                {
                    this.activeTab = window.location.hash.replace("#","");
                },

                _onDomReady: function()
                {
                    var self = this;

                    var JForm = $("#" + this.get('id'));
                    
                    var counter = 0;
                    $('.sx-form-tab').each(function(i,s)
                    {
                        counter = counter + 1;

                        var Jcontroll = $("<a>", {
                            'href' : '#' + $(this).attr('id'),
                            'aria-controls' : $(this).attr('id'),
                            'role' : 'tab',
                            'data-toggle' : 'tab',
                            'class' : 'nav-link',
                        }).append($(this).data('name'));

                        Jcontroll.on('click', function()
                        {
                            location.href = $(this).attr("href");
                        });

                        var Jli = $("<li>", {
                            'role' : 'presentation',
                            'class' : 'presentation nav-item',
                        }).append(Jcontroll);


                        if (self.activeTab)
                        {
                             if (self.activeTab == $(this).attr('id'))
                            {
                                Jli.addClass("active");
                                Jcontroll.addClass("active");
                                $(this).addClass("active");
                            }
                        } else
                        {
                            if (counter == 1)
                            {
                                Jli.addClass("active");
                                Jcontroll.addClass("active");
                                $(this).addClass("active");
                            }
                        }

                        $('.sx-form-tab-panel .nav').append(Jli);
                    });
                    
                    _.defer(function()
                    {
                        $('.sx-pre-loader-form', JForm).hide();
                        $('.sx-form-tab-panel', JForm).fadeIn();
                    });
                },
            });

            new sx.classes.FormUseTabs({$jsOptions});

        })(sx, sx.$, sx._);
JS
);

        $html = <<<HTML
            </div>
        </div>
HTML;

        return $html . parent::run();
    }
158975
function() {
        var form = this.element.find('form:first');

        if (!form) {
            return;
        }

        this.fireEvent('submit', [form]);

        var options = {
            url: form.attr('action'),
            type: (form.attr('method') || 'post').toUpperCase()
        };

        if (window.FormData) {
            options.processData = false;
            options.contentType = false;
            options.data = new FormData(form[0]);
        } else {
            options.data = form.serialize();
        }

        this.requestData(options);
    }
151001
public function renderForm()
    {
        $html = $this->form_open();
        $html .= $this->renderSubForm();
        $html .= $this->form_close();

        return $html;
    }
881904
function() {
			var parent = document.body;
			this.$frameParent = parent;
			this.$$modalExclusions = this.$$modalExclusions || [];
			var range = document.createRange();
			range.selectNode(parent);
			var frameFragment = range.createContextualFragment(this.CONTAINERTEMPLATE);
			parent.appendChild(frameFragment);
			this.$frame = parent.lastChild;
			this.$frame.tabIndex = -1;
			this.$frame.style.outline = "none";
//			this.handle = lib.addAutoDismiss([this.$frame], this.hide.bind(this));
			if (this.title) {
				lib.$(".dialogTitleText", this.$frame).appendChild(document.createTextNode(this.title)); //$NON-NLS-0$
				this.$frame.setAttribute("aria-label", this.title); //$NON-NLS-0$
			}
			this.$close = lib.$(".closeDialog", this.$frame);//$NON-NLS-0$
			this.$close.setAttribute("aria-label", containerMessages["Close"]); //$NON-NLS-0$
			var self = this;
			this.$close.addEventListener("click", function(event) { //$NON-NLS-0$
				self.hide();
			}, false);
						
			this.$parent = lib.$(".dialogContent", this.$frame); //$NON-NLS-0$
			range = document.createRange();
			range.selectNode(this.$parent);
			var contentFragment = range.createContextualFragment(this.TEMPLATE);
			if (this.messages) {
				lib.processTextNodes(contentFragment, this.messages);
			}
			this.$parent.appendChild(contentFragment);
			this.$buttonContainer = lib.$(".dialogButtons", this.$frame); //$NON-NLS-0$
			this._makeButtons();
			
			// hook key handlers.  This must be done after _makeButtons so that the default callback (if any)
			// is established.
			this.$frame.addEventListener("keydown", function (e) { //$NON-NLS-0$
				if(e.keyCode === lib.KEY.ESCAPE) {
					self.hide();
				} else if (e.keyCode === lib.KEY.ENTER && (typeof self._defaultCallback) === "function") { //$NON-NLS-0$
					self._defaultCallback();
				}
			}, false);
			
			this._bindElements(this.$parent);
			if (typeof this._bindToDom === "function") { //$NON-NLS-0$
				this._bindToDom(this.$parent);
			}
		}
322612
function() {
		/**
	     * @property helpPanel
	     * @type {YAHOO.widget.Panel}
	     */
	    this.helpPanel = new widget.Panel('helpPanel', {
	        fixedcenter: true,
	        draggable: true,
	        visible: false,
	        modal: true
	     });
	     this.helpPanel.render();
	}
105351
function (form) {
        render(req, res, 'organization-select', {
          form: form,
          formActionUri: formActionUri,
          formModel: organizationSelectFormModel,
          formErrors: collectFormErrors(form)
        });
      }
699608
public function setup() {

		$this->struct['modal'] = $this->get_base();
		$this->config();
		$this->struct['modal']['config']['view'] = $this->struct['modal']['config']['template'];
		unset( $this->struct['modal']['config']['template'] );
		add_action( 'uix_control_item_submit_' . $this->slug, $this->struct['modal']['config']['callback'], 100 );
		parent::setup();
		$this->set_submit();
	}
1248607
function form(bind, el, param, value) {
  var node = element('input');

  for (var key in param) {
    if (key !== 'signal' && key !== 'element') {
      node.setAttribute(key === 'input' ? 'type' : key, param[key]);
    }
  }
  node.setAttribute('name', param.signal);
  node.value = value;

  el.appendChild(node);

  node.addEventListener('input', function() {
    bind.update(node.value);
  });

  bind.elements = [node];
  bind.set = function(value) { node.value = value; };
}
962957
function LinkForm() {
		Requirements::javascript(THIRDPARTY_DIR . "/behaviour.js");
		Requirements::javascript(ExternalContentAdmin::$directory . "/javascript/external_tiny_mce_improvements.js");

		$form = new Form(
			$this->controller,
			"{$this->name}/LinkForm",
			new FieldSet(
				new LiteralField('Heading', '<h2><img src="cms/images/closeicon.gif" alt="' . _t('HtmlEditorField.CLOSE', 'close').'" title="' . _t('HtmlEditorField.CLOSE', 'close') . '" />' . _t('HtmlEditorField.LINK', 'Link') . '</h2>'),
				new OptionsetField(
					'LinkType',
					_t('HtmlEditorField.LINKTO', 'Link to'),
					array(
						'internal' => _t('HtmlEditorField.LINKINTERNAL', 'Page on the site'),
						'external' => _t('HtmlEditorField.LINKEXTERNAL', 'Another website'),
						'anchor' => _t('HtmlEditorField.LINKANCHOR', 'Anchor on this page'),
						'email' => _t('HtmlEditorField.LINKEMAIL', 'Email address'),
						'file' => _t('HtmlEditorField.LINKFILE', 'Download a file'),
						'externalcontent' =>_t('HtmlEditorField.LINKEXTERNALCONTENT', 'External Content'),
					)
				),
				new TreeDropdownField('internal', _t('HtmlEditorField.PAGE', "Page"), 'SiteTree', 'ID', 'MenuTitle'),
				new TextField('external', _t('HtmlEditorField.URL', 'URL'), 'http://'),
				new EmailField('email', _t('HtmlEditorField.EMAIL', 'Email address')),
				new TreeDropdownField('file', _t('HtmlEditorField.FILE', 'File'), 'File', 'Filename'),
				new ExternalTreeDropdownField('externalcontent', _t('ExternalHtmlEditorField.EXTERNAL_CONTENT', 'External Content'), 'ExternalContentSource', 'Link()'),
				new TextField('Anchor', _t('HtmlEditorField.ANCHORVALUE', 'Anchor')),
				new TextField('LinkText', _t('HtmlEditorField.LINKTEXT', 'Link text')),
				new TextField('Description', _t('HtmlEditorField.LINKDESCR', 'Link description')),
				new CheckboxField('TargetBlank', _t('HtmlEditorField.LINKOPENNEWWIN', 'Open link in a new window?'))
			),
			new FieldSet(
				new FormAction('insert', _t('HtmlEditorField.BUTTONINSERTLINK', 'Insert link')),
				new FormAction('remove', _t('HtmlEditorField.BUTTONREMOVELINK', 'Remove link'))
			)
		);

		$form->loadDataFrom($this);

		return $form;
	}
884915
function() {
            var e = document.createElement("button");
            e.style.height = "1px";
            e.style.width = "1px";
            e.style.position = "absolute";
            e.style.left = "-10000em";
            e.style.opacity = 0;
            e.tabIndex = -1;
            this.innerElement.appendChild(e);
            this._modalFocus = e;
        }
317770
public function renderCalendarEditEventModalAction(){
        $melisKey = $this->params()->fromRoute('melisKey', '');
        // Get Element form for Calendar event
        $melisMelisCoreConfig = $this->serviceLocator->get('MelisCoreConfig');
        $appConfigForm = $melisMelisCoreConfig->getFormMergedAndOrdered('meliscalendar/forms/melicalendar_event_form','melicalendar_event_form');
        // Factoring Calendar event and pass to view
        $factory = new \Zend\Form\Factory();
        $formElements = $this->serviceLocator->get('FormElementManager');
        $factory->setFormElementManager($formElements);
        $propertyForm = $factory->createForm($appConfigForm);
        // Set Calendar Event Title input non-draggable input
        $propertyForm->get('cal_event_title')->setAttribute('data-draggable', false);
        
        
        $calId = $this->params()->fromQuery('cal_id');
        
        if($calId) {
            
            $calendarTable = $this->getServiceLocator()->get('MelisCalendarTable');
             
            $resultEvent = $calendarTable->getEntryById($calId);
             
            if (!empty($resultEvent)){
                $eventData = $resultEvent->current();
                 
                if (!empty($eventData)){
                    $propertyForm->bind($eventData);
                }
            }
        }
        
        $view = new ViewModel();
        $view->setVariable('meliscalendar_event_title', $propertyForm);
        $view->melisKey = $melisKey;
        $view->calId = $calId;
        return $view;
    }
1074094
private function renderForm()
    {
        /** @var ActiveRecord $model */
        $model = new $this->modelClass;
        $labelNewNode = Yii::t('vendor/voskobovich/yii2-tree-manager/widgets/nestable','New node');
        $labelCloseButton = Yii::t('vendor/voskobovich/yii2-tree-manager/widgets/nestable','Close');
        $labelCreateNode = Yii::t('vendor/voskobovich/yii2-tree-manager/widgets/nestable','Create node');

        echo <<<HTML
<div class="modal" id="{$this->id}-new-node-modal" tabindex="-1" role="dialog" aria-labelledby="newNodeModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
HTML;
        /** @var ActiveForm $form */
        $form = ActiveForm::begin([
            'id' => $this->id . '-new-node-form'
        ]);

        echo <<<HTML
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" id="newNodeModalLabel">$labelNewNode</h4>
      </div>
      <div class="modal-body">
HTML;

        echo call_user_func($this->formFieldsCallable, $form, $model);

        echo <<<HTML
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">$labelCloseButton</button>
        <button type="submit" class="btn btn-primary">$labelCreateNode</button>
      </div>
HTML;
        $form->end();
        echo <<<HTML
    </div>
  </div>
</div>
HTML;
    }
982962
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
        
        if self._has_translatable_model():
            lang_code = self.get_form_language(request, obj)
            lang = get_language_title(lang_code)

            available_languages = self.get_available_languages(obj)
            language_tabs = self.get_language_tabs(request, obj, available_languages)
            context['language_tabs'] = language_tabs
            if language_tabs:
                context['title'] = '%s (%s)' % (context['title'], lang)
            if not language_tabs.current_is_translated:
                add = True  # lets prepopulated_fields_js work.

            # Patch form_url to contain the "language" GET parameter.
            # Otherwise AdminModel.render_change_form will clean the URL
            # and remove the "language" when coming from a filtered object
            # list causing the wrong translation to be changed.

            params = request.GET.dict()
            params['language'] = lang_code
            form_url = add_preserved_filters({
                'preserved_filters': urlencode(params),
                'opts': self.model._meta
            }, form_url)

        # django-fluent-pages uses the same technique
        if 'default_change_form_template' not in context:
            context['default_change_form_template'] = self.default_change_form_template

        #context['base_template'] = self.get_change_form_base_template()
        return super(TranslatableAdmin, self).render_change_form(request, context, add, change, form_url, obj)
173476
function attach(node) {
    var addListeners = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];

    $listModals(node).forEach(function (modal_node) {

      var iLisible = Math.random().toString(32).slice(2, 12);
      var wrapperBody = findById(WRAPPER_PAGE_JS);
      var body = doc.querySelector('body');

      modal_node.setAttribute('id', MODAL_ID_PREFIX + iLisible);
      modal_node.setAttribute(ATTR_HASPOPUP, ATTR_HASPOPUP_VALUE);

      if (wrapperBody === null || wrapperBody.length === 0) {
        var wrapper = doc.createElement('DIV');
        wrapper.setAttribute('id', WRAPPER_PAGE_JS);
        wrapInner(body, wrapper);
      }
    });

    if (addListeners) {

      /* listeners */
      ['click', 'keydown'].forEach(function (eventName) {

        doc.body.addEventListener(eventName, function (e) {

          // click on link modal
          var parentModalLauncher = searchParent(e.target, MODAL_JS_CLASS);
          if ((hasClass(e.target, MODAL_JS_CLASS) === true || parentModalLauncher !== '') && eventName === 'click') {
            var body = doc.querySelector('body');
            var modalLauncher = parentModalLauncher !== '' ? findById(parentModalLauncher) : e.target;
            var modalPrefixClass = modalLauncher.hasAttribute(MODAL_PREFIX_CLASS_ATTR) === true ? modalLauncher.getAttribute(MODAL_PREFIX_CLASS_ATTR) + '-' : '';
            var modalText = modalLauncher.hasAttribute(MODAL_TEXT_ATTR) === true ? modalLauncher.getAttribute(MODAL_TEXT_ATTR) : '';
            var modalContentId = modalLauncher.hasAttribute(MODAL_CONTENT_ID_ATTR) === true ? modalLauncher.getAttribute(MODAL_CONTENT_ID_ATTR) : '';
            var modalDescribedById = modalLauncher.hasAttribute(MODAL_DESCRIBEDBY_ID_ATTR) === true ? modalLauncher.getAttribute(MODAL_DESCRIBEDBY_ID_ATTR) : '';
            var modalTitle = modalLauncher.hasAttribute(MODAL_TITLE_ATTR) === true ? modalLauncher.getAttribute(MODAL_TITLE_ATTR) : '';
            var modalCloseText = modalLauncher.hasAttribute(MODAL_CLOSE_TEXT_ATTR) === true ? modalLauncher.getAttribute(MODAL_CLOSE_TEXT_ATTR) : MODAL_OVERLAY_TXT;
            var modalCloseTitle = modalLauncher.hasAttribute(MODAL_CLOSE_TITLE_ATTR) === true ? modalLauncher.getAttribute(MODAL_CLOSE_TITLE_ATTR) : modalCloseText;
            var modalCloseImgPath = modalLauncher.hasAttribute(MODAL_CLOSE_IMG_ATTR) === true ? modalLauncher.getAttribute(MODAL_CLOSE_IMG_ATTR) : '';
            var backgroundEnabled = modalLauncher.hasAttribute(MODAL_DATA_BACKGROUND_ATTR) === true ? modalLauncher.getAttribute(MODAL_DATA_BACKGROUND_ATTR) : '';
            var modalGiveFocusToId = modalLauncher.hasAttribute(MODAL_FOCUS_TO_ATTR) === true ? modalLauncher.getAttribute(MODAL_FOCUS_TO_ATTR) : '';

            var wrapperBody = findById(WRAPPER_PAGE_JS);

            // insert overlay
            body.insertAdjacentHTML('beforeEnd', createOverlay({
              text: modalCloseTitle,
              backgroundEnabled: backgroundEnabled,
              prefixClass: modalPrefixClass
            }));

            // insert modal
            body.insertAdjacentHTML('beforeEnd', createModal({
              modalText: modalText,
              modalPrefixClass: modalPrefixClass,
              backgroundEnabled: modalContentId,
              modalTitle: modalTitle,
              modalCloseText: modalCloseText,
              modalCloseTitle: modalCloseTitle,
              modalCloseImgPath: modalCloseImgPath,
              modalContentId: modalContentId,
              modalDescribedById: modalDescribedById,
              modalFocusBackId: modalLauncher.getAttribute('id')
            }));

            // hide page
            wrapperBody.setAttribute(ATTR_HIDDEN, 'true');

            // add class noscroll to body
            addClass(body, NO_SCROLL_CLASS);

            // give focus to close button or specified element
            var closeButton = findById(MODAL_BUTTON_JS_ID);
            if (modalGiveFocusToId !== '') {
              var focusTo = findById(modalGiveFocusToId);
              if (focusTo) {
                focusTo.focus();
              } else {
                closeButton.focus();
              }
            } else {
              closeButton.focus();
            }

            e.preventDefault();
          }

          // click on close button or on overlay not blocked
          var parentButton = searchParent(e.target, MODAL_BUTTON_JS_CLASS);
          if ((e.target.getAttribute('id') === MODAL_BUTTON_JS_ID || parentButton !== '' || e.target.getAttribute('id') === MODAL_OVERLAY_ID || hasClass(e.target, MODAL_BUTTON_JS_CLASS) === true) && eventName === 'click') {
            var body = doc.querySelector('body');
            var wrapperBody = findById(WRAPPER_PAGE_JS);
            var modal = findById(MODAL_JS_ID);
            var modalContent = findById(MODAL_CONTENT_JS_ID) ? findById(MODAL_CONTENT_JS_ID).innerHTML : '';
            var overlay = findById(MODAL_OVERLAY_ID);
            var modalButtonClose = findById(MODAL_BUTTON_JS_ID);
            var modalFocusBackId = modalButtonClose.getAttribute(MODAL_BUTTON_FOCUS_BACK_ID);
            var contentBackId = modalButtonClose.getAttribute(MODAL_BUTTON_CONTENT_BACK_ID);
            var backgroundEnabled = overlay.getAttribute(MODAL_OVERLAY_BG_ENABLED_ATTR);

            if (!(e.target.getAttribute('id') === MODAL_OVERLAY_ID && backgroundEnabled === 'disabled')) {

              closeModal({
                modal: modal,
                modalContent: modalContent,
                overlay: overlay,
                modalFocusBackId: modalFocusBackId,
                contentBackId: contentBackId,
                backgroundEnabled: backgroundEnabled,
                fromId: e.target.getAttribute('id')
              });

              // show back page
              wrapperBody.removeAttribute(ATTR_HIDDEN);

              // remove class noscroll to body
              removeClass(body, NO_SCROLL_CLASS);
            }
          }

          // strike a key when modal opened
          if (findById(MODAL_JS_ID) && eventName === 'keydown') {
            var body = doc.querySelector('body');
            var wrapperBody = findById(WRAPPER_PAGE_JS);
            var modal = findById(MODAL_JS_ID);
            var modalContent = findById(MODAL_CONTENT_JS_ID) ? findById(MODAL_CONTENT_JS_ID).innerHTML : '';
            var overlay = findById(MODAL_OVERLAY_ID);
            var modalButtonClose = findById(MODAL_BUTTON_JS_ID);
            var modalFocusBackId = modalButtonClose.getAttribute(MODAL_BUTTON_FOCUS_BACK_ID);
            var contentBackId = modalButtonClose.getAttribute(MODAL_BUTTON_CONTENT_BACK_ID);
            var $listFocusables = [].slice.call(modal.querySelectorAll(FOCUSABLE_ELEMENTS_STRING));

            // esc
            if (e.keyCode === 27) {

              closeModal({
                modal: modal,
                modalContent: modalContent,
                overlay: overlay,
                modalFocusBackId: modalFocusBackId,
                contentBackId: contentBackId
              });

              // show back page
              wrapperBody.removeAttribute(ATTR_HIDDEN);

              // remove class noscroll to body
              removeClass(body, NO_SCROLL_CLASS);
            }

            // tab or Maj Tab in modal => capture focus
            if (e.keyCode === 9 && $listFocusables.indexOf(e.target) >= 0) {

              // maj-tab on first element focusable => focus on last
              if (e.shiftKey) {
                if (e.target === $listFocusables[0]) {
                  $listFocusables[$listFocusables.length - 1].focus();
                  e.preventDefault();
                }
              } else {
                // tab on last element focusable => focus on first
                if (e.target === $listFocusables[$listFocusables.length - 1]) {
                  $listFocusables[0].focus();
                  e.preventDefault();
                }
              }
            }

            // tab outside modal => put it in focus
            if (e.keyCode === 9 && $listFocusables.indexOf(e.target) === -1) {
              e.preventDefault();
              $listFocusables[0].focus();
            }
          }
        }, true);
      });
    }
  }