UNPKG

@jlongster/spectacle

Version:

ReactJS Powered Presentation Framework

578 lines (478 loc) 19.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = undefined; var _extends2 = require("babel-runtime/helpers/extends"); var _extends3 = _interopRequireDefault(_extends2); var _keys = require("babel-runtime/core-js/object/keys"); var _keys2 = _interopRequireDefault(_keys); var _jsx2 = require("babel-runtime/helpers/jsx"); var _jsx3 = _interopRequireDefault(_jsx2); var _assign = require("babel-runtime/core-js/object/assign"); var _assign2 = _interopRequireDefault(_assign); var _isFinite = require("babel-runtime/core-js/number/is-finite"); var _isFinite2 = _interopRequireDefault(_isFinite); var _stringify = require("babel-runtime/core-js/json/stringify"); var _stringify2 = _interopRequireDefault(_stringify); var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn"); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require("babel-runtime/helpers/inherits"); var _inherits3 = _interopRequireDefault(_inherits2); var _dec, _class, _class2, _temp; /*eslint new-cap:0, max-statements:0*/ /* eslint react/no-did-mount-set-state: 0 */ var _react = require("react"); var _react2 = _interopRequireDefault(_react); var _reactAddonsTransitionGroup = require("react-addons-transition-group"); var _reactAddonsTransitionGroup2 = _interopRequireDefault(_reactAddonsTransitionGroup); var _radium = require("radium"); var _radium2 = _interopRequireDefault(_radium); var _filter = require("lodash/filter"); var _filter2 = _interopRequireDefault(_filter); var _size = require("lodash/size"); var _size2 = _interopRequireDefault(_size); var _findIndex = require("lodash/findIndex"); var _findIndex2 = _interopRequireDefault(_findIndex); var _reactRedux = require("react-redux"); var _actions = require("../actions"); var _typeface = require("./typeface"); var _typeface2 = _interopRequireDefault(_typeface); var _slides = require("../utils/slides"); var _presenter = require("./presenter"); var _presenter2 = _interopRequireDefault(_presenter); var _export = require("./export"); var _export2 = _interopRequireDefault(_export); var _overview = require("./overview"); var _overview2 = _interopRequireDefault(_overview); var _fullscreen = require("./fullscreen"); var _fullscreen2 = _interopRequireDefault(_fullscreen); var _progress = require("./progress"); var _progress2 = _interopRequireDefault(_progress); var _controls = require("./controls"); var _controls2 = _interopRequireDefault(_controls); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var TransitionGroup = (0, _radium2.default)(_reactAddonsTransitionGroup2.default); var _ref = (0, _jsx3.default)(_fullscreen2.default, {}); var Manager = (_dec = (0, _reactRedux.connect)(function (state) { return state; }), _dec(_class = (0, _radium2.default)(_class = (_temp = _class2 = function (_Component) { (0, _inherits3.default)(Manager, _Component); function Manager() { (0, _classCallCheck3.default)(this, Manager); var _this = (0, _possibleConstructorReturn3.default)(this, _Component.call(this)); _this._handleKeyPress = _this._handleKeyPress.bind(_this); _this._handleScreenChange = _this._handleScreenChange.bind(_this); _this.handleClick = _this.handleClick.bind(_this); _this._goToSlide = _this._goToSlide.bind(_this); _this.state = { lastSlideIndex: null, slideReference: [], fullscreen: window.innerHeight === screen.height, mobile: window.innerWidth < 1000 }; return _this; } Manager.prototype.componentWillMount = function componentWillMount() { this.setState({ slideReference: this._buildSlideReference() }); }; Manager.prototype.componentDidMount = function componentDidMount() { var slideIndex = this._getSlideIndex(); this.setState({ lastSlideIndex: slideIndex }); this._attachEvents(); }; Manager.prototype.componentDidUpdate = function componentDidUpdate() { if (this.props.globalStyles && !this.context.store.getState().style.globalStyleSet) { this.props.dispatch((0, _actions.setGlobalStyle)()); } }; Manager.prototype.componentWillUnmount = function componentWillUnmount() { this._detachEvents(); }; Manager.prototype._attachEvents = function _attachEvents() { window.addEventListener("storage", this._goToSlide); window.addEventListener("keydown", this._handleKeyPress); window.addEventListener("resize", this._handleScreenChange); }; Manager.prototype._detachEvents = function _detachEvents() { window.removeEventListener("storage", this._goToSlide); window.removeEventListener("keydown", this._handleKeyPress); window.removeEventListener("resize", this._handleScreenChange); }; Manager.prototype._handleEvent = function _handleEvent(e) { var event = window.event ? window.event : e; if (event.keyCode === 37 || event.keyCode === 33 || event.keyCode === 32 && event.shiftKey) { this._prevSlide(); } else if (event.keyCode === 39 || event.keyCode === 34 || event.keyCode === 32 && !event.shiftKey) { this._nextSlide(); } else if (event.altKey && event.keyCode === 79 && !event.ctrlKey && !event.metaKey) { // o this._toggleOverviewMode(); } else if (event.altKey && event.keyCode === 80 && !event.ctrlKey && !event.metaKey) { // p this._togglePresenterMode(); } }; Manager.prototype._handleKeyPress = function _handleKeyPress(e) { var event = window.event ? window.event : e; if (event.target instanceof HTMLInputElement || event.target.type === "textarea") { return; } this._handleEvent(e); }; Manager.prototype._handleScreenChange = function _handleScreenChange() { this.setState({ fullscreen: window.innerHeight === screen.height, mobile: window.innerWidth < 1000 }); }; Manager.prototype._toggleOverviewMode = function _toggleOverviewMode() { var suffix = this.props.route.params.indexOf("overview") !== -1 ? "" : "?overview"; this.context.history.replace("/" + this.props.route.slide + suffix); }; Manager.prototype._togglePresenterMode = function _togglePresenterMode() { var suffix = this.props.route.params.indexOf("presenter") !== -1 ? "" : "?presenter"; this.context.history.replace("/" + this.props.route.slide + suffix); }; Manager.prototype._getSuffix = function _getSuffix() { if (this.props.route.params.indexOf("presenter") !== -1) { return "?presenter"; } else if (this.props.route.params.indexOf("overview") !== -1) { return "?overview"; } else { return ""; } }; Manager.prototype._goToSlide = function _goToSlide(e) { if (e.key === "spectacle-slide") { var data = JSON.parse(e.newValue); var slideIndex = this._getSlideIndex(); this.setState({ lastSlideIndex: slideIndex || 0 }); if (this._checkFragments(this.props.route.slide, data.forward)) { this.context.history.replace("/" + data.slide + this._getSuffix()); } } }; Manager.prototype._prevSlide = function _prevSlide() { var slideIndex = this._getSlideIndex(); this.setState({ lastSlideIndex: slideIndex }); if (this._checkFragments(this.props.route.slide, false) || this.props.route.params.indexOf("overview") !== -1) { if (slideIndex > 0) { this.context.history.replace("/" + this._getHash(slideIndex - 1) + this._getSuffix()); localStorage.setItem("spectacle-slide", (0, _stringify2.default)({ slide: this._getHash(slideIndex - 1), forward: false, time: Date.now() })); } } else if (slideIndex > 0) { localStorage.setItem("spectacle-slide", (0, _stringify2.default)({ slide: this._getHash(slideIndex), forward: false, time: Date.now() })); } }; Manager.prototype._nextSlide = function _nextSlide() { var slideIndex = this._getSlideIndex(); this.setState({ lastSlideIndex: slideIndex }); var slideReference = this.state.slideReference; if (this._checkFragments(this.props.route.slide, true) || this.props.route.params.indexOf("overview") !== -1) { if (slideIndex < slideReference.length - 1) { this.context.history.replace("/" + (this._getHash(slideIndex + 1) + this._getSuffix())); localStorage.setItem("spectacle-slide", (0, _stringify2.default)({ slide: this._getHash(slideIndex + 1), forward: true, time: Date.now() })); } } else if (slideIndex < slideReference.length) { localStorage.setItem("spectacle-slide", (0, _stringify2.default)({ slide: this._getHash(slideIndex), forward: true, time: Date.now() })); } }; Manager.prototype._getHash = function _getHash(slideIndex) { return this.state.slideReference[slideIndex].id; }; Manager.prototype._checkFragments = function _checkFragments(slide, forward) { var state = this.context.store.getState(); var fragments = state.fragment.fragments; // Not proud of this at all. 0.14 Parent based contexts will fix this. if (this.props.route.params.indexOf("presenter") !== -1) { var main = document.querySelector(".spectacle-presenter-main"); if (main) { var frags = main.querySelectorAll(".fragment"); if (!frags.length) { return true; } } else { return true; } } if (slide in fragments) { var count = (0, _size2.default)(fragments[slide]); var visible = (0, _filter2.default)(fragments[slide], function (s) { return s.visible === true; }); var hidden = (0, _filter2.default)(fragments[slide], function (s) { return s.visible !== true; }); if (forward === true && visible.length !== count) { this.props.dispatch((0, _actions.updateFragment)({ fragment: hidden[0], visible: true })); return false; } if (forward === false && hidden.length !== count) { this.props.dispatch((0, _actions.updateFragment)({ fragment: visible[(0, _size2.default)(visible) - 1], visible: false })); return false; } return true; } else { return true; } }; Manager.prototype._getTouchEvents = function _getTouchEvents() { var self = this; return { onTouchStart: function onTouchStart(e) { self.touchObject = { startX: e.touches[0].pageX, startY: e.touches[0].pageY }; }, onTouchMove: function onTouchMove(e) { var direction = self._swipeDirection({ x1: self.touchObject.startX, x2: e.touches[0].pageX, y1: self.touchObject.startY, y2: e.touches[0].pageY }); self.touchObject = { startX: self.touchObject.startX, startY: self.touchObject.startY, endX: e.clientX, endY: e.clientY, length: Math.round(Math.sqrt(Math.pow(e.touches[0].pageX - self.touchObject.startX, 2))), direction: direction }; if (direction !== 0) { e.preventDefault(); } }, onTouchEnd: function onTouchEnd(e) { self._handleSwipe(e); }, onTouchCancel: function onTouchCancel(e) { self._handleSwipe(e); } }; }; Manager.prototype.handleClick = function handleClick(e) { if (this.clickSafe === true) { e.preventDefault(); e.stopPropagation(); e.nativeEvent.stopPropagation(); } }; Manager.prototype._handleSwipe = function _handleSwipe() { if (typeof this.touchObject.length !== "undefined" && this.touchObject.length > 44) { this.clickSafe = true; } else { this.clickSafe = false; } if (Math.abs(this.touchObject.length) > 20) { if (this.touchObject.direction === 1) { this._nextSlide(); } else if (this.touchObject.direction === -1) { this._prevSlide(); } } this.touchObject = {}; }; Manager.prototype._swipeDirection = function _swipeDirection(touch) { var xDist = touch.x1 - touch.x2; var yDist = touch.y1 - touch.y2; var r = Math.atan2(yDist, xDist); var swipeAngle = Math.round(r * 180 / Math.PI); if (swipeAngle < 0) { swipeAngle = 360 - Math.abs(swipeAngle); } if (swipeAngle <= 45 && swipeAngle >= 0) { return 1; } if (swipeAngle <= 360 && swipeAngle >= 315) { return 1; } if (swipeAngle >= 135 && swipeAngle <= 225) { return -1; } return 0; }; Manager.prototype._buildSlideReference = function _buildSlideReference() { var slideReference = []; _react.Children.toArray(this.props.children).forEach(function (child, rootIndex) { if (!child.props.hasSlideChildren) { slideReference.push({ id: child.props.id || slideReference.length, rootIndex: rootIndex }); } else { child.props.children.forEach(function (setSlide, setIndex) { slideReference.push({ id: setSlide.props.id || slideReference.length, setIndex: setIndex, rootIndex: rootIndex }); }); } }); return slideReference; }; Manager.prototype._getSlideIndex = function _getSlideIndex() { var _this2 = this; var index = parseInt(this.props.route.slide); if (!(0, _isFinite2.default)(index)) { var foundIndex = (0, _findIndex2.default)(this.state.slideReference, function (reference) { return _this2.props.route.slide === reference.id; }); index = foundIndex >= 0 ? foundIndex : 0; } return index; }; Manager.prototype._getSlideByIndex = function _getSlideByIndex(index) { return (0, _slides.getSlideByIndex)(this.props.children, this.state.slideReference, index); }; Manager.prototype._renderSlide = function _renderSlide() { var slideIndex = this._getSlideIndex(); var slide = this._getSlideByIndex(slideIndex); return (0, _react.cloneElement)(slide, { dispatch: this.props.dispatch, fragments: this.props.fragment, key: slideIndex, export: this.props.route.params.indexOf("export") !== -1, print: this.props.route.params.indexOf("print") !== -1, children: _react.Children.toArray(slide.props.children), hash: this.props.route.slide, slideIndex: slideIndex, lastSlideIndex: this.state.lastSlideIndex, transition: (slide.props.transition || {}).length ? slide.props.transition : this.props.transition, transitionDuration: (slide.props.transition || {}).transitionDuration ? slide.props.transitionDuration : this.props.transitionDuration }); }; Manager.prototype.render = function render() { var globals = this.props.route.params.indexOf("export") !== -1 ? { body: (0, _assign2.default)(this.context.styles.global.body, { minWidth: 1100, minHeight: 850, overflow: "auto" }), ".spectacle-presenter-next .fragment": { display: "none !important" } } : { ".spectacle-presenter-next .fragment": { display: "none !important" } }; var styles = { deck: { backgroundColor: this.props.route.params.indexOf("presenter") !== -1 || this.props.route.params.indexOf("overview") !== -1 ? "black" : "", position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }, transition: { height: "100%", width: "100%", perspective: 1000, transformStyle: "flat" } }; var componentToRender = void 0; var children = _react.Children.toArray(this.props.children); if (this.props.route.params.indexOf("presenter") !== -1) { componentToRender = (0, _jsx3.default)(_presenter2.default, { dispatch: this.props.dispatch, slides: children, slideReference: this.state.slideReference, slideIndex: this._getSlideIndex(), hash: this.props.route.slide, route: this.props.route, lastSlideIndex: this.state.lastSlideIndex }); } else if (this.props.route.params.indexOf("export") !== -1) { componentToRender = (0, _jsx3.default)(_export2.default, { slides: children, slideReference: this.state.slideReference, route: this.props.route }); } else if (this.props.route.params.indexOf("overview") !== -1) { componentToRender = (0, _jsx3.default)(_overview2.default, { slides: children, slideReference: this.state.slideReference, slideIndex: this._getSlideIndex(), route: this.props.route }); } else { componentToRender = (0, _jsx3.default)(TransitionGroup, { component: "div", style: [styles.transition] }, void 0, this._renderSlide()); } var showControls = !this.state.fullscreen && !this.state.mobile && this.props.route.params.indexOf("export") === -1 && this.props.route.params.indexOf("overview") === -1 && this.props.route.params.indexOf("presenter") === -1; var _context$styles$googl = this.context.styles.googleFonts, googleFonts = _context$styles$googl === undefined ? {} : _context$styles$googl; var googleFontsElements = (0, _keys2.default)(googleFonts).map(function (key, index) { return (0, _jsx3.default)(_typeface2.default, { googleFont: googleFonts[key].name, styles: googleFonts[key].styles }, "gFont-" + index); }); return _react2.default.createElement( "div", (0, _extends3.default)({ className: "spectacle-deck", style: [styles.deck], onClick: this.handleClick }, this._getTouchEvents()), this.props.controls && showControls && (0, _jsx3.default)(_controls2.default, { currentSlideIndex: this._getSlideIndex(), totalSlides: this.state.slideReference.length, onPrev: this._prevSlide.bind(this), onNext: this._nextSlide.bind(this) }), googleFontsElements, componentToRender, this.props.route.params.indexOf("export") === -1 && this.props.route.params.indexOf("overview") === -1 ? (0, _jsx3.default)(_progress2.default, { items: this.state.slideReference, currentSlideIndex: this._getSlideIndex(), type: this.props.progress }) : "", this.props.route.params.indexOf("export") === -1 ? _ref : "", this.props.globalStyles && (0, _jsx3.default)(_radium.Style, { rules: (0, _assign2.default)(this.context.styles.global, globals) }) ); }; return Manager; }(_react.Component), _class2.displayName = "Manager", _class2.defaultProps = { transitionDuration: 500, progress: "pacman", controls: true, globalStyles: true }, _class2.contextTypes = { styles: _react.PropTypes.object, print: _react.PropTypes.object, history: _react.PropTypes.object, presenter: _react.PropTypes.bool, export: _react.PropTypes.bool, overview: _react.PropTypes.bool, store: _react.PropTypes.object, slide: _react.PropTypes.oneOfType([_react.PropTypes.number, _react.PropTypes.string]) }, _temp)) || _class) || _class); exports.default = Manager;