");
66 | var option = options[i];
67 | $opt.attr("value", option.val).text(option.label);
68 | $input.append($opt);
69 | }
70 | break;
71 | default:
72 | $input = $("input");
73 | $input.attr("type", type);
74 | }
75 |
76 | $input.addClass("form-control").attr("name", id);
77 | $label.attr("for", id).text(title);
78 | var $div = $("");
79 | $div.addClass("form-group").addClass(id + "-group").addClass("custom");
80 | $div.append($label);
81 | $div.append($input);
82 |
83 | $(".search .customFilters").append($div);
84 | },
85 |
86 | /**
87 | * setSchemaExtension goes through provided schemaExtension and adds custom search
88 | * inputs for items that have "searchable" set to true.
89 | * @param schemaExtension
90 | */
91 | setCustomSearchInputs: function(context) {
92 | // clear custom filters
93 | var $form = $(".search form");
94 | $form.find(".customFilters").html('');
95 |
96 | if (!context) {
97 | return;
98 | }
99 | CollectionExtention.getModeExtention(context, _.bind(function(extData) {
100 | if (!extData) {
101 | return;
102 | }
103 |
104 | for (var i in extData) {
105 | var ext = extData[i];
106 | if (!ext["searchable"]) {
107 | continue;
108 | }
109 | this.addCustomSearchInput(ext.type.toLowerCase(), i, ext.title, ext.options);
110 | }
111 | }, this));
112 | },
113 |
114 | onRender : function(options) {
115 | this.$el.i18n(); // run i18nnext translation in the view context
116 | this.enableAutocomplete();
117 | },
118 |
119 | enableAutocomplete : function() {
120 | // todo auto-complete should take into consideration current context, which is not the case and is misleading
121 | // ideally it would use data already available in grid, instead of querying the back-end.
122 | // keywords auto-completion also needs proper implementation (right now it points to a static json) -
123 | // same idea it can use data available from unfiltered query.
124 |
125 | // disabled for now
126 | return;
127 |
128 | $.getJSON(this.URLOptions.formAutocomplete, _.bind(function(data) {
129 | this.$el.find('#search').autocomplete({
130 | minLength: 2,
131 | source : data.options,
132 | appendTo : '#leftPanel form #name-group',
133 | open : _.bind(function(event, ui) {
134 | var inputWidth = this.$el.find('#name-group input').css('width');
135 | $('.form-group ul, .form-group li').css('width', inputWidth);
136 | }, this)
137 | });
138 | }, this));
139 |
140 | $.getJSON(this.URLOptions.keywordAutocomplete, _.bind(function(data) {
141 | this.$el.find('#keywords').autocomplete({
142 | minLength: 2,
143 | source : data.options,
144 | appendTo : '#leftPanel form #keywords-group',
145 | open : _.bind(function(event, ui) {
146 | var inputWidth = this.$el.find('#name-group input').css('width');
147 | $('.form-group ul, .form-group li').css('width', inputWidth);
148 | }, this)
149 | });
150 | }, this));
151 | },
152 |
153 | clearForm : function() {
154 | this.$el.find('form').trigger("reset");
155 | this.gridChannel.trigger('resetCollection');
156 | }
157 | });
158 |
159 | return LeftPanelView;
160 | });
161 |
--------------------------------------------------------------------------------
/assets/js/editionPageModule/editor/LanguagesEditor.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'jquery', 'lodash', 'backbone', 'tools',
3 | 'text!./LanguagesEditor.html',
4 | 'backbone-forms'
5 | ], function($, _, Backbone, tools, AppearanceTemplate) {
6 | return Backbone.Form.editors.Base.extend({
7 | initialize: function(options) {
8 | // this option saves the day, it disallows parent form to break
9 | // our subforms validations. :+1:
10 | this.hasNestedForm = true;
11 |
12 | Backbone.Form.editors.Base.prototype.initialize.call(this, options);
13 |
14 | this.options = options;
15 | if (options.form && options.form.model) {
16 | this.data = options.form.model.get("translations");
17 | } else {
18 | this.data = options.form.data["translations"];
19 | }
20 |
21 | // avoid passing references around
22 | this.data = _.cloneDeep(this.data);
23 |
24 | _.each(this.schema.languages, _.bind(function(options, lang) {
25 | // init empty lang dictionaries
26 | if (!this.data[lang])
27 | this.data[lang] = {
28 | Language: lang
29 | };
30 | }, this));
31 | this.forms = {};
32 | },
33 |
34 | getValue: function() {
35 | return this.data;
36 | },
37 |
38 | validate: function() {
39 | Backbone.Form.editors.Base.prototype.validate.call(this);
40 | var errors = {};
41 | _.each(this.forms, _.bind(function(form, lang) {
42 | var subErrors = form.validate();
43 | if (subErrors) {
44 | errors[lang] = subErrors;
45 | form.$actionner.addClass("error");
46 | } else {
47 | form.$actionner.removeClass("error");
48 | }
49 | }, this));
50 |
51 | if (Object.keys(errors).length > 0) {
52 | return {
53 | type: "subform",
54 | el: "#" + this.options.id,
55 | errors : errors,
56 | message: null
57 | }
58 | }
59 |
60 | return null;
61 | },
62 |
63 | render: function() {
64 | Backbone.Form.editors.Base.prototype.render.call(this);
65 |
66 | this.$el = $(_.template(AppearanceTemplate)({
67 | id: this.options.id,
68 | languages: this.schema.languages
69 | }));
70 |
71 | // generate one subform per language
72 | _.each(this.schema.languages, _.bind(function(options, lang) {
73 | // clone schema, we're gonna update it
74 | var schema = _.cloneDeep(this.schema.schema);
75 |
76 | // append extra validators for each target
77 | for(var i in options.extraValidators) {
78 | var validator = options.extraValidators[i];
79 | for(var j in validator.targets) {
80 | var target = validator.targets[j];
81 | if (!schema[target]) continue;
82 |
83 | // init empty validators
84 | if (!schema[target].validators)
85 | schema[target].validators = [];
86 |
87 | // push at beginning of array
88 | schema[target].validators.unshift(validator);
89 | }
90 | }
91 |
92 | var form = new Backbone.Form({
93 | schema: schema,
94 | data: this.data[lang]
95 | }).render();
96 | form.parentForm = this;
97 | form.$el.attr("data-lang", lang);
98 | var hasRequiredFields = tools.appendRequired(form.$el, schema);
99 | this.forms[lang] = form;
100 | this.$el.append(form.$el);
101 |
102 | //
button for lang
103 | form.$actionner = this.$el.find("td.lang[data-lang='" + lang + "']");
104 | if (hasRequiredFields) {
105 | // also append required for tab header
106 | form.$actionner.find(".isRequired").empty().addClass("required");
107 | }
108 | // remove error class from actionner if no more error in form
109 | form.$el.find("input, select, textarea").on("change", _.bind(function(e) {
110 | var $el = $(e.delegateTarget);
111 | var $errField = $el.closest(".error");
112 | $errField.removeClass("error");
113 | $errField.find("[data-error]").empty();
114 |
115 | $el.removeClass("error");
116 | this.data[$el[0].name] = $el.val();
117 | if (this.$el.find(".error").length === 0) {
118 | this.$actionner.removeClass("error");
119 |
120 | // try & remove error from editor
121 | if (this.parentForm.$el.find(".error").length === 0) {
122 | this.parentForm.$el.removeClass("error");
123 | }
124 | }
125 | }, form));
126 | }, this));
127 |
128 | // add click handlers on language buttons to switch form display
129 | this.$el.find("td.lang").on("click", _.bind(function(e) {
130 | var $target = $(e.delegateTarget);
131 | if ($target.hasClass("active")) {
132 | return;
133 | }
134 |
135 | var lang = $target.attr("data-lang");
136 |
137 | // hide previously active
138 | this.$el.find("form.active").removeClass("active");
139 | this.$el.find("td.lang.active").removeClass("active");
140 |
141 | // display new active
142 | this.$el.find("form[data-lang='" + lang + "']")
143 | .addClass("active")
144 | // focus first input
145 | .find("input, textarea, select").first().focus();
146 |
147 | $target.addClass("active");
148 | }, this));
149 |
150 | // display first elem
151 | this.$el.find("td.lang").first().trigger("click");
152 |
153 | // bind this editor to $el
154 | this.$el.data("editor", this);
155 |
156 | // add field key & editor to inputs, for handling onchange validation
157 | this.$el.find("input, textarea, select")
158 | .data("field", {
159 | "key": this.options.key,
160 | "editor": this
161 | });
162 |
163 | this.$el.i18n();
164 | this.setElement(this.$el);
165 | return this;
166 | }
167 | });
168 | });
169 |
--------------------------------------------------------------------------------