MediaWiki:Modal.js

/** * Name:       Modal * Version:    v0.1 * Author:     KockaAdmiralac * Description: Abstracts modal logic for native FANDOM modals */ /* eslint {"max-statements": "off"} */ require([   'wikia.window',    'mw',    'jquery',    'wikia.ui.factory' ], function(window, mw, $, uiFactory) {    'use strict';    window.dev = window.dev || {};    if (window.dev.modal) {        return;    }

var module = { modals: {} };

var MODAL_SIZES = [ 'small', 'medium', 'large', 'content-size' ];

var BUTTON_TYPES = [ 'link', 'input', 'button' ];

var config = mw.config.get([       'wgMessages'    ]);

function init(modal) { module._modal = modal; mw.hook('dev.modal').fire(module); }

function mapEvent(e) { return { key: 'event', value: e       }; }

/**    * TODO: UIFactory buttons support way more parameters * type: link buttons support: * - href (required) * - title (required) * - target * - imageClass * type: input buttons support: * - name (required) * type: button buttons support: * - imageClass */

function ModalButton(options) { this.primary = Boolean(options.primary); this.setText(options.text || options.value); this.setEvents(options.events || options.event); this.setClasses(options.classes); this.setType(options.type); this.setID(options.id); this.setDisabled(options.disabled); }

ModalButton.prototype.setClasses = function(classes) { this.classes = classes instanceof Array ? classes : []; // TODO: Make this configurable this.classes.push('normal'); if (!this.primary) { this.classes.push('secondary'); }   };

ModalButton.prototype.setDisabled = function(disabled) { this.disabled = Boolean(disabled); };

ModalButton.prototype.setEvents = function(events) { this.events = []; if (typeof events === 'string') { this.events.push(events); } else if (events instanceof Array) { this.events = events; }   };

ModalButton.prototype.setEvent = ModalButton.prototype.setEvents;

ModalButton.prototype.setID = function(id) { if (typeof id === 'string') { this.id = id; }   };

ModalButton.prototype.setText = function(text) { if (typeof text !== 'string') { throw new Error('No text specified!'); }       this.text = text; };

ModalButton.prototype.setType = function(type) { this.type = BUTTON_TYPES.indexOf(type) === -1 ? 'button' : type; };

ModalButton.prototype.create = function { return { type: this.type, vars: { classes: this.classes, disabled: this.disabled, data: this.events.map(mapEvent), id: this.id, value: this.text }       };    };

function createButton(options) { if (typeof options !== 'object') { return false; }       return new ModalButton(options); }

function buttonComponent(button) { return button.create; }

function AltLink(options) { if (typeof options.id === 'string') { this.id = options.id; }       if (typeof options.href === 'string') { this.href = options.href; }       if (typeof options.title === 'string') { this.title = options.title; }       if (typeof options.text === 'string') { this.text = options.text; }   }

AltLink.prototype.create = function { return { href: this.href, id: this.id, text: this.text, title: this.title };   };

function Modal(options) { this.context = options.context || this; if (typeof options.id !== 'string') { throw new Error('Modal ID must be specified!'); }       if (module.modals[options.id]) { throw new Error('Modal with same ID already registered!'); }       this.id = options.id; this.setSize(options.size); this.setContent(options.content); this.setTitle(options.title, options.isHTML); this.setButtons(options.buttons); this.setEvents(options.events); this.setClass(options.class || options.classes); this.setClose(options.close); this.setCloseEscape(options.closeEscape); this.setCloseTitle(options.closeTitle); }

Modal.prototype.setAltLink = function(options) { if (typeof options === 'object') { this.altLink = new AltLink(options); }   };

Modal.prototype.setButtons = function(buttons) { this.buttons = buttons instanceof Array ? buttons .map(createButton) .filter(Boolean) : [];   };

Modal.prototype.setClass = function(classes) { if (classes instanceof Array) { this.classes = classes; } else if (typeof classes === 'string') { this.classes = [classes]; }   };

Modal.prototype.setClasses = Modal.prototype.setClass;

Modal.prototype.setClose = function(close) { if (typeof close === 'function') { this.close = close; }   };

Modal.prototype.setCloseEscape = function(escape) { this.closeEscape = escape !== false; };

Modal.prototype.setCloseTitle = function(title) { this.closeTitle = typeof title === 'string' ? title : config.wgMessages.close || 'close'; };

Modal.prototype.setContent = function(content) { if (typeof content === 'string') { this.content = content; } else if (           typeof content === 'object' &&            typeof window.dev.ui === 'function'        ) { this.content = window.dev.ui(this.content); } else { throw new Error('Modal content not specified!'); }       // TODO: Refresh };

Modal.prototype.setEvent = function(name, listener) { this.events[name] = this.events[name] || []; if (typeof listener === 'function') { this.events[name].push($.proxy(listener, this.context)); } else if (           typeof listener === 'string' &&            this.context &&            typeof this.context[listener] === 'function'        ) { this.events[name].push(               $.proxy(this.context[listener], this.context)            ); }   };

Modal.prototype.setEvents = function(events) { this.events = {}; if (typeof events !== 'object') { return; }       for (var e in events) { if (events[e] instanceof Array) { for (var i = 0, l = e.length; i < l; ++i) { this.setEvent(e, events[e][i]); }           } else { this.setEvent(e, events[e]); }       }    };

Modal.prototype.setSize = function(size) { if (MODAL_SIZES.indexOf(size) === -1) { this.size = 'medium'; } else { this.size = size; }   };

Modal.prototype.setTitle = function(title, isHTML) { this.title = typeof title === 'string' ? this.title : 'Modal'; this.titleIsHTML = Boolean(isHTML); // TODO: Refresh };

Modal.prototype.create = function { this._loading = new $.Deferred; var component = { vars: { altLink: this.altLink, buttons: this.buttons.map(buttonComponent), classes: this.classes, closeText: this.closeTitle, content: this.content, escapeToClose: this.closeEscape, id: this.id, size: this.size, title: this.title },           confirmCloseModal: $.proxy(this._close, this) };       if (this.titleIsHTML) { component.vars.htmlTitle = this.title; }       module._modal.createComponent(component, $.proxy(this._created, this)); return this._loading; };

Modal.prototype._close = function { this._modal = null; this.create; if (this.close) { return this.close; }       return true; };

Modal.prototype._created = function(modal) { this._modal = modal; for (var e in this.events) { for (var i = 0, l = this.events[e].length; i < l; ++i) { modal.bind(e, this.events[e][i]); }       }        this._loading.resolve; };

['show', 'activate', 'deactivate'].forEach(function(method) {       Modal.prototype[method] = function {            if (this._modal) {                this._modal[method];            } else if (this._loading) {                this._loading.then($.proxy(function {                    this._modal[method];                }, this));            } else {                throw new Error('Modal not created!');            }        };    });

module.Modal = Modal; module.ModalButton = ModalButton; window.dev.modal = module; uiFactory.init(['modal']).then(init); });