UNPKG

fuelux

Version:

Base Fuel UX styles and controls

358 lines (294 loc) 10 kB
/* global jQuery:true */ /* * Fuel UX Placard * https://github.com/ExactTarget/fuelux * * Copyright (c) 2014 ExactTarget * Licensed under the BSD New license. */ // -- BEGIN UMD WRAPPER PREFACE -- // For more information on UMD visit: // https://github.com/umdjs/umd/blob/master/jqueryPlugin.js (function umdFactory (factory) { if (typeof define === 'function' && define.amd) { // if AMD loader is available, register as an anonymous module. define(['jquery'], factory); } else if (typeof exports === 'object') { // Node/CommonJS module.exports = factory(require('jquery')); } else { // OR use browser globals if AMD is not present factory(jQuery); } }(function PlacardWrapper ($) { // -- END UMD WRAPPER PREFACE -- // -- BEGIN MODULE CODE HERE -- var old = $.fn.placard; var EVENT_CALLBACK_MAP = { 'accepted': 'onAccept', 'cancelled': 'onCancel' }; // PLACARD CONSTRUCTOR AND PROTOTYPE var Placard = function Placard(element, options) { var self = this; this.$element = $(element); this.options = $.extend({}, $.fn.placard.defaults, options); if(this.$element.attr('data-ellipsis') === 'true'){ this.options.applyEllipsis = true; } this.$accept = this.$element.find('.placard-accept'); this.$cancel = this.$element.find('.placard-cancel'); this.$field = this.$element.find('.placard-field'); this.$footer = this.$element.find('.placard-footer'); this.$header = this.$element.find('.placard-header'); this.$popup = this.$element.find('.placard-popup'); this.actualValue = null; this.clickStamp = '_'; this.previousValue = ''; if (this.options.revertOnCancel === -1) { this.options.revertOnCancel = (this.$accept.length > 0); } // Placard supports inputs, textareas, or contenteditable divs. These checks determine which is being used this.isContentEditableDiv = this.$field.is('div'); this.isInput = this.$field.is('input'); this.divInTextareaMode = (this.isContentEditableDiv && this.$field.attr('data-textarea') === 'true'); this.$field.on('focus.fu.placard', $.proxy(this.show, this)); this.$field.on('keydown.fu.placard', $.proxy(this.keyComplete, this)); this.$element.on('close.fu.placard', $.proxy(this.hide, this)); this.$accept.on('click.fu.placard', $.proxy(this.complete, this, 'accepted')); this.$cancel.on('click.fu.placard', function (e) { e.preventDefault(); self.complete('cancelled'); }); this.applyEllipsis(); }; var _isShown = function _isShown(placard) { return placard.$element.hasClass('showing'); }; var _closeOtherPlacards = function _closeOtherPlacards() { var otherPlacards; otherPlacards = $(document).find('.placard.showing'); if (otherPlacards.length > 0) { if (otherPlacards.data('fu.placard') && otherPlacards.data('fu.placard').options.explicit) { return false;//failed } otherPlacards.placard('externalClickListener', {}, true); } return true;//succeeded }; Placard.prototype = { constructor: Placard, complete: function complete(action) { var func = this.options[ EVENT_CALLBACK_MAP[action] ]; var obj = { previousValue: this.previousValue, value: this.getValue() }; if (func) { func(obj); this.$element.trigger(action + '.fu.placard', obj); } else { if (action === 'cancelled' && this.options.revertOnCancel) { this.setValue(this.previousValue, true); } this.$element.trigger(action + '.fu.placard', obj); this.hide(); } }, keyComplete: function keyComplete(e) { if (((this.isContentEditableDiv && !this.divInTextareaMode) || this.isInput) && e.keyCode === 13) { this.complete('accepted'); this.$field.blur(); } else if (e.keyCode === 27) { this.complete('cancelled'); this.$field.blur(); } }, destroy: function destroy() { this.$element.remove(); // remove any external bindings $(document).off('click.fu.placard.externalClick.' + this.clickStamp); // set input value attribute this.$element.find('input').each(function () { $(this).attr('value', $(this).val()); }); // empty elements to return to original markup // [none] // return string of markup return this.$element[0].outerHTML; }, disable: function disable() { this.$element.addClass('disabled'); this.$field.attr('disabled', 'disabled'); if (this.isContentEditableDiv) { this.$field.removeAttr('contenteditable'); } this.hide(); }, applyEllipsis: function applyEllipsis() { var field, i, str; if (this.options.applyEllipsis) { field = this.$field.get(0); if ((this.isContentEditableDiv && !this.divInTextareaMode) || this.isInput) { field.scrollLeft = 0; } else { field.scrollTop = 0; if (field.clientHeight < field.scrollHeight) { this.actualValue = this.getValue(); this.setValue('', true); str = ''; i = 0; while (field.clientHeight >= field.scrollHeight) { str += this.actualValue[i]; this.setValue(str + '...', true); i++; } str = (str.length > 0) ? str.substring(0, str.length - 1) : ''; this.setValue(str + '...', true); } } } }, enable: function enable() { this.$element.removeClass('disabled'); this.$field.removeAttr('disabled'); if (this.isContentEditableDiv) { this.$field.attr('contenteditable', 'true'); } }, externalClickListener: function externalClickListener(e, force) { if (force === true || this.isExternalClick(e)) { this.complete(this.options.externalClickAction); } }, getValue: function getValue() { if (this.actualValue !== null) { return this.actualValue; } else if (this.isContentEditableDiv) { return this.$field.html(); } else { return this.$field.val(); } }, hide: function hide() { if (!this.$element.hasClass('showing')) { return; } this.$element.removeClass('showing'); this.applyEllipsis(); $(document).off('click.fu.placard.externalClick.' + this.clickStamp); this.$element.trigger('hidden.fu.placard'); }, isExternalClick: function isExternalClick(e) { var el = this.$element.get(0); var exceptions = this.options.externalClickExceptions || []; var $originEl = $(e.target); var i, l; if (e.target === el || $originEl.parents('.placard:first').get(0) === el) { return false; } else { for (i = 0, l = exceptions.length; i < l; i++) { if ($originEl.is(exceptions[i]) || $originEl.parents(exceptions[i]).length > 0) { return false; } } } return true; }, /** * setValue() sets the Placard triggering DOM element's display value * * @param {String} the value to be displayed * @param {Boolean} If you want to explicitly suppress the application * of ellipsis, pass `true`. This would typically only be * done from internal functions (like `applyEllipsis`) * that want to avoid circular logic. Otherwise, the * value of the option applyEllipsis will be used. * @return {Object} jQuery object representing the DOM element whose * value was set */ setValue: function setValue(val, suppressEllipsis) { //if suppressEllipsis is undefined, check placards init settings if (typeof suppressEllipsis === 'undefined') { suppressEllipsis = !this.options.applyEllipsis; } if (this.isContentEditableDiv) { this.$field.empty().append(val); } else { this.$field.val(val); } if (!suppressEllipsis && !_isShown(this)) { this.applyEllipsis(); } return this.$field; }, show: function show() { if (_isShown(this)) { return; } if (!_closeOtherPlacards()) { return; } this.previousValue = (this.isContentEditableDiv) ? this.$field.html() : this.$field.val(); if (this.actualValue !== null) { this.setValue(this.actualValue, true); this.actualValue = null; } this.showPlacard(); }, showPlacard: function showPlacard() { this.$element.addClass('showing'); if (this.$header.length > 0) { this.$popup.css('top', '-' + this.$header.outerHeight(true) + 'px'); } if (this.$footer.length > 0) { this.$popup.css('bottom', '-' + this.$footer.outerHeight(true) + 'px'); } this.$element.trigger('shown.fu.placard'); this.clickStamp = new Date().getTime() + (Math.floor(Math.random() * 100) + 1); if (!this.options.explicit) { $(document).on('click.fu.placard.externalClick.' + this.clickStamp, $.proxy(this.externalClickListener, this)); } } }; // PLACARD PLUGIN DEFINITION $.fn.placard = function (option) { var args = Array.prototype.slice.call(arguments, 1); var methodReturn; var $set = this.each(function () { var $this = $(this); var data = $this.data('fu.placard'); var options = typeof option === 'object' && option; if (!data) { $this.data('fu.placard', (data = new Placard(this, options))); } if (typeof option === 'string') { methodReturn = data[option].apply(data, args); } }); return (methodReturn === undefined) ? $set : methodReturn; }; $.fn.placard.defaults = { onAccept: undefined, onCancel: undefined, externalClickAction: 'cancelled', externalClickExceptions: [], explicit: false, revertOnCancel: -1,//negative 1 will check for an '.placard-accept' button. Also can be set to true or false applyEllipsis: false }; $.fn.placard.Constructor = Placard; $.fn.placard.noConflict = function () { $.fn.placard = old; return this; }; // DATA-API $(document).on('focus.fu.placard.data-api', '[data-initialize=placard]', function (e) { var $control = $(e.target).closest('.placard'); if (!$control.data('fu.placard')) { $control.placard($control.data()); } }); // Must be domReady for AMD compatibility $(function () { $('[data-initialize=placard]').each(function () { var $this = $(this); if ($this.data('fu.placard')) return; $this.placard($this.data()); }); }); // -- BEGIN UMD WRAPPER AFTERWORD -- })); // -- END UMD WRAPPER AFTERWORD --