diff --git a/modeltranslation/static/modeltranslation/js/tabbed_translation_fields.js b/modeltranslation/static/modeltranslation/js/tabbed_translation_fields.js index 202dd7e..ce3bf3a 100644 --- a/modeltranslation/static/modeltranslation/js/tabbed_translation_fields.js +++ b/modeltranslation/static/modeltranslation/js/tabbed_translation_fields.js @@ -4,159 +4,208 @@ var google, django, gettext; (function () { var jQuery = jQuery || $ || django.jQuery; - /* Add a new selector to jQuery that excludes parent items which match a - given selector */ + /* Add a new selector to jQuery that excludes parent items which match a given selector */ jQuery.expr[':'].parents = function(a, i, m) { return jQuery(a).parents(m[3]).length < 1; }; jQuery(function ($) { - function buildGroupId(id, orig_fieldname) { - /** - * Returns a unique group identifier with respect to Django's way - * of handling inline ids. Essentially that's the translation - * field id without the language prefix. - * - * Examples ('id parameter': 'return value'): - * - * 'id_name_de': 'id_name' - * 'id_name_zh_tw': 'id_name' - * 'id_name_set-2-name_de': 'id_name_set-2-name' - * 'id_name_set-2-name_zh_tw': 'id_name_set-2-name' - * 'id_news-data2-content_type-object_id-0-name_de': 'id_news-data2-content_type-object_id-0-name' - * 'id_news-data2-content_type-object_id-0-name_zh_cn': id_news-data2-content_type-object_id-0-name' - * - */ - var id_bits = id.split('-'), - id_prefix = 'id_' + orig_fieldname; - if (id_bits.length === 3) { // Standard inlines - id_prefix = id_bits[0] + '-' + id_bits[1] + '-' + id_prefix; - } else if (id_bits.length === 6) { // Generic inlines - id_prefix = id_bits[0] + '-' + id_bits[1] + '-' + id_bits[2] + '-' + - id_bits[3] + '-' + id_bits[4] + '-' + orig_fieldname; - } - return id_prefix; - } + var TranslationField = function (options) { + this.el = options.el; + this.cls = options.cls; + this.id = ''; + this.origFieldname = ''; + this.lang = ''; + this.groupId = ''; - function getGroupedTranslationFields() { - /** - * Returns a grouped set of all text based model translation fields. - * The returned datastructure will look something like this: - * - * { - * 'id_name_de': { - * 'en': HTMLInputElement, - * 'de': HTMLInputElement, - * 'zh_tw': HTMLInputElement - * }, - * 'id_name_set-2-name': { - * 'en': HTMLTextAreaElement, - * 'de': HTMLTextAreaElement, - * 'zh_tw': HTMLTextAreaElement - * }, - * 'id_news-data2-content_type-object_id-0-name': { - * 'en': HTMLTextAreaElement, - * 'de': HTMLTextAreaElement, - * 'zh_tw': HTMLTextAreaElement - * } - * } - * - * They key is a unique group identifier as returned by - * buildGroupId(id, orig_fieldname) to handle inlines properly. - * - */ - var translation_fields = $('.mt').filter( - 'input[type=text]:visible, textarea:visible').filter( - ':parents(.tabular)'), // exclude tabular inlines - grouped_translations = {}; + this.init = function () { + var clsBits = this.cls.substring(TranslationField.cssPrefix.length, this.cls.length).split('-'); + this.origFieldname = clsBits[0]; + this.lang = clsBits[1]; + this.id = $(this.el).attr('id'); + this.groupId = this.buildGroupId(); + }; - // Handle fields inside collapsed groups as added by zinnia - translation_fields = translation_fields.add('fieldset.collapse-closed .mt'); - - translation_fields.each(function (i, el) { - var field_prefix = 'mt-field-', - id = '', - orig_fieldname = '', - lang = ''; - $.each($(el).attr('class').split(' '), function(j, cls) { - if (cls.substring(0, field_prefix.length) === field_prefix) { - var v = cls.substring(field_prefix.length, cls.length).split('-'); - orig_fieldname = v[0]; - id = buildGroupId($(el).attr('id'), orig_fieldname); - lang = v[1]; - } - }); - if (!grouped_translations[id]) { - grouped_translations[id] = {}; + this.buildGroupId = function () { + /** + * Returns a unique group identifier with respect to Django's way + * of handling inline ids. Essentially that's the translation + * field id without the language prefix. + * + * Examples ('id parameter': 'return value'): + * + * 'id_name_de': 'id_name' + * 'id_name_zh_tw': 'id_name' + * 'id_name_set-2-name_de': 'id_name_set-2-name' + * 'id_name_set-2-name_zh_tw': 'id_name_set-2-name' + * 'id_news-data2-content_type-object_id-0-name_de': 'id_news-data2-content_type-object_id-0-name' + * 'id_news-data2-content_type-object_id-0-name_zh_cn': id_news-data2-content_type-object_id-0-name' + */ + var idBits = this.id.split('-'), + idPrefix = 'id_' + this.origFieldname; + if (idBits.length === 3) { + // Handle standard inlines + idPrefix = idBits[0] + '-' + idBits[1] + '-' + idPrefix; + } else if (idBits.length === 6) { + // Handle generic inlines + idPrefix = idBits[0] + '-' + idBits[1] + '-' + idBits[2] + '-' + + idBits[3] + '-' + idBits[4] + '-' + this.origFieldname; } - grouped_translations[id][lang] = el; + return idPrefix; + }; + + this.init(); + }; + TranslationField.cssPrefix = 'mt-field-'; + + var TranslationFieldGrouper = function (options) { + this.$fieldSelector = options.$fieldSelector; + this.groupedTranslations = {}; + + this.init = function () { + // Handle fields inside collapsed groups as added by zinnia + this.$fieldSelector = this.$fieldSelector.add('fieldset.collapse-closed .mt'); + + this.groupedTranslations = this.getGroupedTranslations(); + }; + + this.getGroupedTranslations = function () { + /** + * Returns a grouped set of all model translation fields. + * The returned datastructure will look something like this: + * + * { + * 'id_name_de': { + * 'en': HTMLInputElement, + * 'de': HTMLInputElement, + * 'zh_tw': HTMLInputElement + * }, + * 'id_name_set-2-name': { + * 'en': HTMLTextAreaElement, + * 'de': HTMLTextAreaElement, + * 'zh_tw': HTMLTextAreaElement + * }, + * 'id_news-data2-content_type-object_id-0-name': { + * 'en': HTMLTextAreaElement, + * 'de': HTMLTextAreaElement, + * 'zh_tw': HTMLTextAreaElement + * } + * } + * + * The keys are unique group identifiers as returned by + * TranslationField.buildGroupId() to handle inlines properly. + */ + var self = this; + this.$fieldSelector.each(function (idx, el) { + $.each($(el).attr('class').split(' '), function(idx, cls) { + if (cls.substring(0, TranslationField.cssPrefix.length) === TranslationField.cssPrefix) { + var tfield = new TranslationField({el: el, cls: cls}); + if (!self.groupedTranslations[tfield.groupId]) { + self.groupedTranslations[tfield.groupId] = {}; + } + self.groupedTranslations[tfield.groupId][tfield.lang] = el; + } + }); + }); + return this.groupedTranslations; + }; + + this.init(); + }; + + function handleAddAnotherInline() { + $('.mt').parents('.inline-group').not('.tabular').find('.add-row a').click(function () { + var grouper = new TranslationFieldGrouper({ + $fieldSelector: $(this).parent().prev().prev().find('.mt') + }); + var tabs = createTabs(grouper.groupedTranslations); + + // Update the main switch as it is not aware of the newly created tabs + var $select = $('#content').find('h1 select'); + $select.change(function () { + $.each(tabs, function (i, tab) { + tab.tabs('select', parseInt($select.val())); + }); + }); + // Activate the language tab selected in the main switch + $.each(tabs, function (i, tab) { + tab.tabs('select', parseInt($select.val())); + }); }); - return grouped_translations; } - function createTabs(grouped_translations) { + function createTabs(groupedTranslations) { var tabs = []; - $.each(grouped_translations, function (group_id, lang) { - var tabs_container = $('
'), - tabs_list = $(''), - insertion_point; - tabs_container.append(tabs_list); + $.each(groupedTranslations, function (groupId, lang) { + var tabsContainer = $('
'), + tabsList = $(''), + insertionPoint; + tabsContainer.append(tabsList); $.each(lang, function (lang, el) { var container = $(el).closest('.form-row'), label = $('label', container), - field_label = container.find('label'), - id = $(el).attr('id'), - tab_id = 'tab_' + id, + fieldLabel = container.find('label'), + tabId = 'tab_' + $(el).attr('id'), panel, tab; // Remove language and brackets from field label, they are // displayed in the tab already. - if (field_label.html()) { - field_label.html(field_label.html().replace(/\ \[.+\]/, '')); + if (fieldLabel.html()) { + fieldLabel.html(fieldLabel.html().replace(/ \[.+\]/, '')); } - if (!insertion_point) { - insertion_point = { + if (!insertionPoint) { + insertionPoint = { 'insert': container.prev().length ? 'after' : container.next().length ? 'prepend' : 'append', 'el': container.prev().length ? container.prev() : container.parent() }; } container.find('script').remove(); - panel = $('
').append(container); - tab = $('' + lang.replace('_', '-') + ''); - tabs_list.append(tab); - tabs_container.append(panel); + panel = $('
').append(container); + tab = $('' + lang.replace('_', '-') + ''); + tabsList.append(tab); + tabsContainer.append(panel); }); - insertion_point.el[insertion_point.insert](tabs_container); - tabs_container.tabs(); - tabs.push(tabs_container); + insertionPoint.el[insertionPoint.insert](tabsContainer); + tabsContainer.tabs(); + tabs.push(tabsContainer); }); return tabs; } - function createMainSwitch(grouped_translations, tabs) { - var unique_languages = [], + function createMainSwitch(groupedTranslations, tabs) { + var uniqueLanguages = [], select = $('