BeamerReveal

 view release on metacpan or  search on metacpan

beamer-reveal-example_files/libs/revealjs/plugin/notes/speaker-view.html  view on Meta::CPAN

		'notes-only': 'Notes only' */
	      'tall': 'Slides & Notes',
	      'notes-only': 'Notes only'
	  };

	  setupLayout();

	  let openerOrigin;

	  try {
	      openerOrigin = window.opener.location.origin;
	  }
	  catch ( error ) { console.warn( error ) }

	  // In order to prevent XSS, the speaker view will only run if its
	  // opener has the same origin as itself
	  if( window.location.origin !== openerOrigin ) {
	      connectionStatus.innerHTML = 'Cross origin error.<br>The speaker window can only be opened from the same origin.';
	      return;
	  }

	  var connectionTimeout = setTimeout( function() {
	      connectionStatus.innerHTML = 'Error connecting to main window.<br>Please try closing and reopening the speaker view.';
	  }, 5000 );

	  window.addEventListener( 'message', function( event ) {

	      // Validate the origin of all messages to avoid parsing messages
	      // that aren't meant for us. Ignore when running off file:// so
	      // that the speaker view continues to work without a web server.
	      if( window.location.origin !== event.origin && window.location.origin !== 'file://' ) {
		  return
	      }

	      clearTimeout( connectionTimeout );
	      connectionStatus.style.display = 'none';

	      var data = JSON.parse( event.data );

	      // The overview mode is only useful to the reveal.js instance
	      // where navigation occurs so we don't sync it
	      if( data.state ) delete data.state.overview;

	      // Messages sent by the notes plugin inside of the main window
	      if( data && data.namespace === 'reveal-notes' ) {
		  if( data.type === 'connect' ) {
		      handleConnectMessage( data );
		  }
		  else if( data.type === 'state' ) {
		      handleStateMessage( data );
		  }
		  else if( data.type === 'return' ) {
		      pendingCalls[data.callId](data.result);
		      delete pendingCalls[data.callId];
		  }
	      }
	      // Messages sent by the reveal.js inside of the current slide preview
	      else if( data && data.namespace === 'reveal' ) {
		  const supportedEvents = [
		      'slidechanged',
		      'fragmentshown',
		      'fragmenthidden',
		      'paused',
		      'resumed',
		      'previewiframe',
		      'previewimage',
		      'previewvideo',
		      'closeoverlay'
		  ];

		  if( /ready/.test( data.eventName ) ) {
		      // Send a message back to notify that the handshake is complete
		      window.opener.postMessage( JSON.stringify({ namespace: 'reveal-notes', type: 'connected'} ), '*' );
		  }
		  else if( supportedEvents.includes( data.eventName ) && currentState !== JSON.stringify( data.state ) ) {
		      dispatchStateToMainWindow( data.state );
		  }
	      }

	  } );

	  /**
	   * Updates the presentation in the main window to match the state
	   * of the presentation in the notes window.
	   */
	  const dispatchStateToMainWindow = debounce(( state ) => {
	      window.opener.postMessage( JSON.stringify({ method: 'setState', args: [ state ]} ), '*' );
	  }, 500);

	  /**
	   * Asynchronously calls the Reveal.js API of the main frame.
	   */
	  function callRevealApi( methodName, methodArguments, callback ) {

	      var callId = ++lastRevealApiCallId;
	      pendingCalls[callId] = callback;
	      window.opener.postMessage( JSON.stringify( {
		  namespace: 'reveal-notes',
		  type: 'call',
		  callId: callId,
		  methodName: methodName,
		  arguments: methodArguments
	      } ), '*' );

	  }

	  /**
	   * Called when the main window is trying to establish a
	   * connection.
	   */
	  function handleConnectMessage( data ) {

	      if( connected === false ) {
		  connected = true;

		  setupIframes( data );
		  setupKeyboard();
		  setupNotes();
		  setupTimer();
		  setupHeartbeat();
	      }

	  }

	  /**
	   * Called when the main window sends an updated state.
	   */
	  function handleStateMessage( data ) {

	      // Store the most recently set state to avoid circular loops
	      // applying the same state
	      currentState = JSON.stringify( data.state );

	      // No need for updating the notes in case of fragment changes
	      if ( data.notes ) {
		  notes.classList.remove( 'hidden' );
		  notesValue.style.whiteSpace = data.whitespace;
		  if( data.markdown ) {
		      notesValue.innerHTML = marked( data.notes );
		  }
		  else {
		      notesValue.innerHTML = data.notes;
		  }
	      }
	      else {
		  notes.classList.add( 'hidden' );
	      }

	      // Don't show lightboxes in the upcoming slide
	      const { previewVideo, previewImage, previewIframe, ...upcomingState } = data.state;

	      // Update the note slides
	      currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ data.state ] }), '*' );
	      upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'setState', args: [ upcomingState ] }), '*' );
	      upcomingSlide.contentWindow.postMessage( JSON.stringify({ method: 'next' }), '*' );

	  }

	  // Limit to max one state update per X ms
	  handleStateMessage = debounce( handleStateMessage, 200 );

	  /**
	   * Forward keyboard events to the current slide window.
	   * This enables keyboard events to work even if focus
	   * isn't set on the current slide iframe.
	   *
	   * Block F5 default handling, it reloads and disconnects
	   * the speaker notes window.
	   */
	  function setupKeyboard() {

	      document.addEventListener( 'keydown', function( event ) {
		  if( event.keyCode === 116 || ( event.metaKey && event.keyCode === 82 ) ) {
		      event.preventDefault();
		      return false;
		  }
		  currentSlide.contentWindow.postMessage( JSON.stringify({ method: 'triggerKey', args: [ event.keyCode ] }), '*' );
	      } );

	  }

	  /**
	   * Creates the preview iframes.
	   */
	  function setupIframes( data ) {

	      var params = [
		  'receiver',
		  'progress=false',
		  'history=false',
		  'transition=none',
		  'autoSlide=0',
		  'backgroundTransition=none'
	      ].join( '&' );



( run in 1.090 second using v1.01-cache-2.11-cpan-364913b4093 )