utils.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*global jQuery, templates, escape, _, locales */
  2. (function (root, factory) {
  3. if (typeof define === 'function' && define.amd) {
  4. define(["jquery", "underscore", "jed", "converse-templates", "locales"], factory);
  5. } else {
  6. root.utils = factory(jQuery, _, templates, locales);
  7. }
  8. }(this, function ($, _, Jed, templates, locales) {
  9. "use strict";
  10. var XFORM_TYPE_MAP = {
  11. 'text-private': 'password',
  12. 'text-single': 'text',
  13. 'fixed': 'label',
  14. 'boolean': 'checkbox',
  15. 'hidden': 'hidden',
  16. 'jid-multi': 'textarea',
  17. 'list-single': 'dropdown',
  18. 'list-multi': 'dropdown'
  19. };
  20. $.expr[':'].emptyVal = function(obj){
  21. return obj.value === '';
  22. };
  23. $.fn.hasScrollBar = function() {
  24. if (!$.contains(document, this.get(0))) {
  25. return false;
  26. }
  27. if(this.parent().height() < this.get(0).scrollHeight) {
  28. return true;
  29. }
  30. return false;
  31. };
  32. $.fn.addHyperlinks = function () {
  33. if (this.length > 0) {
  34. this.each(function (i, obj) {
  35. var x = $(obj).html();
  36. var list = x.match(/\b(https?:\/\/|www\.|https?:\/\/www\.)[^\s<]{2,200}\b/g );
  37. if (list) {
  38. for (i=0; i<list.length; i++) {
  39. var prot = list[i].indexOf('http://') === 0 || list[i].indexOf('https://') === 0 ? '' : 'http://';
  40. var escaped_url = encodeURI(decodeURI(list[i])).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
  41. x = x.replace(list[i], "<a target='_blank' href='" + prot + escaped_url + "'>"+ list[i] + "</a>" );
  42. }
  43. }
  44. $(obj).html(x);
  45. });
  46. }
  47. return this;
  48. };
  49. $.fn.addEmoticons = function (allowed) {
  50. if (allowed) {
  51. if (this.length > 0) {
  52. this.each(function (i, obj) {
  53. var text = $(obj).html();
  54. text = text.replace(/&gt;:\)/g, '<span class="emoticon icon-evil"></span>');
  55. text = text.replace(/:\)/g, '<span class="emoticon icon-smiley"></span>');
  56. text = text.replace(/:\-\)/g, '<span class="emoticon icon-smiley"></span>');
  57. text = text.replace(/;\)/g, '<span class="emoticon icon-wink"></span>');
  58. text = text.replace(/;\-\)/g, '<span class="emoticon icon-wink"></span>');
  59. text = text.replace(/:D/g, '<span class="emoticon icon-grin"></span>');
  60. text = text.replace(/:\-D/g, '<span class="emoticon icon-grin"></span>');
  61. text = text.replace(/:P/g, '<span class="emoticon icon-tongue"></span>');
  62. text = text.replace(/:\-P/g, '<span class="emoticon icon-tongue"></span>');
  63. text = text.replace(/:p/g, '<span class="emoticon icon-tongue"></span>');
  64. text = text.replace(/:\-p/g, '<span class="emoticon icon-tongue"></span>');
  65. text = text.replace(/8\)/g, '<span class="emoticon icon-cool"></span>');
  66. text = text.replace(/:S/g, '<span class="emoticon icon-confused"></span>');
  67. text = text.replace(/:\\/g, '<span class="emoticon icon-wondering"></span>');
  68. text = text.replace(/:\/ /g, '<span class="emoticon icon-wondering"></span>');
  69. text = text.replace(/&gt;:\(/g, '<span class="emoticon icon-angry"></span>');
  70. text = text.replace(/:\(/g, '<span class="emoticon icon-sad"></span>');
  71. text = text.replace(/:\-\(/g, '<span class="emoticon icon-sad"></span>');
  72. text = text.replace(/:O/g, '<span class="emoticon icon-shocked"></span>');
  73. text = text.replace(/:\-O/g, '<span class="emoticon icon-shocked"></span>');
  74. text = text.replace(/\=\-O/g, '<span class="emoticon icon-shocked"></span>');
  75. text = text.replace(/\(\^.\^\)b/g, '<span class="emoticon icon-thumbs-up"></span>');
  76. text = text.replace(/&lt;3/g, '<span class="emoticon icon-heart"></span>');
  77. $(obj).html(text);
  78. });
  79. }
  80. }
  81. return this;
  82. };
  83. var utils = {
  84. // Translation machinery
  85. // ---------------------
  86. __: function (str) {
  87. // FIXME: this can be refactored to take the i18n obj as a
  88. // parameter.
  89. // Translation factory
  90. if (typeof this.i18n === "undefined") {
  91. this.i18n = locales.en;
  92. }
  93. if (typeof this.i18n === "string") {
  94. this.i18n = $.parseJSON(this.i18n);
  95. }
  96. if (typeof this.jed === "undefined") {
  97. this.jed = new Jed(this.i18n);
  98. }
  99. var t = this.jed.translate(str);
  100. if (arguments.length>1) {
  101. return t.fetch.apply(t, [].slice.call(arguments,1));
  102. } else {
  103. return t.fetch();
  104. }
  105. },
  106. ___: function (str) {
  107. /* XXX: This is part of a hack to get gettext to scan strings to be
  108. * translated. Strings we cannot send to the function above because
  109. * they require variable interpolation and we don't yet have the
  110. * variables at scan time.
  111. *
  112. * See actionInfoMessages in src/converse-muc.js
  113. */
  114. return str;
  115. },
  116. webForm2xForm: function (field) {
  117. /* Takes an HTML DOM and turns it into an XForm field.
  118. *
  119. * Parameters:
  120. * (DOMElement) field - the field to convert
  121. */
  122. var $input = $(field), value;
  123. if ($input.is('[type=checkbox]')) {
  124. value = $input.is(':checked') && 1 || 0;
  125. } else if ($input.is('textarea')) {
  126. value = [];
  127. var lines = $input.val().split('\n');
  128. for( var vk=0; vk<lines.length; vk++) {
  129. var val = $.trim(lines[vk]);
  130. if (val === '')
  131. continue;
  132. value.push(val);
  133. }
  134. } else {
  135. value = $input.val();
  136. }
  137. return $(templates.field({
  138. name: $input.attr('name'),
  139. value: value
  140. }))[0];
  141. },
  142. contains: function (attr, query) {
  143. return function (item) {
  144. if (typeof attr === 'object') {
  145. var value = false;
  146. _.each(attr, function (a) {
  147. value = value || item.get(a).toLowerCase().indexOf(query.toLowerCase()) !== -1;
  148. });
  149. return value;
  150. } else if (typeof attr === 'string') {
  151. return item.get(attr).toLowerCase().indexOf(query.toLowerCase()) !== -1;
  152. } else {
  153. throw new TypeError('contains: wrong attribute type. Must be string or array.');
  154. }
  155. };
  156. },
  157. xForm2webForm: function ($field, $stanza) {
  158. /* Takes a field in XMPP XForm (XEP-004: Data Forms) format
  159. * and turns it into a HTML DOM field.
  160. *
  161. * Parameters:
  162. * (XMLElement) field - the field to convert
  163. */
  164. // FIXME: take <required> into consideration
  165. var options = [], j, $options, $values, value, values;
  166. if ($field.attr('type') === 'list-single' || $field.attr('type') === 'list-multi') {
  167. values = [];
  168. $values = $field.children('value');
  169. for (j=0; j<$values.length; j++) {
  170. values.push($($values[j]).text());
  171. }
  172. $options = $field.children('option');
  173. for (j=0; j<$options.length; j++) {
  174. value = $($options[j]).find('value').text();
  175. options.push(templates.select_option({
  176. value: value,
  177. label: $($options[j]).attr('label'),
  178. selected: (values.indexOf(value) >= 0),
  179. required: $field.find('required').length
  180. }));
  181. }
  182. return templates.form_select({
  183. name: $field.attr('var'),
  184. label: $field.attr('label'),
  185. options: options.join(''),
  186. multiple: ($field.attr('type') === 'list-multi'),
  187. required: $field.find('required').length
  188. });
  189. } else if ($field.attr('type') === 'fixed') {
  190. return $('<p class="form-help">').text($field.find('value').text());
  191. } else if ($field.attr('type') === 'jid-multi') {
  192. return templates.form_textarea({
  193. name: $field.attr('var'),
  194. label: $field.attr('label') || '',
  195. value: $field.find('value').text(),
  196. required: $field.find('required').length
  197. });
  198. } else if ($field.attr('type') === 'boolean') {
  199. return templates.form_checkbox({
  200. name: $field.attr('var'),
  201. type: XFORM_TYPE_MAP[$field.attr('type')],
  202. label: $field.attr('label') || '',
  203. checked: $field.find('value').text() === "1" && 'checked="1"' || '',
  204. required: $field.find('required').length
  205. });
  206. } else if ($field.attr('type') && $field.attr('var') === 'username') {
  207. return templates.form_username({
  208. domain: ' @'+this.domain,
  209. name: $field.attr('var'),
  210. type: XFORM_TYPE_MAP[$field.attr('type')],
  211. label: $field.attr('label') || '',
  212. value: $field.find('value').text(),
  213. required: $field.find('required').length
  214. });
  215. } else if ($field.attr('type')) {
  216. return templates.form_input({
  217. name: $field.attr('var'),
  218. type: XFORM_TYPE_MAP[$field.attr('type')],
  219. label: $field.attr('label') || '',
  220. value: $field.find('value').text(),
  221. required: $field.find('required').length
  222. });
  223. } else {
  224. if ($field.attr('var') === 'ocr') { // Captcha
  225. return _.reduce(_.map($field.find('uri'),
  226. $.proxy(function (uri) {
  227. return templates.form_captcha({
  228. label: this.$field.attr('label'),
  229. name: this.$field.attr('var'),
  230. data: this.$stanza.find('data[cid="'+uri.textContent.replace(/^cid:/, '')+'"]').text(),
  231. type: uri.getAttribute('type'),
  232. required: this.$field.find('required').length
  233. });
  234. }, {'$stanza': $stanza, '$field': $field})
  235. ),
  236. function (memo, num) { return memo + num; }, ''
  237. );
  238. }
  239. }
  240. }
  241. };
  242. utils.contains.not = function (attr, query) {
  243. return function (item) {
  244. return !(utils.contains(attr, query)(item));
  245. };
  246. };
  247. return utils;
  248. }));