facebookarchive / exerslide

A framework to create React-based HTML presentations and tutorials.
https://facebookincubator.github.io/exerslide/
Other
437 stars 46 forks source link

template mode #18

Open kwangkim opened 7 years ago

kwangkim commented 7 years ago

I usually modified configuration to allow latex or other extra things and I duplicated many configuration manually each time. Is there anyway to use it as a template mode?

fkling commented 7 years ago

Could you provide a concrete example? With configuration do you mean the exerslide.config.js or the webpack.config.js file (or both)?

kwangkim commented 7 years ago

No.(Not yet. I may need to modify webpack.config for video.) I just modified

index.html
exerslide-config.js
presentation.js
ReactFence.js (I remove div>p)

I also added a couple of js files(react components) to allow multiple choices.

modified presentation.js

/*
 * This hash helps exerslide to determine whether the file needs to be updated
 * or not. Please don't remove it.
 * @exerslide-file-hash 1f9628cb2d128f4be3e5945f65c9c775
 */

/**
 * This is the JavaScript entry point to the presentation.
 * This file allows you to customize some aspects of the presentation, such
 * as the master layout to use (if you don't want to edit the default one),
 * or which keyboard bindings to use for navigation, or to perform any other
 * kind of custom initialization step.
 */

import {present, use} from 'exerslide/browser';

/**
 * The master layout for this presentation. To customize is, either edit it
 * directly or copy it and point to the copy here.
 */
import MasterLayout from './MasterLayout';

/**
 * The base slide layout. To customize is, either edit it directly or copy it
 * and point to the copy here.
 */
import SlideLayout from './SlideLayout';

/**
 * Many features of exerslide are actually made available via runtime plugins.
 *
 * The following plugin enables keyboard navigation. This sets up the default
 * keybindings for a presentation. This should be an object with
 * `keys -> function` mapping. exerslide will bind event handlers for those keys
 * (key combinations) and call the corresponding function providing an API to
 * control the presentation. Currently provided is
 *
 * - nextSlide(): Advance to the next slide
 * - previousSlide(): Go back to the previous slide
 *
 * We use https://craig.is/killing/mice to bind the event handlers. Have
 * a look at the documentation to find out how to specify key combinations.
 */
import keyboardNavigation from 'exerslide/browser-plugins/keyboardNavigation';
function forward({forward}) {
  forward();
}

function back({back}) {
  back();
}
use(
  keyboardNavigation,
  {
    left: back,
    right: forward,
    'alt+pageup': back,
    'alt+pagedown': forward,
  }
);

/**
 * This plugin automatically scales the font size according to the provided
 * settings. The default settings try to maintain a line length that is
 * considered to be readable. To disable this plugin, just comment or remove the
 * following two lines.
 */
import scaledContent from 'exerslide/browser-plugins/scaledContent';
use(scaledContent);

/**
 * This plugin, when applied to content, injects alerts for screenreaders that
 * let the author know if the content isn't fully visible. That allows authors
 * with visual impairment to adjust the content or to scroll to make the content
 * visible.
 */
import contentVisibility from 'exerslide/browser-plugins/contentVisibility';
use(contentVisibility);

/**
 * This plugin is only enabled during development and shows the file path of the
 * current slide and allows to view the source of the slide.
 */
import debugInformation from 'exerslide/browser-plugins/debugInformation';
use(debugInformation);

/**
 * It is likely that you will be linking to the same external sources from
 * multiple slides. By default exerslide provides the references.yml file as a
 * central place to keep those references. The default markdown parser takes
 * them into account.
 */
import references from '!!json!yaml!../references.yml';

/**
 * __exerslide_slides__ is "magic" global variable that holds an array of slide
 * objects. By default this variable is injected by webpack. You could use
 * to perform additional modifications to the slides.
 */
/* global __exerslide_slides__*/

import mdi_Katex from "./Katex";
import mdi_Collapse from "./Collapse";
import mdi_Collapse_open from "./Collapse_open";

use(mdi_Katex);//Katex
use(mdi_Collapse);// collapse
use(mdi_Collapse_open);// collapse_open

import reactFence from './reactFence';
import React from 'react'
import CheckboxList from './components/CheckboxList';
import RadiobuttonList from './components/RadiobuttonList';

use(reactFence, (tokeninfo, content, env, md) => {
    const keyword="MC";
    const pattern = new RegExp("\\s*"+keyword +"\\b\\s*","i") //case-insentive
    if ( pattern.test(tokeninfo) ) {  //case insenstive!  Check the bane of react component
      const divider="---" //  question    ____ choices
      const escapeRegex = (function() {
        const PATTERN = /[.*?+[\]{}|\\^$()]/g;
        return str => str.replace(PATTERN, '\\$&');
      }());
      let transfer = (fns)=> ( i =>( c=> (fns[i](c))))  //multiple functions for map.
      let fns =[
        c=>md.render(c), //0
        c=>c.split(/^\*\s*/m) //split using *
          .map(c=> c.replace(/\s+$/, '') ).filter(Boolean)  //Remove empty lines and empty spaces of front and back.
          .map(c=> c.match(/^(\S+)\s(.*)/).slice(1) )  // slice once 
          .reduce( (a,c,i,arr) => [ a[0].concat([{ value : i.toString(), text :  md.renderInline(c[1]) }]),  c[0]==='+' ? a[1].concat([i.toString()]) : a[1] ]  , [ [],[] ]),
        c=> md.render(c)   
      ]
      let [question, [choices, answers], explanation ] = content.split(new RegExp('^' + escapeRegex(divider) + '$', 'm')) // split using '___'
        .map( (c,i)=> ( transfer(fns)(i)(c)) );
      if(answers.length > 1){
        return  <CheckboxList  question={question}   choices={choices} answers={answers} explanation={explanation} />;  
      }
      else if(answers.length === 1){
        return  <RadiobuttonList  question={question}   choices={choices} answer={answers[0]} explanation={explanation} />;
      }
      else{
        return '';
      } 
    }
  }
);
present({
  masterLayout: MasterLayout,
  slideLayout: SlideLayout,
  references,
  slides: __exerslide_slides__
});
fkling commented 7 years ago

I see. I don't have a good answer for that, other than using any existing method for making code/modules reusable.

You could try to bundle everything up to limit the number of changes you have to make for each file. E.g. all the code in your presentation.js can be put in a separate file and so you only have to add

import myPlugin from './myPlugin';
use(myPlugin)

You can keep your custom code in a separate package (e.g. /User/you/shared/myCustomizations), install that package locally into each presentation via npm install /User/you/shared/myCustomizations and then import the files where they are needed (e.g. import myPlugin from 'myCustomizations/myPlugin').