You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

418 lines
18 KiB

  1. /*global openerp, _, $ */
  2. openerp.web_m2x_options = function (instance) {
  3. "use strict";
  4. var QWeb = instance.web.qweb,
  5. _t = instance.web._t,
  6. _lt = instance.web._lt;
  7. var OPTIONS = ['web_m2x_options.create',
  8. 'web_m2x_options.create_edit',
  9. 'web_m2x_options.limit',
  10. 'web_m2x_options.search_more',
  11. 'web_m2x_options.m2o_dialog',];
  12. instance.web.form.FieldMany2One = instance.web.form.FieldMany2One.extend({
  13. start: function() {
  14. this._super.apply(this, arguments);
  15. return this.get_options();
  16. },
  17. get_options: function() {
  18. var self = this;
  19. if (!_.isUndefined(this.view) && _.isUndefined(this.view.ir_options_loaded)) {
  20. this.view.ir_options_loaded = $.Deferred();
  21. this.view.ir_options = {};
  22. (new instance.web.Model("ir.config_parameter"))
  23. .query(["key", "value"]).filter([['key', 'in', OPTIONS]])
  24. .all().then(function(records) {
  25. _(records).each(function(record) {
  26. self.view.ir_options[record.key] = record.value;
  27. });
  28. self.view.ir_options_loaded.resolve();
  29. });
  30. return this.view.ir_options_loaded;
  31. }
  32. return $.when();
  33. },
  34. is_option_set: function(option) {
  35. if (_.isUndefined(option)) {
  36. return false
  37. }
  38. var is_string = typeof option === 'string'
  39. var is_bool = typeof option === 'boolean'
  40. if (is_string) {
  41. return option === 'true' || option === 'True'
  42. } else if (is_bool) {
  43. return option
  44. }
  45. return false
  46. },
  47. show_error_displayer: function () {
  48. if(this.is_option_set(this.options.m2o_dialog) ||
  49. _.isUndefined(this.options.m2o_dialog) && this.is_option_set(this.view.ir_options['web_m2x_options.m2o_dialog']) ||
  50. this.can_create && _.isUndefined(this.options.m2o_dialog) && _.isUndefined(this.view.ir_options['web_m2x_options.m2o_dialog'])) {
  51. new instance.web.form.M2ODialog(this).open();
  52. }
  53. },
  54. get_search_result: function (search_val) {
  55. var Objects = new instance.web.Model(this.field.relation);
  56. var def = $.Deferred();
  57. var self = this;
  58. // add options limit used to change number of selections record
  59. // returned.
  60. if (_.isUndefined(this.view))
  61. return this._super.apply(this, arguments);
  62. if (!_.isUndefined(this.view.ir_options['web_m2x_options.limit'])) {
  63. this.limit = parseInt(this.view.ir_options['web_m2x_options.limit'],10);
  64. }
  65. if (typeof this.options.limit === 'number') {
  66. this.limit = this.options.limit;
  67. }
  68. // add options search_more to force enable or disable search_more button
  69. if (this.is_option_set(this.options.search_more) || _.isUndefined(this.options.search_more) && this.is_option_set(self.view.ir_options['web_m2x_options.search_more'])) {
  70. this.search_more = true
  71. }
  72. // add options field_color and colors to color item(s) depending on field_color value
  73. this.field_color = this.options.field_color
  74. this.colors = this.options.colors
  75. var dataset = new instance.web.DataSet(this, this.field.relation,
  76. self.build_context());
  77. var blacklist = this.get_search_blacklist();
  78. this.last_query = search_val;
  79. var search_result = this.orderer.add(dataset.name_search(
  80. search_val,
  81. new instance.web.CompoundDomain(
  82. self.build_domain(), [["id", "not in", blacklist]]),
  83. 'ilike', this.limit + 1,
  84. self.build_context()));
  85. this.create_rights = this.create_rights || (function () {
  86. //call check_access_rights once
  87. var target_model = self.field.relation
  88. if (self.options.no_create || self.options.no_create_edit)
  89. return $.when(false);
  90. return new instance.web.Model('ir.model').
  91. query(['disable_quick_create']).
  92. filter([['model', '=', target_model]]).
  93. first().
  94. then(function(result){
  95. if(result.disable_quick_create)
  96. return $.when(false);
  97. return new instance.web.Model(target_model).call(
  98. "check_access_rights", ["create", false]);
  99. });
  100. })();
  101. $.when(search_result, this.create_rights).then(function (data, can_create) {
  102. self.can_create = can_create; // for ``.show_error_displayer()``
  103. self.last_search = data;
  104. // possible selections for the m2o
  105. var values = _.map(data, function (x) {
  106. x[1] = x[1].split("\n")[0];
  107. return {
  108. label: _.str.escapeHTML(x[1]),
  109. value: x[1],
  110. name: x[1],
  111. id: x[0],
  112. };
  113. });
  114. // Search result value colors
  115. if (self.colors && self.field_color) {
  116. var value_ids = [];
  117. for (var index in values) {
  118. value_ids.push(values[index].id);
  119. }
  120. // RPC request to get field_color from Objects
  121. Objects.query([self.field_color])
  122. .filter([['id', 'in', value_ids]])
  123. .all().done(function (objects) {
  124. for (var index in objects) {
  125. for (var index_value in values) {
  126. if (values[index_value].id == objects[index].id) {
  127. // Find value in values by comparing ids
  128. var value = values[index_value];
  129. // Find color with field value as key
  130. var color = self.colors[objects[index][self.field_color]] || 'black';
  131. value.label = '<span style="color:'+color+'">'+value.label+'</span>';
  132. break;
  133. }
  134. }
  135. }
  136. def.resolve(values);
  137. });
  138. }
  139. // search more... if more results that max
  140. if (values.length > self.limit || self.search_more) {
  141. values = values.slice(0, self.limit);
  142. values.push({
  143. label: _t("Search More..."),
  144. action: function () {
  145. // limit = 80 for improving performance, similar
  146. // to Odoo implementation here:
  147. // https://github.com/odoo/odoo/commit/8c3cdce539d87775b59b3f2d5ceb433f995821bf
  148. dataset.name_search(
  149. search_val, self.build_domain(),
  150. 'ilike', 80).done(function (data) {
  151. self._search_create_popup("search", data);
  152. });
  153. },
  154. classname: 'oe_m2o_dropdown_option'
  155. });
  156. }
  157. // quick create
  158. var raw_result = _(data.result).map(function (x) {
  159. return x[1];
  160. });
  161. var can_quick_create = _.isUndefined(self.view.ir_options['web_m2x_options.create']) ||
  162. (self.view.ir_options['web_m2x_options.create'].toLowerCase() == "true");
  163. if (self.options) {
  164. if (typeof self.options.create === 'boolean') {
  165. // field value is stronger than global settings
  166. can_quick_create = self.options.create;
  167. } else if (self.options.no_create || self.options.no_quick_create) {
  168. // undocumented features, try to keep compatibility
  169. can_quick_create = false;
  170. }
  171. }
  172. if (can_create && can_quick_create) {
  173. if (search_val.length > 0 &&
  174. !_.include(raw_result, search_val)) {
  175. values.push({
  176. label: _.str.sprintf(
  177. _t('Create "<strong>%s</strong>"'),
  178. $('<span />').text(search_val).html()),
  179. action: function () {
  180. self._quick_create(search_val);
  181. },
  182. classname: 'oe_m2o_dropdown_option'
  183. });
  184. }
  185. }
  186. // create...
  187. var can_create_edit = _.isUndefined(self.view.ir_options['web_m2x_options.create_edit']) ||
  188. ( self.view.ir_options['web_m2x_options.create_edit'].toLowerCase() == "true");
  189. if (self.options) {
  190. if (typeof self.options.create_edit === 'boolean') {
  191. // field value is stronger than global settings
  192. can_create_edit = self.options.create_edit;
  193. } else if (self.options.no_create || self.options.no_create_edit) {
  194. // undocumented features, try to keep compatibility
  195. can_create_edit = false;
  196. }
  197. }
  198. if (can_create && can_create_edit) {
  199. values.push({
  200. label: _t("Create and Edit..."),
  201. action: function () {
  202. self._search_create_popup(
  203. "form", undefined,
  204. self._create_context(search_val));
  205. },
  206. classname: 'oe_m2o_dropdown_option'
  207. });
  208. }
  209. // Check if colors specified to wait for RPC
  210. if (!(self.field_color && self.colors)){
  211. def.resolve(values);
  212. }
  213. });
  214. return def;
  215. }
  216. });
  217. instance.web.form.FieldMany2ManyTags.include({
  218. show_error_displayer: function () {
  219. if ((typeof this.options.m2o_dialog === 'undefined' && this.can_create) ||
  220. this.options.m2o_dialog) {
  221. new instance.web.form.M2ODialog(this).open();
  222. }
  223. },
  224. start: function() {
  225. this._super.apply(this, arguments);
  226. return this.get_options();
  227. },
  228. get_options: function() {
  229. var self = this;
  230. if (_.isUndefined(this.view.ir_options_loaded)) {
  231. this.view.ir_options_loaded = $.Deferred();
  232. this.view.ir_options = {};
  233. (new instance.web.Model("ir.config_parameter"))
  234. .query(["key", "value"]).filter([['key', 'in', OPTIONS]])
  235. .all().then(function(records) {
  236. _(records).each(function(record) {
  237. self.view.ir_options[record.key] = record.value;
  238. });
  239. self.view.ir_options_loaded.resolve();
  240. });
  241. }
  242. return this.view.ir_options_loaded;
  243. },
  244. /**
  245. * Call this method to search using a string.
  246. */
  247. get_search_result: function(search_val) {
  248. var self = this;
  249. // add options limit used to change number of selections record
  250. // returned.
  251. if (!_.isUndefined(this.view.ir_options['web_m2x_options.limit'])) {
  252. this.limit = parseInt(this.view.ir_options['web_m2x_options.limit'], 10);
  253. }
  254. if (typeof this.options.limit === 'number') {
  255. this.limit = this.options.limit;
  256. }
  257. var dataset = new instance.web.DataSet(this, this.field.relation, self.build_context());
  258. var blacklist = this.get_search_blacklist();
  259. this.last_query = search_val;
  260. return this.orderer.add(dataset.name_search(
  261. search_val, new instance.web.CompoundDomain(self.build_domain(), [["id", "not in", blacklist]]),
  262. 'ilike', this.limit + 1, self.build_context())).then(function(data) {
  263. self.last_search = data;
  264. // possible selections for the m2o
  265. var values = _.map(data, function(x) {
  266. x[1] = x[1].split("\n")[0];
  267. return {
  268. label: _.str.escapeHTML(x[1]),
  269. value: x[1],
  270. name: x[1],
  271. id: x[0],
  272. };
  273. });
  274. // search more... if more results that max
  275. if (values.length > self.limit) {
  276. values = values.slice(0, self.limit);
  277. values.push({
  278. label: _t("Search More..."),
  279. action: function() {
  280. // limit = 80 for improving performance, similar
  281. // to Odoo implementation here:
  282. // https://github.com/odoo/odoo/commit/8c3cdce539d87775b59b3f2d5ceb433f995821bf
  283. dataset.name_search(search_val, self.build_domain(), 'ilike', 80).done(function(data) {
  284. self._search_create_popup("search", data);
  285. });
  286. },
  287. classname: 'oe_m2o_dropdown_option'
  288. });
  289. }
  290. // quick create
  291. var can_quick_create = _.isUndefined(self.view.ir_options['web_m2x_options.create']) ||
  292. (self.view.ir_options['web_m2x_options.create'].toLowerCase() == "true");
  293. if (self.options) {
  294. if (typeof self.options.create === 'boolean') {
  295. // field value is stronger than global settings
  296. can_quick_create = self.options.create;
  297. } else if (self.options.no_create || self.options.no_quick_create) {
  298. // undocumented features, try to keep compatibility
  299. can_quick_create = false;
  300. }
  301. }
  302. if (can_quick_create) {
  303. var raw_result = _(data.result).map(function(x) {return x[1];});
  304. if (search_val.length > 0 && !_.include(raw_result, search_val)) {
  305. values.push({
  306. label: _.str.sprintf(_t('Create "<strong>%s</strong>"'),
  307. $('<span />').text(search_val).html()),
  308. action: function() {
  309. self._quick_create(search_val);
  310. },
  311. classname: 'oe_m2o_dropdown_option'
  312. });
  313. }
  314. }
  315. // create...
  316. var can_create_edit = _.isUndefined(self.view.ir_options['web_m2x_options.create_edit']) ||
  317. ( self.view.ir_options['web_m2x_options.create_edit'].toLowerCase() == "true");
  318. if (self.options) {
  319. if (typeof self.options.create_edit === 'boolean') {
  320. // field value is stronger than global settings
  321. can_create_edit = self.options.create_edit;
  322. } else if (self.options.no_create || self.options.no_create_edit) {
  323. // undocumented features, try to keep compatibility
  324. can_create_edit = false;
  325. }
  326. }
  327. if (can_create_edit) {
  328. values.push({
  329. label: _t("Create and Edit..."),
  330. action: function() {
  331. self._search_create_popup("form", undefined, self._create_context(search_val));
  332. },
  333. classname: 'oe_m2o_dropdown_option'
  334. });
  335. }
  336. return values;
  337. })
  338. },
  339. render_value: function()
  340. {
  341. var self = this;
  342. return jQuery.when(this._super.apply(this, arguments))
  343. .then(function()
  344. {
  345. if(self.options.open)
  346. {
  347. self.$el.find('.oe_tag')
  348. .css('cursor', 'pointer')
  349. .click(function(e)
  350. {
  351. var id = parseInt(jQuery(this).attr('data-id'), 10);
  352. self.do_action({
  353. type: 'ir.actions.act_window',
  354. res_model: self.field.relation,
  355. views: [[false, 'form']],
  356. res_id: id,
  357. });
  358. });
  359. }
  360. });
  361. },
  362. });
  363. };