!function( $ ){ "use strict"; var Translatable = function( element, options ) { this.$element = $(element); this.options = $.extend({}, $.fn.translatable.defaults, options); if (!this.$element.data('translateTag')) return; var self = this; this.fetch('ajax.php/i18n/langs').then(function(json) { self.langs = json; if (Object.keys(self.langs).length) self.decorate(); }); }, // Class-static variables urlcache = {}; Translatable.prototype = { constructor: Translatable, fetch: function( url, data, callback ) { if ( !urlcache[ url ] ) { urlcache[ url ] = $.Deferred(function( defer ) { $.ajax( url, { data: data, dataType: 'json' } ) .then( defer.resolve, defer.reject ); }).promise(); } return urlcache[ url ].done( callback ); }, decorate: function() { this.$translations = $('<ul class="translations"></ul>'); this.$status = $('<li class="status"><i class="icon-spinner icon-spin"></i> Loading ...</li>') .appendTo(this.$translations); this.$footer = $('<div class="add-translation"></div>'); this.$select = $('<select name="locale"></select>'); this.$menu = $(this.options.menu).appendTo('body'); this.$container = $('<div class="translatable"></div>') .prependTo(this.$element.parent()) .append(this.$element); this.$button = $(this.options.button).insertAfter(this.$container); //this.$menu.append('<a class="close pull-right" href=""><i class="icon-remove-circle"></i></a>') // .on('click', $.proxy(this.hide, this)); this.$menu.append(this.$translations).append(this.$footer); this.shown = false; this.populated = false; this.$button.on('click', $.proxy(this.toggle, this)); this.$element .addClass('translatable') .focus($.proxy(function() { this.addClass('focus'); }, this.$container)) .blur($.proxy(function() { this.removeClass('focus'); }, this.$container)); getConfig().then($.proxy(function(c) { $('<span class="flag"></span>') .addClass('flag-' + c.primary_lang_flag) .insertAfter(this); }, this.$element)); }, buildAdd: function() { var self=this; this.$footer .append($('<form method="post"></form>') .append(this.$select) .append($('<button type="button"><i class="icon-plus-sign"></i> Add</button>') .on('click', $.proxy(this.define, this)) ) ); this.fetch('ajax.php/i18n/langs').then(function(langs) { $.each(langs, function(k, v) { self.$select.append($('<option>').val(k).text(v)); }); }); }, populate: function() { var self=this; if (this.populated) return; this.buildAdd(); this.fetch('ajax.php/i18n/translate/' + this.$element.data('translateTag')) .then(function(json) { $.each(json, function(k,v) { self.add(k, v); }); if (!Object.keys(json).length) { self.$status.text('Not currently translated'); } else self.$status.remove(); }); self.populated = true; }, define: function(e) { this.add($('option:selected', this.$select).val()); }, add: function(lang, text) { this.$translations.append( $('<li>') .append($('<label class="language">').text(this.langs[lang]) .append($('<input type="text" data-lang="'+lang+'">') .on('change', $.proxy(this.showCommit, this)) .val(text) ) ) ); $('option[value='+lang+']', this.$select).remove(); if (!$('option', this.$select).length) this.$footer.hide(); this.$status.remove(); }, showCommit: function(e) { if (this.$commit) return this.$commit.show(); return this.$commit = $('<div class="language-commit"></div>') .insertAfter(this.$translations) .append($('<button type="button" class="commit"><i class="fa fa-save icon-save"></i> Save</button>') .on('click', $.proxy(this.commit, this)) ); }, commit: function(e) { var changes = {}, self = this; $('input[type=text]', this.$translations).each(function() { changes[$(this).data('lang')] = $(this).val(); }); $.ajax('ajax.php/i18n/translate/' + this.$element.data('translateTag'), { type: 'post', data: changes, success: function() { self.$commit.hide(); } }); }, toggle: function(e) { e.stopPropagation(); e.preventDefault(); if (this.shown) this.hide(); else this.show(); }, show: function() { if (this.shown) return this; var pos = $.extend({}, this.$container.offset(), { height: this.$container[0].offsetHeight }) this.$menu.css({ top: pos.top + pos.height , left: pos.left }); this.populate(); this.$menu.show(); this.shown = true; return this; }, hide: function() { if (this.shown) { this.$menu.hide(); this.shown = false; } return this; } }; /* PLUGIN DEFINITION * =========================== */ $.fn.translatable = function ( option ) { return this.each(function () { var $this = $(this), data = $this.data('translatable'), options = typeof option == 'object' && option; if (!data) $this.data('translatable', (data = new Translatable(this, options))); if (typeof option == 'string') data[option](); }); }; $.fn.translatable.defaults = { menu: '<div class="translations dropdown-menu"></div>', button: '<button class="translatable"><i class="fa fa-globe icon-globe"></i></button>' }; $.fn.translatable.Constructor = Translatable; }( window.jQuery );