Source: js/ime_menu.js

  1. 'use strict';
  2. /* global MozActivity, Tagged */
  3. (function(exports) {
  4. /**
  5. * ImeMenu displays a list of currently enabled IMEs in an overlay.
  6. * @class ImeMenu
  7. * @param {Array} listItems An array of objects to display.
  8. * @param {String} title L10n ID of the the content of the header.
  9. * @param {Function} successCb Called when the user selects an option.
  10. * @param {Function} cancelCb Called when the menu is cancelled.
  11. */
  12. function ImeMenu(listItems, title, successCb, cancelCb) {
  13. this.onselected = successCb || function() {};
  14. this.oncancel = cancelCb || function() {};
  15. this.listItems = listItems;
  16. this.title = title;
  17. }
  18. ImeMenu.prototype = {
  19. /**
  20. * Start the ImeMenu instance
  21. * @memberof ImeMenu.prototype
  22. */
  23. start: function() {
  24. this.initUI();
  25. },
  26. /**
  27. * Builds dom and adds event listeners
  28. * @memberof ImeMenu.prototype
  29. */
  30. initUI: function() {
  31. var dummy = document.createElement('div');
  32. dummy.innerHTML = this.imeMenuView({
  33. title: this.title
  34. });
  35. this.container = dummy.firstElementChild;
  36. // We have a menu with all the options
  37. this.menu = this.container.querySelector('.ime-menu-list');
  38. this.buildMenu(this.listItems);
  39. // We append to System app (actually to '#screen')
  40. document.getElementById('screen').appendChild(this.container);
  41. this.container.addEventListener('submit', this);
  42. this.container.addEventListener('click', this);
  43. window.addEventListener('attentionopened', this, true);
  44. window.addEventListener('screenchange', this, true);
  45. window.addEventListener('home', this);
  46. window.addEventListener('holdhome', this);
  47. this.container.addEventListener('mousedown', this.preventFocusChange);
  48. window.dispatchEvent(new CustomEvent('imemenushow'));
  49. },
  50. /**
  51. * Removes the dom and stops event listeners
  52. * @memberof ImeMenu.prototype
  53. */
  54. stop: function() {
  55. document.getElementById('screen').removeChild(this.container);
  56. window.removeEventListener('attentionopened', this, true);
  57. window.removeEventListener('screenchange', this, true);
  58. window.removeEventListener('home', this);
  59. window.removeEventListener('holdhome', this);
  60. this.container.removeEventListener('mousedown', this.preventFocusChange);
  61. },
  62. /**
  63. * Returns the view for the ime menu.
  64. * @memberof ImeMenu.prototype
  65. */
  66. imeMenuView: function({title, cancelLabel}) {
  67. return Tagged.escapeHTML `<form role="dialog" data-type="value-selector"
  68. class="ime-menu value-selector-container"
  69. data-z-index-level="action-menu">
  70. <section>
  71. <h1 data-l10n-id="${title}"></h1>
  72. <ol class="value-selector-options-container ime-menu-list"
  73. aria-multiselectable="false" role="listbox">
  74. </ol>
  75. </section>
  76. <menu class="ime-menu-button-container">
  77. <button class="ime-menu-button" data-type="cancel"
  78. data-action="cancel" data-l10n-id="cancel"></button>
  79. </menu>
  80. </div>`;
  81. },
  82. /**
  83. * Returns the view for a menu item.
  84. * @memberof ImeMenu.prototype
  85. */
  86. menuItemView: function({layoutName, appName, layoutId, selected}) {
  87. return Tagged.escapeHTML `<li role="option" aria-selected="${selected}"
  88. data-id="${layoutId}">
  89. <label role="presentation">
  90. <span class="item-label">${layoutName}</span>
  91. <span class="item-note">${appName}</span>
  92. </label>
  93. </li>`;
  94. },
  95. /**
  96. * Builds the dom for the menu.
  97. * @memberof ImeMenu.prototype
  98. */
  99. buildMenu: function(items) {
  100. this.menu.innerHTML = '';
  101. items.forEach(function traveseItems(item) {
  102. this.menu.innerHTML += this.menuItemView({
  103. layoutName: item.layoutName,
  104. appName: item.appName,
  105. layoutId: item.value.toString(),
  106. selected: item.selected ? 'true' : 'false'
  107. });
  108. }, this);
  109. },
  110. /**
  111. * Hides the ImeMenu.
  112. * @memberof ImeMenu.prototype
  113. * @param {Function} callback The callback to call after hiding.
  114. */
  115. hide: function(callback) {
  116. this.stop();
  117. if (callback && typeof callback === 'function') {
  118. setTimeout(callback);
  119. }
  120. },
  121. /**
  122. * When IME switcher shows, prevent the keyboard focus getting changed.
  123. * @memberof ImeMenu.prototype
  124. * @param {DOMEvent} evt The event.
  125. */
  126. preventFocusChange: function(evt) {
  127. evt.preventDefault();
  128. },
  129. /**
  130. * General event handler interface.
  131. * Handles submission and cancellation events.
  132. * @memberof ImeMenu.prototype
  133. * @param {DOMEvent} evt The event.
  134. */
  135. handleEvent: function(evt) {
  136. var target = evt.target;
  137. var type = evt.type;
  138. switch (type) {
  139. case 'submit':
  140. evt.preventDefault();
  141. break;
  142. case 'screenchange':
  143. if (!evt.detail.screenEnabled) {
  144. this.hide();
  145. this.oncancel();
  146. }
  147. break;
  148. case 'click':
  149. evt.preventDefault();
  150. var action = target.dataset.action;
  151. if (action) {
  152. if (action === 'cancel') {
  153. this.hide();
  154. this.oncancel();
  155. return;
  156. }
  157. if (action === 'settings') {
  158. this.hide();
  159. this.launchSettings();
  160. return;
  161. }
  162. }
  163. var id = target.dataset.id;
  164. if (!id) {
  165. return;
  166. }
  167. id = parseInt(id);
  168. this.hide(this.onselected.bind(this, id));
  169. break;
  170. case 'home':
  171. case 'holdhome':
  172. this.hide();
  173. this.oncancel();
  174. break;
  175. case 'attentionopened':
  176. this.hide();
  177. break;
  178. }
  179. },
  180. /**
  181. * To lauch the settings via web activity.
  182. * @memberof ImeMenu.prototype
  183. */
  184. launchSettings: function() {
  185. var activity = new MozActivity({
  186. name: 'configure',
  187. data: {
  188. target: 'device',
  189. section: 'keyboard'
  190. }
  191. });
  192. activity.onerror = function() {
  193. console.error('Failed to invoke keyboard settings.');
  194. };
  195. }
  196. };
  197. exports.ImeMenu = ImeMenu;
  198. }(window));