您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Etherpad.js 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /* global $, interfaceConfig */
  2. import VideoLayout from '../videolayout/VideoLayout';
  3. import LargeContainer from '../videolayout/LargeContainer';
  4. import UIEvents from '../../../service/UI/UIEvents';
  5. import Filmstrip from '../videolayout/Filmstrip';
  6. /**
  7. * Etherpad options.
  8. */
  9. const options = $.param({
  10. showControns: true,
  11. showChat: false,
  12. showLineNumbers: true,
  13. useMonospaceFont: false
  14. });
  15. /**
  16. *
  17. */
  18. function bubbleIframeMouseMove(iframe) {
  19. const existingOnMouseMove = iframe.contentWindow.onmousemove;
  20. iframe.contentWindow.onmousemove = function(e) {
  21. if (existingOnMouseMove) {
  22. existingOnMouseMove(e);
  23. }
  24. const evt = document.createEvent('MouseEvents');
  25. const boundingClientRect = iframe.getBoundingClientRect();
  26. evt.initMouseEvent(
  27. 'mousemove',
  28. true, // bubbles
  29. false, // not cancelable
  30. window,
  31. e.detail,
  32. e.screenX,
  33. e.screenY,
  34. e.clientX + boundingClientRect.left,
  35. e.clientY + boundingClientRect.top,
  36. e.ctrlKey,
  37. e.altKey,
  38. e.shiftKey,
  39. e.metaKey,
  40. e.button,
  41. null // no related element
  42. );
  43. iframe.dispatchEvent(evt);
  44. };
  45. }
  46. /**
  47. * Default Etherpad frame width.
  48. */
  49. const DEFAULT_WIDTH = 640;
  50. /**
  51. * Default Etherpad frame height.
  52. */
  53. const DEFAULT_HEIGHT = 480;
  54. const ETHERPAD_CONTAINER_TYPE = 'etherpad';
  55. /**
  56. * Container for Etherpad iframe.
  57. */
  58. class Etherpad extends LargeContainer {
  59. /**
  60. * Creates new Etherpad object
  61. */
  62. constructor(domain, name) {
  63. super();
  64. const iframe = document.createElement('iframe');
  65. iframe.id = 'etherpadIFrame';
  66. iframe.src = `${domain + name}?${options}`;
  67. iframe.frameBorder = 0;
  68. iframe.scrolling = 'no';
  69. iframe.width = DEFAULT_WIDTH;
  70. iframe.height = DEFAULT_HEIGHT;
  71. iframe.setAttribute('style', 'visibility: hidden;');
  72. this.container.appendChild(iframe);
  73. iframe.onload = function() {
  74. document.domain = document.domain;
  75. bubbleIframeMouseMove(iframe);
  76. setTimeout(() => {
  77. const doc = iframe.contentDocument;
  78. // the iframes inside of the etherpad are
  79. // not yet loaded when the etherpad iframe is loaded
  80. const outer = doc.getElementsByName('ace_outer')[0];
  81. bubbleIframeMouseMove(outer);
  82. const inner = doc.getElementsByName('ace_inner')[0];
  83. bubbleIframeMouseMove(inner);
  84. }, 2000);
  85. };
  86. this.iframe = iframe;
  87. }
  88. /**
  89. *
  90. */
  91. get isOpen() {
  92. return Boolean(this.iframe);
  93. }
  94. /**
  95. *
  96. */
  97. get container() {
  98. return document.getElementById('etherpad');
  99. }
  100. /**
  101. *
  102. */
  103. resize(containerWidth, containerHeight) {
  104. let height, width;
  105. if (interfaceConfig.VERTICAL_FILMSTRIP) {
  106. height = containerHeight;
  107. width = containerWidth - Filmstrip.getFilmstripWidth();
  108. } else {
  109. height = containerHeight - Filmstrip.getFilmstripHeight();
  110. width = containerWidth;
  111. }
  112. $(this.iframe)
  113. .width(width)
  114. .height(height);
  115. }
  116. /**
  117. *
  118. */
  119. show() {
  120. const $iframe = $(this.iframe);
  121. const $container = $(this.container);
  122. const self = this;
  123. return new Promise(resolve => {
  124. $iframe.fadeIn(300, () => {
  125. self.bodyBackground = document.body.style.background;
  126. document.body.style.background = '#eeeeee';
  127. $iframe.css({ visibility: 'visible' });
  128. $container.css({ zIndex: 2 });
  129. resolve();
  130. });
  131. });
  132. }
  133. /**
  134. *
  135. */
  136. hide() {
  137. const $iframe = $(this.iframe);
  138. const $container = $(this.container);
  139. document.body.style.background = this.bodyBackground;
  140. return new Promise(resolve => {
  141. $iframe.fadeOut(300, () => {
  142. $iframe.css({ visibility: 'hidden' });
  143. $container.css({ zIndex: 0 });
  144. resolve();
  145. });
  146. });
  147. }
  148. /**
  149. * @return {boolean} do not switch on dominant speaker event if on stage.
  150. */
  151. stayOnStage() {
  152. return true;
  153. }
  154. }
  155. /**
  156. * Manager of the Etherpad frame.
  157. */
  158. export default class EtherpadManager {
  159. /**
  160. *
  161. */
  162. constructor(domain, name, eventEmitter) {
  163. if (!domain || !name) {
  164. throw new Error('missing domain or name');
  165. }
  166. this.domain = domain;
  167. this.name = name;
  168. this.eventEmitter = eventEmitter;
  169. this.etherpad = null;
  170. }
  171. /**
  172. *
  173. */
  174. get isOpen() {
  175. return Boolean(this.etherpad);
  176. }
  177. /**
  178. *
  179. */
  180. isVisible() {
  181. return VideoLayout.isLargeContainerTypeVisible(ETHERPAD_CONTAINER_TYPE);
  182. }
  183. /**
  184. * Create new Etherpad frame.
  185. */
  186. openEtherpad() {
  187. this.etherpad = new Etherpad(this.domain, this.name);
  188. VideoLayout.addLargeVideoContainer(
  189. ETHERPAD_CONTAINER_TYPE,
  190. this.etherpad
  191. );
  192. }
  193. /**
  194. * Toggle Etherpad frame visibility.
  195. * Open new Etherpad frame if there is no Etherpad frame yet.
  196. */
  197. toggleEtherpad() {
  198. if (!this.isOpen) {
  199. this.openEtherpad();
  200. }
  201. const isVisible = this.isVisible();
  202. VideoLayout.showLargeVideoContainer(
  203. ETHERPAD_CONTAINER_TYPE, !isVisible);
  204. this.eventEmitter
  205. .emit(UIEvents.TOGGLED_SHARED_DOCUMENT, !isVisible);
  206. }
  207. }