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.

functions.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // @flow
  2. import moment from 'moment';
  3. // MomentJS uses static language bundle loading, so in order to support dynamic
  4. // language selection in the app we need to load all bundles that we support in
  5. // the app.
  6. // FIXME: If we decide to support MomentJS in other features as well we may need
  7. // to move this import and the lenient matcher to the i18n feature.
  8. require('moment/locale/bg');
  9. require('moment/locale/de');
  10. require('moment/locale/eo');
  11. require('moment/locale/es');
  12. require('moment/locale/fr');
  13. require('moment/locale/hy-am');
  14. require('moment/locale/it');
  15. require('moment/locale/nb');
  16. // OC is not available. Please submit OC translation to the MomentJS project.
  17. require('moment/locale/pl');
  18. require('moment/locale/pt');
  19. require('moment/locale/pt-br');
  20. require('moment/locale/ru');
  21. require('moment/locale/sk');
  22. require('moment/locale/sl');
  23. require('moment/locale/sv');
  24. require('moment/locale/tr');
  25. require('moment/locale/zh-cn');
  26. import { i18next } from '../base/i18n';
  27. import { parseURIString } from '../base/util';
  28. const logger = require('jitsi-meet-logger').getLogger(__filename);
  29. /**
  30. * The name of the {@code window.localStorage} item where recent rooms are
  31. * stored.
  32. *
  33. * @type {string}
  34. */
  35. const RECENT_URL_STORAGE = 'recentURLs';
  36. /**
  37. * Retrieves the recent room list that was stored using the legacy way.
  38. *
  39. * @returns {Array<Object>}
  40. */
  41. export function getLegacyRecentRoomList(): Array<Object> {
  42. const legacyListString = window.localStorage.getItem(RECENT_URL_STORAGE);
  43. try {
  44. const legacyList = JSON.parse(legacyListString);
  45. if (legacyList && legacyList.length) {
  46. return legacyList;
  47. }
  48. } catch (error) {
  49. logger.warn('Unable to parse legacy recent list');
  50. }
  51. return [];
  52. }
  53. /**
  54. * Retrieves the recent room list and generates all the data needed to be
  55. * displayed.
  56. *
  57. * @param {Array<Object>} list - The stored recent list retrieved from Redux.
  58. * @returns {Array}
  59. */
  60. export function getRecentRooms(list: Array<Object>): Array<Object> {
  61. const recentRoomDS = [];
  62. if (list.length) {
  63. // We init the locale on every list render, so then it changes
  64. // immediately if a language change happens in the app.
  65. const locale = _getSupportedLocale();
  66. for (const e of list) {
  67. const location = parseURIString(e.conference);
  68. if (location && location.room && location.hostname) {
  69. recentRoomDS.push({
  70. baseURL: `${location.protocol}//${location.host}`,
  71. conference: e.conference,
  72. conferenceDuration: e.conferenceDuration,
  73. conferenceDurationString:
  74. _getDurationString(
  75. e.conferenceDuration,
  76. locale),
  77. dateString: _getDateString(e.date, locale),
  78. dateTimeStamp: e.date,
  79. initials: _getInitials(location.room),
  80. room: location.room,
  81. serverName: location.hostname
  82. });
  83. }
  84. }
  85. }
  86. return recentRoomDS.reverse();
  87. }
  88. /**
  89. * Returns a well formatted date string to be displayed in the list.
  90. *
  91. * @param {number} dateTimeStamp - The UTC timestamp to be converted to String.
  92. * @param {string} locale - The locale to init the formatter with. Note: This
  93. * locale must be supported by the formatter so ensure this prerequisite before
  94. * invoking the function.
  95. * @private
  96. * @returns {string}
  97. */
  98. function _getDateString(dateTimeStamp: number, locale: string) {
  99. const date = new Date(dateTimeStamp);
  100. const m = _getLocalizedFormatter(date, locale);
  101. if (date.toDateString() === new Date().toDateString()) {
  102. // The date is today, we use fromNow format.
  103. return m.fromNow();
  104. }
  105. return m.format('lll');
  106. }
  107. /**
  108. * Returns a well formatted duration string to be displayed as the conference
  109. * length.
  110. *
  111. * @param {number} duration - The duration in MS.
  112. * @param {string} locale - The locale to init the formatter with. Note: This
  113. * locale must be supported by the formatter so ensure this prerequisite before
  114. * invoking the function.
  115. * @private
  116. * @returns {string}
  117. */
  118. function _getDurationString(duration: number, locale: string) {
  119. return _getLocalizedFormatter(duration, locale).humanize();
  120. }
  121. /**
  122. * Returns the initials supposed to be used based on the room name.
  123. *
  124. * @param {string} room - The room name.
  125. * @private
  126. * @returns {string}
  127. */
  128. function _getInitials(room: string) {
  129. return room && room.charAt(0) ? room.charAt(0).toUpperCase() : '?';
  130. }
  131. /**
  132. * Returns a localized date formatter initialized with a specific {@code Date}
  133. * or duration ({@code number}).
  134. *
  135. * @private
  136. * @param {Date | number} dateOrDuration - The date or duration to format.
  137. * @param {string} locale - The locale to init the formatter with. Note: The
  138. * specified locale must be supported by the formatter so ensure the
  139. * prerequisite is met before invoking the function.
  140. * @returns {Object}
  141. */
  142. function _getLocalizedFormatter(dateOrDuration: Date | number, locale: string) {
  143. const m
  144. = typeof dateOrDuration === 'number'
  145. ? moment.duration(dateOrDuration)
  146. : moment(dateOrDuration);
  147. return m.locale(locale);
  148. }
  149. /**
  150. * A lenient locale matcher to match language and dialect if possible.
  151. *
  152. * @private
  153. * @returns {string}
  154. */
  155. function _getSupportedLocale() {
  156. const i18nLocale = i18next.language;
  157. let supportedLocale;
  158. if (i18nLocale) {
  159. const localeRegexp = new RegExp('^([a-z]{2,2})(-)*([a-z]{2,2})*$');
  160. const localeResult = localeRegexp.exec(i18nLocale.toLowerCase());
  161. if (localeResult) {
  162. const currentLocaleRegexp
  163. = new RegExp(
  164. `^${localeResult[1]}(-)*${`(${localeResult[3]})*` || ''}`);
  165. supportedLocale
  166. = moment.locales().find(lang => currentLocaleRegexp.exec(lang));
  167. }
  168. }
  169. return supportedLocale || 'en';
  170. }