main.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. (function() {
  2. 'use strict';
  3. var initialized = false;
  4. var i18n;
  5. // i18n key prefix for MUC ("muc.") or 1:1 chat ("chat.")
  6. var key_prefix;
  7. var display_data = null;
  8. function show_clients(client_array) {
  9. var list = document.getElementById('client_list');
  10. for (var id = 0; id < client_array.length; id++) {
  11. var item = document.createElement('div');
  12. /* innerHTML needed for client links */
  13. item.innerHTML = client_array[id];
  14. list.appendChild(item);
  15. }
  16. }
  17. function load_clients(url) {
  18. var request = new XMLHttpRequest();
  19. request.open('GET', url);
  20. request.onreadystatechange = function () {
  21. if (request.readyState === 4) {
  22. if (request.status === 200 || (isLocalFileRequest(url) && request.responseText.length > 0)) {
  23. show_clients(JSON.parse(request.responseText));
  24. }
  25. }
  26. };
  27. request.send(null);
  28. }
  29. function load_hash() {
  30. key_prefix = "chat";
  31. var xmpp_uri = window.location.search || window.location.hash;
  32. xmpp_uri = decodeURIComponent(xmpp_uri.substring(xmpp_uri.indexOf('#') + 1, xmpp_uri.length));
  33. if (xmpp_uri.indexOf("xmpp:") === 0) {
  34. xmpp_uri = xmpp_uri.slice(5);
  35. }
  36. try {
  37. base_decoded = window.atob(xmpp_uri);
  38. if (base_decoded.search('@') >= 0)
  39. xmpp_uri = base_decoded;
  40. } catch (err) {
  41. // ignore error, JID wasn't base64 encoded
  42. }
  43. if (xmpp_uri.search("\\?join") >= 0) {
  44. key_prefix = "muc";
  45. } else if(xmpp_uri.search("\\?register") >= 0) {
  46. key_prefix = "register";
  47. }
  48. // TODO: proper error checking / display / Creation of invitations
  49. if (xmpp_uri.search("@") <= 0) return {xmpp_uri:xmpp_uri, xmpp_uri_encoded:xmpp_uri, name: xmpp_uri.split("?")[0]};
  50. var xmpp_params = {};
  51. var xmpp_uri_parts = xmpp_uri.split("?");
  52. if (xmpp_uri_parts.length > 1) {
  53. let parameter, parameters = xmpp_uri_parts[1].split(";")
  54. for (parameter of parameters) {
  55. let key_value = parameter.split("=")
  56. xmpp_params[key_value[0]] = key_value.length > 1 ? key_value[1] : "";
  57. }
  58. }
  59. const jid_parts = xmpp_uri_parts[0].split("@");
  60. const local_part = jid_parts[0];
  61. xmpp_params["name"] = local_part.charAt(0).toUpperCase() + local_part.slice(1);
  62. const domain_part = jid_parts[1];
  63. const jid_encoded = encodeURIComponent(local_part) + "@" + encodeURIComponent(domain_part)
  64. xmpp_uri_parts[0] = jid_encoded
  65. const xmpp_uri_encoded = xmpp_uri_parts.join("?")
  66. return {xmpp_uri: xmpp_uri, xmpp_uri_encoded: xmpp_uri_encoded, name: xmpp_params["name"]};
  67. }
  68. let fallbackLocale = "en";
  69. let requested_fallback_locale = false;
  70. function get_translated_string(key, data) {
  71. return new Promise(function (resolve, reject) {
  72. try {
  73. return resolve(i18n.text(key, data));
  74. } catch {
  75. if(i18n.hasLocale(fallbackLocale)) {
  76. return resolve(i18n.text(key, data, fallbackLocale));
  77. }
  78. i18n.once(I18nText.event.LOCALE_LOAD, function () {
  79. try {
  80. return resolve(i18n.text(key, data, fallbackLocale));
  81. } catch {
  82. return resolve("UNTRANSLATED[" + key + "]");
  83. }
  84. });
  85. if(!requested_fallback_locale) {
  86. i18n.loadLocale(fallbackLocale);
  87. requested_fallback_locale = true;
  88. }
  89. }
  90. });
  91. }
  92. function translate_ui() {
  93. // translation
  94. get_translated_string(key_prefix + '.title', display_data).then(function (text) {
  95. document.title = text;
  96. });
  97. let translatable_els = document.querySelectorAll("[data-i18n]");
  98. translatable_els.forEach(function (el) {
  99. let key = el.dataset.i18n;
  100. if(key.startsWith(".")) {
  101. key = key_prefix + key;
  102. }
  103. get_translated_string(key, display_data).then(function (text) {
  104. let target = el.dataset.i18nTarget || "innerText";
  105. if(target.startsWith("@")) {
  106. el.setAttribute(target.substr(1), text);
  107. } else {
  108. el[target] = text;
  109. }
  110. });
  111. });
  112. }
  113. function rehash() {
  114. let hash = window.location.search || window.location.hash;
  115. if(!hash || hash == "#") {
  116. // Input mode
  117. document.getElementById("display-uri").style.display = "none";
  118. document.getElementById("enter-uri").style.display = "block";
  119. initialize_uri_input();
  120. key_prefix = "create";
  121. } else {
  122. document.getElementById("display-uri").style.display = "block";
  123. document.getElementById("enter-uri").style.display = "none";
  124. display_data = load_hash();
  125. document.getElementById('button').href = "xmpp:" + display_data.xmpp_uri_encoded;
  126. document.getElementById('url_in').value = "xmpp:" + display_data.xmpp_uri;
  127. }
  128. translate_ui();
  129. }
  130. function createQR() {
  131. display_data = load_hash();
  132. new QRCode(document.getElementById("qrcode"), "xmpp:" + display_data.xmpp_uri_encoded);
  133. }
  134. function generate_link() {
  135. let input_el = document.getElementById("uri_input");
  136. let output_el = document.getElementById("generated-link");
  137. let is_muc_el = document.getElementById("is_muc");
  138. let input = input_el.value;
  139. var uri;
  140. if(!(input.indexOf("xmpp:") == 0)) {
  141. uri = "xmpp:" + input;
  142. if(is_muc_el.checked) {
  143. uri += "?join";
  144. }
  145. is_muc_el.disabled = false;
  146. } else {
  147. uri = decodeURIComponent(input);
  148. is_muc_el.disabled = true;
  149. is_muc_el.checked = uri.endsWith("?join");
  150. }
  151. let encoded_uri = uri.substr(5).split("@").map(encodeURIComponent).join("@");
  152. let link = document.location.origin + document.location.pathname + "#" + encoded_uri;
  153. output_el.href = link;
  154. output_el.innerText = link;
  155. }
  156. function copy_to_clipboard() {
  157. let link = document.getElementById("generated-link");
  158. let copy_result_el = document.getElementById("copy-result");
  159. Promise.resolve().then(function () {
  160. return navigator.clipboard.writeText(link.href);
  161. }).then(function () {
  162. get_translated_string('copy-success', {}).then(function (text) {
  163. copy_result_el.innerText = text;
  164. });
  165. }, function () {
  166. get_translated_string('copy-failure', {}).then(function (text) {
  167. copy_result_el.innerText = text;
  168. });
  169. }).finally(function () {
  170. copy_result_el.style.visibility = "visible";
  171. });
  172. }
  173. function initialize_uri_input() {
  174. document.getElementById("generate-link-btn").addEventListener("click", function () {
  175. generate_link();
  176. document.getElementById("display-link").style.display = "block";
  177. });
  178. document.getElementById("uri_input").addEventListener("input", generate_link);
  179. document.getElementById("uri_input").addEventListener("keyup", function(event) {
  180. event.preventDefault();
  181. if (event.keyCode === 13) {
  182. document.getElementById("generate-link-btn").click();
  183. }
  184. });
  185. document.getElementById("is_muc").addEventListener("change", generate_link);
  186. document.getElementById("copy-link").addEventListener("click", copy_to_clipboard);
  187. }
  188. function load_done() {
  189. if (initialized) return;
  190. initialized = true;
  191. // load i18n and perform translation
  192. i18n = new I18nText({path: 'lang'});
  193. i18n.once(I18nText.event.LOCALE_CHANGE, function (data) {
  194. rehash();
  195. });
  196. var preferredLocale, setLocale = false;
  197. for (preferredLocale of navigator.languages) {
  198. if (supportedLocales.includes(preferredLocale)) {
  199. i18n.setLocale(preferredLocale);
  200. setLocale = true;
  201. break;
  202. }
  203. }
  204. if (!setLocale) {
  205. i18n.setLocale(defaultLocale);
  206. }
  207. var rtlLangs = "ar, fa, he, ur"
  208. if (rtlLangs.includes(navigator.language)) {
  209. document.querySelector("body").dir = "rtl";
  210. }
  211. // functionality
  212. var ua = navigator.userAgent;
  213. switch (true) {
  214. case (ua.indexOf("Windows") >= 0):
  215. load_clients("clients_Windows.json")
  216. break;
  217. case (ua.indexOf("Android") >= 0):
  218. case (ua.indexOf("CrOS") >= 0):
  219. load_clients("clients_Android.json")
  220. createQR();
  221. break;
  222. case (ua.indexOf("iPad") >= 0):
  223. case (ua.indexOf("iPhone") >= 0):
  224. load_clients("clients_iOS.json")
  225. createQR();
  226. break;
  227. case (ua.indexOf("Mac OS X") >= 0):
  228. case (ua.indexOf("Macintosh") >= 0):
  229. load_clients("clients_OSX.json")
  230. break;
  231. case (ua.indexOf("Tizen") >= 0):
  232. load_clients("clients_Tizen.json")
  233. createQR();
  234. break;
  235. // just default
  236. case (true):
  237. case (ua.indexOf("Linux") >= 0):
  238. load_clients("clients_Linux.json");
  239. createQR();
  240. break;
  241. }
  242. window.addEventListener("hashchange", rehash, false);
  243. document.getElementById("url_in").addEventListener("focus", function(event) {
  244. event.target.select();
  245. });
  246. }
  247. // Wait for the DOM to be ready
  248. document.addEventListener('DOMContentLoaded', load_done, false);
  249. document.onreadystatechange = function() {
  250. if (document.readyState === 'interactive') {
  251. load_done();
  252. }
  253. };
  254. var logo = document.createElement('img');
  255. logo.src = 'assets/xmpp.svg';
  256. logo.alt= 'XMPP logo';
  257. logo.width = 60;
  258. var link = document.createElement('a');
  259. link.href = 'https://xmpp.org/';
  260. link.append(logo)
  261. var brand = document.getElementById('xmpp');
  262. brand.append(link)
  263. })();