xmpp.chapril.org-conversejs/src/utils.js

293 lines
13 KiB
JavaScript
Executable File

/*global escape, locales, Jed */
(function (root, factory) {
define([
"jquery",
"jquery.browser",
"underscore",
"converse-templates"
], factory);
}(this, function ($, dummy, _, templates) {
"use strict";
var XFORM_TYPE_MAP = {
'text-private': 'password',
'text-single': 'text',
'fixed': 'label',
'boolean': 'checkbox',
'hidden': 'hidden',
'jid-multi': 'textarea',
'list-single': 'dropdown',
'list-multi': 'dropdown'
};
$.expr[':'].emptyVal = function(obj){
return obj.value === '';
};
$.fn.hasScrollBar = function() {
if (!$.contains(document, this.get(0))) {
return false;
}
if(this.parent().height() < this.get(0).scrollHeight) {
return true;
}
return false;
};
$.fn.addHyperlinks = function () {
if (this.length > 0) {
this.each(function (i, obj) {
var x = $(obj).html();
var list = x.match(/\b(https?:\/\/|www\.|https?:\/\/www\.)[^\s<]{2,200}\b/g );
if (list) {
for (i=0; i<list.length; i++) {
var prot = list[i].indexOf('http://') === 0 || list[i].indexOf('https://') === 0 ? '' : 'http://';
var escaped_url = encodeURI(decodeURI(list[i])).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
x = x.replace(list[i], '<a target="_blank" rel="noopener" href="' + prot + escaped_url + '">'+ list[i] + '</a>' );
}
}
$(obj).html(x);
});
}
return this;
};
$.fn.addEmoticons = function (allowed) {
if (allowed) {
if (this.length > 0) {
this.each(function (i, obj) {
var text = $(obj).html();
text = text.replace(/&gt;:\)/g, '<span class="emoticon icon-evil"></span>');
text = text.replace(/:\)/g, '<span class="emoticon icon-smiley"></span>');
text = text.replace(/:\-\)/g, '<span class="emoticon icon-smiley"></span>');
text = text.replace(/;\)/g, '<span class="emoticon icon-wink"></span>');
text = text.replace(/;\-\)/g, '<span class="emoticon icon-wink"></span>');
text = text.replace(/:D/g, '<span class="emoticon icon-grin"></span>');
text = text.replace(/:\-D/g, '<span class="emoticon icon-grin"></span>');
text = text.replace(/:P/g, '<span class="emoticon icon-tongue"></span>');
text = text.replace(/:\-P/g, '<span class="emoticon icon-tongue"></span>');
text = text.replace(/:p/g, '<span class="emoticon icon-tongue"></span>');
text = text.replace(/:\-p/g, '<span class="emoticon icon-tongue"></span>');
text = text.replace(/8\)/g, '<span class="emoticon icon-cool"></span>');
text = text.replace(/:S/g, '<span class="emoticon icon-confused"></span>');
text = text.replace(/:\\/g, '<span class="emoticon icon-wondering"></span>');
text = text.replace(/:\/ /g, '<span class="emoticon icon-wondering"></span>');
text = text.replace(/&gt;:\(/g, '<span class="emoticon icon-angry"></span>');
text = text.replace(/:\(/g, '<span class="emoticon icon-sad"></span>');
text = text.replace(/:\-\(/g, '<span class="emoticon icon-sad"></span>');
text = text.replace(/:O/g, '<span class="emoticon icon-shocked"></span>');
text = text.replace(/:\-O/g, '<span class="emoticon icon-shocked"></span>');
text = text.replace(/\=\-O/g, '<span class="emoticon icon-shocked"></span>');
text = text.replace(/\(\^.\^\)b/g, '<span class="emoticon icon-thumbs-up"></span>');
text = text.replace(/&lt;3/g, '<span class="emoticon icon-heart"></span>');
$(obj).html(text);
});
}
}
return this;
};
var utils = {
// Translation machinery
// ---------------------
__: function (str) {
if (typeof Jed === "undefined") {
return str;
}
// FIXME: this can be refactored to take the i18n obj as a
// parameter.
// Translation factory
if (typeof this.i18n === "undefined") {
this.i18n = locales.en;
}
if (typeof this.i18n === "string") {
this.i18n = $.parseJSON(this.i18n);
}
if (typeof this.jed === "undefined") {
this.jed = new Jed(this.i18n);
}
var t = this.jed.translate(str);
if (arguments.length>1) {
return t.fetch.apply(t, [].slice.call(arguments,1));
} else {
return t.fetch();
}
},
___: function (str) {
/* XXX: This is part of a hack to get gettext to scan strings to be
* translated. Strings we cannot send to the function above because
* they require variable interpolation and we don't yet have the
* variables at scan time.
*
* See actionInfoMessages in src/converse-muc.js
*/
return str;
},
isHeadlineMessage: function (message) {
var $message = $(message),
from_jid = $message.attr('from');
if ($message.attr('type') === 'headline' ||
// Some servers (I'm looking at you Prosody) don't set the message
// type to "headline" when sending server messages. For now we
// check if an @ signal is included, and if not, we assume it's
// a headline message.
(typeof from_jid !== 'undefined' && from_jid.indexOf('@') === -1)
) {
return true;
}
return false;
},
refreshWebkit: function () {
/* This works around a webkit bug. Refreshes the browser's viewport,
* otherwise chatboxes are not moved along when one is closed.
*/
if ($.browser.webkit) {
var conversejs = document.getElementById('conversejs');
conversejs.style.display = 'none';
var tmp = conversejs.offsetHeight; // jshint ignore:line
conversejs.style.display = 'block';
}
},
webForm2xForm: function (field) {
/* Takes an HTML DOM and turns it into an XForm field.
*
* Parameters:
* (DOMElement) field - the field to convert
*/
var $input = $(field), value;
if ($input.is('[type=checkbox]')) {
value = $input.is(':checked') && 1 || 0;
} else if ($input.is('textarea')) {
value = [];
var lines = $input.val().split('\n');
for( var vk=0; vk<lines.length; vk++) {
var val = $.trim(lines[vk]);
if (val === '')
continue;
value.push(val);
}
} else {
value = $input.val();
}
return $(templates.field({
name: $input.attr('name'),
value: value
}))[0];
},
contains: function (attr, query) {
return function (item) {
if (typeof attr === 'object') {
var value = false;
_.each(attr, function (a) {
value = value || item.get(a).toLowerCase().indexOf(query.toLowerCase()) !== -1;
});
return value;
} else if (typeof attr === 'string') {
return item.get(attr).toLowerCase().indexOf(query.toLowerCase()) !== -1;
} else {
throw new TypeError('contains: wrong attribute type. Must be string or array.');
}
};
},
xForm2webForm: function ($field, $stanza) {
/* Takes a field in XMPP XForm (XEP-004: Data Forms) format
* and turns it into a HTML DOM field.
*
* Parameters:
* (XMLElement) field - the field to convert
*/
// FIXME: take <required> into consideration
var options = [], j, $options, $values, value, values;
if ($field.attr('type') === 'list-single' || $field.attr('type') === 'list-multi') {
values = [];
$values = $field.children('value');
for (j=0; j<$values.length; j++) {
values.push($($values[j]).text());
}
$options = $field.children('option');
for (j=0; j<$options.length; j++) {
value = $($options[j]).find('value').text();
options.push(templates.select_option({
value: value,
label: $($options[j]).attr('label'),
selected: (values.indexOf(value) >= 0),
required: $field.find('required').length
}));
}
return templates.form_select({
name: $field.attr('var'),
label: $field.attr('label'),
options: options.join(''),
multiple: ($field.attr('type') === 'list-multi'),
required: $field.find('required').length
});
} else if ($field.attr('type') === 'fixed') {
return $('<p class="form-help">').text($field.find('value').text());
} else if ($field.attr('type') === 'jid-multi') {
return templates.form_textarea({
name: $field.attr('var'),
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else if ($field.attr('type') === 'boolean') {
return templates.form_checkbox({
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
checked: $field.find('value').text() === "1" && 'checked="1"' || '',
required: $field.find('required').length
});
} else if ($field.attr('type') && $field.attr('var') === 'username') {
return templates.form_username({
domain: ' @'+this.domain,
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else if ($field.attr('type')) {
return templates.form_input({
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else {
if ($field.attr('var') === 'ocr') { // Captcha
return _.reduce(_.map($field.find('uri'),
$.proxy(function (uri) {
return templates.form_captcha({
label: this.$field.attr('label'),
name: this.$field.attr('var'),
data: this.$stanza.find('data[cid="'+uri.textContent.replace(/^cid:/, '')+'"]').text(),
type: uri.getAttribute('type'),
required: this.$field.find('required').length
});
}, {'$stanza': $stanza, '$field': $field})
),
function (memo, num) { return memo + num; }, ''
);
}
}
}
};
utils.contains.not = function (attr, query) {
return function (item) {
return !(utils.contains(attr, query)(item));
};
};
return utils;
}));